nanook 2.1.0 → 2.5.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.
data/lib/nanook/block.rb CHANGED
@@ -45,8 +45,11 @@ class Nanook
45
45
  rpc(:work_cancel, :hash).empty?
46
46
  end
47
47
 
48
- # Returns an Array of block hashes in the account chain starting at
49
- # this block.
48
+ # Returns a consecutive list of block hashes in the account chain
49
+ # starting at block back to count (direction from frontier back to
50
+ # open block, from newer blocks to older). Will list all blocks back
51
+ # to the open block of this chain when count is set to "-1".
52
+ # The requested block hash is included in the answer.
50
53
  #
51
54
  # See also #successors.
52
55
  #
@@ -60,20 +63,66 @@ class Nanook
60
63
  # "36A0FB717368BA8CF8D255B63DC207771EABC6C6FFC22A7F455EC2209464897E",
61
64
  # "FBF8B0E6623A31AB528EBD839EEAA91CAFD25C12294C46754E45FD017F7939EB"
62
65
  # ]
66
+ #
63
67
  # @param limit [Integer] maximum number of block hashes to return (default is 1000)
64
- def chain(limit: 1000)
65
- response = rpc(:chain, :block, count: limit)[:blocks]
68
+ # @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]
66
71
  Nanook::Util.coerce_empty_string_to_type(response, Array)
67
72
  end
73
+ alias_method :ancestors, :chain
74
+
75
+ # Request confirmation for a block from online representative nodes.
76
+ # Will return immediately with a boolean to indicate if the request for
77
+ # 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?}
81
+ #
82
+ # ==== Example:
83
+ # block.confirm # => true
84
+ #
85
+ # @return [Boolean] if the confirmation request was sent successful
86
+ 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)
112
+ end
113
+ alias_method :recently_confirmed?, :confirmed_recently?
68
114
 
69
115
  # Generate work for a block.
70
116
  #
71
117
  # ==== Example:
72
118
  # block.generate_work # => "2bf29ef00786a6bc"
73
119
  #
120
+ # @param use_peers [Boolean] if set to +true+, then the node will query
121
+ # its work peers (if it has any, see {Nanook::WorkPeer#list}).
122
+ # When +false+, the node will only generate work locally (default is +false+)
74
123
  # @return [String] the work id of the work completed.
75
- def generate_work
76
- rpc(:work_generate, :hash)[:work]
124
+ def generate_work(use_peers: false)
125
+ rpc(:work_generate, :hash, use_peers: use_peers)[:work]
77
126
  end
78
127
 
79
128
  # Returns Array of Hashes containing information about a chain of
@@ -87,7 +136,7 @@ class Nanook
87
136
  #
88
137
  # [
89
138
  # {
90
- # :account=>"xrb_3x7cjioqahgs5ppheys6prpqtb4rdknked83chf97bot1unrbdkaux37t31b",
139
+ # :account=>"nano_3x7cjioqahgs5ppheys6prpqtb4rdknked83chf97bot1unrbdkaux37t31b",
91
140
  # :amount=>539834279601145558517940224,
92
141
  # :hash=>"36A0FB717368BA8CF8D255B63DC207771EABC6C6FFC22A7F455EC2209464897E",
93
142
  # :type=>"send"
@@ -124,7 +173,7 @@ class Nanook
124
173
  # :id=>"36A0FB717368BA8CF8D255B63DC207771EABC6C6FFC22A7F455EC2209464897E",
125
174
  # :type=>"send",
126
175
  # :previous=>"FBF8B0E6623A31AB528EBD839EEAA91CAFD25C12294C46754E45FD017F7939EB",
127
- # :destination=>"xrb_3x7cjioqahgs5ppheys6prpqtb4rdknked83chf97bot1unrbdkaux37t31b",
176
+ # :destination=>"nano_3x7cjioqahgs5ppheys6prpqtb4rdknked83chf97bot1unrbdkaux37t31b",
128
177
  # :balance=>"00000000000000000000000000000000",
129
178
  # :work=>"44cc24b60705083a",
130
179
  # :signature=>"42ADFEFE7C3FFF188AE92A202F8A5734DE91779C454613E446EEC93D001D6C953E9FD16730AF32C891791BA8EDAECEB059A213E2FE1EEB7ADF9D5D0815464D06"
@@ -220,10 +269,12 @@ class Nanook
220
269
  # ["36A0FB717368BA8CF8D255B63DC207771EABC6C6FFC22A7F455EC2209464897E"]
221
270
  #
222
271
  # @param limit [Integer] maximum number of send/receive block hashes
