banano 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 142f940e2f3c62e5d2c5d1b4e41947f4bb3aa4d09afa6ef7499692538e43cc96
4
- data.tar.gz: 8738e7a8e8675e595901e55e2ff2d7acd3841c0695460ca5b66e1e382ec3eddd
3
+ metadata.gz: 13119a6d866dab62fc4f2d4a4c55868c8481e3071859a07de3c66a28667a3643
4
+ data.tar.gz: 5e2943b0615e0de9e8cb1ad638fe3bc8b225bd63dc0657922703d01282377887
5
5
  SHA512:
6
- metadata.gz: abbacfa91f2ebd5b1cad6e736bc43b63ba65e4c4a0d1b4828624ae1807135f73c2ac6ee40d431e25ebf13f8ade1b480c038f0f8b19854521417e1dc5a74b67d2
7
- data.tar.gz: b3e36db244547b823e407536c7951fc2d224502c2abf260eeb1cee0df2b76426831d2916c8c988609b3c7b3f2b621dca2fbe88191a4c87ccc7a2d89bea789d1c
6
+ metadata.gz: dc144a12257fcf86112bde83f9a7f93f605806bc79537242fa75cc5fcb0d21919b9bbea38d401d35493065af6ea5b04c4ec170c8d22cb5a655936fe49bc724f5
7
+ data.tar.gz: bf0682a364a13938561b9339b755d91b444374fd0b973cca8602a04564d79657b9dbe28abe8a683a3db9e8e2d073a284f987c12fbc8c742ca5a5ccb4809d94f5
@@ -1,3 +1,8 @@
1
+ ## v0.1.2
2
+
3
+ - README fixes - typos and wallet usage
4
+ - Banano::Block and Banano::WorkPeer abstractions added
5
+
1
6
  ## v0.1.1
2
7
 
3
8
  - Pending payments fixes - block\_id is mandatory
data/README.md CHANGED
@@ -36,7 +36,6 @@ gem install banano
36
36
 
37
37
  The code is divided on following the parts:
38
38
 
