Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rpctest: add witness commitment when calling CreateBlock #1716

Merged
merged 2 commits into from
Apr 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions integration/rpctest/blockgen.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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{
Expand Down
78 changes: 44 additions & 34 deletions mining/mining.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down