crea-ruby 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +55 -0
  3. data/CONTRIBUTING.md +79 -0
  4. data/Gemfile +3 -0
  5. data/LICENSE +22 -0
  6. data/README.md +234 -0
  7. data/Rakefile +332 -0
  8. data/crea-ruby.gemspec +39 -0
  9. data/gource.sh +6 -0
  10. data/lib/crea.rb +85 -0
  11. data/lib/crea/api.rb +208 -0
  12. data/lib/crea/base_error.rb +218 -0
  13. data/lib/crea/block_api.rb +78 -0
  14. data/lib/crea/broadcast.rb +1334 -0
  15. data/lib/crea/chain_config.rb +36 -0
  16. data/lib/crea/formatter.rb +14 -0
  17. data/lib/crea/jsonrpc.rb +108 -0
  18. data/lib/crea/marshal.rb +231 -0
  19. data/lib/crea/mixins/jsonable.rb +37 -0
  20. data/lib/crea/mixins/retriable.rb +58 -0
  21. data/lib/crea/mixins/serializable.rb +45 -0
  22. data/lib/crea/operation.rb +141 -0
  23. data/lib/crea/operation/account_create.rb +10 -0
  24. data/lib/crea/operation/account_create_with_delegation.rb +12 -0
  25. data/lib/crea/operation/account_update.rb +8 -0
  26. data/lib/crea/operation/account_witness_proxy.rb +4 -0
  27. data/lib/crea/operation/account_witness_vote.rb +5 -0
  28. data/lib/crea/operation/cancel_transfer_from_savings.rb +4 -0
  29. data/lib/crea/operation/challenge_authority.rb +5 -0
  30. data/lib/crea/operation/change_recovery_account.rb +5 -0
  31. data/lib/crea/operation/claim_account.rb +5 -0
  32. data/lib/crea/operation/claim_reward_balance.rb +6 -0
  33. data/lib/crea/operation/comment.rb +9 -0
  34. data/lib/crea/operation/comment_options.rb +10 -0
  35. data/lib/crea/operation/convert.rb +5 -0
  36. data/lib/crea/operation/create_claimed_account.rb +10 -0
  37. data/lib/crea/operation/custom.rb +5 -0
  38. data/lib/crea/operation/custom_binary.rb +8 -0
  39. data/lib/crea/operation/custom_json.rb +6 -0
  40. data/lib/crea/operation/decline_voting_rights.rb +4 -0
  41. data/lib/crea/operation/delegate_vesting_shares.rb +5 -0
  42. data/lib/crea/operation/delete_comment.rb +4 -0
  43. data/lib/crea/operation/escrow_approve.rb +8 -0
  44. data/lib/crea/operation/escrow_dispute.rb +7 -0
  45. data/lib/crea/operation/escrow_release.rb +10 -0
  46. data/lib/crea/operation/escrow_transfer.rb +12 -0
  47. data/lib/crea/operation/feed_publish.rb +4 -0
  48. data/lib/crea/operation/limit_order_cancel.rb +4 -0
  49. data/lib/crea/operation/limit_order_create.rb +8 -0
  50. data/lib/crea/operation/limit_order_create2.rb +8 -0
  51. data/lib/crea/operation/prove_authority.rb +4 -0
  52. data/lib/crea/operation/recover_account.rb +6 -0
  53. data/lib/crea/operation/report_over_production.rb +5 -0
  54. data/lib/crea/operation/request_account_recovery.rb +6 -0
  55. data/lib/crea/operation/reset_account.rb +5 -0
  56. data/lib/crea/operation/set_reset_account.rb +5 -0
  57. data/lib/crea/operation/set_withdraw_vesting_route.rb +6 -0
  58. data/lib/crea/operation/transfer.rb +6 -0
  59. data/lib/crea/operation/transfer_from_savings.rb +7 -0
  60. data/lib/crea/operation/transfer_to_savings.rb +6 -0
  61. data/lib/crea/operation/transfer_to_vesting.rb +5 -0
  62. data/lib/crea/operation/vote.rb +6 -0
  63. data/lib/crea/operation/withdraw_vesting.rb +4 -0
  64. data/lib/crea/operation/witness_set_properties.rb +5 -0
  65. data/lib/crea/operation/witness_update.rb +7 -0
  66. data/lib/crea/rpc/base_client.rb +179 -0
  67. data/lib/crea/rpc/http_client.rb +143 -0
  68. data/lib/crea/rpc/thread_safe_http_client.rb +35 -0
  69. data/lib/crea/stream.rb +385 -0
  70. data/lib/crea/transaction.rb +96 -0
  71. data/lib/crea/transaction_builder.rb +393 -0
  72. data/lib/crea/type/amount.rb +107 -0
  73. data/lib/crea/type/base_type.rb +10 -0
  74. data/lib/crea/utils.rb +17 -0
  75. data/lib/crea/version.rb +4 -0
  76. metadata +478 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 269c2c6639fdfa2ead291e869f37497be0e9cfbd3133903fd47e36be74c71226
