sibit 0.13.1 → 0.14.0

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: 217f15565505e50e8f5d019458edb7a1ced3ae311d3aa8a3600ee9c00f9636fe
4
- data.tar.gz: c98b24bb8acdb59652eea6eab03397487ee0e9be66e9791fac3a2397b5a108fc
3
+ metadata.gz: 3f6e5104f2435ac68861792d65d9032cc0b41e3fd817e0aa78d0fac816498dfd
4
+ data.tar.gz: ab243ba18cdb2d3b12cce59f610cc613f74a52cc5f1e231bce9079cd0793e894
5
5
  SHA512:
6
- metadata.gz: ad0fa1e2cc7589eb8f0016b7ba8735750e033dbf1dd8776f6b6ac0e7e2acbb5f8ae4d6d69918cb35fb1031ab1218b4523cc6c6e27602cb29d0643d9bb990b9a8
7
- data.tar.gz: 43fc86116a93558807dfea80b9af201a9958c2b5a788309287a72591d9e44bfdb6abf6441d8a6ea3fce952a2a5168c191b1500732b8ac8a5fa8bb03c3b906fd3
6
+ metadata.gz: 8c213d7ab111da0b3e5e04b1ebb6493d6a51161b95c1cfa7390b16ab712c2db048c17d0bc05a2653579f0dd4bd7ea1dec9f77e63d7e580699233af1d39105fd8
7
+ data.tar.gz: d165148dfdc656e97e672c98a1a9839d34214ef0c2484d795103aac45e15b026459cd3191fee1d9e336fc588e366c5f0b6bee8e458c8ae34d3eaed91ade7d3c3
data/.simplecov CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2019 Yegor Bugayenko
1
+ # Copyright (c) 2019-2020 Yegor Bugayenko
2
2
  #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  # of this software and associated documentation files (the 'Software'), to deal
data/Gemfile CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright (c) 2019 Yegor Bugayenko
3
+ # Copyright (c) 2019-2020 Yegor Bugayenko
4
4
  #
5
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  # of this software and associated documentation files (the 'Software'), to deal
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  (The MIT License)
2
2
 
3
- Copyright (c) 2019 Yegor Bugayenko
3
+ Copyright (c) 2019-2020 Yegor Bugayenko
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the 'Software'), to deal
data/Rakefile CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright (c) 2019 Yegor Bugayenko
3
+ # Copyright (c) 2019-2020 Yegor Bugayenko
4
4
  #
5
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  # of this software and associated documentation files (the 'Software'), to deal
@@ -66,7 +66,7 @@ Cucumber::Rake::Task.new(:'features:html') do |t|
66
66
  end
67
67
 
68
68
  task :copyright do
69
- sh "grep -q -r '#{Date.today.strftime('%Y')}' \
69
+ sh "grep -q -r '2019-#{Date.today.strftime('%Y')}' \
70
70
  --include '*.rb' \
71
71
  --include '*.txt' \
72
72
  --include 'Rakefile' \
data/bin/sibit CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- # Copyright (c) 2019 Yegor Bugayenko
4
+ # Copyright (c) 2019-2020 Yegor Bugayenko
5
5
  #
6
6
  # Permission is hereby granted, free of charge, to any person obtaining a copy
7
7
  # of this software and associated documentation files (the 'Software'), to deal
@@ -30,6 +30,7 @@ require_relative '../lib/sibit'
30
30
  require_relative '../lib/sibit/version'
31
31
  require_relative '../lib/sibit/blockchain'
32
32
  require_relative '../lib/sibit/btc'
33
+ require_relative '../lib/sibit/bitcoinchain'
33
34
 
34
35
  begin
35
36
  begin
@@ -70,6 +71,8 @@ Options are:"
70
71
  api = Sibit::Blockchain.new(http: http, log: log, dry: opts[:dry])
71
72
  elsif a == 'btc'
72
73
  api = Sibit::Btc.new(http: http, log: log, dry: opts[:dry])
74
+ elsif a == 'bitcoinchain'
75
+ api = Sibit::Bitcoinchain.new(http: http, log: log, dry: opts[:dry])
73
76
  else
74
77
  raise Sibit::Error, "Unknown API \"#{a}\""
75
78
  end
data/features/cli.feature CHANGED
@@ -15,7 +15,7 @@ Feature: Command Line Processing
15
15
  Then Exit code is zero
16
16
 
17
17
  Scenario: Bitcoin latest block hash can be retrieved via Btc
18
- When I run bin/sibit with "latest --api=btc"
18
+ When I run bin/sibit with "latest --api=bitcoinchain"
19
19
  Then Exit code is zero
20
20
 
21
21
  Scenario: Bitcoin private key can be generated
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright (c) 2019 Yegor Bugayenko
3
+ # Copyright (c) 2019-2020 Yegor Bugayenko
4
4
  #
5
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  # of this software and associated documentation files (the 'Software'), to deal
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright (c) 2019 Yegor Bugayenko
3
+ # Copyright (c) 2019-2020 Yegor Bugayenko
4
4
  #
5
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  # of this software and associated documentation files (the 'Software'), to deal
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2019-2020 Yegor Bugayenko
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the 'Software'), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ # SOFTWARE.
22
+
23
+ require 'uri'
24
+ require 'json'
25
+ require_relative 'version'
26
+ require_relative 'error'
27
+ require_relative 'log'
28
+ require_relative 'http'
29
+ require_relative 'json'
30
+
31
+ # Bitcoinchain.com API.
32
+ #
33
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
34
+ # Copyright:: Copyright (c) 2019-2020 Yegor Bugayenko
35
+ # License:: MIT
36
+ class Sibit
37
+ # Btc.com API.
38
+ class Bitcoinchain
39
+ # Constructor.
40
+ def initialize(log: Sibit::Log.new, http: Sibit::Http.new, dry: false)
41
+ @http = http
42
+ @log = log
43
+ @dry = dry
44
+ end
45
+
46
+ # Current price of BTC in USD (float returned).
47
+ def price(_currency)
48
+ raise Sibit::Error, 'Not implemented yet'
49
+ end
50
+
51
+ # Gets the balance of the address, in satoshi.
52
+ def balance(address)
53
+ Sibit::Json.new(http: @http, log: @log).get(
54
+ URI("https://api-r.bitcoinchain.com/v1/address/#{address}")
55
+ )[0]['balance']
56
+ end
57
+
58
+ # Get recommended fees, in satoshi per byte.
59
+ def fees
60
+ raise Sibit::Error, 'Not implemented yet'
61
+ end
62
+
63
+ # Sends a payment and returns the transaction hash.
64
+ def pay(_amount, _fee, _sources, _target, _change)
65
+ raise Sibit::Error, 'Not implemented yet'
66
+ end
67
+
68
+ # Gets the hash of the latest block.
69
+ def latest
70
+ Sibit::Json.new(http: @http, log: @log).get(
71
+ URI('https://api-r.bitcoinchain.com/v1/status')
72
+ )['hash']
73
+ end
74
+
75
+ # This method should fetch a Blockchain block and return as a hash.
76
+ def block(hash)
77
+ head = Sibit::Json.new(http: @http, log: @log).get(
78
+ URI("https://api-r.bitcoinchain.com/v1/block/#{hash}")
79
+ )[0]
80
+ nxt = head['next_block']
81
+ nxt = nil if nxt == '0000000000000000000000000000000000000000000000000000000000000000'
82
+ {
83
+ hash: head['hash'],
84
+ orphan: !head['is_main'],
85
+ next: nxt,
86
+ previous: head['prev_block'],
87
+ txns: Sibit::Json.new(http: @http, log: @log).get(
88
+ URI("https://api-r.bitcoinchain.com/v1/block/txs/#{hash}")
89
+ )[0]['txs'].map do |t|
90
+ {
91
+ hash: t['self_hash'],
92
+ outputs: t['outputs'].select { |o| o['spent'] }.map do |o|
93
+ {
94
+ address: o['receiver'],
95
+ value: o['value']
96
+ }
97
+ end
98
+ }
99
+ end
100
+ }
101
+ end
102
+ end
103
+ end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright (c) 2019 Yegor Bugayenko
3
+ # Copyright (c) 2019-2020 Yegor Bugayenko
4
4
  #
5
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  # of this software and associated documentation files (the 'Software'), to deal
@@ -34,7 +34,7 @@ require_relative 'json'
34
34
  # https://www.blockchain.com/api/blockchain_api
35
35
  #
36
36
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
37
- # Copyright:: Copyright (c) 2019 Yegor Bugayenko
37
+ # Copyright:: Copyright (c) 2019-2020 Yegor Bugayenko
38
38
  # License:: MIT
39
39
  class Sibit
40
40
  # Blockchain.info API.
@@ -133,7 +133,7 @@ class Sibit
133
133
  #{tx.outputs.map { |o| "out: #{o.script.bth} / #{num(o.value, p)}" }.join("\n ")}
134
134
  Min tx fee: #{num(Bitcoin.network[:min_tx_fee], p)}
135
135
  Fee requested: #{num(f, p)} as \"#{fee}\"
136
- Fee left: #{num(left, p)}
136
+ Fee actually paid: #{num(left, p)}
137
137
  Tx size: #{size} bytes
138
138
  Unspent: #{num(unspent, p)}
139
139
  Amount: #{num(satoshi, p)}
@@ -155,6 +155,11 @@ class Sibit
155
155
  )['hash']
156
156
  end
157
157
 
158
+ # This method should fetch a Blockchain block and return as a hash.
159
+ def block(_hash)
160
+ raise Sibit::Error, 'Not implemented yet'
161
+ end
162
+
158
163
  private
159
164
 
160
165
  def num(satoshi, usd)
data/lib/sibit/btc.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright (c) 2019 Yegor Bugayenko
3
+ # Copyright (c) 2019-2020 Yegor Bugayenko
4
4
  #
5
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  # of this software and associated documentation files (the 'Software'), to deal
@@ -31,7 +31,7 @@ require_relative 'json'
31
31
  # Btc.com API.
32
32
  #
33
33
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
34
- # Copyright:: Copyright (c) 2019 Yegor Bugayenko
34
+ # Copyright:: Copyright (c) 2019-2020 Yegor Bugayenko
35
35
  # License:: MIT
36
36
  class Sibit
37
37
  # Btc.com API.
@@ -81,5 +81,48 @@ class Sibit
81
81
  @log.info("The hash of the latest block is #{hash}")
82
82
  hash
83
83
  end
84
+
85
+ # This method should fetch a Blockchain block and return as a hash.
86
+ def block(hash)
87
+ head = Sibit::Json.new(http: @http, log: @log).get(
88
+ URI("https://chain.api.btc.com/v3/block/#{hash}")
89
+ )
90
+ nxt = head['data']['next_block_hash']
91
+ nxt = nil if nxt == '0000000000000000000000000000000000000000000000000000000000000000'
92
+ {
93
+ hash: head['data']['hash'],
94
+ orphan: head['data']['is_orphan'],
95
+ next: nxt,
96
+ previous: head['data']['prev_block_hash'],
97
+ txns: txns(hash)
98
+ }
99
+ end
100
+
101
+ private
102
+
103
+ def txns(hash)
104
+ page = 1
105
+ psize = 50
106
+ all = []
107
+ loop do
108
+ txns = Sibit::Json.new(http: @http, log: @log).get(
109
+ URI("https://chain.api.btc.com/v3/block/#{hash}/tx?page=#{page}&pagesize=#{psize}")
110
+ )['data']['list'].map do |t|
111
+ {
112
+ hash: t['hash'],
113
+ outputs: t['outputs'].reject { |o| o['spent_by_tx'] }.map do |o|
114
+ {
115
+ address: o['addresses'][0],
116
+ value: o['value']
117
+ }
118
+ end
119
+ }
120
+ end
121
+ all += txns
122
+ page += 1
123
+ break if txns.length < psize
124
+ end
125
+ all
126
+ end
84
127
  end
85
128
  end
data/lib/sibit/error.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright (c) 2019 Yegor Bugayenko
3
+ # Copyright (c) 2019-2020 Yegor Bugayenko
4
4
  #
5
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  # of this software and associated documentation files (the 'Software'), to deal
@@ -23,7 +23,7 @@
23
23
  # The error.
24
24
  #
25
25
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
26
- # Copyright:: Copyright (c) 2019 Yegor Bugayenko
26
+ # Copyright:: Copyright (c) 2019-2020 Yegor Bugayenko
27
27
  # License:: MIT
28
28
  class Sibit
29
29
  # The error.
data/lib/sibit/fake.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright (c) 2019 Yegor Bugayenko
3
+ # Copyright (c) 2019-2020 Yegor Bugayenko
4
4
  #
5
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  # of this software and associated documentation files (the 'Software'), to deal
@@ -25,7 +25,7 @@ require_relative 'version'
25
25
  # Fake API.
26
26
  #
27
27
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
28
- # Copyright:: Copyright (c) 2019 Yegor Bugayenko
28
+ # Copyright:: Copyright (c) 2019-2020 Yegor Bugayenko
29
29
  # License:: MIT
30
30
  class Sibit
31
31
  # Fake API
data/lib/sibit/http.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright (c) 2019 Yegor Bugayenko
3
+ # Copyright (c) 2019-2020 Yegor Bugayenko
4
4
  #
5
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  # of this software and associated documentation files (the 'Software'), to deal
@@ -25,7 +25,7 @@ require 'net/http'
25
25
  # HTTP interface.
26
26
  #
27
27
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
28
- # Copyright:: Copyright (c) 2019 Yegor Bugayenko
28
+ # Copyright:: Copyright (c) 2019-2020 Yegor Bugayenko
29
29
  # License:: MIT
30
30
  class Sibit
31
31
  # This HTTP client will be used by default.
@@ -33,6 +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
37
  http
37
38
  end
38
39
  end
@@ -46,6 +47,7 @@ class Sibit
46
47
  def client(uri)
47
48
  http = Net::HTTP.new(uri.host, uri.port, @host, @port.to_i)
48
49
  http.use_ssl = true
50
+ http.read_timeout = 120
49
51
  http
50
52
  end
51
53
  end
data/lib/sibit/json.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright (c) 2019 Yegor Bugayenko
3
+ # Copyright (c) 2019-2020 Yegor Bugayenko
4
4
  #
5
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  # of this software and associated documentation files (the 'Software'), to deal
@@ -22,9 +22,11 @@
22
22
 
23
23
  require 'json'
24
24
  require 'uri'
25
+ require 'cgi'
25
26
  require_relative 'version'
26
27
  require_relative 'error'
27
28
  require_relative 'http'
29
+ require_relative 'log'
28
30
 
29
31
  # Json SDK.
30
32
  #
@@ -32,7 +34,7 @@ require_relative 'http'
32
34
  # https://www.blockchain.com/api/blockchain_api
33
35
  #
34
36
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
35
- # Copyright:: Copyright (c) 2019 Yegor Bugayenko
37
+ # Copyright:: Copyright (c) 2019-2020 Yegor Bugayenko
36
38
  # License:: MIT
37
39
  class Sibit
38
40
  # JSON processing.
@@ -50,8 +52,9 @@ class Sibit
50
52
  start = Time.now
51
53
  res = @http.client(uri).get(
52
54
  "#{uri.path}?#{uri.query}",
53
- 'Accept' => 'text/plain',
55
+ 'Accept' => 'application/json',
54
56
  'User-Agent' => user_agent,
57
+ 'Accept-Charset' => 'UTF-8',
55
58
  'Accept-Encoding' => ''
56
59
  )
57
60
  unless res.code == '200'
@@ -68,6 +71,7 @@ class Sibit
68
71
  "tx=#{CGI.escape(body)}",
69
72
  'Accept' => 'text/plain',
70
73
  'User-Agent' => user_agent,
74
+ 'Accept-Charset' => 'UTF-8',
71
75
  'Accept-Encoding' => '',
72
76
  'Content-Type' => 'application/x-www-form-urlencoded'
73
77
  )
data/lib/sibit/log.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright (c) 2019 Yegor Bugayenko
3
+ # Copyright (c) 2019-2020 Yegor Bugayenko
4
4
  #
5
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  # of this software and associated documentation files (the 'Software'), to deal
@@ -23,7 +23,7 @@
23
23
  # The log.
24
24
  #
25
25
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
26
- # Copyright:: Copyright (c) 2019 Yegor Bugayenko
26
+ # Copyright:: Copyright (c) 2019-2020 Yegor Bugayenko
27
27
  # License:: MIT
28
28
  class Sibit
29
29
  # Log.
data/lib/sibit/version.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright (c) 2019 Yegor Bugayenko
3
+ # Copyright (c) 2019-2020 Yegor Bugayenko
4
4
  #
5
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  # of this software and associated documentation files (the 'Software'), to deal
@@ -22,9 +22,9 @@
22
22
 
23
23
  # Sibit main class.
24
24
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
25
- # Copyright:: Copyright (c) 2019 Yegor Bugayenko
25
+ # Copyright:: Copyright (c) 2019-2020 Yegor Bugayenko
26
26
  # License:: MIT
27
27
  class Sibit
28
28
  # Current version of the library.
29
- VERSION = '0.13.1'
29
+ VERSION = '0.14.0'
30
30
  end
data/lib/sibit.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright (c) 2019 Yegor Bugayenko
3
+ # Copyright (c) 2019-2020 Yegor Bugayenko
4
4
  #
5
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  # of this software and associated documentation files (the 'Software'), to deal
@@ -28,7 +28,7 @@ require_relative 'sibit/blockchain'
28
28
  # Sibit main class.
29
29
  #
30
30
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
31
- # Copyright:: Copyright (c) 2019 Yegor Bugayenko
31
+ # Copyright:: Copyright (c) 2019-2020 Yegor Bugayenko
32
32
  # License:: MIT
33
33
  class Sibit
34
34
  # Constructor.
@@ -115,6 +115,62 @@ class Sibit
115
115
  first_one(&:latest)
116
116
  end
117
117
 
118
+ # You call this method and provide a callback. You provide the hash
119
+ # of the starting block. The method will go through the Blockchain,
120
+ # fetch blocks and find transactions, one by one, passing them to the
121
+ # callback provided. When finished, the method returns the hash of
122
+ # a new block, seen last.
123
+ #
124
+ # The callback will be called with three arguments:
125
+ # 1) Bitcoin address of the receiver, 2) transaction hash, 3) amount
126
+ # in satoshi.
127
+ def scan(start, max: 4)
128
+ block = start
129
+ count = 0
130
+ wrong = []
131
+ loop do
132
+ json = first_one { |api| api.block(block) }
133
+ if json[:orphan]
134
+ steps = 4
135
+ @log.info("Orphan block found at #{block}, moving #{steps} steps back...")
136
+ wrong << block
137
+ steps.times do
138
+ block = json[:previous]
139
+ wrong << block
140
+ @log.info("Moved back to #{block}")
141
+ json = first_one { |api| api.block(block) }
142
+ end
143
+ next
144
+ end
145
+ checked = 0
146
+ checked_outputs = 0
147
+ json[:txns].each do |t|
148
+ t[:outputs].each_with_index do |o, i|
149
+ address = o[:address]
150
+ checked_outputs += 1
151
+ hash = "#{t[:hash]}:#{i}"
152
+ satoshi = o[:value]
153
+ yield(address, hash, satoshi)
154
+ @log.info("Bitcoin tx found at #{hash} for #{satoshi} sent to #{address}")
155
+ end
156
+ checked += 1
157
+ end
158
+ @log.info("We checked #{checked} txns and #{checked_outputs} outputs in block #{block}")
159
+ n = json[:next]
160
+ if n.nil?
161
+ @log.info("The next_block is empty in block #{block}, this is the end of Blockchain")
162
+ break
163
+ end
164
+ block = n
165
+ count += 1
166
+ if count > max
167
+ @log.info("Too many blocks (#{count}) in one go, let's get back to it next time")
168
+ break
169
+ end
170
+ end
171
+ block
172
+ end
173
+
118
174
  private
119
175
 
120
176
  def first_one
data/sibit.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright (c) 2019 Yegor Bugayenko
3
+ # Copyright (c) 2019-2020 Yegor Bugayenko
4
4
  #
5
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  # of this software and associated documentation files (the 'Software'), to deal
data/test/test__helper.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright (c) 2019 Yegor Bugayenko
3
+ # Copyright (c) 2019-2020 Yegor Bugayenko
4
4
  #
5
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  # of this software and associated documentation files (the 'Software'), to deal
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2019-2020 Yegor Bugayenko
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the 'Software'), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ # SOFTWARE.
22
+
23
+ require 'minitest/autorun'
24
+ require 'webmock/minitest'
25
+ require 'json'
26
+ require_relative '../lib/sibit'
27
+ require_relative '../lib/sibit/bitcoinchain'
28
+
29
+ # Sibit::Bitcoinchain test.
30
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
31
+ # Copyright:: Copyright (c) 2019-2020 Yegor Bugayenko
32
+ # License:: MIT
33
+ class TestBitcoinchain < Minitest::Test
34
+ def test_fetch_hash
35
+ stub_request(
36
+ :get,
37
+ 'https://api-r.bitcoinchain.com/v1/status'
38
+ ).to_return(body: '{"hash": "test"}')
39
+ WebMock.allow_net_connect!
40
+ sibit = Sibit::Bitcoinchain.new
41
+ hash = sibit.latest
42
+ assert_equal('test', hash)
43
+ end
44
+
45
+ def test_fetch_balance
46
+ hash = '1Chain4asCYNnLVbvG6pgCLGBrtzh4Lx4b'
47
+ stub_request(:get, "https://api-r.bitcoinchain.com/v1/address/#{hash}")
48
+ .to_return(body: '[{"balance": 123}]')
49
+ sibit = Sibit::Bitcoinchain.new
50
+ satoshi = sibit.balance(hash)
51
+ assert_equal(123, satoshi)
52
+ end
53
+
54
+ def test_fetch_block
55
+ hash = '000000000000000007341915521967247f1dec17b3a311b8a8f4495392f1439b'
56
+ stub_request(:get, "https://api-r.bitcoinchain.com/v1/block/#{hash}")
57
+ .to_return(
58
+ body: '[{"next_block": "nn", "prev_block": "pp", "hash": "hh"}]'
59
+ )
60
+ stub_request(:get, "https://api-r.bitcoinchain.com/v1/block/txs/#{hash}")
61
+ .to_return(
62
+ body: '[{"txs":[{"self_hash":"hash123",
63
+ "outputs":[{"value": 123, "receiver": "a1"}]}]}]'
64
+ )
65
+ sibit = Sibit::Bitcoinchain.new
66
+ json = sibit.block(hash)
67
+ assert_equal('nn', json[:next])
68
+ assert_equal('pp', json[:previous])
69
+ assert_equal('hh', json[:hash])
70
+ assert(json[:txns].is_a?(Array))
71
+ assert_equal('hash123', json[:txns][0][:hash])
72
+ assert(json[:txns][0][:outputs].is_a?(Array))
73
+ end
74
+ end
data/test/test_btc.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright (c) 2019 Yegor Bugayenko
3
+ # Copyright (c) 2019-2020 Yegor Bugayenko
4
4
  #
5
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  # of this software and associated documentation files (the 'Software'), to deal
@@ -28,7 +28,7 @@ require_relative '../lib/sibit/btc'
28
28
 
29
29
  # Sibit::Btc test.
30
30
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
31
- # Copyright:: Copyright (c) 2019 Yegor Bugayenko
31
+ # Copyright:: Copyright (c) 2019-2020 Yegor Bugayenko
32
32
  # License:: MIT
33
33
  class TestBtc < Minitest::Test
34
34
  def test_get_zero_balance
@@ -63,4 +63,21 @@ class TestBtc < Minitest::Test
63
63
  assert(balance.is_a?(Integer))
64
64
  assert_equal(123, balance)
65
65
  end
66
+
67
+ def test_fetch_block
68
+ hash = '000000000000000007341915521967247f1dec17b3a311b8a8f4495392f1439b'
69
+ stub_request(:get, "https://chain.api.btc.com/v3/block/#{hash}")
70
+ .to_return(body: '{"data": {"next_block_hash": "n", "hash": "h", "prev_block_hash": "p"}}')
71
+ stub_request(:get, "https://chain.api.btc.com/v3/block/#{hash}/tx?page=1&pagesize=50")
72
+ .to_return(body: '{"data": {"list":[{"hash": "thash",
73
+ "outputs": [{"addresses": ["a1"], "value": 123}]}]}}')
74
+ sibit = Sibit::Btc.new
75
+ json = sibit.block(hash)
76
+ assert(json[:next])
77
+ assert(json[:previous])
78
+ assert_equal('h', json[:hash])
79
+ assert(json[:txns].is_a?(Array))
80
+ assert_equal('thash', json[:txns][0][:hash])
81
+ assert(json[:txns][0][:outputs].is_a?(Array))
82
+ end
66
83
  end
data/test/test_fake.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright (c) 2019 Yegor Bugayenko
3
+ # Copyright (c) 2019-2020 Yegor Bugayenko
4
4
  #
5
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  # of this software and associated documentation files (the 'Software'), to deal
@@ -27,7 +27,7 @@ require_relative '../lib/sibit/fake'
27
27
 
28
28
  # Sibit::Fake test.
29
29
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
30
- # Copyright:: Copyright (c) 2019 Yegor Bugayenko
30
+ # Copyright:: Copyright (c) 2019-2020 Yegor Bugayenko
31
31
  # License:: MIT
32
32
  class TestFake < Minitest::Test
33
33
  def test_fake_object_works
data/test/test_json.rb ADDED
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2019-2020 Yegor Bugayenko
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the 'Software'), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ # SOFTWARE.
22
+
23
+ require 'minitest/autorun'
24
+ require 'uri'
25
+ require_relative '../lib/sibit/json'
26
+
27
+ # Sibit::Json test.
28
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
29
+ # Copyright:: Copyright (c) 2019-2020 Yegor Bugayenko
30
+ # License:: MIT
31
+ class TestJson < Minitest::Test
32
+ def test_loads_hash
33
+ WebMock.allow_net_connect!
34
+ json = Sibit::Json.new.get(URI('https://api-r.bitcoinchain.com/v1/status'))
35
+ assert(!json['hash'].nil?)
36
+ end
37
+ end
data/test/test_sibit.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright (c) 2019 Yegor Bugayenko
3
+ # Copyright (c) 2019-2020 Yegor Bugayenko
4
4
  #
5
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  # of this software and associated documentation files (the 'Software'), to deal
@@ -27,7 +27,7 @@ require_relative '../lib/sibit'
27
27
 
28
28
  # Sibit.
29
29
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
30
- # Copyright:: Copyright (c) 2019 Yegor Bugayenko
30
+ # Copyright:: Copyright (c) 2019-2020 Yegor Bugayenko
31
31
  # License:: MIT
32
32
  class TestSibit < Minitest::Test
33
33
  def test_loads_fees
@@ -167,4 +167,37 @@ class TestSibit < Minitest::Test
167
167
  )
168
168
  end
169
169
  end
170
+
171
+ def test_scan
172
+ api = Object.new
173
+ def api.block(hash)
174
+ {
175
+ hash: hash,
176
+ orphan: false,
177
+ next: 'next',
178
+ previous: 'previous',
179
+ txns: [
180
+ {
181
+ hash: 'hash',
182
+ outputs: [
183
+ {
184
+ address: 'addr',
185
+ value: 123
186
+ }
187
+ ]
188
+ }
189
+ ]
190
+ }
191
+ end
192
+ sibit = Sibit.new(api: api)
193
+ found = false
194
+ tail = sibit.scan('head') do |addr, tx, satoshi|
195
+ assert_equal(123, satoshi)
196
+ assert_equal('addr', addr)
197
+ assert_equal('hash:0', tx)
198
+ found = true
199
+ end
200
+ assert(found)
201
+ assert_equal('next', tail)
202
+ end
170
203
  end
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.13.1
4
+ version: 0.14.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-12-15 00:00:00.000000000 Z
11
+ date: 2020-03-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: backtrace
@@ -267,6 +267,7 @@ files:
267
267
  - features/step_definitions/steps.rb
268
268
  - features/support/env.rb
269
269
  - lib/sibit.rb
270
+ - lib/sibit/bitcoinchain.rb
270
271
  - lib/sibit/blockchain.rb
271
272
  - lib/sibit/btc.rb
272
273
  - lib/sibit/error.rb
@@ -278,8 +279,10 @@ files:
278
279
  - logo.svg
279
280
  - sibit.gemspec
280
281
  - test/test__helper.rb
282
+ - test/test_bitcoinchain.rb
281
283
  - test/test_btc.rb
282
284
  - test/test_fake.rb
285
+ - test/test_json.rb
283
286
  - test/test_sibit.rb
284
287
  homepage: http://github.com/yegor256/sibit
285
288
  licenses:
@@ -311,6 +314,8 @@ test_files:
311
314
  - features/step_definitions/steps.rb
312
315
  - features/support/env.rb
313
316
  - test/test__helper.rb
317
+ - test/test_bitcoinchain.rb
314
318
  - test/test_btc.rb
315
319
  - test/test_fake.rb
320
+ - test/test_json.rb
316
321
  - test/test_sibit.rb