Skip to content

Commit

Permalink
rpc: add next to getdifficulty and gettarget
Browse files Browse the repository at this point in the history
Obtain the difficulty / target for the next block without having to call getblocktemplate.
  • Loading branch information
Sjors committed Dec 31, 2024
1 parent da1eb29 commit 7696188
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 4 deletions.
50 changes: 46 additions & 4 deletions src/rpc/blockchain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include <net_processing.h>
#include <node/blockstorage.h>
#include <node/context.h>
#include <node/miner.h>
#include <node/transaction.h>
#include <node/utxo_snapshot.h>
#include <node/warnings.h>
Expand Down Expand Up @@ -68,6 +69,7 @@ using interfaces::Mining;
using node::BlockManager;
using node::NodeContext;
using node::SnapshotMetadata;
using node::UpdateTime;
using util::MakeUnorderedList;

std::tuple<std::unique_ptr<CCoinsViewCursor>, CCoinsStats, const CBlockIndex*>
Expand Down Expand Up @@ -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{
Expand All @@ -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);
}

},
};
}
Expand All @@ -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{
Expand All @@ -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();
}
},
};
}
Expand Down
2 changes: 2 additions & 0 deletions src/rpc/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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" },
Expand Down
2 changes: 2 additions & 0 deletions test/functional/rpc_blockchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down

0 comments on commit 7696188

Please sign in to comment.