Auto merge of #5220 - str4d:5197-header-commitments, r=str4d

NU5 header commitments and consensus rules

Part of zcash/zcash#5197.
This commit is contained in:
Homu 2021-06-18 10:24:28 +00:00
commit b0e6119551
16 changed files with 274 additions and 58 deletions

View File

@ -116,6 +116,7 @@ BASE_SCRIPTS= [
'framework.py',
'sapling_rewind_check.py',
'feature_zip221.py',
'feature_zip244_blockcommitments.py',
'upgrade_golden.py',
'post_heartwood_rollback.py',
'feature_logging.py',

View File

@ -0,0 +1,65 @@
#!/usr/bin/env python3
# Copyright (c) 2020 The Zcash developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
from test_framework.blocktools import derive_block_commitments_hash
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
bytes_to_hex_str,
hex_str_to_bytes,
start_nodes,
)
TERMINATOR = b'\x00' * 32
# Verify block header field 'hashLightClientRoot' is set correctly for NU5 blocks.
class AuthDataRootTest(BitcoinTestFramework):
def __init__(self):
super().__init__()
self.num_nodes = 4
def setup_nodes(self):
return start_nodes(self.num_nodes, self.options.tmpdir, extra_args=[[
'-nuparams=5ba81b19:1', # Overwinter
'-nuparams=76b809bb:1', # Sapling
'-nuparams=2bb40e60:201', # Blossom
'-nuparams=f5b9230b:201', # Heartwood
'-nuparams=e9ff75a6:201', # Canopy
'-nuparams=f919a198:205', # NU5
'-nurejectoldversions=false',
]] * self.num_nodes)
def run_test(self):
# Generate a block so we are on Canopy rules.
self.nodes[0].generate(2)
self.sync_all()
# For blocks prior to NU5 activation, the hashBlockCommitments field of
# the block header contains the root of the ZIP 221 history tree.
for i in range(3):
block_before = self.nodes[0].getblock('%d' % (202 + i))
assert_equal(block_before['blockcommitments'], block_before['chainhistoryroot'])
self.nodes[0].generate(1)
self.sync_all()
# From NU5 activation, the hashBlockCommitments field of the block
# header contains a hash of various block commitments (per ZIP 244).
for i in range(2):
block_after = self.nodes[0].getblock('%d' % (205 + i))
block_commitments = bytes_to_hex_str(derive_block_commitments_hash(
hex_str_to_bytes(block_after['chainhistoryroot'])[::-1],
hex_str_to_bytes(block_after['authdataroot'])[::-1],
)[::-1])
assert_equal(block_after['blockcommitments'], block_commitments)
self.nodes[0].generate(1)
self.sync_all()
if __name__ == '__main__':
AuthDataRootTest().main()

View File

@ -4,6 +4,8 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
from pyblake2 import blake2b
from .mininode import CBlock, CTransaction, CTxIn, CTxOut, COutPoint
from .script import CScript, OP_0, OP_EQUAL, OP_HASH160, OP_TRUE, OP_CHECKSIG
@ -29,6 +31,15 @@ def create_block(hashprev, coinbase, nTime=None, nBits=None, hashFinalSaplingRoo
block.calc_sha256()
return block
def derive_block_commitments_hash(chain_history_root, auth_data_root):
digest = blake2b(
digest_size=32,
person=b'ZcashBlockCommit')
digest.update(chain_history_root)
digest.update(auth_data_root)
digest.update(b'\x00' * 32)
return digest.digest()
def serialize_script_num(value):
r = bytearray(0)
if value == 0:

View File

@ -18,6 +18,7 @@
static const int SPROUT_VALUE_VERSION = 1001400;
static const int SAPLING_VALUE_VERSION = 1010100;
static const int CHAIN_HISTORY_ROOT_VERSION = 2010200;
static const int NU5_DATA_VERSION = 4050000;
/**
* Maximum amount of time that a block timestamp is allowed to be ahead of the
@ -231,6 +232,14 @@ public:
//! Persisted at each activation height, memory-only for intervening blocks.
std::optional<uint32_t> nCachedBranchId;
//! Root of the ZIP 244 authorizing data commitment tree for this block.
//!
//! - For blocks prior to (not including) the NU5 activation block, this is always
//! null.
//! - For blocks including and after the NU5 activation block, this is only set once
//! a block has been connected to the main chain, and will be null otherwise.
uint256 hashAuthDataRoot;
//! The anchor for the tree state up to the start of this block
uint256 hashSproutAnchor;
@ -258,23 +267,34 @@ public:
//! Root of the Sapling commitment tree as of the end of this block.
//!
//! - For blocks prior to (not including) the Heartwood activation block, this is
//! always equal to hashLightClientRoot.
//! always equal to hashBlockCommitments.
//! - For blocks including and after the Heartwood activation block, this is only set
//! once a block has been connected to the main chain, and will be null otherwise.
uint256 hashFinalSaplingRoot;
//! Root of the Orchard commitment tree as of the end of this block.
//!
//! - For blocks prior to (not including) the NU5 activation block, this is always
//! null.
//! - For blocks including and after the NU5 activation block, this is only set
//! once a block has been connected to the main chain, and will be null otherwise.
uint256 hashFinalOrchardRoot;
//! Root of the ZIP 221 history tree as of the end of the previous block.
//!
//! - For blocks prior to and including the Heartwood activation block, this is
//! always null.
//! - For blocks after (not including) the Heartwood activation block, this is
//! always equal to hashLightClientRoot.
//! - For blocks after (not including) the Heartwood activation block, and prior to
//! (not including) the NU5 activation block, this is always equal to
//! hashBlockCommitments.
//! - For blocks including and after the NU5 activation block, this is only set
//! once a block has been connected to the main chain, and will be null otherwise.
uint256 hashChainHistoryRoot;
//! block header
int nVersion;
uint256 hashMerkleRoot;
uint256 hashLightClientRoot;
uint256 hashBlockCommitments;
unsigned int nTime;
unsigned int nBits;
uint256 nNonce;
@ -297,8 +317,12 @@ public:
nChainTx = 0;
nStatus = 0;
nCachedBranchId = std::nullopt;
hashAuthDataRoot = uint256();
hashSproutAnchor = uint256();
hashFinalSproutRoot = uint256();
hashFinalSaplingRoot = uint256();
hashFinalOrchardRoot = uint256();
hashChainHistoryRoot = uint256();
nSequenceId = 0;
nSproutValue = std::nullopt;
nChainSproutValue = std::nullopt;
@ -307,7 +331,7 @@ public:
nVersion = 0;
hashMerkleRoot = uint256();
hashLightClientRoot = uint256();
hashBlockCommitments = uint256();
nTime = 0;
nBits = 0;
nNonce = uint256();
@ -325,7 +349,7 @@ public:
nVersion = block.nVersion;
hashMerkleRoot = block.hashMerkleRoot;
hashLightClientRoot = block.hashLightClientRoot;
hashBlockCommitments = block.hashBlockCommitments;
nTime = block.nTime;
nBits = block.nBits;
nNonce = block.nNonce;
@ -357,7 +381,7 @@ public:
if (pprev)
block.hashPrevBlock = pprev->GetBlockHash();
block.hashMerkleRoot = hashMerkleRoot;
block.hashLightClientRoot = hashLightClientRoot;
block.hashBlockCommitments = hashBlockCommitments;
block.nTime = nTime;
block.nBits = nBits;
block.nNonce = nNonce;
@ -486,7 +510,7 @@ public:
READWRITE(this->nVersion);
READWRITE(hashPrev);
READWRITE(hashMerkleRoot);
READWRITE(hashLightClientRoot);
READWRITE(hashBlockCommitments);
READWRITE(nTime);
READWRITE(nBits);
READWRITE(nNonce);
@ -512,7 +536,15 @@ public:
} else if (ser_action.ForRead()) {
// For block indices written before the client was Heartwood-aware,
// these are always identical.
hashFinalSaplingRoot = hashLightClientRoot;
hashFinalSaplingRoot = hashBlockCommitments;
}
// Only read/write NU5 data if the client version used to create this
// index was storing them. For block indices written before the client
// was NU5-aware, these are always null / zero.
if ((s.GetType() & SER_DISK) && (nVersion >= NU5_DATA_VERSION)) {
READWRITE(hashAuthDataRoot);
READWRITE(hashFinalOrchardRoot);
}
// If you have just added new serialized fields above, remember to add
@ -525,7 +557,7 @@ public:
block.nVersion = nVersion;
block.hashPrevBlock = hashPrev;
block.hashMerkleRoot = hashMerkleRoot;
block.hashLightClientRoot = hashLightClientRoot;
block.hashBlockCommitments = hashBlockCommitments;
block.nTime = nTime;
block.nBits = nBits;
block.nNonce = nNonce;

View File

@ -2732,7 +2732,8 @@ static bool ShouldCheckTransactions(const CChainParams& chainparams, const CBloc
}
bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex,
CCoinsViewCache& view, const CChainParams& chainparams, bool fJustCheck)
CCoinsViewCache& view, const CChainParams& chainparams,
bool fJustCheck, bool fCheckAuthDataRoot)
{
AssertLockHeld(cs_main);
@ -2998,6 +2999,17 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION);
}
// Derive the various block commitments.
// We only derive them if they will be used for this block.
std::optional<uint256> hashAuthDataRoot;
std::optional<uint256> hashChainHistoryRoot;
if (chainparams.GetConsensus().NetworkUpgradeActive(pindex->nHeight, Consensus::UPGRADE_NU5)) {
hashAuthDataRoot = block.BuildAuthDataMerkleTree();
}
if (chainparams.GetConsensus().NetworkUpgradeActive(pindex->nHeight, Consensus::UPGRADE_HEARTWOOD)) {
hashChainHistoryRoot = view.GetHistoryRoot(prevConsensusBranchId);
}
view.PushAnchor(sprout_tree);
view.PushAnchor(sapling_tree);
if (!fJustCheck) {
@ -3012,19 +3024,48 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
if (chainparams.GetConsensus().NetworkUpgradeActive(pindex->nHeight, Consensus::UPGRADE_HEARTWOOD)) {
pindex->hashFinalSaplingRoot = sapling_tree.root();
}
// - If this block is before NU5 activation:
// - hashAuthDataRoot and hashFinalOrchardRoot are always null.
// - We don't set hashChainHistoryRoot here to maintain the invariant
// documented in CBlockIndex (which was ensured in AddToBlockIndex).
// - If this block is on or after NU5 activation, this is where we set
// the correct values of hashAuthDataRoot, hashFinalOrchardRoot, and
// hashChainHistoryRoot; in particular, blocks that are never passed
// to ConnectBlock() (and thus never on the main chain) will stay with
// these set to null.
if (chainparams.GetConsensus().NetworkUpgradeActive(pindex->nHeight, Consensus::UPGRADE_NU5)) {
pindex->hashAuthDataRoot = hashAuthDataRoot.value();
pindex->hashFinalOrchardRoot = uint256(); // TODO: replace with Orchard tree root
pindex->hashChainHistoryRoot = hashChainHistoryRoot.value();
}
}
blockundo.old_sprout_tree_root = old_sprout_tree_root;
if (IsActivationHeight(pindex->nHeight, chainparams.GetConsensus(), Consensus::UPGRADE_HEARTWOOD)) {
// In the block that activates ZIP 221, block.hashLightClientRoot MUST
if (chainparams.GetConsensus().NetworkUpgradeActive(pindex->nHeight, Consensus::UPGRADE_NU5)) {
if (fCheckAuthDataRoot) {
// If NU5 is active, block.hashBlockCommitments must be the top digest
// of the ZIP 244 block commitments linked list.
// https://zips.z.cash/zip-0244#block-header-changes
uint256 hashBlockCommitments = DeriveBlockCommitmentsHash(
hashChainHistoryRoot.value(),
hashAuthDataRoot.value());
if (block.hashBlockCommitments != hashBlockCommitments) {
return state.DoS(100,
error("ConnectBlock(): block's hashBlockCommitments is incorrect (should be ZIP 244 block commitment)"),
REJECT_INVALID, "bad-block-commitments-hash");
}
}
} else if (IsActivationHeight(pindex->nHeight, chainparams.GetConsensus(), Consensus::UPGRADE_HEARTWOOD)) {
// In the block that activates ZIP 221, block.hashBlockCommitments MUST
// be set to all zero bytes.
if (!block.hashLightClientRoot.IsNull()) {
if (!block.hashBlockCommitments.IsNull()) {
return state.DoS(100,
error("ConnectBlock(): block's hashLightClientRoot is incorrect (should be null)"),
error("ConnectBlock(): block's hashBlockCommitments is incorrect (should be null)"),
REJECT_INVALID, "bad-heartwood-root-in-block");
}
} else if (chainparams.GetConsensus().NetworkUpgradeActive(pindex->nHeight, Consensus::UPGRADE_HEARTWOOD)) {
// If Heartwood is active, block.hashLightClientRoot must be the same as
// If Heartwood is active, block.hashBlockCommitments must be the same as
// the root of the history tree for the previous block. We only store
// one tree per epoch, so we have two possible cases:
// - If the previous block is in the previous epoch, this block won't
@ -3032,17 +3073,17 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
// - If the previous block is in this epoch, this block would affect
// this epoch's tree root, but as we haven't updated the tree for this
// block yet, view.GetHistoryRoot() returns the root we need.
if (block.hashLightClientRoot != view.GetHistoryRoot(prevConsensusBranchId)) {
if (block.hashBlockCommitments != hashChainHistoryRoot.value()) {
return state.DoS(100,
error("ConnectBlock(): block's hashLightClientRoot is incorrect (should be history tree root)"),
error("ConnectBlock(): block's hashBlockCommitments is incorrect (should be history tree root)"),
REJECT_INVALID, "bad-heartwood-root-in-block");
}
} else if (chainparams.GetConsensus().NetworkUpgradeActive(pindex->nHeight, Consensus::UPGRADE_SAPLING)) {
// If Sapling is active, block.hashLightClientRoot must be the
// If Sapling is active, block.hashBlockCommitments must be the
// same as the root of the Sapling tree
if (block.hashLightClientRoot != sapling_tree.root()) {
if (block.hashBlockCommitments != sapling_tree.root()) {
return state.DoS(100,
error("ConnectBlock(): block's hashLightClientRoot is incorrect (should be Sapling tree root)"),
error("ConnectBlock(): block's hashBlockCommitments is incorrect (should be Sapling tree root)"),
REJECT_INVALID, "bad-sapling-root-in-block");
}
}
@ -3910,15 +3951,26 @@ CBlockIndex* AddToBlockIndex(const CBlockHeader& block, const Consensus::Params&
pindexNew->pprev = (*miPrev).second;
pindexNew->nHeight = pindexNew->pprev->nHeight + 1;
if (IsActivationHeight(pindexNew->nHeight, consensusParams, Consensus::UPGRADE_HEARTWOOD)) {
// hashFinalSaplingRoot is currently null, and will be set correctly in ConnectBlock.
if (consensusParams.NetworkUpgradeActive(pindexNew->nHeight, Consensus::UPGRADE_NU5)) {
// The following hashes will be null if this block has never been
// connected to a main chain; they will be (re)set correctly in
// ConnectBlock:
// - hashFinalSaplingRoot
// - hashFinalOrchardRoot
// - hashChainHistoryRoot
} else if (IsActivationHeight(pindexNew->nHeight, consensusParams, Consensus::UPGRADE_HEARTWOOD)) {
// hashFinalSaplingRoot and hashFinalOrchardRoot will be null if this block has
// never been connected to a main chain; they will be (re)set correctly in
// ConnectBlock.
// hashChainHistoryRoot is null.
} else if (consensusParams.NetworkUpgradeActive(pindexNew->nHeight, Consensus::UPGRADE_HEARTWOOD)) {
// hashFinalSaplingRoot is currently null, and will be set correctly in ConnectBlock.
pindexNew->hashChainHistoryRoot = pindexNew->hashLightClientRoot;
// hashFinalSaplingRoot and hashFinalOrchardRoot will be null if this block has
// never been connected to a main chain; they will be (re)set correctly in
// ConnectBlock.
pindexNew->hashChainHistoryRoot = pindexNew->hashBlockCommitments;
} else {
// hashChainHistoryRoot is null.
pindexNew->hashFinalSaplingRoot = pindexNew->hashLightClientRoot;
// hashFinalOrchardRoot and hashChainHistoryRoot are null.
pindexNew->hashFinalSaplingRoot = pindexNew->hashBlockCommitments;
}
pindexNew->BuildSkip();
@ -4565,7 +4617,7 @@ bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams,
return false;
if (!ContextualCheckBlock(block, state, chainparams, pindexPrev, true))
return false;
if (!ConnectBlock(block, state, &indexDummy, viewNew, chainparams, true))
if (!ConnectBlock(block, state, &indexDummy, viewNew, chainparams, true, fCheckMerkleRoot))
return false;
assert(state.IsValid());

View File

@ -486,7 +486,8 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state,
* Validity checks that depend on the UTXO set are also done; ConnectBlock()
* can fail if those validity checks fail (among other reasons). */
bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins,
const CChainParams& chainparams, bool fJustCheck = false);
const CChainParams& chainparams,
bool fJustCheck = false, bool fCheckAuthDataRoot = true);
/**
* Check a block is completely valid from start to finish (only works on top

View File

@ -621,12 +621,17 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const MinerAddre
// Fill in header
pblock->hashPrevBlock = pindexPrev->GetBlockHash();
if (IsActivationHeight(nHeight, chainparams.GetConsensus(), Consensus::UPGRADE_HEARTWOOD)) {
pblock->hashLightClientRoot.SetNull();
if (chainparams.GetConsensus().NetworkUpgradeActive(nHeight, Consensus::UPGRADE_NU5)) {
// hashBlockCommitments depends on the block transactions, so we have to
// update it whenever the coinbase transaction changes. Leave it unset here,
// like hashMerkleRoot, and instead cache what we will need to calculate it.
pblocktemplate->hashChainHistoryRoot = view.GetHistoryRoot(prevConsensusBranchId);
} else if (IsActivationHeight(nHeight, chainparams.GetConsensus(), Consensus::UPGRADE_HEARTWOOD)) {
pblock->hashBlockCommitments.SetNull();
} else if (chainparams.GetConsensus().NetworkUpgradeActive(nHeight, Consensus::UPGRADE_HEARTWOOD)) {
pblock->hashLightClientRoot = view.GetHistoryRoot(prevConsensusBranchId);
pblock->hashBlockCommitments = view.GetHistoryRoot(prevConsensusBranchId);
} else {
pblock->hashLightClientRoot = sapling_tree.root();
pblock->hashBlockCommitments = sapling_tree.root();
}
UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev);
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, chainparams.GetConsensus());
@ -682,8 +687,13 @@ void GetMinerAddress(MinerAddress &minerAddress)
}
}
void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned int& nExtraNonce)
void IncrementExtraNonce(
CBlockTemplate* pblocktemplate,
const CBlockIndex* pindexPrev,
unsigned int& nExtraNonce,
const Consensus::Params& consensusParams)
{
CBlock *pblock = &pblocktemplate->block;
// Update nExtraNonce
static uint256 hashPrevBlock;
if (hashPrevBlock != pblock->hashPrevBlock)
@ -699,6 +709,11 @@ void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned
pblock->vtx[0] = txCoinbase;
pblock->hashMerkleRoot = pblock->BuildMerkleTree();
if (consensusParams.NetworkUpgradeActive(nHeight, Consensus::UPGRADE_NU5)) {
pblock->hashBlockCommitments = DeriveBlockCommitmentsHash(
pblocktemplate->hashChainHistoryRoot,
pblock->BuildAuthDataMerkleTree());
}
}
static bool ProcessBlockFound(const CBlock* pblock, const CChainParams& chainparams)
@ -797,7 +812,7 @@ void static BitcoinMiner(const CChainParams& chainparams)
return;
}
CBlock *pblock = &pblocktemplate->block;
IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
IncrementExtraNonce(pblocktemplate.get(), pindexPrev, nExtraNonce, chainparams.GetConsensus());
LogPrintf("Running ZcashMiner with %u transactions in block (%u bytes)\n", pblock->vtx.size(),
::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION));

View File

@ -67,6 +67,9 @@ public:
struct CBlockTemplate
{
CBlock block;
// Cached whenever we update `block`, so we can update hashBlockCommitments
// when we change the coinbase transaction.
uint256 hashChainHistoryRoot;
std::vector<CAmount> vTxFees;
std::vector<int64_t> vTxSigOps;
};
@ -80,7 +83,11 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const MinerAddre
/** Get -mineraddress */
void GetMinerAddress(MinerAddress &minerAddress);
/** Modify the extranonce in a block */
void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned int& nExtraNonce);
void IncrementExtraNonce(
CBlockTemplate* pblocktemplate,
const CBlockIndex* pindexPrev,
unsigned int& nExtraNonce,
const Consensus::Params& consensusParams);
/** Run the miner threads */
void GenerateBitcoins(bool fGenerate, int nThreads, const CChainParams& chainparams);
#endif

View File

@ -14,6 +14,20 @@
const unsigned char ZCASH_AUTH_DATA_HASH_PERSONALIZATION[BLAKE2bPersonalBytes] =
{'Z','c','a','s','h','A','u','t','h','D','a','t','H','a','s','h'};
const unsigned char ZCASH_BLOCK_COMMITMENTS_HASH_PERSONALIZATION[BLAKE2bPersonalBytes] =
{'Z','c','a','s','h','B','l','o','c','k','C','o','m','m','i','t'};
uint256 DeriveBlockCommitmentsHash(
uint256 hashChainHistoryRoot,
uint256 hashAuthDataRoot)
{
// https://zips.z.cash/zip-0244#block-header-changes
CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_BLOCK_COMMITMENTS_HASH_PERSONALIZATION);
ss << hashChainHistoryRoot;
ss << hashAuthDataRoot;
ss << uint256(); // terminator
return ss.GetHash();
}
uint256 CBlockHeader::GetHash() const
{
@ -164,12 +178,12 @@ uint256 CBlock::BuildAuthDataMerkleTree() const
std::string CBlock::ToString() const
{
std::stringstream s;
s << strprintf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, hashLightClientRoot=%s, nTime=%u, nBits=%08x, nNonce=%s, vtx=%u)\n",
s << strprintf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, hashBlockCommitments=%s, nTime=%u, nBits=%08x, nNonce=%s, vtx=%u)\n",
GetHash().ToString(),
nVersion,
hashPrevBlock.ToString(),
hashMerkleRoot.ToString(),
hashLightClientRoot.ToString(),
hashBlockCommitments.ToString(),
nTime, nBits, nNonce.ToString(),
vtx.size());
for (unsigned int i = 0; i < vtx.size(); i++)

View File

@ -10,6 +10,11 @@
#include "serialize.h"
#include "uint256.h"
// Derives the ZIP 244 block commitments hash.
uint256 DeriveBlockCommitmentsHash(
uint256 hashChainHistoryRoot,
uint256 hashAuthDataRoot);
/** Nodes collect new transactions into a block, hash them into a hash tree,
* and scan through nonce values to make the block's hash satisfy proof-of-work
* requirements. When they solve the proof-of-work, they broadcast the block
@ -26,7 +31,7 @@ public:
int32_t nVersion;
uint256 hashPrevBlock;
uint256 hashMerkleRoot;
uint256 hashLightClientRoot;
uint256 hashBlockCommitments;
uint32_t nTime;
uint32_t nBits;
uint256 nNonce;
@ -44,7 +49,7 @@ public:
READWRITE(this->nVersion);
READWRITE(hashPrevBlock);
READWRITE(hashMerkleRoot);
READWRITE(hashLightClientRoot);
READWRITE(hashBlockCommitments);
READWRITE(nTime);
READWRITE(nBits);
READWRITE(nNonce);
@ -56,7 +61,7 @@ public:
nVersion = CBlockHeader::CURRENT_VERSION;
hashPrevBlock.SetNull();
hashMerkleRoot.SetNull();
hashLightClientRoot.SetNull();
hashBlockCommitments.SetNull();
nTime = 0;
nBits = 0;
nNonce = uint256();
@ -118,7 +123,7 @@ public:
block.nVersion = nVersion;
block.hashPrevBlock = hashPrevBlock;
block.hashMerkleRoot = hashMerkleRoot;
block.hashLightClientRoot = hashLightClientRoot;
block.hashBlockCommitments = hashBlockCommitments;
block.nTime = nTime;
block.nBits = nBits;
block.nNonce = nNonce;
@ -163,7 +168,7 @@ public:
READWRITE(this->nVersion);
READWRITE(hashPrevBlock);
READWRITE(hashMerkleRoot);
READWRITE(hashLightClientRoot);
READWRITE(hashBlockCommitments);
READWRITE(nTime);
READWRITE(nBits);
}

View File

@ -252,6 +252,7 @@ CTransaction& CTransaction::operator=(const CTransaction &tx) {
*const_cast<Ed25519Signature*>(&joinSplitSig) = tx.joinSplitSig;
*const_cast<binding_sig_t*>(&bindingSig) = tx.bindingSig;
*const_cast<uint256*>(&hash) = tx.hash;
*const_cast<uint256*>(&authDigest) = tx.authDigest;
return *this;
}

View File

@ -233,6 +233,8 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx
result.pushKV("height", blockindex->nHeight);
result.pushKV("version", block.nVersion);
result.pushKV("merkleroot", block.hashMerkleRoot.GetHex());
result.pushKV("blockcommitments", blockindex->hashBlockCommitments.GetHex());
result.pushKV("authdataroot", blockindex->hashAuthDataRoot.GetHex());
result.pushKV("finalsaplingroot", blockindex->hashFinalSaplingRoot.GetHex());
result.pushKV("chainhistoryroot", blockindex->hashChainHistoryRoot.GetHex());
UniValue txs(UniValue::VARR);

View File

@ -218,7 +218,7 @@ UniValue generate(const UniValue& params, bool fHelp)
CBlock *pblock = &pblocktemplate->block;
{
LOCK(cs_main);
IncrementExtraNonce(pblock, chainActive.Tip(), nExtraNonce);
IncrementExtraNonce(pblocktemplate.get(), chainActive.Tip(), nExtraNonce, Params().GetConsensus());
}
// Hash state
@ -444,7 +444,8 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
"{\n"
" \"version\" : n, (numeric) The block version\n"
" \"previousblockhash\" : \"xxxx\", (string) The hash of current highest block\n"
" \"lightclientroothash\" : \"xxxx\", (string) The hash of the light client root field in the block header\n"
" \"blockcommitmentshash\" : \"xxxx\", (string) The hash of the block commitments field in the block header\n"
" \"lightclientroothash\" : \"xxxx\", (string) (DEPRECATED) The hash of the light client root field in the block header\n"
" \"finalsaplingroothash\" : \"xxxx\", (string) (DEPRECATED) The hash of the light client root field in the block header\n"
" \"transactions\" : [ (array) contents of non-coinbase transactions that should be included in the next block\n"
" {\n"
@ -756,9 +757,11 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
result.pushKV("capabilities", aCaps);
result.pushKV("version", pblock->nVersion);
result.pushKV("previousblockhash", pblock->hashPrevBlock.GetHex());
result.pushKV("lightclientroothash", pblock->hashLightClientRoot.GetHex());
result.pushKV("blockcommitmentshash", pblock->hashBlockCommitments.GetHex());
// Deprecated; remove in a future release.
result.pushKV("finalsaplingroothash", pblock->hashLightClientRoot.GetHex());
result.pushKV("lightclientroothash", pblock->hashBlockCommitments.GetHex());
// Deprecated; remove in a future release.
result.pushKV("finalsaplingroothash", pblock->hashBlockCommitments.GetHex());
result.pushKV("transactions", transactions);
if (coinbasetxn) {
assert(txCoinbase.isObject());

View File

@ -272,8 +272,8 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
}
*/
// These tests assume null hashLightClientRoot (before Sapling)
pblock->hashLightClientRoot = uint256();
// These tests assume null hashBlockCommitments (before Sapling)
pblock->hashBlockCommitments = uint256();
CValidationState state;
BOOST_CHECK(ProcessNewBlock(state, chainparams, NULL, pblock, true, NULL));

View File

@ -162,7 +162,7 @@ TestChain100Setup::CreateAndProcessBlock(const std::vector<CMutableTransaction>&
block.vtx.push_back(tx);
// IncrementExtraNonce creates a valid coinbase and merkleRoot
unsigned int extraNonce = 0;
IncrementExtraNonce(&block, chainActive.Tip(), extraNonce);
IncrementExtraNonce(pblocktemplate, chainActive.Tip(), extraNonce, chainparams.GetConsensus());
// Hash state
eh_HashState eh_state;

View File

@ -549,7 +549,7 @@ bool CBlockTreeDB::LoadBlockIndexGuts(
pindexNew->hashSproutAnchor = diskindex.hashSproutAnchor;
pindexNew->nVersion = diskindex.nVersion;
pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
pindexNew->hashLightClientRoot = diskindex.hashLightClientRoot;
pindexNew->hashBlockCommitments = diskindex.hashBlockCommitments;
pindexNew->nTime = diskindex.nTime;
pindexNew->nBits = diskindex.nBits;
pindexNew->nNonce = diskindex.nNonce;
@ -560,7 +560,9 @@ bool CBlockTreeDB::LoadBlockIndexGuts(
pindexNew->nSproutValue = diskindex.nSproutValue;
pindexNew->nSaplingValue = diskindex.nSaplingValue;
pindexNew->hashFinalSaplingRoot = diskindex.hashFinalSaplingRoot;
pindexNew->hashFinalOrchardRoot = diskindex.hashFinalOrchardRoot;
pindexNew->hashChainHistoryRoot = diskindex.hashChainHistoryRoot;
pindexNew->hashAuthDataRoot = diskindex.hashAuthDataRoot;
// Consistency checks
auto header = pindexNew->GetBlockHeader();
@ -588,18 +590,23 @@ bool CBlockTreeDB::LoadBlockIndexGuts(
// a non-upgraded peer. However that case the entry will be
// marked as consensus-invalid.
//
if (diskindex.nClientVersion >= CHAIN_HISTORY_ROOT_VERSION &&
if (diskindex.nClientVersion >= NU5_DATA_VERSION &&
chainParams.GetConsensus().NetworkUpgradeActive(pindexNew->nHeight, Consensus::UPGRADE_NU5)) {
// From NU5 onwards we don't enforce a consistency check, because
// after ZIP 244, hashBlockCommitments will not match any stored
// commitment.
} else if (diskindex.nClientVersion >= CHAIN_HISTORY_ROOT_VERSION &&
chainParams.GetConsensus().NetworkUpgradeActive(pindexNew->nHeight, Consensus::UPGRADE_HEARTWOOD)) {
if (pindexNew->hashLightClientRoot != pindexNew->hashChainHistoryRoot) {
if (pindexNew->hashBlockCommitments != pindexNew->hashChainHistoryRoot) {
return error(
"LoadBlockIndex(): block index inconsistency detected (post-Heartwood; hashLightClientRoot %s != hashChainHistoryRoot %s): %s",
pindexNew->hashLightClientRoot.ToString(), pindexNew->hashChainHistoryRoot.ToString(), pindexNew->ToString());
"LoadBlockIndex(): block index inconsistency detected (post-Heartwood; hashBlockCommitments %s != hashChainHistoryRoot %s): %s",
pindexNew->hashBlockCommitments.ToString(), pindexNew->hashChainHistoryRoot.ToString(), pindexNew->ToString());
}
} else {
if (pindexNew->hashLightClientRoot != pindexNew->hashFinalSaplingRoot) {
if (pindexNew->hashBlockCommitments != pindexNew->hashFinalSaplingRoot) {
return error(
"LoadBlockIndex(): block index inconsistency detected (pre-Heartwood; hashLightClientRoot %s != hashFinalSaplingRoot %s): %s",
pindexNew->hashLightClientRoot.ToString(), pindexNew->hashFinalSaplingRoot.ToString(), pindexNew->ToString());
"LoadBlockIndex(): block index inconsistency detected (pre-Heartwood; hashBlockCommitments %s != hashFinalSaplingRoot %s): %s",
pindexNew->hashBlockCommitments.ToString(), pindexNew->hashFinalSaplingRoot.ToString(), pindexNew->ToString());
}
}
}