nanook 2.5.0 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
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