nanook 2.2.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,10 @@
1
- class Nanook
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'util'
2
4
 
3
- # The <tt>Nanook::WalletAccount</tt> class lets you manage your nano accounts,
4
- # including paying and receiving payment.
5
+ class Nanook
6
+ # The <tt>Nanook::WalletAccount</tt> class lets you manage your nano accounts
7
+ # that are on your node, including paying and receiving payment.
5
8
  #
6
9
  # === Initializing
7
10
  #
@@ -14,17 +17,27 @@ class Nanook
14
17
  # rpc_conn = Nanook::Rpc.new
15
18
  # account = Nanook::WalletAccount.new(rpc_conn, wallet_id, account_id)
16
19
  class WalletAccount
17
-
20
+ include Nanook::Util
18
21
  extend Forwardable
22
+ # @!method ==
23
+ # (see Nanook::Account#==)
19
24
  # @!method balance(unit: Nanook.default_unit)
20
25
  # (see Nanook::Account#balance)
21
26
  # @!method block_count
22
27
  # (see Nanook::Account#block_count)
28
+ # @!method blocks(limit: 1000, sort: :desc)
29
+ # (see Nanook::Account#blocks)
23
30
  # @!method delegators(unit: Nanook.default_unit)
24
31
  # (see Nanook::Account#delegators)
32
+ # @!method delegators_count
33
+ # (see Nanook::Account#delegators_count)
34
+ # @!method eql?
35
+ # (see Nanook::Account#eql?)
25
36
  # @!method exists?
26
37
  # (see Nanook::Account#exists?)
27
- # @!method history(limit: 1000, unit: Nanook.default_unit)
38
+ # @!method hash
39
+ # (see Nanook::Account#hash)
40
+ # @!method history(limit: 1000, unit: Nanook.default_unit, sort: :desc)
28
41
  # (see Nanook::Account#history)
29
42
  # @!method id
30
43
  # (see Nanook::Account#id)
@@ -32,8 +45,10 @@ class Nanook
32
45
  # (see Nanook::Account#info)
33
46
  # @!method last_modified_at
34
47
  # (see Nanook::Account#last_modified_at)
35
- # @!method ledger(limit: 1, modified_since: nil, unit: Nanook.default_unit)
48
+ # @!method ledger(limit: 1, modified_since: nil, unit: Nanook.default_unit, sort: :desc)
36
49
  # (see Nanook::Account#ledger)
50
+ # @!method open_block
51
+ # (see Nanook::Account#open_block)
37
52
  # @!method pending(limit: 1000, detailed: false, unit: Nanook.default_unit)
38
53
  # (see Nanook::Account#pending)
39
54
  # @!method public_key
@@ -42,26 +57,45 @@ class Nanook
42
57
  # (see Nanook::Account#representative)
43
58
  # @!method weight
44
59
  # (see Nanook::Account#weight)
45
- def_delegators :@nanook_account_instance, :balance, :delegators, :exists?, :history, :id, :info, :last_modified_at, :ledger, :pending, :public_key, :representative, :weight
46
- alias_method :open?, :exists?
60
+ def_delegators :@nanook_account_instance,
61
+ :==, :balance, :block_count, :blocks, :delegators, :delegators_count,
62
+ :eql?, :exists?, :hash, :history, :id, :info, :last_modified_at, :ledger,
63
+ :open_block, :pending, :public_key, :representative, :weight
64
+ alias open? exists?
47
65
 
48
- def initialize(rpc, wallet, account)
66
+ def initialize(rpc, wallet, account = nil)
49
67
  @rpc = rpc
50
- @wallet = wallet
51
- @account = account
68
+ @wallet = wallet.to_s
69
+ @account = account.to_s if account
70
+
71
+ # Initialize an instance to delegate the RPC commands that do not
72
+ # need `enable_control` enabled (the read-only RPC commands).
52
73
  @nanook_account_instance = nil
53
74
 
54
- unless @account.nil?
55
- # Wallet must contain the account
56
- unless Nanook::Wallet.new(@rpc, @wallet).contains?(@account)
57
- raise ArgumentError.new("Account does not exist in wallet. Account: #{@account}, wallet: #{@wallet}")
58
- end
75
+ return if @account.nil?
59
76
 
60
- # An object to delegate account methods that don't
61
- # expect a wallet param in the RPC call, to allow this
62
- # class to support all methods that can be called on Nanook::Account
63
- @nanook_account_instance = Nanook::Account.new(@rpc, @account)
77
+ # Wallet must contain the account
78
+ unless Nanook::Wallet.new(@rpc, @wallet).contains?(@account)
79
+ raise ArgumentError, "Account does not exist in wallet. Account: #{@account}, wallet: #{@wallet}"
64
80
  end
81
+
82
+ @nanook_account_instance = as_account(@account)
83
+ end
84
+
85
+ # @param other [Nanook::WalletAccount] wallet account to compare
86
+ # @return [Boolean] true if accounts are equal
87
+ def ==(other)
88
+ other.class == self.class &&
89
+ other.id == @account
90
+ end
91
+ alias eql? ==
92
+
93
+ # The hash value is used along with #eql? by the Hash class to determine if two objects
94
+ # reference the same hash key.
95
+ #
96
+ # @return [Integer]
97
+ def hash
98
+ [@wallet, @account].join('+').hash
65
99
  end
66
100
 
67
101
  # Creates a new account, or multiple new accounts, in this wallet.
@@ -71,23 +105,22 @@ class Nanook
71
105
  # wallet.create # => Nanook::WalletAccount
72
106
  # wallet.create(2) # => [Nanook::WalletAccount, Nanook::WalletAccount]
73
107
  #
74
- # @param n [Integer] number of accounts to create
108
+ # @param n_accounts [Integer] number of accounts to create
75
109
  #
76
110
  # @return [Nanook::WalletAccount] returns a single {Nanook::WalletAccount}
77
111
  # if invoked with no argument
78
112
  # @return [Array<Nanook::WalletAccount>] returns an Array of {Nanook::WalletAccount}
79
113
  # if method was called with argument +n+ > 1
80
114
  # @raise [ArgumentError] if +n+ is less than 1
81
- def create(n=1)
82
- if n < 1
83
- raise ArgumentError.new("number of accounts must be greater than 0")
84
- end
115
+ def create(n_accounts = 1)
116
+ skip_account_required!
117
+ raise ArgumentError, 'number of accounts must be greater than 0' if n_accounts < 1
85
118
 
86
- if n == 1
87
- Nanook::WalletAccount.new(@rpc, @wallet, rpc(:account_create)[:account])
119
+ if n_accounts == 1
120
+ as_wallet_account(rpc(:account_create, _access: :account))
88
121
  else
89
- Array(rpc(:accounts_create, count: n)[:accounts]).map do |account|
90
- Nanook::WalletAccount.new(@rpc, @wallet, account)
122
+ rpc(:accounts_create, count: n_accounts, _access: :accounts, _coerce: Array).map do |account|
123
+ as_wallet_account(account)
91
124
  end
92
125
  end
93
126
  end
@@ -100,27 +133,28 @@ class Nanook
100
133
  #
101
134
  # @return [Boolean] +true+ if action was successful, otherwise +false+
102
135
  def destroy
103
- rpc(:account_remove)[:removed] == 1
136
+ rpc(:account_remove, _access: :removed) == 1
104
137
  end
105
138
 
106
139
  # @return [String]
107
- def inspect
108
- "#{self.class.name}(wallet_id: #{@wallet}, account_id: #{id}, object_id: \"#{"0x00%x" % (object_id << 1)}\")"
140
+ def to_s
141
+ "#{self.class.name}(id: \"#{short_id}\")"
109
142
  end
143
+ alias inspect to_s
110
144
 
111
145
  # Makes a payment from this account to another account
112
146
  # on the nano network. Returns a <i>send</i> block hash
113
- # if successful, or a {Nanook::Error} if unsuccessful.
147
+ # if successful, or a {Nanook::NodeRpcError} if unsuccessful.
114
148
  #
115
149
  # Note, there may be a delay in receiving a response due to Proof
116
- # of Work being done. From the {Nano RPC}[https://github.com/nanocurrency/raiblocks/wiki/RPC-protocol#account-create]:
150
+ # of Work being done. From the {Nano RPC}[https://docs.nano.org/commands/rpc-protocol/#send]:
117
151
  #
118
152
  # <i>Proof of Work is precomputed for one transaction in the background. If it has been a while since your last transaction it will send instantly, the next one will need to wait for Proof of Work to be generated.</i>
119
153
  #
120
154
  # ==== Examples:
121
155
  #
122
- # account.pay(to: "xrb_...", amount: 1.1, id: "myUniqueId123") # => "9AE2311..."
123
- # account.pay(to: "xrb_...", amount: 54000000000000, id: "myUniqueId123", unit: :raw) # => "9AE2311..."
156
+ # account.pay(to: "nano_...", amount: 1.1, id: "myUniqueId123") # => "9AE2311..."
157
+ # account.pay(to: "nano_...", amount: 54000000000000, id: "myUniqueId123", unit: :raw) # => "9AE2311..."
124
158
  #
125
159
  # @param to [String] account id of the recipient of your payment
126
160
  # @param amount [Integer|Float]
@@ -129,42 +163,34 @@ class Nanook
129
163
  # purpose; it allows you to make the same call multiple times with
130
164
  # the same +id+ and be reassured that you will only ever send this
131
165
  # nano payment once
132
- # @return [String] the send block id for the payment
133
- # @raise [Nanook::Error] if unsuccessful
134
- def pay(to:, amount:, unit: Nanook::default_unit, id:)
135
- unless Nanook::UNITS.include?(unit)
136
- raise ArgumentError.new("Unsupported unit: #{unit}")
137
- end
166
+ # @return [Nanook::Block] the send block for the payment
167
+ # @raise [Nanook::NodeRpcError] if unsuccessful
168
+ # @raise [Nanook::NanoUnitError] if `unit` is invalid
169
+ def pay(to:, amount:, id:, unit: Nanook.default_unit)
170
+ validate_unit!(unit)
138
171
 
139
172
  # Check that to account is a valid address
140
- response = @rpc.call(:validate_account_number, account: to)
141
- unless response[:valid] == 1
142
- raise ArgumentError.new("Account address is invalid: #{to}")
143
- end
173
+ valid = @rpc.call(:validate_account_number, account: to, _access: :valid) == 1
174
+ raise ArgumentError, "Account address is invalid: #{to}" unless valid
144
175
 
145
- # Determin amount in raw
176
+ # Determine amount in raw
146
177
  raw = if unit.to_sym.eql?(:nano)
147
- Nanook::Util.NANO_to_raw(amount)
148
- else
149
- amount
150
- end
178
+ NANO_to_raw(amount)
179
+ else
180
+ amount
181
+ end
151
182
 
152
183
  # account is called source, so don't use the normal rpc method