223
- # to return in the chain (default is 1000)
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)
224
275
  # @return [Array<String>] block hashes in the account chain ending at this block
225
- def successors(limit: 1000)
226
- response = rpc(:successors, :block, count: limit)[:blocks]
276
+ def successors(limit: 1000, offset: 0)
277
+ response = rpc(:successors, :block, count: limit, offset: offset)[:blocks]
227
278
  Nanook::Util.coerce_empty_string_to_type(response, Array)
228
279
  end
229
280
 
data/lib/nanook/error.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  class Nanook
2
+ # Standard error for Nanook
2
3
  class Error < StandardError
3
4
  end
4
5
  end
data/lib/nanook/node.rb CHANGED
@@ -1,31 +1,220 @@
1
1
  class Nanook
2
+
3
+ # The <tt>Nanook::Node</tt> class contains methods to manage your nano
4
+ # node and query its data of the nano network.
5
+ #
6
+ # Your node is constantly syncing data with other nodes on the network. When
7
+ # your node first starts up after being built, its database will be empty
8
+ # and it will begin synchronizing and downloading data of the nano ledger
9
+ # to its local database. The ledger is the central record of all accounts
10
+ # and transactions. Some of the methods in this class query your node's
11
+ # database formed from the nano ledger, and so the responses are determined
12
+ # by the completeness of your node's database.
13
+ #
14
+ # You can determine how synchronized your node is with the nano ledger
15
+ # with the {#sync_progress} method.
16
+ #
17
+ # === Initializing
18
+ #
19
+ # Initialize this class through the convenient {Nanook#node} method:
20
+ #
21
+ # node = Nanook.new.node
22
+ #
23
+ # Or compose the longhand way like this:
24
+ #
25
+ # rpc_conn = Nanook::Rpc.new
26
+ # node = Nanook::Node.new(rpc_conn)
2
27
  class Node
3
28
 
4
29
  def initialize(rpc)
5
30
  @rpc = rpc
6
31
  end
7
32
 
33
+ # The number of accounts in the nano ledger--essentially all
34
+ # accounts with _open_ blocks. An _open_ block
35
+ # is the type of block written to the nano ledger when an account
36
+ # receives its first payment (see {Nanook::WalletAccount#receive}). All accounts
37
+ # that respond +true+ to {Nanook::Account#exists?} have open blocks in the ledger.
38
+ #
39
+ # @return [Integer] number of accounts with _open_ blocks.
8
40
  def account_count
9
41
  rpc(:frontier_count)[:count]
10
42
  end
11
43
  alias_method :frontier_count, :account_count
12
44
 
45
+ # The count of all blocks downloaded to the node, and
46
+ # blocks still to be synchronized by the node.
47
+ #
48
+ # ==== Example:
49
+ #
50
+ #
51
+ #
52
+ # @return [Hash{Symbol=>Integer}] number of blocks and unchecked
53
+ # synchronizing blocks
13
54
  def block_count
14
55
  rpc(:block_count)
15
56
  end
16
57
 
17
- def block_count_type
58
+ # The count of all known blocks by their type.
59
+ #
60
+ # ==== Example:
61
+ #
62
+ # node.block_count_by_type
63
+ #
64
+ # Example response:
65
+ #
66
+ # {
67
+ # send: 1000,
68
+ # receive: 900,
69
+ # open: 900,
70
+ # change: 50
71
+ # }
72
+ #
73
+ # @return [Hash{Symbol=>Integer}] number of blocks by type
74
+ def block_count_by_type
18
75
  rpc(:block_count_type)
19
76
  end
77
+ alias_method :block_count_type, :block_count_by_type
20
78
 
79
+ # Initialize bootstrap to a specific IP address and port.
80
+ #
81
+ # @return [Boolean] indicating if the action was successful
21
82
  def bootstrap(address:, port:)
22
83
  rpc(:bootstrap, address: address, port: port).has_key?(:success)
23
84
  end
24
85
 
86
+ # Initialize multi-connection bootstrap to random peers
87
+ #
88
+ # @return [Boolean] indicating if the action was successful
25
89
  def bootstrap_any
26
90
  rpc(:bootstrap_any).has_key?(:success)
27
91
  end
28
92
 
93
+ # Initialize lazy bootstrap with given block hash
94
+ #
95
+ # @param hash [String]
96
+ # @param force [Boolean] False by default. Manually force closing
97
+ # of all current bootstraps
98
+ # @return [Boolean] indicating if the action was successful
99
+ def bootstrap_lazy(hash, force: false)
100
+ rpc(:bootstrap_lazy, hash: hash, force: force)[:started] == 1
101
+ end
102
+
103
+ # Returning status of current bootstrap attempt for debug purposes only.
104
+ # This call is for internal diagnostics/debug purposes only.
105
+ # Do not rely on this interface being stable and do not use in a
106
+ # production system.
107
+ #
108
+ # ==== Example:
109
+ #
110
+ # node.bootstrap_status
111
+ #
112
+ # Example response:
113
+ #
114
+ # {
115
+ # clients: 5790,
116
+ # pulls: 141065,
117
+ # pulling: 3,
118
+ # connections: 16,
119
+ # idle: 0,
120
+ # target_connections: 64,
121
+ # total_blocks: 536820,
122
+ # lazy_mode: true,
123
+ # lazy_blocks: 423388,
124
+ # lazy_state_unknown: 2,
125
+ # lazy_balances: 0,
126
+ # lazy_pulls: 0,
127
+ # lazy_stopped: 644,
128
+ # lazy_keys: 449,
129
+ # lazy_key_1: "A86EB2B479AAF3CD531C8356A1FBE3CB500DFBF5BF292E5E6B8D1048DE199C32"
130
+ # }
131
+ #
132
+ # @return [Hash{Symbol=>String|Integer|Boolean}]
133
+ def bootstrap_status
134
+ rpc(:bootstrap_status)
135
+ end
136
+
137
+ # This call is for internal diagnostics/debug purposes only.
138
+ # Do not rely on this interface being stable and do not use in a
139
+ # production system.
140
+ #
141
+ # Returns block and tally weight (in raw) election duration (in
142
+ # milliseconds), election confirmation timestamp for recent elections
143
+ # winners.
144
+ #
145
+ # ==== Example:
146
+ #
147
+ # node.confirmation_history
148
+ #
149
+ # Example response:
150
+ #
151
+ # [
152
+ # {
153
+ # block: "EA70B32C55C193345D625F766EEA2FCA52D3F2CCE0B3A30838CC543026BB0FEA",
154
+ # tally: 80394786589602980996311817874549318248,
155
+ # duration: 4000,
156
+ # time: 1544819986,
157
+ # },
158
+ # {
159
+ # block: "F2F8DA6D2CA0A4D78EB043A7A29E12BDE5B4CE7DE1B99A93A5210428EE5B8667",
160
+ # tally: 68921714529890443063672782079965877749,
161
+ # duration: 6000,
162
+ # time: 1544819988,
163
+ # }
164
+ # ]
165
+ #
166
+ # @return [Hash{Symbol=>String|Integer}]
167
+ def confirmation_history
168
+ rpc(:confirmation_history)[:confirmations].map do |history|
169
+ # Rename hash key to block
170
+ block = history.delete(:hash)
171
+ {block: block}.merge(history)
172
+ end
173
+ end
174
+
175
+ # Returns the difficulty values (16 hexadecimal digits string, 64 bit)
176
+ # for the minimum required on the network (network_minimum) as well
177
+ # as the current active difficulty seen on the network (network_current,
178
+ # 5 minute trended average of adjusted difficulty seen on confirmed
179
+ # transactions) which can be used to perform rework for better
180
+ # prioritization of transaction processing. A multiplier of the
181
+ # network_current from the base difficulty of network_minimum is also
182
+ # provided for comparison.
183
+ #
184
+ # ==== Example:
185
+ #
186
+ # node.difficulty(include_trend: true)
187
+ #
188
+ # Example response:
189
+ #
190
+ # {
191
+ # network_minimum: "ffffffc000000000",
192
+ # network_current: "ffffffc1816766f2",
193
+ # multiplier: 1.024089858417128,
194
+ # difficulty_trend: [
195
+ # 1.156096135149775,
196
+ # 1.190133894573061,
197
+ # 1.135567138563921,
198
+ # 1.000000000000000,
199
+ # ]
200
+ # }
201
+ #
202
+ # @param include_trend [Boolean] false by default. Also returns the
203
+ # trend of difficulty seen on the network as a list of multipliers.
204
+ # Sampling occurs every 16 to 36 seconds. The list is ordered such
205
+ # that the first value is the most recent sample.
206
+ # @return [Hash{Symbol=>String|Float|Array}]
207
+ def difficulty(include_trend: false)
208
+ rpc(:active_difficulty, include_trend: include_trend).tap do |response|
209
+ response[:multiplier] = response[:multiplier].to_f
210
+
211
+ if response.key?(:difficulty_trend)
212
+ response[:difficulty_trend].map!(&:to_f)
213
+ end
214
+ end
215
+ end
216
+
217
+ # @return [String]
29
218
  def inspect
