nanook 2.5.0 → 4.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +137 -0
- data/README.md +156 -99
- data/bin/console +4 -3
- data/lib/nanook.rb +76 -20
- data/lib/nanook/account.rb +271 -170
- data/lib/nanook/block.rb +384 -156
- data/lib/nanook/errors.rb +10 -0
- data/lib/nanook/node.rb +188 -131
- 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 +72 -19
- data/lib/nanook/version.rb +3 -1
- data/lib/nanook/wallet.rb +355 -164
- data/lib/nanook/wallet_account.rb +152 -92
- data/lib/nanook/work_peer.rb +14 -7
- metadata +30 -29
- data/lib/nanook/error.rb +0 -5
- data/lib/nanook/key.rb +0 -46
data/lib/nanook/block.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'util'
|
2
4
|
|
5
|
+
class Nanook
|
3
6
|
# The <tt>Nanook::Block</tt> class contains methods to discover
|
4
7
|
# publicly-available information about blocks on the nano network.
|
5
8
|
#
|
@@ -17,21 +20,38 @@ class Nanook
|
|
17
20
|
# rpc_conn = Nanook::Rpc.new
|
18
21
|
# block = Nanook::Block.new(rpc_conn, "FBF8B0E...")
|
19
22
|
class Block
|
23
|
+
include Nanook::Util
|
20
24
|
|
21
25
|
def initialize(rpc, block)
|
22
26
|
@rpc = rpc
|
23
|
-
@block = block
|
24
|
-
block_required! # All methods expect a block
|
27
|
+
@block = block.to_s
|
25
28
|
end
|
26
29
|
|
27
|
-
# Returns the
|
30
|
+
# Returns the block hash id.
|
28
31
|
#
|
29
32
|
# ==== Example:
|
30
|
-
# block.account # => Nanook::Account
|
31
33
|
#
|
32
|
-
#
|
33
|
-
|
34
|
-
|
34
|
+
# block.id #=> "FBF8B0E..."
|
35
|
+
#
|
36
|
+
# @return [String] the block hash id
|
37
|
+
def id
|
38
|
+
@block
|
39
|
+
end
|
40
|
+
|
41
|
+
# @param other [Nanook::Block] block to compare
|
42
|
+
# @return [Boolean] true if blocks are equal
|
43
|
+
def ==(other)
|
44
|
+
other.class == self.class &&
|
45
|
+
other.id == id
|
46
|
+
end
|
47
|
+
alias eql? ==
|
48
|
+
|
49
|
+
# The hash value is used along with #eql? by the Hash class to determine if two objects
|
50
|
+
# reference the same hash key.
|
51
|
+
#
|
52
|
+
# @return [Integer]
|
53
|
+
def hash
|
54
|
+
id.hash
|
35
55
|
end
|
36
56
|
|
37
57
|
# Stop generating work for a block.
|
@@ -46,71 +66,50 @@ class Nanook
|
|
46
66
|
end
|
47
67
|
|
48
68
|
# Returns a consecutive list of block hashes in the account chain
|
49
|
-
#
|
69
|
+
# from (but not including) block back to +count+ (direction from frontier back to
|
50
70
|
# open block, from newer blocks to older). Will list all blocks back
|
51
71
|
# to the open block of this chain when count is set to "-1".
|
52
|
-
# The requested block hash is included in the answer.
|
53
72
|
#
|
54
|
-
# See also #
|
73
|
+
# See also #descendants.
|
55
74
|
#
|
56
75
|
# ==== Example:
|
57
76
|
#
|
58
|
-
# block.
|
77
|
+
# block.ancestors(limit: 2)
|
59
78
|
#
|
60
79
|
# ==== Example reponse:
|
61
80
|
#
|
62
|
-
# [
|
63
|
-
# "36A0FB717368BA8CF8D255B63DC207771EABC6C6FFC22A7F455EC2209464897E",
|
64
|
-
# "FBF8B0E6623A31AB528EBD839EEAA91CAFD25C12294C46754E45FD017F7939EB"
|
65
|
-
# ]
|
81
|
+
# [Nanook::Block, ...]
|
66
82
|
#
|
67
83
|
# @param limit [Integer] maximum number of block hashes to return (default is 1000)
|
68
84
|
# @param offset [Integer] return the account chain block hashes offset by the specified number of blocks (default is 0)
|
69
|
-
def
|
70
|
-
|
71
|
-
|
85
|
+
def ancestors(limit: 1000, offset: 0)
|
86
|
+
# The RPC includes this block in its response, and Nanook will remove it from the results.
|
87
|
+
# Increment the limit by 1 to account for this (a limit of -1 is valid and means no limit).
|
88
|
+
limit += 1 if limit > 0
|
89
|
+
params = {
|
90
|
+
count: limit,
|
91
|
+
offset: offset,
|
92
|
+
_access: :blocks,
|
93
|
+
_coerce: Array
|
94
|
+
}
|
95
|
+
|
96
|
+
response = rpc(:chain, :block, params)[1..].to_a
|
97
|
+
response.map { |block| as_block(block) }
|
72
98
|
end
|
73
|
-
|
99
|
+
alias chain ancestors # `chain` is the RPC command name
|
74
100
|
|
75
101
|
# Request confirmation for a block from online representative nodes.
|
76
102
|
# Will return immediately with a boolean to indicate if the request for
|
77
103
|
# confirmation was successful. Note that this boolean does not indicate
|
78
|
-
# the confirmation status of the block.
|
79
|
-
# appear in {Nanook::Node#confirmation_history} within a short amount of
|
80
|
-
# time, or you can use the convenience method {Nanook::Block#confirmed_recently?}
|
104
|
+
# the confirmation status of the block.
|
81
105
|
#
|
82
106
|
# ==== Example:
|
83
107
|
# block.confirm # => true
|
84
108
|
#
|
85
109
|
# @return [Boolean] if the confirmation request was sent successful
|
86
110
|
def confirm
|
87
|
-
rpc(:block_confirm, :hash
|
88
|
-
end
|
89
|
-
|
90
|
-
# This call is for internal diagnostics/debug purposes only. Do not
|
91
|
-
# rely on this interface being stable and do not use in a production system.
|
92
|
-
#
|
93
|
-
# Check if the block appears in the list of recently confirmed blocks by
|
94
|
-
# online representatives. The full list of blocks can be queried for with {Nanook::Node#confirmation_history}.
|
95
|
-
#
|
96
|
-
# This method can work in conjunction with {Nanook::Block#confirm},
|
97
|
-
# whereby you can send any block (old or new) out to online representatives to
|
98
|
-
# confirm. The confirmation process can take up to a couple of minutes.
|
99
|
-
#
|
100
|
-
# The method returning +false+ can indicate that the block is still in the process of being
|
101
|
-
# confirmed and that you should call the method again soon, or that it
|
102
|
-
# was confirmed earlier than the list available in {Nanook::Node#confirmation_history},
|
103
|
-
# or that it was not confirmed.
|
104
|
-
#
|
105
|
-
# ==== Example:
|
106
|
-
# block.confirmed_recently? # => true
|
107
|
-
#
|
108
|
-
# @return [Boolean] +true+ if the block has been recently confirmed by
|
109
|
-
# online representatives.
|
110
|
-
def confirmed_recently?
|
111
|
-
@rpc.call(:confirmation_history)[:confirmations].map{|h| h[:hash]}.include?(@block)
|
111
|
+
rpc(:block_confirm, :hash, _access: :started) == 1
|
112
112
|
end
|
113
|
-
alias_method :recently_confirmed?, :confirmed_recently?
|
114
113
|
|
115
114
|
# Generate work for a block.
|
116
115
|
#
|
@@ -122,42 +121,7 @@ class Nanook
|
|
122
121
|
# When +false+, the node will only generate work locally (default is +false+)
|
123
122
|
# @return [String] the work id of the work completed.
|
124
123
|
def generate_work(use_peers: false)
|
125
|
-
rpc(:work_generate, :hash, use_peers: use_peers
|
126
|
-
end
|
127
|
-
|
128
|
-
# Returns Array of Hashes containing information about a chain of
|
129
|
-
# send/receive blocks, starting from this block.
|
130
|
-
#
|
131
|
-
# ==== Example:
|
132
|
-
#
|
133
|
-
# block.history(limit: 1)
|
134
|
-
#
|
135
|
-
# ==== Example response:
|
136
|
-
#
|
137
|
-
# [
|
138
|
-
# {
|
139
|
-
# :account=>"nano_3x7cjioqahgs5ppheys6prpqtb4rdknked83chf97bot1unrbdkaux37t31b",
|
140
|
-
# :amount=>539834279601145558517940224,
|
141
|
-
# :hash=>"36A0FB717368BA8CF8D255B63DC207771EABC6C6FFC22A7F455EC2209464897E",
|
142
|
-
# :type=>"send"
|
143
|
-
# }
|
144
|
-
# ]
|
145
|
-
#
|
146
|
-
# @param limit [Integer] maximum number of send/receive block hashes
|
147
|
-
# to return in the chain (default is 1000)
|
148
|
-
def history(limit: 1000)
|
149
|
-
rpc(:history, :hash, count: limit)[:history]
|
150
|
-
end
|
151
|
-
|
152
|
-
# Returns the block hash id.
|
153
|
-
#
|
154
|
-
# ==== Example:
|
155
|
-
#
|
156
|
-
# block.id #=> "FBF8B0E..."
|
157
|
-
#
|
158
|
-
# @return [String] the block hash id
|
159
|
-
def id
|
160
|
-
@block
|
124
|
+
rpc(:work_generate, :hash, use_peers: use_peers, _access: :work)
|
161
125
|
end
|
162
126
|
|
163
127
|
# Returns a Hash of information about the block.
|
@@ -170,143 +134,407 @@ class Nanook
|
|
170
134
|
# ==== Example response:
|
171
135
|
#
|
172
136
|
# {
|
173
|
-
#
|
174
|
-
#
|
175
|
-
#
|
176
|
-
#
|
177
|
-
#
|
178
|
-
#
|
179
|
-
# :
|
137
|
+
# "account": Nanook::Account,
|
138
|
+
# "amount": 34.2,
|
139
|
+
# "balance": 2.3
|
140
|
+
# "height": 58,
|
141
|
+
# "local_timestamp": Time,
|
142
|
+
# "confirmed": true,
|
143
|
+
# "type": "send",
|
144
|
+
# "account": Nanook::Account,
|
145
|
+
# "previous": Nanook::Block,
|
146
|
+
# "representative": Nanook::Account,
|
147
|
+
# "link": Nanook::Block,
|
148
|
+
# "link_as_account": Nanook::Account,
|
149
|
+
# "signature": "82D41BC16F313E4B2243D14DFFA2FB04679C540C2095FEE7EAE0F2F26880AD56DD48D87A7CC5DD760C5B2D76EE2C205506AA557BF00B60D8DEE312EC7343A501",
|
150
|
+
# "work": "8a142e07a10996d5"
|
180
151
|
# }
|
181
152
|
#
|
182
153
|
# @param allow_unchecked [Boolean] (default is +false+). If +true+,
|
183
154
|
# information can be returned about blocks that are unchecked (unverified).
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
155
|
+
# @raise [Nanook::NanoUnitError] if `unit` is invalid
|
156
|
+
# @raise [Nanook::NodeRpcError] if block is not found on the node.
|
157
|
+
def info(allow_unchecked: false, unit: Nanook.default_unit)
|
158
|
+
validate_unit!(unit)
|
159
|
+
|
160
|
+
# Params for both `unchecked_get` and `block_info` calls
|
161
|
+
params = {
|
162
|
+
json_block: true,
|
163
|
+
_coerce: Hash
|
164
|
+
}
|
165
|
+
|
166
|
+
begin
|
167
|
+
response = rpc(:block_info, :hash, params)
|
168
|
+
response.merge!(confirmed: true)
|
169
|
+
rescue Nanook::NodeRpcError => e
|
170
|
+
raise e unless allow_unchecked
|
171
|
+
|
172
|
+
response = rpc(:unchecked_get, :hash, params)
|
173
|
+
response.merge!(confirmed: false)
|
191
174
|
end
|
192
175
|
|
193
|
-
response
|
194
|
-
_parse_info_response(response)
|
176
|
+
parse_info_response(response, unit)
|
195
177
|
end
|
196
178
|
|
179
|
+
# Returns true if work is valid for the block.
|
180
|
+
#
|
197
181
|
# ==== Example:
|
198
182
|
#
|
199
|
-
# block.
|
183
|
+
# block.valid_work?("2bf29ef00786a6bc") # => true
|
200
184
|
#
|
201
185
|
# @param work [String] the work id to check is valid
|
202
186
|
# @return [Boolean] signalling if work is valid for the block
|
203
|
-
def
|
187
|
+
def valid_work?(work)
|
204
188
|
response = rpc(:work_validate, :hash, work: work)
|
205
|
-
|
189
|
+
response[:valid_all] == 1 || response[:valid_receive] == 1
|
206
190
|
end
|
207
191
|
|
208
192
|
# Republish blocks starting at this block up the account chain
|
209
193
|
# back to the nano network.
|
210
194
|
#
|
211
|
-
# @return [Array<
|
195
|
+
# @return [Array<Nanook::Block>] blocks that were republished
|
212
196
|
#
|
213
197
|
# ==== Example:
|
214
198
|
#
|
215
|
-
# block.republish
|
216
|
-
|
217
|
-
# ==== Example response:
|
218
|
-
#
|
219
|
-
# ["36A0FB717368BA8CF8D255B63DC207771EABC6C6FFC22A7F455EC2209464897E"]
|
220
|
-
def republish(destinations:nil, sources:nil)
|
199
|
+
# block.republish # => [Nanook::Block, ...]
|
200
|
+
def republish(destinations: nil, sources: nil)
|
221
201
|
if !destinations.nil? && !sources.nil?
|
222
|
-
raise ArgumentError
|
202
|
+
raise ArgumentError, 'You must provide either destinations or sources but not both'
|
223
203
|
end
|
224
204
|
|
225
|
-
|
226
|
-
|
205
|
+
params = {
|
206
|
+
_access: :blocks,
|
207
|
+
_coerce: Array
|
208
|
+
}
|
209
|
+
|
227
210
|
params[:destinations] = destinations unless destinations.nil?
|
228
211
|
params[:sources] = sources unless sources.nil?
|
229
|
-
params[:count] = 1
|
212
|
+
params[:count] = 1 if destinations || sources
|
230
213
|
|
231
|
-
rpc(:republish, :hash, params)
|
214
|
+
rpc(:republish, :hash, params).map do |block|
|
215
|
+
as_block(block)
|
216
|
+
end
|
232
217
|
end
|
233
218
|
|
219
|
+
# Returns true if block is a pending block.
|
220
|
+
#
|
234
221
|
# ==== Example:
|
235
222
|
#
|
236
223
|
# block.pending? #=> false
|
237
224
|
#
|
225
|
+
# @param allow_unconfirmed [Boolean] +false+ by default. When +false+,
|
226
|
+
# will only include blocks which have their confirmation height set
|
227
|
+
# or are undergoing confirmation height processing.
|
238
228
|
# @return [Boolean] signalling if the block is a pending block.
|
239
|
-
def pending?
|
240
|
-
|
241
|
-
|
229
|
+
def pending?(allow_unconfirmed: false)
|
230
|
+
params = {
|
231
|
+
include_only_confirmed: !allow_unconfirmed,
|
232
|
+
_access: :exists
|
233
|
+
}
|
234
|
+
|
235
|
+
rpc(:pending_exists, :hash, params) == 1
|
242
236
|
end
|
243
237
|
|
244
|
-
#
|
238
|
+
# Returns an Array of block hashes in the account chain from (but not including) this block up to +count+
|
239
|
+
# (direction from open block up to frontier, from older blocks to newer). Will list all
|
240
|
+
# blocks up to frontier (latest block) of this chain when +count+ is set to +-1+.
|
245
241
|
#
|
246
|
-
#
|
242
|
+
# See also #ancestors.
|
247
243
|
#
|
248
|
-
# ====
|
244
|
+
# ==== Example:
|
249
245
|
#
|
250
|
-
# block.
|
246
|
+
# block.descendants # => [Nanook::Block, .. ]
|
251
247
|
#
|
252
|
-
# @
|
253
|
-
|
254
|
-
|
248
|
+
# @param limit [Integer] maximum number of send/receive block hashes
|
249
|
+
# to return in the chain (default is 1000)
|
250
|
+
# @param offset [Integer] return the account chain block hashes offset
|
251
|
+
# by the specified number of blocks (default is 0)
|
252
|
+
# @return [Array<Nanook::Block>] blocks in the account chain ending at this block
|
253
|
+
def descendants(limit: 1000, offset: 0)
|
254
|
+
# The RPC includes this block in its response, and Nanook will remove it from the results.
|
255
|
+
# Increment the limit by 1 to account for this (a limit of -1 is valid and means no limit).
|
256
|
+
limit += 1 if limit > 0
|
257
|
+
|
258
|
+
params = {
|
259
|
+
count: limit,
|
260
|
+
offset: offset,
|
261
|
+
_access: :blocks,
|
262
|
+
_coerce: Array
|
263
|
+
}
|
264
|
+
|
265
|
+
response = rpc(:successors, :block, params)[1..].to_a
|
266
|
+
response.map { |block| as_block(block) }
|
255
267
|
end
|
256
|
-
|
268
|
+
alias successors descendants # `successors` is the RPC command name
|
257
269
|
|
258
|
-
# Returns
|
259
|
-
#
|
270
|
+
# Returns the {Nanook::Account} of the block representative.
|
271
|
+
#
|
272
|
+
# ==== Example:
|
273
|
+
# block.representative # => Nanook::Account
|
260
274
|
#
|
261
|
-
#
|
275
|
+
# @return [Nanook::Account] representative account of the block. Can be nil.
|
276
|
+
def representative
|
277
|
+
memoized_info[:representative]
|
278
|
+
end
|
279
|
+
|
280
|
+
# Returns the {Nanook::Account} of the block.
|
262
281
|
#
|
263
282
|
# ==== Example:
|
283
|
+
# block.account # => Nanook::Account
|
264
284
|
#
|
265
|
-
#
|
285
|
+
# @return [Nanook::Account] the account of the block. Can be nil.
|
286
|
+
def account
|
287
|
+
memoized_info[:account]
|
288
|
+
end
|
289
|
+
|
290
|
+
# Returns the amount of the block.
|
266
291
|
#
|
267
|
-
# ==== Example
|
292
|
+
# ==== Example:
|
293
|
+
# block.amount # => 3.01
|
268
294
|
#
|
269
|
-
#
|
295
|
+
# @param unit (see Nanook::Account#balance)
|
296
|
+
# @raise [Nanook::NanoUnitError] if `unit` is invalid
|
297
|
+
# @return [Float]
|
298
|
+
def amount(unit: Nanook.default_unit)
|
299
|
+
validate_unit!(unit)
|
300
|
+
|
301
|
+
amount = memoized_info[:amount]
|
302
|
+
return amount unless unit == :nano
|
303
|
+
|
304
|
+
raw_to_NANO(amount)
|
305
|
+
end
|
306
|
+
|
307
|
+
# Returns the balance of the account at the time the block was created.
|
270
308
|
#
|
271
|
-
#
|
272
|
-
#
|
273
|
-
#
|
274
|
-
#
|
275
|
-
# @
|
276
|
-
|
277
|
-
|
278
|
-
|
309
|
+
# ==== Example:
|
310
|
+
# block.balance # => 3.01
|
311
|
+
#
|
312
|
+
# @param unit (see Nanook::Account#balance)
|
313
|
+
# @raise [Nanook::NanoUnitError] if `unit` is invalid
|
314
|
+
# @return [Float]
|
315
|
+
def balance(unit: Nanook.default_unit)
|
316
|
+
validate_unit!(unit)
|
317
|
+
|
318
|
+
balance = memoized_info[:balance]
|
319
|
+
return balance unless unit == :nano
|
320
|
+
|
321
|
+
raw_to_NANO(balance)
|
322
|
+
end
|
323
|
+
|
324
|
+
# Returns true if block is confirmed.
|
325
|
+
#
|
326
|
+
# ==== Example:
|
327
|
+
# block.confirmed # => true
|
328
|
+
#
|
329
|
+
# @return [Boolean]
|
330
|
+
def confirmed?
|
331
|
+
memoized_info[:confirmed]
|
332
|
+
end
|
333
|
+
alias checked? confirmed?
|
334
|
+
|
335
|
+
# Returns true if block is unconfirmed.
|
336
|
+
#
|
337
|
+
# ==== Example:
|
338
|
+
# block.unconfirmed? # => true
|
339
|
+
#
|
340
|
+
# @return [Boolean]
|
341
|
+
def unconfirmed?
|
342
|
+
!confirmed?
|
343
|
+
end
|
344
|
+
alias unchecked? unconfirmed?
|
345
|
+
|
346
|
+
# Returns true if block exists in the node's ledger. This will return
|
347
|
+
# false for blocks that exist on the nano ledger but have not yet
|
348
|
+
# synchronized to the node.
|
349
|
+
#
|
350
|
+
# ==== Example:
|
351
|
+
#
|
352
|
+
# block.exists? # => false
|
353
|
+
# block.exists?(allow_unchecked: true) # => true
|
354
|
+
#
|
355
|
+
# @param allow_unchecked [Boolean] defaults to +false+
|
356
|
+
# @return [Boolean]
|
357
|
+
def exists?(allow_unchecked: false)
|
358
|
+
begin
|
359
|
+
allow_unchecked ? memoized_info : info
|
360
|
+
rescue Nanook::NodeRpcError
|
361
|
+
return false
|
362
|
+
end
|
363
|
+
|
364
|
+
true
|
365
|
+
end
|
366
|
+
|
367
|
+
# Returns the {Nanook::Block} of the next (newer) block in the account chain.
|
368
|
+
#
|
369
|
+
# ==== Example:
|
370
|
+
# block.next # => Nanook::Block
|
371
|
+
#
|
372
|
+
# @return [Nanook::Block] next (newer) block in the account chain. Can be nil.
|
373
|
+
def next
|
374
|
+
successors(limit: 1).first
|
375
|
+
end
|
376
|
+
|
377
|
+
# Returns the height of the block.
|
378
|
+
#
|
379
|
+
# ==== Example:
|
380
|
+
# block.height # => 5
|
381
|
+
#
|
382
|
+
# @return [Integer]
|
383
|
+
def height
|
384
|
+
memoized_info[:height]
|
385
|
+
end
|
386
|
+
|
387
|
+
# Returns the block work.
|
388
|
+
#
|
389
|
+
# ==== Example:
|
390
|
+
# block.work # => "8a142e07a10996d5"
|
391
|
+
#
|
392
|
+
# @return [String]
|
393
|
+
def work
|
394
|
+
memoized_info[:work]
|
279
395
|
end
|
280
396
|
|
281
|
-
|
282
|
-
|
397
|
+
# Returns the block signature.
|
398
|
+
#
|
399
|
+
# ==== Example:
|
400
|
+
# block.signature # => "82D41BC16F313E4B2243D14DFFA2FB04679C540C2095FEE7EAE0F2F26880AD56DD48D87A7CC5DD760C5B2D76EE2C205506AA557BF00B60D8DEE312EC7343A501"
|
401
|
+
#
|
402
|
+
# @return [String]
|
403
|
+
def signature
|
404
|
+
memoized_info[:signature]
|
283
405
|
end
|
284
406
|
|
407
|
+
# Returns the timestamp of when the node saw the block.
|
408
|
+
#
|
409
|
+
# ==== Example:
|
410
|
+
# block.timestamp # => 2018-05-30 16:41:48 UTC
|
411
|
+
#
|
412
|
+
# @return [Time] Time in UTC of when the node saw the block. Can be nil.
|
413
|
+
def timestamp
|
414
|
+
memoized_info[:local_timestamp]
|
415
|
+
end
|
416
|
+
|
417
|
+
# Returns the {Nanook::Block} of the previous (older) block in the account chain.
|
418
|
+
#
|
419
|
+
# ==== Example:
|
420
|
+
# block.previous # => Nanook::Block
|
421
|
+
#
|
422
|
+
# @return [Nanook::Block] previous (older) block in the account chain. Can be nil.
|
423
|
+
def previous
|
424
|
+
memoized_info[:previous]
|
425
|
+
end
|
426
|
+
|
427
|
+
# Returns the type of the block. One of "open", "send", "receive", "change", "epoch".
|
428
|
+
#
|
429
|
+
# ==== Example:
|
430
|
+
# block.type # => "open"
|
431
|
+
#
|
432
|
+
# @return [String] type of block. Returns nil for unconfirmed blocks.
|
433
|
+
def type
|
434
|
+
memoized_info[:type]
|
435
|
+
end
|
436
|
+
|
437
|
+
# Returns true if block is type "send".
|
438
|
+
#
|
439
|
+
# ==== Example:
|
440
|
+
# block.send? # => true
|
441
|
+
#
|
442
|
+
# @return [Boolean]
|
443
|
+
def send?
|
444
|
+
type == 'send'
|
445
|
+
end
|
446
|
+
|
447
|
+
# Returns true if block is type "open".
|
448
|
+
#
|
449
|
+
# ==== Example:
|
450
|
+
# block.open? # => true
|
451
|
+
#
|
452
|
+
# @return [Boolean]
|
453
|
+
def open?
|
454
|
+
type == 'open'
|
455
|
+
end
|
456
|
+
|
457
|
+
# Returns true if block is type "receive".
|
458
|
+
#
|
459
|
+
# ==== Example:
|
460
|
+
# block.receive? # => true
|
461
|
+
#
|
462
|
+
# @return [Boolean]
|
463
|
+
def receive?
|
464
|
+
type == 'receive'
|
465
|
+
end
|
466
|
+
|
467
|
+
# Returns true if block is type "change" (change of representative).
|
468
|
+
#
|
469
|
+
# ==== Example:
|
470
|
+
# block.change? # => true
|
471
|
+
#
|
472
|
+
# @return [Boolean]
|
473
|
+
def change?
|
474
|
+
type == 'change'
|
475
|
+
end
|
476
|
+
|
477
|
+
# Returns true if block is type "epoch".
|
478
|
+
#
|
479
|
+
# ==== Example:
|
480
|
+
# block.epoch? # => true
|
481
|
+
#
|
482
|
+
# @return [Boolean]
|
483
|
+
def epoch?
|
484
|
+
type == 'epoch'
|
485
|
+
end
|
486
|
+
|
487
|
+
# @return [String]
|
488
|
+
def to_s
|
489
|
+
"#{self.class.name}(id: \"#{short_id}\")"
|
490
|
+
end
|
491
|
+
alias inspect to_s
|
492
|
+
|
285
493
|
private
|
286
494
|
|
287
495
|
# Some RPC calls expect the param that represents the block to be named
|
288
496
|
# "hash", and others "block".
|
289
497
|
# The param_name argument allows us to specify which it should be for this call.
|
290
|
-
def rpc(action, param_name, params={})
|
291
|
-
p =
|
498
|
+
def rpc(action, param_name, params = {})
|
499
|
+
p = { param_name.to_sym => @block }
|
292
500
|
@rpc.call(action, p.merge(params))
|
293
501
|
end
|
294
502
|
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
end
|
503
|
+
# Memoize the `#info` response as we can refer to it for other methods (`type`, `#open?`, `#send?` etc.)
|
504
|
+
def memoized_info
|
505
|
+
@memoized_info ||= info(allow_unchecked: true, unit: :raw)
|
299
506
|
end
|
300
507
|
|
301
|
-
def
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
508
|
+
def parse_info_response(response, unit)
|
509
|
+
response.merge!(id: id)
|
510
|
+
contents = response.delete(:contents)
|
511
|
+
response.merge!(contents) if contents
|
512
|
+
|
513
|
+
response.delete(:block_account) # duplicate of contents.account
|
514
|
+
response[:last_modified_at] = response.delete(:modified_timestamp) # rename key
|
515
|
+
|
516
|
+
# `type` can be "open", "send", "receive", "change", "epoch" or "state".
|
517
|
+
# blocks with `type` == "state" may have a `subtype` that gives more information
|
518
|
+
# about the block ("send", "receive", "change", "epoch"), in which case replace
|
519
|
+
# the `type` with this value.
|
520
|
+
if response[:type] == 'state' && (subtype = response.delete(:subtype))
|
521
|
+
response[:type] = subtype
|
306
522
|
end
|
307
523
|
|
308
|
-
response
|
309
|
-
|
524
|
+
response[:account] = as_account(response[:account])
|
525
|
+
response[:representative] = as_account(response[:representative])
|
526
|
+
response[:previous] = as_block(response[:previous])
|
527
|
+
response[:link] = as_block(response[:link])
|
528
|
+
response[:link_as_account] = as_account(response[:link_as_account])
|
529
|
+
response[:local_timestamp] = as_time(response[:local_timestamp])
|
530
|
+
response[:last_modified_at] = as_time(response[:last_modified_at])
|
310
531
|
|
532
|
+
if unit == :nano
|
533
|
+
response[:amount] = raw_to_NANO(response[:amount])
|
534
|
+
response[:balance] = raw_to_NANO(response[:balance])
|
535
|
+
end
|
536
|
+
|
537
|
+
response.compact
|
538
|
+
end
|
311
539
|
end
|
312
540
|
end
|