nanook 2.5.1 → 3.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.
- 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
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'util'
|
4
|
+
|
5
|
+
class Nanook
|
6
|
+
# The <tt>Nanook::PublicKey</tt> class lets you manage your node's keys.
|
7
|
+
class PublicKey
|
8
|
+
include Nanook::Util
|
9
|
+
|
10
|
+
def initialize(rpc, key)
|
11
|
+
@rpc = rpc
|
12
|
+
@key = key.to_s
|
13
|
+
end
|
14
|
+
|
15
|
+
def id
|
16
|
+
@key
|
17
|
+
end
|
18
|
+
|
19
|
+
# @param other [Nanook::PublicKey] public 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
|
+
# Returns the account for a public key
|
36
|
+
#
|
37
|
+
# @return [Nanook::Account] account for the public key
|
38
|
+
def account
|
39
|
+
account = rpc(:account_get, _access: :account)
|
40
|
+
as_account(account)
|
41
|
+
end
|
42
|
+
|
43
|
+
# @return [String]
|
44
|
+
def to_s
|
45
|
+
"#{self.class.name}(id: \"#{short_id}\")"
|
46
|
+
end
|
47
|
+
alias inspect to_s
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def rpc(action, params = {})
|
52
|
+
@rpc.call(action, { key: @key }.merge(params))
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/lib/nanook/rpc.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'json'
|
2
4
|
require 'symbolized'
|
3
5
|
|
4
6
|
class Nanook
|
5
|
-
|
6
7
|
# The <tt>Nanook::Rpc</tt> class is responsible for maintaining the
|
7
8
|
# connection to the RPC server, calling the RPC and parsing its response
|
8
9
|
# into Ruby primitives.
|
@@ -14,23 +15,35 @@ class Nanook
|
|
14
15
|
# nanook = Nanook.new
|
15
16
|
# nanook.rpc(:accounts_create, wallet: wallet_id, count: 2)
|
16
17
|
class Rpc
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
# Default request timeout in seconds
|
18
|
+
# Default RPC server and port to connect to.
|
19
|
+
DEFAULT_URI = 'http://[::1]:7076'
|
20
|
+
# Default request timeout in seconds.
|
21
21
|
DEFAULT_TIMEOUT = 60
|
22
|
+
# Error expected to be returned when the RPC makes a call that requires the
|
23
|
+
# `enable_control` setting to be enabled when it is disabled.
|
24
|
+
RPC_CONTROL_DISABLED_ERROR = 'RPC control is disabled'
|
22
25
|
|
23
|
-
def initialize(uri=DEFAULT_URI, timeout:DEFAULT_TIMEOUT)
|
26
|
+
def initialize(uri = DEFAULT_URI, timeout: DEFAULT_TIMEOUT)
|
24
27
|
@rpc_server = URI(uri)
|
25
28
|
|
26
|
-
unless [
|
27
|
-
raise ArgumentError
|
29
|
+
unless %w[http https].include?(@rpc_server.scheme)
|
30
|
+
raise ArgumentError, "URI must have http or https in it. Was given: #{uri}"
|
28
31
|
end
|
29
32
|
|
30
|
-
@http = Net::HTTP.new(@rpc_server.
|
33
|
+
@http = Net::HTTP.new(@rpc_server.hostname, @rpc_server.port)
|
31
34
|
@http.read_timeout = timeout
|
32
|
-
@request = Net::HTTP::Post.new(@rpc_server.request_uri, {
|
33
|
-
@request.content_type =
|
35
|
+
@request = Net::HTTP::Post.new(@rpc_server.request_uri, { 'user-agent' => "Ruby nanook gem v#{Nanook::VERSION}" })
|
36
|
+
@request.content_type = 'application/json'
|
37
|
+
end
|
38
|
+
|
39
|
+
# Tests the RPC connection. Returns +true+ if connection is successful,
|
40
|
+
# otherwise raises an exception.
|
41
|
+
#
|
42
|
+
# @raise [Errno::ECONNREFUSED] if connection is unsuccessful
|
43
|
+
# @return [Boolean] true if connection is successful
|
44
|
+
def test
|
45
|
+
call(:telemetry)
|
46
|
+
true
|
34
47
|
end
|
35
48
|
|
36
49
|
# Calls the RPC server and returns the response.
|
@@ -39,57 +52,104 @@ class Nanook
|
|
39
52
|
# expects an "action" param to identify what RPC action is being called.
|
40
53
|
# @param params [Hash] all other params to pass to the RPC
|
41
54
|
# @return [Hash] the response from the RPC
|
42
|
-
def call(action, params={})
|
43
|
-
|
44
|
-
|
55
|
+
def call(action, params = {})
|
56
|
+
coerce_to = params.delete(:_coerce)
|
57
|
+
access_as = params.delete(:_access)
|
45
58
|
|
46
|
-
|
59
|
+
raw_hash = make_call(action, params)
|
47
60
|
|
48
|
-
|
61
|
+
check_for_errors!(raw_hash)
|
49
62
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
63
|
+
hash = parse_values(raw_hash)
|
64
|
+
|
65
|
+
hash = hash[access_as] if access_as
|
66
|
+
hash = coerce_empty_string_to_type(hash, coerce_to) if coerce_to
|
67
|
+
|
68
|
+
hash
|
56
69
|
end
|
57
70
|
|
58
71
|
# @return [String]
|
59
|
-
def
|
60
|
-
"#{self.class.name}(host: \"#{@rpc_server}\", timeout: #{@http.read_timeout}
|
72
|
+
def to_s
|
73
|
+
"#{self.class.name}(host: \"#{@rpc_server}\", timeout: #{@http.read_timeout})"
|
61
74
|
end
|
75
|
+
alias inspect to_s
|
62
76
|
|
63
77
|
private
|
64
78
|
|
79
|
+
def make_call(action, params)
|
80
|
+
# Stringify param values
|
81
|
+
params = params.dup.transform_values do |v|
|
82
|
+
next v if v.is_a?(Array)
|
83
|
+
|
84
|
+
v.to_s
|
85
|
+
end
|
86
|
+
|
87
|
+
@request.body = { action: action }.merge(params).to_json
|
88
|
+
|
89
|
+
response = @http.request(@request)
|
90
|
+
|
91
|
+
raise Nanook::ConnectionError, "Encountered net/http error #{response.code}: #{response.class.name}" \
|
92
|
+
unless response.is_a?(Net::HTTPSuccess)
|
93
|
+
|
94
|
+
JSON.parse(response.body)
|
95
|
+
end
|
96
|
+
|
97
|
+
# Raises a {Nanook::NodeRpcConfigurationError} or {Nanook::NodeRpcError} if the RPC
|
98
|
+
# response contains an `:error` key.
|
99
|
+
def check_for_errors!(response)
|
100
|
+
# Raise a special error for when `enable_control` should be enabled.
|
101
|
+
if response['error'] == RPC_CONTROL_DISABLED_ERROR
|
102
|
+
raise Nanook::NodeRpcConfigurationError,
|
103
|
+
'RPC must have the `enable_control` setting enabled to perform this action.'
|
104
|
+
end
|
105
|
+
|
106
|
+
# Raise any other error.
|
107
|
+
raise Nanook::NodeRpcError, "An error was returned from the RPC: #{response['error']}" if response.key?('error')
|
108
|
+
end
|
109
|
+
|
65
110
|
# Recursively parses the RPC response, sending values to #parse_value
|
66
|
-
def
|
67
|
-
new_hash =
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
111
|
+
def parse_values(hash)
|
112
|
+
new_hash = hash.map do |k, val|
|
113
|
+
new_val = case val
|
114
|
+
when Array
|
115
|
+
if val[0].is_a?(Hash)
|
116
|
+
val.map { |v| parse_values(v) }
|
117
|
+
else
|
118
|
+
val.map { |v| parse_value(v) }
|
119
|
+
end
|
120
|
+
when Hash
|
121
|
+
parse_values(val)
|
122
|
+
else
|
123
|
+
parse_value(val)
|
124
|
+
end
|
125
|
+
|
126
|
+
[k, new_val]
|
81
127
|
end
|
82
128
|
|
83
129
|
Hash[new_hash.sort].to_symbolized_hash
|
84
130
|
end
|
85
131
|
|
86
132
|
# Converts Strings to primitives
|
87
|
-
def parse_value(
|
88
|
-
return
|
89
|
-
return true if
|
90
|
-
return false if
|
91
|
-
|
133
|
+
def parse_value(value)
|
134
|
+
return value.to_i if value.match(/^\d+\Z/)
|
135
|
+
return true if value == 'true'
|
136
|
+
return false if value == 'false'
|
137
|
+
|
138
|
+
value
|
92
139
|
end
|
93
140
|
|
141
|
+
# Converts an empty String value into an empty version of another type.
|
142
|
+
#
|
143
|
+
# The RPC often returns an empty String as a value to signal
|
144
|
+
# emptiness, rather than consistent types like an empty Array,
|
145
|
+
# or empty Hash.
|
146
|
+
#
|
147
|
+
# @param response the value returned from the RPC server
|
148
|
+
# @param type the type to return an empty of
|
149
|
+
def coerce_empty_string_to_type(response, type)
|
150
|
+
return type.new if response == '' || response.nil?
|
151
|
+
|
152
|
+
response
|
153
|
+
end
|
94
154
|
end
|
95
155
|
end
|
data/lib/nanook/util.rb
CHANGED
@@ -1,18 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'bigdecimal'
|
2
4
|
|
3
5
|
class Nanook
|
4
|
-
|
5
|
-
|
6
|
-
class Util
|
7
|
-
|
6
|
+
# Set of utility methods.
|
7
|
+
module Util
|
8
8
|
# Constant used to convert back and forth between raw and NANO.
|
9
|
-
STEP = BigDecimal(
|
9
|
+
STEP = BigDecimal('10')**BigDecimal('30')
|
10
|
+
|
11
|
+
private
|
10
12
|
|
11
13
|
# Converts an amount of NANO to an amount of raw.
|
12
14
|
#
|
13
15
|
# @param nano [Float|Integer] amount in nano
|
14
16
|
# @return [Integer] amount in raw
|
15
|
-
def
|
17
|
+
def NANO_to_raw(nano)
|
18
|
+
return if nano.nil?
|
19
|
+
|
16
20
|
(BigDecimal(nano.to_s) * STEP).to_i
|
17
21
|
end
|
18
22
|
|
@@ -20,25 +24,70 @@ class Nanook
|
|
20
24
|
#
|
21
25
|
# @param raw [Integer] amount in raw
|
22
26
|
# @return [Float|Integer] amount in NANO
|
23
|
-
def
|
27
|
+
def raw_to_NANO(raw)
|
28
|
+
return if raw.nil?
|
29
|
+
|
24
30
|
(raw.to_f / STEP).to_f
|
25
31
|
end
|
26
32
|
|
27
|
-
#
|
33
|
+
# @return [TrueClass] if unit is valid.
|
34
|
+
# @raise [Nanook::NanoUnitError] if `unit` is invalid.
|
35
|
+
def validate_unit!(unit)
|
36
|
+
unless Nanook::UNITS.include?(unit.to_sym)
|
37
|
+
raise Nanook::NanoUnitError, "Unit #{unit} must be one of #{Nanook::UNITS}"
|
38
|
+
end
|
39
|
+
|
40
|
+
true
|
41
|
+
end
|
42
|
+
|
43
|
+
# Returns the +id+ of the object as a short id.
|
44
|
+
# See #shorten_id.
|
28
45
|
#
|
29
|
-
#
|
30
|
-
|
31
|
-
|
46
|
+
# @return [String]
|
47
|
+
def short_id
|
48
|
+
shorten_id(id)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Returns an id string (hash or nano account) truncated with an ellipsis.
|
52
|
+
# The first 7 and last 4 characters are retained for easy identification.
|
32
53
|
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
54
|
+
# ==== Examples:
|
55
|
+
#
|
56
|
+
# shorten_id('nano_16u1uufyoig8777y6r8iqjtrw8sg8maqrm36zzcm95jmbd9i9aj5i8abr8u5')
|
57
|
+
# # => "16u1uuf...r8u5"
|
58
|
+
#
|
59
|
+
# shorten_id('A170D51B94E00371ACE76E35AC81DC9405D5D04D4CEBC399AEACE07AE05DD293')
|
60
|
+
# # => "A170D51...D293"
|
61
|
+
#
|
62
|
+
# @return [String]
|
63
|
+
def shorten_id(long_id)
|
64
|
+
return unless long_id
|
65
|
+
|
66
|
+
[long_id.sub('nano_', '')[0..6], long_id[-4, 4]].join('...')
|
67
|
+
end
|
39
68
|
|
40
|
-
|
69
|
+
def as_account(account_id)
|
70
|
+
Nanook::Account.new(@rpc, account_id)
|
41
71
|
end
|
42
72
|
|
73
|
+
def as_wallet_account(account_id)
|
74
|
+
Nanook::WalletAccount.new(@rpc, @wallet, account_id)
|
75
|
+
end
|
76
|
+
|
77
|
+
def as_block(block_id)
|
78
|
+
Nanook::Block.new(@rpc, block_id)
|
79
|
+
end
|
80
|
+
|
81
|
+
def as_private_key(key)
|
82
|
+
Nanook::PrivateKey.new(@rpc, key)
|
83
|
+
end
|
84
|
+
|
85
|
+
def as_public_key(key)
|
86
|
+
Nanook::PublicKey.new(@rpc, key)
|
87
|
+
end
|
88
|
+
|
89
|
+
def as_time(time)
|
90
|
+
Time.at(time).utc if time
|
91
|
+
end
|
43
92
|
end
|
44
93
|
end
|
data/lib/nanook/version.rb
CHANGED
data/lib/nanook/wallet.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'util'
|
2
4
|
|
3
|
-
|
4
|
-
#
|
5
|
+
class Nanook
|
6
|
+
# The <tt>Nanook::Wallet</tt> class lets you manage your nano wallets.
|
7
|
+
# Your node will need the <tt>enable_control</tt> setting enabled.
|
5
8
|
#
|
6
9
|
# === Wallet seeds vs ids
|
7
10
|
#
|
@@ -47,10 +50,32 @@ class Nanook
|
|
47
50
|
# rpc_conn = Nanook::Rpc.new
|
48
51
|
# wallet = Nanook::Wallet.new(rpc_conn, wallet_id)
|
49
52
|
class Wallet
|
53
|
+
include Nanook::Util
|
50
54
|
|
51
|
-
def initialize(rpc, wallet)
|
55
|
+
def initialize(rpc, wallet = nil)
|
52
56
|
@rpc = rpc
|
53
|
-
@wallet = wallet
|
57
|
+
@wallet = wallet.to_s if wallet
|
58
|
+
end
|
59
|
+
|
60
|
+
# @return [String] the wallet id
|
61
|
+
def id
|
62
|
+
@wallet
|
63
|
+
end
|
64
|
+
|
65
|
+
# @param other [Nanook::Wallet] wallet to compare
|
66
|
+
# @return [Boolean] true if wallets are equal
|
67
|
+
def ==(other)
|
68
|
+
other.class == self.class &&
|
69
|
+
other.id == id
|
70
|
+
end
|
71
|
+
alias eql? ==
|
72
|
+
|
73
|
+
# The hash value is used along with #eql? by the Hash class to determine if two objects
|
74
|
+
# reference the same hash key.
|
75
|
+
#
|
76
|
+
# @return [Integer]
|
77
|
+
def hash
|
78
|
+
id.hash
|
54
79
|
end
|
55
80
|
|
56
81
|
# Returns the given account in the wallet as a {Nanook::WalletAccount} instance
|
@@ -69,14 +94,15 @@ class Nanook
|
|
69
94
|
# wallet.account("nano_...") # => Nanook::WalletAccount
|
70
95
|
# wallet.account.create # => Nanook::WalletAccount
|
71
96
|
#
|
72
|
-
# @param [String]
|
97
|
+
# @param account [String] optional String of an account (starting with
|
73
98
|
# <tt>"xrb..."</tt>) to start working with. Must be an account within
|
74
99
|
# the wallet. When no account is given, the instance returned only
|
75
100
|
# allows you to call +create+ on it, to create a new account.
|
76
|
-
# @raise [ArgumentError] if the wallet does
|
101
|
+
# @raise [ArgumentError] if the wallet does not contain the account
|
77
102
|
# @return [Nanook::WalletAccount]
|
78
|
-
def account(account=nil)
|
79
|
-
|
103
|
+
def account(account = nil)
|
104
|
+
check_wallet_required!
|
105
|
+
as_wallet_account(account)
|
80
106
|
end
|
81
107
|
|
82
108
|
# Array of {Nanook::WalletAccount} instances of accounts in the wallet.
|
@@ -90,13 +116,33 @@ class Nanook
|
|
90
116
|
#
|
91
117
|
# @return [Array<Nanook::WalletAccount>] all accounts in the wallet
|
92
118
|
def accounts
|
93
|
-
|
94
|
-
|
95
|
-
Nanook::Util.coerce_empty_string_to_type(response, Array).map do |account|
|
96
|
-
Nanook::WalletAccount.new(@rpc, @wallet, account)
|
119
|
+
rpc(:account_list, _access: :accounts, _coerce: Array).map do |account|
|
120
|
+
as_wallet_account(account)
|
97
121
|
end
|
98
122
|
end
|
99
123
|
|
124
|
+
# Move accounts from another {Nanook::Wallet} on the node to this {Nanook::Wallet}.
|
125
|
+
#
|
126
|
+
# ==== Example:
|
127
|
+
#
|
128
|
+
# wallet.move_accounts("0023200...", ["nano_3e3j5...", "nano_5f2a1..."]) # => true
|
129
|
+
#
|
130
|
+
# @return [Boolean] true when the move was successful
|
131
|
+
def move_accounts(wallet, accounts)
|
132
|
+
rpc(:account_move, source: wallet, accounts: accounts, _access: :moved) == 1
|
133
|
+
end
|
134
|
+
|
135
|
+
# Remove an {Nanook::Account} from this {Nanook::Wallet}.
|
136
|
+
#
|
137
|
+
# ==== Example:
|
138
|
+
#
|
139
|
+
# wallet.remove_account("nano_3e3j5...") # => true
|
140
|
+
#
|
141
|
+
# @return [Boolean] true when the remove was successful
|
142
|
+
def remove_account(account)
|
143
|
+
rpc(:account_remove, account: account, _access: :removed) == 1
|
144
|
+
end
|
145
|
+
|
100
146
|
# Balance of all accounts in the wallet, optionally breaking the balances down by account.
|
101
147
|
#
|
102
148
|
# ==== Examples:
|
@@ -137,51 +183,50 @@ class Nanook
|
|
137
183
|
# },
|
138
184
|
# }
|
139
185
|
#
|
140
|
-
# @param [Boolean]
|
186
|
+
# @param account_break_down [Boolean] (default is +false+). When +true+
|
141
187
|
# the response will contain balances per account.
|
142
188
|
# @param unit (see Nanook::Account#balance)
|
143
189
|
#
|
144
190
|
# @return [Hash{Symbol=>Integer|Float|Hash}]
|
191
|
+
# @raise [Nanook::NanoUnitError] if `unit` is invalid
|
145
192
|
def balance(account_break_down: false, unit: Nanook.default_unit)
|
146
|
-
|
147
|
-
|
148
|
-
unless Nanook::UNITS.include?(unit)
|
149
|
-
raise ArgumentError.new("Unsupported unit: #{unit}")
|
150
|
-
end
|
193
|
+
validate_unit!(unit)
|
151
194
|
|
152
195
|
if account_break_down
|
153
|
-
return
|
196
|
+
return rpc(:wallet_balances, _access: :balances, _coerce: Hash).tap do |r|
|
154
197
|
if unit == :nano
|
155
|
-
r.each do |account,
|
156
|
-
r[account][:balance] =
|
157
|
-
r[account][:pending] =
|
198
|
+
r.each do |account, _balances|
|
199
|
+
r[account][:balance] = raw_to_NANO(r[account][:balance])
|
200
|
+
r[account][:pending] = raw_to_NANO(r[account][:pending])
|
158
201
|
end
|
159
202
|
end
|
160
203
|
end
|
161
204
|
end
|
162
205
|
|
163
|
-
rpc(:
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
206
|
+
response = rpc(:wallet_info, _coerce: Hash).slice(:balance, :pending)
|
207
|
+
return response unless unit == :nano
|
208
|
+
|
209
|
+
{
|
210
|
+
balance: raw_to_NANO(response[:balance]),
|
211
|
+
pending: raw_to_NANO(response[:pending])
|
212
|
+
}
|
169
213
|
end
|
170
214
|
|
171
215
|
# Changes a wallet's seed.
|
172
216
|
#
|
173
217
|
# It's recommended to only change the seed of a wallet that contains
|
174
|
-
# no accounts.
|
218
|
+
# no accounts. This will clear all deterministic accounts in the wallet.
|
219
|
+
# To restore accounts after changing the seed, see Nanook::WalletAccount#create.
|
175
220
|
#
|
176
221
|
# ==== Example:
|
177
222
|
#
|
178
223
|
# wallet.change_seed("000D1BA...") # => true
|
224
|
+
# wallet.account.create(5) # Restores first 5 accounts for wallet with new seed
|
179
225
|
#
|
180
226
|
# @param seed [String] the seed to change to.
|
181
227
|
# @return [Boolean] indicating whether the change was successful.
|
182
228
|
def change_seed(seed)
|
183
|
-
|
184
|
-
rpc(:wallet_change_seed, seed: seed).has_key?(:success)
|
229
|
+
rpc(:wallet_change_seed, seed: seed).key?(:success)
|
185
230
|
end
|
186
231
|
|
187
232
|
# Creates a new wallet.
|
@@ -199,7 +244,8 @@ class Nanook
|
|
199
244
|
#
|
200
245
|
# @return [Nanook::Wallet]
|
201
246
|
def create
|
202
|
-
|
247
|
+
skip_wallet_required!
|
248
|
+
@wallet = rpc(:wallet_create, _access: :wallet)
|
203
249
|
self
|
204
250
|
end
|
205
251
|
|
@@ -211,19 +257,33 @@ class Nanook
|
|
211
257
|
#
|
212
258
|
# @return [Boolean] indicating success of the action
|
213
259
|
def destroy
|
214
|
-
|
215
|
-
rpc(:wallet_destroy)
|
216
|
-
true
|
260
|
+
rpc(:wallet_destroy, _access: :destroyed) == 1
|
217
261
|
end
|
218
262
|
|
219
263
|
# Generates a String containing a JSON representation of your wallet.
|
220
264
|
#
|
221
265
|
# ==== Example:
|
222
266
|
#
|
223
|
-
# wallet.export
|
267
|
+
# wallet.export
|
268
|
+
# # => "{\n \"0000000000000000000000000000000000000000000000000000000000000000\": \"0000000000000000000000000000000000000000000000000000000000000003\",\n \"0000000000000000000000000000000000000000000000000000000000000001\": \"C3A176FC3B90113277BFC91F55128FC9A1F1B6166A73E7446927CFFCA4C2C9D9\",\n \"0000000000000000000000000000000000000000000000000000000000000002\": \"3E58EC805B99C52B4715598BD332C234A1FBF1780577137E18F53B9B7F85F04B\",\n \"0000000000000000000000000000000000000000000000000000000000000003\": \"5FF8021122F3DEE0E4EC4241D35A3F41DEF63CCF6ADA66AF235DE857718498CD\",\n \"0000000000000000000000000000000000000000000000000000000000000004\": \"A30E0A32ED41C8607AA9212843392E853FCBCB4E7CB194E35C94F07F91DE59EF\",\n \"0000000000000000000000000000000000000000000000000000000000000005\": \"E707002E84143AA5F030A6DB8DD0C0480F2FFA75AB1FFD657EC22B5AA8E395D5\",\n \"0000000000000000000000000000000000000000000000000000000000000006\": \"0000000000000000000000000000000000000000000000000000000000000001\",\n \"8646C0423160DEAEAA64034F9C6858F7A5C8A329E73E825A5B16814F6CCAFFE3\": \"0000000000000000000000000000000000000000000000000000000100000000\"\n}\n"
|
269
|
+
#
|
270
|
+
# @return [String]
|
224
271
|
def export
|
225
|
-
|
226
|
-
|
272
|
+
rpc(:wallet_export, _access: :json)
|
273
|
+
end
|
274
|
+
|
275
|
+
# Returns true if wallet exists on the node.
|
276
|
+
#
|
277
|
+
# ==== Example:
|
278
|
+
#
|
279
|
+
# wallet.exists? # => true
|
280
|
+
#
|
281
|
+
# @return [Boolean] true if wallet exists on the node
|
282
|
+
def exists?
|
283
|
+
export
|
284
|
+
true
|
285
|
+
rescue Nanook::NodeRpcError
|
286
|
+
false
|
227
287
|
end
|
228
288
|
|
229
289
|
# Will return +true+ if the account exists in the wallet.
|
@@ -234,20 +294,14 @@ class Nanook
|
|
234
294
|
# @param account [String] id (will start with <tt>"nano_..."</tt>)
|
235
295
|
# @return [Boolean] indicating if the wallet contains the given account
|
236
296
|
def contains?(account)
|
237
|
-
|
238
|
-
response = rpc(:wallet_contains, account: account)
|
239
|
-
!response.empty? && response[:exists] == 1
|
240
|
-
end
|
241
|
-
|
242
|
-
# @return [String] the wallet id
|
243
|
-
def id
|
244
|
-
@wallet
|
297
|
+
rpc(:wallet_contains, account: account, _access: :exists) == 1
|
245
298
|
end
|
246
299
|
|
247
300
|
# @return [String]
|
248
|
-
def
|
249
|
-
"#{self.class.name}(id: \"#{
|
301
|
+
def to_s
|
302
|
+
"#{self.class.name}(id: \"#{short_id}\")"
|
250
303
|
end
|
304
|
+
alias inspect to_s
|
251
305
|
|
252
306
|
# Makes a payment from an account in your wallet to another account
|
253
307
|
# on the nano network.
|
@@ -263,7 +317,8 @@ class Nanook
|
|
263
317
|
# ==== Examples:
|
264
318
|
#
|
265
319
|
# wallet.pay(from: "nano_...", to: "nano_...", amount: 1.1, id: "myUniqueId123") # => "9AE2311..."
|
266
|
-
# wallet.pay(from: "nano_...", to: "nano_...", amount: 54000000000000, unit: :raw, id: "myUniqueId123")
|
320
|
+
# wallet.pay(from: "nano_...", to: "nano_...", amount: 54000000000000, unit: :raw, id: "myUniqueId123")
|
321
|
+
# # => "9AE2311..."
|
267
322
|
#
|
268
323
|
# @param from [String] account id of an account in your wallet
|
269
324
|
# @param to (see Nanook::WalletAccount#pay)
|
@@ -272,8 +327,7 @@ class Nanook
|
|
272
327
|
# @params id (see Nanook::WalletAccount#pay)
|
273
328
|
# @return (see Nanook::WalletAccount#pay)
|
274
329
|
# @raise [Nanook::Error] if unsuccessful
|
275
|
-
def pay(from:, to:, amount:, unit: Nanook.default_unit
|
276
|
-
wallet_required!
|
330
|
+
def pay(from:, to:, amount:, id:, unit: Nanook.default_unit)
|
277
331
|
validate_wallet_contains_account!(from)
|
278
332
|
account(from).pay(to: to, amount: amount, unit: unit, id: id)
|
279
333
|
end
|
@@ -294,12 +348,12 @@ class Nanook
|
|
294
348
|
# Example response:
|
295
349
|
#
|
296
350
|
# {
|
297
|
-
#
|
298
|
-
#
|
299
|
-
# "
|
351
|
+
# Nanook::Account=>[
|
352
|
+
# Nanook::Block,
|
353
|
+
# Nanook::Block"
|
300
354
|
# ],
|
301
|
-
#
|
302
|
-
#
|
355
|
+
# Nanook::Account=>[
|
356
|
+
# Nanook::Block
|
303
357
|
# ]
|
304
358
|
# }
|
305
359
|
#
|
@@ -310,57 +364,69 @@ class Nanook
|
|
310
364
|
# Example response:
|
311
365
|
#
|
312
366
|
# {
|
313
|
-
#
|
367
|
+
# Nanook::Account=>[
|
314
368
|
# {
|
315
369
|
# :amount=>6.0,
|
316
|
-
# :source=>
|
317
|
-
# :block
|
370
|
+
# :source=>Nanook::Account,
|
371
|
+
# :block=>Nanook::Block
|
318
372
|
# },
|
319
373
|
# {
|
320
374
|
# :amount=>12.0,
|
321
|
-
# :source=>
|
322
|
-
# :block
|
375
|
+
# :source=>Nanook::Account,
|
376
|
+
# :block=>Nanook::Block
|
323
377
|
# }
|
324
378
|
# ],
|
325
|
-
#
|
379
|
+
# Nanook::Account=>[
|
326
380
|
# {
|
327
381
|
# :amount=>106.370018,
|
328
|
-
# :source=>
|
329
|
-
# :block
|
382
|
+
# :source=>Nanook::Account,
|
383
|
+
# :block=>Nanook::Block
|
330
384
|
# }
|
331
385
|
# ]
|
332
386
|
# }
|
333
|
-
|
334
|
-
|
387
|
+
#
|
388
|
+
# @raise [Nanook::NanoUnitError] if `unit` is invalid
|
389
|
+
def pending(limit: 1000, detailed: false, unit: Nanook.default_unit)
|
390
|
+
validate_unit!(unit)
|
335
391
|
|
336
|
-
|
337
|
-
|
338
|
-
|
392
|
+
params = {
|
393
|
+
count: limit,
|
394
|
+
_access: :blocks,
|
395
|
+
_coerce: Hash
|
396
|
+
}
|
339
397
|
|
340
|
-
params = { count: limit }
|
341
398
|
params[:source] = true if detailed
|
342
399
|
|
343
|
-
response = rpc(:wallet_pending, params)
|
344
|
-
response = Nanook::Util.coerce_empty_string_to_type(response, Hash)
|
400
|
+
response = rpc(:wallet_pending, params)
|
345
401
|
|
346
|
-
|
402
|
+
unless detailed
|
403
|
+
|
404
|
+
x = response.map do |account, block_ids|
|
405
|
+
blocks = block_ids.map { |block_id| as_block(block_id) }
|
406
|
+
[as_account(account), blocks]
|
407
|
+
end
|
408
|
+
|
409
|
+
return Hash[x]
|
410
|
+
end
|
347
411
|
|
348
412
|
# Map the RPC response, which is:
|
349
413
|
# account=>block=>[amount|source] into
|
350
414
|
# account=>[block|amount|source]
|
351
415
|
x = response.map do |account, data|
|
352
416
|
new_data = data.map do |block, amount_and_source|
|
353
|
-
d =
|
354
|
-
|
355
|
-
|
356
|
-
|
417
|
+
d = {
|
418
|
+
block: as_block(block),
|
419
|
+
source: as_account(amount_and_source[:source]),
|
420
|
+
amount: amount_and_source[:amount]
|
421
|
+
}
|
422
|
+
d[:amount] = raw_to_NANO(d[:amount]) if unit == :nano
|
357
423
|
d
|
358
424
|
end
|
359
425
|
|
360
|
-
[account, new_data]
|
426
|
+
[as_account(account), new_data]
|
361
427
|
end
|
362
428
|
|
363
|
-
Hash[x]
|
429
|
+
Hash[x]
|
364
430
|
end
|
365
431
|
|
366
432
|
# Receives a pending payment into an account in the wallet.
|
@@ -368,7 +434,7 @@ class Nanook
|
|
368
434
|
# When called with no +block+ argument, the latest pending payment
|
369
435
|
# for the account will be received.
|
370
436
|
#
|
371
|
-
# Returns a <i>receive</i> block
|
437
|
+
# Returns a <i>receive</i> block if a receive was successful,
|
372
438
|
# or +false+ if there were no pending payments to receive.
|
373
439
|
#
|
374
440
|
# You can receive a specific pending block if you know it by
|
@@ -376,19 +442,33 @@ class Nanook
|
|
376
442
|
#
|
377
443
|
# ==== Examples:
|
378
444
|
#
|
379
|
-
# wallet.receive(into: "xrb...") # =>
|
380
|
-
# wallet.receive("718CC21...", into: "xrb...") # =>
|
445
|
+
# wallet.receive(into: "xrb...") # => Nanook::Block
|
446
|
+
# wallet.receive("718CC21...", into: "xrb...") # => Nanook::Block
|
381
447
|
#
|
382
448
|
# @param block (see Nanook::WalletAccount#receive)
|
383
449
|
# @param into [String] account id of account in your wallet to receive the
|
384
450
|
# payment into
|
385
451
|
# @return (see Nanook::WalletAccount#receive)
|
386
|
-
def receive(block=nil, into:)
|
387
|
-
wallet_required!
|
452
|
+
def receive(block = nil, into:)
|
388
453
|
validate_wallet_contains_account!(into)
|
389
454
|
account(into).receive(block)
|
390
455
|
end
|
391
456
|
|
457
|
+
# Rebroadcast blocks for accounts from wallet starting at frontier down to count to the network.
|
458
|
+
#
|
459
|
+
# ==== Examples:
|
460
|
+
#
|
461
|
+
# wallet.republish_blocks # => [Nanook::Block, ...]
|
462
|
+
# wallet.republish_blocks(limit: 10) # => [Nanook::Block, ...
|
463
|
+
#
|
464
|
+
# @param limit [Integer] limit of blocks to publish. Default is 1000.
|
465
|
+
# @return [Array<Nanook::Block>] republished blocks
|
466
|
+
def republish_blocks(limit: 1000)
|
467
|
+
rpc(:wallet_republish, count: limit, _access: :blocks, _coerce: Array).map do |block|
|
468
|
+
as_block(block)
|
469
|
+
end
|
470
|
+
end
|
471
|
+
|
392
472
|
# The default representative account id for the wallet. This is the
|
393
473
|
# representative that all new accounts created in this wallet will have.
|
394
474
|
#
|
@@ -399,11 +479,12 @@ class Nanook
|
|
399
479
|
#
|
400
480
|
# wallet.default_representative # => "nano_3pc..."
|
401
481
|
#
|
402
|
-
# @return [
|
482
|
+
# @return [Nanook::Account] Representative account. Can be nil.
|
403
483
|
def default_representative
|
404
|
-
rpc(:wallet_representative
|
484
|
+
representative = rpc(:wallet_representative, _access: :representative)
|
485
|
+
as_account(representative) if representative
|
405
486
|
end
|
406
|
-
|
487
|
+
alias representative default_representative
|
407
488
|
|
408
489
|
# Sets the default representative for the wallet. A wallet's default
|
409
490
|
# representative is the representative all new accounts created in
|
@@ -415,23 +496,21 @@ class Nanook
|
|
415
496
|
#
|
416
497
|
# wallet.change_default_representative("nano_...") # => "nano_..."
|
417
498
|
#
|
418
|
-
# @param [String]
|
499
|
+
# @param representative [String] id of the representative account
|
419
500
|
# to set as this account's representative
|
420
|
-
# @return [
|
421
|
-
# @raise [ArgumentError] if the representative account does not exist
|
501
|
+
# @return [Nanook::Account] the representative account
|
422
502
|
# @raise [Nanook::Error] if setting the representative fails
|
423
503
|
def change_default_representative(representative)
|
424
|
-
unless
|
425
|
-
raise
|
504
|
+
unless as_account(representative).exists?
|
505
|
+
raise Nanook::Error, "Representative account does not exist: #{representative}"
|
426
506
|
end
|
427
507
|
|
428
|
-
|
429
|
-
representative
|
430
|
-
|
431
|
-
|
432
|
-
end
|
508
|
+
raise Nanook::Error, 'Setting the representative failed' \
|
509
|
+
unless rpc(:wallet_representative_set, representative: representative, _access: :set) == 1
|
510
|
+
|
511
|
+
as_account(representative)
|
433
512
|
end
|
434
|
-
|
513
|
+
alias change_representative change_default_representative
|
435
514
|
|
436
515
|
# Restores a previously created wallet by its seed.
|
437
516
|
# A new wallet will be created on your node (with a new wallet id)
|
@@ -446,21 +525,68 @@ class Nanook
|
|
446
525
|
#
|
447
526
|
# @return [Nanook::Wallet] a new wallet
|
448
527
|
# @raise [Nanook::Error] if unsuccessful
|
449
|
-
def restore(seed, accounts:0)
|
528
|
+
def restore(seed, accounts: 0)
|
529
|
+
skip_wallet_required!
|
530
|
+
|
450
531
|
create
|
451
532
|
|
452
|
-
unless change_seed(seed)
|
453
|
-
raise Nanook::Error.new("Unable to set seed for wallet")
|
454
|
-
end
|
533
|
+
raise Nanook::Error, 'Unable to set seed for wallet' unless change_seed(seed)
|
455
534
|
|
456
|
-
if accounts
|
457
|
-
account.create(accounts)
|
458
|
-
end
|
535
|
+
account.create(accounts) if accounts.positive?
|
459
536
|
|
460
537
|
self
|
461
538
|
end
|
462
539
|
|
463
|
-
# Information about this wallet
|
540
|
+
# Information ledger information about this wallet's accounts.
|
541
|
+
#
|
542
|
+
# This call may return results that include unconfirmed blocks, so it should not be
|
543
|
+
# used in any processes or integrations requiring only details from blocks confirmed
|
544
|
+
# by the network.
|
545
|
+
#
|
546
|
+
# ==== Examples:
|
547
|
+
#
|
548
|
+
# wallet.ledger
|
549
|
+
#
|
550
|
+
# Example response:
|
551
|
+
#
|
552
|
+
# {
|
553
|
+
# Nanook::Account => {
|
554
|
+
# frontier: "E71AF3E9DD86BBD8B4620EFA63E065B34D358CFC091ACB4E103B965F95783321",
|
555
|
+
# open_block: "643B77F1ECEFBDBE1CC909872964C1DBBE23A6149BD3CEF2B50B76044659B60F",
|
556
|
+
# representative_block: "643B77F1ECEFBDBE1CC909872964C1DBBE23A6149BD3CEF2B50B76044659B60F",
|
557
|
+
# balance: 1.45,
|
558
|
+
# modified_timestamp: 1511476234,
|
559
|
+
# block_count: 2
|
560
|
+
# },
|
561
|
+
# Nanook::Account => { ... }
|
562
|
+
# }
|
563
|
+
#
|
564
|
+
# @param unit (see Nanook::Account#balance)
|
565
|
+
# @return [Hash{Nanook::Account=>Hash{Symbol=>Nanook::Block|Integer|Float|Time}}] ledger.
|
566
|
+
# @raise [Nanook::NanoUnitError] if `unit` is invalid
|
567
|
+
def ledger(unit: Nanook.default_unit)
|
568
|
+
validate_unit!(unit)
|
569
|
+
|
570
|
+
response = rpc(:wallet_ledger, _access: :accounts, _coerce: Hash)
|
571
|
+
|
572
|
+
accounts = response.map do |account_id, data|
|
573
|
+
data[:frontier] = as_block(data[:frontier]) if data[:frontier]
|
574
|
+
data[:open_block] = as_block(data[:open_block]) if data[:open_block]
|
575
|
+
data[:representative_block] = as_block(data[:representative_block]) if data[:representative_block]
|
576
|
+
data[:balance] = raw_to_NANO(data[:balance]) if unit == :nano && data[:balance]
|
577
|
+
data[:last_modified_at] = as_time(data.delete(:modified_timestamp))
|
578
|
+
|
579
|
+
[as_account(account_id), data]
|
580
|
+
end
|
581
|
+
|
582
|
+
Hash[accounts]
|
583
|
+
end
|
584
|
+
|
585
|
+
# Information about this wallet.
|
586
|
+
#
|
587
|
+
# This call may return results that include unconfirmed blocks, so it should not be
|
588
|
+
# used in any processes or integrations requiring only details from blocks confirmed
|
589
|
+
# by the network.
|
464
590
|
#
|
465
591
|
# ==== Examples:
|
466
592
|
#
|
@@ -469,42 +595,68 @@ class Nanook
|
|
469
595
|
# Example response:
|
470
596
|
#
|
471
597
|
# {
|
472
|
-
#
|
473
|
-
#
|
474
|
-
#
|
475
|
-
#
|
476
|
-
#
|
477
|
-
#
|
478
|
-
#
|
479
|
-
# balance: 1.45,
|
480
|
-
# modified_timestamp: 1511476234,
|
481
|
-
# block_count: 2
|
482
|
-
# },
|
483
|
-
# { ... }
|
484
|
-
# ]
|
485
|
-
# }
|
598
|
+
# balance: 1.0,
|
599
|
+
# pending: 2.3
|
600
|
+
# accounts_count: 3,
|
601
|
+
# adhoc_count: 1,
|
602
|
+
# deterministic_count: 2,
|
603
|
+
# deterministic_index: 2
|
604
|
+
# }
|
486
605
|
#
|
487
|
-
# @param unit (see #balance)
|
488
|
-
# @return [Hash{Symbol=>
|
489
|
-
#
|
606
|
+
# @param unit (see Nanook::Account#balance)
|
607
|
+
# @return [Hash{Symbol=>Integer|Float}] information about the wallet.
|
608
|
+
# @raise [Nanook::NanoUnitError] if `unit` is invalid
|
490
609
|
def info(unit: Nanook.default_unit)
|
491
|
-
|
492
|
-
raise ArgumentError.new("Unsupported unit: #{unit}")
|
493
|
-
end
|
610
|
+
validate_unit!(unit)
|
494
611
|
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
end
|
501
|
-
payload
|
612
|
+
response = rpc(:wallet_info, _coerce: Hash)
|
613
|
+
|
614
|
+
if unit == :nano
|
615
|
+
response[:balance] = raw_to_NANO(response[:balance])
|
616
|
+
response[:pending] = raw_to_NANO(response[:pending])
|
502
617
|
end
|
503
618
|
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
619
|
+
response
|
620
|
+
end
|
621
|
+
|
622
|
+
# Reports send/receive information for accounts in wallet. Change blocks are skipped,
|
623
|
+
# open blocks will appear as receive. Response will start with most recent blocks
|
624
|
+
# according to local ledger.
|
625
|
+
#
|
626
|
+
# ==== Example:
|
627
|
+
#
|
628
|
+
# wallet.history
|
629
|
+
#
|
630
|
+
# Example response:
|
631
|
+
#
|
632
|
+
# [
|
633
|
+
# {
|
634
|
+
# "type": "send",
|
635
|
+
# "account": Nanook::Account,
|
636
|
+
# "amount": 3.2,
|
637
|
+
# "block_account": Nanook::Account,
|
638
|
+
# "hash": Nanook::Block,
|
639
|
+
# "local_timestamp": Time
|
640
|
+
# },
|
641
|
+
# {
|
642
|
+
# ...
|
643
|
+
# }
|
644
|
+
# ]
|
645
|
+
#
|
646
|
+
# @param unit (see #balance)
|
647
|
+
# @return [Array<Hash{Symbol=>String|Nanook::Account|Nanook::WalletAccount|Nanook::Block|Integer|Float|Time}>]
|
648
|
+
# @raise [Nanook::NanoUnitError] if `unit` is invalid
|
649
|
+
def history(unit: Nanook.default_unit)
|
650
|
+
validate_unit!(unit)
|
651
|
+
|
652
|
+
rpc(:wallet_history, _access: :history, _coerce: Array).map do |h|
|
653
|
+
h[:account] = account(h[:account])
|
654
|
+
h[:block_account] = as_account(h[:block_account])
|
655
|
+
h[:amount] = raw_to_NANO(h[:amount]) if unit == :nano
|
656
|
+
h[:block] = as_block(h.delete(:hash))
|
657
|
+
h[:local_timestamp] = as_time(h[:local_timestamp])
|
658
|
+
h
|
659
|
+
end
|
508
660
|
end
|
509
661
|
|
510
662
|
# Locks the wallet. A locked wallet cannot pocket pending transactions or make payments. See {#unlock}.
|
@@ -515,9 +667,7 @@ class Nanook
|
|
515
667
|
#
|
516
668
|
# @return [Boolean] indicates if the wallet was successfully locked
|
517
669
|
def lock
|
518
|
-
|
519
|
-
response = rpc(:wallet_lock)
|
520
|
-
!response.empty? && response[:locked] == 1
|
670
|
+
rpc(:wallet_lock, _access: :locked) == 1
|
521
671
|
end
|
522
672
|
|
523
673
|
# Returns +true+ if the wallet is locked.
|
@@ -528,9 +678,7 @@ class Nanook
|
|
528
678
|
#
|
529
679
|
# @return [Boolean] indicates if the wallet is locked
|
530
680
|
def locked?
|
531
|
-
|
532
|
-
response = rpc(:wallet_locked)
|
533
|
-
!response.empty? && response[:locked] != 0
|
681
|
+
rpc(:wallet_locked, _access: :locked) == 1
|
534
682
|
end
|
535
683
|
|
536
684
|
# Unlocks a previously locked wallet.
|
@@ -540,9 +688,8 @@ class Nanook
|
|
540
688
|
# wallet.unlock("new_pass") #=> true
|
541
689
|
#
|
542
690
|
# @return [Boolean] indicates if the unlocking action was successful
|
543
|
-
def unlock(password)
|
544
|
-
|
545
|
-
rpc(:password_enter, password: password)[:valid] == 1
|
691
|
+
def unlock(password = nil)
|
692
|
+
rpc(:password_enter, password: password, _access: :valid) == 1
|
546
693
|
end
|
547
694
|
|
548
695
|
# Changes the password for a wallet.
|
@@ -552,33 +699,73 @@ class Nanook
|
|
552
699
|
# wallet.change_password("new_pass") #=> true
|
553
700
|
# @return [Boolean] indicates if the action was successful
|
554
701
|
def change_password(password)
|
555
|
-
|
556
|
-
|
702
|
+
rpc(:password_change, password: password, _access: :changed) == 1
|
703
|
+
end
|
704
|
+
|
705
|
+
# Tells the node to look for pending blocks for any account in the wallet.
|
706
|
+
#
|
707
|
+
# ==== Example:
|
708
|
+
#
|
709
|
+
# wallet.search_pending #=> true
|
710
|
+
# @return [Boolean] indicates if the action was successful
|
711
|
+
def search_pending
|
712
|
+
rpc(:search_pending, _access: :started) == 1
|
713
|
+
end
|
714
|
+
|
715
|
+
# Returns a list of pairs of {Nanook::WalletAccount} and work for wallet.
|
716
|
+
#
|
717
|
+
# ==== Example:
|
718
|
+
#
|
719
|
+
# wallet.work
|
720
|
+
#
|
721
|
+
# ==== Example response:
|
722
|
+
#
|
723
|
+
# {
|
724
|
+
# Nanook::WalletAccount: "432e5cf728c90f4f",
|
725
|
+
# Nanook::WalletAccount: "4efec5f63fc902cf"
|
726
|
+
# }
|
727
|
+
# @return [Boolean] indicates if the action was successful
|
728
|
+
def work
|
729
|
+
hash = rpc(:wallet_work_get, _access: :works, _coerce: Hash).map do |account_id, work|
|
730
|
+
[as_wallet_account(account_id), work]
|
731
|
+
end
|
732
|
+
|
733
|
+
Hash[hash]
|
557
734
|
end
|
558
735
|
|
559
736
|
private
|
560
737
|
|
561
|
-
def rpc(action, params={})
|
562
|
-
|
563
|
-
|
738
|
+
def rpc(action, params = {})
|
739
|
+
check_wallet_required!
|
740
|
+
|
741
|
+
p = { wallet: @wallet }.compact
|
742
|
+
@rpc.call(action, p.merge(params)).tap { reset_skip_wallet_required! }
|
564
743
|
end
|
565
744
|
|
566
|
-
def
|
567
|
-
|
568
|
-
|
569
|
-
|
745
|
+
def skip_wallet_required!
|
746
|
+
@skip_wallet_required_check = true
|
747
|
+
end
|
748
|
+
|
749
|
+
def reset_skip_wallet_required!
|
750
|
+
@skip_wallet_required_check = false
|
751
|
+
end
|
752
|
+
|
753
|
+
def check_wallet_required!
|
754
|
+
return if @wallet || @skip_wallet_required_check
|
755
|
+
|
756
|
+
raise ArgumentError, 'Wallet must be present'
|
570
757
|
end
|
571
758
|
|
572
759
|
def validate_wallet_contains_account!(account)
|
573
760
|
@known_valid_accounts ||= []
|
574
761
|
return if @known_valid_accounts.include?(account)
|
575
762
|
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
raise ArgumentError.new("Account does not exist in wallet. Account: #{account}, wallet: #{@wallet}")
|
763
|
+
unless contains?(account)
|
764
|
+
raise ArgumentError,
|
765
|
+
"Account does not exist in wallet. Account: #{account}, wallet: #{@wallet}"
|
580
766
|
end
|
581
|
-
end
|
582
767
|
|
768
|
+
@known_valid_accounts << account
|
769
|
+
end
|
583
770
|
end
|
584
771
|
end
|