radiator 0.3.0dev1 → 0.3.0dev2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/lib/radiator/api.rb +134 -64
- data/lib/radiator/stream.rb +1 -1
- data/lib/radiator/transaction.rb +1 -0
- data/lib/radiator/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e876d3ec41bf655bc3bfc4494f22d862b71f4442
|
4
|
+
data.tar.gz: 65bec4acf06c108bd56ca239c9cdb660332c91a9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9e1f48eb220ecd006335906909f88e493f7d806a4147e5443f1f9b8663c0ea941d6239bb1a610180414c514e85e9c1b084309d21cc698d0f20e730f9e292f546
|
7
|
+
data.tar.gz: 5e8c2376494c49046e0f18ef34b7a0e235e8230bbc5acbf76515adbced6e17de80942cdfb1214340e41c2ccecf9c4f85684b959fc00f99e65ae787b5afeb7bc0
|
data/Gemfile.lock
CHANGED
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
|
-
|
98
|
-
|
99
|
-
|
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
|
-
|
102
|
-
|
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
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
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
|
-
|
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
|
-
|
178
|
+
body = response.body
|
179
|
+
response = JSON[body]
|
147
180
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
when '
|
154
|
-
|
155
|
-
when '
|
156
|
-
|
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
|
-
|
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
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
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
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
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
|
-
|
253
|
-
|
305
|
+
timestamp = Time.parse(block.timestamp + 'Z')
|
306
|
+
break if timestamp < after
|
254
307
|
|
255
|
-
|
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
|
data/lib/radiator/stream.rb
CHANGED
data/lib/radiator/transaction.rb
CHANGED
data/lib/radiator/version.rb
CHANGED
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.
|
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-
|
11
|
+
date: 2017-09-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|