30
219
  "#{self.class.name}(object_id: \"#{"0x00%x" % (object_id << 1)}\")"
31
220
  end
@@ -34,14 +223,60 @@ class Nanook
34
223
  rpc(:peers)[:peers]
35
224
  end
36
225
 
37
- def representatives
38
- rpc(:representatives)[:representatives]
226
+ # All representatives and their voting weight.
227
+ #
228
+ # ==== Example:
229
+ #
230
+ # node.representatives
231
+ #
232
+ # Example response:
233
+ #
234
+ # {
235
+ # nano_1111111111111111111111111111111111111111111111111117353trpda: 3822372327060170000000000000000000000,
236
+ # nano_1111111111111111111111111111111111111111111111111awsq94gtecn: 30999999999999999999999999000000,
237
+ # nano_114nk4rwjctu6n6tr6g6ps61g1w3hdpjxfas4xj1tq6i8jyomc5d858xr1xi: 0
238
+ # }
239
+ #
240
+ # @return [Hash{Symbol=>Integer}] known representatives and their voting weight
241
+ def representatives(unit: Nanook.default_unit)
242
+ unless Nanook::UNITS.include?(unit)
243
+ raise ArgumentError.new("Unsupported unit: #{unit}")
244
+ end
245
+
246
+ response = rpc(:representatives)[:representatives]
247
+ return response if unit == :raw
248
+
249
+ r = response.map do |account_id, balance|
250
+ balance = Nanook::Util.raw_to_NANO(balance)
251
+
252
+ [account_id, balance]
253
+ end
254
+
255
+ Hash[r].to_symbolized_hash
256
+ end
257
+
258
+ # All online representatives that have voted recently. Note, due to the
259
+ # design of the nano RPC, this method cannot return the voting weight
260
+ # of the representatives.
261
+ #
262
+ # ==== Example:
263
+ #
264
+ # node.representatives_online # => ["nano_111...", "nano_222"]
265
+ #
266
+ # @return [Array<String>] array of representative account ids
267
+ def representatives_online
268
+ rpc(:representatives_online)[:representatives].keys.map(&:to_s)
39
269
  end
40
270
 
271
+ # Safely shuts down the node.
272
+ #
273
+ # @return [Boolean] indicating if action was successful
41
274
  def stop
42
275
  rpc(:stop).has_key?(:success)
43
276
  end
44
277
 
278
+ # @param limit [Integer] number of synchronizing blocks to return
279
+ # @return [Hash{Symbol=>String}] information about the synchronizing blocks for this node
45
280
  def synchronizing_blocks(limit: 1000)
46
281
  response = rpc(:unchecked, count: limit)[:blocks]
47
282
  response = response.map do |block, info|
@@ -49,7 +284,16 @@ class Nanook
49
284
  end
50
285
  Hash[response.sort].to_symbolized_hash
51
286
  end
287
+ alias_method :unchecked, :synchronizing_blocks
52
288
 
289
+ # The percentage completeness of the synchronization process for
290
+ # your node as it downloads the nano ledger. Note, it's normal for
291
+ # your progress to not ever reach 100. The closer to 100, the more
292
+ # complete your node's data is, and so the query methods in this class
293
+ # become more reliable.
294
+ #
295
+ # @return [Float] the percentage completeness of the synchronization
296
+ # process for your node
53
297
  def sync_progress
54
298
  response = rpc(:block_count)
55
299
 
@@ -60,13 +304,27 @@ class Nanook
60
304
  count.to_f * 100 / total.to_f
61
305
  end
62
306
 
307
+ # Returns node uptime in seconds
308
+ #
309
+ # @return [Integer] seconds of uptime
310
+ def uptime
311
+ rpc(:uptime)['seconds']
312
+ end
313
+
314
+ # This method is deprecated and will be removed in 3.0, as a node never
315
+ # reaches 100% synchronization.
316
+ #
317
+ # @return [Boolean] signalling if this node ever reaches 100% synchronized
63
318
  def synced?
319
+ warn "[DEPRECATION] `synced?` is deprecated and will be removed in 3.0"
64
320
  rpc(:block_count)[:unchecked] == 0
65
321
  end
66
322
 
323
+ # @return [Hash{Symbol=>Integer|String}] version information for this node
67
324
  def version
68
325
  rpc(:version)
69
326
  end
327
+ alias_method :info, :version
70
328
 
71
329
  private
72
330