diff --git a/doc/release-notes-31583.md b/doc/release-notes-31583.md new file mode 100644 index 0000000000..e641fc766b --- /dev/null +++ b/doc/release-notes-31583.md @@ -0,0 +1,14 @@ +Updated RPCs +--- +- `getmininginfo` now returns `nBits` and the current target in the `target` field. It also returns a `next` object which specifies the `height`, `nBits`, `difficulty`, and `target` for the next block. +- `getdifficulty` can now return the difficulty for the next block (rather than the current tip) when calling with the boolean `next` argument set to true. +- `getblock` and `getblockheader` now return the current target in the `target` field +- `getblockchaininfo` and `getchainstates` now return `nBits` and the current target in the `target` field + +New RPCs +--- +- `gettarget` can be used to return the current target (for tip) or target for the next block (with the `next` argument) + +REST interface +--- +- `GET /rest/block/.json` and `GET /rest/headers/.json` now return the current target in the `target` field diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 889c00c783..89fdd855a4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -109,6 +109,7 @@ add_library(bitcoin_common STATIC EXCLUDE_FROM_ALL addresstype.cpp base58.cpp bech32.cpp + chain.cpp chainparams.cpp chainparamsbase.cpp coins.cpp @@ -142,6 +143,7 @@ add_library(bitcoin_common STATIC EXCLUDE_FROM_ALL outputtype.cpp policy/feerate.cpp policy/policy.cpp + pow.cpp protocol.cpp psbt.cpp rpc/external_signer.cpp @@ -200,7 +202,6 @@ add_library(bitcoin_node STATIC EXCLUDE_FROM_ALL bip324.cpp blockencodings.cpp blockfilter.cpp - chain.cpp consensus/tx_verify.cpp dbwrapper.cpp deploymentstatus.cpp @@ -262,7 +263,6 @@ add_library(bitcoin_node STATIC EXCLUDE_FROM_ALL policy/rbf.cpp policy/settings.cpp policy/truc_policy.cpp - pow.cpp rest.cpp rpc/blockchain.cpp rpc/fees.cpp 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/pow.cpp b/src/pow.cpp index bbcf39b593..686b177fe3 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -143,7 +143,7 @@ bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params& return CheckProofOfWorkImpl(hash, nBits, params); } -bool CheckProofOfWorkImpl(uint256 hash, unsigned int nBits, const Consensus::Params& params) +std::optional DeriveTarget(unsigned int nBits, const uint256 pow_limit) { bool fNegative; bool fOverflow; @@ -152,8 +152,16 @@ bool CheckProofOfWorkImpl(uint256 hash, unsigned int nBits, const Consensus::Par bnTarget.SetCompact(nBits, &fNegative, &fOverflow); // Check range - if (fNegative || bnTarget == 0 || fOverflow || bnTarget > UintToArith256(params.powLimit)) - return false; + if (fNegative || bnTarget == 0 || fOverflow || bnTarget > UintToArith256(pow_limit)) + return {}; + + return bnTarget; +} + +bool CheckProofOfWorkImpl(uint256 hash, unsigned int nBits, const Consensus::Params& params) +{ + auto bnTarget{DeriveTarget(nBits, params.powLimit)}; + if (!bnTarget) return false; // Check proof of work matches claimed amount if (UintToArith256(hash) > bnTarget) diff --git a/src/pow.h b/src/pow.h index 2b28ade273..ceba55d36a 100644 --- a/src/pow.h +++ b/src/pow.h @@ -13,6 +13,18 @@ class CBlockHeader; class CBlockIndex; class uint256; +class arith_uint256; + +/** + * Convert nBits value to target. + * + * @param[in] nBits compact representation of the target + * @param[in] pow_limit PoW limit (consensus parameter) + * + * @return the proof-of-work target or nullopt if the nBits value + * is invalid (due to overflow or exceeding pow_limit) + */ +std::optional DeriveTarget(unsigned int nBits, const uint256 pow_limit); unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params&); unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nFirstBlockTime, const Consensus::Params&); 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 823d2303c8..1070e8f68f 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))); @@ -431,7 +432,9 @@ static RPCHelpMan getdifficulty() { return RPCHelpMan{"getdifficulty", "\nReturns the proof-of-work difficulty as a multiple of the minimum difficulty.\n", - {}, + { + {"next", RPCArg::Type::BOOL, RPCArg::Default{false}, "difficulty for the next block, if found now"}, + }, RPCResult{ RPCResult::Type::NUM, "", "the proof-of-work difficulty as a multiple of the minimum difficulty."}, RPCExamples{ @@ -441,8 +444,55 @@ static RPCHelpMan getdifficulty() [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { ChainstateManager& chainman = EnsureAnyChainman(request.context); - LOCK(cs_main); - return GetDifficulty(*CHECK_NONFATAL(chainman.ActiveChain().Tip())); + CBlockIndex& tip{*CHECK_NONFATAL(WITH_LOCK(chainman.GetMutex(), return chainman.ActiveChain().Tip()))}; + + bool next{false}; + if (!request.params[0].isNull()) { + next = request.params[0].get_bool(); + } + + if (next) { + CBlockIndex next_index; + NextEmptyBlockIndex(tip, chainman.GetConsensus(), next_index); + return GetDifficulty(next_index); + } else { + return GetDifficulty(tip); + } + +}, + }; +} + +static RPCHelpMan gettarget() +{ + return RPCHelpMan{"gettarget", + "\nReturns the proof-of-work target.\n", + { + {"next", RPCArg::Type::BOOL, RPCArg::Default{false}, "target for the next block, if found now"}, + }, + RPCResult{ + RPCResult::Type::STR_HEX, "", "the proof-of-work target."}, + RPCExamples{ + HelpExampleCli("gettarget", "") + + HelpExampleRpc("gettarget", "") + }, + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ + ChainstateManager& chainman = EnsureAnyChainman(request.context); + CBlockIndex& tip{*CHECK_NONFATAL(WITH_LOCK(chainman.GetMutex(), return chainman.ActiveChain().Tip()))}; + + bool next{false}; + if (!request.params[0].isNull()) { + next = request.params[0].get_bool(); + } + + if (next) { + CBlockIndex next_index; + NextEmptyBlockIndex(tip, chainman.GetConsensus(), next_index); + return GetTarget(next_index, chainman.GetConsensus().powLimit).GetHex(); + } else { + return GetTarget(tip, chainman.GetConsensus().powLimit).GetHex(); + } }, }; } @@ -553,7 +603,8 @@ static RPCHelpMan getblockheader() {RPCResult::Type::NUM_TIME, "time", "The block time expressed in " + UNIX_EPOCH_TIME}, {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", "The bits"}, + {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 +628,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 +647,7 @@ static RPCHelpMan getblockheader() return strHex; } - return blockheaderToJSON(*tip, *pblockindex); + return blockheaderToJSON(*tip, *pblockindex, chainman.GetConsensus().powLimit); }, }; } @@ -727,7 +778,8 @@ static RPCHelpMan getblock() {RPCResult::Type::NUM_TIME, "time", "The block time expressed in " + UNIX_EPOCH_TIME}, {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", "The bits"}, + {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 +854,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); }, }; } @@ -1296,6 +1348,8 @@ RPCHelpMan getblockchaininfo() {RPCResult::Type::NUM, "blocks", "the height of the most-work fully-validated chain. The genesis block has height 0"}, {RPCResult::Type::NUM, "headers", "the current number of headers we have validated"}, {RPCResult::Type::STR, "bestblockhash", "the hash of the currently best block"}, + {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 current difficulty"}, {RPCResult::Type::NUM_TIME, "time", "The block time expressed in " + UNIX_EPOCH_TIME}, {RPCResult::Type::NUM_TIME, "mediantime", "The median block time expressed in " + UNIX_EPOCH_TIME}, @@ -1334,6 +1388,8 @@ RPCHelpMan getblockchaininfo() obj.pushKV("blocks", height); obj.pushKV("headers", chainman.m_best_header ? chainman.m_best_header->nHeight : -1); obj.pushKV("bestblockhash", tip.GetBlockHash().GetHex()); + obj.pushKV("bits", strprintf("%08x", tip.nBits)); + obj.pushKV("target", GetTarget(tip, chainman.GetConsensus().powLimit).GetHex()); obj.pushKV("difficulty", GetDifficulty(tip)); obj.pushKV("time", tip.GetBlockTime()); obj.pushKV("mediantime", tip.GetMedianTimePast()); @@ -3301,6 +3357,8 @@ static RPCHelpMan loadtxoutset() const std::vector RPCHelpForChainstate{ {RPCResult::Type::NUM, "blocks", "number of blocks in this chainstate"}, {RPCResult::Type::STR_HEX, "bestblockhash", "blockhash of the tip"}, + {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", "difficulty of the tip"}, {RPCResult::Type::NUM, "verificationprogress", "progress towards the network tip"}, {RPCResult::Type::STR_HEX, "snapshot_blockhash", /*optional=*/true, "the base block of the snapshot this chainstate is based on, if any"}, @@ -3343,6 +3401,8 @@ return RPCHelpMan{ data.pushKV("blocks", (int)chain.Height()); data.pushKV("bestblockhash", tip->GetBlockHash().GetHex()); + data.pushKV("bits", strprintf("%08x", tip->nBits)); + data.pushKV("target", GetTarget(*tip, chainman.GetConsensus().powLimit).GetHex()); data.pushKV("difficulty", GetDifficulty(*tip)); data.pushKV("verificationprogress", chainman.GuessVerificationProgress(tip)); data.pushKV("coins_db_cache_bytes", cs.m_coinsdb_cache_size_bytes); @@ -3382,6 +3442,7 @@ void RegisterBlockchainRPCCommands(CRPCTable& t) {"blockchain", &getblockheader}, {"blockchain", &getchaintips}, {"blockchain", &getdifficulty}, + {"blockchain", &gettarget}, {"blockchain", &getdeploymentinfo}, {"blockchain", &gettxout}, {"blockchain", &gettxoutsetinfo}, 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/src/rpc/client.cpp b/src/rpc/client.cpp index 1b711e3c5b..1805aa3c26 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -114,6 +114,8 @@ static const CRPCConvertParam vRPCConvertParams[] = { "getblock", 1, "verbose" }, { "getblockheader", 1, "verbose" }, { "getchaintxstats", 0, "nblocks" }, + { "getdifficulty", 0, "next" }, + { "gettarget", 0, "next" }, { "gettransaction", 1, "include_watchonly" }, { "gettransaction", 2, "verbose" }, { "getrawtransaction", 1, "verbosity" }, diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 7e5936fddf..7963903e95 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -421,11 +421,20 @@ static RPCHelpMan getmininginfo() {RPCResult::Type::NUM, "blocks", "The current block"}, {RPCResult::Type::NUM, "currentblockweight", /*optional=*/true, "The block weight of the last assembled block (only present if a block was ever assembled)"}, {RPCResult::Type::NUM, "currentblocktx", /*optional=*/true, "The number of block transactions of the last assembled block (only present if a block was ever assembled)"}, + {RPCResult::Type::STR_HEX, "bits", "The current nBits, compact representation of the block difficulty target"}, {RPCResult::Type::NUM, "difficulty", "The current difficulty"}, + {RPCResult::Type::STR_HEX, "target", "The current target"}, {RPCResult::Type::NUM, "networkhashps", "The network hashes per second"}, {RPCResult::Type::NUM, "pooledtx", "The size of the mempool"}, {RPCResult::Type::STR, "chain", "current network name (" LIST_CHAIN_NAMES ")"}, {RPCResult::Type::STR_HEX, "signet_challenge", /*optional=*/true, "The block challenge (aka. block script), in hexadecimal (only present if the current network is a signet)"}, + {RPCResult::Type::OBJ, "next", "The next block, if found now", + { + {RPCResult::Type::NUM, "height", "The next height"}, + {RPCResult::Type::STR_HEX, "bits", "The next target nBits"}, + {RPCResult::Type::NUM, "difficulty", "The next difficulty"}, + {RPCResult::Type::STR_HEX, "target", "The next target"} + }}, (IsDeprecatedRPCEnabled("warnings") ? RPCResult{RPCResult::Type::STR, "warnings", "any network and blockchain warnings (DEPRECATED)"} : RPCResult{RPCResult::Type::ARR, "warnings", "any network and blockchain warnings (run with `-deprecatedrpc=warnings` to return the latest warning as a single string)", @@ -446,18 +455,32 @@ static RPCHelpMan getmininginfo() ChainstateManager& chainman = EnsureChainman(node); LOCK(cs_main); const CChain& active_chain = chainman.ActiveChain(); + CBlockIndex& tip{*CHECK_NONFATAL(active_chain.Tip())}; UniValue obj(UniValue::VOBJ); obj.pushKV("blocks", active_chain.Height()); if (BlockAssembler::m_last_block_weight) obj.pushKV("currentblockweight", *BlockAssembler::m_last_block_weight); if (BlockAssembler::m_last_block_num_txs) obj.pushKV("currentblocktx", *BlockAssembler::m_last_block_num_txs); - obj.pushKV("difficulty", GetDifficulty(*CHECK_NONFATAL(active_chain.Tip()))); + obj.pushKV("bits", strprintf("%08x", tip.nBits)); + obj.pushKV("difficulty", GetDifficulty(tip)); + obj.pushKV("target", GetTarget(tip, chainman.GetConsensus().powLimit).GetHex()); obj.pushKV("networkhashps", getnetworkhashps().HandleRequest(request)); obj.pushKV("pooledtx", (uint64_t)mempool.size()); obj.pushKV("chain", chainman.GetParams().GetChainTypeString()); + + UniValue next(UniValue::VOBJ); + CBlockIndex next_index; + NextEmptyBlockIndex(tip, chainman.GetConsensus(), next_index); + + next.pushKV("height", next_index.nHeight); + next.pushKV("bits", strprintf("%08x", next_index.nBits)); + next.pushKV("difficulty", GetDifficulty(next_index)); + next.pushKV("target", GetTarget(next_index, chainman.GetConsensus().powLimit).GetHex()); + obj.pushKV("next", next); + if (chainman.GetParams().GetChainType() == ChainType::SIGNET) { const std::vector& signet_challenge = - chainman.GetParams().GetConsensus().signet_challenge; + chainman.GetConsensus().signet_challenge; obj.pushKV("signet_challenge", HexStr(signet_challenge)); } obj.pushKV("warnings", node::GetWarningsForRpc(*CHECK_NONFATAL(node.warnings), IsDeprecatedRPCEnabled("warnings"))); diff --git a/src/rpc/server_util.cpp b/src/rpc/server_util.cpp index 0387cbb8e2..0edd7527a9 100644 --- a/src/rpc/server_util.cpp +++ b/src/rpc/server_util.cpp @@ -4,10 +4,13 @@ #include +#include #include #include #include +#include #include +#include #include #include #include @@ -17,6 +20,7 @@ #include using node::NodeContext; +using node::UpdateTime; NodeContext& EnsureAnyNodeContext(const std::any& context) { @@ -129,3 +133,18 @@ AddrMan& EnsureAnyAddrman(const std::any& context) { return EnsureAddrman(EnsureAnyNodeContext(context)); } + +void NextEmptyBlockIndex(CBlockIndex& tip, const Consensus::Params& consensusParams, CBlockIndex& next_index) +{ + CBlockHeader next_header{}; + next_header.hashPrevBlock = tip.GetBlockHash(); + UpdateTime(&next_header, consensusParams, &tip); + next_header.nBits = GetNextWorkRequired(&tip, &next_header, consensusParams); + next_header.nNonce = 0; + + next_index.pprev = &tip; + next_index.nTime = next_header.nTime; + next_index.nBits = next_header.nBits; + next_index.nNonce = next_header.nNonce; + next_index.nHeight = tip.nHeight + 1; +} diff --git a/src/rpc/server_util.h b/src/rpc/server_util.h index 1e6fb7e6a6..6fb5e1c9b3 100644 --- a/src/rpc/server_util.h +++ b/src/rpc/server_util.h @@ -7,8 +7,11 @@ #include +#include + class AddrMan; class ArgsManager; +class CBlockIndex; class CBlockPolicyEstimator; class CConnman; class CTxMemPool; @@ -39,4 +42,7 @@ PeerManager& EnsurePeerman(const node::NodeContext& node); AddrMan& EnsureAddrman(const node::NodeContext& node); AddrMan& EnsureAnyAddrman(const std::any& context); +/** Return an empty block index on top of the tip, with height, time and nBits set */ +void NextEmptyBlockIndex(CBlockIndex& tip, const Consensus::Params& consensusParams, CBlockIndex& next_index); + #endif // BITCOIN_RPC_SERVER_UTIL_H diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp index b1fbc25641..2941dda8c0 100644 --- a/src/rpc/util.cpp +++ b/src/rpc/util.cpp @@ -4,6 +4,7 @@ #include // IWYU pragma: keep +#include #include #include #include @@ -13,6 +14,7 @@ #include #include #include +#include #include #include