nano_rpc 0.9.0 → 0.10.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/.rubocop.yml +8 -1
- data/README.md +39 -38
- data/lib/nano_rpc/errors.rb +1 -1
- data/lib/nano_rpc/helpers/account_helper.rb +2 -2
- data/lib/nano_rpc/helpers/accounts_helper.rb +5 -5
- data/lib/nano_rpc/helpers/application_helper.rb +6 -2
- data/lib/nano_rpc/helpers/node_helper.rb +15 -3
- data/lib/nano_rpc/helpers/wallet_helper.rb +7 -7
- data/lib/nano_rpc/node.rb +162 -0
- data/lib/nano_rpc/proxies/account.rb +7 -5
- data/lib/nano_rpc/proxies/accounts.rb +7 -5
- data/lib/nano_rpc/proxies/wallet.rb +6 -6
- data/lib/nano_rpc/proxy.rb +19 -18
- data/lib/nano_rpc/response.rb +8 -8
- data/lib/nano_rpc/version.rb +2 -2
- data/lib/nano_rpc.rb +4 -3
- data/nano_rpc.gemspec +6 -6
- metadata +13 -14
- data/lib/nano_rpc/client.rb +0 -100
- data/lib/nano_rpc/proxies/node.rb +0 -63
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4a14ad62aa7895381a7d304358397e3e0c84895e98a910d6958d8f89f0caf80c
|
4
|
+
data.tar.gz: f873b576248b45a70bcddca71721215dde596950c9ce1833918b1dfa66a72133
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: baef53c6d16c0ffc55bc649335dbf61c339a7e3638bf5d05bf199b9de990e108938af88ec01888275efe99e61f96dfb8ef7862b3b861a8264297adec1ba6534a
|
7
|
+
data.tar.gz: 583673b49fc417a05d8b0c08d9caa8ad9bfad57eabb26bbaff0e735222b27ea6f6f5c564c76cc1ee256024412c0e4416dcce7b5428a5483a9c253b9d862b1dda
|
data/.rubocop.yml
CHANGED
@@ -1,8 +1,15 @@
|
|
1
1
|
AllCops:
|
2
2
|
TargetRubyVersion: 2.5.0
|
3
3
|
Exclude:
|
4
|
-
-
|
4
|
+
- bin/*
|
5
5
|
DisplayCopNames: true
|
6
|
+
Metrics/BlockLength:
|
7
|
+
Exclude:
|
8
|
+
- spec/**/*
|
9
|
+
Metrics/ModuleLength:
|
10
|
+
Max: 200
|
11
|
+
Metrics/ClassLength:
|
12
|
+
Max: 200
|
6
13
|
Style/ClassAndModuleChildren:
|
7
14
|
EnforcedStyle: compact
|
8
15
|
Style/EmptyMethod:
|
data/README.md
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
[](https://codeclimate.com/github/codeclimate/codeclimate/maintainability)
|
2
|
+
|
1
3
|

|
2
4
|
|
3
5
|
Nano RPC is a Ruby wrapper for making Remote Procedure Calls against Nano digital currency nodes. Arbitrary RPC access is provided along with proxy objects that expose helper methods ([Wiki](https://github.com/jcraigk/ruby_nano_rpc/wiki)).
|
@@ -22,90 +24,89 @@ Or install it yourself as:
|
|
22
24
|
|
23
25
|
## Usage
|
24
26
|
|
25
|
-
There are two ways to use this gem. You can make direct
|
27
|
+
There are two ways to use this gem. You can make direct RPC calls using Ruby hashes or you can use proxy objects for terser code.
|
26
28
|
|
27
29
|
### Raw RPC Calls
|
28
30
|
|
29
|
-
The
|
31
|
+
The NanoRpc::Node object exposes raw Remote Procedure Call methods according to the [Nano RPC Docs](https://github.com/clemahieu/raiblocks/wiki/RPC-protocol).
|
30
32
|
|
31
33
|
Every method requires an `action`, which is passed as the first argument to `call`. Depending on the action, there may be additional required or optional parameters that are passed as an options hash.
|
32
34
|
|
33
|
-
First setup the
|
35
|
+
First setup the node connection:
|
34
36
|
|
35
37
|
```ruby
|
36
38
|
# Connect to the default node (localhost:7076)
|
37
|
-
|
39
|
+
node = NanoRpc.node
|
38
40
|
|
39
41
|
# or connect to a custom node
|
40
|
-
|
42
|
+
node = NanoRpc::Node.new(host: 'mynanonode', port: 1234)
|
41
43
|
```
|
42
44
|
|
43
45
|
If you're using [Nanode](https://www.nanode.co/) or similar service that requires `Authorization` key in HTTP header, you can specify it using `auth`.
|
44
46
|
|
45
47
|
```ruby
|
46
|
-
|
48
|
+
node = NanoRpc::Node.new(auth: 'someauthkey')
|
47
49
|
```
|
48
50
|
|
49
51
|
You can also specify custom headers as a hash. These will be sent with every RPC request.
|
50
52
|
|
51
53
|
```ruby
|
52
|
-
|
54
|
+
node = NanoRpc::Node.new(headers: { 'Authorization' => 'someauthkey' })
|
53
55
|
```
|
54
56
|
|
55
|
-
Once the
|
57
|
+
Once the node is setup, make a `call`, passing the action and data:
|
56
58
|
|
57
59
|
```ruby
|
58
|
-
|
59
|
-
|
60
|
-
|
60
|
+
node.call(:account_balance, account: 'xrb_1234')
|
61
|
+
# => {"balance"=>100, "pending"=>0}
|
62
|
+
```
|
61
63
|
|
62
64
|
Response data are provided as [Hashie](https://github.com/intridea/hashie) objects with integer coercion, indifferent access, and method access.
|
63
65
|
|
64
66
|
```ruby
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
67
|
+
data = node.call(:account_balance, account: 'xrb_1234')
|
68
|
+
# => {"balance"=>100, "pending"=>0}
|
69
|
+
data.balance
|
70
|
+
# => 100
|
71
|
+
data[:balance]
|
72
|
+
# => 100
|
73
|
+
data['balance']
|
74
|
+
# => 100
|
75
|
+
```
|
74
76
|
|
75
77
|
### Proxy Objects / Helper Methods
|
76
78
|
|
77
79
|
Proxy objects are provided to ease interaction with the API by providing logically grouped helper methods. Here we do not strictly follow the grouping as expressed in the [Nano RPC Docs](https://github.com/clemahieu/raiblocks/wiki/RPC-protocol). Instead, the following objects are provided:
|
78
80
|
|
79
|
-
* [
|
80
|
-
* [
|
81
|
-
* [
|
82
|
-
* [
|
81
|
+
* [NanoRpc::Account](https://github.com/jcraigk/ruby_nano_rpc/wiki/NanoRpc::Account)
|
82
|
+
* [NanoRpc::Accounts](https://github.com/jcraigk/ruby_nano_rpc/wiki/NanoRpc::Accounts)
|
83
|
+
* [NanoRpc::Node](https://github.com/jcraigk/ruby_nano_rpc/wiki/NanoRpc::Node)
|
84
|
+
* [NanoRpc::Wallet](https://github.com/jcraigk/ruby_nano_rpc/wiki/NanoRpc::Wallet)
|
83
85
|
|
84
86
|
`Account`, `Accounts`, and `Wallet` each require a single parameter to be passed during initialization (`address`, `addresses`, and `seed`, respectively). This parameter is persisted for subsequent calls. All RPC methods are provided directly as methods.
|
85
87
|
|
86
88
|
```ruby
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
# => {"balance"=>100, "pending"=>5}
|
91
|
-
account.account_balance.balance
|
92
|
-
# => 100
|
89
|
+
account = node.account('xrb_1234') # Account address required
|
90
|
+
accounts = node.accounts(['xrb_1234', 'xrb_456']) # Array of account addresses required
|
91
|
+
wallet = node.wallet('3AF91AE') # Wallet seed required
|
93
92
|
```
|
94
93
|
|
95
|
-
|
94
|
+
You can call standard RPC methods on each object:
|
96
95
|
|
97
96
|
```ruby
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
97
|
+
account.account_balance
|
98
|
+
# => {"balance"=>100, "pending"=>5}
|
99
|
+
account.account_balance.balance
|
100
|
+
# => 100
|
102
101
|
```
|
103
102
|
|
104
|
-
|
103
|
+
There are also helper methods to bypass repetitive nested calls:
|
105
104
|
|
106
105
|
```ruby
|
107
|
-
|
108
|
-
|
106
|
+
account.balance
|
107
|
+
# => 100
|
108
|
+
account.pending_balance
|
109
|
+
# => 5
|
109
110
|
```
|
110
111
|
|
111
112
|
For a comprehensive guide, see the [Wiki](https://github.com/jcraigk/ruby_nano_rpc/wiki).
|
data/lib/nano_rpc/errors.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
module
|
3
|
-
include
|
2
|
+
module NanoRpc::AccountsHelper
|
3
|
+
include NanoRpc::ApplicationHelper
|
4
4
|
|
5
5
|
def balances
|
6
6
|
accounts_balances
|
@@ -36,11 +36,11 @@ module Nano::AccountsHelper
|
|
36
36
|
end
|
37
37
|
alias pending_blocks pending
|
38
38
|
|
39
|
-
# Array-like access for
|
39
|
+
# Array-like access for NanoRpc::Account
|
40
40
|
def [](idx)
|
41
41
|
return unless @addresses[idx]
|
42
42
|
@account_objects ||= []
|
43
|
-
@account_objects[idx] ||=
|
43
|
+
@account_objects[idx] ||= NanoRpc::Account.new(@addresses[idx], node: node)
|
44
44
|
end
|
45
45
|
|
46
46
|
def <<(val)
|
@@ -49,7 +49,7 @@ module Nano::AccountsHelper
|
|
49
49
|
|
50
50
|
def each(&_block)
|
51
51
|
@addresses.each do |address|
|
52
|
-
yield
|
52
|
+
yield NanoRpc::Account.new(address, node: node)
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
@@ -1,8 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
module
|
2
|
+
module NanoRpc::ApplicationHelper
|
3
3
|
private
|
4
4
|
|
5
5
|
def inspect_prefix
|
6
|
-
"#<#{self.class}:#{
|
6
|
+
"#<#{self.class}:#{obj_id}"
|
7
|
+
end
|
8
|
+
|
9
|
+
def obj_id
|
10
|
+
format('0x00%<object_id>x', object_id: object_id << 1)
|
7
11
|
end
|
8
12
|
end
|
@@ -1,13 +1,21 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
module
|
3
|
-
include
|
2
|
+
module NanoRpc::NodeHelper
|
3
|
+
include NanoRpc::ApplicationHelper
|
4
4
|
|
5
5
|
def account_containing_block(hash:)
|
6
6
|
block_account(hash: hash).account
|
7
7
|
end
|
8
8
|
|
9
|
+
def account(address)
|
10
|
+
NanoRpc::Account.new(address, node: self)
|
11
|
+
end
|
12
|
+
|
13
|
+
def accounts(addresses)
|
14
|
+
NanoRpc::Accounts.new(addresses, node: self)
|
15
|
+
end
|
16
|
+
|
9
17
|
def create_wallet
|
10
|
-
|
18
|
+
NanoRpc::Wallet.new(wallet_create.wallet, node: self)
|
11
19
|
end
|
12
20
|
|
13
21
|
def knano_from_raw(amount:)
|
@@ -46,6 +54,10 @@ module Nano::NodeHelper
|
|
46
54
|
available_supply.available
|
47
55
|
end
|
48
56
|
|
57
|
+
def wallet(seed)
|
58
|
+
NanoRpc::Wallet.new(seed, node: self)
|
59
|
+
end
|
60
|
+
|
49
61
|
def work_valid?(work:, hash:)
|
50
62
|
work_validate(work: work, hash: hash).valid == 1
|
51
63
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
module
|
3
|
-
include
|
2
|
+
module NanoRpc::WalletHelper
|
3
|
+
include NanoRpc::ApplicationHelper
|
4
4
|
|
5
5
|
def account_work(account:)
|
6
6
|
work_get(account: account).work
|
@@ -8,7 +8,7 @@ module Nano::WalletHelper
|
|
8
8
|
|
9
9
|
def accounts
|
10
10
|
return [] unless account_list.accounts.size.positive?
|
11
|
-
|
11
|
+
NanoRpc::Accounts.new(account_list.accounts, node: node)
|
12
12
|
end
|
13
13
|
|
14
14
|
def add_key(key:, work: true)
|
@@ -49,12 +49,12 @@ module Nano::WalletHelper
|
|
49
49
|
|
50
50
|
def create_account(work: true)
|
51
51
|
address = account_create(work: work).account
|
52
|
-
|
52
|
+
NanoRpc::Account.new(address, node: node)
|
53
53
|
end
|
54
54
|
|
55
55
|
def create_accounts(count:, work: true)
|
56
56
|
addresses = accounts_create(count: count, work: work).accounts
|
57
|
-
|
57
|
+
NanoRpc::Accounts.new(addresses, node: node)
|
58
58
|
end
|
59
59
|
|
60
60
|
def destroy
|
@@ -67,7 +67,7 @@ module Nano::WalletHelper
|
|
67
67
|
alias unlock enter_password
|
68
68
|
|
69
69
|
def export
|
70
|
-
|
70
|
+
NanoRpc::Response.new(JSON[wallet_export.json])
|
71
71
|
end
|
72
72
|
|
73
73
|
def frontiers
|
@@ -79,7 +79,7 @@ module Nano::WalletHelper
|
|
79
79
|
end
|
80
80
|
|
81
81
|
def ledger
|
82
|
-
wallet_ledger
|
82
|
+
wallet_ledger.accounts
|
83
83
|
end
|
84
84
|
|
85
85
|
def locked?
|
@@ -0,0 +1,162 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'rest-client'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module NanoRpc
|
6
|
+
def self.node
|
7
|
+
@node ||= Node.new
|
8
|
+
end
|
9
|
+
|
10
|
+
class Node
|
11
|
+
include NanoRpc::Proxy
|
12
|
+
include NanoRpc::NodeHelper
|
13
|
+
|
14
|
+
attr_reader :host, :port, :auth, :headers, :node
|
15
|
+
|
16
|
+
def initialize(host: 'localhost', port: 7076, auth: nil, headers: nil)
|
17
|
+
@host = host
|
18
|
+
@port = port
|
19
|
+
@auth = auth
|
20
|
+
@headers = headers
|
21
|
+
@node = self
|
22
|
+
|
23
|
+
super
|
24
|
+
end
|
25
|
+
|
26
|
+
# Condense host/port on object inspection
|
27
|
+
def inspect
|
28
|
+
"#{inspect_prefix}, @url=\"#{@host}:#{port}\">"
|
29
|
+
end
|
30
|
+
|
31
|
+
def call(action, params = {})
|
32
|
+
args = { action: action }
|
33
|
+
args.merge!(params) if params.is_a?(Hash)
|
34
|
+
args = extract_proxy_args(args)
|
35
|
+
rpc_post(args)
|
36
|
+
end
|
37
|
+
|
38
|
+
proxy_method :available_supply
|
39
|
+
proxy_method :block, required: %i[hash]
|
40
|
+
proxy_method :block_account, required: %i[hash]
|
41
|
+
proxy_method :block_confirm, required: %i[hash]
|
42
|
+
proxy_method :block_count
|
43
|
+
proxy_method :block_count_type
|
44
|
+
proxy_method :block_create,
|
45
|
+
required: %i[type key representative source],
|
46
|
+
optional: %i[work]
|
47
|
+
proxy_method :blocks, required: %i[hashes]
|
48
|
+
proxy_method :blocks_info,
|
49
|
+
required: %i[hashes],
|
50
|
+
optional: %i[pending source balance]
|
51
|
+
proxy_method :bootstrap, required: %i[address port]
|
52
|
+
proxy_method :bootstrap_any
|
53
|
+
proxy_method :chain, required: %i[block count]
|
54
|
+
proxy_method :confirmation_history
|
55
|
+
proxy_method :deterministic_key, required: %i[seed index]
|
56
|
+
proxy_method :frontier_count
|
57
|
+
proxy_method :history, required: %i[hash count]
|
58
|
+
proxy_method :keepalive, required: %i[address port]
|
59
|
+
proxy_method :key_create
|
60
|
+
proxy_method :key_expand, required: %i[key]
|
61
|
+
proxy_method :krai_from_raw, required: %i[amount]
|
62
|
+
proxy_method :krai_to_raw, required: %i[amount]
|
63
|
+
proxy_method :mrai_from_raw, required: %i[amount]
|
64
|
+
proxy_method :mrai_to_raw, required: %i[amount]
|
65
|
+
proxy_method :payment_wait, required: %i[account amount timeout]
|
66
|
+
proxy_method :peers
|
67
|
+
proxy_method :pending_exists, required: %i[hash]
|
68
|
+
proxy_method :process, required: %i[block]
|
69
|
+
proxy_method :rai_from_raw, required: %i[amount]
|
70
|
+
proxy_method :rai_to_raw, required: %i[amount]
|
71
|
+
proxy_method :receive_minimum
|
72
|
+
proxy_method :receive_minimum_set, required: %i[amount]
|
73
|
+
proxy_method :representatives
|
74
|
+
proxy_method :representatives_online
|
75
|
+
proxy_method :republish,
|
76
|
+
required: %i[hash],
|
77
|
+
optional: %i[count sources destinations]
|
78
|
+
proxy_method :search_pending, required: %i[wallet]
|
79
|
+
proxy_method :search_pending_all
|
80
|
+
proxy_method :stats, required: %i[type]
|
81
|
+
proxy_method :stop
|
82
|
+
proxy_method :successors, required: %i[block count]
|
83
|
+
proxy_method :unchecked, required: %i[count]
|
84
|
+
proxy_method :unchecked_clear
|
85
|
+
proxy_method :unchecked_get, required: %i[hash]
|
86
|
+
proxy_method :unchecked_keys, required: %i[key count]
|
87
|
+
proxy_method :version
|
88
|
+
proxy_method :wallet_create
|
89
|
+
proxy_method :work_cancel, required: %i[hash]
|
90
|
+
proxy_method :work_generate, required: %i[hash]
|
91
|
+
proxy_method :work_peer_add, required: %i[address port]
|
92
|
+
proxy_method :work_peers
|
93
|
+
proxy_method :work_peers_clear
|
94
|
+
proxy_method :work_validate, required: %i[work hash]
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
def extract_proxy_args(args)
|
99
|
+
args.each do |k, v|
|
100
|
+
m = proxy_method(v)
|
101
|
+
args[k] = v.send(m) if m
|
102
|
+
end
|
103
|
+
args
|
104
|
+
end
|
105
|
+
|
106
|
+
def proxy_method(obj)
|
107
|
+
if obj.is_a?(NanoRpc::Wallet)
|
108
|
+
:seed
|
109
|
+
elsif obj.is_a?(NanoRpc::Accounts)
|
110
|
+
:addresses
|
111
|
+
elsif obj.is_a?(NanoRpc::Account)
|
112
|
+
:address
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def rpc_post(params)
|
117
|
+
response = rest_client_post(url, params)
|
118
|
+
ensure_status_success!(response)
|
119
|
+
data = NanoRpc::Response.new(JSON[response&.body])
|
120
|
+
ensure_valid_response!(data)
|
121
|
+
|
122
|
+
data
|
123
|
+
end
|
124
|
+
|
125
|
+
def request_headers
|
126
|
+
h = headers || {}
|
127
|
+
h['Content-Type'] = 'json'
|
128
|
+
h['Authorization'] = auth unless auth.nil?
|
129
|
+
h
|
130
|
+
end
|
131
|
+
|
132
|
+
def rest_client_post(url, params)
|
133
|
+
RestClient.post(url, params.to_json, request_headers)
|
134
|
+
rescue Errno::ECONNREFUSED
|
135
|
+
raise NanoRpc::NodeConnectionFailure,
|
136
|
+
"Node connection failure at #{url}"
|
137
|
+
rescue RestClient::Exceptions::OpenTimeout
|
138
|
+
raise NanoRpc::NodeOpenTimeout,
|
139
|
+
'Node failed to respond in time'
|
140
|
+
end
|
141
|
+
|
142
|
+
def url
|
143
|
+
if host.start_with?('http://', 'https://')
|
144
|
+
"#{host}:#{port}"
|
145
|
+
else
|
146
|
+
"http://#{host}:#{port}"
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def ensure_status_success!(response)
|
151
|
+
return if response&.code == 200
|
152
|
+
raise NanoRpc::BadRequest,
|
153
|
+
"Error response from node: #{JSON[response&.body]}"
|
154
|
+
end
|
155
|
+
|
156
|
+
def ensure_valid_response!(data)
|
157
|
+
return unless data['error']
|
158
|
+
raise NanoRpc::InvalidRequest,
|
159
|
+
"Invalid request: #{data['error']}"
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
@@ -1,13 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
class
|
3
|
-
include
|
4
|
-
include
|
2
|
+
class NanoRpc::Account
|
3
|
+
include NanoRpc::Proxy
|
4
|
+
include NanoRpc::AccountHelper
|
5
5
|
|
6
6
|
attr_reader :address
|
7
7
|
|
8
8
|
def initialize(address = nil, opts = {})
|
9
9
|
unless address.is_a?(String)
|
10
|
-
raise
|
10
|
+
raise NanoRpc::MissingParameters,
|
11
11
|
'Missing argument: address (str)'
|
12
12
|
end
|
13
13
|
|
@@ -33,7 +33,9 @@ class Nano::Account
|
|
33
33
|
proxy_method :frontiers, required: %i[count]
|
34
34
|
proxy_method :ledger,
|
35
35
|
required: %i[count],
|
36
|
-
optional: %i[
|
36
|
+
optional: %i[
|
37
|
+
representative weight pending modified_since sorting
|
38
|
+
]
|
37
39
|
proxy_method :validate_account_number
|
38
40
|
proxy_method :pending, required: %i[count], optional: %i[threshold exists]
|
39
41
|
proxy_method :payment_wait, required: %i[amount timeout]
|
@@ -1,13 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
class
|
3
|
-
include
|
4
|
-
include
|
2
|
+
class NanoRpc::Accounts
|
3
|
+
include NanoRpc::Proxy
|
4
|
+
include NanoRpc::AccountsHelper
|
5
5
|
|
6
6
|
attr_reader :addresses
|
7
7
|
|
8
8
|
def initialize(addresses = nil, opts = {})
|
9
9
|
unless addresses.is_a?(Array)
|
10
|
-
raise
|
10
|
+
raise NanoRpc::MissingParameters,
|
11
11
|
'Missing argument: addresses (str[])'
|
12
12
|
end
|
13
13
|
|
@@ -19,7 +19,9 @@ class Nano::Accounts
|
|
19
19
|
|
20
20
|
proxy_method :account_move, required: %i[wallet source]
|
21
21
|
proxy_method :accounts_balances
|
22
|
-
proxy_method :accounts_create,
|
22
|
+
proxy_method :accounts_create,
|
23
|
+
required: %i[wallet count],
|
24
|
+
optional: %i[work]
|
23
25
|
proxy_method :accounts_frontiers
|
24
26
|
proxy_method :accounts_pending,
|
25
27
|
required: %i[count], optional: %i[threshold source]
|
@@ -1,14 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
class
|
3
|
-
include
|
4
|
-
include
|
2
|
+
class NanoRpc::Wallet
|
3
|
+
include NanoRpc::Proxy
|
4
|
+
include NanoRpc::WalletHelper
|
5
5
|
|
6
6
|
attr_reader :seed
|
7
7
|
|
8
8
|
def initialize(seed = nil, opts = {})
|
9
9
|
unless seed.is_a?(String)
|
10
|
-
raise
|
11
|
-
'Missing argument:
|
10
|
+
raise NanoRpc::MissingParameters,
|
11
|
+
'Missing argument: seed (str)'
|
12
12
|
end
|
13
13
|
|
14
14
|
@seed = seed
|
@@ -17,7 +17,7 @@ class Nano::Wallet
|
|
17
17
|
|
18
18
|
# Hide secret seed on object inspection
|
19
19
|
def inspect
|
20
|
-
"#{inspect_prefix}, @
|
20
|
+
"#{inspect_prefix}, @node=#{@node.inspect}>"
|
21
21
|
end
|
22
22
|
|
23
23
|
proxy_params wallet: :seed
|
data/lib/nano_rpc/proxy.rb
CHANGED
@@ -1,11 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
module
|
3
|
-
|
4
|
-
|
5
|
-
attr_accessor :client
|
2
|
+
module NanoRpc::Proxy
|
3
|
+
attr_reader :node
|
6
4
|
|
7
5
|
def initialize(opts = {})
|
8
|
-
@
|
6
|
+
@node ||= opts[:node] || NanoRpc.node
|
9
7
|
self.class.proxy_methods&.each { |m| define_proxy_method(m) }
|
10
8
|
end
|
11
9
|
|
@@ -35,9 +33,9 @@ module Nano::Proxy
|
|
35
33
|
|
36
34
|
private
|
37
35
|
|
38
|
-
def define_proxy_method(
|
39
|
-
self.class.send(:define_method, method_alias(
|
40
|
-
@
|
36
|
+
def define_proxy_method(meth)
|
37
|
+
self.class.send(:define_method, method_alias(meth)) do |args = {}|
|
38
|
+
@meth = meth
|
41
39
|
@call_args = args
|
42
40
|
|
43
41
|
validate_params!
|
@@ -46,7 +44,7 @@ module Nano::Proxy
|
|
46
44
|
end
|
47
45
|
|
48
46
|
def execute_call
|
49
|
-
expose_nested_data(
|
47
|
+
expose_nested_data(node.call(@meth, @call_args))
|
50
48
|
end
|
51
49
|
|
52
50
|
def base_params
|
@@ -61,13 +59,16 @@ module Nano::Proxy
|
|
61
59
|
end
|
62
60
|
|
63
61
|
# Nano `send` action is also the method caller in Ruby ;)
|
64
|
-
def method_alias(
|
65
|
-
|
62
|
+
def method_alias(meth)
|
63
|
+
meth == :send ? :send_currency : meth
|
66
64
|
end
|
67
65
|
|
68
66
|
# If single-key response matches method name, expose nested data
|
69
67
|
def expose_nested_data(data)
|
70
|
-
data.is_a?(Hash) && data.keys.map(&:to_s) == [@
|
68
|
+
if data.is_a?(Hash) && data.keys.map(&:to_s) == [@meth.to_s]
|
69
|
+
return data[@meth]
|
70
|
+
end
|
71
|
+
data
|
71
72
|
end
|
72
73
|
|
73
74
|
def validate_params!
|
@@ -91,14 +92,14 @@ module Nano::Proxy
|
|
91
92
|
def ensure_required_params!
|
92
93
|
missing_params = required_params - opts_keys
|
93
94
|
return unless missing_params.any?
|
94
|
-
raise
|
95
|
+
raise NanoRpc::MissingParameters,
|
95
96
|
"Missing required parameter(s): #{missing_params.join(', ')}"
|
96
97
|
end
|
97
98
|
|
98
99
|
def prevent_forbidden_params!
|
99
100
|
forbidden_params = base_param_keys + opts_keys - allowed_params
|
100
101
|
return unless forbidden_params.any?
|
101
|
-
raise
|
102
|
+
raise NanoRpc::ForbiddenParameter,
|
102
103
|
"Forbidden parameter(s) passed: #{forbidden_params.join(', ')}"
|
103
104
|
end
|
104
105
|
|
@@ -115,13 +116,13 @@ module Nano::Proxy
|
|
115
116
|
end
|
116
117
|
|
117
118
|
def required_params
|
118
|
-
return [] unless method_def && method_def[@
|
119
|
-
method_def[@
|
119
|
+
return [] unless method_def && method_def[@meth]
|
120
|
+
method_def[@meth][:required] || []
|
120
121
|
end
|
121
122
|
|
122
123
|
def optional_params
|
123
|
-
return [] unless method_def && method_def[@
|
124
|
-
method_def[@
|
124
|
+
return [] unless method_def && method_def[@meth]
|
125
|
+
method_def[@meth][:optional] || []
|
125
126
|
end
|
126
127
|
|
127
128
|
def base_param_keys
|
data/lib/nano_rpc/response.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
require 'hashie'
|
3
3
|
|
4
|
-
class
|
4
|
+
class NanoRpc::Response < Hash
|
5
5
|
include ::Hashie::Extensions::MergeInitializer
|
6
6
|
include ::Hashie::Extensions::IndifferentAccess
|
7
7
|
include ::Hashie::Extensions::MethodAccess
|
@@ -17,15 +17,15 @@ class Nano::Response < Hash
|
|
17
17
|
merge!(self) { |_k, v| to_f_or_i_or_s(v) }
|
18
18
|
end
|
19
19
|
|
20
|
-
def to_f_or_i_or_s(
|
21
|
-
return if
|
22
|
-
return
|
23
|
-
(float = Float(
|
20
|
+
def to_f_or_i_or_s(val)
|
21
|
+
return if val.nil?
|
22
|
+
return val.to_i if big_integer?(val)
|
23
|
+
(float = Float(val)) && (float % 1.0).zero? ? float.to_i : float
|
24
24
|
rescue ArgumentError, TypeError
|
25
|
-
|
25
|
+
val
|
26
26
|
end
|
27
27
|
|
28
|
-
def big_integer?(
|
29
|
-
|
28
|
+
def big_integer?(val)
|
29
|
+
val.respond_to?(:to_i) && val.to_i > 1_000_000_000_000_000
|
30
30
|
end
|
31
31
|
end
|
data/lib/nano_rpc/version.rb
CHANGED
data/lib/nano_rpc.rb
CHANGED
@@ -1,15 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
require 'nano_rpc/version'
|
3
|
+
|
3
4
|
require 'nano_rpc/helpers/application_helper'
|
4
5
|
require 'nano_rpc/helpers/account_helper'
|
5
6
|
require 'nano_rpc/helpers/accounts_helper'
|
6
7
|
require 'nano_rpc/helpers/node_helper'
|
7
8
|
require 'nano_rpc/helpers/wallet_helper'
|
8
|
-
|
9
|
-
require 'nano_rpc/errors'
|
9
|
+
|
10
10
|
require 'nano_rpc/proxy'
|
11
|
+
require 'nano_rpc/node'
|
12
|
+
require 'nano_rpc/errors'
|
11
13
|
require 'nano_rpc/response'
|
12
14
|
require 'nano_rpc/proxies/account'
|
13
15
|
require 'nano_rpc/proxies/accounts'
|
14
|
-
require 'nano_rpc/proxies/node'
|
15
16
|
require 'nano_rpc/proxies/wallet'
|
data/nano_rpc.gemspec
CHANGED
@@ -5,7 +5,7 @@ require 'nano_rpc/version'
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = 'nano_rpc'
|
8
|
-
spec.version =
|
8
|
+
spec.version = NanoRpc::VERSION
|
9
9
|
spec.authors = ['Justin Craig-Kuhn (JCK)']
|
10
10
|
spec.email = ['jcraigk@gmail.com']
|
11
11
|
|
@@ -23,12 +23,12 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
24
24
|
spec.require_paths = %w[lib]
|
25
25
|
|
26
|
-
spec.add_development_dependency 'bundler', '~> 1.16'
|
26
|
+
spec.add_development_dependency 'bundler', '~> 1.16.1'
|
27
27
|
spec.add_development_dependency 'pry', '~> 0.11.3'
|
28
|
-
spec.add_development_dependency 'rake', '~>
|
29
|
-
spec.add_development_dependency 'rspec', '~> 3.0'
|
30
|
-
spec.add_development_dependency 'rubocop', '~> 0.
|
31
|
-
spec.add_development_dependency 'simplecov', '~> 0.
|
28
|
+
spec.add_development_dependency 'rake', '~> 12.3.1'
|
29
|
+
spec.add_development_dependency 'rspec', '~> 3.7.0'
|
30
|
+
spec.add_development_dependency 'rubocop', '~> 0.56.0'
|
31
|
+
spec.add_development_dependency 'simplecov', '~> 0.16.1'
|
32
32
|
|
33
33
|
spec.add_runtime_dependency 'hashie', '~> 3.5', '>= 3.5.7'
|
34
34
|
spec.add_runtime_dependency 'rest-client', '~> 2.0', '>= 2.0.2'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nano_rpc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Craig-Kuhn (JCK)
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-05-
|
11
|
+
date: 2018-05-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 1.16.1
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 1.16.1
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: pry
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -44,56 +44,56 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
47
|
+
version: 12.3.1
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
54
|
+
version: 12.3.1
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: rspec
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
61
|
+
version: 3.7.0
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version:
|
68
|
+
version: 3.7.0
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rubocop
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: 0.
|
75
|
+
version: 0.56.0
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: 0.
|
82
|
+
version: 0.56.0
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: simplecov
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
87
|
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: 0.
|
89
|
+
version: 0.16.1
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: 0.
|
96
|
+
version: 0.16.1
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
98
|
name: hashie
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -152,16 +152,15 @@ files:
|
|
152
152
|
- bin/console
|
153
153
|
- bin/setup
|
154
154
|
- lib/nano_rpc.rb
|
155
|
-
- lib/nano_rpc/client.rb
|
156
155
|
- lib/nano_rpc/errors.rb
|
157
156
|
- lib/nano_rpc/helpers/account_helper.rb
|
158
157
|
- lib/nano_rpc/helpers/accounts_helper.rb
|
159
158
|
- lib/nano_rpc/helpers/application_helper.rb
|
160
159
|
- lib/nano_rpc/helpers/node_helper.rb
|
161
160
|
- lib/nano_rpc/helpers/wallet_helper.rb
|
161
|
+
- lib/nano_rpc/node.rb
|
162
162
|
- lib/nano_rpc/proxies/account.rb
|
163
163
|
- lib/nano_rpc/proxies/accounts.rb
|
164
|
-
- lib/nano_rpc/proxies/node.rb
|
165
164
|
- lib/nano_rpc/proxies/wallet.rb
|
166
165
|
- lib/nano_rpc/proxy.rb
|
167
166
|
- lib/nano_rpc/response.rb
|
data/lib/nano_rpc/client.rb
DELETED
@@ -1,100 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
require 'rest-client'
|
3
|
-
require 'json'
|
4
|
-
|
5
|
-
module Nano
|
6
|
-
def self.client
|
7
|
-
@client ||= Client.new
|
8
|
-
end
|
9
|
-
|
10
|
-
class Client
|
11
|
-
include Nano::ApplicationHelper
|
12
|
-
|
13
|
-
attr_reader :host, :port, :auth, :headers
|
14
|
-
|
15
|
-
def initialize(host: 'localhost', port: 7076, auth: nil, headers: nil)
|
16
|
-
@host = host
|
17
|
-
@port = port
|
18
|
-
@auth = auth
|
19
|
-
@headers = headers
|
20
|
-
end
|
21
|
-
|
22
|
-
# Condense host/port on object inspection
|
23
|
-
def inspect
|
24
|
-
"#{inspect_prefix}, @url=\"#{@host}:#{port}\">"
|
25
|
-
end
|
26
|
-
|
27
|
-
def call(action, params = {})
|
28
|
-
args = { action: action }
|
29
|
-
args.merge!(params) if params.is_a?(Hash)
|
30
|
-
args = extract_proxy_args(args)
|
31
|
-
rpc_post(args)
|
32
|
-
end
|
33
|
-
|
34
|
-
private
|
35
|
-
|
36
|
-
def extract_proxy_args(args)
|
37
|
-
args.each do |k, v|
|
38
|
-
m = proxy_method(v)
|
39
|
-
args[k] = v.send(m) if m
|
40
|
-
end
|
41
|
-
args
|
42
|
-
end
|
43
|
-
|
44
|
-
def proxy_method(v)
|
45
|
-
if v.is_a?(Nano::Wallet)
|
46
|
-
:seed
|
47
|
-
elsif v.is_a?(Nano::Accounts)
|
48
|
-
:addresses
|
49
|
-
elsif v.is_a?(Nano::Account)
|
50
|
-
:address
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
def rpc_post(params)
|
55
|
-
response = rest_client_post(url, params)
|
56
|
-
ensure_status_success!(response)
|
57
|
-
data = Nano::Response.new(JSON[response&.body])
|
58
|
-
ensure_valid_response!(data)
|
59
|
-
|
60
|
-
data
|
61
|
-
end
|
62
|
-
|
63
|
-
def request_headers
|
64
|
-
h = headers || {}
|
65
|
-
h['Content-Type'] = 'json'
|
66
|
-
h['Authorization'] = auth unless auth.nil?
|
67
|
-
h
|
68
|
-
end
|
69
|
-
|
70
|
-
def rest_client_post(url, params)
|
71
|
-
RestClient.post(url, params.to_json, request_headers)
|
72
|
-
rescue Errno::ECONNREFUSED
|
73
|
-
raise Nano::NodeConnectionFailure,
|
74
|
-
"Node connection failure at #{url}"
|
75
|
-
rescue RestClient::Exceptions::OpenTimeout
|
76
|
-
raise Nano::NodeOpenTimeout,
|
77
|
-
'Node failed to respond in time'
|
78
|
-
end
|
79
|
-
|
80
|
-
def url
|
81
|
-
if host.start_with?('http://', 'https://')
|
82
|
-
"#{host}:#{port}"
|
83
|
-
else
|
84
|
-
"http://#{host}:#{port}"
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
def ensure_status_success!(response)
|
89
|
-
return if response&.code == 200
|
90
|
-
raise Nano::BadRequest,
|
91
|
-
"Error response from node: #{JSON[response&.body]}"
|
92
|
-
end
|
93
|
-
|
94
|
-
def ensure_valid_response!(data)
|
95
|
-
return unless data['error']
|
96
|
-
raise Nano::InvalidRequest,
|
97
|
-
"Invalid request: #{data['error']}"
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
@@ -1,63 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
class Nano::Node
|
3
|
-
include Nano::Proxy
|
4
|
-
include Nano::NodeHelper
|
5
|
-
|
6
|
-
proxy_method :available_supply
|
7
|
-
proxy_method :block, required: %i[hash]
|
8
|
-
proxy_method :block_account, required: %i[hash]
|
9
|
-
proxy_method :block_confirm, required: %i[hash]
|
10
|
-
proxy_method :block_count
|
11
|
-
proxy_method :block_count_type
|
12
|
-
proxy_method :block_create,
|
13
|
-
required: %i[type key representative source],
|
14
|
-
optional: %i[work]
|
15
|
-
proxy_method :blocks, required: %i[hashes]
|
16
|
-
proxy_method :blocks_info,
|
17
|
-
required: %i[hashes],
|
18
|
-
optional: %i[pending source balance]
|
19
|
-
proxy_method :bootstrap, required: %i[address port]
|
20
|
-
proxy_method :bootstrap_any
|
21
|
-
proxy_method :chain, required: %i[block count]
|
22
|
-
proxy_method :confirmation_history
|
23
|
-
proxy_method :deterministic_key, required: %i[seed index]
|
24
|
-
proxy_method :frontier_count
|
25
|
-
proxy_method :history, required: %i[hash count]
|
26
|
-
proxy_method :keepalive, required: %i[address port]
|
27
|
-
proxy_method :key_create
|
28
|
-
proxy_method :key_expand, required: %i[key]
|
29
|
-
proxy_method :krai_from_raw, required: %i[amount]
|
30
|
-
proxy_method :krai_to_raw, required: %i[amount]
|
31
|
-
proxy_method :mrai_from_raw, required: %i[amount]
|
32
|
-
proxy_method :mrai_to_raw, required: %i[amount]
|
33
|
-
proxy_method :payment_wait, required: %i[account amount timeout]
|
34
|
-
proxy_method :peers
|
35
|
-
proxy_method :pending_exists, required: %i[hash]
|
36
|
-
proxy_method :process, required: %i[block]
|
37
|
-
proxy_method :rai_from_raw, required: %i[amount]
|
38
|
-
proxy_method :rai_to_raw, required: %i[amount]
|
39
|
-
proxy_method :receive_minimum
|
40
|
-
proxy_method :receive_minimum_set, required: %i[amount]
|
41
|
-
proxy_method :representatives
|
42
|
-
proxy_method :representatives_online
|
43
|
-
proxy_method :republish,
|
44
|
-
required: %i[hash],
|
45
|
-
optional: %i[count sources destinations]
|
46
|
-
proxy_method :search_pending, required: %i[wallet]
|
47
|
-
proxy_method :search_pending_all
|
48
|
-
proxy_method :stats, required: %i[type]
|
49
|
-
proxy_method :stop
|
50
|
-
proxy_method :successors, required: %i[block count]
|
51
|
-
proxy_method :unchecked, required: %i[count]
|
52
|
-
proxy_method :unchecked_clear
|
53
|
-
proxy_method :unchecked_get, required: %i[hash]
|
54
|
-
proxy_method :unchecked_keys, required: %i[key count]
|
55
|
-
proxy_method :version
|
56
|
-
proxy_method :wallet_create
|
57
|
-
proxy_method :work_cancel, required: %i[hash]
|
58
|
-
proxy_method :work_generate, required: %i[hash]
|
59
|
-
proxy_method :work_peer_add, required: %i[address port]
|
60
|
-
proxy_method :work_peers
|
61
|
-
proxy_method :work_peers_clear
|
62
|
-
proxy_method :work_validate, required: %i[work hash]
|
63
|
-
end
|