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.
data/lib/nanook/block.rb CHANGED
@@ -1,5 +1,8 @@
1
- class Nanook
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 {Nanook::Account} of the block.
30
+ # Returns the block hash id.
28
31
  #
29
32
  # ==== Example:
30
- # block.account # => Nanook::Account
31
33
  #
32
- # @return [Nanook::Account] the account of the block
33
- def account
34
- Nanook::Account.new(@rpc, rpc(:block_account, :hash)[:account])
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
- # starting at block back to count (direction from frontier back to
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 #successors.
73
+ # See also #descendants.
55
74
  #
56
75
  # ==== Example:
57
76
  #
58
- # block.chain(limit: 2)
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 chain(limit: 1000, offset: 0)
70
- response = rpc(:chain, :block, count: limit, offset: offset)[:blocks]
71
- Nanook::Util.coerce_empty_string_to_type(response, Array)
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
- alias_method :ancestors, :chain
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. If confirmed, your block should
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)[:started] == 1
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)[:work]
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
- # :id=>"36A0FB717368BA8CF8D255B63DC207771EABC6C6FFC22A7F455EC2209464897E",
174
- # :type=>"send",
175
- # :previous=>"FBF8B0E6623A31AB528EBD839EEAA91CAFD25C12294C46754E45FD017F7939EB",
176
- # :destination=>"nano_3x7cjioqahgs5ppheys6prpqtb4rdknked83chf97bot1unrbdkaux37t31b",
177
- # :balance=>"00000000000000000000000000000000",
178
- # :work=>"44cc24b60705083a",
179
- # :signature=>"42ADFEFE7C3FFF188AE92A202F8A5734DE91779C454613E446EEC93D001D6C953E9FD16730AF32C891791BA8EDAECEB059A213E2FE1EEB7ADF9D5D0815464D06"
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
- def info(allow_unchecked: false)
185
- if allow_unchecked
186
- response = rpc(:unchecked_get, :hash)
187
- unless response.has_key?(:error)
188
- return _parse_info_response(response)
189
- end
190
- # If unchecked not found, continue to checked block
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 = rpc(:block, :hash)
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.is_valid_work?("2bf29ef00786a6bc") # => true
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 is_valid_work?(work)
187
+ def valid_work?(work)
204
188
  response = rpc(:work_validate, :hash, work: work)
205
- !response.empty? && response[:valid] == 1
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<String>] block hashes that were republished
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.new("You must provide either destinations or sources but not both")
202
+ raise ArgumentError, 'You must provide either destinations or sources but not both'
223
203
  end
224
204
 
225
- # Add in optional arguments
226
- params = {}
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 unless params.empty?
212
+ params[:count] = 1 if destinations || sources
230
213
 
231
- rpc(:republish, :hash, params)[:blocks]
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
- response = rpc(:pending_exists, :hash)
241
- !response.empty? && response[:exists] == 1
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
- # Publish the block to the nano network.
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
- # Note, if block has previously been published, use #republish instead.
242
+ # See also #ancestors.
247
243
  #
248
- # ==== Examples:
244
+ # ==== Example:
249
245
  #
250
- # block.publish # => "FBF8B0E..."
246
+ # block.descendants # => [Nanook::Block, .. ]
251
247
  #
252
- # @return [String] the block hash, or false.
253
- def publish
254
- rpc(:process, :block)[:hash] || false
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
- alias_method :process, :publish
268
+ alias successors descendants # `successors` is the RPC command name
257
269
 
258
- # Returns an Array of block hashes in the account chain ending at
259
- # this block.
270
+ # Returns the {Nanook::Account} of the block representative.
271
+ #
272
+ # ==== Example:
273
+ # block.representative # => Nanook::Account
260
274
  #
261
- # See also #chain.
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
- # block.successors
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 response:
292
+ # ==== Example:
293
+ # block.amount # => 3.01
268
294
  #
269
- # ["36A0FB717368BA8CF8D255B63DC207771EABC6C6FFC22A7F455EC2209464897E"]
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
- # @param limit [Integer] maximum number of send/receive block hashes
272
- # to return in the chain (default is 1000)
273
- # @param offset [Integer] return the account chain block hashes offset
274
- # by the specified number of blocks (default is 0)
275
- # @return [Array<String>] block hashes in the account chain ending at this block
276
- def successors(limit: 1000, offset: 0)
277
- response = rpc(:successors, :block, count: limit, offset: offset)[:blocks]
278
- Nanook::Util.coerce_empty_string_to_type(response, Array)
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
- def inspect
282
- "#{self.class.name}(id: \"#{id}\", object_id: \"#{"0x00%x" % (object_id << 1)}\")"
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 = @block.nil? ? {} : { param_name.to_sym => @block }
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
- def block_required!
296
- if @block.nil?
297
- raise ArgumentError.new("Block must be present")
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 _parse_info_response(response)
302
- # The contents is a stringified JSON
303
- if response[:contents]
304
- r = JSON.parse(response[:contents]).to_symbolized_hash
305
- return r.merge(id: id)
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
- end
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