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