bitcoinrb 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 79b3878cc9efefd8c38b5cd870144bc23a80bbf7bf1c741378dd66c9e5ebdbf8
4
- data.tar.gz: a5d9956a5a6b7bed15b73e552b84110d9636f1b069c1d97978be4e94c1e0a0f0
3
+ metadata.gz: 524753cfa61041f101f72d76e914f70b20b504fb0eecad9d378a436afe7db718
4
+ data.tar.gz: f3181a60120da9f892ceaaaaf22aba5923b26f495fb9fb9dd314c5cce8127129
5
5
  SHA512:
6
- metadata.gz: b779fd9decef5b224144dae60e06b99f3ac0fbb17b34202af0ce31eb2bd7e0a6076b3a940dcfe2e460923017c14feb40c2d0bf891f3ebe9553b65be124559a32
7
- data.tar.gz: 7f011d31ab1ec5364cc8f04a63b6baf74d37db05d49666588dd1329d5005f3ba01a8e8b83752989121b73c3956eda8a5808365b729f6d21dc136f6abf0c817cd
6
+ metadata.gz: da27669ddabc4d64bf3c96d4e83eb8c5d90ef837ed91b6f2e1d0e7d50c74153c62ff39eecb1867463f5a8435f7643d62ba6108e7a10d1fa46e4b10178fe8e2f1
7
+ data.tar.gz: 2f85e04fecddba5bb1d1ce4fc61bf79fd972280f4834e56a4b56974958903e74bd1d19789c93d6bdebe8bead9b5fca8ad26d4c35967760cf0517da42ebfeb35d
data/lib/bitcoin/block.rb CHANGED
@@ -17,6 +17,10 @@ module Bitcoin
17
17
  header.hash
18
18
  end
19
19
 
20
+ def block_hash
21
+ header.block_hash
22
+ end
23
+
20
24
  # calculate block weight
21
25
  def weight
22
26
  stripped_size * (WITNESS_SCALE_FACTOR - 1) + size
@@ -41,7 +45,7 @@ module Bitcoin
41
45
 
42
46
  # calculate merkle root from tx list.
43
47
  def calculate_merkle_root
44
- Bitcoin::MerkleTree.build_from_leaf(transactions.map(&:hash)).merkle_root
48
+ Bitcoin::MerkleTree.build_from_leaf(transactions.map(&:tx_hash)).merkle_root
45
49
  end
46
50
 
47
51
  # check the witness commitment in coinbase tx matches witness commitment calculated from tx list.
@@ -36,14 +36,17 @@ module Bitcoin
36
36
  (mantissa * 2 ** (8 * (exponent - 3)))
37
37
  end
38
38
 
39
- # block hash(little endian)
40
39
  def hash
40
+ calc_hash.to_i(16)
41
+ end
42
+
43
+ def block_hash
41
44
  calc_hash
42
45
  end
43
46
 
44
47
  # block hash(big endian)
45
48
  def block_id
46
- hash.rhex
49
+ block_hash.rhex
47
50
  end
48
51
 
49
52
  # evaluate block header
@@ -10,7 +10,7 @@ module Bitcoin
10
10
  end
11
11
 
12
12
  def merkle_root
13
- root.hash
13
+ root.value
14
14
  end
15
15
 
16
16
  def self.build_from_leaf(txids)
@@ -31,11 +31,16 @@ module Bitcoin
31
31
  flags.each do |f|
32
32
  current_node.flag = f
33
33
  if f.zero? || current_node.leaf?
34
- current_node.hash = hashes[hash_index]
34
+ current_node.value = hashes[hash_index]
35
35
  hash_index += 1
36
36
  end
37
37
  current_node = current_node.next_partial
38
- break if hash_index == hashes.size
38
+ if hash_index == hashes.size
39
+ if current_node&.leaf?
40
+ current_node.value = hashes.last
41
+ end
42
+ break
43
+ end
39
44
  end
40
45
  new(root)
41
46
  end
@@ -52,17 +57,21 @@ module Bitcoin
52
57
  nodes.first
53
58
  end
54
59
 
60
+ def find_node(value)
61
+ root.find_node(value)
62
+ end
63
+
55
64
  # node of merkle tree
56
65
  class Node
57
66
 
58
67
  attr_accessor :flag
59
- attr_accessor :hash
68
+ attr_accessor :value
60
69
  attr_accessor :parent
61
70
  attr_accessor :left
62
71
  attr_accessor :right
63
72
 
64
- def initialize(hash = nil)
65
- @hash = hash
73
+ def initialize(value = nil)
74
+ @value = value
66
75
  end
67
76
 
68
77
  def left=(node)
@@ -75,10 +84,10 @@ module Bitcoin
75
84
  @right = node
76
85
  end
77
86
 
78
- def hash
79
- return @hash if @hash
87
+ def value
88
+ return @value if @value
80
89
  self.right = left.dup unless right
81
- Bitcoin.double_sha256([left.hash + right.hash].pack('H*')).bth
90
+ Bitcoin.double_sha256([left.value + right.value].pack('H*')).bth
82
91
  end
83
92
 
84
93
  def root?
@@ -112,7 +121,25 @@ module Bitcoin
112
121
  d
113
122
  end
114
123
 
124
+ # @param target value to be found
125
+ # @return node which has same value as target. nil if this node and any children don't have same value.
126
+ def find_node(target)
127
+ return self if value == target
128
+ return nil if flag && flag.zero?
129
+ return left&.find_node(target) || right&.find_node(target)
130
+ end
131
+
132
+ def index
133
+ i = 0
134
+ d = 1
135
+ current_node = self
136
+ until current_node.root? do
137
+ i += d if current_node.parent.right == current_node
138
+ current_node = current_node.parent
139
+ d *= 2
140
+ end
141
+ i
142
+ end
115
143
  end
116
144
  end
117
-
118
145
  end
@@ -226,6 +226,7 @@ module Bitcoin
226
226
 
227
227
  def on_merkle_block(merkle_block)
228
228
  logger.info("receive merkle block message. #{merkle_block.build_json}")
229
+ peer.handle_merkle_block(merkle_block)
229
230
  end
230
231
 
231
232
  def on_cmpct_block(cmpct_block)
@@ -92,7 +92,7 @@ module Bitcoin
92
92
  def start_block_header_download
93
93
  logger.info("[#{addr}] start block header download.")
94
94
  get_headers = Bitcoin::Message::GetHeaders.new(
95
- Bitcoin.chain_params.protocol_version, [chain.latest_block.hash])
95
+ Bitcoin.chain_params.protocol_version, [chain.latest_block.block_hash])
96
96
  conn.send_message(get_headers)
97
97
  end
98
98
 
@@ -138,7 +138,7 @@ module Bitcoin
138
138
  break unless header.valid?
139
139
  entry = chain.append_header(header)
140
140
  next unless entry
141
- @best_hash = entry.hash
141
+ @best_hash = entry.block_hash
142
142
  @best_height = entry.height
143
143
  end
144
144
  pool.changed
@@ -190,6 +190,11 @@ module Bitcoin
190
190
  pool.notify_observers(:tx, tx)
191
191
  end
192
192
 
193
+ def handle_merkle_block(merkle_block)
194
+ pool.changed
195
+ pool.notify_observers(:merkleblock, merkle_block)
196
+ end
197
+
193
198
  # send ping message.
194
199
  def send_ping
195
200
  ping = Bitcoin::Message::Ping.new
@@ -20,9 +20,9 @@ module Bitcoin
20
20
  # @param [String] payload hd key path value with binary format.
21
21
  # @return [Bitcoin::PSBT::HDKeyPath]
22
22
  def self.parse_from_payload(pubkey, payload)
23
- raise '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)
23
+ 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
24
  pubkey = Bitcoin::Key.new(pubkey: pubkey.bth)
25
- raise 'Invalid pubkey' unless pubkey.fully_valid_pubkey?
25
+ raise ArgumentError, 'Invalid pubkey' unless pubkey.fully_valid_pubkey?
26
26
  self.new(pubkey.pubkey, fingerprint: payload[0...4].bth, path: payload[4..-1].unpack('I*'))
27
27
  end
28
28
 
@@ -38,9 +38,11 @@ module Bitcoin
38
38
 
39
39
  case key_type
40
40
  when PSBT_IN_TYPES[:non_witness_utxo]
41
+ raise ArgumentError, 'Invalid non-witness utxo typed key.' unless key_len == 1
41
42
  raise ArgumentError, 'Duplicate Key, input non-witness utxo already provided.' if input.non_witness_utxo
42
43
  input.non_witness_utxo = Bitcoin::Tx.parse_from_payload(value)
43
44
  when PSBT_IN_TYPES[:witness_utxo]
45
+ raise ArgumentError, 'Invalid input witness utxo typed key.' unless key_len == 1
44
46
  raise ArgumentError, 'Duplicate Key, input witness utxo already provided.' if input.witness_utxo
45
47
  input.witness_utxo = Bitcoin::TxOut.parse_from_payload(value)
46
48
  when PSBT_IN_TYPES[:partial_sig]
@@ -52,21 +54,27 @@ module Bitcoin
52
54
  raise ArgumentError, 'Duplicate Key, input partial signature for pubkey already provided.' if input.partial_sigs[pubkey.pubkey]
53
55
  input.partial_sigs[pubkey.pubkey] = value
54
56
  when PSBT_IN_TYPES[:sighash]
57
+ raise ArgumentError, 'Invalid input sighash type typed key.' unless key_len == 1
55
58
  raise ArgumentError 'Duplicate Key, input sighash type already provided.' if input.sighash_type
56
59
  input.sighash_type = value.unpack('I').first
57
60
  when PSBT_IN_TYPES[:redeem_script]
61
+ raise ArgumentError, 'Invalid redeemscript typed key.' unless key_len == 1
58
62
  raise ArgumentError, 'Duplicate Key, input redeemScript already provided.' if input.redeem_script
59
63
  input.redeem_script = Bitcoin::Script.parse_from_payload(value)
60
64
  when PSBT_IN_TYPES[:witness_script]
65
+ raise ArgumentError, 'Invalid witnessscript typed key.' unless key_len == 1
61
66
  raise ArgumentError, 'Duplicate Key, input witnessScript already provided.' if input.witness_script
62
67
  input.witness_script = Bitcoin::Script.parse_from_payload(value)
63
68
  when PSBT_IN_TYPES[:bip32_derivation]
69
+ raise ArgumentError, 'Invalid bip32 typed key.' unless key_len
64
70
  raise ArgumentError, 'Duplicate Key, pubkey derivation path already provided.' if input.hd_key_paths[key.bth]
65
71
  input.hd_key_paths[key.bth] = Bitcoin::PSBT::HDKeyPath.parse_from_payload(key, value)
66
72
  when PSBT_IN_TYPES[:script_sig]
73
+ raise ArgumentError, 'Invalid final scriptsig typed key.' unless key_len == 1
67
74
  raise ArgumentError, 'Duplicate Key, input final scriptSig already provided.' if input.final_script_sig
68
75
  input.final_script_sig = Bitcoin::Script.parse_from_payload(value)
69
76
  when PSBT_IN_TYPES[:script_witness]
77
+ raise ArgumentError, 'Invalid final script witness typed key.' unless key_len == 1
70
78
  raise ArgumentError, 'Duplicate Key, input final scriptWitness already provided.' if input.final_script_witness
71
79
  input.final_script_witness = Bitcoin::ScriptWitness.parse_from_payload(value)
72
80
  else
@@ -27,9 +27,11 @@ module Bitcoin
27
27
  value = buf.read(Bitcoin.unpack_var_int_from_io(buf))
28
28
  case key_type
29
29
  when PSBT_OUT_TYPES[:redeem_script]
30
+ raise ArgumentError, 'Invalid output redeemScript typed key.' unless key_len == 1
30
31
  raise ArgumentError, 'Duplicate Key, output redeemScript already provided' if output.redeem_script
31
32
  output.redeem_script = value
32
33
  when PSBT_OUT_TYPES[:witness_script]
34
+ raise ArgumentError, 'Invalid output witnessScript typed key.' unless key_len == 1
33
35
  raise ArgumentError, 'Duplicate Key, output witnessScript already provided' if output.witness_script
34
36
  output.witness_script = value
35
37
  when PSBT_OUT_TYPES[:bip32_derivation]
@@ -40,26 +40,27 @@ module Bitcoin
40
40
 
41
41
  case key_type
42
42
  when PSBT_GLOBAL_TYPES[:unsigned_tx]
43
- raise ArgumentError, 'Duplicate Key, unsigned tx already provided' if partial_tx.tx
43
+ raise ArgumentError, 'Invalid global transaction typed key.' unless key_len == 1
44
+ raise ArgumentError, 'Duplicate Key, unsigned tx already provided.' if partial_tx.tx
44
45
  partial_tx.tx = Bitcoin::Tx.parse_from_payload(value)
45
46
  partial_tx.tx.in.each do |tx_in|
46
47
  raise ArgumentError, 'Unsigned tx does not have empty scriptSigs and scriptWitnesses.' if !tx_in.script_sig.empty? || !tx_in.script_witness.empty?
47
48
  end
48
49
  else
49
- raise ArgumentError, 'Duplicate Key, key for unknown value already provided' if partial_tx.unknowns[key]
50
+ raise ArgumentError, 'Duplicate Key, key for unknown value already provided.' if partial_tx.unknowns[key]
50
51
  partial_tx.unknowns[([key_type].pack('C') + key).bth] = value
51
52
  end
52
53
  end
53
54
 
54
- raise ArgumentError, 'No unsigned transcation was provided.' unless partial_tx.tx
55
+ raise ArgumentError, 'No unsigned transaction was provided.' unless partial_tx.tx
55
56
 
56
57
  # read input data.
57
58
  partial_tx.tx.in.each do |tx_in|
58
59
  break if buf.eof?
59
60
  input = Input.parse_from_buf(buf)
60
61
  partial_tx.inputs << input
61
- if input.non_witness_utxo && input.non_witness_utxo.hash != tx_in.prev_hash
62
- raise ArgumentError, 'Non-witness UTXO does not match outpoint hash'
62
+ if input.non_witness_utxo && input.non_witness_utxo.tx_hash != tx_in.prev_hash
63
+ raise ArgumentError, 'Non-witness UTXO does not match outpoint hash.'
63
64
  end
64
65
  end
65
66
 
@@ -110,7 +111,7 @@ module Bitcoin
110
111
  # @param [Bitcoin::Script] witness_script witness script to set input.
111
112
  # @param [Hash] hd_key_paths bip 32 hd key paths to set input.
112
113
  def update!(prev_tx, redeem_script: nil, witness_script: nil, hd_key_paths: [])
113
- prev_hash = prev_tx.hash
114
+ prev_hash = prev_tx.tx_hash
114
115
  tx.in.each_with_index do|tx_in, i|
115
116
  if tx_in.prev_hash == prev_hash
116
117
  utxo = prev_tx.out[tx_in.out_point.index]
@@ -12,7 +12,7 @@ module Bitcoin
12
12
  h[:headers] = best_block.height
13
13
  h[:bestblockhash] = best_block.header.block_id
14
14
  h[:chainwork] = best_block.header.work
15
- h[:mediantime] = node.chain.mtp(best_block.hash)
15
+ h[:mediantime] = node.chain.mtp(best_block.block_hash)
16
16
  h
17
17
  end
18
18
 
@@ -352,6 +352,11 @@ module Bitcoin
352
352
  to_payload.bytesize
353
353
  end
354
354
 
355
+ # execute script interpreter using this script for development.
356
+ def run
357
+ Bitcoin::ScriptInterpreter.eval(Bitcoin::Script.new, self.dup)
358
+ end
359
+
355
360
  # encode int value to script number hex.
356
361
  # The stacks hold byte vectors.
357
362
  # When used as numbers, byte vectors are interpreted as little-endian variable-length integers
@@ -16,14 +16,18 @@ module Bitcoin
16
16
 
17
17
  # get database key
18
18
  def key
19
- Bitcoin::Store::KEY_PREFIX[:entry] + header.hash
19
+ Bitcoin::Store::KEY_PREFIX[:entry] + header.block_hash
20
20
  end
21
21
 
22
- # block hash
23
22
  def hash
24
23
  header.hash
25
24
  end
26
25
 
26
+ # block hash
27
+ def block_hash
28
+ header.block_hash
29
+ end
30
+
27
31
  # previous block hash
28
32
  def prev_hash
29
33
  header.prev_hash
@@ -61,7 +61,7 @@ module Bitcoin
61
61
  def save_entry(entry)
62
62
  db.batch do
63
63
  db.put(entry.key ,entry.to_payload)
64
- db.put(height_key(entry.height), entry.hash)
64
+ db.put(height_key(entry.height), entry.block_hash)
65
65
  connect_entry(entry)
66
66
  end
67
67
  end
