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:
commit
b0e6119551
|
@ -116,6 +116,7 @@ BASE_SCRIPTS= [
|
||||||
'framework.py',
|
'framework.py',
|
||||||
'sapling_rewind_check.py',
|
'sapling_rewind_check.py',
|
||||||
'feature_zip221.py',
|
'feature_zip221.py',
|
||||||
|
'feature_zip244_blockcommitments.py',
|
||||||
'upgrade_golden.py',
|
'upgrade_golden.py',
|
||||||
'post_heartwood_rollback.py',
|
'post_heartwood_rollback.py',
|
||||||
'feature_logging.py',
|
'feature_logging.py',
|
||||||
|
|
|
@ -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()
|
|
@ -4,6 +4,8 @@
|
||||||
# Distributed under the MIT software license, see the accompanying
|
# Distributed under the MIT software license, see the accompanying
|
||||||
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
|
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
|
||||||
|
|
||||||
|
from pyblake2 import blake2b
|
||||||
|
|
||||||
from .mininode import CBlock, CTransaction, CTxIn, CTxOut, COutPoint
|
from .mininode import CBlock, CTransaction, CTxIn, CTxOut, COutPoint
|
||||||
from .script import CScript, OP_0, OP_EQUAL, OP_HASH160, OP_TRUE, OP_CHECKSIG
|
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()
|
block.calc_sha256()
|
||||||
return block
|
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):
|
def serialize_script_num(value):
|
||||||
r = bytearray(0)
|
r = bytearray(0)
|
||||||
if value == 0:
|
if value == 0:
|
||||||
|
|
52
src/chain.h
52
src/chain.h
|
@ -18,6 +18,7 @@
|
||||||
static const int SPROUT_VALUE_VERSION = 1001400;
|
static const int SPROUT_VALUE_VERSION = 1001400;
|
||||||
static const int SAPLING_VALUE_VERSION = 1010100;
|
static const int SAPLING_VALUE_VERSION = 1010100;
|
||||||
static const int CHAIN_HISTORY_ROOT_VERSION = 2010200;
|
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
|
* 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.
|
//! Persisted at each activation height, memory-only for intervening blocks.
|
||||||
std::optional<uint32_t> nCachedBranchId;
|
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
|
//! The anchor for the tree state up to the start of this block
|
||||||
uint256 hashSproutAnchor;
|
uint256 hashSproutAnchor;
|
||||||
|
|
||||||
|
@ -258,23 +267,34 @@ public:
|
||||||
//! Root of the Sapling commitment tree as of the end of this block.
|
//! 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
|
//! - 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
|
//! - 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.
|
//! once a block has been connected to the main chain, and will be null otherwise.
|
||||||
uint256 hashFinalSaplingRoot;
|
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.
|
//! 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
|
//! - For blocks prior to and including the Heartwood activation block, this is
|
||||||
//! always null.
|
//! always null.
|
||||||
//! - For blocks after (not including) the Heartwood activation block, this is
|
//! - For blocks after (not including) the Heartwood activation block, and prior to
|
||||||
//! always equal to hashLightClientRoot.
|
//! (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;
|
uint256 hashChainHistoryRoot;
|
||||||
|
|
||||||
//! block header
|
//! block header
|
||||||
int nVersion;
|
int nVersion;
|
||||||
uint256 hashMerkleRoot;
|
uint256 hashMerkleRoot;
|
||||||
uint256 hashLightClientRoot;
|
uint256 hashBlockCommitments;
|
||||||
unsigned int nTime;
|
unsigned int nTime;
|
||||||
unsigned int nBits;
|
unsigned int nBits;
|
||||||
uint256 nNonce;
|
uint256 nNonce;
|
||||||
|
@ -297,8 +317,12 @@ public:
|
||||||
nChainTx = 0;
|
nChainTx = 0;
|
||||||
nStatus = 0;
|
nStatus = 0;
|
||||||
nCachedBranchId = std::nullopt;
|
nCachedBranchId = std::nullopt;
|
||||||
|
hashAuthDataRoot = uint256();
|
||||||
hashSproutAnchor = uint256();
|
hashSproutAnchor = uint256();
|
||||||
hashFinalSproutRoot = uint256();
|
hashFinalSproutRoot = uint256();
|
||||||
|
hashFinalSaplingRoot = uint256();
|
||||||
|
hashFinalOrchardRoot = uint256();
|
||||||
|
hashChainHistoryRoot = uint256();
|
||||||
nSequenceId = 0;
|
nSequenceId = 0;
|
||||||
nSproutValue = std::nullopt;
|
nSproutValue = std::nullopt;
|
||||||
nChainSproutValue = std::nullopt;
|
nChainSproutValue = std::nullopt;
|
||||||
|
@ -307,7 +331,7 @@ public:
|
||||||
|
|
||||||
nVersion = 0;
|
nVersion = 0;
|
||||||
hashMerkleRoot = uint256();
|
hashMerkleRoot = uint256();
|
||||||
hashLightClientRoot = uint256();
|
hashBlockCommitments = uint256();
|
||||||
nTime = 0;
|
nTime = 0;
|
||||||
nBits = 0;
|
nBits = 0;
|
||||||
nNonce = uint256();
|
nNonce = uint256();
|
||||||
|
@ -325,7 +349,7 @@ public:
|
||||||
|
|
||||||
nVersion = block.nVersion;
|
nVersion = block.nVersion;
|
||||||
hashMerkleRoot = block.hashMerkleRoot;
|
hashMerkleRoot = block.hashMerkleRoot;
|
||||||
hashLightClientRoot = block.hashLightClientRoot;
|
hashBlockCommitments = block.hashBlockCommitments;
|
||||||
nTime = block.nTime;
|
nTime = block.nTime;
|
||||||
nBits = block.nBits;
|
nBits = block.nBits;
|
||||||
nNonce = block.nNonce;
|
nNonce = block.nNonce;
|
||||||
|
@ -357,7 +381,7 @@ public:
|
||||||
if (pprev)
|
if (pprev)
|
||||||
block.hashPrevBlock = pprev->GetBlockHash();
|
block.hashPrevBlock = pprev->GetBlockHash();
|
||||||
block.hashMerkleRoot = hashMerkleRoot;
|
block.hashMerkleRoot = hashMerkleRoot;
|
||||||
block.hashLightClientRoot = hashLightClientRoot;
|
block.hashBlockCommitments = hashBlockCommitments;
|
||||||
block.nTime = nTime;
|
block.nTime = nTime;
|
||||||
block.nBits = nBits;
|
block.nBits = nBits;
|
||||||
block.nNonce = nNonce;
|
block.nNonce = nNonce;
|
||||||
|
@ -486,7 +510,7 @@ public:
|
||||||
READWRITE(this->nVersion);
|
READWRITE(this->nVersion);
|
||||||
READWRITE(hashPrev);
|
READWRITE(hashPrev);
|
||||||
READWRITE(hashMerkleRoot);
|
READWRITE(hashMerkleRoot);
|
||||||
READWRITE(hashLightClientRoot);
|
READWRITE(hashBlockCommitments);
|
||||||
READWRITE(nTime);
|
READWRITE(nTime);
|
||||||
READWRITE(nBits);
|
READWRITE(nBits);
|
||||||
READWRITE(nNonce);
|
READWRITE(nNonce);
|
||||||
|
@ -512,7 +536,15 @@ public:
|
||||||
} else if (ser_action.ForRead()) {
|
} else if (ser_action.ForRead()) {
|
||||||
// For block indices written before the client was Heartwood-aware,
|
// For block indices written before the client was Heartwood-aware,
|
||||||
// these are always identical.
|
// 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
|
// If you have just added new serialized fields above, remember to add
|
||||||
|
@ -525,7 +557,7 @@ public:
|
||||||
block.nVersion = nVersion;
|
block.nVersion = nVersion;
|
||||||
block.hashPrevBlock = hashPrev;
|
block.hashPrevBlock = hashPrev;
|
||||||
block.hashMerkleRoot = hashMerkleRoot;
|
block.hashMerkleRoot = hashMerkleRoot;
|
||||||
block.hashLightClientRoot = hashLightClientRoot;
|
block.hashBlockCommitments = hashBlockCommitments;
|
||||||
block.nTime = nTime;
|
block.nTime = nTime;
|
||||||
block.nBits = nBits;
|
block.nBits = nBits;
|
||||||
block.nNonce = nNonce;
|
block.nNonce = nNonce;
|
||||||
|
|
88
src/main.cpp
88
src/main.cpp
|
@ -2732,7 +2732,8 @@ static bool ShouldCheckTransactions(const CChainParams& chainparams, const CBloc
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex,
|
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);
|
AssertLockHeld(cs_main);
|
||||||
|
|
||||||
|
@ -2998,6 +2999,17 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
||||||
pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION);
|
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(sprout_tree);
|
||||||
view.PushAnchor(sapling_tree);
|
view.PushAnchor(sapling_tree);
|
||||||
if (!fJustCheck) {
|
if (!fJustCheck) {
|
||||||
|
@ -3012,19 +3024,48 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
||||||
if (chainparams.GetConsensus().NetworkUpgradeActive(pindex->nHeight, Consensus::UPGRADE_HEARTWOOD)) {
|
if (chainparams.GetConsensus().NetworkUpgradeActive(pindex->nHeight, Consensus::UPGRADE_HEARTWOOD)) {
|
||||||
pindex->hashFinalSaplingRoot = sapling_tree.root();
|
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;
|
blockundo.old_sprout_tree_root = old_sprout_tree_root;
|
||||||
|
|
||||||
if (IsActivationHeight(pindex->nHeight, chainparams.GetConsensus(), Consensus::UPGRADE_HEARTWOOD)) {
|
if (chainparams.GetConsensus().NetworkUpgradeActive(pindex->nHeight, Consensus::UPGRADE_NU5)) {
|
||||||
// In the block that activates ZIP 221, block.hashLightClientRoot MUST
|
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.
|
// be set to all zero bytes.
|
||||||
if (!block.hashLightClientRoot.IsNull()) {
|
if (!block.hashBlockCommitments.IsNull()) {
|
||||||
return state.DoS(100,
|
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");
|
REJECT_INVALID, "bad-heartwood-root-in-block");
|
||||||
}
|
}
|
||||||
} else if (chainparams.GetConsensus().NetworkUpgradeActive(pindex->nHeight, Consensus::UPGRADE_HEARTWOOD)) {
|
} 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
|
// the root of the history tree for the previous block. We only store
|
||||||
// one tree per epoch, so we have two possible cases:
|
// one tree per epoch, so we have two possible cases:
|
||||||
// - If the previous block is in the previous epoch, this block won't
|
// - 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
|
// - 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
|
// this epoch's tree root, but as we haven't updated the tree for this
|
||||||
// block yet, view.GetHistoryRoot() returns the root we need.
|
// block yet, view.GetHistoryRoot() returns the root we need.
|
||||||
if (block.hashLightClientRoot != view.GetHistoryRoot(prevConsensusBranchId)) {
|
if (block.hashBlockCommitments != hashChainHistoryRoot.value()) {
|
||||||
return state.DoS(100,
|
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");
|
REJECT_INVALID, "bad-heartwood-root-in-block");
|
||||||
}
|
}
|
||||||
} else if (chainparams.GetConsensus().NetworkUpgradeActive(pindex->nHeight, Consensus::UPGRADE_SAPLING)) {
|
} 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
|
// same as the root of the Sapling tree
|
||||||
if (block.hashLightClientRoot != sapling_tree.root()) {
|
if (block.hashBlockCommitments != sapling_tree.root()) {
|
||||||
return state.DoS(100,
|
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");
|
REJECT_INVALID, "bad-sapling-root-in-block");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3910,15 +3951,26 @@ CBlockIndex* AddToBlockIndex(const CBlockHeader& block, const Consensus::Params&
|
||||||
pindexNew->pprev = (*miPrev).second;
|
pindexNew->pprev = (*miPrev).second;
|
||||||
pindexNew->nHeight = pindexNew->pprev->nHeight + 1;
|
pindexNew->nHeight = pindexNew->pprev->nHeight + 1;
|
||||||
|
|
||||||
if (IsActivationHeight(pindexNew->nHeight, consensusParams, Consensus::UPGRADE_HEARTWOOD)) {
|
if (consensusParams.NetworkUpgradeActive(pindexNew->nHeight, Consensus::UPGRADE_NU5)) {
|
||||||
// hashFinalSaplingRoot is currently null, and will be set correctly in ConnectBlock.
|
// 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.
|
// hashChainHistoryRoot is null.
|
||||||
} else if (consensusParams.NetworkUpgradeActive(pindexNew->nHeight, Consensus::UPGRADE_HEARTWOOD)) {
|
} else if (consensusParams.NetworkUpgradeActive(pindexNew->nHeight, Consensus::UPGRADE_HEARTWOOD)) {
|
||||||
// hashFinalSaplingRoot is currently null, and will be set correctly in ConnectBlock.
|
// hashFinalSaplingRoot and hashFinalOrchardRoot will be null if this block has
|
||||||
pindexNew->hashChainHistoryRoot = pindexNew->hashLightClientRoot;
|
// never been connected to a main chain; they will be (re)set correctly in
|
||||||
|
// ConnectBlock.
|
||||||
|
pindexNew->hashChainHistoryRoot = pindexNew->hashBlockCommitments;
|
||||||
} else {
|
} else {
|
||||||
// hashChainHistoryRoot is null.
|
// hashFinalOrchardRoot and hashChainHistoryRoot are null.
|
||||||
pindexNew->hashFinalSaplingRoot = pindexNew->hashLightClientRoot;
|
pindexNew->hashFinalSaplingRoot = pindexNew->hashBlockCommitments;
|
||||||
}
|
}
|
||||||
|
|
||||||
pindexNew->BuildSkip();
|
pindexNew->BuildSkip();
|
||||||
|
@ -4565,7 +4617,7 @@ bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams,
|
||||||
return false;
|
return false;
|
||||||
if (!ContextualCheckBlock(block, state, chainparams, pindexPrev, true))
|
if (!ContextualCheckBlock(block, state, chainparams, pindexPrev, true))
|
||||||
return false;
|
return false;
|
||||||
if (!ConnectBlock(block, state, &indexDummy, viewNew, chainparams, true))
|
if (!ConnectBlock(block, state, &indexDummy, viewNew, chainparams, true, fCheckMerkleRoot))
|
||||||
return false;
|
return false;
|
||||||
assert(state.IsValid());
|
assert(state.IsValid());
|
||||||
|
|
||||||
|
|
|
@ -486,7 +486,8 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state,
|
||||||
* Validity checks that depend on the UTXO set are also done; ConnectBlock()
|
* Validity checks that depend on the UTXO set are also done; ConnectBlock()
|
||||||
* can fail if those validity checks fail (among other reasons). */
|
* can fail if those validity checks fail (among other reasons). */
|
||||||
bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins,
|
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
|
* Check a block is completely valid from start to finish (only works on top
|
||||||
|
|
|
@ -621,12 +621,17 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const MinerAddre
|
||||||
|
|
||||||
// Fill in header
|
// Fill in header
|
||||||
pblock->hashPrevBlock = pindexPrev->GetBlockHash();
|
pblock->hashPrevBlock = pindexPrev->GetBlockHash();
|
||||||
if (IsActivationHeight(nHeight, chainparams.GetConsensus(), Consensus::UPGRADE_HEARTWOOD)) {
|
if (chainparams.GetConsensus().NetworkUpgradeActive(nHeight, Consensus::UPGRADE_NU5)) {
|
||||||
pblock->hashLightClientRoot.SetNull();
|
// 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)) {
|
} else if (chainparams.GetConsensus().NetworkUpgradeActive(nHeight, Consensus::UPGRADE_HEARTWOOD)) {
|
||||||
pblock->hashLightClientRoot = view.GetHistoryRoot(prevConsensusBranchId);
|
pblock->hashBlockCommitments = view.GetHistoryRoot(prevConsensusBranchId);
|
||||||
} else {
|
} else {
|
||||||
pblock->hashLightClientRoot = sapling_tree.root();
|
pblock->hashBlockCommitments = sapling_tree.root();
|
||||||
}
|
}
|
||||||
UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev);
|
UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev);
|
||||||
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, chainparams.GetConsensus());
|
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
|
// Update nExtraNonce
|
||||||
static uint256 hashPrevBlock;
|
static uint256 hashPrevBlock;
|
||||||
if (hashPrevBlock != pblock->hashPrevBlock)
|
if (hashPrevBlock != pblock->hashPrevBlock)
|
||||||
|
@ -699,6 +709,11 @@ void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned
|
||||||
|
|
||||||
pblock->vtx[0] = txCoinbase;
|
pblock->vtx[0] = txCoinbase;
|
||||||
pblock->hashMerkleRoot = pblock->BuildMerkleTree();
|
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)
|
static bool ProcessBlockFound(const CBlock* pblock, const CChainParams& chainparams)
|
||||||
|
@ -797,7 +812,7 @@ void static BitcoinMiner(const CChainParams& chainparams)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
CBlock *pblock = &pblocktemplate->block;
|
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(),
|
LogPrintf("Running ZcashMiner with %u transactions in block (%u bytes)\n", pblock->vtx.size(),
|
||||||
::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION));
|
::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION));
|
||||||
|
|
|
@ -67,6 +67,9 @@ public:
|
||||||
struct CBlockTemplate
|
struct CBlockTemplate
|
||||||
{
|
{
|
||||||
CBlock block;
|
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<CAmount> vTxFees;
|
||||||
std::vector<int64_t> vTxSigOps;
|
std::vector<int64_t> vTxSigOps;
|
||||||
};
|
};
|
||||||
|
@ -80,7 +83,11 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const MinerAddre
|
||||||
/** Get -mineraddress */
|
/** Get -mineraddress */
|
||||||
void GetMinerAddress(MinerAddress &minerAddress);
|
void GetMinerAddress(MinerAddress &minerAddress);
|
||||||
/** Modify the extranonce in a block */
|
/** 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 */
|
/** Run the miner threads */
|
||||||
void GenerateBitcoins(bool fGenerate, int nThreads, const CChainParams& chainparams);
|
void GenerateBitcoins(bool fGenerate, int nThreads, const CChainParams& chainparams);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -14,6 +14,20 @@
|
||||||
|
|
||||||
const unsigned char ZCASH_AUTH_DATA_HASH_PERSONALIZATION[BLAKE2bPersonalBytes] =
|
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'};
|
{'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
|
uint256 CBlockHeader::GetHash() const
|
||||||
{
|
{
|
||||||
|
@ -164,12 +178,12 @@ uint256 CBlock::BuildAuthDataMerkleTree() const
|
||||||
std::string CBlock::ToString() const
|
std::string CBlock::ToString() const
|
||||||
{
|
{
|
||||||
std::stringstream s;
|
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(),
|
GetHash().ToString(),
|
||||||
nVersion,
|
nVersion,
|
||||||
hashPrevBlock.ToString(),
|
hashPrevBlock.ToString(),
|
||||||
hashMerkleRoot.ToString(),
|
hashMerkleRoot.ToString(),
|
||||||
hashLightClientRoot.ToString(),
|
hashBlockCommitments.ToString(),
|
||||||
nTime, nBits, nNonce.ToString(),
|
nTime, nBits, nNonce.ToString(),
|
||||||
vtx.size());
|
vtx.size());
|
||||||
for (unsigned int i = 0; i < vtx.size(); i++)
|
for (unsigned int i = 0; i < vtx.size(); i++)
|
||||||
|
|
|
@ -10,6 +10,11 @@
|
||||||
#include "serialize.h"
|
#include "serialize.h"
|
||||||
#include "uint256.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,
|
/** 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
|
* 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
|
* requirements. When they solve the proof-of-work, they broadcast the block
|
||||||
|
@ -26,7 +31,7 @@ public:
|
||||||
int32_t nVersion;
|
int32_t nVersion;
|
||||||
uint256 hashPrevBlock;
|
uint256 hashPrevBlock;
|
||||||
uint256 hashMerkleRoot;
|
uint256 hashMerkleRoot;
|
||||||
uint256 hashLightClientRoot;
|
uint256 hashBlockCommitments;
|
||||||
uint32_t nTime;
|
uint32_t nTime;
|
||||||
uint32_t nBits;
|
uint32_t nBits;
|
||||||
uint256 nNonce;
|
uint256 nNonce;
|
||||||
|
@ -44,7 +49,7 @@ public:
|
||||||
READWRITE(this->nVersion);
|
READWRITE(this->nVersion);
|
||||||
READWRITE(hashPrevBlock);
|
READWRITE(hashPrevBlock);
|
||||||
READWRITE(hashMerkleRoot);
|
READWRITE(hashMerkleRoot);
|
||||||
READWRITE(hashLightClientRoot);
|
READWRITE(hashBlockCommitments);
|
||||||
READWRITE(nTime);
|
READWRITE(nTime);
|
||||||
READWRITE(nBits);
|
READWRITE(nBits);
|
||||||
READWRITE(nNonce);
|
READWRITE(nNonce);
|
||||||
|
@ -56,7 +61,7 @@ public:
|
||||||
nVersion = CBlockHeader::CURRENT_VERSION;
|
nVersion = CBlockHeader::CURRENT_VERSION;
|
||||||
hashPrevBlock.SetNull();
|
hashPrevBlock.SetNull();
|
||||||
hashMerkleRoot.SetNull();
|
hashMerkleRoot.SetNull();
|
||||||
hashLightClientRoot.SetNull();
|
hashBlockCommitments.SetNull();
|
||||||
nTime = 0;
|
nTime = 0;
|
||||||
nBits = 0;
|
nBits = 0;
|
||||||
nNonce = uint256();
|
nNonce = uint256();
|
||||||
|
@ -118,7 +123,7 @@ public:
|
||||||
block.nVersion = nVersion;
|
block.nVersion = nVersion;
|
||||||
block.hashPrevBlock = hashPrevBlock;
|
block.hashPrevBlock = hashPrevBlock;
|
||||||
block.hashMerkleRoot = hashMerkleRoot;
|
block.hashMerkleRoot = hashMerkleRoot;
|
||||||
block.hashLightClientRoot = hashLightClientRoot;
|
block.hashBlockCommitments = hashBlockCommitments;
|
||||||
block.nTime = nTime;
|
block.nTime = nTime;
|
||||||
block.nBits = nBits;
|
block.nBits = nBits;
|
||||||
block.nNonce = nNonce;
|
block.nNonce = nNonce;
|
||||||
|
@ -163,7 +168,7 @@ public:
|
||||||
READWRITE(this->nVersion);
|
READWRITE(this->nVersion);
|
||||||
READWRITE(hashPrevBlock);
|
READWRITE(hashPrevBlock);
|
||||||
READWRITE(hashMerkleRoot);
|
READWRITE(hashMerkleRoot);
|
||||||
READWRITE(hashLightClientRoot);
|
READWRITE(hashBlockCommitments);
|
||||||
READWRITE(nTime);
|
READWRITE(nTime);
|
||||||
READWRITE(nBits);
|
READWRITE(nBits);
|
||||||
}
|
}
|
||||||
|
|
|
@ -252,6 +252,7 @@ CTransaction& CTransaction::operator=(const CTransaction &tx) {
|
||||||
*const_cast<Ed25519Signature*>(&joinSplitSig) = tx.joinSplitSig;
|
*const_cast<Ed25519Signature*>(&joinSplitSig) = tx.joinSplitSig;
|
||||||
*const_cast<binding_sig_t*>(&bindingSig) = tx.bindingSig;
|
*const_cast<binding_sig_t*>(&bindingSig) = tx.bindingSig;
|
||||||
*const_cast<uint256*>(&hash) = tx.hash;
|
*const_cast<uint256*>(&hash) = tx.hash;
|
||||||
|
*const_cast<uint256*>(&authDigest) = tx.authDigest;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -233,6 +233,8 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx
|
||||||
result.pushKV("height", blockindex->nHeight);
|
result.pushKV("height", blockindex->nHeight);
|
||||||
result.pushKV("version", block.nVersion);
|
result.pushKV("version", block.nVersion);
|
||||||
result.pushKV("merkleroot", block.hashMerkleRoot.GetHex());
|
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("finalsaplingroot", blockindex->hashFinalSaplingRoot.GetHex());
|
||||||
result.pushKV("chainhistoryroot", blockindex->hashChainHistoryRoot.GetHex());
|
result.pushKV("chainhistoryroot", blockindex->hashChainHistoryRoot.GetHex());
|
||||||
UniValue txs(UniValue::VARR);
|
UniValue txs(UniValue::VARR);
|
||||||
|
|
|
@ -218,7 +218,7 @@ UniValue generate(const UniValue& params, bool fHelp)
|
||||||
CBlock *pblock = &pblocktemplate->block;
|
CBlock *pblock = &pblocktemplate->block;
|
||||||
{
|
{
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
IncrementExtraNonce(pblock, chainActive.Tip(), nExtraNonce);
|
IncrementExtraNonce(pblocktemplate.get(), chainActive.Tip(), nExtraNonce, Params().GetConsensus());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hash state
|
// Hash state
|
||||||
|
@ -444,7 +444,8 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
|
||||||
"{\n"
|
"{\n"
|
||||||
" \"version\" : n, (numeric) The block version\n"
|
" \"version\" : n, (numeric) The block version\n"
|
||||||
" \"previousblockhash\" : \"xxxx\", (string) The hash of current highest block\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"
|
" \"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"
|
" \"transactions\" : [ (array) contents of non-coinbase transactions that should be included in the next block\n"
|
||||||
" {\n"
|
" {\n"
|
||||||
|
@ -756,9 +757,11 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
|
||||||
result.pushKV("capabilities", aCaps);
|
result.pushKV("capabilities", aCaps);
|
||||||
result.pushKV("version", pblock->nVersion);
|
result.pushKV("version", pblock->nVersion);
|
||||||
result.pushKV("previousblockhash", pblock->hashPrevBlock.GetHex());
|
result.pushKV("previousblockhash", pblock->hashPrevBlock.GetHex());
|
||||||
result.pushKV("lightclientroothash", pblock->hashLightClientRoot.GetHex());
|
result.pushKV("blockcommitmentshash", pblock->hashBlockCommitments.GetHex());
|
||||||
// Deprecated; remove in a future release.
|
// 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);
|
result.pushKV("transactions", transactions);
|
||||||
if (coinbasetxn) {
|
if (coinbasetxn) {
|
||||||
assert(txCoinbase.isObject());
|
assert(txCoinbase.isObject());
|
||||||
|
|
|
@ -272,8 +272,8 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// These tests assume null hashLightClientRoot (before Sapling)
|
// These tests assume null hashBlockCommitments (before Sapling)
|
||||||
pblock->hashLightClientRoot = uint256();
|
pblock->hashBlockCommitments = uint256();
|
||||||
|
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
BOOST_CHECK(ProcessNewBlock(state, chainparams, NULL, pblock, true, NULL));
|
BOOST_CHECK(ProcessNewBlock(state, chainparams, NULL, pblock, true, NULL));
|
||||||
|
|
|
@ -162,7 +162,7 @@ TestChain100Setup::CreateAndProcessBlock(const std::vector<CMutableTransaction>&
|
||||||
block.vtx.push_back(tx);
|
block.vtx.push_back(tx);
|
||||||
// IncrementExtraNonce creates a valid coinbase and merkleRoot
|
// IncrementExtraNonce creates a valid coinbase and merkleRoot
|
||||||
unsigned int extraNonce = 0;
|
unsigned int extraNonce = 0;
|
||||||
IncrementExtraNonce(&block, chainActive.Tip(), extraNonce);
|
IncrementExtraNonce(pblocktemplate, chainActive.Tip(), extraNonce, chainparams.GetConsensus());
|
||||||
|
|
||||||
// Hash state
|
// Hash state
|
||||||
eh_HashState eh_state;
|
eh_HashState eh_state;
|
||||||
|
|
23
src/txdb.cpp
23
src/txdb.cpp
|
@ -549,7 +549,7 @@ bool CBlockTreeDB::LoadBlockIndexGuts(
|
||||||
pindexNew->hashSproutAnchor = diskindex.hashSproutAnchor;
|
pindexNew->hashSproutAnchor = diskindex.hashSproutAnchor;
|
||||||
pindexNew->nVersion = diskindex.nVersion;
|
pindexNew->nVersion = diskindex.nVersion;
|
||||||
pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
|
pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
|
||||||
pindexNew->hashLightClientRoot = diskindex.hashLightClientRoot;
|
pindexNew->hashBlockCommitments = diskindex.hashBlockCommitments;
|
||||||
pindexNew->nTime = diskindex.nTime;
|
pindexNew->nTime = diskindex.nTime;
|
||||||
pindexNew->nBits = diskindex.nBits;
|
pindexNew->nBits = diskindex.nBits;
|
||||||
pindexNew->nNonce = diskindex.nNonce;
|
pindexNew->nNonce = diskindex.nNonce;
|
||||||
|
@ -560,7 +560,9 @@ bool CBlockTreeDB::LoadBlockIndexGuts(
|
||||||
pindexNew->nSproutValue = diskindex.nSproutValue;
|
pindexNew->nSproutValue = diskindex.nSproutValue;
|
||||||
pindexNew->nSaplingValue = diskindex.nSaplingValue;
|
pindexNew->nSaplingValue = diskindex.nSaplingValue;
|
||||||
pindexNew->hashFinalSaplingRoot = diskindex.hashFinalSaplingRoot;
|
pindexNew->hashFinalSaplingRoot = diskindex.hashFinalSaplingRoot;
|
||||||
|
pindexNew->hashFinalOrchardRoot = diskindex.hashFinalOrchardRoot;
|
||||||
pindexNew->hashChainHistoryRoot = diskindex.hashChainHistoryRoot;
|
pindexNew->hashChainHistoryRoot = diskindex.hashChainHistoryRoot;
|
||||||
|
pindexNew->hashAuthDataRoot = diskindex.hashAuthDataRoot;
|
||||||
|
|
||||||
// Consistency checks
|
// Consistency checks
|
||||||
auto header = pindexNew->GetBlockHeader();
|
auto header = pindexNew->GetBlockHeader();
|
||||||
|
@ -588,18 +590,23 @@ bool CBlockTreeDB::LoadBlockIndexGuts(
|
||||||
// a non-upgraded peer. However that case the entry will be
|
// a non-upgraded peer. However that case the entry will be
|
||||||
// marked as consensus-invalid.
|
// 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)) {
|
chainParams.GetConsensus().NetworkUpgradeActive(pindexNew->nHeight, Consensus::UPGRADE_HEARTWOOD)) {
|
||||||
if (pindexNew->hashLightClientRoot != pindexNew->hashChainHistoryRoot) {
|
if (pindexNew->hashBlockCommitments != pindexNew->hashChainHistoryRoot) {
|
||||||
return error(
|
return error(
|
||||||
"LoadBlockIndex(): block index inconsistency detected (post-Heartwood; hashLightClientRoot %s != hashChainHistoryRoot %s): %s",
|
"LoadBlockIndex(): block index inconsistency detected (post-Heartwood; hashBlockCommitments %s != hashChainHistoryRoot %s): %s",
|
||||||
pindexNew->hashLightClientRoot.ToString(), pindexNew->hashChainHistoryRoot.ToString(), pindexNew->ToString());
|
pindexNew->hashBlockCommitments.ToString(), pindexNew->hashChainHistoryRoot.ToString(), pindexNew->ToString());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (pindexNew->hashLightClientRoot != pindexNew->hashFinalSaplingRoot) {
|
if (pindexNew->hashBlockCommitments != pindexNew->hashFinalSaplingRoot) {
|
||||||
return error(
|
return error(
|
||||||
"LoadBlockIndex(): block index inconsistency detected (pre-Heartwood; hashLightClientRoot %s != hashFinalSaplingRoot %s): %s",
|
"LoadBlockIndex(): block index inconsistency detected (pre-Heartwood; hashBlockCommitments %s != hashFinalSaplingRoot %s): %s",
|
||||||
pindexNew->hashLightClientRoot.ToString(), pindexNew->hashFinalSaplingRoot.ToString(), pindexNew->ToString());
|
pindexNew->hashBlockCommitments.ToString(), pindexNew->hashFinalSaplingRoot.ToString(), pindexNew->ToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue