bitcoinrb 0.2.6 → 0.2.7

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: 2dea1d2e52223f2754f748f612c5d3df9606988476ee0c1f5b1ad03e71ba0ead
4
- data.tar.gz: baedfcc44fdacd0c2c46766a360fb76404630bd01dbaf034664d358f5564d5b8
3
+ metadata.gz: 14d06b76233959dbd16e89459a109982612c8ec6e91b746328fac54bb0d6ddae
4
+ data.tar.gz: ca60bd4fb4f1075335a0806bfdb5cd829da3f2a2d0b3794012e55ee17c7d417c
5
5
  SHA512:
6
- metadata.gz: 851b762a403ebd8a0f175171e000650b76b5380522c174cbea3c03817477aa89e98b8a3e204c0cc3c223fb281dfbc75ae936cd1b1fe6e6f6b06ae5aeca74b335
7
- data.tar.gz: 75fd1e350ab651a01b1eae0d0b6885ca933a60efcfc237ad75de55002777806aaf805c4a724430535521c421a10111871838d97bfaf94d93766f93e433e33160
6
+ metadata.gz: d49893ec5f8819dc78c19974bd74e1cf2545a787e8861b212a2801e40135b3c0f22650e46df9d5089bbae47dd9c6b74ce13320763a4107633fce5a1355cbbc5b
7
+ data.tar.gz: b2d422ecfc721e2e41b87d089dd2e6727f564f1346ae8a05b7e0d0b16247f8ca4b4113190c92d6e6abedb6180c8373289773ee6648963a10dbe9f3b0f726f471
data/.travis.yml CHANGED
@@ -6,4 +6,6 @@ rvm:
6
6
  addons:
7
7
  apt:
8
8
  packages:
9
- - libleveldb-dev
9
+ - libleveldb-dev
10
+ script:
11
+ - bundle exec parallel_test spec/ -n 6 --type rspec
data/Gemfile CHANGED
@@ -2,3 +2,5 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in bitcoinrb.gemspec
4
4
  gemspec
5
+
6
+ gem 'parallel_tests'
data/README.md CHANGED
@@ -9,13 +9,14 @@ NOTE: Bitcoinrb work in progress, and there is a possibility of incompatible cha
9
9
 
10
10
  Bitcoinrb supports following feature:
11
11
 
12
- * Bitcoin script interpreter
12
+ * Bitcoin script interpreter(including [BIP-65](https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki), [BIP-68](https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki), [BIP-112](https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki))
13
13
  * De/serialization of Bitcoin protocol network messages
14
14
  * De/serialization of blocks and transactions
15
15
  * Key generation and verification for ECDSA, including [BIP-32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) and [BIP-39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki) supports.
16
16
  * ECDSA signature(RFC6979 -Deterministic ECDSA, LOW-S, LOW-R support)
17
- * Segwit support (parsing segwit payload, Bech32 address, sign for segwit tx, etc..)
18
- * PSBT(Partially Signed Bitcoin Transaction) support
17
+ * Segwit support (parsing segwit payload, Bech32 address, sign for segwit tx, [BIP-141](https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki), [BIP-143](https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki), [BIP-144](https://github.com/bitcoin/bips/blob/master/bip-0144.mediawiki))
18
+ * [BIP-173](https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki) Bech32 address support
19
+ * [BIP-174](https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki) PSBT(Partially Signed Bitcoin Transaction) support
19
20
  * [WIP] SPV node
20
21
  * [WIP] 0ff-chain protocol
21
22
 
@@ -29,9 +29,13 @@ module Bitcoin
29
29
  # @return [Bitcoin::PSBTInput] psbt input.
30
30
  def self.parse_from_buf(buf)
31
31
  input = self.new
32
+ found_sep = false
32
33
  until buf.eof?
33
34
  key_len = Bitcoin.unpack_var_int_from_io(buf)
34
- break if key_len == 0
35
+ if key_len == 0
36
+ found_sep = true
37
+ break
38
+ end
35
39
  key_type = buf.read(1).unpack('C').first
36
40
  key = buf.read(key_len - 1)
37
41
  value = buf.read(Bitcoin.unpack_var_int_from_io(buf))
@@ -83,6 +87,7 @@ module Bitcoin
83
87
  input.unknowns[unknown_key] = value
84
88
  end
85
89
  end
90
+ raise ArgumentError, 'Separator is missing at the end of an input map.' unless found_sep
86
91
  input
87
92
  end
88
93
 
@@ -116,28 +121,35 @@ module Bitcoin
116
121
  # Check whether input's scriptPubkey is correct witness.
117
122
  # @return [Boolean]
118
123
  def valid_witness_input?
119
- return true if witness_utxo.script_pubkey.p2wpkh? # P2WPKH
120
- return true if witness_utxo.script_pubkey.p2wsh? && witness_utxo.script_pubkey == redeem_script.to_p2wsh # P2WSH
121
- return true if witness_utxo.script_pubkey.p2sh? && redeem_script&.witness_program? && # segwit nested in P2SH
122
- redeem_script.to_p2sh == witness_utxo.script_pubkey && witness_script&.to_sha256 == redeem_script.witness_data[1].bth
124
+ return true if witness_utxo&.script_pubkey.p2wpkh? # P2WPKH
125
+ return true if witness_utxo&.script_pubkey.p2wsh? && witness_utxo&.script_pubkey == redeem_script.to_p2wsh # P2WSH
126
+ # segwit nested in P2SH
127
+ if witness_utxo&.script_pubkey.p2sh? && redeem_script&.witness_program? && redeem_script.to_p2sh == witness_utxo&.script_pubkey
128
+ return true if redeem_script.p2wpkh?# nested p2wpkh
129
+ return true if witness_script&.to_sha256 == redeem_script.witness_data[1].bth # nested p2wsh
130
+ end
123
131
  false
124
132
  end
125
133
 
126
134
  # Check whether input's scriptPubkey is correct witness.
127
135
  # @return [Boolean]
128
- def valid_non_witness_input?
129
- non_witness_utxo.outputs.each do |o|
130
- return true if o.script_pubkey.p2sh? && redeem_script.to_p2sh == o.script_pubkey
131
- end
132
- false
136
+ def valid_non_witness_input?(utxo)
137
+ utxo.script_pubkey.p2sh? && redeem_script.to_p2sh == utxo.script_pubkey
133
138
  end
134
139
 
135
140
  # Check whether the signer can sign this input.
141
+ # @param [Bitcoin::TxOut] utxo utxo object which input refers.
136
142
  # @return [Boolean]
137
- def ready_to_sign?
143
+ def ready_to_sign?(utxo)
138
144
  return false unless sane?
139
145
  return valid_witness_input? if witness_utxo
140
- valid_non_witness_input? # non_witness_utxo
146
+ valid_non_witness_input?(utxo) # non_witness_utxo
147
+ end
148
+
149
+ # Checks whether a PSBTInput is already signed.
150
+ # @return [Boolean] return true if already signed.
151
+ def signed?
152
+ final_script_sig || final_script_witness
141
153
  end
142
154
 
143
155
  # add signature as partial sig.
@@ -19,9 +19,13 @@ module Bitcoin
19
19
  # @return [Bitcoin::PSBTOutput] psbt output.
20
20
  def self.parse_from_buf(buf)
21
21
  output = self.new
22
+ found_sep = false
22
23
  until buf.eof?
23
24
  key_len = Bitcoin.unpack_var_int_from_io(buf)
24
- break if key_len == 0
25
+ if key_len == 0
26
+ found_sep = true
27
+ break
28
+ end
25
29
  key_type = buf.read(1).unpack('C').first
26
30
  key = buf.read(key_len - 1)
27
31
  value = buf.read(Bitcoin.unpack_var_int_from_io(buf))
@@ -43,6 +47,7 @@ module Bitcoin
43
47
  output.unknowns[unknown_key] = value
44
48
  end
45
49
  end
50
+ raise ArgumentError, 'Separator is missing at the end of an output map.' unless found_sep
46
51
  output
47
52
  end
48
53
 
@@ -29,11 +29,14 @@ module Bitcoin
29
29
  raise ArgumentError, 'Invalid PSBT magic bytes.' unless buf.read(4).unpack('N').first == PSBT_MAGIC_BYTES
30
30
  raise ArgumentError, 'Invalid PSBT separator.' unless buf.read(1).bth.to_i(16) == 0xff
31
31
  partial_tx = self.new
32
-
32
+ found_sep = false
33
33
  # read global data.
34
34
  until buf.eof?
35
35
  key_len = Bitcoin.unpack_var_int_from_io(buf)
36
- break if key_len == 0
36
+ if key_len == 0
37
+ found_sep = true
38
+ break
39
+ end
37
40
  key_type = buf.read(1).unpack('C').first
38
41
  key = buf.read(key_len - 1)
39
42
  value = buf.read(Bitcoin.unpack_var_int_from_io(buf))
@@ -42,7 +45,7 @@ module Bitcoin
42
45
  when PSBT_GLOBAL_TYPES[:unsigned_tx]
43
46
  raise ArgumentError, 'Invalid global transaction typed key.' unless key_len == 1
44
47
  raise ArgumentError, 'Duplicate Key, unsigned tx already provided.' if partial_tx.tx
45
- partial_tx.tx = Bitcoin::Tx.parse_from_payload(value)
48
+ partial_tx.tx = Bitcoin::Tx.parse_from_payload(value, non_witness: true)
46
49
  partial_tx.tx.in.each do |tx_in|
47
50
  raise ArgumentError, 'Unsigned tx does not have empty scriptSigs and scriptWitnesses.' if !tx_in.script_sig.empty? || !tx_in.script_witness.empty?
48
51
  end
@@ -52,6 +55,7 @@ module Bitcoin
52
55
  end
53
56
  end
54
57
 
58
+ raise ArgumentError, 'Separator is missing at the end of an output map.' unless found_sep
55
59
  raise ArgumentError, 'No unsigned transaction was provided.' unless partial_tx.tx
56
60
 
57
61
  # read input data.
@@ -83,6 +87,17 @@ module Bitcoin
83
87
  partial_tx
84
88
  end
85
89
 
90
+ # Finds the UTXO for a given input index
91
+ # @param [Integer] index input_index Index of the input to retrieve the UTXO of
92
+ # @return [Bitcoin::TxOut] The UTXO of the input if found.
93
+ def input_utxo(index)
94
+ input = inputs[index]
95
+ prevout_index = tx.in[index].out_point.index
96
+ return input.non_witness_utxo.out[prevout_index] if input.non_witness_utxo
97
+ return input.witness_utxo if input.witness_utxo
98
+ nil
99
+ end
100
+
86
101
  # generate payload.
87
102
  # @return [String] a payload with binary format.
88
103
  def to_payload
@@ -136,7 +151,8 @@ module Bitcoin
136
151
  # * If a witnessScript is provided, the scriptPubKey or the redeemScript must be for that witnessScript
137
152
  # @return [Boolean]
138
153
  def ready_to_sign?
139
- inputs.all?(&:ready_to_sign?)
154
+ inputs.each.with_index{|psbt_in, index|return false unless psbt_in.ready_to_sign?(input_utxo(index))}
155
+ true
140
156
  end
141
157
 
142
158
  # get signature script of input specified by +index+
@@ -87,17 +87,22 @@ module Bitcoin
87
87
  end
88
88
  end
89
89
 
90
+ INITIAL_V = '0101010101010101010101010101010101010101010101010101010101010101'.htb
91
+ INITIAL_K = '0000000000000000000000000000000000000000000000000000000000000000'.htb
92
+ ZERO_B = '00'.htb
93
+ ONE_B = '01'.htb
94
+
90
95
  # generate temporary key k to be used when ECDSA sign.
91
96
  # https://tools.ietf.org/html/rfc6979#section-3.2
92
97
  def generate_rfc6979_nonce(data, privkey, extra_entropy)
93
- v = ('01' * 32).htb # 3.2.b
94
- k = ('00' * 32).htb # 3.2.c
98
+ v = INITIAL_V # 3.2.b
99
+ k = INITIAL_K # 3.2.c
95
100
  # 3.2.d
96
- k = Bitcoin.hmac_sha256(k, v + '00'.htb + privkey + data + extra_entropy)
101
+ k = Bitcoin.hmac_sha256(k, v + ZERO_B + privkey + data + extra_entropy)
97
102
  # 3.2.e
98
103
  v = Bitcoin.hmac_sha256(k, v)
99
104
  # 3.2.f
100
- k = Bitcoin.hmac_sha256(k, v + '01'.htb + privkey + data + extra_entropy)
105
+ k = Bitcoin.hmac_sha256(k, v + ONE_B + privkey + data + extra_entropy)
101
106
  # 3.2.g
102
107
  v = Bitcoin.hmac_sha256(k, v)
103
108
  # 3.2.h
data/lib/bitcoin/tx.rb CHANGED
@@ -31,14 +31,14 @@ module Bitcoin
31
31
  alias_method :in, :inputs
32
32
  alias_method :out, :outputs
33
33
 
34
- def self.parse_from_payload(payload)
34
+ def self.parse_from_payload(payload, non_witness: false)
35
35
  buf = payload.is_a?(String) ? StringIO.new(payload) : payload
36
36
  tx = new
37
37
  tx.version = buf.read(4).unpack('V').first
38
38
 
39
39
  in_count = Bitcoin.unpack_var_int_from_io(buf)
40
40
  witness = false
41
- if in_count.zero?
41
+ if in_count.zero? && !non_witness
42
42
  tx.marker = 0
43
43
  tx.flag = buf.read(1).unpack('c').first
44
44
  if tx.flag.zero?
@@ -1,3 +1,3 @@
1
1
  module Bitcoin
2
- VERSION = "0.2.6"
2
+ VERSION = "0.2.7"
3
3
  end
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.6
4
+ version: 0.2.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - azuchi
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-04-10 00:00:00.000000000 Z
11
+ date: 2019-05-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ecdsa