sibit 0.30.1 → 0.30.2

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: 1dd376cf7257a4cf89035007b18896c215315cacacf9f5d228afc27c9f279cb3
4
- data.tar.gz: a610165efa18b499479a81816086e8ddad79399ee6d2e0d780594f5b38c18e91
3
+ metadata.gz: 7463ec26890a5bd8515ce96c92190a50edaf46f5b94aed0a1b54261f0d63ca65
4
+ data.tar.gz: 71be0a78c7bfcfffdebc6daa2c63a570d561b5e6e923f0d600e2791c2856cac5
5
5
  SHA512:
6
- metadata.gz: 588b35b318760b910ba00f2ed13af88ba325f59e21191faab27d7596771d54c9f4e5a6d419d80e6a3e6f4594a1089bfaf58ef107ccf7e78f738aa9258c181a19
7
- data.tar.gz: b347020232596daa847f6b3398f9cdaa7ad56ea6b03cf157377a8652922d93e7df33c18d639f1ee6bd324254fd453e24fb2992a8cea76ec00b3814ecc6081ae6
6
+ metadata.gz: ae0606a033a0506be0d3f397a0ac81bf51db53e7c35671256642764e2dcca358d95cbb9517c67c0a49f0621110926760154ea1c1c885d4aa5b6a2a32792078ff
7
+ data.tar.gz: 21a0bf5f5e27f3c22ceb82f2432d3b3fdd8a4ae1181cbdad383d34f081024c4802b6c83c2a7f51c1205728ccede22c8e45c8498f2d74ffd04282f828b29b4c54
data/Gemfile.lock CHANGED
@@ -4,10 +4,11 @@ PATH
4
4
  sibit (0.0.0)
5
5
  backtrace (~> 0.3)
6
6
  decoor (~> 0.1)
7
+ elapsed (~> 0.2)
7
8
  iri (~> 0.5)
8
- json (~> 2)
9
+ json (~> 2.18)
9
10
  loog (~> 0.6)
10
- openssl (>= 2.0)
11
+ openssl (~> 3.0)
11
12
  retriable_proxy (~> 1.0)
12
13
  slop (~> 4.6)
13
14
 
@@ -89,7 +90,7 @@ GEM
89
90
  racc (~> 1.4)
90
91
  nokogiri (1.18.10-x86_64-linux-gnu)
91
92
  racc (~> 1.4)
92
- openssl (4.0.0)
93
+ openssl (3.3.2)
93
94
  os (1.1.4)
94
95
  parallel (1.27.0)
95
96
  parser (3.3.10.0)
data/bin/sibit CHANGED
@@ -23,6 +23,8 @@ require_relative '../lib/sibit/fake'
23
23
  require_relative '../lib/sibit/firstof'
24
24
  require_relative '../lib/sibit/version'
25
25
 
26
+ log = Loog::REGULAR
27
+
26
28
  opts =
27
29
  begin
28
30
  Slop.parse(ARGV, strict: true, help: true) do |o|
@@ -44,7 +46,7 @@ Options are:"
44
46
  )
45
47
  o.bool '--dry', 'Don\'t send a real payment, run in a read-only mode'
46
48
  o.bool '--help', 'Read this: https://github.com/yegor256/sibit' do
47
- puts o
49
+ log.info(o)
48
50
  exit
49
51
  end
50
52
  o.bool '--verbose', 'Print all possible debug messages'
@@ -66,7 +68,7 @@ Options are:"
66
68
  raise 'Try --help' if opts.arguments.empty?
67
69
 
68
70
  begin
69
- log = opts[:verbose] ? Loog::VERBOSE : Loog::NULL
71
+ log = Loog::VERBOSE if opts[:verbose]
70
72
  http = opts[:proxy] ? Sibit::HttpProxy.new(opts[:proxy]) : Sibit::Http.new
71
73
  apis = opts[:api].map(&:downcase).map do |a|
72
74
  case a
@@ -92,7 +94,7 @@ begin
92
94
  sibit = Sibit.new(log: log, api: api)
93
95
  case opts.arguments[0]
94
96
  when 'price'
95
- puts sibit.price
97
+ log.info(sibit.price)
96
98
  when 'fees'
97
99
  fees = sibit.fees
98
100
  text = %i[S M L XL].map do |m|
@@ -100,19 +102,19 @@ begin
100
102
  usd = sat * sibit.price / 100_000_000
101
103
  "#{m}: #{sat}sat / $#{format('%<usd>.02f', usd: usd)}"
102
104
  end.join("\n")
103
- puts text
105
+ log.info(text)
104
106
  when 'latest'
105
- puts sibit.latest
107
+ log.info(sibit.latest)
106
108
  when 'generate'
107
- puts sibit.generate
109
+ log.info(sibit.generate)
108
110
  when 'create'
109
111
  pvt = opts.arguments[1]
110
112
  raise 'Private key argument is required' if pvt.nil?
111
- puts sibit.create(pvt)
113
+ log.info(sibit.create(pvt))
112
114
  when 'balance'
113
115
  address = opts.arguments[1]
114
116
  raise 'Address argument is required' if address.nil?
115
- puts sibit.balance(address)
117
+ log.info(sibit.balance(address))
116
118
  when 'pay'
117
119
  amount = opts.arguments[1]
118
120
  raise 'Amount argument is required' if amount.nil?
@@ -126,20 +128,22 @@ begin
126
128
  raise 'Target argument is required' if target.nil?
127
129
  change = opts.arguments[5]
128
130
  raise 'Change argument is required' if change.nil?
129
- puts sibit.pay(
130
- amount, fee,
131
- sources.split(','),
132
- target, change,
133
- skip_utxo: opts['skip-utxo']
131
+ log.info(
132
+ sibit.pay(
133
+ amount, fee,
134
+ sources.split(','),
135
+ target, change,
136
+ skip_utxo: opts['skip-utxo']
137
+ )
134
138
  )
135
139
  else
136
140
  raise "Command #{opts.arguments[0]} is not supported"
137
141
  end
138
142
  rescue StandardError => e
139
143
  if opts[:verbose]
140
- puts Backtrace.new(e)
144
+ log.error(Backtrace.new(e))
141
145
  else
142
- puts "ERROR: #{e.message}"
146
+ log.error(e.message)
143
147
  end
144
148
  exit(255)
145
149
  end
data/lib/sibit/bestof.rb CHANGED
@@ -92,10 +92,10 @@ class Sibit::BestOf
92
92
  # Just ignore it
93
93
  rescue Sibit::Error => e
94
94
  errors << e
95
- @log.info("The API #{api.class.name} failed at #{method}(): #{e.message}") if @verbose
95
+ @log.debug("The API #{api.class.name} failed at #{method}(): #{e.message}") if @verbose
96
96
  end
97
97
  if results.empty?
98
- errors.each { |e| @log.info(Backtrace.new(e).to_s) }
98
+ errors.each { |e| @log.debug(Backtrace.new(e).to_s) }
99
99
  raise Sibit::Error, "No APIs out of #{@list.length} managed to succeed at #{method}(): \
100
100
  #{@list.map { |a| a.class.name }.join(', ')}"
101
101
  end
@@ -42,8 +42,8 @@ class Sibit::Bitcoinchain
42
42
  raise Sibit::Error, "Block #{hash} not found" if block.nil?
43
43
  nxt = block['next_block']
44
44
  nxt = nil if nxt == '0000000000000000000000000000000000000000000000000000000000000000'
45
- @log.info("The block #{hash} is the latest, there is no next block") if nxt.nil?
46
- @log.info("The next block of #{hash} is #{nxt}") unless nxt.nil?
45
+ @log.debug("The block #{hash} is the latest, there is no next block") if nxt.nil?
46
+ @log.debug("The next block of #{hash} is #{nxt}") unless nxt.nil?
47
47
  nxt
48
48
  end
49
49
 
@@ -55,12 +55,12 @@ class Sibit::Bitcoinchain
55
55
  )[0]
56
56
  b = json['balance']
57
57
  if b.nil?
58
- @log.info("The balance of #{address} is not visible")
58
+ @log.debug("The balance of #{address} is not visible")
59
59
  return 0
60
60
  end
61
61
  b *= 100_000_000
62
62
  b = b.to_i
63
- @log.info("The balance of #{address} is #{b} satoshi (#{json['transactions']} txns)")
63
+ @log.debug("The balance of #{address} is #{b} satoshi (#{json['transactions']} txns)")
64
64
  b
65
65
  end
66
66
 
@@ -74,7 +74,7 @@ class Sibit::Bitcoinchain
74
74
  hash = Sibit::Json.new(http: @http, log: @log).get(
75
75
  Iri.new('https://api-r.bitcoinchain.com/v1/status')
76
76
  )['hash']
77
- @log.info("The latest block hash is #{hash}")
77
+ @log.debug("The latest block hash is #{hash}")
78
78
  hash
79
79
  end
80
80
 
@@ -34,7 +34,7 @@ class Sibit::Blockchain
34
34
  )[currency]
35
35
  raise Error, "Unrecognized currency #{currency}" if h.nil?
36
36
  price = h['15m']
37
- @log.info("The price of BTC is #{price} USD")
37
+ @log.debug("The price of BTC is #{price} USD")
38
38
  price
39
39
  end
40
40
 
@@ -46,9 +46,9 @@ class Sibit::Blockchain
46
46
  # )
47
47
  # nxt = json['next_block'][0]
48
48
  # if nxt.nil?
49
- # @log.info("There is no block after #{hash}")
49
+ # @log.debug("There is no block after #{hash}")
50
50
  # else
51
- # @log.info("The next block of #{hash} is #{nxt}")
51
+ # @log.debug("The next block of #{hash} is #{nxt}")
52
52
  # end
53
53
  # nxt
54
54
  end
@@ -59,7 +59,7 @@ class Sibit::Blockchain
59
59
  Iri.new('https://blockchain.info/rawblock').append(hash)
60
60
  )
61
61
  h = json['height']
62
- @log.info("The height of #{hash} is #{h}")
62
+ @log.debug("The height of #{hash} is #{h}")
63
63
  h
64
64
  end
65
65
 
@@ -70,7 +70,7 @@ class Sibit::Blockchain
70
70
  accept: [200, 500]
71
71
  )
72
72
  b = json['final_balance']
73
- @log.info("The balance of #{address} is #{b} satoshi (#{json['n_tx']} txns)")
73
+ @log.debug("The balance of #{address} is #{b} satoshi (#{json['n_tx']} txns)")
74
74
  b
75
75
  end
76
76
 
@@ -79,8 +79,12 @@ class Sibit::Blockchain
79
79
  json = Sibit::Json.new(http: @http, log: @log).get(
80
80
  Iri.new('https://api.blockchain.info/mempool/fees')
81
81
  )
82
- @log.info("Current recommended Bitcoin fees: \
83
- #{json['regular']}/#{json['priority']}/#{json['limits']['max']} sat/byte")
82
+ @log.debug(
83
+ [
84
+ 'Currently recommended Bitcoin fees: ',
85
+ "#{json['regular']}/#{json['priority']}/#{json['limits']['max']} sat/byte"
86
+ ].join
87
+ )
84
88
  {
85
89
  S: json['regular'] / 3,
86
90
  M: json['regular'],
@@ -118,7 +122,7 @@ class Sibit::Blockchain
118
122
  hash = Sibit::Json.new(http: @http, log: @log).get(
119
123
  Iri.new('https://blockchain.info/latestblock')
120
124
  )['hash']
121
- @log.info("The latest block hash is #{hash}")
125
+ @log.debug("The latest block hash is #{hash}")
122
126
  hash
123
127
  end
124
128
 
@@ -48,12 +48,12 @@ class Sibit::Blockchair
48
48
  Iri.new('https://api.blockchair.com/bitcoin/dashboards/address').append(address).fragment(the_key)
49
49
  )['data'][address]
50
50
  if json.nil?
51
- @log.info("Address #{address} not found")
51
+ @log.debug("Address #{address} not found")
52
52
  return 0
53
53
  end
54
54
  a = json['address']
55
55
  b = a['balance']
56
- @log.info("The balance of #{address} is #{b} satoshi")
56
+ @log.debug("The balance of #{address} is #{b} satoshi")
57
57
  b
58
58
  end
59
59
 
@@ -78,7 +78,7 @@ class Sibit::Blockchair
78
78
  Iri.new('https://api.blockchair.com/bitcoin/push/transaction').fragment(the_key),
79
79
  "data=#{hex}"
80
80
  )
