bitcoinrb 0.5.0 → 0.6.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/.ruby-version +1 -1
- data/.travis.yml +5 -4
- data/README.md +10 -0
- data/bitcoinrb.gemspec +4 -4
- data/lib/bitcoin.rb +29 -16
- data/lib/bitcoin/block_filter.rb +14 -0
- data/lib/bitcoin/chain_params.rb +9 -0
- data/lib/bitcoin/chainparams/signet.yml +39 -0
- data/lib/bitcoin/constants.rb +43 -3
- data/lib/bitcoin/descriptor.rb +1 -1
- data/lib/bitcoin/errors.rb +19 -0
- data/lib/bitcoin/ext/ecdsa.rb +31 -0
- data/lib/bitcoin/ext_key.rb +35 -19
- data/lib/bitcoin/key.rb +43 -26
- data/lib/bitcoin/message/cfcheckpt.rb +2 -2
- data/lib/bitcoin/message/cfheaders.rb +1 -1
- data/lib/bitcoin/message/cfilter.rb +1 -1
- data/lib/bitcoin/message/fee_filter.rb +1 -1
- data/lib/bitcoin/message/filter_load.rb +3 -3
- data/lib/bitcoin/message/header_and_short_ids.rb +1 -1
- data/lib/bitcoin/message/inventory.rb +1 -1
- data/lib/bitcoin/message/merkle_block.rb +1 -1
- data/lib/bitcoin/message/network_addr.rb +3 -3
- data/lib/bitcoin/message/ping.rb +1 -1
- data/lib/bitcoin/message/pong.rb +1 -1
- data/lib/bitcoin/message/send_cmpct.rb +2 -2
- data/lib/bitcoin/mnemonic.rb +2 -2
- data/lib/bitcoin/network/peer_discovery.rb +1 -3
- data/lib/bitcoin/node/configuration.rb +3 -1
- data/lib/bitcoin/node/spv.rb +8 -0
- data/lib/bitcoin/opcodes.rb +14 -1
- data/lib/bitcoin/payment_code.rb +2 -2
- data/lib/bitcoin/psbt/hd_key_path.rb +1 -1
- data/lib/bitcoin/psbt/input.rb +3 -3
- data/lib/bitcoin/psbt/output.rb +1 -1
- data/lib/bitcoin/psbt/tx.rb +4 -4
- data/lib/bitcoin/rpc/bitcoin_core_client.rb +1 -1
- data/lib/bitcoin/script/script.rb +52 -19
- data/lib/bitcoin/script/script_error.rb +27 -1
- data/lib/bitcoin/script/script_interpreter.rb +161 -62
- data/lib/bitcoin/script/tx_checker.rb +64 -14
- data/lib/bitcoin/secp256k1/native.rb +138 -25
- data/lib/bitcoin/secp256k1/ruby.rb +78 -19
- data/lib/bitcoin/sighash_generator.rb +156 -0
- data/lib/bitcoin/tx.rb +13 -80
- data/lib/bitcoin/tx_in.rb +1 -1
- data/lib/bitcoin/tx_out.rb +2 -3
- data/lib/bitcoin/util.rb +15 -6
- data/lib/bitcoin/version.rb +1 -1
- data/lib/bitcoin/wallet/account.rb +1 -1
- metadata +19 -15
data/lib/bitcoin/key.rb
CHANGED
@@ -28,7 +28,7 @@ module Bitcoin
|
|
28
28
|
# @param [Integer] key_type a key type which determine address type.
|
29
29
|
# @param [Boolean] compressed [Deprecated] whether public key is compressed.
|
30
30
|
# @return [Bitcoin::Key] a key object.
|
31
|
-
def initialize(priv_key: nil, pubkey: nil, key_type: nil, compressed: true)
|
31
|
+
def initialize(priv_key: nil, pubkey: nil, key_type: nil, compressed: true, allow_hybrid: false)
|
32
32
|
puts "[Warning] Use key_type parameter instead of compressed. compressed parameter removed in the future." if key_type.nil? && !compressed.nil? && pubkey.nil?
|
33
33
|
if key_type
|
34
34
|
@key_type = key_type
|
@@ -39,13 +39,14 @@ module Bitcoin
|
|
39
39
|
@secp256k1_module = Bitcoin.secp_impl
|
40
40
|
@priv_key = priv_key
|
41
41
|
if @priv_key
|
42
|
-
raise ArgumentError,
|
42
|
+
raise ArgumentError, Errors::Messages::INVALID_PRIV_KEY unless validate_private_key_range(@priv_key)
|
43
43
|
end
|
44
44
|
if pubkey
|
45
45
|
@pubkey = pubkey
|
46
46
|
else
|
47
47
|
@pubkey = generate_pubkey(priv_key, compressed: compressed) if priv_key
|
48
48
|
end
|
49
|
+
raise ArgumentError, Errors::Messages::INVALID_PUBLIC_KEY unless fully_valid_pubkey?(allow_hybrid)
|
49
50
|
end
|
50
51
|
|
51
52
|
# generate key pair
|
@@ -63,9 +64,9 @@ module Bitcoin
|
|
63
64
|
data = hex[2...-8].htb
|
64
65
|
checksum = hex[-8..-1]
|
65
66
|
raise ArgumentError, 'invalid version' unless version == Bitcoin.chain_params.privkey_version
|
66
|
-
raise ArgumentError,
|
67
|
+
raise ArgumentError, Errors::Messages::INVALID_CHECKSUM unless Bitcoin.calc_checksum(version + data.bth) == checksum
|
67
68
|
key_len = data.bytesize
|
68
|
-
if key_len == COMPRESSED_PUBLIC_KEY_SIZE && data[-1].
|
69
|
+
if key_len == COMPRESSED_PUBLIC_KEY_SIZE && data[-1].unpack1('C') == 1
|
69
70
|
key_type = TYPES[:compressed]
|
70
71
|
data = data[0..-2]
|
71
72
|
elsif key_len == 32
|
@@ -88,30 +89,46 @@ module Bitcoin
|
|
88
89
|
# sign +data+ with private key
|
89
90
|
# @param [String] data a data to be signed with binary format
|
90
91
|
# @param [Boolean] low_r flag to apply low-R.
|
91
|
-
# @param [String] extra_entropy the extra entropy for rfc6979.
|
92
|
+
# @param [String] extra_entropy the extra entropy with binary format for rfc6979.
|
93
|
+
# @param [Symbol] algo signature algorithm. ecdsa(default) or schnorr.
|
92
94
|
# @return [String] signature data with binary format
|
93
|
-
def sign(data, low_r = true, extra_entropy = nil)
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
95
|
+
def sign(data, low_r = true, extra_entropy = nil, algo: :ecdsa)
|
96
|
+
case algo
|
97
|
+
when :ecdsa
|
98
|
+
sig = secp256k1_module.sign_data(data, priv_key, extra_entropy)
|
99
|
+
if low_r && !sig_has_low_r?(sig)
|
100
|
+
counter = 1
|
101
|
+
until sig_has_low_r?(sig)
|
102
|
+
extra_entropy = [counter].pack('I*').bth.ljust(64, '0').htb
|
103
|
+
sig = secp256k1_module.sign_data(data, priv_key, extra_entropy)
|
104
|
+
counter += 1
|
105
|
+
end
|
101
106
|
end
|
107
|
+
sig
|
108
|
+
when :schnorr
|
109
|
+
secp256k1_module.sign_data(data, priv_key, extra_entropy, algo: :schnorr)
|
110
|
+
else
|
111
|
+
raise ArgumentError "Unsupported algo specified: #{algo}"
|
102
112
|
end
|
103
|
-
sig
|
104
113
|
end
|
105
114
|
|
106
115
|
# verify signature using public key
|
107
116
|
# @param [String] sig signature data with binary format
|
108
|
-
# @param [String]
|
117
|
+
# @param [String] data original message
|
118
|
+
# @param [Symbol] algo signature algorithm. ecdsa(default) or schnorr.
|
109
119
|
# @return [Boolean] verify result
|
110
|
-
def verify(sig,
|
120
|
+
def verify(sig, data, algo: :ecdsa)
|
111
121
|
return false unless valid_pubkey?
|
112
122
|
begin
|
113
|
-
|
114
|
-
|
123
|
+
case algo
|
124
|
+
when :ecdsa
|
125
|
+
sig = ecdsa_signature_parse_der_lax(sig)
|
126
|
+
secp256k1_module.verify_sig(data, sig, pubkey)
|
127
|
+
when :schnorr
|
128
|
+
secp256k1_module.verify_sig(data, sig, xonly_pubkey, algo: :schnorr)
|
129
|
+
else
|
130
|
+
false
|
131
|
+
end
|
115
132
|
rescue Exception
|
116
133
|
false
|
117
134
|
end
|
@@ -152,6 +169,12 @@ module Bitcoin
|
|
152
169
|
ECDSA::Format::PointOctetString.decode(p.htb, Bitcoin::Secp256k1::GROUP)
|
153
170
|
end
|
154
171
|
|
172
|
+
# get xonly public key (32 bytes).
|
173
|
+
# @return [String] xonly public key with hex format
|
174
|
+
def xonly_pubkey
|
175
|
+
pubkey[2..65]
|
176
|
+
end
|
177
|
+
|
155
178
|
# check +pubkey+ (hex) is compress or uncompress pubkey.
|
156
179
|
def self.compress_or_uncompress_pubkey?(pubkey)
|
157
180
|
p = pubkey.htb
|
@@ -225,14 +248,8 @@ module Bitcoin
|
|
225
248
|
end
|
226
249
|
|
227
250
|
# fully validate whether this is a valid public key (more expensive than IsValid())
|
228
|
-
def fully_valid_pubkey?
|
229
|
-
|
230
|
-
begin
|
231
|
-
point = ECDSA::Format::PointOctetString.decode(pubkey.htb, ECDSA::Group::Secp256k1)
|
232
|
-
ECDSA::Group::Secp256k1.valid_public_key?(point)
|
233
|
-
rescue ECDSA::Format::DecodeError
|
234
|
-
false
|
235
|
-
end
|
251
|
+
def fully_valid_pubkey?(allow_hybrid = false)
|
252
|
+
valid_pubkey? && secp256k1_module.parse_ec_pubkey?(pubkey, allow_hybrid)
|
236
253
|
end
|
237
254
|
|
238
255
|
private
|
@@ -19,8 +19,8 @@ module Bitcoin
|
|
19
19
|
|
20
20
|
def self.parse_from_payload(payload)
|
21
21
|
buf = StringIO.new(payload)
|
22
|
-
type = buf.read(1).
|
23
|
-
hash = buf.read(32).
|
22
|
+
type = buf.read(1).unpack1('C')
|
23
|
+
hash = buf.read(32).unpack1('H*')
|
24
24
|
count = Bitcoin.unpack_var_int_from_io(buf)
|
25
25
|
headers = count.times.map{buf.read(32).bth}
|
26
26
|
self.new(type, hash, headers)
|
@@ -21,7 +21,7 @@ module Bitcoin
|
|
21
21
|
|
22
22
|
def self.parse_from_payload(payload)
|
23
23
|
buf = StringIO.new(payload)
|
24
|
-
type = buf.read(1).
|
24
|
+
type = buf.read(1).unpack1("C")
|
25
25
|
hash = buf.read(32).bth
|
26
26
|
header = buf.read(32).bth
|
27
27
|
count = Bitcoin.unpack_var_int_from_io(buf)
|
@@ -19,7 +19,7 @@ module Bitcoin
|
|
19
19
|
|
20
20
|
def self.parse_from_payload(payload)
|
21
21
|
buf = StringIO.new(payload)
|
22
|
-
type = buf.read(1).
|
22
|
+
type = buf.read(1).unpack1("C")
|
23
23
|
hash = buf.read(32).bth
|
24
24
|
len = Bitcoin.unpack_var_int_from_io(buf)
|
25
25
|
filter = buf.read(len).bth
|
@@ -23,9 +23,9 @@ module Bitcoin
|
|
23
23
|
buf = StringIO.new(payload)
|
24
24
|
filter_count = Bitcoin.unpack_var_int_from_io(buf)
|
25
25
|
filter = buf.read(filter_count).unpack('C*')
|
26
|
-
func_count = buf.read(4).
|
27
|
-
tweak = buf.read(4).
|
28
|
-
flag = buf.read(1).
|
26
|
+
func_count = buf.read(4).unpack1('V')
|
27
|
+
tweak = buf.read(4).unpack1('V')
|
28
|
+
flag = buf.read(1).unpack1('C')
|
29
29
|
FilterLoad.new(Bitcoin::BloomFilter.new(filter, func_count, tweak), flag)
|
30
30
|
end
|
31
31
|
|
@@ -22,7 +22,7 @@ module Bitcoin
|
|
22
22
|
def self.parse_from_payload(payload)
|
23
23
|
buf = StringIO.new(payload)
|
24
24
|
header = Bitcoin::BlockHeader.parse_from_payload(buf.read(80))
|
25
|
-
nonce = buf.read(8).
|
25
|
+
nonce = buf.read(8).unpack1('q*')
|
26
26
|
short_ids_len = Bitcoin.unpack_var_int_from_io(buf)
|
27
27
|
short_ids = short_ids_len.times.map do
|
28
28
|
buf.read(6).reverse.bth.to_i(16)
|
@@ -26,7 +26,7 @@ module Bitcoin
|
|
26
26
|
# parse inventory payload
|
27
27
|
def self.parse_from_payload(payload)
|
28
28
|
raise Error, 'invalid inventory size.' if payload.bytesize != 36
|
29
|
-
identifier = payload[0..4].
|
29
|
+
identifier = payload[0..4].unpack1('V')
|
30
30
|
hash = payload[4..-1].bth # internal byte order
|
31
31
|
new(identifier, hash)
|
32
32
|
end
|
@@ -20,7 +20,7 @@ module Bitcoin
|
|
20
20
|
m = new
|
21
21
|
buf = StringIO.new(payload)
|
22
22
|
m.header = Bitcoin::BlockHeader.parse_from_payload(buf.read(80))
|
23
|
-
m.tx_count = buf.read(4).
|
23
|
+
m.tx_count = buf.read(4).unpack1('V')
|
24
24
|
hash_count = Bitcoin.unpack_var_int_from_io(buf)
|
25
25
|
hash_count.times do
|
26
26
|
m.hashes << buf.read(32).bth
|
@@ -31,10 +31,10 @@ module Bitcoin
|
|
31
31
|
buf = payload.is_a?(String) ? StringIO.new(payload) : payload
|
32
32
|
has_time = buf.size > 26
|
33
33
|
addr = new(time: nil)
|
34
|
-
addr.time = buf.read(4).
|
35
|
-
addr.services = buf.read(8).
|
34
|
+
addr.time = buf.read(4).unpack1('V') if has_time
|
35
|
+
addr.services = buf.read(8).unpack1('Q')
|
36
36
|
addr.ip_addr = IPAddr::new_ntoh(buf.read(16))
|
37
|
-
addr.port = buf.read(2).
|
37
|
+
addr.port = buf.read(2).unpack1('n')
|
38
38
|
addr
|
39
39
|
end
|
40
40
|
|
data/lib/bitcoin/message/ping.rb
CHANGED
data/lib/bitcoin/message/pong.rb
CHANGED
@@ -21,8 +21,8 @@ module Bitcoin
|
|
21
21
|
|
22
22
|
def self.parse_from_payload(payload)
|
23
23
|
buf = StringIO.new(payload)
|
24
|
-
mode = buf.read(1).
|
25
|
-
version = buf.read(8).
|
24
|
+
mode = buf.read(1).unpack1('c')
|
25
|
+
version = buf.read(8).unpack1('Q')
|
26
26
|
new(mode, version)
|
27
27
|
end
|
28
28
|
|
data/lib/bitcoin/mnemonic.rb
CHANGED
@@ -39,7 +39,7 @@ module Bitcoin
|
|
39
39
|
# @return [Array] the array of mnemonic word.
|
40
40
|
def to_mnemonic(entropy)
|
41
41
|
raise ArgumentError, 'entropy is empty.' if entropy.nil? || entropy.empty?
|
42
|
-
e = entropy.htb.
|
42
|
+
e = entropy.htb.unpack1('B*')
|
43
43
|
seed = e + checksum(e)
|
44
44
|
mnemonic_index = seed.chars.each_slice(11).map{|i|i.join.to_i(2)}
|
45
45
|
word_master = load_words
|
@@ -61,7 +61,7 @@ module Bitcoin
|
|
61
61
|
# @param [String] entropy an entropy with bit string format
|
62
62
|
# @return [String] an entropy checksum with bit string format
|
63
63
|
def checksum(entropy)
|
64
|
-
b = Bitcoin.sha256([entropy].pack('B*')).
|
64
|
+
b = Bitcoin.sha256([entropy].pack('B*')).unpack1('B*')
|
65
65
|
b.slice(0, (entropy.length/32))
|
66
66
|
end
|
67
67
|
|
@@ -30,9 +30,7 @@ module Bitcoin
|
|
30
30
|
logger.debug 'discover peer address from DNS seeds.'
|
31
31
|
dns_seeds.map { |seed|
|
32
32
|
begin
|
33
|
-
#
|
34
|
-
# https://github.com/bitcoin/bitcoin/pull/8083#issuecomment-221552835
|
35
|
-
Socket.getaddrinfo("x5.#{seed}", Bitcoin.chain_params.default_port).map{|a|a[2]}.uniq
|
33
|
+
Socket.getaddrinfo("#{seed}", Bitcoin.chain_params.default_port).map{|a|a[2]}.uniq
|
36
34
|
rescue SocketError => e
|
37
35
|
logger.error "SocketError occurred when load DNS seed: #{seed}, error: #{e.message}"
|
38
36
|
nil
|
@@ -4,8 +4,10 @@ module Bitcoin
|
|
4
4
|
module Node
|
5
5
|
class Configuration
|
6
6
|
|
7
|
-
attr_reader :conf
|
7
|
+
attr_reader :conf # Hash
|
8
8
|
|
9
|
+
# initialize configuration
|
10
|
+
# @param [Hash] opts parameter for node.
|
9
11
|
def initialize(opts = {})
|
10
12
|
# TODO apply configuration file.
|
11
13
|
opts[:network] = :mainnet unless opts[:network]
|
data/lib/bitcoin/node/spv.rb
CHANGED
@@ -13,6 +13,14 @@ module Bitcoin
|
|
13
13
|
attr_accessor :wallet
|
14
14
|
attr_accessor :bloom
|
15
15
|
|
16
|
+
# Initialize spv settings
|
17
|
+
# @param [Bitcoin::Node::Configuration] configuration configuration for spv.
|
18
|
+
#
|
19
|
+
# ```ruby
|
20
|
+
# config = Bitcoin::Node::Configuration.new(network: :mainnet)
|
21
|
+
# spv = Bitcoin::Node::SPV.new(config)
|
22
|
+
# spv.run
|
23
|
+
# ````
|
16
24
|
def initialize(configuration)
|
17
25
|
@chain = Bitcoin::Store::SPVChain.new
|
18
26
|
@configuration = configuration
|
data/lib/bitcoin/opcodes.rb
CHANGED
@@ -136,6 +136,8 @@ module Bitcoin
|
|
136
136
|
OP_NOP9 = 0xb8
|
137
137
|
OP_NOP10 = 0xb9
|
138
138
|
|
139
|
+
OP_CHECKSIGADD = 0xba # BIP 342 opcodes (Tapscript)
|
140
|
+
|
139
141
|
# https://en.bitcoin.it/wiki/Script#Pseudo-words
|
140
142
|
OP_PUBKEYHASH = 0xfd
|
141
143
|
OP_PUBKEY = 0xfe
|
@@ -145,6 +147,9 @@ module Bitcoin
|
|
145
147
|
OPCODES_MAP = Hash[*(constants.grep(/^OP_/) - [:OP_NOP2, :OP_NOP3, :OP_CHECKLOCKTIMEVERIFY, :OP_CHECKSEQUENCEVERIFY]).map { |c| [const_get(c), c.to_s] }.flatten]
|
146
148
|
NAME_MAP = Hash[*constants.grep(/^OP_/).map { |c| [c.to_s, const_get(c)] }.flatten]
|
147
149
|
|
150
|
+
OP_SUCCESSES = [0x50, 0x62, 0x89, 0x8a, 0x8d, 0x8e, (0x7e..0x81).to_a,
|
151
|
+
(0x83..0x86).to_a, (0x95..0x99).to_a, (0xbb..0xfe).to_a].flatten
|
152
|
+
|
148
153
|
def opcode_to_name(opcode)
|
149
154
|
return OPCODES_MAP[opcode].delete('OP_') if opcode == OP_0 || (opcode <= OP_16 && opcode >= OP_1)
|
150
155
|
OPCODES_MAP[opcode]
|
@@ -156,7 +161,8 @@ module Bitcoin
|
|
156
161
|
end
|
157
162
|
|
158
163
|
# whether opcode is predefined opcode
|
159
|
-
def defined?(opcode)
|
164
|
+
def defined?(opcode, allow_success = false)
|
165
|
+
return true if allow_success && op_success?(opcode)
|
160
166
|
!opcode_to_name(opcode).nil?
|
161
167
|
end
|
162
168
|
|
@@ -174,5 +180,12 @@ module Bitcoin
|
|
174
180
|
nil
|
175
181
|
end
|
176
182
|
|
183
|
+
# Check whether +opcode+ is OP_SUCCESSx or not?
|
184
|
+
# @param [Integer] opcode an opcode.
|
185
|
+
# @return [Boolean] if +opcode+ is OP_SUCCESSx return true, otherwise false.
|
186
|
+
def op_success?(opcode)
|
187
|
+
OP_SUCCESSES.include?(opcode)
|
188
|
+
end
|
189
|
+
|
177
190
|
end
|
178
191
|
end
|
data/lib/bitcoin/payment_code.rb
CHANGED
@@ -61,8 +61,8 @@ module Bitcoin
|
|
61
61
|
raise ArgumentError, 'invalid version byte' unless hex[0..1] == VERSION_BYTE
|
62
62
|
raise ArgumentError, 'invalid version' unless PaymentCode.support_version?(version)
|
63
63
|
raise ArgumentError, 'invalid sign' unless PaymentCode.support_sign?(sign)
|
64
|
-
raise ArgumentError,
|
65
|
-
raise ArgumentError,
|
64
|
+
raise ArgumentError, Errors::Messages::INVALID_PUBLIC_KEY unless Bitcoin::Key.new(priv_key: nil, pubkey: sign + public_key).fully_valid_pubkey?
|
65
|
+
raise ArgumentError, Errors::Messages::INVALID_CHECKSUM unless Bitcoin.calc_checksum(payment_code) == hex[-8..-1]
|
66
66
|
|
67
67
|
x_value = payment_code[8..71]
|
68
68
|
chain_code_hex = payment_code[72..135]
|
@@ -12,7 +12,7 @@ module Bitcoin
|
|
12
12
|
pubkey = pubkey.encoding == Encoding::ASCII_8BIT ? pubkey : pubkey.htb
|
13
13
|
raise ArgumentError, 'Size of key was not the expected size for the type BIP32 keypath.' unless [Bitcoin::Key::PUBLIC_KEY_SIZE, Bitcoin::Key::COMPRESSED_PUBLIC_KEY_SIZE].include?(pubkey.bytesize)
|
14
14
|
pubkey = Bitcoin::Key.new(pubkey: pubkey.bth)
|
15
|
-
raise ArgumentError,
|
15
|
+
raise ArgumentError, Errors::Messages::INVALID_PUBLIC_KEY unless pubkey.fully_valid_pubkey?
|
16
16
|
@pubkey = pubkey.pubkey
|
17
17
|
@info = info
|
18
18
|
end
|
data/lib/bitcoin/psbt/input.rb
CHANGED
@@ -36,7 +36,7 @@ module Bitcoin
|
|
36
36
|
found_sep = true
|
37
37
|
break
|
38
38
|
end
|
39
|
-
key_type = buf.read(1).
|
39
|
+
key_type = buf.read(1).unpack1('C')
|
40
40
|
key = buf.read(key_len - 1)
|
41
41
|
value = buf.read(Bitcoin.unpack_var_int_from_io(buf))
|
42
42
|
|
@@ -54,13 +54,13 @@ module Bitcoin
|
|
54
54
|
raise ArgumentError, 'Size of key was not the expected size for the type partial signature pubkey.'
|
55
55
|
end
|
56
56
|
pubkey = Bitcoin::Key.new(pubkey: key.bth)
|
57
|
-
raise ArgumentError,
|
57
|
+
raise ArgumentError, Errors::Messages::INVALID_PUBLIC_KEY unless pubkey.fully_valid_pubkey?
|
58
58
|
raise ArgumentError, 'Duplicate Key, input partial signature for pubkey already provided.' if input.partial_sigs[pubkey.pubkey]
|
59
59
|
input.partial_sigs[pubkey.pubkey] = value
|
60
60
|
when PSBT_IN_TYPES[:sighash]
|
61
61
|
raise ArgumentError, 'Invalid input sighash type typed key.' unless key_len == 1
|
62
62
|
raise ArgumentError 'Duplicate Key, input sighash type already provided.' if input.sighash_type
|
63
|
-
input.sighash_type = value.
|
63
|
+
input.sighash_type = value.unpack1('I')
|
64
64
|
when PSBT_IN_TYPES[:redeem_script]
|
65
65
|
raise ArgumentError, 'Invalid redeemscript typed key.' unless key_len == 1
|
66
66
|
raise ArgumentError, 'Duplicate Key, input redeemScript already provided.' if input.redeem_script
|
data/lib/bitcoin/psbt/output.rb
CHANGED
data/lib/bitcoin/psbt/tx.rb
CHANGED
@@ -55,7 +55,7 @@ module Bitcoin
|
|
55
55
|
# @return [Bitcoin::PartiallySignedTx]
|
56
56
|
def self.parse_from_payload(payload)
|
57
57
|
buf = StringIO.new(payload)
|
58
|
-
raise ArgumentError, 'Invalid PSBT magic bytes.' unless buf.read(4).
|
58
|
+
raise ArgumentError, 'Invalid PSBT magic bytes.' unless buf.read(4).unpack1('N') == PSBT_MAGIC_BYTES
|
59
59
|
raise ArgumentError, 'Invalid PSBT separator.' unless buf.read(1).bth.to_i(16) == 0xff
|
60
60
|
partial_tx = self.new
|
61
61
|
found_sep = false
|
@@ -66,7 +66,7 @@ module Bitcoin
|
|
66
66
|
found_sep = true
|
67
67
|
break
|
68
68
|
end
|
69
|
-
key_type = buf.read(1).
|
69
|
+
key_type = buf.read(1).unpack1('C')
|
70
70
|
key = buf.read(key_len - 1)
|
71
71
|
value = buf.read(Bitcoin.unpack_var_int_from_io(buf))
|
72
72
|
|
@@ -81,13 +81,13 @@ module Bitcoin
|
|
81
81
|
when PSBT_GLOBAL_TYPES[:xpub]
|
82
82
|
raise ArgumentError, 'Size of key was not the expected size for the type global xpub.' unless key.size == Bitcoin::BIP32_EXTKEY_WITH_VERSION_SIZE
|
83
83
|
xpub = Bitcoin::ExtPubkey.parse_from_payload(key)
|
84
|
-
raise ArgumentError,
|
84
|
+
raise ArgumentError, Errors::Messages::INVALID_PUBLIC_KEY unless xpub.key.fully_valid_pubkey?
|
85
85
|
raise ArgumentError, 'Duplicate key, global xpub already provided' if partial_tx.xpubs.any?{|x|x.xpub == xpub}
|
86
86
|
info = Bitcoin::PSBT::KeyOriginInfo.parse_from_payload(value)
|
87
87
|
raise ArgumentError, "global xpub's depth and the number of indexes not matched." unless xpub.depth == info.key_paths.size
|
88
88
|
partial_tx.xpubs << Bitcoin::PSBT::GlobalXpub.new(xpub, info)
|
89
89
|
when PSBT_GLOBAL_TYPES[:ver]
|
90
|
-
partial_tx.version_number = value.
|
90
|
+
partial_tx.version_number = value.unpack1('V')
|
91
91
|
raise ArgumentError, "An unsupported version was detected." if SUPPORT_VERSION < partial_tx.version_number
|
92
92
|
else
|
93
93
|
raise ArgumentError, 'Duplicate Key, key for unknown value already provided.' if partial_tx.unknowns[key]
|