From f0f4784c1ccf8cdafb3c72b8f251fa5290174297 Mon Sep 17 00:00:00 2001 From: "Johan T. Halseth" Date: Mon, 26 Apr 2021 13:53:22 +0200 Subject: [PATCH 1/2] mining: extract witness commitment add into method --- mining/mining.go | 78 +++++++++++++++++++++++++++--------------------- 1 file changed, 44 insertions(+), 34 deletions(-) diff --git a/mining/mining.go b/mining/mining.go index 44ec7dc7..e918328d 100644 --- a/mining/mining.go +++ b/mining/mining.go @@ -803,40 +803,7 @@ mempoolLoop: // OP_RETURN output within the coinbase transaction. var witnessCommitment []byte if witnessIncluded { - // The witness of the coinbase transaction MUST be exactly 32-bytes - // of all zeroes. - var witnessNonce [blockchain.CoinbaseWitnessDataLen]byte - coinbaseTx.MsgTx().TxIn[0].Witness = wire.TxWitness{witnessNonce[:]} - - // Next, obtain the merkle root of a tree which consists of the - // wtxid of all transactions in the block. The coinbase - // transaction will have a special wtxid of all zeroes. - witnessMerkleTree := blockchain.BuildMerkleTreeStore(blockTxns, - true) - witnessMerkleRoot := witnessMerkleTree[len(witnessMerkleTree)-1] - - // The preimage to the witness commitment is: - // witnessRoot || coinbaseWitness - var witnessPreimage [64]byte - copy(witnessPreimage[:32], witnessMerkleRoot[:]) - copy(witnessPreimage[32:], witnessNonce[:]) - - // The witness commitment itself is the double-sha256 of the - // witness preimage generated above. With the commitment - // generated, the witness script for the output is: OP_RETURN - // OP_DATA_36 {0xaa21a9ed || witnessCommitment}. The leading - // prefix is referred to as the "witness magic bytes". - witnessCommitment = chainhash.DoubleHashB(witnessPreimage[:]) - witnessScript := append(blockchain.WitnessMagicBytes, witnessCommitment...) - - // Finally, create the OP_RETURN carrying witness commitment - // output as an additional output within the coinbase. - commitmentOutput := &wire.TxOut{ - Value: 0, - PkScript: witnessScript, - } - coinbaseTx.MsgTx().TxOut = append(coinbaseTx.MsgTx().TxOut, - commitmentOutput) + witnessCommitment = AddWitnessCommitment(coinbaseTx, blockTxns) } // Calculate the required difficulty for the block. The timestamp @@ -895,6 +862,49 @@ mempoolLoop: }, nil } +// AddWitnessCommitment adds the witness commitment as an OP_RETURN outpout +// within the coinbase tx. The raw commitment is returned. +func AddWitnessCommitment(coinbaseTx *btcutil.Tx, + blockTxns []*btcutil.Tx) []byte { + + // The witness of the coinbase transaction MUST be exactly 32-bytes + // of all zeroes. + var witnessNonce [blockchain.CoinbaseWitnessDataLen]byte + coinbaseTx.MsgTx().TxIn[0].Witness = wire.TxWitness{witnessNonce[:]} + + // Next, obtain the merkle root of a tree which consists of the + // wtxid of all transactions in the block. The coinbase + // transaction will have a special wtxid of all zeroes. + witnessMerkleTree := blockchain.BuildMerkleTreeStore(blockTxns, + true) + witnessMerkleRoot := witnessMerkleTree[len(witnessMerkleTree)-1] + + // The preimage to the witness commitment is: + // witnessRoot || coinbaseWitness + var witnessPreimage [64]byte + copy(witnessPreimage[:32], witnessMerkleRoot[:]) + copy(witnessPreimage[32:], witnessNonce[:]) + + // The witness commitment itself is the double-sha256 of the + // witness preimage generated above. With the commitment + // generated, the witness script for the output is: OP_RETURN + // OP_DATA_36 {0xaa21a9ed || witnessCommitment}. The leading + // prefix is referred to as the "witness magic bytes". + witnessCommitment := chainhash.DoubleHashB(witnessPreimage[:]) + witnessScript := append(blockchain.WitnessMagicBytes, witnessCommitment...) + + // Finally, create the OP_RETURN carrying witness commitment + // output as an additional output within the coinbase. + commitmentOutput := &wire.TxOut{ + Value: 0, + PkScript: witnessScript, + } + coinbaseTx.MsgTx().TxOut = append(coinbaseTx.MsgTx().TxOut, + commitmentOutput) + + return witnessCommitment +} + // UpdateBlockTime updates the timestamp in the header of the passed block to // the current time while taking into account the median time of the last // several blocks to ensure the new time is after that time per the chain From 37a6e8485b69f9514d74d153843477c73d1b0473 Mon Sep 17 00:00:00 2001 From: "Johan T. Halseth" Date: Mon, 26 Apr 2021 13:53:51 +0200 Subject: [PATCH 2/2] rpctest: add witness commitment when calling CreateBlock If we tried to include transactions having witnesses, the block would be invalid since the witness commitment was not added. --- integration/rpctest/blockgen.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/integration/rpctest/blockgen.go b/integration/rpctest/blockgen.go index de5821b0..0d802f5a 100644 --- a/integration/rpctest/blockgen.go +++ b/integration/rpctest/blockgen.go @@ -14,6 +14,7 @@ import ( "github.com/btcsuite/btcd/blockchain" "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/btcsuite/btcd/mining" "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcutil" @@ -181,6 +182,21 @@ func CreateBlock(prevBlock *btcutil.Block, inclusionTxs []*btcutil.Tx, if inclusionTxs != nil { blockTxns = append(blockTxns, inclusionTxs...) } + + // We must add the witness commitment to the coinbase if any + // transactions are segwit. + witnessIncluded := false + for i := 1; i < len(blockTxns); i++ { + if blockTxns[i].MsgTx().HasWitness() { + witnessIncluded = true + break + } + } + + if witnessIncluded { + _ = mining.AddWitnessCommitment(coinbaseTx, blockTxns) + } + merkles := blockchain.BuildMerkleTreeStore(blockTxns, false) var block wire.MsgBlock block.Header = wire.BlockHeader{