BIP: (number unassigned) Title: Merged Mining 2 Specification Author: Forrest Voight <[email protected]> Status: Draft Type: Standards Track Created: 19-2-2014
This BIP proposes a new standard for merged mining, consisting of the format of data included in the parent chain's coinbase transaction, the format of an auxiliary proof-of-work, and procedures to generate and validate these proofs.
Of particular interest is the requirement that only one piece of auxiliary data per context (e.g. one auxiliary block per auxiliary chain) can have a valid auxiliary proof-of-work derived from a single parent proof-of-work (this concept is hereafter referred to as "PoW uniqueness"). Ensuring PoW uniqueness is important in many situations because it prevents an unbounded number of auxiliary proof-of-works being created from one parent proof-of-work, which in many situations would enable at least a denial of service attack.
As it stands, the current implementation of merged mining (hereafter referred to as MM1) requires the entire relevant coinbase transaction from the parent chain to be contained within the auxiliary proof-of-work. In addition, MM1's method of ensuring PoW uniqueness is complex and space-inefficient due to flaws in its Merkle tree slot selection algorithm.
This MM2 specification produces markedly shorter auxiliary proof-of-works, making applications such as P2Pool and ChronoBit possible, while reducing the burden on auxiliary blockchains.
PoW: a proof of work.
auxiliary proof of work: a PoW of arbitrary data that is potentially also a valid Bitcoin block solution.
H(x): the standard double-SHA-256 hash function used by Bitcoin.
Ha(x) and Hb(s, y): defined such that Hb(Ha(x), y) = H(x || y), with Ha(x) producing an SHA-256 midstate augmented with the number of blocks processed and less than a block-length of unprocessed data and Hb(s, x) finalizing the SHA-256 hash of the data compressed into s concatenated with x and then SHA-256 hashing it again to yield H(x || y).
hash link: the result of the earlier defined Ha(x) function. Using a hash link, one can compute the double-SHA256 hash of a block of data from the portion of it that wasn't input to Ha(x).
Merkle link: (elsewhere called a Merkle branch) a list of sibling hashes and a bit for each describing which side they're on. Using a Merkle link, one can compute the Merkle root of a tree from the hash of a given leaf node.
auxiliary datum: the datum that the PoW is building on. In Namecoin's case, it would be the Namecoin block header.
context: a realm within which a given MM2 PoW is only valid for at most one auxiliary datum. Contexts are internally represented as 256-bit numbers, which are recommended to be H(some identifying string) (e.g. H("namecoin").)
PoW uniqueness: the property of a auxiliary PoW scheme that ensures that, in a given context, a given PoW is only valid for at most one auxiliary datum.
The parent block contains a "MM2 root hash" within the scriptPubkey of the last txout of its coinbase transaction. The scriptPubkey must be exactly:
OP_RETURN (MM2 root hash || last txout nonce)
which serializes to 42 bytes: (x is the MM2 root hash, y is the last txout nonce)
6a28xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyyy
The "last txout nonce" is a freely chosen 64-bit number, which is useful as a nonce for Stratum mining.
The serialized coinbase transaction ends with the last txout's scriptPubKey and then nLockTime, a 32-bit number, which is always 0 for the generation transaction.
Everything else about the parent chain's generation transaction is unconstrained.
In order to achieve PoW uniqueness, a binary tree with leaf nodes being the H((64 0x00 bytes) || H(auxiliary datum)) and non-leaf nodes being H(left || right) is used to compute the binary tree root hash. The tree has the requirement that path to a leaf node must be a prefix of a predetermined choice of path for the context. For example, H("namecoin"), represented as a bit sequence with 0 meaning left and 1 meaning right, might be used for the mandatory path prefix of Namecoin blocks. This requirement ensures that multiple instances of auxiliary data for the same context can not be within the same tree, which is PoW uniqueness.
def verify_mm2_pow_proof( target, pow_category_hash, # following data makes up MM2 proof parent_block_header_without_merkle_root, parent_merkle_link, parent_generation_transaction_hash_link, mm2_merkle_link, auxiliary_data_hash, last_txout_nonce): if not mm2_merkle_link.side_choices.is_prefix_of(pow_category_hash): # check to make sure that auxiliary_data_hash is in the right place in # the merkle tree of MM2 in order to ensure PoW uniqueness return False mm2_root_hash = execute_merkle_link(mm2_merkle_link, auxiliary_data_hash) # parent_generation_transaction_hash_link is: # Ha(parent_generation_transaction up to where the "MM2 root hash" starts) # We know everything after that, namely the MM2 root hash, the last txout # nonce, and nLockTime (which is always 0). parent_generation_transaction_hash = execute_hash_link(parent_generation_transaction_hash_link, mm2_root_hash + last_txout_nonce + '00000000') parent_merkle_root = execute_merkle_link(parent_merkle_link, parent_generation_transaction_hash) parent_block_hash = H(parent_block_header_without_merkle_root.insert_merkle_root(parent_merkle_root)) return parent_block_hash <= target
XXX
XXX