sibit 0.30.2 → 0.30.4
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/lib/sibit/base58.rb +6 -1
- data/lib/sibit/bech32.rb +86 -0
- data/lib/sibit/tx.rb +14 -7
- data/lib/sibit/version.rb +1 -1
- data/lib/sibit.rb +5 -2
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d3d770048c5c19650ec325dd100d556c798c58d27ae06c120569161dc5ede087
|
|
4
|
+
data.tar.gz: b8b19fa66905fcd77379c4ebe6892ed6e5ee7ceece7ae1cc46f8921a50bb8a0e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: eb8af223383b416274d70182ab890d8d41540687112086510827f5b95f0a3ced72bd641d57fb7afd4bb43ff6c0ece6eb453dba8d4ff91f61d7097e069370f716
|
|
7
|
+
data.tar.gz: 2ec794eb825e11f3154c28f874e1fa6e6aadbe5be70510576a6c45768f5afba653561e1ade8e32ce3f8d1e32b64ea4b610892ec2a557b1504d377961358769b8
|
data/lib/sibit/base58.rb
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
# SPDX-License-Identifier: MIT
|
|
5
5
|
|
|
6
6
|
require 'digest'
|
|
7
|
+
require_relative 'error'
|
|
7
8
|
|
|
8
9
|
# Sibit main class.
|
|
9
10
|
class Sibit
|
|
@@ -36,7 +37,11 @@ class Sibit
|
|
|
36
37
|
def decode
|
|
37
38
|
leading = @data.match(/^1*/)[0].length
|
|
38
39
|
num = 0
|
|
39
|
-
@data.each_char
|
|
40
|
+
@data.each_char do |c|
|
|
41
|
+
idx = ALPHABET.index(c)
|
|
42
|
+
raise Sibit::Error, "Invalid Base58 character '#{c}' in address '#{@data}'" if idx.nil?
|
|
43
|
+
num = (num * 58) + idx
|
|
44
|
+
end
|
|
40
45
|
hex = num.zero? ? '' : num.to_s(16)
|
|
41
46
|
hex = "0#{hex}" if hex.length.odd?
|
|
42
47
|
('00' * leading) + hex
|
data/lib/sibit/bech32.rb
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2019-2025 Yegor Bugayenko
|
|
4
|
+
# SPDX-License-Identifier: MIT
|
|
5
|
+
|
|
6
|
+
require_relative 'error'
|
|
7
|
+
|
|
8
|
+
# Sibit main class.
|
|
9
|
+
class Sibit
|
|
10
|
+
# Bech32 decoding for SegWit addresses.
|
|
11
|
+
#
|
|
12
|
+
# Decodes Bech32/Bech32m addresses (bc1...) to witness programs.
|
|
13
|
+
#
|
|
14
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
|
15
|
+
# Copyright:: Copyright (c) 2019-2025 Yegor Bugayenko
|
|
16
|
+
# License:: MIT
|
|
17
|
+
class Bech32
|
|
18
|
+
CHARSET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l'
|
|
19
|
+
GENERATOR = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3].freeze
|
|
20
|
+
|
|
21
|
+
def initialize(addr)
|
|
22
|
+
@addr = addr.downcase
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def witness
|
|
26
|
+
hrp, data = parse
|
|
27
|
+
raise Sibit::Error, "Invalid Bech32 checksum in '#{@addr}'" unless verified?(hrp, data)
|
|
28
|
+
prog = convert(data[1..-7], 5, 8, false)
|
|
29
|
+
prog.pack('C*').unpack1('H*')
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def version
|
|
33
|
+
_, data = parse
|
|
34
|
+
data[0]
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def parse
|
|
40
|
+
pos = @addr.rindex('1')
|
|
41
|
+
raise Sibit::Error, "Invalid Bech32 address '#{@addr}': no separator" if pos.nil? || pos < 1
|
|
42
|
+
hrp = @addr[0...pos]
|
|
43
|
+
rest = @addr[(pos + 1)..]
|
|
44
|
+
raise Sibit::Error, "Invalid Bech32 address '#{@addr}': data too short" if rest.length < 6
|
|
45
|
+
data = rest.chars.map { |c| CHARSET.index(c) }
|
|
46
|
+
raise Sibit::Error, "Invalid Bech32 character in '#{@addr}'" if data.include?(nil)
|
|
47
|
+
[hrp, data]
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def verified?(hrp, data)
|
|
51
|
+
chk = polymod(expand(hrp) + data)
|
|
52
|
+
[1, 0x2bc830a3].include?(chk)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def expand(hrp)
|
|
56
|
+
hrp.chars.map { |c| c.ord >> 5 } + [0] + hrp.chars.map { |c| c.ord & 31 }
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def polymod(values)
|
|
60
|
+
chk = 1
|
|
61
|
+
values.each do |v|
|
|
62
|
+
top = chk >> 25
|
|
63
|
+
chk = ((chk & 0x1ffffff) << 5) ^ v
|
|
64
|
+
5.times { |i| chk ^= GENERATOR[i] if (top >> i).allbits?(1) }
|
|
65
|
+
end
|
|
66
|
+
chk
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def convert(data, frombits, tobits, pad)
|
|
70
|
+
acc = 0
|
|
71
|
+
bits = 0
|
|
72
|
+
result = []
|
|
73
|
+
maxv = (1 << tobits) - 1
|
|
74
|
+
data.each do |v|
|
|
75
|
+
acc = (acc << frombits) | v
|
|
76
|
+
bits += frombits
|
|
77
|
+
while bits >= tobits
|
|
78
|
+
bits -= tobits
|
|
79
|
+
result << ((acc >> bits) & maxv)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
result << ((acc << (tobits - bits)) & maxv) if pad && bits.positive?
|
|
83
|
+
result
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
data/lib/sibit/tx.rb
CHANGED
|
@@ -5,13 +5,12 @@
|
|
|
5
5
|
|
|
6
6
|
require 'digest'
|
|
7
7
|
require_relative 'base58'
|
|
8
|
+
require_relative 'bech32'
|
|
8
9
|
require_relative 'key'
|
|
9
10
|
require_relative 'script'
|
|
10
11
|
|
|
11
12
|
# Sibit main class.
|
|
12
13
|
class Sibit
|
|
13
|
-
MIN_TX_FEE = 10_000
|
|
14
|
-
|
|
15
14
|
# Bitcoin Transaction structure.
|
|
16
15
|
#
|
|
17
16
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
|
@@ -98,8 +97,8 @@ class Sibit
|
|
|
98
97
|
end
|
|
99
98
|
|
|
100
99
|
def script
|
|
101
|
-
|
|
102
|
-
|
|
100
|
+
return segwit_script if @address.downcase.start_with?('bc1')
|
|
101
|
+
p2pkh_script
|
|
103
102
|
end
|
|
104
103
|
|
|
105
104
|
def script_hex
|
|
@@ -108,9 +107,17 @@ class Sibit
|
|
|
108
107
|
|
|
109
108
|
private
|
|
110
109
|
|
|
111
|
-
def
|
|
112
|
-
decoded = Base58.new(
|
|
113
|
-
decoded[2..41]
|
|
110
|
+
def p2pkh_script
|
|
111
|
+
decoded = Base58.new(@address).decode
|
|
112
|
+
hash = decoded[2..41]
|
|
113
|
+
[0x76, 0xa9, 0x14].pack('C*') + [hash].pack('H*') + [0x88, 0xac].pack('C*')
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def segwit_script
|
|
117
|
+
bech = Bech32.new(@address)
|
|
118
|
+
witness = bech.witness
|
|
119
|
+
len = witness.length / 2
|
|
120
|
+
[0x00, len].pack('C*') + [witness].pack('H*')
|
|
114
121
|
end
|
|
115
122
|
end
|
|
116
123
|
|
data/lib/sibit/version.rb
CHANGED
data/lib/sibit.rb
CHANGED
|
@@ -18,6 +18,9 @@ require_relative 'sibit/version'
|
|
|
18
18
|
# Copyright:: Copyright (c) 2019-2025 Yegor Bugayenko
|
|
19
19
|
# License:: MIT
|
|
20
20
|
class Sibit
|
|
21
|
+
# Minimium fee we must pay for transaction processing:
|
|
22
|
+
MIN_SATOSHI_PER_BYTE = 0.1
|
|
23
|
+
|
|
21
24
|
# Constructor.
|
|
22
25
|
#
|
|
23
26
|
# You may provide the log you want to see the messages in. If you don't
|
|
@@ -143,7 +146,7 @@ class Sibit
|
|
|
143
146
|
tx = builder.tx(
|
|
144
147
|
input_value: unspent,
|
|
145
148
|
leave_fee: true,
|
|
146
|
-
extra_fee: [f,
|
|
149
|
+
extra_fee: [f, (size * MIN_SATOSHI_PER_BYTE).to_i].max,
|
|
147
150
|
change_address: change
|
|
148
151
|
)
|
|
149
152
|
left = unspent - tx.outputs.sum(&:value)
|
|
@@ -152,7 +155,7 @@ class Sibit
|
|
|
152
155
|
#{tx.inputs.map { |i| " in: #{i.prev_out.unpack1('H*')}:#{i.prev_out_index}" }.join("\n ")}
|
|
153
156
|
#{tx.out.count} output#{'s' if tx.out.count > 1}:
|
|
154
157
|
#{tx.outputs.map { |o| "out: #{o.script_hex} / #{num(o.value, p)}" }.join("\n ")}
|
|
155
|
-
Min
|
|
158
|
+
Min fee: #{num(MIN_SATOSHI_PER_BYTE, p)} s/byte
|
|
156
159
|
Fee requested: #{num(f, p)} as \"#{fee}\"
|
|
157
160
|
Fee actually paid: #{num(left, p)}
|
|
158
161
|
Tx size: #{size} bytes
|
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.
|
|
4
|
+
version: 0.30.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Yegor Bugayenko
|
|
@@ -162,6 +162,7 @@ files:
|
|
|
162
162
|
- features/support/env.rb
|
|
163
163
|
- lib/sibit.rb
|
|
164
164
|
- lib/sibit/base58.rb
|
|
165
|
+
- lib/sibit/bech32.rb
|
|
165
166
|
- lib/sibit/bestof.rb
|
|
166
167
|
- lib/sibit/bitcoinchain.rb
|
|
167
168
|
- lib/sibit/blockchain.rb
|