diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 1a41a5c50c453a..0d38625177c09e 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -68,6 +69,7 @@ using interfaces::Mining; using node::BlockManager; using node::NodeContext; using node::SnapshotMetadata; +using node::UpdateTime; using util::MakeUnorderedList; std::tuple, CCoinsStats, const CBlockIndex*> @@ -431,7 +433,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{ @@ -442,7 +446,26 @@ static RPCHelpMan getdifficulty() { ChainstateManager& chainman = EnsureAnyChainman(request.context); LOCK(cs_main); - return GetDifficulty(*CHECK_NONFATAL(chainman.ActiveChain().Tip())); + CBlockIndex* tip{CHECK_NONFATAL(chainman.ActiveChain().Tip())}; + + bool next{false}; + if (!request.params[0].isNull()) { + next = request.params[0].get_bool(); + } + + if (next) { + CBlock block{}; + auto consensusParams{chainman.GetParams().GetConsensus()}; + // This also updates nBits + UpdateTime(&block, consensusParams, tip); + CBlockIndex index(block); + index.pprev = tip; + index.nHeight = tip->nHeight + 1; + return GetDifficulty(index); + } else { + return GetDifficulty(*tip); + } + }, }; } @@ -451,7 +474,9 @@ 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{ @@ -463,7 +488,24 @@ static RPCHelpMan gettarget() ChainstateManager& chainman = EnsureAnyChainman(request.context); LOCK(cs_main); CBlockIndex* tip{CHECK_NONFATAL(chainman.ActiveChain().Tip())}; - return GetTarget(*tip, chainman.GetParams().GetConsensus().powLimit).GetHex(); + auto consensusParams{chainman.GetParams().GetConsensus()}; + + bool next{false}; + if (!request.params[0].isNull()) { + next = request.params[0].get_bool(); + } + + if (next) { + CBlock block{}; + // This also updates nBits + UpdateTime(&block, consensusParams, tip); + CBlockIndex index(block); + index.pprev = tip; + index.nHeight = tip->nHeight + 1; + return GetTarget(index, consensusParams.powLimit).GetHex(); + } else { + return GetTarget(*tip, consensusParams.powLimit).GetHex(); + } }, }; } diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index 1b711e3c5b1500..1805aa3c260667 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/test/functional/rpc_blockchain.py b/test/functional/rpc_blockchain.py index 972d3984df535d..58a0fbfa07f820 100755 --- a/test/functional/rpc_blockchain.py +++ b/test/functional/rpc_blockchain.py @@ -441,11 +441,13 @@ def _test_getdifficulty(self): # 1 hash in 2 should be valid, so difficulty should be 1/2**31 # binary => decimal => binary math is why we do this check assert abs(difficulty * 2**31 - 1) < 0.0001 + assert_equal(self.nodes[0].getdifficulty(next=True), difficulty) def _test_gettarget(self): self.log.info("Test gettarget") target = self.nodes[0].gettarget() assert_equal(target, REGTEST_TARGET_STR) + assert_equal(self.nodes[0].gettarget(next=True), REGTEST_TARGET_STR) def _test_getnetworkhashps(self): self.log.info("Test getnetworkhashps")