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