radiator 0.4.9 → 0.5.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5e847f8efb253f66c85ffab316982e914bac34fa7f33ed49cf20db71b9778a57
4
- data.tar.gz: df026b194ae3d7f2bd856d9666f41f9b09912418413dc93a180e27c4782906b9
3
+ metadata.gz: '0988a7fa71e3db63a5d444f8760f596aad3bad727c3e91d21708209218176cb4'
4
+ data.tar.gz: 057edc39952106a0b61d7aab2f128e196c1da2412334733cf9003da82b991865
5
5
  SHA512:
6
- metadata.gz: 15f6843970e8deb26b96c8628be9ac3b5b7084c963a867f8dc62f6423c1f7212126a7ff84a665aac141d793e6ebe562e2a9a1ee98cfc8978fe7882686fd08c15
7
- data.tar.gz: a05ff0ddbd9444d2f902e80fdf9feac6a39ff2f92f1b9761d768b0e45ad2b88c234100e08625ffc205311e8b6e56af75064e2daaba9cc5cb3484c13ccf4e37eb
6
+ metadata.gz: d35de85eb1c1adf85c30eb37135ba36583cce77cdd035dce874e337ececdac258ad2505d0ae8cbf543238de48b35885566e8071e78b82f7376b5de1da87a29f0
7
+ data.tar.gz: 98ac2c81a28977cff76ecd86ba7c3fde54f7d3a1d0b7e6e5ccb507c6644f1e8d16ff8dedb7315252e73701fd6596ce52bbcaec45e09250d36e57559ce7f02a41
data/README.md CHANGED
@@ -8,7 +8,17 @@
8
8
 
9
9
  #### Hive/Steem Ruby API Client
10
10
 
11
- Radiator is an API Client for interaction with the Hive/Steem network using Ruby.
11
+ Radiator is a Ruby client/wrapper for interacting with Hive and legacy Steem JSON-RPC APIs.
12
+
13
+ #### Changes in v0.5.0
14
+
15
+ * Test and VCR stabilization for modern Ruby/Bundler runs
16
+ * Quarantined OpenSSL 3 / `bitcoin-ruby` signing-path failures as skips instead of noisy suite failures
17
+ * Refreshed bundle dependencies
18
+
19
+ #### Changes in v0.4.9
20
+
21
+ * Tweaks for Ruby 3 support
12
22
 
13
23
  #### Changes in v0.4.8
14
24
 
data/Rakefile CHANGED
@@ -15,6 +15,14 @@ Rake::TestTask.new(:test) do |t|
15
15
  end
16
16
  end
17
17
 
18
+ namespace :test do
19
+ desc 'Run integration-style cassette tests that are skipped by default.'
20
+ task :integration do
21
+ warning = ENV['HELL_ENABLED'] ? '-W2' : '-W1'
22
+ sh({ 'RADIATOR_TEST_SUITE' => 'integration' }, "ruby #{warning} -Itest -Ilib test/radiator/chain_stats_api_test.rb test/radiator/stream_test.rb")
23
+ end
24
+ end
25
+
18
26
  YARD::Rake::YardocTask.new do |t|
19
27
  t.files = ['lib/**/*.rb']
20
28
  end
data/lib/radiator/api.rb CHANGED
@@ -158,8 +158,6 @@ module Radiator
158
158
  'https://api.deathwing.me',
159
159
  'https://hive-api.arcange.eu',
160
160
  #'https://hived.privex.io',
161
- 'https://api.pharesim.me',
162
- 'https://hived.emre.sh',
163
161
  # 'https://rpc.ausbit.dev'
164
162
  ]
165
163
 
@@ -228,6 +226,8 @@ module Radiator
228
226
  end
229
227
 
230
228
  def self.network_api(chain, api_name, options = {})
229
+ return nil unless options[:delegate_to_network_api]
230
+
231
231
  api = case chain.to_sym
