sibit 0.19.3 → 0.20.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1954a732f204708506dbbba992e87c8e1e49f111cbfb822d493214e031b06ee2
4
- data.tar.gz: 6cd88b88f880045ce63597644280d6d27df2ee0249189c13abdbcdda8ed00203
3
+ metadata.gz: a10cbcbf86d4a0c612ebba219e7e5d0a09480444280a106fd47bb41cbadd0405
4
+ data.tar.gz: 5c3ede973fe824a8f247099c6980b938dc83b07481553bf7925678837553d4ad
5
5
  SHA512:
6
- metadata.gz: 6d301e854ae0915e62bd6d9903f7ed2e5ef37b6e68f1a7b94d813ca9c5d4c0f0f8a590019a3cdc8f15b7aeb6ffa9eeb391e5da17af8e1518be22bf2c3cdde68a
7
- data.tar.gz: 9772fc2ec4c8f445bad36b6c7403ed97dff4a050b79609bf8cefc083c69358b319e4cc5a6c8020e51aae739177fa931b3a83e14d3ae0b3ebec75d3037c7c3b3f
6
+ metadata.gz: 4bd040eb2e985bd9af773e4bcda1108939cecbcea6b4719f3779eba70a3ce3d2bd69c1deb5c8a748eaaeee85f98fcc6ac5f447189ef635befbd75d68abde6aff
7
+ data.tar.gz: ee1ba5bc4c7bd03d0f975a38c0d2f5d315804eb3444dad26b93511fed19ce3092420907d0a338d4d871dc1abc7fd9307bc3d9f4f7a97a46a6a5824be52c13c62
data/bin/sibit CHANGED
@@ -29,9 +29,12 @@ require 'retriable_proxy'
29
29
  require_relative '../lib/sibit'
30
30
  require_relative '../lib/sibit/version'
31
31
  require_relative '../lib/sibit/blockchain'
32
+ require_relative '../lib/sibit/blockchair'
32
33
  require_relative '../lib/sibit/btc'
33
34
  require_relative '../lib/sibit/bitcoinchain'
35
+ require_relative '../lib/sibit/cex'
34
36
  require_relative '../lib/sibit/earn'
37
+ require_relative '../lib/sibit/fake'
35
38
  require_relative '../lib/sibit/firstof'
36
39
 
37
40
  begin
@@ -62,7 +65,7 @@ Options are:"
62
65
  o.array(
63
66
  '--api',
64
67
  'Ordered List of APIs to use, e.g. "earn,blockchain,btc,bitcoinchain"',
65
- default: %w[earn blockchain btc bitcoinchain]
68
+ default: %w[earn blockchain btc bitcoinchain blockchair cex]
66
69
  )
67
70
  end
68
71
  rescue Slop::Error => ex
@@ -79,6 +82,12 @@ Options are:"
79
82
  api = Sibit::Btc.new(http: http, log: log, dry: opts[:dry])
80
83
  elsif a == 'bitcoinchain'
81
84
  api = Sibit::Bitcoinchain.new(http: http, log: log, dry: opts[:dry])
85
+ elsif a == 'blockchair'
86
+ api = Sibit::Blockchair.new(http: http, log: log, dry: opts[:dry])
87
+ elsif a == 'cex'
88
+ api = Sibit::Cex.new(http: http, log: log, dry: opts[:dry])
89
+ elsif a == 'fake'
90
+ api = Sibit::Fake.new
82
91
  elsif a == 'earn'
83
92
  api = Sibit::Earn.new(http: http, log: log, dry: opts[:dry])
84
93
  else
@@ -87,7 +96,7 @@ Options are:"
87
96
  api = RetriableProxy.for_object(api, on: Sibit::Error) if opts[:attempts] > 1
88
97
  api
89
98
  end
90
- sibit = Sibit.new(log: log, api: Sibit::FirstOf.new(apis, log: log))
99
+ sibit = Sibit.new(log: log, api: Sibit::FirstOf.new(apis, log: log, verbose: true))
91
100
  case opts.arguments[0]
92
101
  when 'price'
93
102
  puts sibit.price
@@ -31,5 +31,5 @@ Feature: Command Line Processing
31
31
  Then Exit code is zero
32
32
 
33
33
  Scenario: Bitcoin fees can be printed
34
- When I run bin/sibit with "fees --verbose"
34
+ When I run bin/sibit with "fees --verbose --api=fake"
35
35
  Then Exit code is zero
@@ -32,9 +32,10 @@ class Sibit
32
32
  # Best of API.
33
33
  class BestOf
34
34
  # Constructor.
