mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-09 11:27:28 -03:00
Compare commits
12 commits
223e8bcb99
...
d925a9bd7a
Author | SHA1 | Date | |
---|---|---|---|
|
d925a9bd7a | ||
|
7dc2f06990 | ||
|
d3564be226 | ||
|
a9ce7d1774 | ||
|
4463b0e04c | ||
|
590d3ab92c | ||
|
1502b98b8b | ||
|
f06f55090e | ||
|
a0145ce476 | ||
|
ef9e86039a | ||
|
ddd2ede17a | ||
|
2401931542 |
22 changed files with 2329 additions and 30 deletions
14
doc/release-notes-31583.md
Normal file
14
doc/release-notes-31583.md
Normal file
|
@ -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/<BLOCK-HASH>.json` and `GET /rest/headers/<BLOCK-HASH>.json` now return the current target in the `target` field
|
|
@ -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);
|
||||
|
|
10
src/rest.cpp
10
src/rest.cpp
|
@ -225,10 +225,10 @@ static bool rest_headers(const std::any& context,
|
|||
const CBlockIndex* tip = nullptr;
|
||||
std::vector<const CBlockIndex*> 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);
|
||||
|
|
|
@ -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<RPCResult> 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},
|
||||
|
|
|
@ -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<std::pair<CAmount, int64_t>>& scores, int64_t total_weight);
|
||||
|
|
|
@ -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" },
|
||||
|
|
|
@ -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<uint8_t>& 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")));
|
||||
|
|
|
@ -4,10 +4,13 @@
|
|||
|
||||
#include <rpc/server_util.h>
|
||||
|
||||
#include <chain.h>
|
||||
#include <common/args.h>
|
||||
#include <net_processing.h>
|
||||
#include <node/context.h>
|
||||
#include <node/miner.h>
|
||||
#include <policy/fees.h>
|
||||
#include <pow.h>
|
||||
#include <rpc/protocol.h>
|
||||
#include <rpc/request.h>
|
||||
#include <txmempool.h>
|
||||
|
@ -17,6 +20,7 @@
|
|||
#include <any>
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -7,8 +7,11 @@
|
|||
|
||||
#include <any>
|
||||
|
||||
#include <consensus/params.h>
|
||||
|
||||
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
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include <bitcoin-build-config.h> // IWYU pragma: keep
|
||||
|
||||
#include <chain.h>
|
||||
#include <clientversion.h>
|
||||
#include <common/args.h>
|
||||
#include <common/messages.h>
|
||||
|
@ -13,6 +14,7 @@
|
|||
#include <key_io.h>
|
||||
#include <node/types.h>
|
||||
#include <outputtype.h>
|
||||
#include <pow.h>
|
||||
#include <rpc/util.h>
|
||||
#include <script/descriptor.h>
|
||||
#include <script/interpreter.h>
|
||||
|
@ -1418,3 +1420,9 @@ std::vector<RPCResult> ScriptPubKeyDoc() {
|
|||
{RPCResult::Type::STR, "type", "The type (one of: " + GetAllOutputTypes() + ")"},
|
||||
};
|
||||
}
|
||||
|
||||
uint256 GetTarget(const CBlockIndex& blockindex, const uint256 pow_limit)
|
||||
{
|
||||
arith_uint256 target{*CHECK_NONFATAL(DeriveTarget(blockindex.nBits, pow_limit))};
|
||||
return ArithToUint256(target);
|
||||
}
|
||||
|
|
|
@ -516,4 +516,14 @@ void PushWarnings(const std::vector<bilingual_str>& warnings, UniValue& obj);
|
|||
|
||||
std::vector<RPCResult> ScriptPubKeyDoc();
|
||||
|
||||
/***
|
||||
* Get the target for a given block index.
|
||||
*
|
||||
* @param[in] blockindex the block
|
||||
* @param[in] pow_limit PoW limit (consensus parameter)
|
||||
*
|
||||
* @return the target
|
||||
*/
|
||||
uint256 GetTarget(const CBlockIndex& blockindex, const uint256 pow_limit);
|
||||
|
||||
#endif // BITCOIN_RPC_UTIL_H
|
||||
|
|
|
@ -147,6 +147,7 @@ const std::vector<std::string> RPC_COMMANDS_SAFE_FOR_FUZZING{
|
|||
"getorphantxs",
|
||||
"getpeerinfo",
|
||||
"getprioritisedtransactions",
|
||||
"gettarget",
|
||||
"getrawaddrman",
|
||||
"getrawmempool",
|
||||
"getrawtransaction",
|
||||
|
|
2015
test/functional/data/testnet4.hex
Normal file
2015
test/functional/data/testnet4.hex
Normal file
File diff suppressed because one or more lines are too long
|
@ -38,6 +38,12 @@ from test_framework.wallet import (
|
|||
getnewdestination,
|
||||
MiniWallet,
|
||||
)
|
||||
from test_framework.blocktools import (
|
||||
REGTEST_N_BITS,
|
||||
REGTEST_TARGET,
|
||||
nbits_str,
|
||||
target_str,
|
||||
)
|
||||
|
||||
START_HEIGHT = 199
|
||||
SNAPSHOT_BASE_HEIGHT = 299
|
||||
|
@ -229,6 +235,12 @@ class AssumeutxoTest(BitcoinTestFramework):
|
|||
assert_equal(normal['blocks'], START_HEIGHT + 99)
|
||||
assert_equal(snapshot['blocks'], SNAPSHOT_BASE_HEIGHT)
|
||||
|
||||
# Both states should have the same nBits and target
|
||||
assert_equal(normal['bits'], nbits_str(REGTEST_N_BITS))
|
||||
assert_equal(normal['bits'], snapshot['bits'])
|
||||
assert_equal(normal['target'], target_str(REGTEST_TARGET))
|
||||
assert_equal(normal['target'], snapshot['target'])
|
||||
|
||||
# Now lets sync the nodes and wait for the background validation to finish
|
||||
self.connect_nodes(0, 3)
|
||||
self.sync_blocks(nodes=(n0, n3))
|
||||
|
|
|
@ -12,6 +12,7 @@ from test_framework.blocktools import (
|
|||
create_tx_with_script,
|
||||
get_legacy_sigopcount_block,
|
||||
MAX_BLOCK_SIGOPS,
|
||||
REGTEST_N_BITS,
|
||||
)
|
||||
from test_framework.messages import (
|
||||
CBlock,
|
||||
|
@ -590,7 +591,7 @@ class FullBlockTest(BitcoinTestFramework):
|
|||
b44 = CBlock()
|
||||
b44.nTime = self.tip.nTime + 1
|
||||
b44.hashPrevBlock = self.tip.sha256
|
||||
b44.nBits = 0x207fffff
|
||||
b44.nBits = REGTEST_N_BITS
|
||||
b44.vtx.append(coinbase)
|
||||
tx = self.create_and_sign_transaction(out[14], 1)
|
||||
b44.vtx.append(tx)
|
||||
|
@ -606,7 +607,7 @@ class FullBlockTest(BitcoinTestFramework):
|
|||
b45 = CBlock()
|
||||
b45.nTime = self.tip.nTime + 1
|
||||
b45.hashPrevBlock = self.tip.sha256
|
||||
b45.nBits = 0x207fffff
|
||||
b45.nBits = REGTEST_N_BITS
|
||||
b45.vtx.append(non_coinbase)
|
||||
b45.hashMerkleRoot = b45.calc_merkle_root()
|
||||
b45.solve()
|
||||
|
@ -620,7 +621,7 @@ class FullBlockTest(BitcoinTestFramework):
|
|||
b46 = CBlock()
|
||||
b46.nTime = b44.nTime + 1
|
||||
b46.hashPrevBlock = b44.sha256
|
||||
b46.nBits = 0x207fffff
|
||||
b46.nBits = REGTEST_N_BITS
|
||||
b46.vtx = []
|
||||
b46.hashMerkleRoot = 0
|
||||
b46.solve()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -16,6 +16,10 @@ from test_framework.blocktools import (
|
|||
get_witness_script,
|
||||
NORMAL_GBT_REQUEST_PARAMS,
|
||||
TIME_GENESIS_BLOCK,
|
||||
REGTEST_N_BITS,
|
||||
REGTEST_TARGET,
|
||||
nbits_str,
|
||||
target_str,
|
||||
)
|
||||
from test_framework.messages import (
|
||||
BLOCK_HEADER_SIZE,
|
||||
|
@ -206,7 +210,15 @@ class MiningTest(BitcoinTestFramework):
|
|||
assert_equal(mining_info['chain'], self.chain)
|
||||
assert 'currentblocktx' not in mining_info
|
||||
assert 'currentblockweight' not in mining_info
|
||||
assert_equal(mining_info['bits'], nbits_str(REGTEST_N_BITS))
|
||||
assert_equal(mining_info['target'], target_str(REGTEST_TARGET))
|
||||
assert_equal(mining_info['difficulty'], Decimal('4.656542373906925E-10'))
|
||||
assert_equal(mining_info['next'], {
|
||||
'height': 201,
|
||||
'target': target_str(REGTEST_TARGET),
|
||||
'bits': nbits_str(REGTEST_N_BITS),
|
||||
'difficulty': Decimal('4.656542373906925E-10')
|
||||
})
|
||||
assert_equal(mining_info['networkhashps'], Decimal('0.003333333333333334'))
|
||||
assert_equal(mining_info['pooledtx'], 0)
|
||||
|
||||
|
|
73
test/functional/mining_testnet.py
Executable file
73
test/functional/mining_testnet.py
Executable file
|
@ -0,0 +1,73 @@
|
|||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2024 The Bitcoin Core developers
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
"""Test mining on testnet
|
||||
|
||||
Test mining related RPCs that involve difficulty adjustment, which
|
||||
regtest doesn't have.
|
||||
|
||||
It uses the first retarget period of testnet4, generated as follows:
|
||||
|
||||
for i in {1..2015}
|
||||
do
|
||||
hash=`bitcoin-cli -testnet4 getblockhash $i`
|
||||
block=`bitcoin-cli -testnet4 getblock $hash 0`
|
||||
echo $block >> data/testnet4.hex
|
||||
done
|
||||
"""
|
||||
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.util import (
|
||||
assert_equal,
|
||||
)
|
||||
from test_framework.blocktools import (
|
||||
DIFF_1_N_BITS,
|
||||
DIFF_1_TARGET,
|
||||
DIFF_4_N_BITS,
|
||||
DIFF_4_TARGET,
|
||||
nbits_str,
|
||||
target_str
|
||||
)
|
||||
|
||||
import os
|
||||
|
||||
class MiningTestnetTest(BitcoinTestFramework):
|
||||
|
||||
def set_test_params(self):
|
||||
self.num_nodes = 1
|
||||
self.setup_clean_chain = True
|
||||
self.chain = "testnet4"
|
||||
|
||||
def add_options(self, parser):
|
||||
parser.add_argument(
|
||||
'--datafile',
|
||||
default='data/testnet4.hex',
|
||||
help='Test data file (default: %(default)s)',
|
||||
)
|
||||
|
||||
def run_test(self):
|
||||
node = self.nodes[0]
|
||||
self.log.info("Load testnet4 blocks")
|
||||
self.headers_file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), self.options.datafile)
|
||||
with open(self.headers_file_path, encoding='utf-8') as blocks_data:
|
||||
for block in blocks_data:
|
||||
node.submitblock(block.strip())
|
||||
|
||||
assert_equal(node.getblockcount(), 2015)
|
||||
|
||||
mining_info = node.getmininginfo()
|
||||
assert_equal(mining_info['difficulty'], 1)
|
||||
assert_equal(mining_info['bits'], nbits_str(DIFF_1_N_BITS))
|
||||
assert_equal(mining_info['target'], target_str(DIFF_1_TARGET))
|
||||
|
||||
assert_equal(mining_info['next']['height'], 2016)
|
||||
assert_equal(mining_info['next']['difficulty'], 4)
|
||||
assert_equal(mining_info['next']['bits'], nbits_str(DIFF_4_N_BITS))
|
||||
assert_equal(mining_info['next']['target'], target_str(DIFF_4_TARGET))
|
||||
|
||||
assert_equal(node.getdifficulty(next=True), 4)
|
||||
assert_equal(node.gettarget(next=True), target_str(DIFF_4_TARGET))
|
||||
|
||||
if __name__ == '__main__':
|
||||
MiningTestnetTest(__file__).main()
|
|
@ -1,5 +1,5 @@
|
|||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2014-2022 The Bitcoin Core developers
|
||||
# Copyright (c) 2014-present The Bitcoin Core developers
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
"""Test RPCs related to blockchainstate.
|
||||
|
@ -11,6 +11,7 @@ Test the following RPCs:
|
|||
- gettxoutsetinfo
|
||||
- getblockheader
|
||||
- getdifficulty
|
||||
- gettarget
|
||||
- getnetworkhashps
|
||||
- waitforblockheight
|
||||
- getblock
|
||||
|
@ -30,9 +31,13 @@ import textwrap
|
|||
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,
|
||||
|
@ -88,6 +93,7 @@ class BlockchainTest(BitcoinTestFramework):
|
|||
self._test_gettxoutsetinfo()
|
||||
self._test_getblockheader()
|
||||
self._test_getdifficulty()
|
||||
self._test_gettarget()
|
||||
self._test_getnetworkhashps()
|
||||
self._test_stopatheight()
|
||||
self._test_waitforblock() # also tests waitfornewblock
|
||||
|
@ -129,6 +135,7 @@ class BlockchainTest(BitcoinTestFramework):
|
|||
|
||||
keys = [
|
||||
'bestblockhash',
|
||||
'bits',
|
||||
'blocks',
|
||||
'chain',
|
||||
'chainwork',
|
||||
|
@ -138,6 +145,7 @@ class BlockchainTest(BitcoinTestFramework):
|
|||
'mediantime',
|
||||
'pruned',
|
||||
'size_on_disk',
|
||||
'target',
|
||||
'time',
|
||||
'verificationprogress',
|
||||
'warnings',
|
||||
|
@ -194,6 +202,9 @@ class BlockchainTest(BitcoinTestFramework):
|
|||
assert_equal(res['prune_target_size'], 576716800)
|
||||
assert_greater_than(res['size_on_disk'], 0)
|
||||
|
||||
assert_equal(res['bits'], nbits_str(REGTEST_N_BITS))
|
||||
assert_equal(res['target'], target_str(REGTEST_TARGET))
|
||||
|
||||
def check_signalling_deploymentinfo_result(self, gdi_result, height, blockhash, status_next):
|
||||
assert height >= 144 and height <= 287
|
||||
|
||||
|
@ -412,7 +423,8 @@ class BlockchainTest(BitcoinTestFramework):
|
|||
assert_is_hash_string(header['hash'])
|
||||
assert_is_hash_string(header['previousblockhash'])
|
||||
assert_is_hash_string(header['merkleroot'])
|
||||
assert_is_hash_string(header['bits'], length=None)
|
||||
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)
|
||||
|
@ -437,6 +449,14 @@ class BlockchainTest(BitcoinTestFramework):
|
|||
# 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
|
||||
self.log.info("Next difficulty should be the same as the current (no difficulty adjustment)")
|
||||
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, target_str(REGTEST_TARGET))
|
||||
assert_equal(self.nodes[0].gettarget(next=True), target_str(REGTEST_TARGET))
|
||||
|
||||
def _test_getnetworkhashps(self):
|
||||
self.log.info("Test getnetworkhashps")
|
||||
|
|
|
@ -27,6 +27,7 @@ from .messages import (
|
|||
hash256,
|
||||
ser_uint256,
|
||||
tx_from_hex,
|
||||
uint256_from_compact,
|
||||
uint256_from_str,
|
||||
WITNESS_SCALE_FACTOR,
|
||||
)
|
||||
|
@ -65,6 +66,23 @@ NORMAL_GBT_REQUEST_PARAMS = {"rules": ["segwit"]}
|
|||
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)
|
||||
|
||||
DIFF_1_N_BITS = 0x1d00ffff
|
||||
DIFF_1_TARGET = 0x00000000ffff0000000000000000000000000000000000000000000000000000
|
||||
assert_equal(uint256_from_compact(DIFF_1_N_BITS), DIFF_1_TARGET)
|
||||
|
||||
DIFF_4_N_BITS = 0x1c3fffc0
|
||||
DIFF_4_TARGET = int(DIFF_1_TARGET / 4)
|
||||
assert_equal(uint256_from_compact(DIFF_4_N_BITS), DIFF_4_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)."""
|
||||
|
@ -77,7 +95,7 @@ def create_block(hashprev=None, coinbase=None, ntime=None, *, version=None, tmpl
|
|||
if tmpl and tmpl.get('bits') is not None:
|
||||
block.nBits = struct.unpack('>I', bytes.fromhex(tmpl['bits']))[0]
|
||||
else:
|
||||
block.nBits = 0x207fffff # difficulty retargeting is disabled in REGTEST chainparams
|
||||
block.nBits = REGTEST_N_BITS
|
||||
if coinbase is None:
|
||||
coinbase = create_coinbase(height=tmpl['height'])
|
||||
block.vtx.append(coinbase)
|
||||
|
|
|
@ -316,6 +316,7 @@ BASE_SCRIPTS = [
|
|||
'wallet_upgradewallet.py --legacy-wallet',
|
||||
'wallet_crosschain.py',
|
||||
'mining_basic.py',
|
||||
'mining_testnet.py',
|
||||
'feature_signet.py',
|
||||
'p2p_mutated_blocks.py',
|
||||
'wallet_implicitsegwit.py --legacy-wallet',
|
||||
|
|
|
@ -9,6 +9,7 @@ import subprocess
|
|||
import sys
|
||||
import time
|
||||
|
||||
from test_framework.blocktools import DIFF_1_N_BITS
|
||||
from test_framework.key import ECKey
|
||||
from test_framework.script_util import key_to_p2wpkh_script
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
|
@ -55,7 +56,7 @@ class SignetMinerTest(BitcoinTestFramework):
|
|||
'generate',
|
||||
f'--address={node.getnewaddress()}',
|
||||
f'--grind-cmd={self.options.bitcoinutil} grind',
|
||||
'--nbits=1d00ffff',
|
||||
f'--nbits={hex(DIFF_1_N_BITS)}',
|
||||
f'--set-block-time={int(time.time())}',
|
||||
'--poolnum=99',
|
||||
], check=True, stderr=subprocess.STDOUT)
|
||||
|
|
Loading…
Reference in a new issue