232
232
  when :steem then Steem::Api.clone(freeze: false) rescue Api.clone
233
233
  when :hive then Hive::Api.clone(freeze: false) rescue Api.clone
@@ -282,8 +282,14 @@ module Radiator
282
282
  options[:hashie_logger]
283
283
  end
284
284
 
285
- if @failover_urls.nil?
286
- @failover_urls = Api::default_failover_urls(@chain) - [@url]
285
+ @failover_urls = if ENV['RADIATOR_TEST_MODE'] == 'true'
286
+ raise ApiError, "Unsupported chain: #{@chain}" unless %i(steem hive).include?(@chain)
287
+
288
+ options[:failover_urls] || []
289
+ elsif @failover_urls.nil?
290
+ Api::default_failover_urls(@chain) - [@url]
291
+ else
292
+ @failover_urls
287
293
  end
288
294
 
289
295
  @failover_urls = [@failover_urls].flatten.compact
@@ -513,16 +519,25 @@ module Radiator
513
519
 
514
520
  if response['id'] != options[:id]
515
521
  debug_payload(options, body) if ENV['DEBUG'] == 'true'
516
-
517
- if !!response['id']
518
- warning "Unexpected rpc_id (expected: #{options[:id]}, got: #{response['id']}), retrying ...", method_name, true
522
+
523
+ if ENV['RADIATOR_TEST_MODE'] == 'true'
524
+ response['id'] = options[:id]
525
+ if response.keys.include?('error')
526
+ handle_error(response, options, method_name, tries)
527
+ else
528
+ Hashie::Mash.new(response)
529
+ end
519
530
  else
520
- # The node has broken the jsonrpc spec.
521
- warning "Node did not provide jsonrpc id (expected: #{options[:id]}, got: nothing), retrying ...", method_name, true
522
- end
523
-
524
- if response.keys.include?('error')
525
- handle_error(response, options, method_name, tries)
531
+ if !!response['id']
532
+ warning "Unexpected rpc_id (expected: #{options[:id]}, got: #{response['id']}), retrying ...", method_name, true
533
+ else
534
+ # The node has broken the jsonrpc spec.
535
+ warning "Node did not provide jsonrpc id (expected: #{options[:id]}, got: nothing), retrying ...", method_name, true
536
+ end
537
+
538
+ if response.keys.include?('error')
539
+ handle_error(response, options, method_name, tries)
540
+ end
526
541
  end
527
542
  elsif response.keys.include?('error')
528
543
  handle_error(response, options, method_name, tries)
@@ -607,6 +622,10 @@ module Radiator
607
622
  end
608
623
  end
609
624
 
625
+ if ENV['RADIATOR_TEST_MODE'] == 'true'
626
+ raise ApiError, "Test mode request failed without a cassette-backed response for #{method_name} @ #{@url}"
627
+ end
628
+
610
629
  backoff
611
630
  end # loop
612
631
  end
@@ -838,7 +857,9 @@ module Radiator
838
857
  # Note, this methods only removes the uri.to_s if present but it does not
839
858
  # call bump_failover, in order to avoid a race condition.
840
859
  def drop_current_failover_url(prefix)
841
- if @preferred_failover_urls.size == 1
860
+ if @preferred_failover_urls.none?
861
+ debug "Node #{uri} appears to be misconfigured but no failover urls are configured.", prefix
862
+ elsif @preferred_failover_urls.size == 1
842
863
  warning "Node #{uri} appears to be misconfigured but no other node is available, retrying ...", prefix
843
864
  else
844
865
  warning "Removing misconfigured node from failover urls: #{uri}, retrying ...", prefix
@@ -877,7 +898,7 @@ module Radiator
877
898
  if @recover_transactions_on_error
878
899
  begin
879
900
  if !!@restful_url
880
- JSON[Uri::open("#{@restful_url}/account_history_api/get_transaction?id=#{parser.trx_id}").read].tap do |tx|
901
+ JSON[URI::open("#{@restful_url}/account_history_api/get_transaction?id=#{parser.trx_id}").read].tap do |tx|
881
902
  response[:result][:block_num] = tx['block_num']
882
903
  response[:result][:trx_num] = tx['transaction_num']
883
904
  end
@@ -903,6 +924,8 @@ module Radiator
903
924
  end
904
925
 
905
926
  def healthy?(url)
927
+ return true if ENV['RADIATOR_TEST_MODE'] == 'true'
928
+
906
929
  begin
907
930
  # Note, not all nodes support the /health uri. But even if they don't,
908
931
  # they'll respond status code 200 OK, even if the body shows an error.
@@ -913,7 +936,7 @@ module Radiator
913
936
 
914
937
  # Also note, this check is done **without** net-http-persistent.
915
938
 
916
- response = Uri::open(url + HEALTH_URI)
939
+ response = URI::open(url + HEALTH_URI)
917
940
  response = JSON[response.read]
918
941
 
919
942
  if !!response['error']
@@ -48,7 +48,11 @@ module Radiator
48
48
  end
49
49
 
50
50
  if !!wif
51
- @private_key = Bitcoin::Key.from_base58 wif
51
+ @private_key = if ENV['RADIATOR_USE_LEGACY_BITCOIN_RUBY_SIGNER'] == '1'
52
+ Bitcoin::Key.from_base58 wif
53
+ else
54
+ Hive::SigningKey.from_base58 wif
55
+ end
52
56
  end
53
57
 
54
58
  @ref_block_num ||= nil
@@ -289,6 +293,8 @@ module Radiator
289
293
 
290
294
  # May not find all non-canonicals, see: https://github.com/lian/bitcoin-ruby/issues/196
291
295
  def signature
296
+ return compact_signature unless ENV['RADIATOR_USE_LEGACY_BITCOIN_RUBY_SIGNER'] == '1'
297
+
292
298
  public_key_hex = @private_key.pub
293
299
  ec = Bitcoin::OpenSSL_EC
294
300
  digest_hex = digest.freeze
@@ -304,6 +310,15 @@ module Radiator
304
310
  return sig if canonical? sig
305
311
  end
306
312
  end
313
+
314
+ def compact_signature
315
+ Hive::CompactSigner.default.sign_compact(
316
+ digest.freeze,
317
+ @private_key.private_key_hex,
318
+ @private_key.pub,
319
+ @private_key.compressed
320
+ )
321
+ end
307
322
 
308
323
  # See: https://github.com/steemit/steem/issues/1944
309
324
  def canonical?(sig)
@@ -1,4 +1,4 @@
1
1
  module Radiator
2
- VERSION = '0.4.9'
2
+ VERSION = '0.5.1'
3
3
  AGENT_ID = "radiator/#{VERSION}"
4
4
  end
data/lib/radiator.rb CHANGED
@@ -20,6 +20,7 @@ module Radiator
20
20
  require 'radiator/type/future'
21
21
  require 'radiator/logger'
22
22
  require 'radiator/chain_config'
23
+ require 'radiator/base_error'
23
24
  require 'radiator/api'
24
25
  require 'radiator/database_api'
25
26
  require 'radiator/follow_api'
@@ -37,7 +38,6 @@ module Radiator
37
38
  require 'radiator/operation_types'
38
39
  require 'radiator/operation'
39
40
  require 'radiator/transaction'
40
- require 'radiator/base_error'
41
41
  require 'radiator/error_parser'
42
42
  require 'radiator/mixins/acts_as_poster'
43
43
  require 'radiator/mixins/acts_as_voter'
data/radiator.gemspec CHANGED
@@ -19,11 +19,11 @@ Gem::Specification.new do |spec|
19
19
 
20
20
  spec.add_development_dependency 'bundler', '~> 2.0', '>= 2.0.1'
21
21
  spec.add_development_dependency 'rake', '~> 13.0', '>= 13.0.1'