81
- @log.info("Transaction (#{hex.length} in hex) has been pushed to Blockchair")
81
+ @log.debug("Transaction (#{hex.length} in hex) has been pushed to Blockchair")
82
82
  end
83
83
 
84
84
  # This method should fetch a Blockchain block and return as a hash.
data/lib/sibit/btc.rb CHANGED
@@ -36,21 +36,21 @@ class Sibit::Btc
36
36
  uri = Iri.new('https://chain.api.btc.com/v3/address').append(address).append('unspent')
37
37
  json = Sibit::Json.new(http: @http, log: @log).get(uri)
38
38
  if json['err_no'] == 1
39
- @log.info("The balance of #{address} is zero (not found)")
39
+ @log.debug("The balance of #{address} is zero (not found)")
40
40
  return 0
41
41
  end
42
42
  data = json['data']
43
43
  if data.nil?
44
- @log.info("The balance of #{address} is probably zero (not found)")
44
+ @log.debug("The balance of #{address} is probably zero (not found)")
45
45
  return 0
46
46
  end
47
47
  txns = data['list']
48
48
  if txns.nil?
49
- @log.info("The balance of #{address} is probably zero (not found)")
49
+ @log.debug("The balance of #{address} is probably zero (not found)")
50
50
  return 0
51
51
  end
52
52
  balance = txns.sum { |tx| tx['value'] } || 0
53
- @log.info("The balance of #{address} is #{balance}, total txns: #{txns.count}")
53
+ @log.debug("The balance of #{address} is #{balance}, total txns: #{txns.count}")
54
54
  balance
55
55
  end
56
56
 
@@ -63,8 +63,8 @@ class Sibit::Btc
63
63
  raise Sibit::Error, "The block #{hash} not found" if data.nil?
64
64
  nxt = data['next_block_hash']
65
65
  nxt = nil if nxt == '0000000000000000000000000000000000000000000000000000000000000000'
66
- @log.info("In BTC.com the block #{hash} is the latest, there is no next block") if nxt.nil?
67
- @log.info("The next block of #{hash} is #{nxt}") unless nxt.nil?
66
+ @log.debug("In BTC.com the block #{hash} is the latest, there is no next block") if nxt.nil?
67
+ @log.debug("The next block of #{hash} is #{nxt}") unless nxt.nil?
68
68
  nxt
69
69
  end
70
70
 
@@ -77,7 +77,7 @@ class Sibit::Btc
77
77
  raise Sibit::Error, "The block #{hash} not found" if data.nil?
78
78
  h = data['height']
79
79
  raise Sibit::Error, "The block #{hash} found but the height is absent" if h.nil?
80
- @log.info("The height of #{hash} is #{h}")
80
+ @log.debug("The height of #{hash} is #{h}")
81
81
  h
82
82
  end
83
83
 
@@ -93,7 +93,7 @@ class Sibit::Btc
93
93
  data = json['data']
94
94
  raise Sibit::Error, 'The latest block not found' if data.nil?
95
95
  hash = data['hash']
96
- @log.info("The hash of the latest block is #{hash}")
96
+ @log.debug("The hash of the latest block is #{hash}")
97
97
  hash
98
98
  end
99
99
 
data/lib/sibit/cex.rb CHANGED
@@ -29,7 +29,7 @@ class Sibit::Cex
29
29
  Iri.new('https://cex.io/api/last_price/BTC').append(currency)
30
30
  )
31
31
  p = json['lprice'].to_f
32
- @log.info("The price of BTC is #{p} #{currency}")
32
+ @log.debug("The price of BTC is #{p} #{currency}")
33
33
  p
34
34
  end
35
35
 
@@ -36,8 +36,8 @@ class Sibit::Cryptoapis
36
36
  Iri.new('https://api.cryptoapis.io/v1/bc/btc/mainnet/blocks').append(hash),
37
37
  headers: headers
38
38
  )['payload']['hash']
39
- @log.info("The block #{hash} is the latest, there is no next block") if nxt.nil?
40
- @log.info("The next block of #{hash} is #{nxt}") unless nxt.nil?
39
+ @log.debug("The block #{hash} is the latest, there is no next block") if nxt.nil?
40
+ @log.debug("The next block of #{hash} is #{nxt}") unless nxt.nil?
41
41
  nxt
42
42
  end