35
- def initialize(list, log: Sibit::Log.new)
35
+ def initialize(list, log: Sibit::Log.new, verbose: false)
36
36
  @list = list
37
37
  @log = log
38
+ @verbose = verbose
38
39
  end
39
40
 
40
41
  # Current price of BTC in USD (float returned).
@@ -106,7 +107,7 @@ class Sibit
106
107
  begin
107
108
  results << yield(api)
108
109
  rescue Sibit::Error => e
109
- @log.info("The API #{api.class.name} failed at #{method}(): #{e.message}")
110
+ @log.info("The API #{api.class.name} failed at #{method}(): #{e.message}") if @verbose
110
111
  end
111
112
  end
112
113
  if results.empty?
@@ -64,6 +64,10 @@ class Sibit
64
64
  return 0
65
65
  end
66
66
  txns = data['list']
67
+ if txns.nil?
68
+ @log.info("The balance of #{address} is probably zero (not found)")
69
+ return 0
70
+ end
67
71
  balance = txns.map { |tx| tx['value'] }.inject(&:+) || 0
68
72
  @log.info("The balance of #{address} is #{balance}, total txns: #{txns.count}")
69
73
  balance
@@ -91,6 +95,7 @@ class Sibit
91
95
  data = json['data']
92
96
  raise Sibit::Error, "The block #{hash} not found" if data.nil?
93
97
  h = data['height']
98
+ raise Sibit::Error, "The block #{hash} found but the height is absent" if h.nil?
94
99
  @log.info("The height of #{hash} is #{h}")
95
100
  h
96
101
  end
@@ -120,7 +125,9 @@ class Sibit
120
125
  )
121
126
  data = json['data']
122
127
  raise Sibit::Error, "The address #{hash} not found" if data.nil?
123
- data['list'].each do |u|
128
+ txns = data['list']
129
+ next if txns.nil?
130
+ txns.each do |u|
124
131
  outs = Sibit::Json.new(http: @http, log: @log).get(
125
132
  URI("https://chain.api.btc.com/v3/tx/#{u['tx_hash']}?verbose=3")
126
133
  )['data']['outputs']
@@ -169,9 +176,13 @@ class Sibit
169
176
  psize = 50
170
177
  all = []
171
178
  loop do
172
- txns = Sibit::Json.new(http: @http, log: @log).get(
179
+ data = Sibit::Json.new(http: @http, log: @log).get(
173
180
  URI("https://chain.api.btc.com/v3/block/#{hash}/tx?page=#{page}&pagesize=#{psize}")
174
- )['data']['list'].map do |t|
181
+ )['data']
182
+ raise Sibit::Error, "The block #{hash} has no data at page #{page}" if data.nil?
183
+ list = data['list']
184
+ raise Sibit::Error, "The list is empty for block #{hash} at page #{page}" if list.nil?
185
+ txns = list.map do |t|
175
186
  {
176
187
  hash: t['hash'],
177
188
  outputs: t['outputs'].reject { |o| o['spent_by_tx'] }.map do |o|
@@ -32,9 +32,10 @@ class Sibit
32
32
  # First of API.
33
33
  class FirstOf
34
34
  # Constructor.
35
- def initialize(list, log: Sibit::Log.new)
35
+ def initialize(list, log: Sibit::Log.new, verbose: false)
36
36
  @list = list
37
37
  @log = log
38
+ @verbose = verbose
38
39
  end
39
40
 
40
41
  # Current price of BTC in USD (float returned).
@@ -104,12 +105,13 @@ class Sibit
104
105
  done = false
105
106
  result = nil
106
107
  @list.each do |api|
108
+ @log.info("Calling #{api.class.name}##{method}()...")
107
109
  begin
108
110
  result = yield api
109
111
  done = true
110
112
  break
111
113
  rescue Sibit::Error => e
112
- @log.info("The API #{api.class.name} failed at #{method}(): #{e.message}")
114
+ @log.info("The API #{api.class.name} failed at #{method}(): #{e.message}") if @verbose
113
115
  end
114
116
  end
115
117
  unless done
@@ -33,7 +33,7 @@ class Sibit
33
33
  def client(uri)
34
34
  http = Net::HTTP.new(uri.host, uri.port)
35
35
  http.use_ssl = true
36
- http.read_timeout = 120
36
+ http.read_timeout = 240
37
37
  http
38
38
  end
39
39
  end
@@ -47,7 +47,7 @@ class Sibit
47
47
  def client(uri)
48
48
  http = Net::HTTP.new(uri.host, uri.port, @host, @port.to_i)
49
49
  http.use_ssl = true
50
- http.read_timeout = 120
50
+ http.read_timeout = 240
51
51
  http
52
52
  end
53
53
  end
@@ -62,7 +62,7 @@ class Sibit
62
62
  unless accept.include?(res.code.to_i)
63
63
  raise Sibit::Error, "Failed to retrieve #{uri} (#{res.code}): #{res.body}"
64
64
  end
65
- @log.info("GET #{uri}: #{res.code}/#{res.body.length}b in #{age(start)}")
65
+ @log.info("GET #{uri}: #{res.code}/#{length(res.body.length)} in #{age(start)}")
66
66
  JSON.parse(res.body)
67
67
  end
68
68
 
@@ -91,6 +91,16 @@ class Sibit
91
91
  "#{((Time.now - start) * 1000).round}ms"
92
92
  end
93
93
 
94
+ def length(bytes)
95
+ if bytes > 1024 * 1024
96
+ "#{bytes / (1024 * 1024)}mb"
97
+ elsif bytes > 1024
98
+ "#{bytes / 1024}kb"
99
+ else
100
+ "#{bytes}b"
101
+ end
102
+ end
103
+
94
104
  def user_agent
95
105
  "Anonymous/#{Sibit::VERSION}"
96
106
  end
@@ -26,5 +26,5 @@
26
26
  # License:: MIT
27
27
  class Sibit
28
28
  # Current version of the library.
29
- VERSION = '0.19.3'
29
+ VERSION = '0.20.3'
30
30
  end
@@ -55,7 +55,7 @@ and Ruby 2.3+.'
55
55
  s.add_runtime_dependency 'retriable_proxy', '1.0.2'
56
56
  s.add_runtime_dependency 'slop', '~> 4.6'
57
57
  s.add_development_dependency 'aruba', '~> 0.14.1'
58
- s.add_development_dependency 'codecov', '0.1.10'
58
+ s.add_development_dependency 'codecov', '0.2.8'
59
59
  s.add_development_dependency 'cucumber', '~> 1.3.17'
60
60
  s.add_development_dependency 'debase', '0.2.2'
61
61
  s.add_development_dependency 'minitest', '5.5.0'
@@ -42,6 +42,17 @@ class TestBtc < Minitest::Test
42
42
  assert_equal(0, balance)
43
43
  end
44
44
 
45
+ def test_get_zero_balance_no_txns
46
+ stub_request(
47
+ :get,
48
+ 'https://chain.api.btc.com/v3/address/1MZT1fa6y8H9UmbZV6HqKF4UY41o9MGT5f/unspent'
49
+ ).to_return(body: '{"data":{}}')
50
+ sibit = Sibit::Btc.new
51
+ balance = sibit.balance('1MZT1fa6y8H9UmbZV6HqKF4UY41o9MGT5f')
52
+ assert(balance.is_a?(Integer))
53
+ assert_equal(0, balance)
54
+ end
55
+
45
56
  def test_get_broken_balance
46
57
  stub_request(
47
58
  :get,
@@ -75,6 +86,18 @@ class TestBtc < Minitest::Test
75
86
  assert_equal(123, balance)
76
87
  end
77
88
 
89
+ def test_fetch_block_broken
90
+ hash = '000000000000000007341915521967247f1dec17b3a311b8a8f4495392f1439b'
91
+ stub_request(:get, "https://chain.api.btc.com/v3/block/#{hash}")
92
+ .to_return(body: '{"data": {"next_block_hash": "n", "hash": "h", "prev_block_hash": "p"}}')
93
+ stub_request(:get, "https://chain.api.btc.com/v3/block/#{hash}/tx?page=1&pagesize=50")
94
+ .to_return(body: '{}')
95
+ sibit = Sibit::Btc.new
96
+ assert_raises Sibit::Error do
97
+ sibit.block(hash)
98
+ end
99
+ end
100
+
78
101
  def test_fetch_block
79
102
  hash = '000000000000000007341915521967247f1dec17b3a311b8a8f4495392f1439b'
80
103
  stub_request(:get, "https://chain.api.btc.com/v3/block/#{hash}")
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sibit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.19.3
4
+ version: 0.20.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-07-09 00:00:00.000000000 Z
11
+ date: 2020-09-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: backtrace
@@ -114,14 +114,14 @@ dependencies:
114
114
  requirements:
115
115
  - - '='
116
116
  - !ruby/object:Gem::Version
117
- version: 0.1.10
117
+ version: 0.2.8
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
122
  - - '='
123
123
  - !ruby/object:Gem::Version
124
- version: 0.1.10
124
+ version: 0.2.8
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: cucumber
127
127
  requirement: !ruby/object:Gem::Requirement