hive-ruby 1.0.0.pre.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 (80) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +54 -0
  3. data/CONTRIBUTING.md +79 -0
  4. data/Gemfile +3 -0
  5. data/Gemfile.lock +91 -0
  6. data/LICENSE +21 -0
  7. data/README.md +248 -0
  8. data/Rakefile +358 -0
  9. data/gource.sh +6 -0
  10. data/hive-ruby.gemspec +40 -0
  11. data/images/Anthony Martin.png +0 -0
  12. data/lib/hive.rb +89 -0
  13. data/lib/hive/api.rb +223 -0
  14. data/lib/hive/base_error.rb +218 -0
  15. data/lib/hive/block_api.rb +78 -0
  16. data/lib/hive/bridge.rb +12 -0
  17. data/lib/hive/broadcast.rb +1334 -0
  18. data/lib/hive/chain_config.rb +34 -0
  19. data/lib/hive/fallback.rb +287 -0
  20. data/lib/hive/formatter.rb +14 -0
  21. data/lib/hive/jsonrpc.rb +112 -0
  22. data/lib/hive/marshal.rb +231 -0
  23. data/lib/hive/mixins/jsonable.rb +37 -0
  24. data/lib/hive/mixins/retriable.rb +58 -0
  25. data/lib/hive/mixins/serializable.rb +45 -0
  26. data/lib/hive/operation.rb +141 -0
  27. data/lib/hive/operation/account_create.rb +10 -0
  28. data/lib/hive/operation/account_create_with_delegation.rb +12 -0
  29. data/lib/hive/operation/account_update.rb +8 -0
  30. data/lib/hive/operation/account_witness_proxy.rb +4 -0
  31. data/lib/hive/operation/account_witness_vote.rb +5 -0
  32. data/lib/hive/operation/cancel_transfer_from_savings.rb +4 -0
  33. data/lib/hive/operation/challenge_authority.rb +5 -0
  34. data/lib/hive/operation/change_recovery_account.rb +5 -0
  35. data/lib/hive/operation/claim_account.rb +5 -0
  36. data/lib/hive/operation/claim_reward_balance.rb +6 -0
  37. data/lib/hive/operation/comment.rb +9 -0
  38. data/lib/hive/operation/comment_options.rb +10 -0
  39. data/lib/hive/operation/convert.rb +5 -0
  40. data/lib/hive/operation/create_claimed_account.rb +10 -0
  41. data/lib/hive/operation/custom.rb +5 -0
  42. data/lib/hive/operation/custom_binary.rb +8 -0
  43. data/lib/hive/operation/custom_json.rb +6 -0
  44. data/lib/hive/operation/decline_voting_rights.rb +4 -0
  45. data/lib/hive/operation/delegate_vesting_shares.rb +5 -0
  46. data/lib/hive/operation/delete_comment.rb +4 -0
  47. data/lib/hive/operation/escrow_approve.rb +8 -0
  48. data/lib/hive/operation/escrow_dispute.rb +7 -0
  49. data/lib/hive/operation/escrow_release.rb +10 -0
  50. data/lib/hive/operation/escrow_transfer.rb +12 -0
  51. data/lib/hive/operation/feed_publish.rb +4 -0
  52. data/lib/hive/operation/limit_order_cancel.rb +4 -0
  53. data/lib/hive/operation/limit_order_create.rb +8 -0
  54. data/lib/hive/operation/limit_order_create2.rb +8 -0
  55. data/lib/hive/operation/prove_authority.rb +4 -0
  56. data/lib/hive/operation/recover_account.rb +6 -0
  57. data/lib/hive/operation/report_over_production.rb +5 -0
  58. data/lib/hive/operation/request_account_recovery.rb +6 -0
  59. data/lib/hive/operation/reset_account.rb +5 -0
  60. data/lib/hive/operation/set_reset_account.rb +5 -0
  61. data/lib/hive/operation/set_withdraw_vesting_route.rb +6 -0
  62. data/lib/hive/operation/transfer.rb +6 -0
  63. data/lib/hive/operation/transfer_from_savings.rb +7 -0
  64. data/lib/hive/operation/transfer_to_savings.rb +6 -0
  65. data/lib/hive/operation/transfer_to_vesting.rb +5 -0
  66. data/lib/hive/operation/vote.rb +6 -0
  67. data/lib/hive/operation/withdraw_vesting.rb +4 -0
  68. data/lib/hive/operation/witness_set_properties.rb +5 -0
  69. data/lib/hive/operation/witness_update.rb +7 -0
  70. data/lib/hive/rpc/base_client.rb +179 -0
  71. data/lib/hive/rpc/http_client.rb +143 -0
  72. data/lib/hive/rpc/thread_safe_http_client.rb +35 -0
  73. data/lib/hive/stream.rb +385 -0
  74. data/lib/hive/transaction.rb +115 -0
  75. data/lib/hive/transaction_builder.rb +406 -0
  76. data/lib/hive/type/amount.rb +126 -0
  77. data/lib/hive/type/base_type.rb +10 -0
  78. data/lib/hive/utils.rb +17 -0
  79. data/lib/hive/version.rb +4 -0
  80. metadata +502 -0
data/lib/hive/api.rb ADDED
@@ -0,0 +1,223 @@
1
+ module Hive
2
+ # This ruby API works with
3
+ # {https://github.com/openhive-network/hive/releases hived-0.23.00} and other AppBase
4
+ # compatible upstreams. To access different API namespaces, use the
5
+ # following:
6
+ #
7
+ # api = Hive::Api.new
8
+ # api.get_dynamic_global_properties
9
+ #
10
+ # The above example will make an instance that can access the
11
+ # {https://developers.hive.io/apidefinitions/condenser-api.html condenser_api}
12
+ # namespace. Alternatively, you may also create a direct instances with its
13
+ # full name, if you prefer:
14
+ #
15
+ # api = Hive::CondenserApi.new
16
+ # api.get_dynamic_global_properties
17
+ #
18
+ # If you know the name of another API that is supported by the remote node,
19
+ # you can create an instance to that instead, for example:
20
+ #
21
+ # api = Hive::MarketHistoryApi.new
22
+ # api.get_volume
23
+ #
24
+ # All known API by namespace:
25
+ #
26
+ # * {AccountByKeyApi}
27
+ # * {AccountHistoryApi}
28
+ # * {BlockApi}
29
+ # * {DatabaseApi}
30
+ # * {FollowApi}
31
+ # * {Jsonrpc}
32
+ # * {MarketHistoryApi}
33
+ # * {NetworkBroadcastApi}
34
+ # * {TagsApi}
35
+ # * {WitnessApi}
36
+ #
37
+ # Also see: {https://developers.hive.io/apidefinitions/ Complete API Definitions}
38
+ class Api
39
+ attr_accessor :chain, :methods, :rpc_client
40
+
41
+ # Use this for debugging naive thread handler.
42
+ # DEFAULT_RPC_CLIENT_CLASS = RPC::HttpClient
43
+ DEFAULT_RPC_CLIENT_CLASS = RPC::ThreadSafeHttpClient
44
+
45
+ def self.api_name=(api_name)
46
+ @api_name = api_name.to_s.
47
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
48
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
49
+ tr('-', '_').downcase.to_sym
50
+ end
51
+
52
+ def self.api_name
53
+ @api_name
54
+ end
55
+
56
+ def self.api_class_name
57
+ @api_name.to_s.split('_').map(&:capitalize).join
58
+ end
59
+
60
+ def self.jsonrpc=(jsonrpc, url = nil)
61
+ @jsonrpc ||= {}
62
+ @jsonrpc[url || jsonrpc.rpc_client.uri.to_s] = jsonrpc
63
+ end
64
+
65
+ def self.jsonrpc(url = nil)
66
+ if @jsonrpc.size < 2 && url.nil?
67
+ @jsonrpc.values.first
68
+ else
69
+ @jsonrpc[url]
70
+ end
71
+ end
72
+
73
+ # Override this if you want to just use your own client. Otherwise, inject
74
+ # the default using:
75
+ #
76
+ # Hive::Api.register default_rpc_client_class: MyClient
77
+ def self.default_rpc_client_class
78
+ if !!@injected_dependencies && !!@injected_dependencies[:default_rpc_client_class]
79
+ @injected_dependencies[:default_rpc_client_class]
80
+ else
81
+ DEFAULT_RPC_CLIENT_CLASS
82
+ end
83
+ end
84
+
85
+ # Used for dependency injection. Currently, the only key supported is:
86
+ #
87
+ # `default_rpc_client_class`
88
+ def self.register(register)
89
+ @injected_dependencies ||= {}
90
+ @injected_dependencies = @injected_dependencies.merge register
91
+ end
92
+
93
+ def initialize(options = {})
94
+ @chain = options[:chain] || :hive
95
+ @error_pipe = options[:error_pipe] || STDERR
96
+ @api_name = self.class.api_name ||= :condenser_api
97
+
98
+ @rpc_client = if !!options[:rpc_client]
99
+ options[:rpc_client]
100
+ else
101
+ rpc_client_class = self.class.default_rpc_client_class
102
+ rpc_client_class.new(options.merge(api_name: @api_name))
103
+ end
104
+
105
+ if @api_name == :jsonrpc
106
+ Api::jsonrpc = self
107
+ else
108
+ # Note, we have to wait until initialize to check this because we don't
109
+ # have access to instance options until now.
110
+
111
+ Api::jsonrpc = Jsonrpc.new(options)
112
+
113
+ @methods = begin
114
+ Api::jsonrpc(rpc_client.uri.to_s).get_api_methods
115
+ rescue => e
116
+ Fallback::API_METHODS
117
+ end
118
+
119
+ if Jsonrpc::UNLISTED_APIS.include? @api_name
120
+ @methods ||= {}
121
+ @methods[@api_name] ||= Fallback::API_METHODS[@api_name]
122
+ end
123
+
124
+ unless !!@methods[@api_name]
125
+ raise UnknownApiError, "#{@api_name} (known APIs: #{@methods.keys.join(' ')})"
126
+ end
127
+
128
+ @methods = @methods[@api_name]
129
+ end
130
+
131
+ @try_count = 0
132
+ end
133
+
134
+ def inspect
135
+ properties = %w(chain methods).map do |prop|
136
+ if !!(v = instance_variable_get("@#{prop}"))
137
+ case v
138
+ when Array then "@#{prop}=<#{v.size} #{v.size == 1 ? 'element' : 'elements'}>"
139
+ else; "@#{prop}=#{v}"
140
+ end
141
+ end
142
+ end.compact.join(', ')
143
+
144
+ "#<#{self.class.api_class_name} [#{properties}]>"
145
+ end
146
+ private
147
+ # @private
148
+ def args_keys_to_s(rpc_method_name)
149
+ args = signature(rpc_method_name).args
150
+ args_keys = JSON[args.to_json]
151
+ end
152
+
153
+ # @private
154
+ def signature(rpc_method_name)
155
+ url = rpc_client.uri.to_s
156
+
157
+ @@signatures ||= {}
158
+ @@signatures[url] ||= {}
159
+
160
+ @@signatures[url][rpc_method_name] ||= begin
161
+ Api::jsonrpc(url).get_signature(method: rpc_method_name).result
162
+ rescue => e
163
+ Hashie::Mash.new({args: Fallback::API_METHOD_SIGNATURES[@api_name][rpc_method_name.split('.').last.to_sym]})
164
+ end
165
+ end
166
+
167
+ # @private
168
+ def respond_to_missing?(m, include_private = false)
169
+ methods.nil? ? false : methods.include?(m.to_sym)
170
+ end
171
+
172
+ # @private
173
+ def method_missing(m, *args, &block)
174
+ super unless respond_to_missing?(m)
175
+
176
+ rpc_method_name = "#{@api_name}.#{m}"
177
+ rpc_args = case @api_name
178
+ when :condenser_api then args
179
+ when :jsonrpc then args.first
180
+ else
181
+ expected_args = signature(rpc_method_name).args || []
182
+ expected_args_key_string = if expected_args.size > 0
183
+ " (#{args_keys_to_s(rpc_method_name)})"
184
+ end
185
+ expected_args_size = expected_args.size
186
+
187
+ begin
188
+ args = args.first.to_h
189
+ args_size = args.size
190
+
191
+ # Some argument are optional, but if the arguments passed are greater
192
+ # than the expected arguments size, we can warn.
193
+ if args_size > expected_args_size
194
+ @error_pipe.puts "Warning #{rpc_method_name} expects arguments: #{expected_args_size}, got: #{args_size}"
195
+ end
196
+ rescue NoMethodError => e
197
+ error = Hive::ArgumentError.new("#{rpc_method_name} expects arguments: #{expected_args_size}", e)
198
+ raise error
199
+ rescue => e
200
+ raise UnknownError.new("#{rpc_method_name} unknown error.", e)
201
+ end
202
+
203
+ args
204
+ end
205
+
206
+ response = rpc_client.rpc_execute(@api_name, m, rpc_args)
207
+
208
+ if !!block
209
+ case response
210
+ when Hashie::Mash then yield response.result, response.error, response.id
211
+ when Hashie::Array
212
+ response.each do |r|
213
+ r = Hashie::Mash.new(r)
214
+ yield r.result, r.error, r.id
215
+ end
216
+ else; yield response
217
+ end
218
+ else
219
+ return response
220
+ end
221
+ end
222
+ end
223
+ end
@@ -0,0 +1,218 @@
1
+ module Hive
2
+ class BaseError < StandardError
3
+ def initialize(error = nil, cause = nil)
4
+ @error = error
5
+ @cause = cause
6
+ end
7
+
8
+ def to_s
9
+ detail = {}
10
+ detail[:error] = @error if !!@error
11
+ detail[:cause] = @cause if !!@cause
12
+
13
+ JSON[detail] rescue detail.to_s
14
+ end
15
+
16
+ def self.build_error(error, context)
17
+ if error.message == 'Unable to acquire database lock'
18
+ raise Hive::RemoteDatabaseLockError, error.message, build_backtrace(error)
19
+ end
20
+
21
+ if error.message.include? 'Internal Error'
22
+ raise Hive::RemoteNodeError, error.message, build_backtrace(error)
23
+ end
24
+
25
+ if error.message.include? 'Server error'
26
+ raise Hive::RemoteNodeError, error.message, build_backtrace(error)
27
+ end
28
+
29
+ if error.message.include? 'plugin not enabled'
30
+ raise Hive::PluginNotEnabledError, error.message, build_backtrace(error)
31
+ end
32
+
33
+ if error.message.include? 'argument'
34
+ raise Hive::ArgumentError, "#{context}: #{error.message}", build_backtrace(error)
35
+ end
36
+
37
+ if error.message.include? 'Invalid params'
38
+ raise Hive::ArgumentError, "#{context}: #{error.message}", build_backtrace(error)
39
+ end
40
+
41
+ if error.message.start_with? 'Bad Cast:'
42
+ raise Hive::ArgumentError, "#{context}: #{error.message}", build_backtrace(error)
43
+ end
44
+
45
+ if error.message.include? 'prefix_len'
46
+ raise Hive::ArgumentError, "#{context}: #{error.message}", build_backtrace(error)
47
+ end
48
+
49
+ if error.message.include? 'Parse Error'
50
+ raise Hive::ArgumentError, "#{context}: #{error.message}", build_backtrace(error)
51
+ end
52
+
53
+ if error.message.include? 'unknown key'
54
+ raise Hive::ArgumentError, "#{context}: #{error.message} (or content has been deleted)", build_backtrace(error)
55
+ end
56
+
57
+ if error.message.include? 'Comment is not in account\'s comments'
58
+ raise Hive::ArgumentError, "#{context}: #{error.message}", build_backtrace(error)
59
+ end
60
+
61
+ if error.message.include? 'Could not find comment'
62
+ raise Hive::ArgumentError, "#{context}: #{error.message}", build_backtrace(error)
63
+ end
64
+
65
+ if error.message.include? 'unable to convert ISO-formatted string to fc::time_point_sec'
66
+ raise Hive::ArgumentError, "#{context}: #{error.message}", build_backtrace(error)
67
+ end
68
+
69
+ if error.message.include? 'Input data have to treated as object.'
70
+ raise Hive::ArgumentError, "#{context}: #{error.message}", build_backtrace(error)
71
+ end
72
+
73
+ if error.message.include? 'base.amount > share_type(0)'
74
+ raise Hive::ArgumentError, "#{context}: #{error.message}", build_backtrace(error)
75
+ end
76
+
77
+ if error.message.include? 'blk->transactions.size() > itr->trx_in_block'
78
+ raise Hive::VirtualOperationsNotAllowedError, "#{context}: #{error.message}", build_backtrace(error)
79
+ end
80
+
81
+ if error.message.include? 'A transaction must have at least one operation'
82
+ raise Hive::EmptyTransactionError, "#{context}: #{error.message}", build_backtrace(error)
83
+ end
84
+
85
+ if error.message.include? 'transaction expiration exception'
86
+ raise Hive::TransactionExpiredError, "#{context}: #{error.message}", build_backtrace(error)
87
+ end
88
+
89
+ if error.message.include? 'Duplicate transaction check failed'
90
+ raise Hive::DuplicateTransactionError, "#{context}: #{error.message}", build_backtrace(error)
91
+ end
92
+
93
+ if error.message.include? 'signature is not canonical'
94
+ raise Hive::NonCanonicalSignatureError, "#{context}: #{error.message}", build_backtrace(error)
95
+ end
96
+
97
+ if error.message.include? 'attempting to push a block that is too old'
98
+ raise Hive::BlockTooOldError, "#{context}: #{error.message}", build_backtrace(error)
99
+ end
100
+
101
+ if error.message.include? 'irrelevant signature'
102
+ raise Hive::IrrelevantSignatureError, "#{context}: #{error.message}", build_backtrace(error)
103
+ end
104
+
105
+ if error.message.include? 'missing required posting authority'
106
+ raise Hive::MissingPostingAuthorityError, "#{context}: #{error.message}", build_backtrace(error)
107
+ end
108
+
109
+ if error.message.include? 'missing required active authority'
110
+ raise Hive::MissingActiveAuthorityError, "#{context}: #{error.message}", build_backtrace(error)
111
+ end
112
+
113
+ if error.message.include? 'missing required owner authority'
114
+ raise Hive::MissingOwnerAuthorityError, "#{context}: #{error.message}", build_backtrace(error)
115
+ end
116
+
117
+ if error.message.include? 'missing required other authority'
118
+ raise Hive::MissingOtherAuthorityError, "#{context}: #{error.message}", build_backtrace(error)
119
+ end
120
+
121
+ if error.message.include? 'Upstream response error'
122
+ raise Hive::UpstreamResponseError, "#{context}: #{error.message}", build_backtrace(error)
123
+ end
124
+
125
+ if error.message.include? 'Bad or missing upstream response'
126
+ raise Hive::BadOrMissingUpstreamResponseError, "#{context}: #{error.message}", build_backtrace(error)
127
+ end
128
+
129
+ if error.message.include? 'operator has disabled operation indexing by transaction_id'
130
+ raise Hive::TransactionIndexDisabledError, "#{context}: #{error.message}", build_backtrace(error)
131
+ end
132
+
133
+ if error.message.include? 'is_valid_account_name'
134
+ raise Hive::InvalidAccountError, "#{context}: #{error.message}", build_backtrace(error)
135
+ end
136
+
137
+ if error.message.include?('Method') && error.message.include?(' does not exist.')
138
+ raise Hive::UnknownMethodError, "#{context}: #{error.message}", build_backtrace(error)
139
+ end
140
+
141
+ if error.message.include? 'Invalid operation name'
142
+ raise Hive::UnknownOperationError, "#{context}: #{error.message}", build_backtrace(error)
143
+ end
144
+
145
+ if error.message =~ /Invalid object name: .+_operation/
146
+ raise Hive::UnknownOperationError, "#{context}: #{error.message}", build_backtrace(error)
147
+ end
148
+
149
+ if error.message.include? 'Author not found'
150
+ raise Hive::AuthorNotFoundError, "#{context}: #{error.message}", build_backtrace(error)
151
+ end
152
+
153
+ if error.message.include? ' != fc::time_point_sec::maximum()'
154
+ raise Hive::ReachedMaximumTimeError, "#{context}: #{error.message}", build_backtrace(error)
155
+ end
156
+
157
+ if error.message.include? 'Cannot transfer a negative amount (aka: stealing)'
158
+ raise Hive::TheftError, "#{context}: #{error.message}", build_backtrace(error)
159
+ end
160
+
161
+ if error.message.include? 'Must transfer a nonzero amount'
162
+ raise Hive::NonZeroRequiredError, "#{context}: #{error.message}", build_backtrace(error)
163
+ end
164
+
165
+ if error.message.include? 'is_asset_type'
166
+ raise Hive::UnexpectedAssetError, "#{context}: #{error.message}", build_backtrace(error)
167
+ end
168
+
169
+ puts JSON.pretty_generate(error) if ENV['DEBUG']
170
+ raise UnknownError, "#{context}: #{error.message}", build_backtrace(error)
171
+ end
172
+ private
173
+ def self.build_backtrace(error)
174
+ backtrace = Thread.current.backtrace.reject{ |line| line =~ /base_error/ }
175
+ JSON.pretty_generate(error) + "\n" + backtrace.join("\n")
176
+ end
177
+ end
178
+
179
+ class DeserializationError < BaseError; end
180
+ class SerializationMismatchError < BaseError; end
181
+ class UnsupportedChainError < BaseError; end
182
+ class ArgumentError < BaseError; end
183
+ class TypeError < BaseError; end
184
+ class EmptyTransactionError < ArgumentError; end
185
+ class InvalidAccountError < ArgumentError; end
186
+ class AuthorNotFoundError < ArgumentError; end
187
+ class ReachedMaximumTimeError < ArgumentError; end
188
+ class VirtualOperationsNotAllowedError < ArgumentError; end
189
+ class TheftError < ArgumentError; end
190
+ class NonZeroRequiredError < ArgumentError; end
191
+ class UnexpectedAssetError < ArgumentError; end
192
+ class TransactionExpiredError < BaseError; end
193
+ class DuplicateTransactionError < TransactionExpiredError; end
194
+ class NonCanonicalSignatureError < TransactionExpiredError; end
195
+ class BlockTooOldError < BaseError; end
196
+ class IrrelevantSignatureError < BaseError; end
197
+ class MissingAuthorityError < BaseError; end
198
+ class MissingPostingAuthorityError < MissingAuthorityError; end
199
+ class MissingActiveAuthorityError < MissingAuthorityError; end
200
+ class MissingOwnerAuthorityError < MissingAuthorityError; end
201
+ class MissingOtherAuthorityError < MissingAuthorityError; end
202
+ class IncorrectRequestIdError < BaseError; end
203
+ class IncorrectResponseIdError < BaseError; end
204
+ class RemoteNodeError < BaseError; end
205
+ class UpstreamResponseError < RemoteNodeError; end
206
+ class RemoteDatabaseLockError < UpstreamResponseError; end
207
+ class PluginNotEnabledError < UpstreamResponseError; end
208
+ class BadOrMissingUpstreamResponseError < UpstreamResponseError; end
209
+ class TransactionIndexDisabledError < BaseError; end
210
+ class NotAppBaseError < BaseError; end
211
+ class UnknownApiError < BaseError; end
212
+ class UnknownMethodError < BaseError; end
213
+ class UnknownOperationError < BaseError; end
214
+ class JsonRpcBatchMaximumSizeExceededError < BaseError; end
215
+ class TooManyTimeoutsError < BaseError; end
216
+ class TooManyRetriesError < BaseError; end
217
+ class UnknownError < BaseError; end
218
+ end
@@ -0,0 +1,78 @@
1
+ module Hive
2
+ # {BlockApi} is used to query values related to the block plugin. It can also
3
+ # be used to access a range of multiple blocks by using
4
+ # {http://www.jsonrpc.org/specification#batch JSON-RPC 2.0 batch} requests.
5
+ #
6
+ # Also see: {https://developers.hive.io/apidefinitions/block-api.html Block API Definitions}
7
+ class BlockApi < Api
8
+ MAX_RANGE_SIZE = 50
9
+
10
+ def initialize(options = {})
11
+ self.class.api_name = :block_api
12
+ super
13
+ end
14
+
15
+ # Uses a batched requst on a range of block headers.
16
+ #
17
+ # @param options [Hash] The attributes to get a block range with.
18
+ # @option options [Range] :block_range starting on one block number and ending on an higher block number.
19
+ def get_block_headers(options = {block_range: (0..0)}, &block)
20
+ get_block_objects(options.merge(object: :block_header), block)
21
+ end
22
+
23
+ # Uses a batched requst on a range of blocks.
24
+ #
25
+ # @param options [Hash] The attributes to get a block range with.
26
+ # @option options [Range] :block_range starting on one block number and ending on an higher block number.
27
+ def get_blocks(options = {block_range: (0..0)}, &block)
28
+ get_block_objects(options.merge(object: :block), block)
29
+ end
30
+ private
31
+ def get_block_objects(options = {block_range: (0..0)}, block = nil)
32
+ object = options[:object]
33
+ object_method = "get_#{object}".to_sym
34
+ block_range = options[:block_range] || (0..0)
35
+
36
+ if (start = block_range.first) < 1
37
+ raise Hive::ArgumentError, "Invalid starting block: #{start}"
38
+ end
39
+
40
+ chunks = if block_range.size > MAX_RANGE_SIZE
41
+ block_range.each_slice(MAX_RANGE_SIZE)
42
+ else
43
+ [block_range]
44
+ end
45
+
46
+ for sub_range in chunks do
47
+ request_object = []
48
+
49
+ for i in sub_range do
50
+ @rpc_client.put(self.class.api_name, object_method, block_num: i, request_object: request_object)
51
+ end
52
+
53
+ if !!block
54
+ index = 0
55
+ @rpc_client.rpc_batch_execute(request_object: request_object) do |result, error, id|
56
+ block_num = sub_range.to_a[index]
57
+ index = index + 1
58
+
59
+ case object
60
+ when :block_header
61
+ block.call(result.nil? ? nil : result[:header], block_num)
62
+ else
63
+ block.call(result.nil? ? nil : result[object], block_num)
64
+ end
65
+ end
66
+ else
67
+ blocks = []
68
+
69
+ @rpc_client.rpc_batch_execute(request_object: request_object) do |result, error, id|
70
+ blocks << result
71
+ end
72
+ end
73
+ end
74
+
75
+ blocks
76
+ end
77
+ end
78
+ end