Skip to content

Commit 5acf12b

Browse files
committed
Merge bitcoin/bitcoin#31583: rpc: add target to getmininginfo field and show next block info
a4df123 doc: add release notes (Sjors Provoost) c75872f test: use DIFF_1_N_BITS in tool_signet_miner (tdb3) 4131f32 test: check difficulty adjustment using alternate mainnet (Sjors Provoost) c4f68c1 Use OP_0 for BIP34 padding in signet and tests (Sjors Provoost) cf0a628 rpc: add next to getmininginfo (Sjors Provoost) 2d18a07 rpc: add target and bits to getchainstates (Sjors Provoost) f153f57 rpc: add target and bits to getblockchaininfo (Sjors Provoost) baa504f rpc: add target to getmininginfo result (Sjors Provoost) 2a7bfeb Add target to getblock(header) in RPC and REST (Sjors Provoost) 341f932 rpc: add GetTarget helper (Sjors Provoost) d20d96f test: use REGTEST_N_BITS in feature_block (tdb3) 7ddbed4 rpc: add nBits to getmininginfo (Sjors Provoost) ba7b9f3 build: move pow and chain to bitcoin_common (Sjors Provoost) c4cc9e3 consensus: add DeriveTarget() to pow.h (Sjors Provoost) Pull request description: **tl&dr for consensus-code only reviewers**: the first commit splits `CheckProofOfWorkImpl()` in order to create a `DeriveTarget()` helper. The rest of this PR does not touch consensus code. There are three ways to represent the proof-of-work in a block: 1. nBits 2. Difficulty 3. Target The latter notation is useful when you want to compare share work against either the pool target (to get paid) or network difficulty (found an actual block). E.g. for difficulty 1 which corresponds to an nBits value of `0x00ffff`: ``` share hash: f6b973257df982284715b0c7a20640dad709d22b0b1a58f2f88d35886ea5ac45 target: 7fffff0000000000000000000000000000000000000000000000000000000000 ``` It's immediately clear that the share is invalid because the hash is above the target. This type of logging is mostly done by the pool software. It's a nice extra convenience, but not very important. It impacts the following RPC calls: 1. `getmininginfo` displays the `target` for the tip block 2. `getblock` and `getblockheader` display the `target` for a specific block (ditto for their REST equivalents) The `getdifficulty` method is a bit useless in its current state, because what miners really want to know if the difficulty for the _next_ block. So I added a boolean argument `next` to `getdifficulty`. (These values are typically the same, except for the first block in a retarget period. On testnet3 / testnet4 they change when no block is found after 20 minutes). Similarly I added a `next` object to `getmininginfo` which shows `bit`, `difficulty` and `target` for the next block. In order to test the difficulty transition, an alternate mainnet chain with 2016 blocks was generated and used in `mining_mainnet.py`. The chain is deterministic except for its timestamp and nonce values, which are stored in `mainnet_alt.json`. As described at the top, this PR introduces a helper method `DeriveTarget()` which is split out from `CheckProofOfWorkImpl`. The proposed `checkblock` RPC in #31564 needs this helper method internally to figure out the consensus target. Finally, this PR moves `pow.cpp` and `chain.cpp` from `bitcoin_node` to `bitcoin_common`, in order to give `rpc/util.cpp` (which lives in `bitcoin_common`) access to `pow.h`. ACKs for top commit: ismaelsadeeq: re-ACK a4df123 tdb3: code review re ACK a4df123 ryanofsky: Code review ACK a4df123. Only overall changes since last review were dropping new `gettarget` method and dropping changes to `getdifficulty`, but there were also various internal changes splitting and rearranging commits. Tree-SHA512: edef5633590379c4be007ac96fd1deda8a5b9562ca6ff19fe377cb552b5166f3890d158554c249ab8345977a06da5df07866c9f42ac43ee83dfe3830c61cd169
2 parents 78fa88c + a4df123 commit 5acf12b

24 files changed

+4385
-37
lines changed