4
+ data.tar.gz: ef814ed1b89df19337d65e43df16be2308c356e355b0a7d5ce914211443cb37e
5
+ SHA512:
6
+ metadata.gz: cb396bae71994a57dfa877ceebe594e7e1f868c653fd19e4114935ae9862df03bc23972bb05715c45c964b0665ef7e64504331d6bb8eea3c472a84e80b7b3386
7
+ data.tar.gz: 1d5008adca748ef979603983cc16272825486a541ac26fc728ac5dc34a8302bf3684d71f747fd39c21fd608efb1d4620e35257aa8f1d1d8060ecdaa5d76a7358
data/.gitignore ADDED
@@ -0,0 +1,55 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /spec/examples.txt
9
+ /test/tmp/
10
+ /test/fixtures/vcr_cassettes/*.yml
11
+ /test/version_tmp/
12
+ /tmp/
13
+
14
+ # Used by dotenv library to load environment variables.
15
+ # .env
16
+
17
+ ## Specific to RubyMotion:
18
+ .dat*
19
+ .repl_history
20
+ build/
21
+ *.bridgesupport
22
+ build-iPhoneOS/
23
+ build-iPhoneSimulator/
24
+
25
+ ## Specific to RubyMotion (use of CocoaPods):
26
+ #
27
+ # We recommend against adding the Pods directory to your .gitignore. However
28
+ # you should judge for yourself, the pros and cons are mentioned at:
29
+ # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
30
+ #
31
+ # vendor/Pods/
32
+
33
+ ## Documentation cache and generated files:
34
+ /.yardoc/
35
+ /_yardoc/
36
+ /doc/
37
+ /rdoc/
38
+
39
+ ## Environment normalization:
40
+ /.bundle/
41
+ /vendor/bundle
42
+ /lib/bundler/man/
43
+
44
+ # for a library or gem, you might want to ignore these files since the code is
45
+ # intended to run in multiple environments; otherwise, check them in:
46
+ # Gemfile.lock
47
+ # .ruby-version
48
+ # .ruby-gemset
49
+
50
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
51
+ .rvmrc
52
+
53
+ # gource output
54
+ output.mp4
55
+ .idea
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,79 @@
1
+
2
+ # Contributing
3
+
4
+ Everyone is welcome to contribute code to Creativechain FDN projects. We have a Code of Conduct;
5
+ we ask that you please follow it in all your interactions with our team and your fellow
6
+ contributors.
7
+
8
+ Please note that this contributing guide only applies to our development presence.
9
+
10
+ ## How to contribute
11
+
12
+ 1. File an issue describing the problem you would like to
13
+ solve or the feature you would like to add. It saves unnecessary work on your part,
14
+ in case there's a nontechnical reason we can't accept a particular change.
15
+ Please note that we can and will _automatically close all pull requests that do not refer to
16
+ an issue_.
17
+ 2. Learn the conventions of the project you are submitting code to, even implicit ones,
18
+ and follow them. In case you have a question about a project's conventions, please
19
+ ask on the issue you filed. This includes writing tests, formatting code, and documentation.
20
+ 3. File a pull request against your Github issue and fill out the pull request template.
21
+ Remember, you are agreeing to license your code and any intellectual property associated
22
+ with your code under the same terms as the repository you are contributing to.
23
+ 4. If one of our teammates asks you to make changes, please make them. Our rule is that all
24
+ requests for changes in code review are resolved in favor of the reviewer. Our teammates
25
+ follow this rule too!
26
+
27
+ ## Code of Conduct
28
+
29
+ Again, please note that this Code of Conduct _only applies to our development presence_.
30
+
31
+ ### Our Pledge
32
+
33
+ We welcome your membership in our project and community under the rules that we have set below.
34
+
35
+ In the interest of fostering an open and welcoming environment, we as
36
+ contributors and maintainers will work to make your participation in
37
+ our project and community as fulfilling as possible.
38
+
39
+ ### Our Rules
40
+
41
+ All members of our project and community must:
42
+
43
+ 1. Show empathy toward other project and community members
44
+ 2. Use welcoming and inclusive language
45
+ 3. Respect differing viewpoints and experiences
46
+ 4. Gracefully accept constructive criticism
47
+
48
+ All members of our project and community must not:
49
+
50
+ 1. Harm our project and community, or advocate harm to our project and community
51
+ 2. Insult or make derogatory comments about others
52
+ 3. Interact with others after they have withdrawn permission to do so
53
+
54
+ ### Our Responsibilities
55
+
56
+ We will use any and all lawful means at our disposal to enforce our rules. This includes
57
+ but is not limited to:
58
+
59
+ 1. Rejecting contributions
60
+ 2. Removing comments, commits, code, wiki edits, and issues
61
+ 3. Banning abusers
62
+
63
+ We will clarify standards of acceptable behavior and we will take appropriate
64
+ and fair corrective action in response to any instances of unacceptable behavior.
65
+
66
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
67
+ reported by contacting us at github.abuse@creary.net. All
68
+ complaints will be reviewed and investigated and will result in a response that
69
+ is deemed necessary and appropriate to the circumstances. We
70
+ maintain strict confidentiality with regard to the reporter of an incident.
71
+ Further details of specific enforcement policies may be posted separately.
72
+
73
+ ### Attribution
74
+
75
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
76
+ available at [http://contributor-covenant.org/version/1/4][version]
77
+
78
+ [homepage]: http://contributor-covenant.org
79
+ [version]: http://contributor-covenant.org/version/1/4/gg
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2018 Creativechain FDN
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
data/README.md ADDED
@@ -0,0 +1,234 @@
1
+ [![Gem Version](https://badge.fury.io/rb/crea-ruby.svg)](https://badge.fury.io/rb/crea-ruby)
2
+ [![Inline docs](http://inch-ci.org/github/creativechain/crea-ruby.svg?branch=master&style=shields)](http://inch-ci.org/github/creary/crea-ruby)
3
+
4
+ # `crea-ruby`
5
+
6
+ Crea-ruby the Ruby API for Crea blockchain.
7
+
8
+ Full documentation: http://www.rubydoc.info/gems/crea-ruby
9
+
10
+ **Note:** *This library depends on AppBase methods that are a work in progress.*
11
+
12
+ ## Getting Started
13
+
14
+ The crea-ruby gem is compatible with Ruby 2.2.5 or later.
15
+
16
+ ### Install the gem for your project
17
+
18
+ *(Assuming that [Ruby is installed](https://www.ruby-lang.org/en/downloads/) on your computer, as well as [RubyGems](http://rubygems.org/pages/download))*
19
+
20
+ To install the gem on your computer, run in shell:
21
+
22
+ ```bash
23
+ gem install crea-ruby
24
+ ```
25
+
26
+ ... then add in your code:
27
+
28
+ ```ruby
29
+ require 'crea'
30
+ ```
31
+
32
+ To add the gem as a dependency to your project with [Bundler](http://bundler.io/), you can add this line in your Gemfile:
33
+
34
+ ```ruby
35
+ gem 'crea-ruby', require: 'crea'
36
+ ```
37
+
38
+ ## Examples
39
+
40
+ ### Broadcast Vote
41
+
42
+ ```ruby
43
+ params = {
44
+ voter: voter,
45
+ author: author,
46
+ permlink: permlink,
47
+ weight: weight
48
+ }
49
+
50
+ Crea::Broadcast.vote(wif: wif, params: params) do |result|
51
+ puts result
52
+ end
53
+ ```
54
+
55
+ *See: [Broadcast](https://www.rubydoc.info/gems/crea-ruby/Crea/Broadcast)*
56
+
57
+ ### Streaming
58
+
59
+ The value passed to the block is an object, with the keys: `:type` and `:value`.
60
+
61
+ ```ruby
62
+ stream = Crea::Stream.new
63
+
64
+ stream.operations do |op|
65
+ puts "#{op.type}: #{op.value}"
66
+ end
67
+ ```
68
+
69
+ To start a stream from a specific block number, pass it as an argument:
70
+
71
+ ```ruby
72
+ stream = Crea::Stream.new
73
+
74
+ stream.operations(at_block_num: 9001) do |op|
75
+ puts "#{op.type}: #{op.value}"
76
+ end
77
+ ```
78
+
79
+ You can also grab the related transaction id and block number for each operation:
80
+
81
+ ```ruby
82
+ stream = Crea::Stream.new
83
+
84
+ stream.operations do |op, trx_id, block_num|
85
+ puts "#{block_num} :: #{trx_id}"
86
+ puts "#{op.type}: #{op.value}"
87
+ end
88
+ ```
89
+
90
+ To stream only certain operations:
91
+
92
+ ```ruby
93
+ stream = Crea::Stream.new
94
+
95
+ stream.operations(types: :vote_operation) do |op|
96
+ puts "#{op.type}: #{op.value}"
97
+ end
98
+ ```
99
+
100
+ Or pass an array of certain operations:
101
+
102
+ ```ruby
103
+ stream = Crea::Stream.new
104
+
105
+ stream.operations(types: [:comment_operation, :vote_operation]) do |op|
106
+ puts "#{op.type}: #{op.value}"
107
+ end
108
+ ```
109
+
110
+ Or (optionally) just pass the operation(s) you want as the only arguments. This is semantic sugar for when you want specific types and take all of the defaults.
111
+
112
+ ```ruby
113
+ stream = Crea::Stream.new
114
+
115
+ stream.operations(:vote_operation) do |op|
116
+ puts "#{op.type}: #{op.value}"
117
+ end
118
+ ```
119
+
120
+ To also include virtual operations:
121
+
122
+ ```ruby
123
+ stream = Crea::Stream.new
124
+
125
+ stream.operations(include_virtual: true) do |op|
126
+ puts "#{op.type}: #{op.value}"
127
+ end
128
+ ```
129
+
130
+ ### Multisig
131
+
132
+ You can use multisignature to broadcast an operation.
133
+
134
+ ```ruby
135
+ params = {
136
+ voter: voter,
137
+ author: author,
138
+ permlink: permlink,
139
+ weight: weight
140
+ }
141
+
142
+ Crea::Broadcast.vote(wif: [wif1, wif2], params: params) do |result|
143
+ puts result
144
+ end
145
+ ```
146
+
147
+ In addition to signing with multiple `wif` private keys, it is possible to also export a partially signed transaction to have signing completed by someone else.
148
+
149
+ ```ruby
150
+ builder = Crea::TransactionBuilder.new(wif: wif1)
151
+
152
+ builder.put(vote: {
153
+ voter: voter,
154
+ author: author,
155
+ permlink: permlink,
156
+ weight: weight
157
+ })
158
+
159
+ trx = builder.sign.to_json
160
+
161
+ File.open('trx.json', 'w') do |f|
162
+ f.write(trx)
163
+ end
164
+ ```
165
+
166
+ Then send the contents of `trx.json` to the other signing party so they can privately sign and broadcast the transaction.
167
+
168
+ ```ruby
169
+ trx = open('trx.json').read
170
+ builder = Crea::TransactionBuilder.new(wif: wif2, trx: trx)
171
+ api = Crea::CondenserApi.new
172
+ trx = builder.transaction
173
+ api.broadcast_transaction_synchronous(trx)
174
+ ```
175
+
176
+ ### Get Accounts
177
+
178
+ ```ruby
179
+ api = Crea::DatabaseApi.new
180
+
181
+ api.find_accounts(accounts: ['creary', 'alice']) do |result|
182
+ puts result.accounts
183
+ end
184
+ ```
185
+
186
+ *See: [Api](https://www.rubydoc.info/gems/crea-ruby/Crea/Api)*
187
+
188
+ ### Reputation Formatter
189
+
190
+ ```ruby
191
+ rep = Crea::Formatter.reputation(account.reputation)
192
+ puts rep
193
+ ```
194
+
195
+ ### Tests
196
+
197
+ * Clone the client repository into a directory of your choice:
198
+ * `git clone https://github.com/creary/crea-ruby.git`
199
+ * Navigate into the new folder
200
+ * `cd crea-ruby`
201
+ * All tests can be invoked as follows:
202
+ * `bundle exec rake test`
203
+ * To run `static` tests:
204
+ * `bundle exec rake test:static`
205
+ * To run `broadcast` tests (broadcast is simulated, only `verify` is actually used):
206
+ * `bundle exec rake test:broadcast`
207
+ * To run `threads` tests (which quickly verifies thread safety):
208
+ * `bundle exec rake test:threads`
209
+ * To run `testnet` tests (which does actual broadcasts)
210
+ * `TEST_NODE=https://testnet.crearydev.com bundle exec rake test:testnet`
211
+
212
+ You can also run other tests that are not part of the above `test` execution:
213
+
214
+ * To run `block_range`, which streams blocks (using `json-rpc-batch`)
215
+ * `bundle exec rake stream:block_range`
216
+
217
+
218
+ If you want to point to any node for tests, instead of letting the test suite pick the default, set the environment variable to `TEST_NODE`, e.g.:
219
+
220
+ ```bash
221
+ $ TEST_NODE=https://api.crearydev.com bundle exec rake test
222
+ ```
223
+
224
+ ## Contributions
225
+
226
+ Patches are welcome! Contributors are listed in the `crea-ruby.gemspec` file. Please run the tests (`rake test`) before opening a pull request and make sure that you are passing all of them. If you would like to contribute, but don't know what to work on, check the issues list.
227
+
228
+ ## Issues
229
+
230
+ When you find issues, please report them!
231
+
232
+ ## License
233
+
234
+ MIT
data/Rakefile ADDED
@@ -0,0 +1,332 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+ require 'yard'
4
+ require 'crea'
5
+
6
+ Rake::TestTask.new(test: ['clean:vcr', 'test:threads']) do |t|
7
+ t.libs << 'test'
8
+ t.libs << 'lib'
9
+ t.test_files = FileList['test/**/*_test.rb']
10
+ t.ruby_opts << if ENV['HELL_ENABLED']
11
+ '-W2'
12
+ else
13
+ '-W1'
14
+ end
15
+ end
16
+
17
+ namespace :test do
18
+ Rake::TestTask.new(static: 'clean:vcr') do |t|
19
+ t.description = <<-EOD
20
+ Run static tests, which are those that have static request/responses.
21
+ These are tests that are typically read-only and do not require heavy
22
+ matches on the json-rpc request body. Often, the only difference between
23
+ one execution and another is the json-rpc-id.
24
+ EOD
25
+ t.libs << 'test'
26
+ t.libs << 'lib'
27
+ t.test_files = [
28
+ 'test/crea/account_by_key_api_test.rb',
29
+ 'test/crea/account_history_api_test.rb',
30
+ 'test/crea/block_api_test.rb',
31
+ 'test/crea/database_api_test.rb',
32
+ 'test/crea/follow_api_test.rb',
33
+ 'test/crea/jsonrpc_test.rb',
34
+ 'test/crea/market_history_api_test.rb',
35
+ 'test/crea/tags_api_test.rb',
36
+ 'test/crea/witness_api_test.rb'
37
+ ]
38
+ t.ruby_opts << if ENV['HELL_ENABLED']
39
+ '-W2'
40
+ else
41
+ '-W1'
42
+ end
43
+ end
44
+
45
+ Rake::TestTask.new(broadcast: 'clean:vcr') do |t|
46
+ t.description = <<-EOD
47
+ Run broadcast tests, which are those that only use network_broadcast_api
48
+ and/or database_api.verify_authority (pretend: true).
49
+ EOD
50
+ t.libs << 'test'
51
+ t.libs << 'lib'
52
+ t.test_files = [
53
+ 'test/crea/broadcast_test.rb',
54
+ 'test/crea/transaction_builder_test.rb'
55
+ ]
56
+ t.ruby_opts << if ENV['HELL_ENABLED']
57
+ '-W2'
58
+ else
59
+ '-W1'
60
+ end
61
+ end
62
+
63
+ Rake::TestTask.new(testnet: 'clean:vcr') do |t|
64
+ t.description = <<-EOD
65
+ Run testnet tests, which are those that use network_broadcast_api to do
66
+ actual broadcast operations, on a specified (or default) testnet.
67
+ EOD
68
+ t.libs << 'test'
69
+ t.libs << 'lib'
70
+ t.test_files = [
71
+ 'test/crea/testnet_test.rb'
72
+ ]
73
+ t.ruby_opts << if ENV['HELL_ENABLED']
74
+ '-W2'
75
+ else
76
+ '-W1'
77
+ end
78
+ end
79
+
80
+ desc 'Tests the API using multiple threads.'
81
+ task :threads do
82
+ next if !!ENV['TEST']
83
+
84
+ threads = []
85
+ api = Crea::Api.new(url: ENV['TEST_NODE'])
86
+ database_api = Crea::DatabaseApi.new(url: ENV['TEST_NODE'])
87
+ witnesses = {}
88
+ keys = %i(created url total_missed props running_version
89
+ hardfork_version_vote hardfork_time_vote)
90
+
91
+ if defined? Thread.report_on_exception
92
+ Thread.report_on_exception = true
93
+ end
94
+
95
+ database_api.get_active_witnesses do |result|
96
+ print "Found #{result.witnesses.size} witnesses ..."
97
+
98
+ result.witnesses.each do |witness_name|
99
+ threads << Thread.new do
100
+ api.get_witness_by_account(witness_name) do |witness|
101
+ witnesses[witness.owner] = witness.map do |k, v|
102
+ [k, v] if keys.include? k.to_sym
103
+ end.compact.to_h
104
+
105
+ cbd_exchange_rate = witness[:cbd_exchange_rate]
106
+ base = cbd_exchange_rate[:base].to_f
107
+
108
+ if (quote = cbd_exchange_rate[:quote].to_f) > 0
109
+ rate = (base / quote).round(3)
110
+ witnesses[witness.owner][:cbd_exchange_rate] = rate
111
+ else
112
+ witnesses[witness.owner][:cbd_exchange_rate] = nil
113
+ end
114
+
115
+ last_cbd_exchange_update = witness[:last_cbd_exchange_update]
116
+ last_cbd_exchange_update = Time.parse(last_cbd_exchange_update + 'Z')
117
+ last_cbd_exchange_elapsed = '%.2f hours ago' % ((Time.now.utc - last_cbd_exchange_update) / 60)
118
+ witnesses[witness.owner][:last_cbd_exchange_elapsed] = last_cbd_exchange_elapsed
119
+ end
120
+ end
121
+ end
122
+ end
123
+
124
+ threads.each do |thread|
125
+ print '.'
126
+ thread.join
127
+ end
128
+
129
+ puts ' done!'
130
+
131
+ if threads.size != witnesses.size
132
+ puts "Bug: expected #{threads.size} witnesses, only found #{witnesses.size}."
133
+ else
134
+ puts JSON.pretty_generate witnesses rescue puts witnesses
135
+ end
136
+ end
137
+ end
138
+
139
+ namespace :stream do
140
+ desc 'Test the ability to stream a block range.'
141
+ task :block_range, [:mode, :at_block_num] do |t, args|
142
+ mode = (args[:mode] || 'irreversible').to_sym
143
+ first_block_num = args[:at_block_num].to_i if !!args[:at_block_num]
144
+ stream = Crea::Stream.new(url: ENV['TEST_NODE'], mode: mode)
145
+ api = Crea::Api.new(url: ENV['TEST_NODE'])
146
+ last_block_num = nil
147
+ last_timestamp = nil
148
+ range_complete = false
149
+
150
+ api.get_dynamic_global_properties do |properties|
151
+ current_block_num = if mode == :head
152
+ properties.head_block_number
153
+ else
154
+ properties.last_irreversible_block_num
155
+ end
156
+
157
+ # First pass replays latest a random number of blocks to test chunking.
158
+ first_block_num ||= current_block_num - (rand * 200).to_i
159
+
160
+ range = first_block_num..current_block_num
161
+ puts "Initial block range: #{range.size}"
162
+
163
+ stream.blocks(at_block_num: range.first) do |block, block_num|
164
+ current_timestamp = Time.parse(block.timestamp + 'Z')
165
+
166
+ if !range_complete && block_num > range.last
167
+ puts 'Done with initial range.'
168
+ range_complete = true
169
+ end
170
+
171
+ if !!last_timestamp && block_num != last_block_num + 1
172
+ puts "Bug: Last block number was #{last_block_num} then jumped to: #{block_num}"
173
+ exit
174
+ end
175
+
176
+ if !!last_timestamp && current_timestamp < last_timestamp
177
+ puts "Bug: Went back in time. Last timestamp was #{last_timestamp}, then jumped back to #{current_timestamp}"
178
+ exit
179
+ end
180
+
181
+ puts "\t#{block_num} Timestamp: #{current_timestamp}, witness: #{block.witness}"
182
+ last_block_num = block_num
183
+ last_timestamp = current_timestamp
184
+ end
185
+ end
186
+ end
187
+
188
+ desc 'Test the ability to stream a block range of transactions.'
189
+ task :trx_range, [:mode, :at_block_num] do |t, args|
190
+ mode = (args[:mode] || 'irreversible').to_sym
191
+ first_block_num = args[:at_block_num].to_i if !!args[:at_block_num]
192
+ stream = Crea::Stream.new(url: ENV['TEST_NODE'], mode: mode)
193
+ api = Crea::Api.new(url: ENV['TEST_NODE'])
194
+
195
+ api.get_dynamic_global_properties do |properties|
196
+ current_block_num = if mode == :head
197
+ properties.head_block_number
198
+ else
199
+ properties.last_irreversible_block_num
200
+ end
201
+
202
+ # First pass replays latest a random number of blocks to test chunking.
203
+ first_block_num ||= current_block_num - (rand * 200).to_i
204
+
205
+ stream.transactions(at_block_num: first_block_num) do |trx, trx_id, block_num|
206
+ puts "#{block_num} :: #{trx_id}; ops: #{trx.operations.map(&:type).join(', ')}"
207
+ end
208
+ end
209
+ end
210
+
211
+ desc 'Test the ability to stream a block range of operations.'
212
+ task :op_range, [:mode, :at_block_num] do |t, args|
213
+ mode = (args[:mode] || 'irreversible').to_sym
214
+ first_block_num = args[:at_block_num].to_i if !!args[:at_block_num]
215
+ stream = Crea::Stream.new(url: ENV['TEST_NODE'], mode: mode)
216
+ api = Crea::Api.new(url: ENV['TEST_NODE'])
217
+
218
+ api.get_dynamic_global_properties do |properties|
219
+ current_block_num = if mode == :head
220
+ properties.head_block_number
221
+ else
222
+ properties.last_irreversible_block_num
223
+ end
224
+
225
+ # First pass replays latest a random number of blocks to test chunking.
226
+ first_block_num ||= current_block_num - (rand * 200).to_i
227
+
228
+ stream.operations(at_block_num: first_block_num) do |op, trx_id, block_num|
229
+ puts "#{block_num} :: #{trx_id}; op: #{op.type}"
230
+ end
231
+ end
232
+ end
233
+
234
+ desc 'Test the ability to stream a block range of virtual operations.'
235
+ task :vop_range, [:mode, :at_block_num] do |t, args|
236
+ mode = (args[:mode] || 'irreversible').to_sym
237
+ first_block_num = args[:at_block_num].to_i if !!args[:at_block_num]
238
+ stream = Crea::Stream.new(url: ENV['TEST_NODE'], mode: mode)
239
+ api = Crea::Api.new(url: ENV['TEST_NODE'])
240
+
241
+ api.get_dynamic_global_properties do |properties|
242
+ current_block_num = if mode == :head
243
+ properties.head_block_number
244
+ else
245
+ properties.last_irreversible_block_num
246
+ end
247
+
248
+ # First pass replays latest a random number of blocks to test chunking.
249
+ first_block_num ||= current_block_num - (rand * 200).to_i
250
+
251
+ stream.operations(at_block_num: first_block_num, only_virtual: true) do |op, trx_id, block_num|
252
+ puts "#{block_num} :: #{trx_id}; op: #{op.type}"
253
+ end
254
+ end
255
+ end
256
+
257
+ desc 'Test the ability to stream a block range of all operations (including virtual).'
258
+ task :all_op_range, [:mode, :at_block_num] do |t, args|
259
+ mode = (args[:mode] || 'irreversible').to_sym
260
+ first_block_num = args[:at_block_num].to_i if !!args[:at_block_num]
261
+ stream = Crea::Stream.new(url: ENV['TEST_NODE'], mode: mode)
262
+ api = Crea::Api.new(url: ENV['TEST_NODE'])
263
+
264
+ api.get_dynamic_global_properties do |properties|
265
+ current_block_num = if mode == :head
266
+ properties.head_block_number
267
+ else
268
+ properties.last_irreversible_block_num
269
+ end
270
+
271
+ # First pass replays latest a random number of blocks to test chunking.
272
+ first_block_num ||= current_block_num - (rand * 200).to_i
273
+
274
+ stream.operations(at_block_num: first_block_num, include_virtual: true) do |op, trx_id, block_num|
275
+ puts "#{block_num} :: #{trx_id}; op: #{op.type}"
276
+ end
277
+ end
278
+ end
279
+ end
280
+
281
+ YARD::Rake::YardocTask.new do |t|
282
+ t.files = ['lib/**/*.rb']
283
+ end
284
+
285
+ task default: :test
286
+
287
+ desc 'Ruby console with crea already required.'
288
+ task :console do
289
+ exec 'irb -r crea -I ./lib'
290
+ end
291
+
292
+ namespace :clean do
293
+ desc 'Remove test/fixtures/vcr_cassettes/*.yml so they can be rebuilt fresh.'
294
+ task :vcr do |t|
295
+ cmd = 'echo Cleaned cassettes: $(rm -v test/fixtures/vcr_cassettes/*.yml | wc -l)'
296
+ system cmd
297
+ end
298
+ end
299
+
300
+ namespace :show do
301
+ desc 'Shows known API names.'
302
+ task :apis do
303
+ url = ENV['URL']
304
+ jsonrpc = Crea::Jsonrpc.new(url: url)
305
+ api_methods = jsonrpc.get_api_methods
306
+ puts api_methods.keys
307
+ end
308
+
309
+ desc 'Shows known method names for specified API.'
310
+ task :methods, [:api] do |t, args|
311
+ url = ENV['URL']
312
+ jsonrpc = Crea::Jsonrpc.new(url: url)
313
+ api_methods = jsonrpc.get_api_methods
314
+ api_methods[args[:api]].each do |method|
315
+ jsonrpc.get_signature(method: "#{args[:api]}.#{method}") do |signature|
316
+ print "#{method} "
317
+ params = signature.args.map do |k, v|
318
+ if v =~ /\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2]\d|3[0-1])T(2[0-3]|[01]\d):[0-5]\d:[0-5]\d/
319
+ "#{k}: Time"
320
+ elsif v.class == Hashie::Array
321
+ "#{k}: []"
322
+ elsif v.class == Hashie::Mash
323
+ "#{k}: {}"
324
+ else
325
+ "#{k}: #{v.class}"
326
+ end
327
+ end
328
+ puts params.join(', ')
329
+ end
330
+ end
331
+ end
332
+ end