bitcoinrb 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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]
|