radiator 0.3.0dev1 → 0.3.0dev2

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
  SHA1:
3
- metadata.gz: db2757e072c1d05c7f12eb6228245cb66680af4a
4
- data.tar.gz: 33ade0af04c25fdae0dce9bf94322367d68cfbe3
3
+ metadata.gz: e876d3ec41bf655bc3bfc4494f22d862b71f4442
4
+ data.tar.gz: 65bec4acf06c108bd56ca239c9cdb660332c91a9
5
5
  SHA512:
6
- metadata.gz: 8c5a3a4079b0f5d92f142fee590f3e6e0256bdba99c2f78951f2030dc68ad4f3f42cc6fd013293cab4342b596be3789432acea19f518de5cf06a8097da1048c1
7
- data.tar.gz: 836ea02d0e39a9ac338b301ff65ed9efc8256336b3fccc482e377f573d131970459cb4dee3af3102c49583b61b308a8e77b1241cbca9cdd2755f8bc901285de8
6
+ metadata.gz: 9e1f48eb220ecd006335906909f88e493f7d806a4147e5443f1f9b8663c0ea941d6239bb1a610180414c514e85e9c1b084309d21cc698d0f20e730f9e292f546
7
+ data.tar.gz: 5e8c2376494c49046e0f18ef34b7a0e235e8230bbc5acbf76515adbced6e17de80942cdfb1214340e41c2ccecf9c4f85684b959fc00f99e65ae787b5afeb7bc0
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- radiator (0.3.0dev1)
4
+ radiator (0.3.0dev2)
5
5
  bitcoin-ruby (= 0.0.11)
6
6
  ffi (= 1.9.18)
7
7
  hashie (~> 3.5, >= 3.5.5)
data/lib/radiator/api.rb CHANGED
@@ -15,6 +15,9 @@ module Radiator
15
15
  'https://steemd-int.steemit.com',
16
16
  'https://steemd.steemitstage.com',
17
17
  'https://gtg.steem.house:8090',
18
+ "https://seed.bitcoiner.me",
19
+ "https://steemd.minnowsupportproject.org",
20
+ "https://steemd.privex.io",
18
21
  'https://rpc.steemliberator.com'
19
22
  ]
20
23
 
@@ -30,7 +33,6 @@ module Radiator
30
33
  @failover_urls = options[:failover_urls] || (DEFAULT_FAILOVER_URLS - [@url])
31
34
  @preferred_failover_urls = @failover_urls.dup
32
35
  @debug = !!options[:debug]
33
- @net_http_persistent_enabled = true
34
36
  @logger = options[:logger] || Radiator.logger
35
37
  @hashie_logger = options[:hashie_logger] || Logger.new(nil)
36
38
 
@@ -38,8 +40,15 @@ module Radiator
38
40
  @hashie_logger = Logger.new(@hashie_logger)
39
41
  end
40
42
 
43
+ @recover_transactions_on_error = if options.keys.include? :recover_transactions_on_error
44
+ options[:recover_transactions_on_error]
45
+ else
46
+ true
47
+ end
48
+
41
49
  Hashie.logger = @hashie_logger
42
50
  @method_names = nil
51
+ @api_options = options.dup
43
52
  end
44
53
 
45
54
  def method_names
@@ -64,11 +73,11 @@ module Radiator
64
73
 
65
74
  if !!block
66
75
  block_number.each do |i|
67
- yield get_block(i).result, i
76
+ yield api.get_block(i).result, i
68
77
  end
69
78
  else
70
79
  block_number.map do |i|
71
- get_block(i).result
80
+ api.get_block(i).result
72
81
  end
73
82
  end
74
83
  end
@@ -80,43 +89,45 @@ module Radiator
80
89
  # @return [Hash]
81
90
  def find_block(block_number, &block)
82
91
  if !!block
83
- yield get_blocks(block_number).first
92
+ yield api.get_blocks(block_number).first
84
93
  else
85
- get_blocks(block_number).first
94
+ api.get_blocks(block_number).first
86
95
  end
87
96
  end
88
97
 
89
98
  def find_account(id, &block)
90
99
  if !!block
91
- yield get_accounts([id]).result.first
100
+ yield api.get_accounts([id]).result.first
92
101
  else
93
- get_accounts([id]).result.first
102
+ api.get_accounts([id]).result.first
94
103
  end
95
104
  end
96
105
 
97
- # TODO: Need to rename this to base_per_mvest and alias to steem_per_mvest
98
- def steem_per_mvest
99
- properties = get_dynamic_global_properties.result
106
+ def base_per_mvest
107
+ api.get_dynamic_global_properties do |properties|
108
+ total_vesting_fund_steem = properties.total_vesting_fund_steem.to_f
109
+ total_vesting_shares_mvest = properties.total_vesting_shares.to_f / 1e6
100
110
 
