crea-ruby 0.0.1

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