sibit 0.13.1 → 0.14.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.simplecov +1 -1
- data/Gemfile +1 -1
- data/LICENSE.txt +1 -1
- data/Rakefile +2 -2
- data/bin/sibit +4 -1
- data/features/cli.feature +1 -1
- data/features/step_definitions/steps.rb +1 -1
- data/features/support/env.rb +1 -1
- data/lib/sibit/bitcoinchain.rb +103 -0
- data/lib/sibit/blockchain.rb +8 -3
- data/lib/sibit/btc.rb +45 -2
- data/lib/sibit/error.rb +2 -2
- data/lib/sibit/fake.rb +2 -2
- data/lib/sibit/http.rb +4 -2
- data/lib/sibit/json.rb +7 -3
- data/lib/sibit/log.rb +2 -2
- data/lib/sibit/version.rb +3 -3
- data/lib/sibit.rb +58 -2
- data/sibit.gemspec +1 -1
- data/test/test__helper.rb +1 -1
- data/test/test_bitcoinchain.rb +74 -0
- data/test/test_btc.rb +19 -2
- data/test/test_fake.rb +2 -2
- data/test/test_json.rb +37 -0
- data/test/test_sibit.rb +35 -2
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3f6e5104f2435ac68861792d65d9032cc0b41e3fd817e0aa78d0fac816498dfd
|
4
|
+
data.tar.gz: ab243ba18cdb2d3b12cce59f610cc613f74a52cc5f1e231bce9079cd0793e894
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8c213d7ab111da0b3e5e04b1ebb6493d6a51161b95c1cfa7390b16ab712c2db048c17d0bc05a2653579f0dd4bd7ea1dec9f77e63d7e580699233af1d39105fd8
|
7
|
+
data.tar.gz: d165148dfdc656e97e672c98a1a9839d34214ef0c2484d795103aac45e15b026459cd3191fee1d9e336fc588e366c5f0b6bee8e458c8ae34d3eaed91ade7d3c3
|
data/.simplecov
CHANGED
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
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 '
|
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=
|
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
|
data/features/support/env.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,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
|
data/lib/sibit/blockchain.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
|
@@ -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
|
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' => '
|
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.
|
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.
|
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:
|
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
|