39
- - `Banano::Unit` - conversion between [RAW and Banano units](https://nanoo.tools/banano-units)
40
39
  - `Banano::Protocol` - including all other parts. Can be used also for some syntax sugar (to avoid sending node parameter to constructors)
41
40
  - `Banano::Client` - very thin wrapper around [Faraday HTTP Client](https://github.com/lostisland/faraday) for easy JSON-based communications
42
41
  - `Banano::Node` - Banano Node abstraction - mostly encapsulate JSON communications
@@ -44,6 +43,9 @@ The code is divided on following the parts:
44
43
  - `Banano::Account` - uniq 'ban_...' addresses used for currency tokens exchange
45
44
  - `Banano::WalletAccount` - link between `Account` and `Wallet` - check if account exists in the wallet etc.
46
45
  - `Banano::Key` - account key management
46
+ - `Banano::Block` - low level work with individual blocks
47
+ - `Banano::WorkPeer` - do work on peers
48
+ - `Banano::Unit` - conversion between [RAW and Banano units](https://nanoo.tools/banano-units)
47
49
 
48
50
  ### Banano::Protocol
49
51
 
@@ -52,7 +54,7 @@ If it is impossible to be done, you can use the [Public bananode RPC API](https:
52
54
 
53
55
  ```rb
54
56
  BETA_URL = 'https://api-beta.banano.cc'
55
- @anano = Banano::Protocol.new(uri: BETA_URL)
57
+ @banano = Banano::Protocol.new(uri: BETA_URL)
56
58
  # From here it is easy to create other object, without sending URI to them
57
59
  wallet = @banano.wallet('WALLET15263636...')
58
60
  account = @banano.account('ban_1...')
@@ -89,25 +91,26 @@ Wallets are like a bags of accounts. Accounts can be only local, created on the
89
91
 
90
92
  ```rb
91
93
  wallet = Banano::Wallet.create # create new wallet
92
- wallet.destroy # remove the wallet
93
- wallet.export # export wallet to JSON
94
+ wallet.restore(seed: 'XVVREGNN...') # restore some wallet and its accounts
94
95
  wallet.accounts # current wellet accounts
95
96
  wallet.contains?('ban_1...') # check if the account exists in the current wallet
97
+ wallet.export # export wallet to JSON
98
+ wallet.destroy # remove the wallet
96
99
  # Accounts with voting power
97
100
  wallet.default_representative
98
101
  wallet.change_default_representative('ban_1...')
102
+ # Security
99
103
  wallet.change_password('SomePassword') # protect your wallet
100
- walled.lock # no more payments
104
+ wallet.lock # no more payments
101
105
  wallet.locked?
102
- walled.unlock('SomePassword') # resume receiving payments
106
+ wallet.unlock('SomePassword') # resume receiving payments
107
+ # Payments
108
+ block_id = wallet.pay(from: 'ban_1...', to: 'ban_3...', amount: '1.23', raw: false, id: 'x123')
109
+ wallet.pending(limit: 10, detailed: true) # waiting payments (does not work well unless enable_control = true)
110
+ wallet.receive(into: 'ban_1', block: block_id) # receive the pending banano into some wallet account
103
111
  wallet.balance # check how many banano the whole wallet have, RAW units
104
112
  wallet.balance(raw: false) # wallet balance in Banano units
105
113
  wallet.balance(account_break_down: true) # banano per acount, RAW units
106
- # Payments
107
- wallet.pay(from: 'ban_1...', to: 'ban_3...', amount: '1.23', raw: false, id: 'x123')
108
- wallet.pending(limit: 10, detailed: true) # some payments waiting wallet unlock
109
- wallet.receive(into: 'ban_1') # receive the pending banano into some wallet account
110
- wallet.restore(seed: 'XVVREGNN...') # restore some wallet on the current node
111
114
  ```
112
115
 
113
116
  ### Banano::Account
@@ -122,7 +125,7 @@ account.last_modified_at
122
125
  account.public_key
123
126
  account.representative
124
127
  account.balance # in RAW units
125
- accunt.balance(raw: false) # in banano units
128
+ account.balance(raw: false) # in banano units
126
129
  # Payments
127
130
  account.pending(limit: 100, detailed: true) # detailed information about the pending payments
128
131
  account.history(limit: 10) # the latest payments - send and receive
@@ -136,13 +139,13 @@ Because accounts and wallets so closly connected, some linkage object is very he
136
139
  wallet = @banano.wallet('XBHHNN...')
137
140
  # create wallet <-> accounts connection
138
141
  wallet_acc = Banano::WalletAccount(node: @banano.node, wallet: wallet.id)
139
- wallet_acc.create # create account in the wallet
142
+ wallet_acc.create # create new account in the wallet
140
143
  wallet_acc.create(3) # create additional 3 accounts inside the same wallet
141
144
  # Working with specific account
142
145
  account = @banano.account('ban_1')
143
- wallet_other_acc = Banano::WalletAccount(node: pbanano.node, wallet: wallet.id, account: account.id)
144
- wallet_other_acc.pay(to: 'ban_1...', amount: 10, raw: false, id: 'x1234') # send some banano
145
- wallet_other_acc.receive # receive some banano
146
+ wallet_other_acc = Banano::WalletAccount(node: @banano.node, wallet: wallet.id, account: account.id)
147
+ block_id = wallet_other_acc.pay(to: 'ban_1...', amount: 10, raw: false, id: 'x1234') # send some banano
148
+ wallet_other_acc.receive(block_id) # receive some banano
146
149
 
147
150
  ```
148
151
 
@@ -161,7 +164,38 @@ key_builder.generate(seed: SEED, index: 0) # will always generate SAME pair o
161
164
  key_builder.generate(seed: SEED, index: 1)
162
165
  new_builder = @banano.key(saved_private_key) # generate keys from saved private key
163
166
  new_builder.expand # return private, public key and account address
164
- ```
167
+ ```
168
+
169
+ ### Banano::WorkPeer
170
+
171
+ Delegate block validating work to some network peers:
172
+
173
+ ```rb
174
+ work = Banano::WorkPeer(@banano.node)
175
+ work.add(address: '::ffff:1.2.3.4', port: '7071') # add peer to the work flow
176
+ work.list # list of working peers
177
+ work.clear # remove all peers
178
+ ```
179
+
180
+ ### Banano::Block
181
+
182
+ Blocks, also known as transactions are the building items of the banano network.
183
+ Every block have uniq ID, which can be used for processing the block
184
+
185
+ ```rb
186
+ block = Banano::Block(node: @banano.node, block: 'F1B7EDB1...')
187
+ block.account # account associated with the block
188
+ block.successors(limit: 10)
189
+ block.chain(limit: 10) # also 'block.ancestors' - blocks chain, leading to the current one
190
+ block.history # more detailed chain history
191
+ block.info # information about the block
192
+ block.confirm # block confirmation from the online representatives
193
+ work = block.generate_work(use_peers: true) # start some work
194
+ block.is_valid_work?(work) # check if the work done is valid
195
+ block.cancel_work # stop generating work for block
196
+ block.pending? # is the block in pending state. not work very well...
197
+ block.publish('send') # dependes what kind of block is this: 'send', 'receive' etc.
198
+ ```
165
199
 
166
200
  ### Banano::Unit
167
201
 
@@ -21,7 +21,18 @@ module Banano
21
21
  Banano::Account.new(node: @node, address: address)
22
22
  end
23
23
 
24
- # Returns a new instance of {Nanook::Key}.
24
+ # Returns a new instance of {Banano::Block}.
25
+ #
26
+ # ==== Example:
27
+ # block = Banano::Protocol.new.block("FBF8B0E...")
28
+ #
29
+ # @param block [String] the id/hash of the block you want to work with
30
+ # @return [Banano::Block]
31
+ def block(block)
32
+ Banano::Block.new(node: @node, block: block)
33
+ end
34
+
35
+ # Returns a new instance of {Banano::Key}.
25
36
  #
26
37
  # ==== Example:
27
38
  # key = Banano::Protocol.new.key("3068BB...")
@@ -0,0 +1,257 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Banano
4
+ # The <tt>Banano::Block</tt> class contains methods to discover
5
+ # publicly-available information about blocks on the nano network.
6
+ #
7
+ # A block is represented by a unique id like this:
8
+ #
9
+ # "FBF8B0E6623A31AB528EBD839EEAA91CAFD25C12294C46754E45FD017F7939EB"
10
+ #
11
+ class Block
12
+ def initialize(node:, block:)
13
+ @node = node
14
+ @block = block
15
+ block_required! # All methods expect a block
16
+ end
17
+
18
+ # Returns the {Banano::Account} of the block.
19
+ #
20
+ # ==== Example:
21
+ # block.account # => Banano::Account
22
+ #
23
+ # @return [Banano::Account] the account of the block
24
+ def account
25
+ address = rpc(action: :block_account, param_name: :hash)[:account]
26
+ Banano::Account.new(node: @node, address: address)
27
+ end
28
+
29
+ # Stop generating work for a block.
30
+ #
31
+ # ==== Example:
32
+ #
33
+ # block.cancel_work # => true
34
+ #
35
+ # @return [Boolean] signalling if the action was successful
36
+ def cancel_work
37
+ rpc(action: :work_cancel, param_name: :hash).empty?
38
+ end
39
+
40
+ # Returns a consecutive list of block hashes in the account chain
41
+ # starting at block back to count (direction from frontier back to
42
+ # open block, from newer blocks to older). Will list all blocks back
43
+ # to the open block of this chain when count is set to "-1".
44
+ # The requested block hash is included in the answer.
45
+ #
46
+ # See also #successors.
47
+ #
48
+ # ==== Example:
49
+ #
50
+ # block.chain(limit: 2)
51
+ #
52
+ # @param limit [Integer] maximum number of block hashes to return (default is 1000)
53
+ # @param offset [Integer] return the account chain block hashes offset by
54
+ # the specified number of blocks (default is 0)
55
+ def chain(limit: 1000, offset: 0)
56
+ params = {count: limit, offset: offset}
57
+ rpc(action: :chain, param_name: :block, params: params)[:blocks]
58
+ end
59
+ alias ancestors chain
60
+
61
+ # Request confirmation for a block from online representative nodes.
62
+ # Will return immediately with a boolean to indicate if the request for
63
+ # confirmation was successful. Note that this boolean does not indicate
64
+ # the confirmation status of the block.
65
+ #
66
+ # ==== Example:
67
+ # block.confirm # => true
68
+ #
69
+ # @return [Boolean] if the confirmation request was sent successful
70
+ def confirm
71
+ rpc(action: :block_confirm, param_name: :hash)[:started] == '1'
72
+ end
73
+
74
+ # This call is for internal diagnostics/debug purposes only. Do not
75
+ # rely on this interface being stable and do not use in a production system.
76
+ #
77
+ # Check if the block appears in the list of recently confirmed blocks by
78
+ # online representatives.
79
+ #
80
+ # This method can work in conjunction with {Banano::Block#confirm},
81
+ # whereby you can send any block (old or new) out to online representatives to
82
+ # confirm. The confirmation process can take up to a couple of minutes.
83
+ #
84
+ # The method returning +false+ can indicate that the block is still in the process of being
85
+ # confirmed and that you should call the method again soon, or that it
86
+ # was confirmed earlier than the list available in {Banano::Node#confirmation_history},
87
+ # or that it was not confirmed.
88
+ #
89
+ # ==== Example:
90
+ # block.confirmed_recently? # => true
91
+ #
92
+ # @return [Boolean] +true+ if the block has been recently confirmed by
93
+ # online representatives.
94
+ def confirmed_recently?
95
+ @node.rpc(action: :confirmation_history)[:confirmations].map do |h|
96
+ h[:hash]
97
+ end.include?(@block)
98
+ end
99
+ alias recently_confirmed? confirmed_recently?
100
+
101
+ # Generate work for a block.
102
+ #
103
+ # ==== Example:
104
+ # block.generate_work # => "2bf29ef00786a6bc"
105
+ #
106
+ # @param use_peers [Boolean] if set to +true+, then the node will query
107
+ # its work peers (if it has any, see {Banano::WorkPeer#list}).
108
+ # When +false+, the node will only generate work locally (default is +false+)
109
+ # @return [String] the work id of the work completed.
110
+ def generate_work(use_peers: false)
111
+ rpc(action: :work_generate, param_name: :hash, params: {use_peers: use_peers})[:work]
112
+ end
113
+
114
+ # Returns Array of Hashes containing information about a chain of
115
+ # send/receive blocks, starting from this block.
116
+ #
117
+ # ==== Example:
118
+ #
119
+ # block.history(limit: 1)
120
+ #
121
+ # @param limit [Integer] maximum number of send/receive block hashes
122
+ # to return in the chain (default is 1000)
123
+ def history(limit: 1000)
124
+ response = rpc(action: :history, param_name: :hash, params: {count: limit})
125
+ response[:history].collect {|entry| Banano::Util.symbolize_keys(entry) }
126
+ end
127
+
128
+ # Returns the block hash id.
129
+ #
130
+ # ==== Example:
131
+ #
132
+ # block.id #=> "FBF8B0E..."
133
+ #
134
+ # @return [String] the block hash id
135
+ def id
136
+ @block
137
+ end
138
+
139
+ # Returns a Hash of information about the block.
140
+ #
141
+ # ==== Examples:
142
+ #
143
+ # block.info
144
+ # block.info(allow_unchecked: true)
145
+ #
146
+ # @param allow_unchecked [Boolean] (default is +false+). If +true+,
147
+ # information can be returned about blocks that are unchecked (unverified).
148
+ def info(allow_unchecked: false)
149
+ if allow_unchecked
150
+ response = rpc(action: :unchecked_get, param_name: :hash)
151
+ return _parse_info_response(response) unless response.key?(:error)
152
+ # If unchecked not found, continue to checked block
153
+ end
154
+
155
+ response = rpc(action: :block, param_name: :hash)
156
+ _parse_info_response(response)
157
+ end
158
+
159
+ # ==== Example:
160
+ #
161
+ # block.is_valid_work?("2bf29ef00786a6bc") # => true
162
+ #
163
+ # @param work [String] the work id to check is valid
164
+ # @return [Boolean] signalling if work is valid for the block
165
+ def is_valid_work?(work)
166
+ response = rpc(action: :work_validate, param_name: :hash, params: {work: work})
167
+ !response.empty? && response[:valid] == '1'
168
+ end
169
+
170
+ # Republish blocks starting at this block up the account chain
171
+ # back to the nano network.
172
+ #
173
+ # @return [Array<String>] block hashes that were republished
174
+ #
175
+ # ==== Example:
176
+ #
177
+ # block.republish
178
+ #
179
+ def republish(destinations: nil, sources: nil)
180
+ if !destinations.nil? && !sources.nil?
181
+ raise ArgumentError, "Either destinations or sources but not both"
182
+ end
183
+
184
+ # Add in optional arguments
185
+ params = {}
186
+ params[:destinations] = destinations unless destinations.nil?
187
+ params[:sources] = sources unless sources.nil?
188
+ params[:count] = 1 unless params.empty?
189
+
190
+ rpc(action: :republish, param_name: :hash, params: params)[:blocks]
191
+ end
192
+
193
+ # ==== Example:
194
+ #
195
+ # block.pending? #=> false
196
+ #
197
+ # @return [Boolean] signalling if the block is a pending block.
198
+ def pending?
199
+ response = rpc(action: :pending_exists, param_name: :hash)
200
+ !response.empty? && response[:exists] == '1'
201
+ end
202
+
203
+ # Publish the block to the banano network.
204
+ #
205
+ # Note, if block has previously been published, use #republish instead.
206
+ #
207
+ # ==== Examples:
208
+ #
209
+ # block.publish # => "FBF8B0E..."
210
+ #
211
+ # @param [String] subtype: 'send', 'receive', 'open', 'epoch' etc.
212
+ # @return [String] the block hash, or false.
213
+ def publish(subtype = '')
214
+ json_rpc(action: :process, params: {subtype: subtype})
215
+ end
216
+ alias process publish
217
+
218
+ # Returns an Array of block hashes in the account chain ending at
219
+ # this block.
220
+ #
221
+ # See also #chain.
222
+ #
223
+ # ==== Example:
224
+ #
225
+ # block.successors
226
+ #
227
+ # @param limit [Integer] maximum number of send/receive block hashes
228
+ # to return in the chain (default is 1000)
229
+ # @param offset [Integer] return the account chain block hashes offset
230
+ # by the specified number of blocks (default is 0)
231
+ # @return [Array<String>] block hashes in the account chain ending at this block
232
+ def successors(limit: 1000, offset: 0)
233
+ params = {count: limit, offset: offset}
234
+ rpc(action: :successors, param_name: :block, params: params)[:blocks]
235
+ end
236
+
237
+ private
238
+
239
+ # Some RPC calls expect the param that represents the block to be named
240
+ # "hash", and others "block".
241
+ # The param_name argument allows us to specify which it should be for this call.
242
+ def rpc(action:, param_name:, params: {})
243
+ p = @block.nil? ? {} : {param_name.to_sym => @block}
244
+ @node.rpc(action: action, params: p.merge(params))
245
+ end
246
+
247
+ # Special RPC - publish require {block: block.info} parameter
248
+ def json_rpc(action:, params: {})
249
+ p = {block: JSON.dump(info), json_block: true}
250
+ @node.rpc(action: action, params: p.merge(params))
251
+ end
252
+
253
+ def block_required!
254
+ raise ArgumentError, "Block must be present" if @block.nil?
255
+ end
256
+ end
257
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Banano
4
- VERSION = '0.1.1'
4
+ VERSION = '0.1.2'
5
5
  end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Banano
4
+ class WorkPeer
5
+ def initialize(node)
6
+ @node = node
7
+ end
8
+
9
+ def add(address:, port:)
10
+ rpc(action: :work_peer_add, params: {address: address, port: port}).key?(:success)
11
+ end
12
+
13
+ def clear
14
+ rpc(action: :work_peers_clear).key?(:success)
15
+ end
16
+
17
+ def list
18
+ rpc(action: :work_peers)[:work_peers]
19
+ end
20
+
21
+ private
22
+
23
+ def rpc(action:, params: {})
24
+ @node.rpc(action: action, params: params)
25
+ end
26
+ end
27
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: banano
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stoyan Zhekov
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-06-24 00:00:00.000000000 Z
11
+ date: 2020-06-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -123,6 +123,7 @@ files:
123
123
  - bin/setup
124
124
  - lib/banano.rb
125
125
  - lib/banano/account.rb
126
+ - lib/banano/block.rb
126
127
  - lib/banano/client.rb
127
128
  - lib/banano/error.rb
128
129
  - lib/banano/key.rb
@@ -132,13 +133,14 @@ files:
132
133
  - lib/banano/version.rb
133
134
  - lib/banano/wallet.rb
134
135
  - lib/banano/wallet_account.rb
135
- homepage: http://github.com/zh/rbanano
136
+ - lib/banano/work_peer.rb
137
+ homepage: https://github.com/zh/rbanano
136
138
  licenses:
137
139
  - MIT
138
140
  metadata:
139
- homepage_uri: http://github.com/zh/rbanano
140
- source_code_uri: http://github.com/zh/rbanano
141
- changelog_uri: http://github.com/zh/rbanano/CHANGELOG.md
141
+ homepage_uri: https://github.com/zh/rbanano
142
+ source_code_uri: https://github.com/zh/rbanano
143
+ changelog_uri: https://github.com/zh/rbanano/blob/master/CHANGELOG.md
142
144
  post_install_message:
143
145
  rdoc_options: []
144
146
  require_paths: