bitcoinrb 0.2.8 → 0.2.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bitcoinrb.gemspec +1 -0
- data/lib/bitcoin.rb +1 -0
- data/lib/bitcoin/bit_stream.rb +1 -0
- data/lib/bitcoin/chain_params.rb +12 -3
- data/lib/bitcoin/chainparams/regtest.yml +2 -1
- data/lib/bitcoin/constants.rb +7 -0
- data/lib/bitcoin/ext_key.rb +16 -9
- data/lib/bitcoin/key_path.rb +26 -0
- data/lib/bitcoin/psbt.rb +2 -1
- data/lib/bitcoin/psbt/hd_key_path.rb +15 -16
- data/lib/bitcoin/psbt/input.rb +1 -1
- data/lib/bitcoin/psbt/key_origin_info.rb +34 -0
- data/lib/bitcoin/psbt/output.rb +1 -1
- data/lib/bitcoin/psbt/tx.rb +34 -0
- data/lib/bitcoin/script/script.rb +19 -5
- data/lib/bitcoin/store/spv_chain.rb +2 -0
- data/lib/bitcoin/tx.rb +15 -1
- data/lib/bitcoin/tx_out.rb +24 -0
- data/lib/bitcoin/version.rb +1 -1
- data/lib/bitcoin/wallet/master_key.rb +2 -9
- metadata +18 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: db45450b62847b14f755e93063e237e6f521a30de9125659dd2325b1b445d5b2
|
4
|
+
data.tar.gz: b1e446e457bdad6cc7d5449ffd7a97cf26fba50f0ec85659aa53584a01ac998d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 67767d3f68b7b1656730a43e1dce32c9dff0b43cdd603f813e6de1c4a1b3fe4c5c51784d6afb356db42a2cc230c2fa559e1ebc2f0992afe3bb55b3d635a05ffe
|
7
|
+
data.tar.gz: 4d38a01b81e90b79836c47cfd4912b6f70aba0ca257627fc0aba368ace227ee475b3205263e011c84fc00b43de4e33719b72c65fdddcb81210f5f35b19ba3bbd
|
data/bitcoinrb.gemspec
CHANGED
@@ -34,6 +34,7 @@ Gem::Specification.new do |spec|
|
|
34
34
|
spec.add_runtime_dependency 'siphash'
|
35
35
|
spec.add_runtime_dependency 'protobuf', '3.8.5'
|
36
36
|
spec.add_runtime_dependency 'scrypt'
|
37
|
+
spec.add_runtime_dependency 'activesupport', '~> 5.2.3'
|
37
38
|
|
38
39
|
# for options
|
39
40
|
spec.add_development_dependency 'leveldb-ruby'
|
data/lib/bitcoin.rb
CHANGED
data/lib/bitcoin/bit_stream.rb
CHANGED
data/lib/bitcoin/chain_params.rb
CHANGED
@@ -34,22 +34,24 @@ module Bitcoin
|
|
34
34
|
attr_reader :genesis
|
35
35
|
attr_reader :bip44_coin_type
|
36
36
|
|
37
|
+
attr_accessor :dust_relay_fee
|
38
|
+
|
37
39
|
# fork coin id.
|
38
40
|
attr_accessor :fork_id
|
39
41
|
|
40
42
|
# mainnet genesis
|
41
43
|
def self.mainnet
|
42
|
-
|
44
|
+
init('mainnet')
|
43
45
|
end
|
44
46
|
|
45
47
|
# testnet genesis
|
46
48
|
def self.testnet
|
47
|
-
|
49
|
+
init('testnet')
|
48
50
|
end
|
49
51
|
|
50
52
|
# regtest genesis
|
51
53
|
def self.regtest
|
52
|
-
|
54
|
+
init('regtest')
|
53
55
|
end
|
54
56
|
|
55
57
|
def mainnet?
|
@@ -76,6 +78,13 @@ module Bitcoin
|
|
76
78
|
!fork_id.nil?
|
77
79
|
end
|
78
80
|
|
81
|
+
def self.init(name)
|
82
|
+
i = YAML.load(File.open("#{__dir__}/chainparams/#{name}.yml"))
|
83
|
+
i.dust_relay_fee ||= Bitcoin::DUST_RELAY_TX_FEE
|
84
|
+
i
|
85
|
+
end
|
86
|
+
|
87
|
+
private_class_method :init
|
79
88
|
end
|
80
89
|
|
81
90
|
end
|
data/lib/bitcoin/constants.rb
CHANGED
@@ -22,6 +22,9 @@ module Bitcoin
|
|
22
22
|
LOCKTIME_VERIFY_SEQUENCE = (1 << 0)
|
23
23
|
LOCKTIME_MEDIAN_TIME_PAST = (1 << 1)
|
24
24
|
|
25
|
+
# Min feerate for defining dust.
|
26
|
+
DUST_RELAY_TX_FEE = 3000
|
27
|
+
|
25
28
|
# script verify flags
|
26
29
|
SCRIPT_VERIFY_NONE = 0
|
27
30
|
SCRIPT_VERIFY_P2SH = (1 << 0)
|
@@ -185,4 +188,8 @@ module Bitcoin
|
|
185
188
|
|
186
189
|
# Size of set to pick median time from.
|
187
190
|
MEDIAN_TIME_SPAN = 11
|
191
|
+
|
192
|
+
BIP32_EXTKEY_WITH_VERSION_SIZE = 78
|
193
|
+
|
194
|
+
HARDENED_THRESHOLD = 2147483648 # 2**31
|
188
195
|
end
|
data/lib/bitcoin/ext_key.rb
CHANGED
@@ -3,8 +3,6 @@ module Bitcoin
|
|
3
3
|
# Integers modulo the order of the curve(secp256k1)
|
4
4
|
CURVE_ORDER = ECDSA::Group::Secp256k1.order
|
5
5
|
|
6
|
-
HARDENED_THRESHOLD = 2147483648 # 2**31
|
7
|
-
|
8
6
|
# BIP32 Extended private key
|
9
7
|
class ExtKey
|
10
8
|
|
@@ -85,7 +83,7 @@ module Bitcoin
|
|
85
83
|
|
86
84
|
# whether hardened key.
|
87
85
|
def hardened?
|
88
|
-
number >= HARDENED_THRESHOLD
|
86
|
+
number >= Bitcoin::HARDENED_THRESHOLD
|
89
87
|
end
|
90
88
|
|
91
89
|
# derive new key
|
@@ -93,12 +91,12 @@ module Bitcoin
|
|
93
91
|
# @param [Boolean] harden whether hardened key or not. If true, 2^31 is added to +number+.
|
94
92
|
# @return [Bitcoin::ExtKey] derived new key.
|
95
93
|
def derive(number, harden = false)
|
96
|
-
number += HARDENED_THRESHOLD if harden
|
94
|
+
number += Bitcoin::HARDENED_THRESHOLD if harden
|
97
95
|
new_key = ExtKey.new
|
98
96
|
new_key.depth = depth + 1
|
99
97
|
new_key.number = number
|
100
98
|
new_key.parent_fingerprint = fingerprint
|
101
|
-
if number > (HARDENED_THRESHOLD - 1)
|
99
|
+
if number > (Bitcoin::HARDENED_THRESHOLD - 1)
|
102
100
|
data = [0x00].pack('C') << key.priv_key.htb << [number].pack('N')
|
103
101
|
else
|
104
102
|
data = key.pubkey.htb << [number].pack('N')
|
@@ -134,6 +132,10 @@ module Bitcoin
|
|
134
132
|
end
|
135
133
|
end
|
136
134
|
|
135
|
+
def ==(other)
|
136
|
+
to_payload == other.to_payload
|
137
|
+
end
|
138
|
+
|
137
139
|
def self.parse_from_payload(payload)
|
138
140
|
buf = StringIO.new(payload)
|
139
141
|
ext_key = ExtKey.new
|
@@ -155,7 +157,7 @@ module Bitcoin
|
|
155
157
|
|
156
158
|
# get version bytes from purpose' value.
|
157
159
|
def self.version_from_purpose(purpose)
|
158
|
-
v = purpose - HARDENED_THRESHOLD
|
160
|
+
v = purpose - Bitcoin::HARDENED_THRESHOLD
|
159
161
|
case v
|
160
162
|
when 49
|
161
163
|
Bitcoin.chain_params.bip49_privkey_p2wpkh_p2sh_version
|
@@ -247,7 +249,7 @@ module Bitcoin
|
|
247
249
|
|
248
250
|
# whether hardened key.
|
249
251
|
def hardened?
|
250
|
-
number >= HARDENED_THRESHOLD
|
252
|
+
number >= Bitcoin::HARDENED_THRESHOLD
|
251
253
|
end
|
252
254
|
|
253
255
|
# derive child key
|
@@ -256,7 +258,7 @@ module Bitcoin
|
|
256
258
|
new_key.depth = depth + 1
|
257
259
|
new_key.number = number
|
258
260
|
new_key.parent_fingerprint = fingerprint
|
259
|
-
raise 'hardened key is not support' if number > (HARDENED_THRESHOLD - 1)
|
261
|
+
raise 'hardened key is not support' if number > (Bitcoin::HARDENED_THRESHOLD - 1)
|
260
262
|
data = pub.htb << [number].pack('N')
|
261
263
|
l = Bitcoin.hmac_sha512(chain_code, data)
|
262
264
|
left = l[0..31].bth.to_i(16)
|
@@ -288,6 +290,10 @@ module Bitcoin
|
|
288
290
|
end
|
289
291
|
end
|
290
292
|
|
293
|
+
def ==(other)
|
294
|
+
to_payload == other.to_payload
|
295
|
+
end
|
296
|
+
|
291
297
|
def self.parse_from_payload(payload)
|
292
298
|
buf = StringIO.new(payload)
|
293
299
|
ext_pubkey = ExtPubkey.new
|
@@ -301,6 +307,7 @@ module Bitcoin
|
|
301
307
|
ext_pubkey
|
302
308
|
end
|
303
309
|
|
310
|
+
|
304
311
|
# import pub key from Base58 private key address
|
305
312
|
def self.from_base58(address)
|
306
313
|
ExtPubkey.parse_from_payload(Base58.decode(address).htb)
|
@@ -308,7 +315,7 @@ module Bitcoin
|
|
308
315
|
|
309
316
|
# get version bytes from purpose' value.
|
310
317
|
def self.version_from_purpose(purpose)
|
311
|
-
v = purpose - HARDENED_THRESHOLD
|
318
|
+
v = purpose - Bitcoin::HARDENED_THRESHOLD
|
312
319
|
case v
|
313
320
|
when 49
|
314
321
|
Bitcoin.chain_params.bip49_pubkey_p2wpkh_p2sh_version
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Bitcoin
|
2
|
+
module KeyPath
|
3
|
+
|
4
|
+
# key path convert an array of derive number
|
5
|
+
# @param [String] path_string
|
6
|
+
# @return [Array[Integer]] key path numbers.
|
7
|
+
def parse_key_path(path_string)
|
8
|
+
path_string.split('/').map.with_index do|p, index|
|
9
|
+
if index == 0
|
10
|
+
raise ArgumentError.new("#{path_string} is invalid format.") unless p == 'm'
|
11
|
+
next
|
12
|
+
end
|
13
|
+
raise ArgumentError.new("#{path_string} is invalid format.") unless p.delete("'") =~ /^[0-9]+$/
|
14
|
+
(p[-1] == "'" ? p.delete("'").to_i + Bitcoin::HARDENED_THRESHOLD : p.to_i)
|
15
|
+
end[1..-1]
|
16
|
+
end
|
17
|
+
|
18
|
+
# key path numbers convert to path string.
|
19
|
+
# @param [Array[Integer]] key path numbers.
|
20
|
+
# @return [String] path string.
|
21
|
+
def to_key_path(numbers)
|
22
|
+
"m/#{numbers.map{|p| p >= Bitcoin::HARDENED_THRESHOLD ? "#{p - Bitcoin::HARDENED_THRESHOLD}'" : p.to_s}.join('/')}"
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
data/lib/bitcoin/psbt.rb
CHANGED
@@ -7,11 +7,12 @@ module Bitcoin
|
|
7
7
|
autoload :Tx, 'bitcoin/psbt/tx'
|
8
8
|
autoload :Input, 'bitcoin/psbt/input'
|
9
9
|
autoload :Output, 'bitcoin/psbt/output'
|
10
|
+
autoload :KeyOriginInfo, 'bitcoin/psbt/key_origin_info'
|
10
11
|
autoload :HDKeyPath, 'bitcoin/psbt/hd_key_path'
|
11
12
|
|
12
13
|
# constants for PSBT
|
13
14
|
PSBT_MAGIC_BYTES = 0x70736274
|
14
|
-
PSBT_GLOBAL_TYPES = {unsigned_tx: 0x00}
|
15
|
+
PSBT_GLOBAL_TYPES = {unsigned_tx: 0x00, xpub: 0x01}
|
15
16
|
PSBT_IN_TYPES = {non_witness_utxo: 0x00, witness_utxo: 0x01, partial_sig: 0x02,
|
16
17
|
sighash: 0x03, redeem_script: 0x04, witness_script: 0x05,
|
17
18
|
bip32_derivation: 0x06, script_sig: 0x07, script_witness: 0x08}
|
@@ -5,31 +5,30 @@ module Bitcoin
|
|
5
5
|
# see https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki#Specification
|
6
6
|
class HDKeyPath
|
7
7
|
|
8
|
-
attr_reader :pubkey
|
9
|
-
|
10
|
-
attr_reader :path
|
8
|
+
attr_reader :pubkey # String
|
9
|
+
attr_reader :info # KeyOriginInfo
|
11
10
|
|
12
|
-
def initialize(pubkey,
|
13
|
-
|
14
|
-
@fingerprint = fingerprint
|
15
|
-
@path = path
|
16
|
-
end
|
17
|
-
|
18
|
-
# parse hd key path from payload.
|
19
|
-
# @param [String] pubkey a public key with binary format.
|
20
|
-
# @param [String] payload hd key path value with binary format.
|
21
|
-
# @return [Bitcoin::PSBT::HDKeyPath]
|
22
|
-
def self.parse_from_payload(pubkey, payload)
|
11
|
+
def initialize(pubkey, info)
|
12
|
+
pubkey = pubkey.encoding == Encoding::ASCII_8BIT ? pubkey : pubkey.htb
|
23
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)
|
24
14
|
pubkey = Bitcoin::Key.new(pubkey: pubkey.bth)
|
25
15
|
raise ArgumentError, 'Invalid pubkey' unless pubkey.fully_valid_pubkey?
|
26
|
-
|
16
|
+
@pubkey = pubkey.pubkey
|
17
|
+
@info = info
|
27
18
|
end
|
28
19
|
|
29
20
|
# generate payload which consist of pubkey and fingerprint, hd key path payload.
|
30
21
|
# @return [String] a payload
|
31
22
|
def to_payload(type = PSBT_IN_TYPES[:bip32_derivation])
|
32
|
-
PSBT.serialize_to_vector(type, key: pubkey.htb, value:
|
23
|
+
PSBT.serialize_to_vector(type, key: pubkey.htb, value: info.to_payload)
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_h
|
27
|
+
{pubkey: pubkey}.merge(info.to_h)
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_s
|
31
|
+
to_h.to_s
|
33
32
|
end
|
34
33
|
|
35
34
|
end
|
data/lib/bitcoin/psbt/input.rb
CHANGED
@@ -72,7 +72,7 @@ module Bitcoin
|
|
72
72
|
when PSBT_IN_TYPES[:bip32_derivation]
|
73
73
|
raise ArgumentError, 'Invalid bip32 typed key.' unless key_len
|
74
74
|
raise ArgumentError, 'Duplicate Key, pubkey derivation path already provided.' if input.hd_key_paths[key.bth]
|
75
|
-
input.hd_key_paths[key.bth] = Bitcoin::PSBT::HDKeyPath.
|
75
|
+
input.hd_key_paths[key.bth] = Bitcoin::PSBT::HDKeyPath.new(key, Bitcoin::PSBT::KeyOriginInfo.parse_from_payload(value))
|
76
76
|
when PSBT_IN_TYPES[:script_sig]
|
77
77
|
raise ArgumentError, 'Invalid final scriptsig typed key.' unless key_len == 1
|
78
78
|
raise ArgumentError, 'Duplicate Key, input final scriptSig already provided.' if input.final_script_sig
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Bitcoin
|
2
|
+
module PSBT
|
3
|
+
|
4
|
+
class KeyOriginInfo
|
5
|
+
|
6
|
+
include Bitcoin::KeyPath
|
7
|
+
|
8
|
+
attr_reader :fingerprint # String hex format
|
9
|
+
attr_reader :key_paths # Array[Integer]
|
10
|
+
|
11
|
+
def initialize(fingerprint: nil, key_paths: [])
|
12
|
+
@fingerprint = fingerprint
|
13
|
+
@key_paths = key_paths
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.parse_from_payload(payload)
|
17
|
+
buf = StringIO.new(payload)
|
18
|
+
self.new(fingerprint: buf.read(4).bth, key_paths: buf.read.unpack('I*'))
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_payload
|
22
|
+
fingerprint.htb + key_paths.pack('I*')
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_h
|
26
|
+
{fingerprint: fingerprint, key_paths: to_key_path(key_paths)}
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_s
|
30
|
+
to_h.to_s
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/bitcoin/psbt/output.rb
CHANGED
@@ -40,7 +40,7 @@ module Bitcoin
|
|
40
40
|
output.witness_script = value
|
41
41
|
when PSBT_OUT_TYPES[:bip32_derivation]
|
42
42
|
raise ArgumentError, 'Duplicate Key, pubkey derivation path already provided' if output.hd_key_paths[key.bth]
|
43
|
-
output.hd_key_paths[key.bth] = Bitcoin::PSBT::HDKeyPath.
|
43
|
+
output.hd_key_paths[key.bth] = Bitcoin::PSBT::HDKeyPath.new(key, Bitcoin::PSBT::KeyOriginInfo.parse_from_payload(value))
|
44
44
|
else
|
45
45
|
unknown_key = ([key_type].pack('C') + key).bth
|
46
46
|
raise ArgumentError, 'Duplicate Key, key for unknown value already provided' if output.unknowns[unknown_key]
|
data/lib/bitcoin/psbt/tx.rb
CHANGED
@@ -1,14 +1,39 @@
|
|
1
1
|
module Bitcoin
|
2
2
|
module PSBT
|
3
3
|
|
4
|
+
class GlobalXpub
|
5
|
+
|
6
|
+
attr_reader :xpub # Bitcoin::ExtPubkey
|
7
|
+
attr_reader :info # Bitcoin::PSBT::KeyOriginInfo
|
8
|
+
|
9
|
+
def initialize(xpub, info)
|
10
|
+
@xpub = xpub
|
11
|
+
@info = info
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_payload
|
15
|
+
PSBT.serialize_to_vector(PSBT_GLOBAL_TYPES[:xpub], key: xpub.to_payload, value: info.to_payload)
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_h
|
19
|
+
{xpub: xpub.to_payload.bth}.merge(info.to_h)
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_s
|
23
|
+
to_h.to_s
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
4
27
|
class Tx
|
5
28
|
attr_accessor :tx
|
29
|
+
attr_accessor :xpubs
|
6
30
|
attr_reader :inputs
|
7
31
|
attr_reader :outputs
|
8
32
|
attr_accessor :unknowns
|
9
33
|
|
10
34
|
def initialize(tx = nil)
|
11
35
|
@tx = tx
|
36
|
+
@xpubs = []
|
12
37
|
@inputs = tx ? tx.in.map{Input.new}: []
|
13
38
|
@outputs = tx ? tx.out.map{Output.new}: []
|
14
39
|
@unknowns = {}
|
@@ -49,6 +74,14 @@ module Bitcoin
|
|
49
74
|
partial_tx.tx.in.each do |tx_in|
|
50
75
|
raise ArgumentError, 'Unsigned tx does not have empty scriptSigs and scriptWitnesses.' if !tx_in.script_sig.empty? || !tx_in.script_witness.empty?
|
51
76
|
end
|
77
|
+
when PSBT_GLOBAL_TYPES[:xpub]
|
78
|
+
raise ArgumentError, 'Size of key was not the expected size for the type global xpub.' unless key.size == Bitcoin::BIP32_EXTKEY_WITH_VERSION_SIZE
|
79
|
+
xpub = Bitcoin::ExtPubkey.parse_from_payload(key)
|
80
|
+
raise ArgumentError, 'Invalid pubkey.' unless xpub.key.fully_valid_pubkey?
|
81
|
+
raise ArgumentError, 'Duplicate key, global xpub already provided' if partial_tx.xpubs.any?{|x|x.xpub == xpub}
|
82
|
+
info = Bitcoin::PSBT::KeyOriginInfo.parse_from_payload(value)
|
83
|
+
raise ArgumentError, "global xpub's depth and the number of indexes not matched." unless xpub.depth == info.key_paths.size
|
84
|
+
partial_tx.xpubs << Bitcoin::PSBT::GlobalXpub.new(xpub, info)
|
52
85
|
else
|
53
86
|
raise ArgumentError, 'Duplicate Key, key for unknown value already provided.' if partial_tx.unknowns[key]
|
54
87
|
partial_tx.unknowns[([key_type].pack('C') + key).bth] = value
|
@@ -104,6 +137,7 @@ module Bitcoin
|
|
104
137
|
payload = PSBT_MAGIC_BYTES.itb << 0xff.itb
|
105
138
|
|
106
139
|
payload << PSBT.serialize_to_vector(PSBT_GLOBAL_TYPES[:unsigned_tx], value: tx.to_payload)
|
140
|
+
payload << xpubs.map(&:to_payload).join
|
107
141
|
|
108
142
|
payload << unknowns.map {|k,v|Bitcoin.pack_var_int(k.htb.bytesize) << k.htb << Bitcoin.pack_var_int(v.bytesize) << v}.join
|
109
143
|
|
@@ -58,7 +58,6 @@ module Bitcoin
|
|
58
58
|
new << m << pubkeys << pubkeys.size << OP_CHECKMULTISIG
|
59
59
|
end
|
60
60
|
|
61
|
-
|
62
61
|
# generate p2wsh script for +redeem_script+
|
63
62
|
# @param [Script] redeem_script target redeem script
|
64
63
|
# @param [Script] p2wsh script
|
@@ -144,10 +143,6 @@ module Bitcoin
|
|
144
143
|
chunks.join
|
145
144
|
end
|
146
145
|
|
147
|
-
def to_hex
|
148
|
-
to_payload.bth
|
149
|
-
end
|
150
|
-
|
151
146
|
def empty?
|
152
147
|
chunks.size == 0
|
153
148
|
end
|
@@ -219,6 +214,12 @@ module Bitcoin
|
|
219
214
|
true
|
220
215
|
end
|
221
216
|
|
217
|
+
# get public keys in the stack.
|
218
|
+
# @return[Array[String]] an array of the pubkeys with hex format.
|
219
|
+
def get_pubkeys
|
220
|
+
chunks.select{|c|c.pushdata? && [33, 65].include?(c.pushed_data.bytesize) && [2, 3, 4, 6, 7].include?(c.pushed_data[0].bth.to_i(16))}.map{|c|c.pushed_data.bth}
|
221
|
+
end
|
222
|
+
|
222
223
|
# A witness program is any valid Script that consists of a 1-byte push opcode followed by a data push between 2 and 40 bytes.
|
223
224
|
def witness_program?
|
224
225
|
return false if size < 4 || size > 42 || chunks.size < 2
|
@@ -495,6 +496,19 @@ module Bitcoin
|
|
495
496
|
h
|
496
497
|
end
|
497
498
|
|
499
|
+
# Returns whether the script is guaranteed to fail at execution, regardless of the initial stack.
|
500
|
+
# This allows outputs to be pruned instantly when entering the UTXO set.
|
501
|
+
# @return [Boolean] whether the script is guaranteed to fail at execution
|
502
|
+
def unspendable?
|
503
|
+
(size > 0 && op_return?) || size > Bitcoin::MAX_SCRIPT_SIZE
|
504
|
+
end
|
505
|
+
|
506
|
+
# convert payload to hex data.
|
507
|
+
# @return [String] script with hex format.
|
508
|
+
def to_hex
|
509
|
+
to_payload.bth
|
510
|
+
end
|
511
|
+
|
498
512
|
private
|
499
513
|
|
500
514
|
# generate p2pkh address. if script dose not p2pkh, return nil.
|
data/lib/bitcoin/tx.rb
CHANGED
@@ -104,6 +104,12 @@ module Bitcoin
|
|
104
104
|
witness? ? serialize_witness_format : serialize_old_format
|
105
105
|
end
|
106
106
|
|
107
|
+
# convert tx to hex format.
|
108
|
+
# @return [String] tx with hex format.
|
109
|
+
def to_hex
|
110
|
+
to_payload.bth
|
111
|
+
end
|
112
|
+
|
107
113
|
def coinbase_tx?
|
108
114
|
inputs.length == 1 && inputs.first.coinbase?
|
109
115
|
end
|
@@ -156,7 +162,7 @@ module Bitcoin
|
|
156
162
|
return false unless o.script_pubkey.standard?
|
157
163
|
data_count += 1 if o.script_pubkey.op_return?
|
158
164
|
# TODO add non P2SH multisig relay(permitbaremultisig)
|
159
|
-
|
165
|
+
return false if o.dust?
|
160
166
|
end
|
161
167
|
return false if data_count > 1
|
162
168
|
true
|
@@ -233,6 +239,14 @@ module Bitcoin
|
|
233
239
|
}
|
234
240
|
end
|
235
241
|
|
242
|
+
# Verify transaction validity.
|
243
|
+
# @return [Boolean] whether this tx is valid or not.
|
244
|
+
def valid?
|
245
|
+
state = Bitcoin::ValidationState.new
|
246
|
+
validation = Bitcoin::Validation.new
|
247
|
+
validation.check_tx(self, state) && state.valid?
|
248
|
+
end
|
249
|
+
|
236
250
|
private
|
237
251
|
|
238
252
|
# generate sighash with legacy format
|
data/lib/bitcoin/tx_out.rb
CHANGED
@@ -45,6 +45,30 @@ module Bitcoin
|
|
45
45
|
to_payload == other.to_payload
|
46
46
|
end
|
47
47
|
|
48
|
+
# Returns this output bytesize
|
49
|
+
# @return [Integer] bytesize
|
50
|
+
def size
|
51
|
+
to_payload.bytesize
|
52
|
+
end
|
53
|
+
|
54
|
+
# Whether this output is dust or not
|
55
|
+
# @return [Boolean]
|
56
|
+
def dust?
|
57
|
+
value < dust_threshold
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def dust_threshold
|
63
|
+
return 0 if script_pubkey.unspendable?
|
64
|
+
n_size = size
|
65
|
+
n_size += script_pubkey.witness_program? ? (32 + 4 + 1 + (107 / Bitcoin::WITNESS_SCALE_FACTOR) + 4) : (32 + 4 + 1 + 107 + 4)
|
66
|
+
fee = n_size * Bitcoin.chain_params.dust_relay_fee / 1000
|
67
|
+
if fee == 0 && n_size != 0
|
68
|
+
fee = Bitcoin.chain_params.dust_relay_fee > 0 ? 1 : -1
|
69
|
+
end
|
70
|
+
fee
|
71
|
+
end
|
48
72
|
end
|
49
73
|
|
50
74
|
end
|
data/lib/bitcoin/version.rb
CHANGED
@@ -5,6 +5,7 @@ module Bitcoin
|
|
5
5
|
class MasterKey
|
6
6
|
extend Bitcoin::Util
|
7
7
|
include Bitcoin::Util
|
8
|
+
include Bitcoin::KeyPath
|
8
9
|
|
9
10
|
attr_reader :seed
|
10
11
|
attr_accessor :salt
|
@@ -65,15 +66,7 @@ module Bitcoin
|
|
65
66
|
# @return [Bitcoin::ExtKey]
|
66
67
|
def derive(path)
|
67
68
|
derived_key = key
|
68
|
-
path
|
69
|
-
if index == 0
|
70
|
-
raise ArgumentError.new("#{path} is invalid format.") unless p == 'm'
|
71
|
-
next
|
72
|
-
end
|
73
|
-
raise ArgumentError.new("#{path} is invalid format.") unless p.delete("'") =~ /^[0-9]+$/
|
74
|
-
num = (p[-1] == "'" ? p.delete("'").to_i + Bitcoin::HARDENED_THRESHOLD : p.to_i)
|
75
|
-
derived_key = derived_key.derive(num)
|
76
|
-
end
|
69
|
+
parse_key_path(path).each{|num| derived_key = derived_key.derive(num)}
|
77
70
|
derived_key
|
78
71
|
end
|
79
72
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bitcoinrb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- azuchi
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-09-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ecdsa
|
@@ -206,6 +206,20 @@ dependencies:
|
|
206
206
|
- - ">="
|
207
207
|
- !ruby/object:Gem::Version
|
208
208
|
version: '0'
|
209
|
+
- !ruby/object:Gem::Dependency
|
210
|
+
name: activesupport
|
211
|
+
requirement: !ruby/object:Gem::Requirement
|
212
|
+
requirements:
|
213
|
+
- - "~>"
|
214
|
+
- !ruby/object:Gem::Version
|
215
|
+
version: 5.2.3
|
216
|
+
type: :runtime
|
217
|
+
prerelease: false
|
218
|
+
version_requirements: !ruby/object:Gem::Requirement
|
219
|
+
requirements:
|
220
|
+
- - "~>"
|
221
|
+
- !ruby/object:Gem::Version
|
222
|
+
version: 5.2.3
|
209
223
|
- !ruby/object:Gem::Dependency
|
210
224
|
name: leveldb-ruby
|
211
225
|
requirement: !ruby/object:Gem::Requirement
|
@@ -316,6 +330,7 @@ files:
|
|
316
330
|
- lib/bitcoin/ext_key.rb
|
317
331
|
- lib/bitcoin/gcs_filter.rb
|
318
332
|
- lib/bitcoin/key.rb
|
333
|
+
- lib/bitcoin/key_path.rb
|
319
334
|
- lib/bitcoin/logger.rb
|
320
335
|
- lib/bitcoin/merkle_tree.rb
|
321
336
|
- lib/bitcoin/message.rb
|
@@ -385,6 +400,7 @@ files:
|
|
385
400
|
- lib/bitcoin/psbt.rb
|
386
401
|
- lib/bitcoin/psbt/hd_key_path.rb
|
387
402
|
- lib/bitcoin/psbt/input.rb
|
403
|
+
- lib/bitcoin/psbt/key_origin_info.rb
|
388
404
|
- lib/bitcoin/psbt/output.rb
|
389
405
|
- lib/bitcoin/psbt/tx.rb
|
390
406
|
- lib/bitcoin/rpc.rb
|