43
43
 
@@ -48,7 +48,7 @@ class Sibit::Cryptoapis
48
48
  headers: headers
49
49
  )['payload']
50
50
  h = json['height']
51
- @log.info("The height of #{hash} is #{h}")
51
+ @log.debug("The height of #{hash} is #{h}")
52
52
  h
53
53
  end
54
54
 
@@ -59,7 +59,7 @@ class Sibit::Cryptoapis
59
59
  headers: headers
60
60
  )['payload']
61
61
  b = (json['balance'].to_f * 100_000_000).to_i
62
- @log.info("The balance of #{address} is #{b} satoshi")
62
+ @log.debug("The balance of #{address} is #{b} satoshi")
63
63
  b
64
64
  end
65
65
 
@@ -74,7 +74,7 @@ class Sibit::Cryptoapis
74
74
  Iri.new('https://api.cryptoapis.io/v1/bc/btc/mainnet/blocks/latest'),
75
75
  headers: headers
76
76
  )['payload']['hash']
77
- @log.info("The latest block hash is #{hash}")
77
+ @log.debug("The latest block hash is #{hash}")
78
78
  hash
79
79
  end
80
80
 
data/lib/sibit/dry.rb CHANGED
@@ -23,7 +23,7 @@ class Sibit::Dry
23
23
  decoor(:api)
24
24
 
25
25
  def push(_hex)
26
- @log.info("Transaction not pushed, dry mode is ON (#{@origin.class.name})")
26
+ @log.debug('Transaction not pushed, dry mode is ON')
27
27
  nil
28
28
  end
29
29
  end
data/lib/sibit/firstof.rb CHANGED
@@ -88,7 +88,7 @@ class Sibit::FirstOf
88
88
  done = false
89
89
  result = nil
90
90
  @list.each do |api|
91
- @log.info("Calling #{api.class.name}##{method}()...")
91
+ @log.debug("Calling #{api.class.name}##{method}()...")
92
92
  begin
93
93
  result = yield api
94
94
  done = true
@@ -97,11 +97,11 @@ class Sibit::FirstOf
97
97
  # Just ignore it
98
98
  rescue Sibit::Error => e
99
99
  errors << e
100
- @log.info("The API #{api.class.name} failed at #{method}(): #{e.message}") if @verbose
100
+ @log.debug("The API #{api.class.name} failed at #{method}(): #{e.message}") if @verbose
101
101
  end
102
102
  end
103
103
  unless done
104
- errors.each { |e| @log.info(Backtrace.new(e).to_s) }
104
+ errors.each { |e| @log.debug(Backtrace.new(e).to_s) }
105
105
  raise Sibit::Error, "No APIs out of #{@list.length} managed to succeed at #{method}(): \
106
106
  #{@list.map { |a| a.class.name }.join(', ')}"
107
107
  end
data/lib/sibit/json.rb CHANGED
@@ -4,6 +4,7 @@
4
4
  # SPDX-License-Identifier: MIT
5
5
 
6
6
  require 'cgi'
7
+ require 'elapsed'
7
8
  require 'json'
8
9
  require 'loog'
9
10
  require 'uri'
@@ -30,52 +31,55 @@ class Sibit::Json
30
31
  # This method will also log the process and will validate the
31
32
  # response for correctness.
32
33
  def get(address, headers: {}, accept: [200])
33
- start = Time.now
34
- uri = URI(address.to_s)
35
- res = @http.client(uri).get(
36
- "#{uri.path.empty? ? '/' : uri.path}#{"?#{uri.query}" if uri.query}",
37
- {
38
- 'Accept' => 'application/json',
39
- 'User-Agent' => user_agent,
40
- 'Accept-Charset' => 'UTF-8',
41
- 'Accept-Encoding' => ''
42
- }.merge(headers)
43
- )
44
- unless accept.include?(res.code.to_i)
45
- raise Sibit::Error, "Failed to retrieve #{uri} (#{res.code}): #{res.body}"
34
+ ret = nil
35
+ elapsed(@log) do
36
+ uri = URI(address.to_s)
37
+ res = @http.client(uri).get(
38
+ "#{uri.path.empty? ? '/' : uri.path}#{"?#{uri.query}" if uri.query}",
39
+ {
40
+ 'Accept' => 'application/json',
41
+ 'User-Agent' => user_agent,
42
+ 'Accept-Charset' => 'UTF-8',
43
+ 'Accept-Encoding' => ''
44
+ }.merge(headers)
45
+ )
46
+ unless accept.include?(res.code.to_i)
47
+ raise Sibit::Error, "Failed to retrieve #{uri} (#{res.code}): #{res.body}"
48
+ end
49
+ ret =
50
+ begin
51
+ JSON.parse(res.body)
52
+ rescue JSON::ParserError => e
53
+ raise Sibit::Error, "Can't parse JSON: #{e.message}"
54
+ end
55
+ throw :"GET #{uri}: #{res.code}/#{length(res.body.length)}"
46
56
  end
47
- @log.info("GET #{uri}: #{res.code}/#{length(res.body.length)} in #{age(start)}")
48
- JSON.parse(res.body)
49
- rescue JSON::ParserError => e
50
- raise Sibit::Error, "Can't parse JSON: #{e.message}"
57
+ ret
51
58
  end
52
59
 
53
60
  def post(address, body, headers: {})
54
- start = Time.now
55
61
  uri = URI(address.to_s)
56
- res = @http.client(uri).post(
57
- "#{uri.path}?#{uri.query}",
58
- "tx=#{CGI.escape(body)}",
59
- {
60
- 'Accept' => 'text/plain',
61
- 'User-Agent' => user_agent,
62
- 'Accept-Charset' => 'UTF-8',
63
- 'Accept-Encoding' => '',
64
- 'Content-Type' => 'application/x-www-form-urlencoded'
65
- }.merge(headers)
66
- )
67
- unless res.code == '200'
68
- raise Sibit::Error, "Failed to post tx to #{uri}: #{res.code}\n#{res.body}"
62
+ elapsed(@log) do
63
+ res = @http.client(uri).post(
64
+ "#{uri.path}?#{uri.query}",
65
+ "tx=#{CGI.escape(body)}",
66
+ {
67
+ 'Accept' => 'text/plain',
68
+ 'User-Agent' => user_agent,
69
+ 'Accept-Charset' => 'UTF-8',
70
+ 'Accept-Encoding' => '',
71
+ 'Content-Type' => 'application/x-www-form-urlencoded'
72
+ }.merge(headers)
73
+ )
74
+ unless res.code == '200'
75
+ raise Sibit::Error, "Failed to post tx to #{uri}: #{res.code}\n#{res.body}"
76
+ end
77
+ throw :"POST #{uri}: #{res.code}"
69
78
  end
70
- @log.info("POST #{uri}: #{res.code} in #{age(start)}")
71
79
  end
72
80
 
73
81
  private
74
82
 
75
- def age(start)
76
- "#{((Time.now - start) * 1000).round}ms"
77
- end
78
-
79
83
  def length(bytes)
80
84
  if bytes > 1024 * 1024
81
85
  "#{bytes / (1024 * 1024)}mb"
data/lib/sibit/version.rb CHANGED
@@ -9,5 +9,5 @@
9
9
  # License:: MIT
10
10
  class Sibit
11
11
  # Current version of the library.
12
- VERSION = '0.30.1'
12
+ VERSION = '0.30.2'
13
13
  end
data/lib/sibit.rb CHANGED
@@ -49,7 +49,7 @@ class Sibit
49
49
  # Generates new Bitcoin private key and returns in Hash160 format.
50
50
  def generate
51
51
  key = Key.generate.priv
52
- @log.info("Bitcoin private key generated: #{key[0..8]}...")
52
+ @log.debug("Bitcoin private key generated: #{key[0..8]}...")
53
53
  key
54
54
  end
55
55
 
@@ -106,11 +106,11 @@ class Sibit
106
106
  unspent = 0
107
107
  size = 100
108
108
  utxos = @api.utxos(sources.keys)