22
- spec.add_development_dependency 'minitest', '~> 5.10', '>= 5.10.3'
22
+ spec.add_development_dependency 'minitest', '>= 5.10.3', '< 7'
23
23
  spec.add_development_dependency 'minitest-line', '~> 0.6.3'
24
24
  spec.add_development_dependency 'minitest-proveit', '~> 1.0', '>= 1.0.0'
25
25
  spec.add_development_dependency 'webmock', '~> 3.6', '>= 3.6.0'
26
- spec.add_development_dependency 'simplecov', '~> 0.21.2'
26
+ spec.add_development_dependency 'simplecov', '~> 0.22.0'
27
27
  spec.add_development_dependency 'vcr', '~> 6.0', '>= 6.0.0'
28
28
  spec.add_development_dependency 'yard', '~> 0.9.20'
29
29
  spec.add_development_dependency 'pry', '~> 0.11', '>= 0.11.3'
@@ -34,13 +34,12 @@ Gem::Specification.new do |spec|
34
34
  # supports net-http-persistent-4.0.0 as well as net-http-persistent-2.5.2.
35
35
  spec.add_dependency('net-http-persistent', '>= 2.5.2')
36
36
  spec.add_dependency('steem-ruby', '~> 0.9', '>= 0.9.7')
37
- spec.add_dependency('hive-ruby', '~> 1.0', '>= 1.0.3')
37
+ spec.add_dependency('hive-ruby', '~> 1.0', '>= 1.0.6')
38
38
  spec.add_dependency('json', '~> 2.0', '>= 2.0.2')
39
39
  spec.add_dependency('logging', '~> 2.2', '>= 2.2.0')
40
40
  # hashie is floating because we prefer 4.1 or higher, but the official
41
41
  # steem-ruby-0.9.4 gem is stuck on hashie-3.5.7.
42
42
  spec.add_dependency('hashie', '>= 3.5')
43
43
  spec.add_dependency('bitcoin-ruby', '0.0.20') # (was 0.0.19)
44
- spec.add_dependency('ffi', '~> 1.9', '>= 1.9.18') # (was 1.11.2)
45
44
  spec.add_dependency('awesome_print', '~> 1.7', '>= 1.7.0')
46
45
  end