101
- total_vesting_fund_steem = properties.total_vesting_fund_steem.to_f
102
- total_vesting_shares_mvest = properties.total_vesting_shares.to_f / 1e6
103
-
104
- total_vesting_fund_steem / total_vesting_shares_mvest
111
+ total_vesting_fund_steem / total_vesting_shares_mvest
112
+ end
105
113
  end
106
114
 
107
- # TODO: Need to rename this to base_per_debt and alias to steem_per_debt
108
- def steem_per_usd
109
- feed_history = get_feed_history.result
110
-
111
- current_median_history = feed_history.current_median_history
112
- base = current_median_history.base
113
- base = base.split(' ').first.to_f
114
- quote = current_median_history.quote
115
- quote = quote.split(' ').first.to_f
115
+ alias steem_per_mvest base_per_mvest
116
+
117
+ def base_per_debt
118
+ get_feed_history do |feed_history|
119
+ current_median_history = feed_history.current_median_history
120
+ base = current_median_history.base
121
+ base = base.split(' ').first.to_f
122
+ quote = current_median_history.quote
123
+ quote = quote.split(' ').first.to_f
116
124
 
117
- (base / quote) * steem_per_mvest
125
+ (base / quote) * steem_per_mvest
126
+ end
118
127
  end
119
128
 
129
+ alias steem_per_usd base_per_debt
130
+
120
131
  def respond_to_missing?(m, include_private = false)
121
132
  method_names.include?(m.to_sym)
122
133
  end
@@ -124,6 +135,7 @@ module Radiator
124
135
  def method_missing(m, *args, &block)
125
136
  super unless respond_to_missing?(m)
126
137
 
138
+ response = nil
127
139
  options = {
128
140
  jsonrpc: "2.0",
129
141
  params: [api_name, m, args],
@@ -131,35 +143,57 @@ module Radiator
131
143
  method: "call"
132
144
  }
133
145
 
146
+ tries = 0
147
+ timestamp = Time.now.utc
148
+
134
149
  loop do
150
+ tries += 1
151
+
135
152
  begin
153
+ if @recover_transactions_on_error
154
+ signatures = extract_signatures(options)
155
+
156
+ if tries > 1 && !!signatures && signatures.any?
157
+ if !!(response = recover_transaction(signatures, rpc_id, timestamp))
158
+ @logger.warn 'Found recovered transaction after retry.'
159
+ response = Hashie::Mash.new(response)
160
+ end
161
+ end
162
+ end
163
+
136
164
  response = request(options)
137
165
 
138
166
  if response.nil?
139
167
  @logger.error "No response, retrying ..."
140
168
  backoff
141
169
  redo
170
+ elsif !response.kind_of? Net::HTTPSuccess
171
+ @logger.warn "Unexpected response: #{response.inspect}"
172
+ backoff
173
+ redo
142
174
  end
143
175
 
144
- case response.code
176
+ response = case response.code
145
177
  when '200'
146
- response = JSON[response.body]
178
+ body = response.body
179
+ response = JSON[body]
147
180
 
148
- return Hashie::Mash.new(response)
149
- when '400'
150
- @logger.warn 'Code 400: Bad Request, retrying ...'
151
- when '502'
152
- @logger.warn 'Code 502: Bad Gateway, retrying ...'
153
- when '503'
154
- @logger.warn 'Code 503: Service Unavailable, retrying ...'
155
- when '504'
156
- @logger.warn 'Code 504: Gateway Timeout, retrying ...'
181
+ if response.keys.include?('result') && response['result'].nil?
182
+ @logger.warn 'Invalid response from node, retrying ...'; nil
183
+ else
184
+ Hashie::Mash.new(response)
185
+ end
186
+ when '400' then @logger.warn 'Code 400: Bad Request, retrying ...'; nil
187
+ when '502' then @logger.warn 'Code 502: Bad Gateway, retrying ...'; nil
188
+ when '503' then @logger.warn 'Code 503: Service Unavailable, retrying ...'; nil
189
+ when '504' then @logger.warn 'Code 504: Gateway Timeout, retrying ...'; nil
157
190
  else
158
191
  @logger.warn "Unknown code #{response.code}, retrying ..."
159
192
  ap response
160
193
  end
161
-
162
- backoff
194
+ rescue Net::HTTP::Persistent::Error => e
195
+ @logger.warn "Unable to perform request: #{e} :: #{!!e.cause ? "cause: #{e.cause.message}" : ''}"
196
+ @wakka = true
163
197
  rescue Errno::ECONNREFUSED => e
164
198
  @logger.warn 'Connection refused, retrying ...'
165
199
  rescue Errno::EADDRNOTAVAIL => e
@@ -178,9 +212,17 @@ module Radiator
178
212
  @logger.warn "JSON Parse Error (#{e.message}), retrying ..."
179
213
  rescue => e
180
214
  @logger.warn "Unknown exception from request ..."
181
- ap e
215
+ ap e if defined? ap
182
216
  end