doc/release-notes-31583.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Updated RPCs
2+
---
3+
- `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.
4+
- `getblock` and `getblockheader` now return the current target in the `target` field
5+
- `getblockchaininfo` and `getchainstates` now return `nBits` and the current target in the `target` field
6+
7+
REST interface
8+
---
9+
- `GET /rest/block/<BLOCK-HASH>.json` and `GET /rest/headers/<BLOCK-HASH>.json` now return the current target in the `target` field

src/CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ add_library(bitcoin_common STATIC EXCLUDE_FROM_ALL
109109
addresstype.cpp
110110
base58.cpp
111111
bech32.cpp
112+
chain.cpp
112113
chainparams.cpp
113114
chainparamsbase.cpp
114115
coins.cpp
@@ -142,6 +143,7 @@ add_library(bitcoin_common STATIC EXCLUDE_FROM_ALL
142143
outputtype.cpp
143144
policy/feerate.cpp
144145
policy/policy.cpp
146+
pow.cpp
145147
protocol.cpp
146148
psbt.cpp
147149
rpc/external_signer.cpp
@@ -200,7 +202,6 @@ add_library(bitcoin_node STATIC EXCLUDE_FROM_ALL
200202
bip324.cpp
201203
blockencodings.cpp
202204
blockfilter.cpp
203-
chain.cpp
204205
consensus/tx_verify.cpp
205206
dbwrapper.cpp
206207
deploymentstatus.cpp
@@ -262,7 +263,6 @@ add_library(bitcoin_node STATIC EXCLUDE_FROM_ALL
262263
policy/rbf.cpp
263264
policy/settings.cpp
264265
policy/truc_policy.cpp
265-
pow.cpp
266266
rest.cpp
267267
rpc/blockchain.cpp
268268
rpc/fees.cpp

src/bench/rpc_blockchain.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,9 @@ struct TestBlockAndIndex {
4848
static void BlockToJsonVerbose(benchmark::Bench& bench)
4949
{
5050
TestBlockAndIndex data;
51+
const uint256 pow_limit{data.testing_setup->m_node.chainman->GetParams().GetConsensus().powLimit};
5152
bench.run([&] {
52-
auto univalue = blockToJSON(data.testing_setup->m_node.chainman->m_blockman, data.block, data.blockindex, data.blockindex, TxVerbosity::SHOW_DETAILS_AND_PREVOUT);
53+
auto univalue = blockToJSON(data.testing_setup->m_node.chainman->m_blockman, data.block, data.blockindex, data.blockindex, TxVerbosity::SHOW_DETAILS_AND_PREVOUT, pow_limit);
5354
ankerl::nanobench::doNotOptimizeAway(univalue);
5455
});
5556
}
@@ -59,7 +60,8 @@ BENCHMARK(BlockToJsonVerbose, benchmark::PriorityLevel::HIGH);
5960
static void BlockToJsonVerboseWrite(benchmark::Bench& bench)
6061
{
6162
TestBlockAndIndex data;
62-
auto univalue = blockToJSON(data.testing_setup->m_node.chainman->m_blockman, data.block, data.blockindex, data.blockindex, TxVerbosity::SHOW_DETAILS_AND_PREVOUT);
63+
const uint256 pow_limit{data.testing_setup->m_node.chainman->GetParams().GetConsensus().powLimit};
64+
auto univalue = blockToJSON(data.testing_setup->m_node.chainman->m_blockman, data.block, data.blockindex, data.blockindex, TxVerbosity::SHOW_DETAILS_AND_PREVOUT, pow_limit);
6365
bench.run([&] {
6466
auto str = univalue.write();
6567
ankerl::nanobench::doNotOptimizeAway(str);

src/pow.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params&
143143
return CheckProofOfWorkImpl(hash, nBits, params);
144144
}
145145

146-
bool CheckProofOfWorkImpl(uint256 hash, unsigned int nBits, const Consensus::Params& params)
146+
std::optional<arith_uint256> DeriveTarget(unsigned int nBits, const uint256 pow_limit)
147147
{
148148
bool fNegative;
149149
bool fOverflow;
@@ -152,8 +152,16 @@ bool CheckProofOfWorkImpl(uint256 hash, unsigned int nBits, const Consensus::Par
152152
bnTarget.SetCompact(nBits, &fNegative, &fOverflow);
153153

154154
// Check range
155-
if (fNegative || bnTarget == 0 || fOverflow || bnTarget > UintToArith256(params.powLimit))
156-
return false;
155+
if (fNegative || bnTarget == 0 || fOverflow || bnTarget > UintToArith256(pow_limit))
156+
return {};
157+
158+
return bnTarget;
159+
}
160+
161+
bool CheckProofOfWorkImpl(uint256 hash, unsigned int nBits, const Consensus::Params& params)
162+
{
163+
auto bnTarget{DeriveTarget(nBits, params.powLimit)};
164+
if (!bnTarget) return false;
157165

158166
// Check proof of work matches claimed amount
159167
if (UintToArith256(hash) > bnTarget)

src/pow.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,18 @@
1313
class CBlockHeader;
1414
class CBlockIndex;
1515
class uint256;
16+
class arith_uint256;
17+
18+
/**
19+
* Convert nBits value to target.
20+
*
21+
* @param[in] nBits compact representation of the target
22+
* @param[in] pow_limit PoW limit (consensus parameter)
23+
*
24+
* @return the proof-of-work target or nullopt if the nBits value
25+
* is invalid (due to overflow or exceeding pow_limit)
26+
*/
27+
std::optional<arith_uint256> DeriveTarget(unsigned int nBits, const uint256 pow_limit);
1628

1729
unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params&);
1830
unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nFirstBlockTime, const Consensus::Params&);

src/rest.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -225,10 +225,10 @@ static bool rest_headers(const std::any& context,
225225
const CBlockIndex* tip = nullptr;
226226
std::vector<const CBlockIndex*> headers;
227227
headers.reserve(*parsed_count);
228+
ChainstateManager* maybe_chainman = GetChainman(context, req);
229+
if (!maybe_chainman) return false;
230+
ChainstateManager& chainman = *maybe_chainman;
228231
{
229-
ChainstateManager* maybe_chainman = GetChainman(context, req);
230-
if (!maybe_chainman) return false;
231-
ChainstateManager& chainman = *maybe_chainman;
232232
LOCK(cs_main);
233233
CChain& active_chain = chainman.ActiveChain();
234234
tip = active_chain.Tip();
@@ -268,7 +268,7 @@ static bool rest_headers(const std::any& context,
268268
case RESTResponseFormat::JSON: {
269269
UniValue jsonHeaders(UniValue::VARR);
270270
for (const CBlockIndex *pindex : headers) {
271-
jsonHeaders.push_back(blockheaderToJSON(*tip, *pindex));
271+
jsonHeaders.push_back(blockheaderToJSON(*tip, *pindex, chainman.GetConsensus().powLimit));
272272
}
273273
std::string strJSON = jsonHeaders.write() + "\n";
274274
req->WriteHeader("Content-Type", "application/json");
@@ -341,7 +341,7 @@ static bool rest_block(const std::any& context,
341341
CBlock block{};
342342
DataStream block_stream{block_data};
343343
block_stream >> TX_WITH_WITNESS(block);
344-
UniValue objBlock = blockToJSON(chainman.m_blockman, block, *tip, *pblockindex, tx_verbosity);
344+
UniValue objBlock = blockToJSON(chainman.m_blockman, block, *tip, *pblockindex, tx_verbosity, chainman.GetConsensus().powLimit);
345345
std::string strJSON = objBlock.write() + "\n";
346346
req->WriteHeader("Content-Type", "application/json");
347347
req->WriteReply(HTTP_OK, strJSON);

src/rpc/blockchain.cpp

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ static const CBlockIndex* ParseHashOrHeight(const UniValue& param, ChainstateMan
146146
}
147147
}
148148

149-
UniValue blockheaderToJSON(const CBlockIndex& tip, const CBlockIndex& blockindex)
149+
UniValue blockheaderToJSON(const CBlockIndex& tip, const CBlockIndex& blockindex, const uint256 pow_limit)
150150
{
151151
// Serialize passed information without accessing chain state of the active chain!
152152
AssertLockNotHeld(cs_main); // For performance reasons
@@ -164,6 +164,7 @@ UniValue blockheaderToJSON(const CBlockIndex& tip, const CBlockIndex& blockindex
164164
result.pushKV("mediantime", blockindex.GetMedianTimePast());
165165
result.pushKV("nonce", blockindex.nNonce);
166166
result.pushKV("bits", strprintf("%08x", blockindex.nBits));
167+
result.pushKV("target", GetTarget(tip, pow_limit).GetHex());
167168
result.pushKV("difficulty", GetDifficulty(blockindex));
168169
result.pushKV("chainwork", blockindex.nChainWork.GetHex());
169170
result.pushKV("nTx", blockindex.nTx);
@@ -175,9 +176,9 @@ UniValue blockheaderToJSON(const CBlockIndex& tip, const CBlockIndex& blockindex
175176
return result;
176177
}
177178

178-
UniValue blockToJSON(BlockManager& blockman, const CBlock& block, const CBlockIndex& tip, const CBlockIndex& blockindex, TxVerbosity verbosity)
179+
UniValue blockToJSON(BlockManager& blockman, const CBlock& block, const CBlockIndex& tip, const CBlockIndex& blockindex, TxVerbosity verbosity, const uint256 pow_limit)
179180
{
180-
UniValue result = blockheaderToJSON(tip, blockindex);
181+
UniValue result = blockheaderToJSON(tip, blockindex, pow_limit);
181182

182183
result.pushKV("strippedsize", (int)::GetSerializeSize(TX_NO_WITNESS(block)));
183184
result.pushKV("size", (int)::GetSerializeSize(TX_WITH_WITNESS(block)));
@@ -553,7 +554,8 @@ static RPCHelpMan getblockheader()
553554
{RPCResult::Type::NUM_TIME, "time", "The block time expressed in " + UNIX_EPOCH_TIME},
554555
{RPCResult::Type::NUM_TIME, "mediantime", "The median block time expressed in " + UNIX_EPOCH_TIME},
555556
{RPCResult::Type::NUM, "nonce", "The nonce"},
556-
{RPCResult::Type::STR_HEX, "bits", "The bits"},
557+
{RPCResult::Type::STR_HEX, "bits", "nBits: compact representation of the block difficulty target"},
558+
{RPCResult::Type::STR_HEX, "target", "The difficulty target"},
557559
{RPCResult::Type::NUM, "difficulty", "The difficulty"},
558560
{RPCResult::Type::STR_HEX, "chainwork", "Expected number of hashes required to produce the current chain"},
559561
{RPCResult::Type::NUM, "nTx", "The number of transactions in the block"},
@@ -577,8 +579,8 @@ static RPCHelpMan getblockheader()
577579

578580
const CBlockIndex* pblockindex;
579581
const CBlockIndex* tip;
582+
ChainstateManager& chainman = EnsureAnyChainman(request.context);
580583
{
581-
ChainstateManager& chainman = EnsureAnyChainman(request.context);
582584
LOCK(cs_main);
583585
pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
584586
tip = chainman.ActiveChain().Tip();
@@ -596,7 +598,7 @@ static RPCHelpMan getblockheader()
596598
return strHex;
597599
}
598600

599-
return blockheaderToJSON(*tip, *pblockindex);
601+
return blockheaderToJSON(*tip, *pblockindex, chainman.GetConsensus().powLimit);
600602
},
601603
};
602604
}
@@ -727,7 +729,8 @@ static RPCHelpMan getblock()
727729
{RPCResult::Type::NUM_TIME, "time", "The block time expressed in " + UNIX_EPOCH_TIME},
728730
{RPCResult::Type::NUM_TIME, "mediantime", "The median block time expressed in " + UNIX_EPOCH_TIME},
729731
{RPCResult::Type::NUM, "nonce", "The nonce"},
730-
{RPCResult::Type::STR_HEX, "bits", "The bits"},
732+
{RPCResult::Type::STR_HEX, "bits", "nBits: compact representation of the block difficulty target"},
733+
{RPCResult::Type::STR_HEX, "target", "The difficulty target"},
731734
{RPCResult::Type::NUM, "difficulty", "The difficulty"},
732735
{RPCResult::Type::STR_HEX, "chainwork", "Expected number of hashes required to produce the chain up to this block (in hex)"},
733736
{RPCResult::Type::NUM, "nTx", "The number of transactions in the block"},
@@ -802,7 +805,7 @@ static RPCHelpMan getblock()
802805
tx_verbosity = TxVerbosity::SHOW_DETAILS_AND_PREVOUT;
803806
}
804807

805-
return blockToJSON(chainman.m_blockman, block, *tip, *pblockindex, tx_verbosity);
808+
return blockToJSON(chainman.m_blockman, block, *tip, *pblockindex, tx_verbosity, chainman.GetConsensus().powLimit);
806809
},
807810
};
808811
}
@@ -1296,6 +1299,8 @@ RPCHelpMan getblockchaininfo()
12961299
{RPCResult::Type::NUM, "blocks", "the height of the most-work fully-validated chain. The genesis block has height 0"},
12971300
{RPCResult::Type::NUM, "headers", "the current number of headers we have validated"},
12981301
{RPCResult::Type::STR, "bestblockhash", "the hash of the currently best block"},
1302+
{RPCResult::Type::STR_HEX, "bits", "nBits: compact representation of the block difficulty target"},
1303+
{RPCResult::Type::STR_HEX, "target", "The difficulty target"},
12991304
{RPCResult::Type::NUM, "difficulty", "the current difficulty"},
13001305
{RPCResult::Type::NUM_TIME, "time", "The block time expressed in " + UNIX_EPOCH_TIME},
13011306
{RPCResult::Type::NUM_TIME, "mediantime", "The median block time expressed in " + UNIX_EPOCH_TIME},
@@ -1334,6 +1339,8 @@ RPCHelpMan getblockchaininfo()
13341339
obj.pushKV("blocks", height);
13351340
obj.pushKV("headers", chainman.m_best_header ? chainman.m_best_header->nHeight : -1);
13361341
obj.pushKV("bestblockhash", tip.GetBlockHash().GetHex());
1342+
obj.pushKV("bits", strprintf("%08x", tip.nBits));
1343+
obj.pushKV("target", GetTarget(tip, chainman.GetConsensus().powLimit).GetHex());
13371344
obj.pushKV("difficulty", GetDifficulty(tip));
13381345
obj.pushKV("time", tip.GetBlockTime());
13391346
obj.pushKV("mediantime", tip.GetMedianTimePast());
@@ -3301,6 +3308,8 @@ static RPCHelpMan loadtxoutset()
33013308
const std::vector<RPCResult> RPCHelpForChainstate{
33023309
{RPCResult::Type::NUM, "blocks", "number of blocks in this chainstate"},
33033310
{RPCResult::Type::STR_HEX, "bestblockhash", "blockhash of the tip"},
3311+
{RPCResult::Type::STR_HEX, "bits", "nBits: compact representation of the block difficulty target"},
3312+
{RPCResult::Type::STR_HEX, "target", "The difficulty target"},
33043313
{RPCResult::Type::NUM, "difficulty", "difficulty of the tip"},
33053314
{RPCResult::Type::NUM, "verificationprogress", "progress towards the network tip"},
33063315
{RPCResult::Type::STR_HEX, "snapshot_blockhash", /*optional=*/true, "the base block of the snapshot this chainstate is based on, if any"},
@@ -3343,6 +3352,8 @@ return RPCHelpMan{
33433352

33443353
data.pushKV("blocks", (int)chain.Height());
33453354
data.pushKV("bestblockhash", tip->GetBlockHash().GetHex());
3355+
data.pushKV("bits", strprintf("%08x", tip->nBits));
3356+
data.pushKV("target", GetTarget(*tip, chainman.GetConsensus().powLimit).GetHex());
33463357
data.pushKV("difficulty", GetDifficulty(*tip));
33473358
data.pushKV("verificationprogress", chainman.GuessVerificationProgress(tip));
33483359
data.pushKV("coins_db_cache_bytes", cs.m_coinsdb_cache_size_bytes);

src/rpc/blockchain.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,10 @@ static constexpr int NUM_GETBLOCKSTATS_PERCENTILES = 5;
3636
double GetDifficulty(const CBlockIndex& blockindex);
3737

3838
/** Block description to JSON */
39-
UniValue blockToJSON(node::BlockManager& blockman, const CBlock& block, const CBlockIndex& tip, const CBlockIndex& blockindex, TxVerbosity verbosity) LOCKS_EXCLUDED(cs_main);
39+
UniValue blockToJSON(node::BlockManager& blockman, const CBlock& block, const CBlockIndex& tip, const CBlockIndex& blockindex, TxVerbosity verbosity, const uint256 pow_limit) LOCKS_EXCLUDED(cs_main);
4040

4141
/** Block header to JSON */
42-
UniValue blockheaderToJSON(const CBlockIndex& tip, const CBlockIndex& blockindex) LOCKS_EXCLUDED(cs_main);
42+
UniValue blockheaderToJSON(const CBlockIndex& tip, const CBlockIndex& blockindex, const uint256 pow_limit) LOCKS_EXCLUDED(cs_main);
4343

4444
/** Used by getblockstats to get feerates at different percentiles by weight */
4545
void CalculatePercentilesByWeight(CAmount result[NUM_GETBLOCKSTATS_PERCENTILES], std::vector<std::pair<CAmount, int64_t>>& scores, int64_t total_weight);

src/rpc/mining.cpp

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -421,11 +421,20 @@ static RPCHelpMan getmininginfo()
421421
{RPCResult::Type::NUM, "blocks", "The current block"},
422422
{RPCResult::Type::NUM, "currentblockweight", /*optional=*/true, "The block weight of the last assembled block (only present if a block was ever assembled)"},
423423
{RPCResult::Type::NUM, "currentblocktx", /*optional=*/true, "The number of block transactions of the last assembled block (only present if a block was ever assembled)"},
424+
{RPCResult::Type::STR_HEX, "bits", "The current nBits, compact representation of the block difficulty target"},
424425
{RPCResult::Type::NUM, "difficulty", "The current difficulty"},
426+
{RPCResult::Type::STR_HEX, "target", "The current target"},
425427
{RPCResult::Type::NUM, "networkhashps", "The network hashes per second"},
426428
{RPCResult::Type::NUM, "pooledtx", "The size of the mempool"},
427429
{RPCResult::Type::STR, "chain", "current network name (" LIST_CHAIN_NAMES ")"},
428430
{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)"},
431+
{RPCResult::Type::OBJ, "next", "The next block",
432+
{
433+
{RPCResult::Type::NUM, "height", "The next height"},
434+
{RPCResult::Type::STR_HEX, "bits", "The next target nBits"},
435+
{RPCResult::Type::NUM, "difficulty", "The next difficulty"},
436+
{RPCResult::Type::STR_HEX, "target", "The next target"}
437+
}},
429438
(IsDeprecatedRPCEnabled("warnings") ?
430439
RPCResult{RPCResult::Type::STR, "warnings", "any network and blockchain warnings (DEPRECATED)"} :
431440
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()
446455
ChainstateManager& chainman = EnsureChainman(node);
447456
LOCK(cs_main);
448457
const CChain& active_chain = chainman.ActiveChain();
458+
CBlockIndex& tip{*CHECK_NONFATAL(active_chain.Tip())};
449459

450460
UniValue obj(UniValue::VOBJ);
451461
obj.pushKV("blocks", active_chain.Height());
452462
if (BlockAssembler::m_last_block_weight) obj.pushKV("currentblockweight", *BlockAssembler::m_last_block_weight);
453463
if (BlockAssembler::m_last_block_num_txs) obj.pushKV("currentblocktx", *BlockAssembler::m_last_block_num_txs);
454-
obj.pushKV("difficulty", GetDifficulty(*CHECK_NONFATAL(active_chain.Tip())));
464+
obj.pushKV("bits", strprintf("%08x", tip.nBits));
465+
obj.pushKV("difficulty", GetDifficulty(tip));
466+
obj.pushKV("target", GetTarget(tip, chainman.GetConsensus().powLimit).GetHex());
455467
obj.pushKV("networkhashps", getnetworkhashps().HandleRequest(request));
456468
obj.pushKV("pooledtx", (uint64_t)mempool.size());
457469
obj.pushKV("chain", chainman.GetParams().GetChainTypeString());
470+
471+
UniValue next(UniValue::VOBJ);
472+
CBlockIndex next_index;
473+
NextEmptyBlockIndex(tip, chainman.GetConsensus(), next_index);
474+
475+
next.pushKV("height", next_index.nHeight);
476+
next.pushKV("bits", strprintf("%08x", next_index.nBits));
477+
next.pushKV("difficulty", GetDifficulty(next_index));
478+
next.pushKV("target", GetTarget(next_index, chainman.GetConsensus().powLimit).GetHex());
479+
obj.pushKV("next", next);
480+
458481
if (chainman.GetParams().GetChainType() == ChainType::SIGNET) {
459482
const std::vector<uint8_t>& signet_challenge =
460-
chainman.GetParams().GetConsensus().signet_challenge;
483+
chainman.GetConsensus().signet_challenge;
461484
obj.pushKV("signet_challenge", HexStr(signet_challenge));
462485
}
463486
obj.pushKV("warnings", node::GetWarningsForRpc(*CHECK_NONFATAL(node.warnings), IsDeprecatedRPCEnabled("warnings")));

src/rpc/server_util.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@
44

55
#include <rpc/server_util.h>
66

7+
#include <chain.h>
78
#include <common/args.h>
89
#include <net_processing.h>
910
#include <node/context.h>
11+
#include <node/miner.h>
1012
#include <policy/fees.h>
13+
#include <pow.h>
1114
#include <rpc/protocol.h>
1215
#include <rpc/request.h>
1316
#include <txmempool.h>
@@ -17,6 +20,7 @@
1720
#include <any>
1821

1922
using node::NodeContext;
23+
using node::UpdateTime;
2024

2125
NodeContext& EnsureAnyNodeContext(const std::any& context)
2226
{
@@ -129,3 +133,18 @@ AddrMan& EnsureAnyAddrman(const std::any& context)
129133
{
130134
return EnsureAddrman(EnsureAnyNodeContext(context));
131135
}
136+
137+
void NextEmptyBlockIndex(CBlockIndex& tip, const Consensus::Params& consensusParams, CBlockIndex& next_index)
138+
{
139+
CBlockHeader next_header{};
140+
next_header.hashPrevBlock = tip.GetBlockHash();
141+
UpdateTime(&next_header, consensusParams, &tip);
142+
next_header.nBits = GetNextWorkRequired(&tip, &next_header, consensusParams);
143+
next_header.nNonce = 0;
144+
145+
next_index.pprev = &tip;
146+
next_index.nTime = next_header.nTime;
147+
next_index.nBits = next_header.nBits;
148+
next_index.nNonce = next_header.nNonce;
149+
next_index.nHeight = tip.nHeight + 1;
150+
}

0 commit comments

Comments
 (0)