radiator 0.3.15 → 0.4.0pre1

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: a2d13a99e9a18133d52e256663cd27bb52e77d15
4
- data.tar.gz: 5e986442c8577f297c1636f41fcd849f199ade9c
3
+ metadata.gz: b0f7aaa5e12224ae48fdfe1535182583e298d97f
4
+ data.tar.gz: 5ec823c95e96ad1a44ceb0b77bc08b72aede7f8e
5
5
  SHA512:
6
- metadata.gz: 73fd7dc83bcf3426ff096ab659ecbfb7f7108b8db2572fa238d82bbf9d8cb88ec65bacd166adb772404370110030400dad8f9493cf2fba09efc962cdf947f972
7
- data.tar.gz: f81a73d0a4e8cf45163b43b12126fa89e1d2ad6a094ad0a2b111b826bb6183300c08a045b2f1b2331a8a7aee99fccf66f9df30e7a1223bf1ba06a6eef7e8358a
6
+ metadata.gz: 6b7736813af94b8ef03e1b80e0f43aa593b194c48f71094e672798d3791eab2f0925ee313d1ea5b8b749cc8b753e0209f9298205038c5ff71b43015289eedc27
7
+ data.tar.gz: 55248de7d7142432b2d8b3a11a9e536c34915ba52bea098e38988e4c3c180ace704cfe852aa9a65914b6afc702f6bd94a6a831c2e5a1a7b6ee623b31c5e8aa53
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- radiator (0.3.15)
4
+ radiator (0.4.0pre1)
5
5
  awesome_print (~> 1.7, >= 1.7.0)
6
6
  bitcoin-ruby (~> 0.0, >= 0.0.11)
7
7
  ffi (~> 1.9, >= 1.9.18)
@@ -16,28 +16,28 @@ GEM
16
16
  addressable (2.5.2)
17
17
  public_suffix (>= 2.0.2, < 4.0)
18
18
  awesome_print (1.8.0)
19
- bitcoin-ruby (0.0.13)
19
+ bitcoin-ruby (0.0.17)
20
20
  connection_pool (2.2.1)
21
21
  crack (0.4.3)
22
22
  safe_yaml (~> 1.0.0)
23
23
  docile (1.1.5)
24
- ffi (1.9.18)
24
+ ffi (1.9.21)
25
25
  hashdiff (0.3.7)
26
- hashie (3.5.6)
26
+ hashie (3.5.7)
27
27
  json (2.1.0)
28
28
  little-plugger (1.1.4)
29
29
  logging (2.2.2)
30
30
  little-plugger (~> 1.1)
31
31
  multi_json (~> 1.10)
32
- minitest (5.10.3)
32
+ minitest (5.11.3)
33
33
  minitest-line (0.6.4)
34
34
  minitest (~> 5.0)
35
35
  minitest-proveit (1.0.0)
36
36
  minitest (> 5, < 7)
37
- multi_json (1.12.2)
37
+ multi_json (1.13.1)
38
38
  net-http-persistent (3.0.0)
39
39
  connection_pool (~> 2.2)
40
- public_suffix (3.0.1)
40
+ public_suffix (3.0.2)
41
41
  rake (12.3.0)
42
42
  safe_yaml (1.0.4)
43
43
  simplecov (0.15.1)
@@ -46,7 +46,7 @@ GEM
46
46
  simplecov-html (~> 0.10.0)
47
47
  simplecov-html (0.10.2)
48
48
  vcr (3.0.3)
49
- webmock (3.1.1)
49
+ webmock (3.3.0)
50
50
  addressable (>= 2.3.6)
51
51
  crack (>= 0.3.2)
52
52
  hashdiff
@@ -68,4 +68,4 @@ DEPENDENCIES
68
68
  yard (~> 0.9.9)
69
69
 
70
70
  BUNDLED WITH
71
- 1.16.0.pre.3
71
+ 1.16.1
data/README.md CHANGED
@@ -397,7 +397,7 @@ Radiator supports failover for situations where a node has, for example, become
397
397
 
398
398
  ```ruby
399
399
  options = {
400
- url: 'https://api.steemit.com',
400
+ ur: 'https://api.steemit.com',
401
401
  failover_urls: [
402
402
  'https://api.steemitstage.com',
403
403
  'https://gtg.steem.house:8090'
@@ -421,22 +421,6 @@ There is another rare scenario involving `::Transaction` broadcasts that's handl
421
421
  tx = Radiator::Transaction.new(wif: wif, recover_transactions_on_error: false)
422
422
  ```
