Merge pull request #5454 from zcash/hotfix-v4.6.0-1

Hotfix v4.6.0-1
This commit is contained in:
Kris Nuttycombe 2022-01-05 18:15:33 -07:00 committed by GitHub
commit 0403799be2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 247 additions and 71 deletions

View File

@ -1,4 +1,4 @@
Zcash 4.6.0
Zcash 4.6.0-1
<img align="right" width="120" height="80" src="doc/imgs/logo.png">
===========

View File

@ -3,7 +3,7 @@ AC_PREREQ([2.60])
define(_CLIENT_VERSION_MAJOR, 4)
define(_CLIENT_VERSION_MINOR, 6)
define(_CLIENT_VERSION_REVISION, 0)
define(_CLIENT_VERSION_BUILD, 50)
define(_CLIENT_VERSION_BUILD, 51)
define(_ZC_BUILD_VAL, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, m4_incr(_CLIENT_VERSION_BUILD), m4_eval(_CLIENT_VERSION_BUILD < 50), 1, m4_eval(_CLIENT_VERSION_BUILD - 24), m4_eval(_CLIENT_VERSION_BUILD == 50), 1, , m4_eval(_CLIENT_VERSION_BUILD - 50)))
define(_CLIENT_VERSION_SUFFIX, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, _CLIENT_VERSION_REVISION-beta$1, m4_eval(_CLIENT_VERSION_BUILD < 50), 1, _CLIENT_VERSION_REVISION-rc$1, m4_eval(_CLIENT_VERSION_BUILD == 50), 1, _CLIENT_VERSION_REVISION, _CLIENT_VERSION_REVISION-$1)))
define(_CLIENT_VERSION_IS_RELEASE, true)

View File

@ -1,3 +1,9 @@
zcash (4.6.0+1) stable; urgency=medium
* 4.6.0-1 release.
-- Electric Coin Company <team@electriccoin.co> Wed, 05 Jan 2022 20:18:43 +0000
zcash (4.6.0) stable; urgency=medium
* 4.6.0 release.

View File

@ -1,5 +1,5 @@
---
name: "zcash-4.6.0"
name: "zcash-4.6.0-1"
enable_cache: true
distro: "debian"
suites:

View File

@ -1,7 +1,7 @@
Zcash Contributors
==================
Jack Grigg (1124)
Jack Grigg (1127)
Simon Liu (460)
Sean Bowe (367)
Daira Hopwood (270)
@ -16,7 +16,7 @@ Jonas Schnelli (89)
Jay Graber (89)
Marco Falke (82)
Cory Fields (75)
Larry Ruane (69)
Larry Ruane (72)
Ying Tong Lai (56)
Nathan Wilcox (56)
Matt Corallo (52)

View File

@ -1,9 +1,9 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.48.1.
.TH ZCASH-CLI "1" "December 2021" "zcash-cli v4.6.0" "User Commands"
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.13.
.TH ZCASH-CLI "1" "January 2022" "zcash-cli v4.6.0-1" "User Commands"
.SH NAME
zcash-cli \- manual page for zcash-cli v4.6.0
zcash-cli \- manual page for zcash-cli v4.6.0-1
.SH DESCRIPTION
Zcash RPC client version v4.6.0
Zcash RPC client version v4.6.0\-1
.PP
In order to ensure you are adequately protecting your privacy when using Zcash,
please see <https://z.cash/support/security/>.

View File

@ -1,9 +1,9 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.48.1.
.TH ZCASH-TX "1" "December 2021" "zcash-tx v4.6.0" "User Commands"
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.13.
.TH ZCASH-TX "1" "January 2022" "zcash-tx v4.6.0-1" "User Commands"
.SH NAME
zcash-tx \- manual page for zcash-tx v4.6.0
zcash-tx \- manual page for zcash-tx v4.6.0-1
.SH DESCRIPTION
Zcash zcash\-tx utility version v4.6.0
Zcash zcash\-tx utility version v4.6.0\-1
.SS "Usage:"
.TP
zcash\-tx [options] <hex\-tx> [commands]

View File

