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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7463ec26890a5bd8515ce96c92190a50edaf46f5b94aed0a1b54261f0d63ca65
4
- data.tar.gz: 71be0a78c7bfcfffdebc6daa2c63a570d561b5e6e923f0d600e2791c2856cac5
3
+ metadata.gz: d3d770048c5c19650ec325dd100d556c798c58d27ae06c120569161dc5ede087
4
+ data.tar.gz: b8b19fa66905fcd77379c4ebe6892ed6e5ee7ceece7ae1cc46f8921a50bb8a0e
5
5
  SHA512:
6
- metadata.gz: ae0606a033a0506be0d3f397a0ac81bf51db53e7c35671256642764e2dcca358d95cbb9517c67c0a49f0621110926760154ea1c1c885d4aa5b6a2a32792078ff
7
- data.tar.gz: 21a0bf5f5e27f3c22ceb82f2432d3b3fdd8a4ae1181cbdad383d34f081024c4802b6c83c2a7f51c1205728ccede22c8e45c8498f2d74ffd04282f828b29b4c54
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 { |c| num = (num * 58) + ALPHABET.index(c) }
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
@@ -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
- hash160 = address_to_hash160(@address)
102
- [0x76, 0xa9, 0x14].pack('C*') + [hash160].pack('H*') + [0x88, 0xac].pack('C*')
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 address_to_hash160(addr)
112
- decoded = Base58.new(addr).decode
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
@@ -9,5 +9,5 @@
9
9
  # License:: MIT
10
10
  class Sibit
11
11
  # Current version of the library.
12
- VERSION = '0.30.2'
12
+ VERSION = '0.30.4' unless defined?(VERSION)
13
13
  end
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, MIN_TX_FEE].max,
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 tx fee: #{num(MIN_TX_FEE, p)}
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.2
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