183
-
217
+
218
+ if !!response
219
+ if !!block
220
+ return yield(response.result, response.error, response.id)
221
+ else
222
+ return response
223
+ end
224
+ end
225
+
184
226
  backoff
185
227
  end # loop
186
228
  end
@@ -201,6 +243,10 @@ module Radiator
201
243
  end.compact.freeze
202
244
  end
203
245
 
246
+ def api
247
+ @api ||= self.class == Api ? self : Api.new(@api_options)
248
+ end
249
+
204
250
  def rpc_id
205
251
  @rpc_id ||= 0
206
252
  @rpc_id = @rpc_id + 1
@@ -225,35 +271,59 @@ module Radiator
225
271
  end
226
272
 
227
273
  def request(options)
228
- if !!@net_http_persistent_enabled
229
- begin
230
- request = post_request
231
- request.body = JSON[options]
232
- response = http.request(uri, request)
233
-
234
- return response if response.kind_of? Net::HTTPSuccess
235
- @logger.warn "Unexpeced response: #{response.inspect}; temporarily falling back to non-persistent-http"
236
- backoff
237
- @net_http_persistent_enabled = false
238
- rescue Net::HTTP::Persistent::Error => e
239
- @logger.warn "Unable to perform request: #{request} :: #{e} :: #{!!e.cause ? "cause: #{e.cause.message}" : ''}; temporarily falling back to non-persistent-http"
240
- backoff
241
- @net_http_persistent_enabled = false
242
- end
243
- end
274
+ request = post_request
275
+ request.body = JSON[options]
276
+ http.request(uri, request)
277
+ end
278
+
279
+ def extract_signatures(options)
280
+ return unless options[:params].include? :network_broadcast_api
281
+
282
+ options[:params].map do |param|
283
+ next unless defined? param.map
244
284
 
245
- unless @net_http_persistent_enabled
246
- non_persistent_http = Net::HTTP.new(uri.host, uri.port)
247
- non_persistent_http.use_ssl = true
248
- non_persistent_http.verify_mode = OpenSSL::SSL::VERIFY_NONE
249
- request = post_request
250
- request.body = JSON[options]
285
+ param.map { |tx| tx[:signatures] }
286
+ end.flatten.compact
287
+ end
288
+
289
+ def recover_transaction(signatures, rpc_id, after)
290
+ now = Time.now.utc
291
+ block_range = api.get_dynamic_global_properties do |properties|
292
+ high = properties.head_block_number
293
+ low = high - 100
294
+ [*(low..(high))].reverse
295
+ end
296
+
297
+ # It would be nice if Steemit, Inc. would add an API method like
298
+ # `get_transaction`, call it `get_transaction_by_signature`, so we didn't
299
+ # have to scan the latest blocks like this. At most, we read 100 blocks
300
+ # but we also give up once the block time is before the `after` argument.
301
+
302
+ api.get_blocks(block_range) do |block, block_num|
303
+ raise "Race condition detected at: #{block_num}" if block.nil?
251
304
 
252
- # Try to go back to http persistent on next request.
253
- @net_http_persistent_enabled = true
305
+ timestamp = Time.parse(block.timestamp + 'Z')
306
+ break if timestamp < after
254
307
 
255
- non_persistent_http.request(request)
308
+ block.transactions.each_with_index do |tx, index|
309
+ next unless ((tx['signatures'] || []) & signatures).any?
310
+
311
+ puts "Found matching signatures in #{(Time.now.utc - now)} seconds: #{signatures}"
312
+ ap tx
313
+
314
+ return {
315
+ id: rpc_id,
316
+ result: {
317
+ id: block.transaction_ids[index],
318
+ block_num: block_num,
319
+ trx_num: index,
320
+ expired: false
321
+ }
322
+ }
323
+ end
256
324
  end
325
+
326
+ puts "Took #{(Time.now.utc - now)} seconds to scan for signatures."
257
327
  end
258
328
 
259
329
  def reset_failover
@@ -16,7 +16,7 @@ module Radiator
16
16
  MAX_BLOCKS_PER_NODE = 100
17
17
 
18
18
  def initialize(options = {})
19
- @api_options = options
19
+ @api_options = options.dup
20
20
  @logger = @api_options[:logger] || Radiator.logger
21
21
  end
22
22
 
@@ -16,6 +16,7 @@ module Radiator
16
16
  VALID_OPTIONS.each { |option| attr_accessor option }
17
17
 
18
18
  def initialize(options = {})
19
+ options = options.dup
19
20
  options.each do |k, v|
20
21
  k = k.to_sym
21
22
  if VALID_OPTIONS.include?(k.to_sym)
@@ -1,3 +1,3 @@
1
1
  module Radiator
2
- VERSION = '0.3.0dev1'
2
+ VERSION = '0.3.0dev2'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: radiator
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0dev1
4
+ version: 0.3.0dev2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Anthony Martin
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-09-28 00:00:00.000000000 Z
11
+ date: 2017-09-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler