bitcoinrb 0.2.8 → 0.2.9
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/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
|