153
- p = {
184
+ params = {
154
185
  wallet: @wallet,
155
186
  source: @account,
156
187
  destination: to,
157
188
  amount: raw,
158
- id: id
189
+ id: id,
190
+ _access: :block
159
191
  }
160
192
 
161
- response = @rpc.call(:send, p)
162
-
163
- if response.has_key?(:error)
164
- return Nanook::Error.new(response[:error])
165
- end
166
-
167
- response[:block]
193
+ as_block(@rpc.call(:send, params))
168
194
  end
169
195
 
170
196
  # Receives a pending payment for this account.
@@ -181,19 +207,17 @@ class Nanook
181
207
  #
182
208
  # ==== Examples:
183
209
  #
184
- # account.receive # => "9AE2311..."
185
- # account.receive("718CC21...") # => "9AE2311..."
210
+ # account.receive # => Nanook::Block
211
+ # account.receive("718CC21...") # => Nanook::Block
186
212
  #
187
213
  # @param block [String] optional block id of pending payment. If
188
214
  # not provided, the latest pending payment will be received
189
- # @return [String] the receive block id
215
+ # @return [Nanook::Block] the receive block
190
216
  # @return [false] if there was no block to receive
191
- def receive(block=nil)
192
- if block.nil?
193
- _receive_without_block
194
- else
195
- _receive_with_block(block)
196
- end
217
+ def receive(block = nil)
218
+ return receive_without_block if block.nil?
219
+
220
+ receive_with_block(block)
197
221
  end
198
222
 
199
223
  # Sets the representative for the account.
@@ -206,50 +230,89 @@ class Nanook
206
230
  # broadcast to the nano network. The block contains the information
207
231
  # about the representative change for your account.
208
232
  #
233
+ # Also see {Nanook::Wallet#change_default_representative} for how to set a default
234
+ # representative for all new accounts created in a wallet.
235
+ #
209
236
  # ==== Example:
210
237
  #
211
- # account.change_representative("xrb_...") # => "000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F"
238
+ # account.change_representative("nano_...") # => Nanook::Block
212
239
  #
213
- # @param [String] representative the id of the representative account
240
+ # @param representative [String] the id of the representative account
214
241
  # to set as this account's representative
215
- # @return [String] id of the <i>change</i> block created
216
- # @raise [ArgumentError] if the representative account does not exist
242
+ # @return [Nanook::Block] <i>change</i> block created
243
+ # @raise [Nanook::Error] if setting the representative account fails
217
244
  def change_representative(representative)
218
- unless Nanook::Account.new(@rpc, representative).exists?
219
- raise ArgumentError.new("Representative account does not exist: #{representative}")
245
+ unless as_account(representative).exists?
246
+ raise Nanook::Error, "Representative account does not exist: #{representative}"
220
247
  end
221
248
 
222
- rpc(:account_representative_set, representative: representative)[:block]
249
+ params = {
250
+ representative: representative,
251
+ _access: :block
252
+ }
253
+
254
+ as_block(rpc(:account_representative_set, params))
255
+ end
256
+
257
+ # Returns the work for the account.
258
+ #
259
+ # ==== Example:
260
+ #
261
+ # account.work # => "432e5cf728c90f4f"
262
+ #
263
+ # @return [String] work
264
+ def work
265
+ rpc(:work_get, _access: :work)
266
+ end
267
+
268
+ # Set work for account.
269
+ #
270
+ # ==== Example:
271
+ #
272
+ # account.set_work("432e5cf728c90f4f") # => true
273
+ #
274
+ # @return [Boolean] true if action was successful
275
+ def set_work(work)
276
+ rpc(:work_set, work: work).key?(:success)
223
277
  end
224
278
 
225
279
  private
226
280
 
227
- def _receive_without_block
281
+ def receive_without_block
228
282
  # Discover the first pending block
229
- pending_blocks = @rpc.call(:pending, { account: @account, count: 1 })
283
+ block = @rpc.call(:pending, { account: @account, count: 1, _access: :blocks, _coerce: Array }).first
230
284
 
231
- if pending_blocks[:blocks].empty?
232
- return false
233
- end
285
+ return false unless block
234
286
 
235
287
  # Then call receive_with_block as normal
236
- block = pending_blocks[:blocks][0]
237
- _receive_with_block(block)
288
+ receive_with_block(block)
238
289
  end
239
290
 
240
291
  # Returns block if successful, otherwise false
241
- def _receive_with_block(block)
242
- response = rpc(:receive, block: block)[:block]
243
- response.nil? ? false : response
292
+ def receive_with_block(block)
293
+ response = rpc(:receive, block: block, _access: :block)
294
+ response ? as_block(response) : false
244
295
  end
245
296
 
246
- def rpc(action, params={})
247
- p = {}
248
- p[:wallet] = @wallet unless @wallet.nil?
249
- p[:account] = @account unless @account.nil?
297
+ def rpc(action, params = {})
298
+ check_account_required!
250
299
 
251
- @rpc.call(action, p.merge(params))
300
+ p = { wallet: @wallet, account: @account }.compact
301
+ @rpc.call(action, p.merge(params)).tap { reset_skip_account_required! }
252
302
  end
253
303
 
304
+ def skip_account_required!
305
+ @skip_account_required_check = true
306
+ end
307
+
308
+ def reset_skip_account_required!
309
+ @skip_account_required_check = false
310
+ end
311
+
312
+ def check_account_required!
313
+ return if @account || @skip_account_required_check
314
+
315
+ raise ArgumentError, 'Account must be present'
316
+ end
254
317
  end
255
318
  end
@@ -1,31 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'util'
4
+
1
5
  class Nanook
6
+ # The <tt>Nanook::WorkPeer</tt> class lets you manage your node's work peers.
2
7
  class WorkPeer
8
+ include Nanook::Util
3
9
 
4
10
  def initialize(rpc)
5
11
  @rpc = rpc
6
12
  end
7
13
 
8
14
  def add(address:, port:)
9
- rpc(:work_peer_add, address: address, port: port).has_key?(:success)
15
+ rpc(:work_peer_add, address: address, port: port).key?(:success)
10
16
  end
11
17
 
12
18
  def clear
13
- rpc(:work_peers_clear).has_key?(:success)
19
+ rpc(:work_peers_clear).key?(:success)
14
20
  end
15
21
 
16
- def inspect
17
- "#{self.class.name}(object_id: \"#{"0x00%x" % (object_id << 1)}\")"
22
+ # @return [String]
23
+ def to_s
24
+ self.class.name
18
25
  end
26
+ alias inspect to_s
19
27
 
20
28
  def list
21
- rpc(:work_peers)[:work_peers]
29
+ rpc(:work_peers, _access: :work_peers, _coerce: Array)
22
30
  end
23
31
 
24
32
  private
25
33
 
26
- def rpc(action, params={})
34
+ def rpc(action, params = {})
27
35
  @rpc.call(action, params)
28
36
  end
29
-
30
37
  end
31
38
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nanook
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.0
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Luke Duncalfe
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-04-16 00:00:00.000000000 Z
11
+ date: 2021-04-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.16'
19
+ version: '2.2'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.16'
26
+ version: '2.2'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: pry
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -44,99 +44,100 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '10.0'
47
+ version: '12.3'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '10.0'
54
+ version: '12.3'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rspec
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '3.2'
61
+ version: '3.10'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '3.2'
68
+ version: '3.10'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rspec-collection_matchers
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '1.1'
75
+ version: '1.2'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '1.1'
82
+ version: '1.2'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: rspec_junit_formatter
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '0.3'
89
+ version: '0.4'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '0.3'
96
+ version: '0.4'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: webmock
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: '3.3'
103
+ version: '3.12'
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: '3.3'
110
+ version: '3.12'
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: yard
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
- - - "~>"
115
+ - - ">="
116
116
  - !ruby/object:Gem::Version
117
- version: '0'
117
+ version: 0.9.20
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
- - - "~>"
122
+ - - ">="
123
123
  - !ruby/object:Gem::Version
124
- version: '0'
124
+ version: 0.9.20
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: symbolized
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
- - - "~>"
129
+ - - '='
130
130
  - !ruby/object:Gem::Version
131
131
  version: 0.0.1
132
132
  type: :runtime
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
- - - "~>"
136
+ - - '='
137
137
  - !ruby/object:Gem::Version
138
138
  version: 0.0.1
139
- description: Ruby library for managing a nano currency node, including making and
139
+ description: |
140
+ Library for managing a nano currency node, including making and
140
141
  receiving payments, using the nano RPC protocol
141
142
  email:
142
143
  - lduncalfe@eml.cc
@@ -152,9 +153,10 @@ files:
152
153
  - lib/nanook.rb
153
154
  - lib/nanook/account.rb
154
155
  - lib/nanook/block.rb
155
- - lib/nanook/error.rb
156
- - lib/nanook/key.rb
156
+ - lib/nanook/errors.rb
157
157
  - lib/nanook/node.rb
158
+ - lib/nanook/private_key.rb
159
+ - lib/nanook/public_key.rb
158
160
  - lib/nanook/rpc.rb
159
161
  - lib/nanook/util.rb
160
162
  - lib/nanook/version.rb
@@ -166,7 +168,7 @@ licenses:
166
168
  - MIT
167
169
  metadata:
168
170
  yard.run: yri
169
- post_install_message:
171
+ post_install_message:
170
172
  rdoc_options: []
171
173
  require_paths:
172
174
  - lib
@@ -181,9 +183,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
181
183
  - !ruby/object:Gem::Version
182
184
  version: '0'
183
185
  requirements: []
184
- rubyforge_project:
185
- rubygems_version: 2.4.5.1
186
- signing_key:
186
+ rubygems_version: 3.2.3
187
+ signing_key:
187
188
  specification_version: 4
188
189
  summary: Library for managing a nano currency node, including making and receiving
189
190
  payments, using the nano RPC protocol