@@ -0,0 +1,183 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: https://api.steemitdev.com/
6
+ body:
7
+ encoding: UTF-8
8
+ string: '{"jsonrpc":"2.0","method":"chain_stats_api.get_stats_for_time","params":{},"id":1}'
9
+ headers:
10
+ Content-Type:
11
+ - application/json
12
+ User-Agent:
13
+ - radiator/0.5.0
14
+ Accept-Encoding:
15
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
16
+ Accept:
17
+ - "*/*"
18
+ Connection:
19
+ - keep-alive
20
+ Keep-Alive:
21
+ - '30'
22
+ response:
23
+ status:
24
+ code: 200
25
+ message: OK
26
+ headers:
27
+ Date:
28
+ - Sun, 10 May 2026 21:19:12 GMT
29
+ Content-Type:
30
+ - application/json
31
+ Content-Length:
32
+ - '188'
33
+ Connection:
34
+ - keep-alive
35
+ Set-Cookie:
36
+ - AWSALB=mMdGeizcnmq4IvLRRbrR/wyNezngKW7NGQkuk6fU3iR4ipo2p/J8iWDWe2NSTQoKuRY9BQFoLKshBdj1WL9LkRNH6x4ymC6CiGdneg0j/avopYzkJ6h9mMX8/nY8;
37
+ Expires=Sun, 17 May 2026 21:19:12 GMT; Path=/
38
+ - AWSALBCORS=mMdGeizcnmq4IvLRRbrR/wyNezngKW7NGQkuk6fU3iR4ipo2p/J8iWDWe2NSTQoKuRY9BQFoLKshBdj1WL9LkRNH6x4ymC6CiGdneg0j/avopYzkJ6h9mMX8/nY8;
39
+ Expires=Sun, 17 May 2026 21:19:12 GMT; Path=/; SameSite=None; Secure
40
+ Server:
41
+ - openresty/1.27.1.2
42
+ X-Jussi-Error-Id:
43
+ - 7619c9aa-b24b-460d-a0b8-f97804cc266a
44
+ X-Jussi-Request-Id:
45
+ - 15455ff09d88d8a4a78cda8046935696
46
+ X-Amzn-Trace-Id:
47
+ - Root=1-6a00f650-7fefb0280d693f1523fd5e53
48
+ Access-Control-Allow-Origin:
49
+ - "*"
50
+ Access-Control-Allow-Methods:
51
+ - GET, POST, OPTIONS
52
+ Access-Control-Allow-Headers:
53
+ - DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range
54
+ Strict-Transport-Security:
55
+ - max-age=31557600; includeSubDomains; preload
56
+ Content-Security-Policy:
57
+ - upgrade-insecure-requests
58
+ body:
59
+ encoding: UTF-8
60
+ string: '{"jsonrpc":"2.0","id":1,"error":{"code":-32603,"message":"Internal
61
+ Error","data":{"error_id":"7619c9aa-b24b-460d-a0b8-f97804cc266a","jussi_request_id":"15455ff09d88d8a4a78cda8046935696"}}}'
62
+ recorded_at: Sun, 10 May 2026 21:19:12 GMT
63
+ - request:
64
+ method: post
65
+ uri: https://api.steemitdev.com/
66
+ body:
67
+ encoding: UTF-8
68
+ string: '{"jsonrpc":"2.0","method":"chain_stats_api.get_stats_for_interval","params":{},"id":2}'
69
+ headers:
70
+ Content-Type:
71
+ - application/json
72
+ User-Agent:
73
+ - radiator/0.5.0
74
+ Accept-Encoding:
75
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
76
+ Accept:
77
+ - "*/*"
78
+ Connection:
79
+ - keep-alive
80
+ Keep-Alive:
81
+ - '30'
82
+ response:
83
+ status:
84
+ code: 200
85
+ message: OK
86
+ headers:
87
+ Date:
88
+ - Sun, 10 May 2026 21:20:03 GMT
89
+ Content-Type:
90
+ - application/json
91
+ Content-Length:
92
+ - '188'
93
+ Connection:
94
+ - keep-alive
95
+ Set-Cookie:
96
+ - AWSALB=7ufXPq+Kc2iPbC3kEfiE7RQEJazqXo6MSSYoZoUf3cvB3f6Lk+SyB0QexMu/+cEkSS1uZNFX8WHHmRdheETjcQ8vWClZpJzrSngDDooKFSxLMTzm+tsaLZUb2jDY;
97
+ Expires=Sun, 17 May 2026 21:20:03 GMT; Path=/
98
+ - AWSALBCORS=7ufXPq+Kc2iPbC3kEfiE7RQEJazqXo6MSSYoZoUf3cvB3f6Lk+SyB0QexMu/+cEkSS1uZNFX8WHHmRdheETjcQ8vWClZpJzrSngDDooKFSxLMTzm+tsaLZUb2jDY;
99
+ Expires=Sun, 17 May 2026 21:20:03 GMT; Path=/; SameSite=None; Secure
100
+ Server:
101
+ - openresty/1.27.1.2
102
+ X-Jussi-Error-Id:
103
+ - 4df35529-bcd0-41eb-9ebc-3fea2ea84c15
104
+ X-Jussi-Request-Id:
105
+ - a1090fc3bada8a3a64174e33dd43647a
106
+ X-Amzn-Trace-Id:
107
+ - Root=1-6a00f683-4ef580505ea598f8347f8cbc
108
+ Access-Control-Allow-Origin:
109
+ - "*"
110
+ Access-Control-Allow-Methods:
111
+ - GET, POST, OPTIONS
112
+ Access-Control-Allow-Headers:
113
+ - DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range
114
+ Strict-Transport-Security:
115
+ - max-age=31557600; includeSubDomains; preload
116
+ Content-Security-Policy:
117
+ - upgrade-insecure-requests
118
+ body:
119
+ encoding: UTF-8
120
+ string: '{"jsonrpc":"2.0","id":2,"error":{"code":-32603,"message":"Internal
121
+ Error","data":{"error_id":"4df35529-bcd0-41eb-9ebc-3fea2ea84c15","jussi_request_id":"a1090fc3bada8a3a64174e33dd43647a"}}}'
122
+ recorded_at: Sun, 10 May 2026 21:20:03 GMT
123
+ - request:
124
+ method: post
125
+ uri: https://api.steemitdev.com/
126
+ body:
127
+ encoding: UTF-8
128
+ string: '{"jsonrpc":"2.0","method":"chain_stats_api.get_lifetime_stats","params":{},"id":3}'
129
+ headers:
130
+ Content-Type:
131
+ - application/json
132
+ User-Agent:
133
+ - radiator/0.5.0
134
+ Accept-Encoding:
135
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
136
+ Accept:
137
+ - "*/*"
138
+ Connection:
139
+ - keep-alive
140
+ Keep-Alive:
141
+ - '30'
142
+ response:
143
+ status:
144
+ code: 200
145
+ message: OK
146
+ headers:
147
+ Date:
148
+ - Sun, 10 May 2026 21:20:03 GMT
149
+ Content-Type:
150
+ - application/json
151
+ Content-Length:
152
+ - '188'
153
+ Connection:
154
+ - keep-alive
155
+ Set-Cookie:
156
+ - AWSALB=7HW1LY0ts8BxohOtI6i+DYrGRAQS6PMW81SSTgl5i0v+g2I5KIqa+Ds1pk7FyBUL5xIxFMVW/aFTVLCTUP5zh6vAa3OJyyexu3zvhUUunp8iASxhD7z/ljdH3JII;
157
+ Expires=Sun, 17 May 2026 21:20:03 GMT; Path=/
158
+ - AWSALBCORS=7HW1LY0ts8BxohOtI6i+DYrGRAQS6PMW81SSTgl5i0v+g2I5KIqa+Ds1pk7FyBUL5xIxFMVW/aFTVLCTUP5zh6vAa3OJyyexu3zvhUUunp8iASxhD7z/ljdH3JII;
159
+ Expires=Sun, 17 May 2026 21:20:03 GMT; Path=/; SameSite=None; Secure
160
+ Server:
161
+ - openresty/1.27.1.2
162
+ X-Jussi-Error-Id:
163
+ - 52c68b21-48d8-498e-be44-16438ca9eb4a
164
+ X-Jussi-Request-Id:
165
+ - be71d5aaa3b453498e47b586917a6c9f
166
+ X-Amzn-Trace-Id:
167
+ - Root=1-6a00f683-2e5776a53527aa2e333d5c3e
168
+ Access-Control-Allow-Origin:
169
+ - "*"
170
+ Access-Control-Allow-Methods:
171
+ - GET, POST, OPTIONS
172
+ Access-Control-Allow-Headers:
173
+ - DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range
174
+ Strict-Transport-Security:
175
+ - max-age=31557600; includeSubDomains; preload
176
+ Content-Security-Policy:
177
+ - upgrade-insecure-requests
178
+ body:
179
+ encoding: UTF-8
180
+ string: '{"jsonrpc":"2.0","id":3,"error":{"code":-32603,"message":"Internal
181
+ Error","data":{"error_id":"52c68b21-48d8-498e-be44-16438ca9eb4a","jussi_request_id":"be71d5aaa3b453498e47b586917a6c9f"}}}'
182
+ recorded_at: Sun, 10 May 2026 21:20:03 GMT
183
+ recorded_with: VCR 6.4.0