nanook 2.5.1 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +99 -0
- data/README.md +135 -85
- data/bin/console +4 -3
- data/lib/nanook.rb +76 -20
- data/lib/nanook/account.rb +232 -164
- data/lib/nanook/block.rb +343 -150
- data/lib/nanook/errors.rb +10 -0
- data/lib/nanook/node.rb +164 -132
- data/lib/nanook/private_key.rb +115 -0
- data/lib/nanook/public_key.rb +55 -0
- data/lib/nanook/rpc.rb +104 -44
- data/lib/nanook/util.rb +67 -18
- data/lib/nanook/version.rb +3 -1
- data/lib/nanook/wallet.rb +348 -161
- data/lib/nanook/wallet_account.rb +148 -88
- data/lib/nanook/work_peer.rb +14 -7
- metadata +20 -18
- data/lib/nanook/error.rb +0 -5
- data/lib/nanook/key.rb +0 -46
@@ -1,7 +1,10 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'util'
|
2
4
|
|
3
|
-
|
4
|
-
#
|
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
|
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,
|
46
|
-
|
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
|
-
|
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
|
-
|
61
|
-
|
62
|
-
|
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
|
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(
|
82
|
-
|
83
|
-
|
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
|
87
|
-
|
119
|
+
if n_accounts == 1
|
120
|
+
as_wallet_account(rpc(:account_create, _access: :account))
|
88
121
|
else
|
89
|
-
|
90
|
-
|
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,17 +133,18 @@ class Nanook
|
|
100
133
|
#
|
101
134
|
# @return [Boolean] +true+ if action was successful, otherwise +false+
|
102
135
|
def destroy
|
103
|
-
rpc(:account_remove
|
136
|
+
rpc(:account_remove, _access: :removed) == 1
|
104
137
|
end
|
105
138
|
|
106
139
|
# @return [String]
|
107
|
-
def
|
108
|
-
"#{self.class.name}(
|
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::
|
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
150
|
# of Work being done. From the {Nano RPC}[https://docs.nano.org/commands/rpc-protocol/#send]:
|
@@ -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 [
|
133
|
-
# @raise [Nanook::
|
134
|
-
|
135
|
-
|
136
|
-
|
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
|
-
|
141
|
-
|
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
|
-
#
|
176
|
+
# Determine amount in raw
|
146
177
|
raw = if unit.to_sym.eql?(:nano)
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
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
|
-
|
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
|
-
|
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 # =>
|
185
|
-
# account.receive("718CC21...") # =>
|
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 [
|
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
|
-
|
194
|
-
|
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.
|
@@ -211,48 +235,84 @@ class Nanook
|
|
211
235
|
#
|
212
236
|
# ==== Example:
|
213
237
|
#
|
214
|
-
# account.change_representative("nano_...") # =>
|
238
|
+
# account.change_representative("nano_...") # => Nanook::Block
|
215
239
|
#
|
216
|
-
# @param [String]
|
240
|
+
# @param representative [String] the id of the representative account
|
217
241
|
# to set as this account's representative
|
218
|
-
# @return [
|
219
|
-
# @raise [
|
242
|
+
# @return [Nanook::Block] <i>change</i> block created
|
243
|
+
# @raise [Nanook::Error] if setting the representative account fails
|
220
244
|
def change_representative(representative)
|
221
|
-
unless
|
222
|
-
raise
|
245
|
+
unless as_account(representative).exists?
|
246
|
+
raise Nanook::Error, "Representative account does not exist: #{representative}"
|
223
247
|
end
|
224
248
|
|
225
|
-
|
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)
|
226
277
|
end
|
227
278
|
|
228
279
|
private
|
229
280
|
|
230
|
-
def
|
281
|
+
def receive_without_block
|
231
282
|
# Discover the first pending block
|
232
|
-
|
283
|
+
block = @rpc.call(:pending, { account: @account, count: 1, _access: :blocks, _coerce: Array }).first
|
233
284
|
|
234
|
-
|
235
|
-
return false
|
236
|
-
end
|
285
|
+
return false unless block
|
237
286
|
|
238
287
|
# Then call receive_with_block as normal
|
239
|
-
block
|
240
|
-
_receive_with_block(block)
|
288
|
+
receive_with_block(block)
|
241
289
|
end
|
242
290
|
|
243
291
|
# Returns block if successful, otherwise false
|
244
|
-
def
|
245
|
-
response = rpc(:receive, block: block
|
246
|
-
response
|
292
|
+
def receive_with_block(block)
|
293
|
+
response = rpc(:receive, block: block, _access: :block)
|
294
|
+
response ? as_block(response) : false
|
247
295
|
end
|
248
296
|
|
249
|
-
def rpc(action, params={})
|
250
|
-
|
251
|
-
p[:wallet] = @wallet unless @wallet.nil?
|
252
|
-
p[:account] = @account unless @account.nil?
|
297
|
+
def rpc(action, params = {})
|
298
|
+
check_account_required!
|
253
299
|
|
254
|
-
@
|
300
|
+
p = { wallet: @wallet, account: @account }.compact
|
301
|
+
@rpc.call(action, p.merge(params)).tap { reset_skip_account_required! }
|
255
302
|
end
|
256
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
|
257
317
|
end
|
258
318
|
end
|
data/lib/nanook/work_peer.rb
CHANGED
@@ -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).
|
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).
|
19
|
+
rpc(:work_peers_clear).key?(:success)
|
14
20
|
end
|
15
21
|
|
16
|
-
|
17
|
-
|
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
|
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:
|
4
|
+
version: 3.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Luke Duncalfe
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-04-
|
11
|
+
date: 2021-04-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -58,70 +58,70 @@ dependencies:
|
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '3.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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:
|
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:
|
124
|
+
version: 0.9.20
|
125
125
|
- !ruby/object:Gem::Dependency
|
126
126
|
name: symbolized
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -136,8 +136,9 @@ dependencies:
|
|
136
136
|
- - '='
|
137
137
|
- !ruby/object:Gem::Version
|
138
138
|
version: 0.0.1
|
139
|
-
description:
|
140
|
-
|
139
|
+
description: |
|
140
|
+
Library for managing a nano currency node, including making and
|
141
|
+
receiving payments, using the nano RPC protocol
|
141
142
|
email:
|
142
143
|
- lduncalfe@eml.cc
|
143
144
|
executables: []
|
@@ -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/
|
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
|