diff --git a/src/bench/rpc_blockchain.cpp b/src/bench/rpc_blockchain.cpp index 7e3e2d8e48..df951a14e4 100644 --- a/src/bench/rpc_blockchain.cpp +++ b/src/bench/rpc_blockchain.cpp @@ -48,8 +48,9 @@ struct TestBlockAndIndex { static void BlockToJsonVerbose(benchmark::Bench& bench) { TestBlockAndIndex data; + const uint256 pow_limit{data.testing_setup->m_node.chainman->GetParams().GetConsensus().powLimit}; bench.run([&] { - auto univalue = blockToJSON(data.testing_setup->m_node.chainman->m_blockman, data.block, data.blockindex, data.blockindex, TxVerbosity::SHOW_DETAILS_AND_PREVOUT); + auto univalue = blockToJSON(data.testing_setup->m_node.chainman->m_blockman, data.block, data.blockindex, data.blockindex, TxVerbosity::SHOW_DETAILS_AND_PREVOUT, pow_limit); ankerl::nanobench::doNotOptimizeAway(univalue); }); } @@ -59,7 +60,8 @@ BENCHMARK(BlockToJsonVerbose, benchmark::PriorityLevel::HIGH); static void BlockToJsonVerboseWrite(benchmark::Bench& bench) { TestBlockAndIndex data; - auto univalue = blockToJSON(data.testing_setup->m_node.chainman->m_blockman, data.block, data.blockindex, data.blockindex, TxVerbosity::SHOW_DETAILS_AND_PREVOUT); + const uint256 pow_limit{data.testing_setup->m_node.chainman->GetParams().GetConsensus().powLimit}; + auto univalue = blockToJSON(data.testing_setup->m_node.chainman->m_blockman, data.block, data.blockindex, data.blockindex, TxVerbosity::SHOW_DETAILS_AND_PREVOUT, pow_limit); bench.run([&] { auto str = univalue.write(); ankerl::nanobench::doNotOptimizeAway(str); diff --git a/src/rest.cpp b/src/rest.cpp index 3e4b8b37c6..bb064782f5 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -225,10 +225,10 @@ static bool rest_headers(const std::any& context, const CBlockIndex* tip = nullptr; std::vector headers; headers.reserve(*parsed_count); + ChainstateManager* maybe_chainman = GetChainman(context, req); + if (!maybe_chainman) return false; + ChainstateManager& chainman = *maybe_chainman; { - ChainstateManager* maybe_chainman = GetChainman(context, req); - if (!maybe_chainman) return false; - ChainstateManager& chainman = *maybe_chainman; LOCK(cs_main); CChain& active_chain = chainman.ActiveChain(); tip = active_chain.Tip(); @@ -268,7 +268,7 @@ static bool rest_headers(const std::any& context, case RESTResponseFormat::JSON: { UniValue jsonHeaders(UniValue::VARR); for (const CBlockIndex *pindex : headers) { - jsonHeaders.push_back(blockheaderToJSON(*tip, *pindex)); + jsonHeaders.push_back(blockheaderToJSON(*tip, *pindex, chainman.GetConsensus().powLimit)); } std::string strJSON = jsonHeaders.write() + "\n"; req->WriteHeader("Content-Type", "application/json"); @@ -341,7 +341,7 @@ static bool rest_block(const std::any& context, CBlock block{}; DataStream block_stream{block_data}; block_stream >> TX_WITH_WITNESS(block); - UniValue objBlock = blockToJSON(chainman.m_blockman, block, *tip, *pblockindex, tx_verbosity); + UniValue objBlock = blockToJSON(chainman.m_blockman, block, *tip, *pblockindex, tx_verbosity, chainman.GetConsensus().powLimit); std::string strJSON = objBlock.write() + "\n"; req->WriteHeader("Content-Type", "application/json"); req->WriteReply(HTTP_OK, strJSON); diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 3caf4bf4eb..07822b476c 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -146,7 +146,7 @@ static const CBlockIndex* ParseHashOrHeight(const UniValue& param, ChainstateMan } } -UniValue blockheaderToJSON(const CBlockIndex& tip, const CBlockIndex& blockindex) +UniValue blockheaderToJSON(const CBlockIndex& tip, const CBlockIndex& blockindex, const uint256 pow_limit) { // Serialize passed information without accessing chain state of the active chain! AssertLockNotHeld(cs_main); // For performance reasons @@ -164,6 +164,7 @@ UniValue blockheaderToJSON(const CBlockIndex& tip, const CBlockIndex& blockindex result.pushKV("mediantime", blockindex.GetMedianTimePast()); result.pushKV("nonce", blockindex.nNonce); result.pushKV("bits", strprintf("%08x", blockindex.nBits)); + result.pushKV("target", GetTarget(tip, pow_limit).GetHex()); result.pushKV("difficulty", GetDifficulty(blockindex)); result.pushKV("chainwork", blockindex.nChainWork.GetHex()); result.pushKV("nTx", blockindex.nTx); @@ -175,9 +176,9 @@ UniValue blockheaderToJSON(const CBlockIndex& tip, const CBlockIndex& blockindex return result; } -UniValue blockToJSON(BlockManager& blockman, const CBlock& block, const CBlockIndex& tip, const CBlockIndex& blockindex, TxVerbosity verbosity) +UniValue blockToJSON(BlockManager& blockman, const CBlock& block, const CBlockIndex& tip, const CBlockIndex& blockindex, TxVerbosity verbosity, const uint256 pow_limit) { - UniValue result = blockheaderToJSON(tip, blockindex); + UniValue result = blockheaderToJSON(tip, blockindex, pow_limit); result.pushKV("strippedsize", (int)::GetSerializeSize(TX_NO_WITNESS(block))); result.pushKV("size", (int)::GetSerializeSize(TX_WITH_WITNESS(block))); @@ -554,6 +555,7 @@ static RPCHelpMan getblockheader() {RPCResult::Type::NUM_TIME, "mediantime", "The median block time expressed in " + UNIX_EPOCH_TIME}, {RPCResult::Type::NUM, "nonce", "The nonce"}, {RPCResult::Type::STR_HEX, "bits", "nBits: compact representation of the block difficulty target"}, + {RPCResult::Type::STR_HEX, "target", "The difficulty target"}, {RPCResult::Type::NUM, "difficulty", "The difficulty"}, {RPCResult::Type::STR_HEX, "chainwork", "Expected number of hashes required to produce the current chain"}, {RPCResult::Type::NUM, "nTx", "The number of transactions in the block"}, @@ -577,8 +579,8 @@ static RPCHelpMan getblockheader() const CBlockIndex* pblockindex; const CBlockIndex* tip; + ChainstateManager& chainman = EnsureAnyChainman(request.context); { - ChainstateManager& chainman = EnsureAnyChainman(request.context); LOCK(cs_main); pblockindex = chainman.m_blockman.LookupBlockIndex(hash); tip = chainman.ActiveChain().Tip(); @@ -596,7 +598,7 @@ static RPCHelpMan getblockheader() return strHex; } - return blockheaderToJSON(*tip, *pblockindex); + return blockheaderToJSON(*tip, *pblockindex, chainman.GetConsensus().powLimit); }, }; } @@ -728,6 +730,7 @@ static RPCHelpMan getblock() {RPCResult::Type::NUM_TIME, "mediantime", "The median block time expressed in " + UNIX_EPOCH_TIME}, {RPCResult::Type::NUM, "nonce", "The nonce"}, {RPCResult::Type::STR_HEX, "bits", "nBits: compact representation of the block difficulty target"}, + {RPCResult::Type::STR_HEX, "target", "The difficulty target"}, {RPCResult::Type::NUM, "difficulty", "The difficulty"}, {RPCResult::Type::STR_HEX, "chainwork", "Expected number of hashes required to produce the chain up to this block (in hex)"}, {RPCResult::Type::NUM, "nTx", "The number of transactions in the block"}, @@ -802,7 +805,7 @@ static RPCHelpMan getblock() tx_verbosity = TxVerbosity::SHOW_DETAILS_AND_PREVOUT; } - return blockToJSON(chainman.m_blockman, block, *tip, *pblockindex, tx_verbosity); + return blockToJSON(chainman.m_blockman, block, *tip, *pblockindex, tx_verbosity, chainman.GetConsensus().powLimit); }, }; } diff --git a/src/rpc/blockchain.h b/src/rpc/blockchain.h index 89b9921d55..954ede6519 100644 --- a/src/rpc/blockchain.h +++ b/src/rpc/blockchain.h @@ -36,10 +36,10 @@ static constexpr int NUM_GETBLOCKSTATS_PERCENTILES = 5; double GetDifficulty(const CBlockIndex& blockindex); /** Block description to JSON */ -UniValue blockToJSON(node::BlockManager& blockman, const CBlock& block, const CBlockIndex& tip, const CBlockIndex& blockindex, TxVerbosity verbosity) LOCKS_EXCLUDED(cs_main); +UniValue blockToJSON(node::BlockManager& blockman, const CBlock& block, const CBlockIndex& tip, const CBlockIndex& blockindex, TxVerbosity verbosity, const uint256 pow_limit) LOCKS_EXCLUDED(cs_main); /** Block header to JSON */ -UniValue blockheaderToJSON(const CBlockIndex& tip, const CBlockIndex& blockindex) LOCKS_EXCLUDED(cs_main); +UniValue blockheaderToJSON(const CBlockIndex& tip, const CBlockIndex& blockindex, const uint256 pow_limit) LOCKS_EXCLUDED(cs_main); /** Used by getblockstats to get feerates at different percentiles by weight */ void CalculatePercentilesByWeight(CAmount result[NUM_GETBLOCKSTATS_PERCENTILES], std::vector>& scores, int64_t total_weight); diff --git a/test/functional/interface_rest.py b/test/functional/interface_rest.py index ed117ae08b..0e294696b0 100755 --- a/test/functional/interface_rest.py +++ b/test/functional/interface_rest.py @@ -289,7 +289,7 @@ class RESTTest (BitcoinTestFramework): # Compare with normal RPC block response rpc_block_json = self.nodes[0].getblock(bb_hash) - for key in ['hash', 'confirmations', 'height', 'version', 'merkleroot', 'time', 'nonce', 'bits', 'difficulty', 'chainwork', 'previousblockhash']: + for key in ['hash', 'confirmations', 'height', 'version', 'merkleroot', 'time', 'nonce', 'bits', 'target', 'difficulty', 'chainwork', 'previousblockhash']: assert_equal(json_obj[0][key], rpc_block_json[key]) # See if we can get 5 headers in one response diff --git a/test/functional/rpc_blockchain.py b/test/functional/rpc_blockchain.py index ae95beae2c..3f6a4750b2 100755 --- a/test/functional/rpc_blockchain.py +++ b/test/functional/rpc_blockchain.py @@ -31,10 +31,12 @@ from test_framework.blocktools import ( MAX_FUTURE_BLOCK_TIME, TIME_GENESIS_BLOCK, REGTEST_N_BITS, + REGTEST_TARGET, create_block, create_coinbase, create_tx_with_script, nbits_str, + target_str, ) from test_framework.messages import ( CBlockHeader, @@ -415,6 +417,7 @@ class BlockchainTest(BitcoinTestFramework): assert_is_hash_string(header['previousblockhash']) assert_is_hash_string(header['merkleroot']) assert_equal(header['bits'], nbits_str(REGTEST_N_BITS)) + assert_equal(header['target'], target_str(REGTEST_TARGET)) assert isinstance(header['time'], int) assert_equal(header['mediantime'], TIME_RANGE_MTP) assert isinstance(header['nonce'], int) diff --git a/test/functional/test_framework/blocktools.py b/test/functional/test_framework/blocktools.py index c92b1398c3..7c455ea52f 100644 --- a/test/functional/test_framework/blocktools.py +++ b/test/functional/test_framework/blocktools.py @@ -27,6 +27,7 @@ from .messages import ( hash256, ser_uint256, tx_from_hex, + uint256_from_compact, uint256_from_str, WITNESS_SCALE_FACTOR, ) @@ -66,10 +67,15 @@ VERSIONBITS_LAST_OLD_BLOCK_VERSION = 4 MIN_BLOCKS_TO_KEEP = 288 REGTEST_N_BITS = 0x207fffff # difficulty retargeting is disabled in REGTEST chainparams" +REGTEST_TARGET = 0x7fffff0000000000000000000000000000000000000000000000000000000000 +assert_equal(uint256_from_compact(REGTEST_N_BITS), REGTEST_TARGET) def nbits_str(nbits): return f"{nbits:08x}" +def target_str(target): + return f"{target:064x}" + def create_block(hashprev=None, coinbase=None, ntime=None, *, version=None, tmpl=None, txlist=None): """Create a block (with regtest difficulty).""" block = CBlock()