banano 0.1.1 → 0.1.2

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 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: