lib/bitcoin/protocol/aux_pow.rb in bitcoin-ruby-0.0.7 vs lib/bitcoin/protocol/aux_pow.rb in bitcoin-ruby-0.0.8

- old
+ new

@@ -2,119 +2,119 @@ module Bitcoin module Protocol # Auxiliary Proof-of-Work for merge-mined blockchains + # See https://en.bitcoin.it/wiki/Merged_mining_specification. + # + # The AuxPow contains all data needed to verify that the child + # block was included in the parents coinbase transaction, and + # the parent satisfies the difficulty target. + # + # It encodes the +parent_block+ header, and its +coinbase_tx+. + # The +coinbase_branch+ and +coinbase_index+ can be used to recalculate + # the parent blocks merkle root and prove the coinbase transaction is + # really included in it. + # The +chain_branch+ and +chain_index+ are used to link the child block + # to the merkle root contained in the +coinbase_tx+. (So there can be + # more than one merge-mined chain) + # + # TODO: decode merged-mining data from +coinbase_tx+ class AuxPow - # Coinbase transaction linking the aux to its parent block - attr_accessor :tx + # Coinbase transaction of the parent block, linking to the child block + attr_accessor :coinbase_tx - # Hash of the block header + # Hash of the parent block header attr_accessor :block_hash - # Merkle branches to bring the transaction to the block's merkle root - attr_accessor :branch + # Merkle branch linking the +coinbase_tx+ to the +parent_block+ + attr_accessor :coinbase_branch - # Index of this transaction in the merkle tree - attr_accessor :mrkl_index + # Index of the +coinbase_tx+ in the parent blocks merkle tree + attr_accessor :coinbase_index - # Merkle branches linking this aux chains to the aux root - attr_accessor :aux_branch + # Merkle branch linking the child block to the +coinbase_tx+ + attr_accessor :chain_branch - # Index of "this" block chain in the aux chain list - attr_accessor :aux_index + # Index of the child block in the chain merkle tree + attr_accessor :chain_index # Parent block header attr_accessor :parent_block def initialize(data) parse_data (data) if data end def parse_data(data) - @tx = P::Tx.new(nil) - payload = @tx.parse_data(data) - @block_hash, payload = payload.unpack("a32a*") - - branch_count, payload = P.unpack_var_int(payload) - @branch = [] - branch_count.times { - b, payload = payload.unpack("a32a*") - @branch << b - } - @mrkl_index, payload = payload.unpack("Ia*") - - @aux_branch = [] - aux_branch_count, payload = P.unpack_var_int(payload) - aux_branch_count.times { - b, payload = payload.unpack("a32a*") - @aux_branch << b - } - - @aux_index, payload = payload.unpack("Ia*") - block, payload = payload.unpack("a80a*") - @parent_block = P::Block.new(block) - - payload + buf = StringIO.new(data) + parse_data_from_io(buf) + buf.eof? ? '' : buf.read end def parse_data_from_io(data) - @tx = P::Tx.new(nil) - @tx.parse_data_from_io(data) + @coinbase_tx = P::Tx.new(nil) + @coinbase_tx.parse_data_from_io(data) @block_hash = data.read(32) - branch_count = P.unpack_var_int_from_io(data) - @branch = [] - branch_count.times{ @branch << data.read(32) } - @mrkl_index = data.read(4).unpack("I")[0] + coinbase_branch_count = P.unpack_var_int_from_io(data) + @coinbase_branch = [] + coinbase_branch_count.times{ + break if data.eof? + @coinbase_branch << data.read(32).reverse.hth + } + @coinbase_index = data.read(4).unpack("I")[0] - @aux_branch = [] - aux_branch_count = P.unpack_var_int_from_io(data) - aux_branch_count.times{ @aux_branch << data.read(32) } + @chain_branch = [] + chain_branch_count = P.unpack_var_int_from_io(data) + chain_branch_count.times{ + break if data.eof? + @chain_branch << data.read(32).reverse.hth + } - @aux_index = data.read(4).unpack("I")[0] + @chain_index = data.read(4).unpack("I")[0] block = data.read(80) @parent_block = P::Block.new(block) data end def to_payload - payload = @tx.to_payload + payload = @coinbase_tx.to_payload payload << @block_hash - payload << P.pack_var_int(@branch.count) - payload << @branch.join - payload << [@mrkl_index].pack("I") - payload << P.pack_var_int(@aux_branch.count) - payload << @aux_branch.join - payload << [@aux_index].pack("I") + payload << P.pack_var_int(@coinbase_branch.count) + payload << @coinbase_branch.map(&:htb).map(&:reverse).join + payload << [@coinbase_index].pack("I") + payload << P.pack_var_int(@chain_branch.count) + payload << @chain_branch.map(&:htb).map(&:reverse).join + payload << [@chain_index].pack("I") payload << @parent_block.to_payload payload end def self.from_hash h aux_pow = new(nil) aux_pow.instance_eval do - @tx = P::Tx.from_hash(h['tx']) + @coinbase_tx = P::Tx.from_hash(h['coinbase_tx']) @block_hash = h['block_hash'].htb - @branch = h['branch'].map(&:htb) - @mrkl_index = h['mrkl_index'] - @aux_branch = h['aux_branch'].map(&:htb) - @aux_index = h['aux_index'] + @coinbase_branch = h['coinbase_branch'] + @coinbase_index = h['coinbase_index'] + @chain_branch = h['chain_branch'] + @chain_index = h['chain_index'] @parent_block = P::Block.from_hash(h['parent_block']) end aux_pow end def to_hash - { 'tx' => @tx.to_hash, + { 'coinbase_tx' => @coinbase_tx.to_hash, 'block_hash' => @block_hash.hth, - 'branch' => @branch.map(&:hth), - 'mrkl_index' => @mrkl_index, - 'aux_branch' => @aux_branch.map(&:hth), - 'aux_index' => @aux_index, + 'coinbase_branch' => @coinbase_branch, + 'coinbase_index' => @coinbase_index, + 'chain_branch' => @chain_branch, + 'chain_index' => @chain_index, 'parent_block' => @parent_block.to_hash } end end