@ -1,9 +1,9 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.48.1.
.TH ZCASHD "1" "December 2021" "zcashd v4.6.0" "User Commands"
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.13.
.TH ZCASHD "1" "January 2022" "zcashd v4.6.0-1" "User Commands"
.SH NAME
zcashd \- manual page for zcashd v4.6.0
zcashd \- manual page for zcashd v4.6.0-1
.SH DESCRIPTION
Zcash Daemon version v4.6.0
Zcash Daemon version v4.6.0\-1
.PP
In order to ensure you are adequately protecting your privacy when using Zcash,
please see <https://z.cash/support/security/>.
@ -84,7 +84,7 @@ Keep at most <n> unconnectable transactions in memory (default: 100)
.HP
\fB\-par=\fR<n>
.IP
Set the number of script verification threads (\fB\-8\fR to 16, 0 = auto, <0 =
Set the number of script verification threads (\fB\-16\fR to 16, 0 = auto, <0 =
leave that many cores free, default: 0)
.HP
\fB\-pid=\fR<file>

View File

@ -0,0 +1,37 @@
`getblocktemplate` regression fix
=================================
We added support for the NU5 consensus rules in v4.5.0, which alters the
block header to contain a `hashBlockCommitments` value instead of the
chain history root. However, the output of `getblocktemplate` wasn't
returning this value; once NU5 activated, the `blockcommitmentshash`
field was being set to "null" (all-zeroes).
In v4.6.0 we added full NU5 support to `getblocktemplate`, by adding a
`defaultroots` field that gave default values for `hashBlockCommitments`
and the components required to derive it. However, in doing so we
introduced a regression in the (now-deprecated) legacy fields, where
prior to NU5 activation they contained nonsense.
This release fixes the output of `getblocktemplate` to have the intended
semantics for all fields:
- The `blockcommitmentshash` and `authdataroot` fields in `defaultroots`
are now omitted from block templates for heights before NU5 activation.
- The legacy fields now always contain the default value to be placed
into the block header (regaining their previous semantics).
Changelog
=========
Jack Grigg (3):
rpc: Fix regression in getblocktemplate output
make-release.py: Versioning changes for 4.6.0-1.
make-release.py: Updated manpages for 4.6.0-1.
Larry Ruane (3):
assert that the return value of submitblock is None
test: check getblocktemplate output before and after NU5
test: Fix ZIP 244 implementation

View File

@ -8,11 +8,8 @@ import codecs
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
BLOSSOM_BRANCH_ID,
CANOPY_BRANCH_ID,
HEARTWOOD_BRANCH_ID,
NU5_BRANCH_ID,
get_coinbase_address,
hex_str_to_bytes,
nuparams,
start_nodes,
@ -20,8 +17,9 @@ from test_framework.util import (
)
from test_framework.mininode import (
CTransaction,
uint256_from_str,
)
from test_framework.blocktools import(
from test_framework.blocktools import (
create_block
)
from decimal import Decimal
@ -39,48 +37,57 @@ class GetBlockTemplateTest(BitcoinTestFramework):
def setup_network(self, split=False):
args = [
nuparams(BLOSSOM_BRANCH_ID, 1),
nuparams(HEARTWOOD_BRANCH_ID, 1),
nuparams(CANOPY_BRANCH_ID, 1),
nuparams(NU5_BRANCH_ID, 1),
nuparams(CANOPY_BRANCH_ID, 115),
nuparams(NU5_BRANCH_ID, 130),
]
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, [args] * self.num_nodes)
self.is_network_split=False
self.sync_all()
self.is_network_split = False
self.node = self.nodes[0]
def run_test(self):
node = self.nodes[0]
print("Generating blocks")
node.generate(110)
def add_nu5_v4_tx_to_mempool(self):
node = self.node
# sprout to transparent (v4)
recipients = [{"address": self.transparent_addr, "amount": Decimal('0.1')}]
myopid = node.z_sendmany(self.sprout_addr, recipients)
wait_and_assert_operationid_status(node, myopid)
print("Add transactions to the mempool so they will be in the template")
# This part of the test should be improved, submit some V4 transactions
# and varying combinations of shielded and transparent
for _ in range(5):
# submit a tx with a shielded output
taddr0 = get_coinbase_address(node)
zaddr = node.z_getnewaddress('sapling')
recipients = [{"address": zaddr, "amount": Decimal('0.1')}]
myopid = node.z_sendmany(taddr0, recipients, 1, 0)
wait_and_assert_operationid_status(node, myopid)
def add_transparent_tx_to_mempool(self):
node = self.node
# transparent to transparent (v5 after nu5)
outputs = {self.transparent_addr: 0.1}
node.sendmany('', outputs)
# submit a tx with a transparent output
outputs = {node.getnewaddress():0.2}
node.sendmany('', outputs)
def gbt_submitblock(self, nu5_active):
node = self.node
mempool_tx_list = node.getrawmempool()
print("Getting block template")
gbt = node.getblocktemplate()
# make sure no transactions were left out (or added)
assert_equal(len(mempool_tx_list), len(gbt['transactions']))
assert_equal(set(mempool_tx_list), set([tx['hash'] for tx in gbt['transactions']]))
prevhash = int(gbt['previousblockhash'], 16)
blockcommitmentshash = int(gbt['defaultroots']['blockcommitmentshash'], 16)
nTime = gbt['mintime']
nBits = int(gbt['bits'], 16)
if nu5_active:
blockcommitmentshash = int(gbt['defaultroots']['blockcommitmentshash'], 16)
else:
blockcommitmentshash = int(gbt['defaultroots']['chainhistoryroot'], 16)
assert 'blockcommitmentshash' not in gbt['defaultroots']
# Confirm that the legacy fields match this default value.
assert_equal(blockcommitmentshash, int(gbt['blockcommitmentshash'], 16))
assert_equal(blockcommitmentshash, int(gbt['lightclientroothash'], 16))
assert_equal(blockcommitmentshash, int(gbt['finalsaplingroothash'], 16))
f = BytesIO(hex_str_to_bytes(gbt['coinbasetxn']['data']))
coinbase = CTransaction()
coinbase.deserialize(f)
coinbase.calc_sha256()
assert_equal(coinbase.hash, gbt['coinbasetxn']['hash'])
assert_equal(coinbase.auth_digest_hex, gbt['coinbasetxn']['authdigest'])
print("Creating_block from template (simulating a miner)")
block = create_block(prevhash, coinbase, nTime, nBits, blockcommitmentshash)
# copy the non-coinbase transactions from the block template to the block
@ -88,18 +95,92 @@ class GetBlockTemplateTest(BitcoinTestFramework):
f = BytesIO(hex_str_to_bytes(gbt_tx['data']))
tx = CTransaction()
tx.deserialize(f)
tx.calc_sha256()
assert_equal(tx.auth_digest_hex, node.getrawtransaction(tx.hash, 1)['authdigest'])
block.vtx.append(tx)
block.hashMerkleRoot = int(gbt['defaultroots']['merkleroot'], 16)
assert_equal(block.hashMerkleRoot, block.calc_merkle_root(), "merkleroot")
assert_equal(len(block.vtx), len(gbt['transactions']) + 1, "number of transactions")
assert_equal(block.hashPrevBlock, int(gbt['previousblockhash'], 16), "prevhash")
if nu5_active:
assert_equal(uint256_from_str(block.calc_auth_data_root()), int(gbt['defaultroots']['authdataroot'], 16))
else:
assert 'authdataroot' not in gbt['defaultroots']
block.solve()
block = block.serialize()
block = codecs.encode(block, 'hex_codec')
block.calc_sha256()
print("Submitting block")
submitblock_reply = node.submitblock(block)
submitblock_reply = node.submitblock(codecs.encode(block.serialize(), 'hex_codec'))
assert_equal(None, submitblock_reply)
assert_equal(block.hash, node.getbestblockhash())
# Wait until the wallet has been notified of all blocks, so that it doesn't try to
# double-spend transparent coins in subsequent test phases.
self.sync_all()
def run_test(self):
node = self.node
# Generate Sprout funds before Canopy activates; using the Sprout address will
# force the generation of v4 transactions from NU5.
print("Generating pre-Canopy blocks to create sprout funds")
# coinbase only becomes mature after 100 blocks, so make one mature.
node.generate(105)
self.sprout_addr = node.z_getnewaddress('sprout')
myopid = node.z_shieldcoinbase('*', self.sprout_addr)['opid']
wait_and_assert_operationid_status(node, myopid)
self.transparent_addr = node.getnewaddress()
node.generate(15)
# at height 120, NU5 is not active
assert_equal(node.getblockchaininfo()['upgrades']['37519621']['status'], 'pending')
print("Testing getblocktemplate for pre-NU5")
# Only the coinbase; this covers the case where the Merkle root
# is equal to the coinbase txid.
print("- only coinbase")
self.gbt_submitblock(False)
# Adding one transaction triggering a single Merkle digest.
print("- one transaction (plus coinbase)")
self.add_transparent_tx_to_mempool()
self.gbt_submitblock(False)
# Adding two transactions to trigger hash Merkle root edge case.
print("- two transactions (plus coinbase)")
self.add_transparent_tx_to_mempool()
self.add_transparent_tx_to_mempool()
self.gbt_submitblock(False)
# Activate NU5, repeat the above cases
node.generate(7)
assert_equal(node.getblockchaininfo()['upgrades']['37519621']['status'], 'active')
print("Testing getblocktemplate for post-NU5")
# Only the coinbase; this covers the case where the block authdata root
# is equal to the coinbase authdata
print("- only coinbase")
self.gbt_submitblock(True)
# Adding one transaction triggering a single Merkle digest.
print("- one transaction (plus coinbase)")
self.add_transparent_tx_to_mempool()
self.gbt_submitblock(True)
# Adding two transactions to trigger hash Merkle root edge case.
print("- two transactions (plus coinbase)")
self.add_transparent_tx_to_mempool()
self.add_transparent_tx_to_mempool()
self.gbt_submitblock(True)
# Adding both v4 and v5 to cover legacy auth digest.
print("- both v4 and v5 transactions (plus coinbase)")
self.add_nu5_v4_tx_to_mempool()
self.add_transparent_tx_to_mempool()
self.add_transparent_tx_to_mempool()
self.gbt_submitblock(True)
if __name__ == '__main__':

View File

@ -1126,11 +1126,14 @@ class CTransaction(object):
if self.nVersion >= 5:
from . import zip244
txid = zip244.txid_digest(self)
self.auth_digest = zip244.auth_digest(self)
else:
txid = hash256(self.serialize())
self.auth_digest = b'\xFF'*32
if self.sha256 is None:
self.sha256 = uint256_from_str(txid)
self.hash = encode(txid[::-1], 'hex_codec').decode('ascii')
self.auth_digest_hex = encode(self.auth_digest[::-1], 'hex_codec').decode('ascii')
def is_valid(self):
self.calc_sha256()
@ -1263,6 +1266,27 @@ class CBlock(CBlockHeader):
hashes = newhashes
return uint256_from_str(hashes[0])
def calc_auth_data_root(self):
hashes = []
nleaves = 0
for tx in self.vtx:
tx.calc_sha256()
hashes.append(tx.auth_digest)
nleaves += 1
# Continue adding leaves (of zeros) until reaching a power of 2
while nleaves & (nleaves-1) > 0:
hashes.append(b'\x00'*32)
nleaves += 1
while len(hashes) > 1:
newhashes = []
for i in range(0, len(hashes), 2):
digest = blake2b(digest_size=32, person=b'ZcashAuthDatHash')
digest.update(hashes[i])
digest.update(hashes[i+1])
newhashes.append(digest.digest())
hashes = newhashes
return hashes[0]
def is_valid(self, n=48, k=5):
# H(I||...
digest = blake2b(digest_size=(512//n)*n//8, person=zcash_person(n, k))

View File

@ -15,7 +15,7 @@ import struct
from pyblake2 import blake2b
from .mininode import ser_uint256
from .mininode import ser_string, ser_uint256
from .script import (
SIGHASH_ANYONECANPAY,
SIGHASH_NONE,
@ -41,7 +41,7 @@ def transparent_digest(tx):
def transparent_scripts_digest(tx):
digest = blake2b(digest_size=32, person=b'ZTxAuthTransHash')
for x in tx.vin:
digest.update(bytes(x.scriptSig))
digest.update(ser_string(x.scriptSig))
return digest.digest()
# Sapling
@ -288,7 +288,7 @@ def outputs_sig_digest(tx, nHashType, txin):
def txin_sig_digest(tx, txin):
digest = blake2b(digest_size=32, person=b'Zcash___TxInHash')
digest.update(bytes(tx.vin[txin.nIn].prevout))
digest.update(bytes(txin.scriptCode))
digest.update(ser_string(txin.scriptCode))
digest.update(struct.pack('<Q', txin.amount))
digest.update(struct.pack('<I', tx.vin[txin.nIn].nSequence))
return digest.digest()

View File

@ -18,7 +18,7 @@
#define CLIENT_VERSION_MAJOR 4
#define CLIENT_VERSION_MINOR 6
#define CLIENT_VERSION_REVISION 0
#define CLIENT_VERSION_BUILD 50
#define CLIENT_VERSION_BUILD 51
//! Set to true for release, false for prerelease or test build
#define CLIENT_VERSION_IS_RELEASE true

View File

@ -642,14 +642,38 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const MinerAddre
pblock->hashPrevBlock = pindexPrev->GetBlockHash();
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.
// update it whenever the coinbase transaction changes.
//
// - For the internal miner (either directly or via the `generate` RPC), this
// will occur in `IncrementExtraNonce()`, like for `hashMerkleRoot`.
// - For `getblocktemplate`, we have two sets of fields to handle:
// - The `defaultroots` fields, which contain both the default value (if
// nothing in the template is altered), and the roots that can be used to
// recalculate it (if some or all of the template is altered).
// - The legacy `finalsaplingroothash`, `lightclientroothash`, and
// `blockcommitmentshash` fields, which had the semantics of "place this
// value into the block header and things will work" (except for in
// v4.6.0 where they were accidentally set to always be the NU5 value).
//
// To accommodate all use cases, we calculate the `hashBlockCommitments`
// default value here (unlike `hashMerkleRoot`), and additionally cache the
// values necessary to recalculate it.
pblocktemplate->hashChainHistoryRoot = view.GetHistoryRoot(prevConsensusBranchId);
pblocktemplate->hashAuthDataRoot = pblock->BuildAuthDataMerkleTree();
pblock->hashBlockCommitments = DeriveBlockCommitmentsHash(
pblocktemplate->hashChainHistoryRoot,
pblocktemplate->hashAuthDataRoot);
} else if (IsActivationHeight(nHeight, chainparams.GetConsensus(), Consensus::UPGRADE_HEARTWOOD)) {
pblocktemplate->hashChainHistoryRoot.SetNull();
pblocktemplate->hashAuthDataRoot.SetNull();
pblock->hashBlockCommitments.SetNull();
} else if (chainparams.GetConsensus().NetworkUpgradeActive(nHeight, Consensus::UPGRADE_HEARTWOOD)) {
pblock->hashBlockCommitments = view.GetHistoryRoot(prevConsensusBranchId);
pblocktemplate->hashChainHistoryRoot = view.GetHistoryRoot(prevConsensusBranchId);
pblocktemplate->hashAuthDataRoot.SetNull();
pblock->hashBlockCommitments = pblocktemplate->hashChainHistoryRoot;
} else {
pblocktemplate->hashChainHistoryRoot.SetNull();
pblocktemplate->hashAuthDataRoot.SetNull();
pblock->hashBlockCommitments = sapling_tree.root();
}
UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev);
@ -727,9 +751,10 @@ void IncrementExtraNonce(
pblock->vtx[0] = txCoinbase;
pblock->hashMerkleRoot = pblock->BuildMerkleTree();
if (consensusParams.NetworkUpgradeActive(nHeight, Consensus::UPGRADE_NU5)) {
pblocktemplate->hashAuthDataRoot = pblock->BuildAuthDataMerkleTree();
pblock->hashBlockCommitments = DeriveBlockCommitmentsHash(
pblocktemplate->hashChainHistoryRoot,
pblock->BuildAuthDataMerkleTree());
pblocktemplate->hashAuthDataRoot);
}
}

View File

@ -110,6 +110,10 @@ struct CBlockTemplate
// Cached whenever we update `block`, so we can update hashBlockCommitments
// when we change the coinbase transaction.
uint256 hashChainHistoryRoot;
// Cached whenever we update `block`, so we can return it from `getblocktemplate`
// (enabling the caller to update `hashBlockCommitments` when they change
// `hashPrevBlock`).
uint256 hashAuthDataRoot;
std::vector<CAmount> vTxFees;
std::vector<int64_t> vTxSigOps;
};

View File

@ -454,9 +454,9 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
" \"finalsaplingroothash\" : \"xxxx\", (string) (DEPRECATED) The hash of the light client root field in the block header\n"
" \"defaultroots\" : { (json object) root hashes that need to be recomputed if the transaction set is modified\n"
" \"merkleroot\" : \"xxxx\" (string) The hash of the transactions in the block header\n"
" \"authdataroot\" : \"xxxx\" (string) The hash of the authorizing data merkel tree\n"
" \"chainhistoryroot\" : \"xxxx\" (string) The hash of the chain history\n"
" \"blockcommitmentshash\" : \"xxxx\" (string) The hash of the block commitments field in the block header\n"
" \"authdataroot\" : \"xxxx\" (string) (From NU5) The hash of the authorizing data merkel tree\n"
" \"blockcommitmentshash\" : \"xxxx\" (string) (From NU5) The hash of the block commitments field in the block header\n"
" }\n"
" \"transactions\" : [ (array) contents of non-coinbase transactions that should be included in the next block\n"
" {\n"
@ -723,6 +723,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
entry.pushKV("data", EncodeHexTx(tx));
entry.pushKV("hash", txHash.GetHex());
entry.pushKV("authdigest", tx.GetAuthDigest().GetHex());
UniValue deps(UniValue::VARR);
for (const CTxIn &in : tx.vin)
@ -764,27 +765,25 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
aMutable.push_back("prevblock");
}
auto hashAuthDataRoot = pblock->BuildAuthDataMerkleTree();
std::string hashBlockCommitments_hex = DeriveBlockCommitmentsHash(
pblocktemplate->hashChainHistoryRoot,
hashAuthDataRoot).GetHex();
UniValue result(UniValue::VOBJ);
result.pushKV("capabilities", aCaps);
result.pushKV("version", pblock->nVersion);
result.pushKV("previousblockhash", pblock->hashPrevBlock.GetHex());
// The following 3 are deprecated; remove in a future release.
result.pushKV("blockcommitmentshash", hashBlockCommitments_hex);
result.pushKV("lightclientroothash", hashBlockCommitments_hex);
result.pushKV("finalsaplingroothash", hashBlockCommitments_hex);
result.pushKV("blockcommitmentshash", pblock->hashBlockCommitments.GetHex());
result.pushKV("lightclientroothash", pblock->hashBlockCommitments.GetHex());
result.pushKV("finalsaplingroothash", pblock->hashBlockCommitments.GetHex());
{
// These are items in the result object that are valid only if the
// block template returned by this RPC is used unmodified. Otherwise,
// these values must be recomputed.
UniValue defaults(UniValue::VOBJ);
defaults.pushKV("merkleroot", pblock->BuildMerkleTree().GetHex());
defaults.pushKV("authdataroot", hashAuthDataRoot.GetHex());
defaults.pushKV("chainhistoryroot", pblocktemplate->hashChainHistoryRoot.GetHex());
defaults.pushKV("blockcommitmentshash", hashBlockCommitments_hex);
if (consensus.NetworkUpgradeActive(pindexPrev->nHeight+1, Consensus::UPGRADE_NU5)) {
defaults.pushKV("authdataroot", pblocktemplate->hashAuthDataRoot.GetHex());
defaults.pushKV("blockcommitmentshash", pblock->hashBlockCommitments.GetHex());
}
result.pushKV("defaultroots", defaults);
}
result.pushKV("transactions", transactions);