109
- @log.info("#{utxos.count} UTXOs found, these will be used \
109
+ @log.debug("#{utxos.count} UTXOs found, these will be used \
110
110
  (value/confirmations at tx_hash):")
111
111
  utxos.each do |utxo|
112
112
  if skip_utxo.include?(utxo[:hash])
113
- @log.info("UTXO skipped: #{utxo[:hash]}")
113
+ @log.debug("UTXO skipped: #{utxo[:hash]}")
114
114
  next
115
115
  end
116
116
  unspent += utxo[:value]
@@ -124,7 +124,7 @@ class Sibit
124
124
  i.signature_key(key(k))
125
125
  end
126
126
  size += 180
127
- @log.info(
127
+ @log.debug(
128
128
  " #{num(utxo[:value], p)}/#{utxo[:confirmations]} at #{utxo[:hash]}"
129
129
  )
130
130
  break if unspent > satoshi
@@ -132,11 +132,14 @@ class Sibit
132
132
  if unspent < satoshi
133
133
  raise Error, "Not enough funds to send #{num(satoshi, p)}, only #{num(unspent, p)} left"
134
134
  end
135
- builder.output(satoshi, target)
136
135
  f = mfee(fee, size)
137
- satoshi += f if f.negative?
136
+ if f.negative?
137
+ satoshi += f
138
+ f = -f
139
+ end
138
140
  raise Error, "The fee #{f.abs} covers the entire amount" if satoshi.zero?
139
141
  raise Error, "The fee #{f.abs} is bigger than the amount #{satoshi}" if satoshi.negative?
142
+ builder.output(satoshi, target)
140
143
  tx = builder.tx(
141
144
  input_value: unspent,
142
145
  leave_fee: true,
@@ -144,7 +147,7 @@ class Sibit
144
147
  change_address: change
145
148
  )
146
149
  left = unspent - tx.outputs.sum(&:value)
147
- @log.info("A new Bitcoin transaction #{tx.hash} prepared:
150
+ @log.debug("A new Bitcoin transaction #{tx.hash} prepared:
148
151
  #{tx.in.count} input#{'s' if tx.in.count > 1}:
149
152
  #{tx.inputs.map { |i| " in: #{i.prev_out.unpack1('H*')}:#{i.prev_out_index}" }.join("\n ")}
150
153
  #{tx.out.count} output#{'s' if tx.out.count > 1}:
@@ -186,10 +189,10 @@ class Sibit
186
189
  json = @api.block(block)
187
190
  if json[:orphan]
188
191
  steps = 4
189
- @log.info("Orphan block found at #{block}, moving #{steps} steps back...")
192
+ @log.debug("Orphan block found at #{block}, moving #{steps} steps back...")
190
193
  steps.times do
191
194
  block = json[:previous]
192
- @log.info("Moved back to #{block}")
195
+ @log.debug("Moved back to #{block}")
193
196
  json = @api.block(block)
194
197
  end
195
198
  next
@@ -203,34 +206,34 @@ class Sibit
203
206
  hash = "#{t[:hash]}:#{i}"
204
207
  satoshi = o[:value]
205
208
  if yield(address, hash, satoshi)
206
- @log.info("Bitcoin tx found at #{hash} for #{satoshi} sent to #{address}")
209
+ @log.debug("Bitcoin tx found at #{hash} for #{satoshi} sent to #{address}")
207
210
  end
208
211
  end
209
212
  checked += 1
210
213
  end
211
214
  count += 1
212
- @log.info("We checked #{checked} txns and #{checked_outputs} outputs \
215
+ @log.debug("We checked #{checked} txns and #{checked_outputs} outputs \
213
216
  in block #{block} (by #{json[:provider]})")
214
217
  block = json[:next]
215
218
  begin
216
219
  if block.nil?
217
- @log.info("The next_block is empty in #{json[:hash]}, this may be the end...")
220
+ @log.debug("The next_block is empty in #{json[:hash]}, this may be the end...")
218
221
  block = @api.next_of(json[:hash])
219
222
  end
220
223
  rescue Sibit::Error => e
221
- @log.info("Failed to get the next_of(#{json[:hash]}), quitting: #{e.message}")
224
+ @log.debug("Failed to get the next_of(#{json[:hash]}), quitting: #{e.message}")
222
225
  break
223
226
  end
224
227
  if block.nil?
225
- @log.info("The block #{json[:hash]} is definitely the end of Blockchain, we stop.")
228
+ @log.debug("The block #{json[:hash]} is definitely the end of Blockchain, we stop.")
226
229
  break
227
230
  end
228
231
  if count >= max
229
- @log.info("Too many blocks (#{count}) in one go, let's get back to it next time")
232
+ @log.debug("Too many blocks (#{count}) in one go, let's get back to it next time")
230
233
  break
231
234
  end
232
235
  end
233
- @log.info("Scanned from #{start} to #{json[:hash]} (#{count} blocks)")
236
+ @log.debug("Scanned from #{start} to #{json[:hash]} (#{count} blocks)")
234
237
  json[:hash]
235
238
  end
236
239
 
@@ -256,7 +259,7 @@ in block #{block} (by #{json[:provider]})")
256
259
 
257
260
  # Calculates a fee in satoshi for the transaction of the specified size.
258
261
  # The +fee+ argument could be a number in satoshi, in which case it will
259
- # be returned as is, or a string like "XL" or "S", in which case the
262
+ # be returned as is, or a string like "XL" or "S-", in which case the
260
263
  # fee will be calculated using the +size+ argument (which is the size
261
264
  # of the transaction in bytes).
262
265
  def mfee(fee, size)
@@ -269,7 +272,9 @@ in block #{block} (by #{json[:provider]})")
269
272
  end
270
273
  sat = fees[fee.to_sym]
271
274
  raise Error, "Can't understand the fee: #{fee.inspect}" if sat.nil?
272
- mul * sat * size
275
+ f = mul * sat * size
276
+ @log.debug("Fee calculated as #{mul} * #{sat} * #{size} = #{f}")
277
+ f
273
278
  end
274
279
 
275
280
  # Make key from private key string in Hash160.
data/sibit.gemspec CHANGED
@@ -31,10 +31,11 @@ Gem::Specification.new do |s|
31
31
  s.extra_rdoc_files = ['README.md', 'LICENSE.txt']
32
32
  s.add_dependency 'backtrace', '~> 0.3'
33
33
  s.add_dependency 'decoor', '~> 0.1'
34
+ s.add_dependency 'elapsed', '~> 0.2'
34
35
  s.add_dependency 'iri', '~> 0.5'
35
- s.add_dependency 'json', '~> 2'
36
+ s.add_dependency 'json', '~> 2.18'
36
37
  s.add_dependency 'loog', '~> 0.6'
37
- s.add_dependency 'openssl', '>= 2.0'
38
+ s.add_dependency 'openssl', '~> 3.0'
38
39
  s.add_dependency 'retriable_proxy', '~> 1.0'
39
40
  s.add_dependency 'slop', '~> 4.6'
40
41
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sibit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.30.1
4
+ version: 0.30.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko
@@ -37,6 +37,20 @@ dependencies:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
39
  version: '0.1'
40
+ - !ruby/object:Gem::Dependency
41
+ name: elapsed
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '0.2'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '0.2'
40
54
  - !ruby/object:Gem::Dependency
41
55
  name: iri
42
56
  requirement: !ruby/object:Gem::Requirement
@@ -57,14 +71,14 @@ dependencies:
57
71
  requirements:
58
72
  - - "~>"
59
73
  - !ruby/object:Gem::Version
60
- version: '2'
74
+ version: '2.18'
61
75
  type: :runtime
62
76
  prerelease: false
63
77
  version_requirements: !ruby/object:Gem::Requirement
64
78
  requirements:
65
79
  - - "~>"
66
80
  - !ruby/object:Gem::Version
67
- version: '2'
81
+ version: '2.18'
68
82
  - !ruby/object:Gem::Dependency
69
83
  name: loog
70
84
  requirement: !ruby/object:Gem::Requirement
@@ -83,16 +97,16 @@ dependencies:
83
97
  name: openssl
84
98
  requirement: !ruby/object:Gem::Requirement
85
99
  requirements:
86
- - - ">="
100
+ - - "~>"
87
101
  - !ruby/object:Gem::Version
88
- version: '2.0'
102
+ version: '3.0'
89
103
  type: :runtime
90
104
  prerelease: false
91
105
  version_requirements: !ruby/object:Gem::Requirement
92
106
  requirements:
93
- - - ">="
107
+ - - "~>"
94
108
  - !ruby/object:Gem::Version
95
- version: '2.0'
109
+ version: '3.0'
96
110
  - !ruby/object:Gem::Dependency
97
111
  name: retriable_proxy
98
112
  requirement: !ruby/object:Gem::Requirement