sibit 0.10.0 → 0.11.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 +4 -4
- data/.rultor.yml +2 -2
- data/README.md +3 -1
- data/bin/sibit +9 -0
- data/features/cli.feature +4 -0
- data/lib/sibit/version.rb +1 -1
- data/lib/sibit.rb +21 -6
- data/test/test_sibit.rb +21 -7
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6a410aaa9dcc78c30bde9cf5f0b38f5869a6b6b1bbb1a364b2a1ef603aceba72
|
|
4
|
+
data.tar.gz: cc2b8197a9b230607b376205029300aa68ff55ac409b4c7a1334f46417ea5069
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3f28d118de6d6611298ebc0088c1583bf6a1d8ff99e0c46d9d37e19dfb896ae544a783933347ceb73a6335c8c88212ea73fee5cc81a136db854b903d79c68552
|
|
7
|
+
data.tar.gz: d3f3a9ee63757febd44c8b309a6edc605f360e116fdb45d6c07f769883ba05a496dd624f424fb44fb2deb13fe71593ed3d9d334ab5dcee17ba798b1b4750556c
|
data/.rultor.yml
CHANGED
data/README.md
CHANGED
|
@@ -15,7 +15,9 @@
|
|
|
15
15
|
[](https://hitsofcode.com/view/github/yegor256/sibit)
|
|
16
16
|
|
|
17
17
|
To understand how Bitcoin protocol works, I recommend you watching
|
|
18
|
-
this [short video](https://www.youtube.com/watch?v=IV9pRBq5A4g)
|
|
18
|
+
this [short video](https://www.youtube.com/watch?v=IV9pRBq5A4g) and
|
|
19
|
+
then reading this blog post of mine:
|
|
20
|
+
[_Sibit Demonstrates How Bitcoin Works_](https://www.yegor256.com/2019/05/07/sibit-bitcoin-command-line-client.html).
|
|
19
21
|
|
|
20
22
|
This is a simple Bitcoin client, to use from the command line
|
|
21
23
|
or from your Ruby app. You don't need to run any Bitcoin software,
|
data/bin/sibit
CHANGED
|
@@ -32,6 +32,7 @@ begin
|
|
|
32
32
|
o.banner = "Usage (#{Sibit::VERSION}): sibit [options] command [args]
|
|
33
33
|
Commands are:
|
|
34
34
|
price: Get current price of BTC in USD
|
|
35
|
+
fees: Get currently recommended transaction fees
|
|
35
36
|
latest: Get hash of the latest block
|
|
36
37
|
generate: Generate a new private key
|
|
37
38
|
create: Create a public Bitcoin address from the key
|
|
@@ -61,6 +62,14 @@ Options are:"
|
|
|
61
62
|
case opts.arguments[0]
|
|
62
63
|
when 'price'
|
|
63
64
|
puts sibit.price
|
|
65
|
+
when 'fees'
|
|
66
|
+
fees = sibit.fees
|
|
67
|
+
text = %i[S M L XL].map do |m|
|
|
68
|
+
sat = fees[m] * 250
|
|
69
|
+
usd = sat * sibit.price / 100_000_000
|
|
70
|
+
"#{m}: #{sat}sat / $#{format('%.02f', usd)}"
|
|
71
|
+
end.join("\n")
|
|
72
|
+
puts text
|
|
64
73
|
when 'latest'
|
|
65
74
|
puts sibit.latest
|
|
66
75
|
when 'generate'
|
data/features/cli.feature
CHANGED
|
@@ -26,6 +26,10 @@ Feature: Command Line Processing
|
|
|
26
26
|
When I run bin/sibit with "balance 1MZT1fa6y8H9UmbZV6HqKF4UY41o9MGT5f --verbose"
|
|
27
27
|
Then Exit code is zero
|
|
28
28
|
|
|
29
|
+
Scenario: Bitcoin fees can be printed
|
|
30
|
+
When I run bin/sibit with "fees --verbose"
|
|
31
|
+
Then Exit code is zero
|
|
32
|
+
|
|
29
33
|
Scenario: Bitcoin transaction can be sent
|
|
30
34
|
When I run bin/sibit with "--verbose --dry pay 100000 S 1JvCsJtLmCxEk7ddZFnVkGXpr9uhxZPmJi:fd2333686f49d8647e1ce8d5ef39c304520b08f3c756b67068b30a3db217dcb2 1JvCsJtLmCxEk7ddZFnVkGXpr9uhxZPmJi 1JvCsJtLmCxEk7ddZFnVkGXpr9uhxZPmJi"
|
|
31
35
|
Then Exit code is zero
|
data/lib/sibit/version.rb
CHANGED
data/lib/sibit.rb
CHANGED
|
@@ -123,6 +123,24 @@ class Sibit
|
|
|
123
123
|
json['final_balance']
|
|
124
124
|
end
|
|
125
125
|
|
|
126
|
+
# Get recommended fees, in satoshi per byte. The method returns
|
|
127
|
+
# a hash: { S: 12, M: 45, L: 100, XL: 200 }
|
|
128
|
+
def fees
|
|
129
|
+
json = JSON.parse(
|
|
130
|
+
Net::HTTP.get(
|
|
131
|
+
URI('https://bitcoinfees.earn.com/api/v1/fees/recommended')
|
|
132
|
+
)
|
|
133
|
+
)
|
|
134
|
+
info("Current recommended Bitcoin fees: \
|
|
135
|
+
#{json['hourFee']}/#{json['halfHourFee']}/#{json['fastestFee']} sat/byte")
|
|
136
|
+
{
|
|
137
|
+
S: json['hourFee'] / 3,
|
|
138
|
+
M: json['hourFee'],
|
|
139
|
+
L: json['halfHourFee'],
|
|
140
|
+
XL: json['fastestFee']
|
|
141
|
+
}
|
|
142
|
+
end
|
|
143
|
+
|
|
126
144
|
# Sends a payment and returns the transaction hash.
|
|
127
145
|
#
|
|
128
146
|
# If the payment can't be signed (the key is wrong, for example) or the
|
|
@@ -181,7 +199,6 @@ class Sibit
|
|
|
181
199
|
#{tx.inputs.map { |i| " in: #{i.prev_out.bth}:#{i.prev_out_index}" }.join("\n ")}
|
|
182
200
|
#{tx.out.count} output#{tx.out.count > 1 ? 's' : ''}:
|
|
183
201
|
#{tx.outputs.map { |o| "out: #{o.script.bth} / #{num(o.value, p)}" }.join("\n ")}
|
|
184
|
-
Fee required: #{num(f, p)}
|
|
185
202
|
Min tx fee: #{num(Bitcoin.network[:min_tx_fee], p)}
|
|
186
203
|
Fee left: #{num(left, p)}
|
|
187
204
|
Tx size: #{size} bytes
|
|
@@ -242,11 +259,9 @@ class Sibit
|
|
|
242
259
|
def mfee(fee, size)
|
|
243
260
|
return fee.to_i if fee.is_a?(Integer)
|
|
244
261
|
raise Error, 'Fee should either be a String or Integer' unless fee.is_a?(String)
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
return 250 * size if fee == 'XL'
|
|
249
|
-
raise Error, "Can't understand the fee: #{fee.inspect}"
|
|
262
|
+
sat = fees[fee.to_sym]
|
|
263
|
+
raise Error, "Can't understand the fee: #{fee.inspect}" if sat.nil?
|
|
264
|
+
sat * size
|
|
250
265
|
end
|
|
251
266
|
|
|
252
267
|
# Make key from private key string in Hash160.
|
data/test/test_sibit.rb
CHANGED
|
@@ -30,10 +30,22 @@ require_relative '../lib/sibit'
|
|
|
30
30
|
# Copyright:: Copyright (c) 2019 Yegor Bugayenko
|
|
31
31
|
# License:: MIT
|
|
32
32
|
class TestSibit < Minitest::Test
|
|
33
|
+
def test_loads_fees
|
|
34
|
+
stub_request(
|
|
35
|
+
:get, 'https://bitcoinfees.earn.com/api/v1/fees/recommended'
|
|
36
|
+
).to_return(body: '{"fastestFee":300,"halfHourFee":200,"hourFee":180}')
|
|
37
|
+
sibit = Sibit.new
|
|
38
|
+
fees = sibit.fees
|
|
39
|
+
assert_equal(60, fees[:S])
|
|
40
|
+
assert_equal(180, fees[:M])
|
|
41
|
+
assert_equal(200, fees[:L])
|
|
42
|
+
assert_equal(300, fees[:XL])
|
|
43
|
+
end
|
|
44
|
+
|
|
33
45
|
def test_fetch_current_price
|
|
34
46
|
stub_request(
|
|
35
47
|
:get, 'https://blockchain.info/ticker'
|
|
36
|
-
).to_return(
|
|
48
|
+
).to_return(body: '{"USD" : {"15m" : 5160.04}}')
|
|
37
49
|
sibit = Sibit.new
|
|
38
50
|
price = sibit.price
|
|
39
51
|
assert(!price.nil?)
|
|
@@ -62,7 +74,7 @@ class TestSibit < Minitest::Test
|
|
|
62
74
|
stub_request(
|
|
63
75
|
:get,
|
|
64
76
|
'https://blockchain.info/rawaddr/1MZT1fa6y8H9UmbZV6HqKF4UY41o9MGT5f'
|
|
65
|
-
).to_return(
|
|
77
|
+
).to_return(body: '{"final_balance": 100}')
|
|
66
78
|
sibit = Sibit.new
|
|
67
79
|
balance = sibit.balance('1MZT1fa6y8H9UmbZV6HqKF4UY41o9MGT5f')
|
|
68
80
|
assert(balance.is_a?(Integer))
|
|
@@ -71,7 +83,6 @@ class TestSibit < Minitest::Test
|
|
|
71
83
|
|
|
72
84
|
def test_get_latest_block
|
|
73
85
|
stub_request(:get, 'https://blockchain.info/latestblock').to_return(
|
|
74
|
-
status: 200,
|
|
75
86
|
body: '{"hash": "0000000000000538200a48202ca6340e983646ca088c7618ae82d68e0c76ef5a"}'
|
|
76
87
|
)
|
|
77
88
|
sibit = Sibit.new
|
|
@@ -80,9 +91,12 @@ class TestSibit < Minitest::Test
|
|
|
80
91
|
end
|
|
81
92
|
|
|
82
93
|
def test_send_payment
|
|
94
|
+
stub_request(
|
|
95
|
+
:get, 'https://bitcoinfees.earn.com/api/v1/fees/recommended'
|
|
96
|
+
).to_return(body: '{"fastestFee":300,"halfHourFee":200,"hourFee":180}')
|
|
83
97
|
stub_request(
|
|
84
98
|
:get, 'https://blockchain.info/ticker'
|
|
85
|
-
).to_return(
|
|
99
|
+
).to_return(body: '{"USD" : {"15m" : 5160.04}}')
|
|
86
100
|
json = {
|
|
87
101
|
unspent_outputs: [
|
|
88
102
|
{
|
|
@@ -97,7 +111,7 @@ class TestSibit < Minitest::Test
|
|
|
97
111
|
stub_request(
|
|
98
112
|
:get,
|
|
99
113
|
'https://blockchain.info/unspent?active=1JvCsJtLmCxEk7ddZFnVkGXpr9uhxZPmJi&limit=1000'
|
|
100
|
-
).to_return(
|
|
114
|
+
).to_return(body: JSON.pretty_generate(json))
|
|
101
115
|
stub_request(:post, 'https://blockchain.info/pushtx').to_return(status: 200)
|
|
102
116
|
sibit = Sibit.new
|
|
103
117
|
target = sibit.create(sibit.generate)
|
|
@@ -117,14 +131,14 @@ class TestSibit < Minitest::Test
|
|
|
117
131
|
def test_fail_if_not_enough_funds
|
|
118
132
|
stub_request(
|
|
119
133
|
:get, 'https://blockchain.info/ticker'
|
|
120
|
-
).to_return(
|
|
134
|
+
).to_return(body: '{"USD" : {"15m" : 5160.04}}')
|
|
121
135
|
json = {
|
|
122
136
|
unspent_outputs: []
|
|
123
137
|
}
|
|
124
138
|
stub_request(
|
|
125
139
|
:get,
|
|
126
140
|
'https://blockchain.info/unspent?active=1JvCsJtLmCxEk7ddZFnVkGXpr9uhxZPmJi&limit=1000'
|
|
127
|
-
).to_return(
|
|
141
|
+
).to_return(body: JSON.pretty_generate(json))
|
|
128
142
|
sibit = Sibit.new
|
|
129
143
|
target = sibit.create(sibit.generate)
|
|
130
144
|
change = sibit.create(sibit.generate)
|
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.11.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-05-
|
|
11
|
+
date: 2019-05-29 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: backtrace
|