nanook 2.5.1 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +99 -0
- data/README.md +135 -85
- data/bin/console +4 -3
- data/lib/nanook.rb +76 -20
- data/lib/nanook/account.rb +232 -164
- data/lib/nanook/block.rb +343 -150
- data/lib/nanook/errors.rb +10 -0
- data/lib/nanook/node.rb +164 -132
- 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 +67 -18
- data/lib/nanook/version.rb +3 -1
- data/lib/nanook/wallet.rb +348 -161
- data/lib/nanook/wallet_account.rb +148 -88
- data/lib/nanook/work_peer.rb +14 -7
- metadata +20 -18
- data/lib/nanook/error.rb +0 -5
- data/lib/nanook/key.rb +0 -46
data/lib/nanook/node.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::Node</tt> class contains methods to manage your nano
|
4
7
|
# node and query its data of the nano network.
|
5
8
|
#
|
@@ -25,6 +28,7 @@ class Nanook
|
|
25
28
|
# rpc_conn = Nanook::Rpc.new
|
26
29
|
# node = Nanook::Node.new(rpc_conn)
|
27
30
|
class Node
|
31
|
+
include Nanook::Util
|
28
32
|
|
29
33
|
def initialize(rpc)
|
30
34
|
@rpc = rpc
|
@@ -38,56 +42,46 @@ class Nanook
|
|
38
42
|
#
|
39
43
|
# @return [Integer] number of accounts with _open_ blocks.
|
40
44
|
def account_count
|
41
|
-
rpc(:frontier_count
|
45
|
+
rpc(:frontier_count, _access: :count)
|
42
46
|
end
|
43
|
-
|
47
|
+
alias frontier_count account_count
|
44
48
|
|
45
49
|
# The count of all blocks downloaded to the node, and
|
46
50
|
# blocks still to be synchronized by the node.
|
47
51
|
#
|
48
52
|
# ==== Example:
|
49
53
|
#
|
50
|
-
#
|
54
|
+
# {
|
55
|
+
# count: 100,
|
56
|
+
# unchecked: 10,
|
57
|
+
# cemented: 25
|
58
|
+
# }
|
51
59
|
#
|
52
60
|
# @return [Hash{Symbol=>Integer}] number of blocks and unchecked
|
53
61
|
# synchronizing blocks
|
54
62
|
def block_count
|
55
|
-
rpc(:block_count)
|
63
|
+
rpc(:block_count, _coerce: Hash)
|
56
64
|
end
|
57
65
|
|
58
|
-
#
|
59
|
-
#
|
60
|
-
# ==== Example:
|
61
|
-
#
|
62
|
-
# node.block_count_by_type
|
66
|
+
# Tells the node to send a keepalive packet to a specific IP address and port.
|
63
67
|
#
|
64
|
-
#
|
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
|
75
|
-
rpc(:block_count_type)
|
68
|
+
# @return [Boolean] indicating if the action was successful
|
69
|
+
def keepalive(address:, port:)
|
70
|
+
rpc(:keepalive, address: address, port: port).key?(:started)
|
76
71
|
end
|
77
|
-
alias_method :block_count_type, :block_count_by_type
|
78
72
|
|
79
73
|
# Initialize bootstrap to a specific IP address and port.
|
80
74
|
#
|
81
75
|
# @return [Boolean] indicating if the action was successful
|
82
76
|
def bootstrap(address:, port:)
|
83
|
-
rpc(:bootstrap, address: address, port: port).
|
77
|
+
rpc(:bootstrap, address: address, port: port).key?(:success)
|
84
78
|
end
|
85
79
|
|
86
80
|
# Initialize multi-connection bootstrap to random peers
|
87
81
|
#
|
88
82
|
# @return [Boolean] indicating if the action was successful
|
89
83
|
def bootstrap_any
|
90
|
-
rpc(:bootstrap_any).
|
84
|
+
rpc(:bootstrap_any).key?(:success)
|
91
85
|
end
|
92
86
|
|
93
87
|
# Initialize lazy bootstrap with given block hash
|
@@ -97,79 +91,49 @@ class Nanook
|
|
97
91
|
# of all current bootstraps
|
98
92
|
# @return [Boolean] indicating if the action was successful
|
99
93
|
def bootstrap_lazy(hash, force: false)
|
100
|
-
rpc(:bootstrap_lazy, hash: hash, force: force
|
94
|
+
rpc(:bootstrap_lazy, hash: hash, force: force, _access: :started) == 1
|
101
95
|
end
|
102
96
|
|
103
|
-
#
|
104
|
-
#
|
105
|
-
#
|
106
|
-
#
|
97
|
+
# Returns information about node elections settings and observed network state:
|
98
|
+
#
|
99
|
+
# - `quorum_delta`: delta tally required to rollback block
|
100
|
+
# - `online_weight_quorum_percent`: percentage of online weight for delta
|
101
|
+
# - `online_weight_minimum`: minimum online weight to confirm block
|
102
|
+
# - `online_stake_total`: currently observed online total weight
|
103
|
+
# - `peers_stake_total`: known peers total weight
|
104
|
+
# - `peers_stake_required`: effective stake needed from directly connected peers for quorum
|
107
105
|
#
|
108
106
|
# ==== Example:
|
109
107
|
#
|
110
|
-
# node.
|
108
|
+
# node.confirmation_quorum
|
111
109
|
#
|
112
110
|
# Example response:
|
113
111
|
#
|
114
112
|
# {
|
115
|
-
#
|
116
|
-
#
|
117
|
-
#
|
118
|
-
#
|
119
|
-
#
|
120
|
-
#
|
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"
|
113
|
+
# "quorum_delta": 43216377.43025059,
|
114
|
+
# "online_weight_quorum_percent": 50,
|
115
|
+
# "online_weight_minimum": 60000000.0",
|
116
|
+
# "online_stake_total": 86432754.86050119,
|
117
|
+
# "peers_stake_total": 84672338.52479072,
|
118
|
+
# "peers_stake_required": 60000000.0"
|
130
119
|
# }
|
131
120
|
#
|
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
121
|
# @return [Hash{Symbol=>String|Integer}]
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
122
|
+
# @raise [Nanook::NanoUnitError] if `unit` is invalid
|
123
|
+
def confirmation_quorum(unit: Nanook.default_unit)
|
124
|
+
validate_unit!(unit)
|
125
|
+
|
126
|
+
response = rpc(:confirmation_quorum, _coerce: Hash)
|
127
|
+
|
128
|
+
return response unless unit == :nano
|
129
|
+
|
130
|
+
response[:quorum_delta] = raw_to_NANO(response[:quorum_delta])
|
131
|
+
response[:online_weight_minimum] = raw_to_NANO(response[:online_weight_minimum])
|
132
|
+
response[:online_stake_total] = raw_to_NANO(response[:online_stake_total])
|
133
|
+
response[:peers_stake_total] = raw_to_NANO(response[:peers_stake_total])
|
134
|
+
response[:peers_stake_required] = raw_to_NANO(response[:peers_stake_required])
|
135
|
+
|
136
|
+
response.compact
|
173
137
|
end
|
174
138
|
|
175
139
|
# Returns the difficulty values (16 hexadecimal digits string, 64 bit)
|
@@ -205,22 +169,35 @@ class Nanook
|
|
205
169
|
# that the first value is the most recent sample.
|
206
170
|
# @return [Hash{Symbol=>String|Float|Array}]
|
207
171
|
def difficulty(include_trend: false)
|
208
|
-
rpc(:active_difficulty, include_trend: include_trend).tap do |response|
|
172
|
+
rpc(:active_difficulty, include_trend: include_trend, _coerce: Hash).tap do |response|
|
209
173
|
response[:multiplier] = response[:multiplier].to_f
|
210
174
|
|
211
|
-
if response.key?(:difficulty_trend)
|
212
|
-
response[:difficulty_trend].map!(&:to_f)
|
213
|
-
end
|
175
|
+
response[:difficulty_trend].map!(&:to_f) if response.key?(:difficulty_trend)
|
214
176
|
end
|
215
177
|
end
|
216
178
|
|
217
179
|
# @return [String]
|
218
|
-
def
|
219
|
-
|
180
|
+
def to_s
|
181
|
+
self.class.name
|
220
182
|
end
|
183
|
+
alias inspect to_s
|
221
184
|
|
185
|
+
# Returns peers information.
|
186
|
+
#
|
187
|
+
# Example response:
|
188
|
+
#
|
189
|
+
# {
|
190
|
+
# :"[::ffff:104.131.102.132]:7075" => {
|
191
|
+
# protocol_version: 20,
|
192
|
+
# node_id: "node_1y7j5rdqhg99uyab1145gu3yur1ax35a3b6qr417yt8cd6n86uiw3d4whty3",
|
193
|
+
# type: "udp"
|
194
|
+
# },
|
195
|
+
# :"[::ffff:104.131.114.102]:7075" => { ... }
|
196
|
+
# }
|
197
|
+
#
|
198
|
+
# @return [Hash{Symbol=>Hash{Symbol=>Integer|String}}]
|
222
199
|
def peers
|
223
|
-
rpc(:peers
|
200
|
+
rpc(:peers, peer_details: true, _access: :peers, _coerce: Hash)
|
224
201
|
end
|
225
202
|
|
226
203
|
# All representatives and their voting weight.
|
@@ -232,59 +209,86 @@ class Nanook
|
|
232
209
|
# Example response:
|
233
210
|
#
|
234
211
|
# {
|
235
|
-
#
|
236
|
-
#
|
237
|
-
#
|
212
|
+
# Nanook::Account: 3822372327060170000000000000000000000,
|
213
|
+
# Nanook::Account: 30999999999999999999999999000000,
|
214
|
+
# Nanook::Account: 0
|
238
215
|
# }
|
239
216
|
#
|
240
|
-
# @return [Hash{
|
217
|
+
# @return [Hash{Nanook::Account=>Float|Integer}] known representatives and their voting weight
|
218
|
+
# @raise [Nanook::NanoUnitError] if `unit` is invalid
|
241
219
|
def representatives(unit: Nanook.default_unit)
|
242
|
-
|
243
|
-
raise ArgumentError.new("Unsupported unit: #{unit}")
|
244
|
-
end
|
220
|
+
validate_unit!(unit)
|
245
221
|
|
246
|
-
response = rpc(:representatives
|
247
|
-
return response if unit == :raw
|
222
|
+
response = rpc(:representatives, _access: :representatives, _coerce: Hash)
|
248
223
|
|
249
|
-
r = response.map do |account_id,
|
250
|
-
|
224
|
+
r = response.map do |account_id, weight|
|
225
|
+
weight = raw_to_NANO(weight) if unit == :nano
|
251
226
|
|
252
|
-
[account_id,
|
227
|
+
[as_account(account_id), weight]
|
253
228
|
end
|
254
229
|
|
255
|
-
Hash[r]
|
230
|
+
Hash[r]
|
256
231
|
end
|
257
232
|
|
258
|
-
# All online representatives that have voted recently
|
259
|
-
# design of the nano RPC, this method cannot return the voting weight
|
260
|
-
# of the representatives.
|
233
|
+
# All online representatives that have voted recently and their weight.
|
261
234
|
#
|
262
235
|
# ==== Example:
|
263
236
|
#
|
264
|
-
# node.representatives_online # => [
|
237
|
+
# node.representatives_online # => [Nanook::Account, ...]
|
265
238
|
#
|
266
|
-
# @return [
|
239
|
+
# @return [Nanook::Account] array of representative accounts
|
267
240
|
def representatives_online
|
268
|
-
rpc(:representatives_online
|
241
|
+
rpc(:representatives_online, _access: :representatives, _coerce: Array).map do |representative|
|
242
|
+
as_account(representative)
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
# Tells the node to look for any account in all available wallets.
|
247
|
+
#
|
248
|
+
# ==== Example:
|
249
|
+
#
|
250
|
+
# node.search_pending #=> true
|
251
|
+
# @return [Boolean] indicates if the action was successful
|
252
|
+
def search_pending
|
253
|
+
rpc(:search_pending_all).key?(:success)
|
269
254
|
end
|
270
255
|
|
271
256
|
# Safely shuts down the node.
|
272
257
|
#
|
273
258
|
# @return [Boolean] indicating if action was successful
|
274
259
|
def stop
|
275
|
-
rpc(:stop).
|
260
|
+
rpc(:stop).key?(:success)
|
276
261
|
end
|
277
262
|
|
278
263
|
# @param limit [Integer] number of synchronizing blocks to return
|
264
|
+
# @param unit (see Nanook::Account#balance)
|
265
|
+
#
|
279
266
|
# @return [Hash{Symbol=>String}] information about the synchronizing blocks for this node
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
267
|
+
# @raise [Nanook::NanoUnitError] if `unit` is invalid
|
268
|
+
def synchronizing_blocks(limit: 1000, unit: Nanook.default_unit)
|
269
|
+
validate_unit!(unit)
|
270
|
+
|
271
|
+
params = {
|
272
|
+
count: limit,
|
273
|
+
json_block: true,
|
274
|
+
_access: :blocks,
|
275
|
+
_coerce: Hash
|
276
|
+
}
|
277
|
+
|
278
|
+
response = rpc(:unchecked, params).map do |block, info|
|
279
|
+
info[:account] = as_account(info[:account]) if info[:account]
|
280
|
+
info[:link_as_account] = as_account(info[:link_as_account]) if info[:link_as_account]
|
281
|
+
info[:representative] = as_account(info[:representative]) if info[:representative]
|
282
|
+
info[:previous] = as_block(info[:previous]) if info[:previous]
|
283
|
+
info[:link] = as_block(info[:link]) if info[:link]
|
284
|
+
info[:balance] = raw_to_NANO(info[:balance]) if unit == :nano && info[:balance]
|
285
|
+
|
286
|
+
[as_block(block), info]
|
284
287
|
end
|
285
|
-
|
288
|
+
|
289
|
+
Hash[response]
|
286
290
|
end
|
287
|
-
|
291
|
+
alias unchecked synchronizing_blocks
|
288
292
|
|
289
293
|
# The percentage completeness of the synchronization process for
|
290
294
|
# your node as it downloads the nano ledger. Note, it's normal for
|
@@ -295,11 +299,11 @@ class Nanook
|
|
295
299
|
# @return [Float] the percentage completeness of the synchronization
|
296
300
|
# process for your node
|
297
301
|
def sync_progress
|
298
|
-
response = rpc(:block_count)
|
302
|
+
response = rpc(:block_count, _coerce: Hash)
|
299
303
|
|
300
304
|
count = response[:count]
|
301
305
|
unchecked = response[:unchecked]
|
302
|
-
total =
|
306
|
+
total = count + unchecked
|
303
307
|
|
304
308
|
count.to_f * 100 / total.to_f
|
305
309
|
end
|
@@ -308,29 +312,57 @@ class Nanook
|
|
308
312
|
#
|
309
313
|
# @return [Integer] seconds of uptime
|
310
314
|
def uptime
|
311
|
-
rpc(:uptime)
|
315
|
+
rpc(:uptime, _access: :seconds, _coerce: Hash)
|
316
|
+
end
|
317
|
+
|
318
|
+
# Sets the receive minimum for wallets on the node. The value is in +Nano+ by default.
|
319
|
+
# To specify an amount in +raw+, pass the argument +unit: :raw+.
|
320
|
+
#
|
321
|
+
# ==== Example:
|
322
|
+
#
|
323
|
+
# account.change_receive_minimum(0.01) # true
|
324
|
+
#
|
325
|
+
# @return [Boolean] true if the action was successful
|
326
|
+
# @param minimum Amount to set as the receive minimum
|
327
|
+
# @param unit optional. Specify +raw+ if you want to set the amount in +raw+. (See Nanook::Account#balance)
|
328
|
+
# @raise [Nanook::NanoUnitError] if `unit` is invalid
|
329
|
+
def change_receive_minimum(minimum, unit: Nanook.default_unit)
|
330
|
+
validate_unit!(unit)
|
331
|
+
|
332
|
+
minimum = NANO_to_raw(minimum) if unit == :nano
|
333
|
+
|
334
|
+
rpc(:receive_minimum_set, amount: minimum).key?(:success)
|
312
335
|
end
|
313
336
|
|
314
|
-
#
|
315
|
-
#
|
337
|
+
# Returns receive minimum for wallets on the node.
|
338
|
+
#
|
339
|
+
# ==== Example:
|
340
|
+
#
|
341
|
+
# account.receive_minimum # => 0.01
|
316
342
|
#
|
317
|
-
# @return [
|
318
|
-
|
319
|
-
|
320
|
-
|
343
|
+
# @return [Integer|Float] the receive minimum
|
344
|
+
# @param unit (see Nanook::Account#balance)
|
345
|
+
# @raise [Nanook::NanoUnitError] if `unit` is invalid
|
346
|
+
def receive_minimum(unit: Nanook.default_unit)
|
347
|
+
validate_unit!(unit)
|
348
|
+
|
349
|
+
amount = rpc(:receive_minimum, _access: :amount)
|
350
|
+
|
351
|
+
return amount unless unit == :nano
|
352
|
+
|
353
|
+
raw_to_NANO(amount)
|
321
354
|
end
|
322
355
|
|
323
356
|
# @return [Hash{Symbol=>Integer|String}] version information for this node
|
324
357
|
def version
|
325
|
-
rpc(:version)
|
358
|
+
rpc(:version, _coerce: Hash)
|
326
359
|
end
|
327
|
-
|
360
|
+
alias info version
|
328
361
|
|
329
362
|
private
|
330
363
|
|
331
|
-
def rpc(action, params={})
|
364
|
+
def rpc(action, params = {})
|
332
365
|
@rpc.call(action, params)
|
333
366
|
end
|
334
|
-
|
335
367
|
end
|
336
368
|
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'util'
|
4
|
+
|
5
|
+
class Nanook
|
6
|
+
# The <tt>Nanook::PrivateKey</tt> class lets you manage your node's keys.
|
7
|
+
class PrivateKey
|
8
|
+
include Nanook::Util
|
9
|
+
|
10
|
+
def initialize(rpc, key = nil)
|
11
|
+
@rpc = rpc
|
12
|
+
@key = key.to_s if key
|
13
|
+
end
|
14
|
+
|
15
|
+
def id
|
16
|
+
@key
|
17
|
+
end
|
18
|
+
|
19
|
+
# @param other [Nanook::PrivateKey] private key to compare
|
20
|
+
# @return [Boolean] true if keys are equal
|
21
|
+
def ==(other)
|
22
|
+
other.class == self.class &&
|
23
|
+
other.id == id
|
24
|
+
end
|
25
|
+
alias eql? ==
|
26
|
+
|
27
|
+
# The hash value is used along with #eql? by the Hash class to determine if two objects
|
28
|
+
# reference the same hash key.
|
29
|
+
#
|
30
|
+
# @return [Integer]
|
31
|
+
def hash
|
32
|
+
id.hash
|
33
|
+
end
|
34
|
+
|
35
|
+
# Generate a new private public key pair. Returns the new {Nanook::PrivateKey}.
|
36
|
+
# The public key can be retrieved by calling `#public_key` on the private key.
|
37
|
+
#
|
38
|
+
# ==== Examples:
|
39
|
+
#
|
40
|
+
# private_key = nanook.private_key.create
|
41
|
+
# private_key.public_key # => Nanook::PublicKey pair for the private key
|
42
|
+
#
|
43
|
+
# deterministic_private_key = nanook.private_key.create(seed: seed, index: 0)
|
44
|
+
#
|
45
|
+
# @param seed [String] optional seed to generate a deterministic private key.
|
46
|
+
# @param index [Integer] optional (but required if +seed+ is given) index to generate a deterministic private key.
|
47
|
+
# @return Nanook::PrivateKey
|
48
|
+
def create(seed: nil, index: nil)
|
49
|
+
skip_key_required!
|
50
|
+
|
51
|
+
params = {
|
52
|
+
_access: :private,
|
53
|
+
_coerce: Hash
|
54
|
+
}
|
55
|
+
|
56
|
+
@key = if seed.nil?
|
57
|
+
rpc(:key_create, params)
|
58
|
+
else
|
59
|
+
raise ArgumentError, 'index argument is required when seed is given' if index.nil?
|
60
|
+
|
61
|
+
rpc(:deterministic_key, params.merge(seed: seed, index: index))
|
62
|
+
end
|
63
|
+
|
64
|
+
self
|
65
|
+
end
|
66
|
+
|
67
|
+
# Returns the {Nanook::Account} that matches this private key. The
|
68
|
+
# account may not exist yet in the ledger.
|
69
|
+
#
|
70
|
+
# @return Nanook::Account
|
71
|
+
def account
|
72
|
+
as_account(memoized_key_expand[:account])
|
73
|
+
end
|
74
|
+
|
75
|
+
# Returns the {Nanook::PublicKey} pair for this private key.
|
76
|
+
#
|
77
|
+
# @return Nanook::PublicKey
|
78
|
+
def public_key
|
79
|
+
as_public_key(memoized_key_expand[:public])
|
80
|
+
end
|
81
|
+
|
82
|
+
# @return [String]
|
83
|
+
def to_s
|
84
|
+
"#{self.class.name}(id: \"#{short_id}\")"
|
85
|
+
end
|
86
|
+
alias inspect to_s
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
def memoized_key_expand
|
91
|
+
@memoized_key_expand ||= rpc(:key_expand, _coerce: Hash)
|
92
|
+
end
|
93
|
+
|
94
|
+
def rpc(action, params = {})
|
95
|
+
check_key_required!
|
96
|
+
|
97
|
+
p = { key: @key }.compact
|
98
|
+
@rpc.call(action, p.merge(params)).tap { reset_skip_key_required! }
|
99
|
+
end
|
100
|
+
|
101
|
+
def skip_key_required!
|
102
|
+
@skip_key_required_check = true
|
103
|
+
end
|
104
|
+
|
105
|
+
def reset_skip_key_required!
|
106
|
+
@skip_key_required_check = false
|
107
|
+
end
|
108
|
+
|
109
|
+
def check_key_required!
|
110
|
+
return if @key || @skip_key_required_check
|
111
|
+
|
112
|
+
raise ArgumentError, 'Key must be present'
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|