@@ -81,17 +81,15 @@ module Bitcoin
81
81
  def connect_entry(entry)
82
82
  unless entry.genesis?
83
83
  tip_block = Bitcoin::Store::ChainEntry.parse_from_payload(get_entry_payload_from_hash(best_hash))
84
- unless tip_block.hash == entry.prev_hash
85
- raise "entry(#{entry.hash}) does not reference current best block hash(#{tip_block.hash})"
84
+ unless tip_block.block_hash == entry.prev_hash
85
+ raise "entry(#{entry.block_hash}) does not reference current best block hash(#{tip_block.block_hash})"
86
86
  end
87
87
  unless tip_block.height + 1 == entry.height
88
88
  raise "block height is small than current best block."
89
89
  end
90
90
  end
91
-
92
-
93
- db.put(KEY_PREFIX[:best], entry.hash)
94
- db.put(KEY_PREFIX[:next] + entry.prev_hash, entry.hash)
91
+ db.put(KEY_PREFIX[:best], entry.block_hash)
92
+ db.put(KEY_PREFIX[:next] + entry.prev_hash, entry.block_hash)
95
93
  end
96
94
  end
97
95
 
@@ -44,17 +44,17 @@ module Bitcoin
44
44
  # @return [Bitcoin::Store::ChainEntry] appended block header entry.
45
45
  def append_header(header)
46
46
  logger.info("append header #{header.block_id}")
47
- raise "this header is invalid. #{header.hash}" unless header.valid?
47
+ raise "this header is invalid. #{header.block_hash}" unless header.valid?
48
48
  best_block = latest_block
49
49
  current_height = best_block.height
50
- if best_block.hash == header.prev_hash
50
+ if best_block.block_hash == header.prev_hash
51
51
  entry = Bitcoin::Store::ChainEntry.new(header, current_height + 1)
52
52
  db.save_entry(entry)
53
53
  entry
54
54
  else
55
- unless find_entry_by_hash(header.hash)
55
+ unless find_entry_by_hash(header.block_hash)
56
56
  # TODO implements recovery process
57
- raise "header's previous hash(#{header.prev_hash}) does not match current best block's(#{best_block.hash})."
57
+ raise "header's previous hash(#{header.prev_hash}) does not match current best block's(#{best_block.block_hash})."
58
58
  end
59
59
  end
60
60
  end
data/lib/bitcoin/tx.rb CHANGED
@@ -70,11 +70,15 @@ module Bitcoin
70
70
  end
71
71
 
72
72
  def hash
73
+ to_payload.bth.to_i(16)
74
+ end
75
+
76
+ def tx_hash
73
77
  Bitcoin.double_sha256(serialize_old_format).bth
74
78
  end
75
79
 
76
80
  def txid
77
- hash.rhex
81
+ tx_hash.rhex
78
82
  end
79
83
 
80
84
  def witness_hash
@@ -109,7 +113,7 @@ module Bitcoin
109
113
  end
110
114
 
111
115
  def ==(other)
112
- hash == other.hash
116
+ to_payload == other.to_payload
113
117
  end
114
118
 
115
119
  # serialize tx with old tx format
@@ -49,7 +49,7 @@ module Bitcoin
49
49
 
50
50
  # check proof of work
51
51
  def check_block_header(header, state)
52
- header.hash
52
+ header.block_hash
53
53
  header.bits
54
54
 
55
55
  end
@@ -1,3 +1,3 @@
1
1
  module Bitcoin
2
- VERSION = "0.2.1"
2
+ VERSION = "0.2.2"
3
3
  end
@@ -5,8 +5,14 @@ module OpenAssets
5
5
  # whether this output is marker output for open assets.
6
6
  def open_assets_marker?
7
7
  return false unless script_pubkey.op_return?
8
- payload = Payload.parse_from_payload(script_pubkey.op_return_data)
9
- !payload.nil?
8
+ !oa_payload.nil?
9
+ end
10
+
11
+ # get open asset payload.
12
+ # @return [OpenAssets::Payload] open asset payload.
13
+ def oa_payload
14
+ return nil unless script_pubkey.op_return?
15
+ Payload.parse_from_payload(script_pubkey.op_return_data)
10
16
  end
11
17
 
12
18
  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.1
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - azuchi
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-08-02 00:00:00.000000000 Z
11
+ date: 2018-09-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ecdsa