Skip to content

Commit 0a25cca

Browse files
committed
Reconsider coinbase witness commitment
Rather than having the coinbase witness commitment be the hash of the concatenation of the transaction witness merkle root and a single 32-byte nonce from the coinbase witness, treat it instead as the merkle root of a tree with the leaves being the transaction witness merkle root, and each of the items from the coinbase stack. For the case where the coinbase witness stack contains a single, 32-byte item this change has no effect, however it should generalise well to allow the coinbase witness stack to contain an arbitrary number of elements. (If an element on the coinbase stack is not already exactly 32 bytes, it is first hashed before being added as a leaf to the merkle tree)
1 parent ffe4700 commit 0a25cca

File tree

3 files changed

+30
-6
lines changed

3 files changed

+30
-6
lines changed

src/consensus/merkle.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,25 @@ uint256 BlockTxWitnessMerkleRoot(const CBlock& block, bool* mutated)
172172
return ComputeMerkleRoot(leaves, mutated);
173173
}
174174

175+
uint256 BlockWitnessMerkleRoot(const CBlock& block, bool* pmutated)
176+
{
177+
const CScriptWitness& cbsw = block.vtx[0].wit.vtxinwit[0].scriptWitness;
178+
std::vector<uint256> leaves;
179+
leaves.resize(cbsw.stack.size() + 1);
180+
leaves[0] = BlockTxWitnessMerkleRoot(block, pmutated);
181+
for (size_t s = 0; s < cbsw.stack.size(); s++) {
182+
if (cbsw.stack[s].size() == 32) {
183+
// dumb idea, but should make it backwards compatible with segnet3
184+
leaves[s+1] = uint256(cbsw.stack[s]);
185+
} else {
186+
leaves[s+1] = Hash(cbsw.stack[s].begin(), cbsw.stack[s].end());
187+
}
188+
}
189+
if (pmutated && *pmutated)
190+
pmutated = NULL;
191+
return ComputeMerkleRoot(leaves, pmutated);
192+
}
193+
175194
std::vector<uint256> BlockMerkleBranch(const CBlock& block, uint32_t position)
176195
{
177196
std::vector<uint256> leaves;

src/consensus/merkle.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ uint256 BlockMerkleRoot(const CBlock& block, bool* mutated = NULL);
2828
*/
2929
uint256 BlockTxWitnessMerkleRoot(const CBlock& block, bool* mutated = NULL);
3030

31+
/*
32+
* Compute the Merkle root of the coinbase transaction's witness stack.
33+
* *mutated is set to true if a duplicated subtree was found.
34+
*/
35+
uint256 BlockWitnessMerkleRoot(const CBlock& block, bool* mutated = NULL);
36+
3137
/*
3238
* Compute the Merkle branch for the tree of transactions in a block, for a
3339
* given position.

src/main.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3065,17 +3065,16 @@ bool IsWitnessEnabled(const CBlock& block, const CBlockIndex* pindexPrev, const
30653065

30663066
bool CheckWitnessCommitAndNonce(const CBlock& block, int commitpos, CValidationState& state)
30673067
{
3068+
if (block.vtx[0].wit.vtxinwit.size() != 1 || block.vtx[0].wit.vtxinwit[0].scriptWitness.stack.size() != 1 || block.vtx[0].wit.vtxinwit[0].scriptWitness.stack[0].size() != 32) {
3069+
return state.DoS(100, error("%s : invalid witness commitment size", __func__), REJECT_INVALID, "bad-witness-merkle-size", true);
3070+
}
3071+
30683072
bool malleated = false;
3069-
uint256 hashWitness = BlockTxWitnessMerkleRoot(block, &malleated);
3073+
uint256 hashWitness = BlockWitnessMerkleRoot(block, &malleated);
30703074
// The malleation check is ignored; as the transaction tree itself
30713075
// already does not permit it, it is impossible to trigger in the
30723076
// witness tree.
30733077

3074-
if (block.vtx[0].wit.vtxinwit.size() != 1 || block.vtx[0].wit.vtxinwit[0].scriptWitness.stack.size() != 1 || block.vtx[0].wit.vtxinwit[0].scriptWitness.stack[0].size() != 32) {
3075-
return state.DoS(100, error("%s : invalid witness commitment size", __func__), REJECT_INVALID, "bad-witness-merkle-size", true);
3076-
}
3077-
3078-
CHash256().Write(hashWitness.begin(), 32).Write(&block.vtx[0].wit.vtxinwit[0].scriptWitness.stack[0][0], 32).Finalize(hashWitness.begin());
30793078
if (memcmp(hashWitness.begin(), &block.vtx[0].vout[commitpos].scriptPubKey[6], 32)) {
30803079
return state.DoS(100, error("%s : witness merkle commitment mismatch", __func__), REJECT_INVALID, "bad-witness-merkle-match", true);
30813080
}

0 commit comments

Comments
 (0)