423
423
 
424
- ### Golos Failover Examples
425
-
426
- Typically, you only need to pass `chain: :golos` to enable Golos. Failover is enabled by default. If you want to provide your own full nodes, use this format:
427
-
428
- ```ruby
429
- options = {
430
- chain: :golos,
431
- url: 'https://ws.golos.io',
432
- failover_urls: [
433
- 'https://api.golos.cf'
434
- ]
435
- }
436
-
437
- api = Radiator::Api.new(options)
438
- ```
439
-
440
424
  ## Debugging
441
425
 
442
426
  To enable debugging, set environment `LOG=DEBUG` before launching your app. E.g.:
@@ -501,7 +485,7 @@ Verify your code is not doing too much between blocks.
501
485
  <img src="http://www.steemimg.com/images/2016/08/19/RadiatorCoolingFan-54in-Webfdcb1.png" />
502
486
  </center>
503
487
 
504
- See my previous Ruby How To posts in: [/f/ruby](https://chainbb.com/f/ruby)
488
+ See my previous Ruby How To posts in: [#radiator](https://steemit.com/created/radiator) [#ruby](https://steemit.com/created/ruby)
505
489
 
506
490
  ## Get in touch!
507
491
 
data/Rakefile CHANGED
@@ -75,8 +75,17 @@ task :test_live_stream, [:chain, :persist] do |t, args|
75
75
  o = t.map(&:operations)
76
76
  op_size = o.map(&:size).reduce(0, :+)
77
77
  total_ops += op_size
78
- api.get_ops_in_block(n, true) do |vops|
79
- vop_size = vops.size
78
+ api.get_ops_in_block(n, true) do |vops, error|
79
+ if !!error
80
+ puts "Error on get_ops_in_block for block #{n}"
81
+ ap error
82
+ end
83
+
84
+ vop_size = if vops.nil?
85
+ 0
86
+ else
87
+ vops.size
88
+ end
80
89
  total_vops += vop_size
81
90
 
82
91
  vop_ratio = if total_vops > 0
data/lib/golos.rb CHANGED
@@ -5,4 +5,7 @@ class Golos < Radiator::Chain
5
5
  def initialize(options = {})
6
6
  super(options.merge(chain: :golos))
7
7
  end
8
+
9
+ alias golos_per_mgest base_per_mvest
10
+ alias golos_per_gbg base_per_debt
8
11
  end
data/lib/radiator/api.rb CHANGED
@@ -151,7 +151,8 @@ module Radiator
151
151
  DEFAULT_GOLOS_FAILOVER_URLS = [
152
152
  DEFAULT_GOLOS_URL,
153
153
  'https://api.golos.cf',
154
- # not recommended:
154
+ # not recommended, not all plug-ins enabled:
155
+ # 'https://ws.goldvoice.club',
155
156
  # 'http://golos-seed.arcange.eu',
156
157
  # not recommended, requires option ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE
157
158
  # 'https://golos-seed.arcange.eu',
@@ -245,13 +246,14 @@ module Radiator
245
246
 
246
247
  Hashie.logger = @hashie_logger
247
248
  @method_names = nil
249
+ @uri = nil
250
+ @http_id = nil
248
251
  @http_memo = {}
249
252
  @api_options = options.dup.merge(chain: @chain)
250
253
  @api = nil
251
254
  @block_api = nil
252
255
  @backoff_at = nil
253
-
254
- ObjectSpace.define_finalizer(self, self.class.finalize(@logger, @hashie_logger))
256
+ @jussi_supported = []
255
257
  end
256
258
 
257
259
  # Get a specific block or range of blocks.
@@ -287,87 +289,6 @@ module Radiator
287
289
  end
288
290
  end
289
291
 
290
- # Find a specific block.
291
- #
292
- # Example:
293
- #
294
- # api = Radiator::Api.new
295
- # block = api.find_block(12345678)
296
- # transactions = block.transactions
297
- #
298
- # ... or ...
299
- #
300
- # api = Radiator::Api.new
301
- # transactions = api.find_block(12345678) do |block|
302
- # block.transactions
303
- # end
304
- #
305
- # @param block_number [Fixnum]
306
- # @param block the block to execute for each result, optional.
307
- # @return [Hash]
308
- def find_block(block_number, &block)
309
- if !!block
310
- yield api.get_blocks(block_number).first
311
- else
312
- api.get_blocks(block_number).first
313
- end
314
- end
315
-
316
- # Find a specific account.
317
- #
318
- # Example:
319
- #
320
- # api = Radiator::Api.new
321
- # ned = api.find_account('ned')
322
- # vesting_shares = ned.vesting_shares
323
- #
324
- # ... or ...
325
- #
326
- # api = Radiator::Api.new
327
- # vesting_shares = api.find_account('ned') do |ned|
328
- # ned.vesting_shares
329
- # end
330
- #
331
- # @param id [String] Name of the account to find.
332
- # @param block the block to execute for each result, optional.
333
- # @return [Hash]
334
- def find_account(id, &block)
335
- if !!block
336
- yield api.get_accounts([id]).result.first
337
- else
338
- api.get_accounts([id]).result.first
339
- end
340
- end
341
-
342
- # Returns the current base (STEEM) price in the vest asset (VESTS).
343
- #
344
- def base_per_mvest
345
- api.get_dynamic_global_properties do |properties|
346
- total_vesting_fund_steem = properties.total_vesting_fund_steem.to_f
347
- total_vesting_shares_mvest = properties.total_vesting_shares.to_f / 1e6
348
-
349
- total_vesting_fund_steem / total_vesting_shares_mvest
350
- end
351
- end
352
-
353
- alias steem_per_mvest base_per_mvest
354
-
355
- # Returns the current base (STEEM) price in the debt asset (SBD).
356
- #
357
- def base_per_debt
358
- get_feed_history do |feed_history|
359
- current_median_history = feed_history.current_median_history
360
- base = current_median_history.base
361
- base = base.split(' ').first.to_f
362
- quote = current_median_history.quote
363
- quote = quote.split(' ').first.to_f
364
-
365
- (base / quote) * steem_per_mvest
366
- end
367
- end
368
-
369
- alias steem_per_usd base_per_debt
370
-
371
292
  # Stops the persistant http connections.
372
293
  #
373
294
  def shutdown
@@ -384,6 +305,18 @@ module Radiator
384
305
  @api = nil
385
306
  @block_api.shutdown if !!@block_api && @block_api != self
386
307
  @block_api = nil
308
+
309
+ if !!@logger && defined?(@logger.close)
310
+ if defined?(@logger.closed?)
311
+ @logger.close unless @logger.closed?
312
+ end
313
+ end
314
+
315
+ if !!@hashie_logger && defined?(@hashie_logger.close)
316
+ if defined?(@hashie_logger.closed?)
317
+ @hashie_logger.close unless @hashie_logger.closed?
318
+ end
319
+ end
387
320
  end
388
321
 
389
322
  # @private
@@ -412,12 +345,21 @@ module Radiator
412
345
  current_rpc_id = rpc_id
413
346
  method_name = [api_name, m].join('.')
414
347
  response = nil
415
- options = {
416
- jsonrpc: "2.0",
417
- params: [api_name, m, args],
418
- id: current_rpc_id,
419
- method: "call"
420
- }
348
+ options = if jussi_supported? && api_name == :database_api
349
+ {
350
+ jsonrpc: "2.0",
351
+ params: args,
352
+ id: current_rpc_id,
353
+ method: m
354
+ }
355
+ else
356
+ {
357
+ jsonrpc: "2.0",
358
+ params: [api_name, m, args],
359
+ id: current_rpc_id,
360
+ method: "call"
361
+ }
362
+ end
421
363
 
422
364
  tries = 0
423
365
  timestamp = Time.now.utc
@@ -425,10 +367,6 @@ module Radiator
425
367
  loop do
426
368
  tries += 1
427
369
 
428
- if tries > 5 && flappy? && !check_file_open?
429
- raise ApiError, 'PANIC: Out of file resources'
430
- end
431
-
432
370
  begin
433
371
  if tries > 1 && @recover_transactions_on_error && api_name == :network_broadcast_api
434
372
  signatures, exp = extract_signatures(options)
@@ -450,6 +388,8 @@ module Radiator
450
388
  elsif !response.kind_of? Net::HTTPSuccess
451
389
  warning "Unexpected response (code: #{response.code}): #{response.inspect}, retrying ...", method_name, true
452
390
  else
391
+ detect_jussi(response)
392
+
453
393
  case response.code
454
394
  when '200'
455
395
  body = response.body
@@ -475,12 +415,18 @@ module Radiator
475
415
  end
476
416
  rescue Net::HTTP::Persistent::Error => e
477
417
  warning "Unable to perform request: #{e} :: #{!!e.cause ? "cause: #{e.cause.message}" : ''}, retrying ...", method_name, true
418
+ rescue ConnectionPool::Error => e
419
+ warning "Connection Pool Error (#{e.message}), retrying ...", method_name, true
478
420
  rescue Errno::ECONNREFUSED => e
479
421
  warning 'Connection refused, retrying ...', method_name, true
480
422
  rescue Errno::EADDRNOTAVAIL => e
481
423
  warning 'Node not available, retrying ...', method_name, true
482
424
  rescue Errno::ECONNRESET => e
483
425
  warning "Connection Reset (#{e.message}), retrying ...", method_name, true
426
+ rescue Errno::EBUSY => e
427
+ warning "Resource busy (#{e.message}), retrying ...", method_name, true
428
+ rescue Errno::ENETDOWN => e
429
+ warning "Network down (#{e.message}), retrying ...", method_name, true
484
430
  rescue Net::ReadTimeout => e
485
431
  warning 'Node read timeout, retrying ...', method_name, true
486
432
  rescue Net::OpenTimeout => e
@@ -626,6 +572,21 @@ module Radiator
626
572
  end
627
573
  end
628
574
 
575
+ def jussi_supported?(url = @url)
576
+ @jussi_supported.include? url
577
+ end
578
+
579
+ def detect_jussi(response)
580
+ return if jussi_supported?(@url)
581
+
582
+ jussi_response_id = response['x-jussi-response-id']
583
+
584
+ if !!jussi_response_id
585
+ debug "Found a node that supports jussi: #{@url}"
586
+ @jussi_supported << @url
587
+ end
588
+ end
589
+
629
590
  def recover_transaction(signatures, expected_rpc_id, after)
630
591
  debug "Looking for signatures: #{signatures.map{|s| s[0..5]}} since: #{after}"
631
592
 
@@ -643,25 +604,21 @@ module Radiator
643
604
  # but we also give up once the block time is before the `after` argument.
644
605
 
645
606
  api.get_blocks(block_range) do |block, block_num|
646
- count += 1
647
- raise ApiError, "Race condition detected on remote node at: #{block_num}" if block.nil?
648
-
649
- # TODO Some blockchains (like Golos) do not have transaction_ids. In
650
- # the future, it would be better to decode the operation and signature
651
- # into the transaction id.
652
- # See: https://github.com/steemit/steem/issues/187
653
- # See: https://github.com/GolosChain/golos/issues/281
654
607
  unless defined? block.transaction_ids
655
- @recover_transactions_on_error = false
656
- return
608
+ # Happens on Golos, see: https://github.com/GolosChain/golos/issues/281
609
+ error "Blockchain does not provide transaction ids in blocks, giving up."
610
+ return nil
657
611
  end
658
612
 
613
+ count += 1
614
+ raise ApiError, "Race condition detected on remote node at: #{block_num}" if block.nil?
615
+
659
616
  timestamp = Time.parse(block.timestamp + 'Z')
660
617
  break if timestamp < after
661
618
 
662
619
  block.transactions.each_with_index do |tx, index|
663
620
  next unless ((tx['signatures'] || []) & signatures).any?
664
-
621
+
665
622
  debug "Found transaction #{count} block(s) ago; took #{(Time.now.utc - start)} seconds to scan."
666
623
 
667
624
  return {
@@ -783,12 +740,6 @@ module Radiator
783
740
  end
784
741
  end
785
742
 
786
- def check_file_open?
787
- File.exists?('.')
788
- rescue
789
- false
790
- end
791
-
792
743
  def backoff
793
744
  shutdown
794
745
  bump_failover if flappy? || !healthy?(uri)
@@ -803,17 +754,5 @@ module Radiator
803
754
  @backoff_sleep = nil
804
755
  end
805
756
  end
806
-
807
- def self.finalize(logger, hashie_logger)
808
- proc {
809
- if !!logger && defined?(logger.close) && !logger.closed?
810
- logger.close
811
- end
812
-
813
- if !!hashie_logger && defined?(hashie_logger.close) && !hashie_logger.closed?
814
- hashie_logger.close
815
- end
816
- }
817
- end
818
757
  end
819
758
  end