Blockbind technique describes a robust way of making the MinerId specific to the block it's in by adding block specific data into the final MinerInfo coinbase output. However, doing this creates a causality dilemma (chicken/egg scenario) since the header cannot be finalised and signed by the MinerId key without the hash of the coinbase transaction which, in turn, cannot be created until the MinerId key is finalised. The solution to that is detailed below:
To get around the chicken/egg scenario described above we recalculate the Merkle tree but replace the coinbase transaction with a modified coinbase transaction (shown below) which ensures that blockBind signature can only be valid if contained within the block that the miner intended.
Steps to create the modified miner-info coinbase transaction:
- Begin with a copy of the original coinbase transaction (with coinbase1, extranonce1, extranonce2 and coinbase2 parts - see Mining Protocol v1 definition)
- Replace the coinbase input scriptSig with an 8 byte array of zeros and ensuring that the length field proceeding the scriptSig is also set to 8. This zeros extranonce1 and extranonce2 fields.
- scriptlen:
0x08
- scriptSig:
0x0000000000000000
- scriptlen:
- Set the remaining fields of coinbase1 to the following values:
- version:
0x01000000
- input count:
0x01
- previous hash:
0x0000000000000000000000000000000000000000000000000000000000000000
- index:
0xffffffff
- version:
- Add a miner-info output script with a minerInfoTxId data field:
OP_0 OP_RETURN 0x601dface 0x00 minerInfoTxId
.
Note: The choice to use an 8 byte array of zeroes is simply for compatibility with existing bitcoin libraries. Many libraries will check to ensure the coinbase input is valid and one of those rules requires the coinbase to be at least 4 bytes.
Double hash the modified MinerInfo coinbase transaction to get a new transaction ID and modify the Merkle proof by replacing the original coinbase transaction ID with the ID generated. After that calculate modifiedMerkleRoot
from Merkle branch.
It's a hash over the modified Merkle root and previous block hash concatenated field:
Hash256(concat(modifiedMerkleRoot, prevhash))
Note: The concatenation is done on the hex encoded bytes.
It's a signature over the blockBind field using the private key associated with the minerId public key.
The blockBind and blockBindSig fields are added to the final MinerInfo coinbase output which is defined as below:
OP_0 OP_RETURN 0x601dface 0x00 minerInfoTxId blockBind blockBindSig
Thanks to this technique, the worst an attacker can do is to mine exactly the same block paying to the same (authentic miner) outputs. They can modify the coinbase text but nothing else without invalidating the blockBind and blockBindSig fields, further disincentivising an attack as the block reward is added to the cost of the attack.