aboutsummaryrefslogtreecommitdiff
path: root/src/rpc/blockchain.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/rpc/blockchain.cpp')
-rw-r--r--src/rpc/blockchain.cpp427
1 files changed, 244 insertions, 183 deletions
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index a61857ca7d..315f69d46b 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -39,7 +39,6 @@
#include <univalue.h>
-#include <boost/algorithm/string.hpp>
#include <boost/thread/thread.hpp> // boost::thread::interrupt
#include <memory>
@@ -60,10 +59,7 @@ static CUpdatedBlock latestblock;
*/
double GetDifficulty(const CBlockIndex* blockindex)
{
- if (blockindex == nullptr)
- {
- return 1.0;
- }
+ assert(blockindex);
int nShift = (blockindex->nBits >> 24) & 0xff;
double dDiff =
@@ -83,15 +79,22 @@ double GetDifficulty(const CBlockIndex* blockindex)
return dDiff;
}
-UniValue blockheaderToJSON(const CBlockIndex* blockindex)
+static int ComputeNextBlockAndDepth(const CBlockIndex* tip, const CBlockIndex* blockindex, const CBlockIndex*& next)
+{
+ next = tip->GetAncestor(blockindex->nHeight + 1);
+ if (next && next->pprev == blockindex) {
+ return tip->nHeight - blockindex->nHeight + 1;
+ }
+ next = nullptr;
+ return blockindex == tip ? 1 : -1;
+}
+
+UniValue blockheaderToJSON(const CBlockIndex* tip, const CBlockIndex* blockindex)
{
- AssertLockHeld(cs_main);
UniValue result(UniValue::VOBJ);
result.pushKV("hash", blockindex->GetBlockHash().GetHex());
- int confirmations = -1;
- // Only report confirmations if the block is on the main chain
- if (chainActive.Contains(blockindex))
- confirmations = chainActive.Height() - blockindex->nHeight + 1;
+ const CBlockIndex* pnext;
+ int confirmations = ComputeNextBlockAndDepth(tip, blockindex, pnext);
result.pushKV("confirmations", confirmations);
result.pushKV("height", blockindex->nHeight);
result.pushKV("version", blockindex->nVersion);
@@ -107,21 +110,17 @@ UniValue blockheaderToJSON(const CBlockIndex* blockindex)
if (blockindex->pprev)
result.pushKV("previousblockhash", blockindex->pprev->GetBlockHash().GetHex());
- CBlockIndex *pnext = chainActive.Next(blockindex);
if (pnext)
result.pushKV("nextblockhash", pnext->GetBlockHash().GetHex());
return result;
}
-UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails)
+UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, bool txDetails)
{
- AssertLockHeld(cs_main);
UniValue result(UniValue::VOBJ);
result.pushKV("hash", blockindex->GetBlockHash().GetHex());
- int confirmations = -1;
- // Only report confirmations if the block is on the main chain
- if (chainActive.Contains(blockindex))
- confirmations = chainActive.Height() - blockindex->nHeight + 1;
+ const CBlockIndex* pnext;
+ int confirmations = ComputeNextBlockAndDepth(tip, blockindex, pnext);
result.pushKV("confirmations", confirmations);
result.pushKV("strippedsize", (int)::GetSerializeSize(block, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS));
result.pushKV("size", (int)::GetSerializeSize(block, PROTOCOL_VERSION));
@@ -153,7 +152,6 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx
if (blockindex->pprev)
result.pushKV("previousblockhash", blockindex->pprev->GetBlockHash().GetHex());
- CBlockIndex *pnext = chainActive.Next(blockindex);
if (pnext)
result.pushKV("nextblockhash", pnext->GetBlockHash().GetHex());
return result;
@@ -163,8 +161,9 @@ static UniValue getblockcount(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
throw std::runtime_error(
- "getblockcount\n"
- "\nReturns the number of blocks in the longest blockchain.\n"
+ RPCHelpMan{"getblockcount",
+ "\nReturns the number of blocks in the longest blockchain.\n", {}}
+ .ToString() +
"\nResult:\n"
"n (numeric) The current block count\n"
"\nExamples:\n"
@@ -180,8 +179,9 @@ static UniValue getbestblockhash(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
throw std::runtime_error(
- "getbestblockhash\n"
- "\nReturns the hash of the best (tip) block in the longest blockchain.\n"
+ RPCHelpMan{"getbestblockhash",
+ "\nReturns the hash of the best (tip) block in the longest blockchain.\n", {}}
+ .ToString() +
"\nResult:\n"
"\"hex\" (string) the block hash, hex-encoded\n"
"\nExamples:\n"
@@ -207,11 +207,13 @@ static UniValue waitfornewblock(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() > 1)
throw std::runtime_error(
- "waitfornewblock (timeout)\n"
- "\nWaits for a specific new block and returns useful info about it.\n"
- "\nReturns the current block on timeout or exit.\n"
- "\nArguments:\n"
- "1. timeout (int, optional, default=0) Time in milliseconds to wait for a response. 0 indicates no timeout.\n"
+ RPCHelpMan{"waitfornewblock",
+ "\nWaits for a specific new block and returns useful info about it.\n"
+ "\nReturns the current block on timeout or exit.\n",
+ {
+ {"timeout", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "0", "Time in milliseconds to wait for a response. 0 indicates no timeout."},
+ }}
+ .ToString() +
"\nResult:\n"
"{ (json object)\n"
" \"hash\" : { (string) The blockhash\n"
@@ -245,12 +247,14 @@ static UniValue waitforblock(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
throw std::runtime_error(
- "waitforblock <blockhash> (timeout)\n"
- "\nWaits for a specific new block and returns useful info about it.\n"
- "\nReturns the current block on timeout or exit.\n"
- "\nArguments:\n"
- "1. \"blockhash\" (required, string) Block hash to wait for.\n"
- "2. timeout (int, optional, default=0) Time in milliseconds to wait for a response. 0 indicates no timeout.\n"
+ RPCHelpMan{"waitforblock",
+ "\nWaits for a specific new block and returns useful info about it.\n"
+ "\nReturns the current block on timeout or exit.\n",
+ {
+ {"blockhash", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "Block hash to wait for."},
+ {"timeout", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "0", "Time in milliseconds to wait for a response. 0 indicates no timeout."},
+ }}
+ .ToString() +
"\nResult:\n"
"{ (json object)\n"
" \"hash\" : { (string) The blockhash\n"
@@ -287,13 +291,15 @@ static UniValue waitforblockheight(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
throw std::runtime_error(
- "waitforblockheight <height> (timeout)\n"
- "\nWaits for (at least) block height and returns the height and hash\n"
- "of the current tip.\n"
- "\nReturns the current block on timeout or exit.\n"
- "\nArguments:\n"
- "1. height (required, int) Block height to wait for (int)\n"
- "2. timeout (int, optional, default=0) Time in milliseconds to wait for a response. 0 indicates no timeout.\n"
+ RPCHelpMan{"waitforblockheight",
+ "\nWaits for (at least) block height and returns the height and hash\n"
+ "of the current tip.\n"
+ "\nReturns the current block on timeout or exit.\n",
+ {
+ {"height", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "Block height to wait for."},
+ {"timeout", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "0", "Time in milliseconds to wait for a response. 0 indicates no timeout."},
+ }}
+ .ToString() +
"\nResult:\n"
"{ (json object)\n"
" \"hash\" : { (string) The blockhash\n"
@@ -329,8 +335,9 @@ static UniValue syncwithvalidationinterfacequeue(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() > 0) {
throw std::runtime_error(
- "syncwithvalidationinterfacequeue\n"
- "\nWaits for the validation interface queue to catch up on everything that was there when we entered this function.\n"
+ RPCHelpMan{"syncwithvalidationinterfacequeue",
+ "\nWaits for the validation interface queue to catch up on everything that was there when we entered this function.\n", {}}
+ .ToString() +
"\nExamples:\n"
+ HelpExampleCli("syncwithvalidationinterfacequeue","")
+ HelpExampleRpc("syncwithvalidationinterfacequeue","")
@@ -344,8 +351,9 @@ static UniValue getdifficulty(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
throw std::runtime_error(
- "getdifficulty\n"
- "\nReturns the proof-of-work difficulty as a multiple of the minimum difficulty.\n"
+ RPCHelpMan{"getdifficulty",
+ "\nReturns the proof-of-work difficulty as a multiple of the minimum difficulty.\n", {}}
+ .ToString() +
"\nResult:\n"
"n.nnn (numeric) the proof-of-work difficulty as a multiple of the minimum difficulty.\n"
"\nExamples:\n"
@@ -478,11 +486,13 @@ static UniValue getrawmempool(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() > 1)
throw std::runtime_error(
- "getrawmempool ( verbose )\n"
- "\nReturns all transaction ids in memory pool as a json array of string transaction ids.\n"
- "\nHint: use getmempoolentry to fetch a specific transaction from the mempool.\n"
- "\nArguments:\n"
- "1. verbose (boolean, optional, default=false) True for a json object, false for array of transaction ids\n"
+ RPCHelpMan{"getrawmempool",
+ "\nReturns all transaction ids in memory pool as a json array of string transaction ids.\n"
+ "\nHint: use getmempoolentry to fetch a specific transaction from the mempool.\n",
+ {
+ {"verbose", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "True for a json object, false for array of transaction ids"},
+ }}
+ .ToString() +
"\nResult: (for verbose = false):\n"
"[ (json array of string)\n"
" \"transactionid\" (string) The transaction id\n"
@@ -510,11 +520,13 @@ static UniValue getmempoolancestors(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) {
throw std::runtime_error(
- "getmempoolancestors txid ( verbose )\n"
- "\nIf txid is in the mempool, returns all in-mempool ancestors.\n"
- "\nArguments:\n"
- "1. \"txid\" (string, required) The transaction id (must be in mempool)\n"
- "2. verbose (boolean, optional, default=false) True for a json object, false for array of transaction ids\n"
+ RPCHelpMan{"getmempoolancestors",
+ "\nIf txid is in the mempool, returns all in-mempool ancestors.\n",
+ {
+ {"txid", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The transaction id (must be in mempool)"},
+ {"verbose", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "True for a json object, false for array of transaction ids"},
+ }}
+ .ToString() +
"\nResult (for verbose = false):\n"
"[ (json array of strings)\n"
" \"transactionid\" (string) The transaction id of an in-mempool ancestor transaction\n"
@@ -574,11 +586,13 @@ static UniValue getmempooldescendants(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) {
throw std::runtime_error(
- "getmempooldescendants txid ( verbose )\n"
- "\nIf txid is in the mempool, returns all in-mempool descendants.\n"
- "\nArguments:\n"
- "1. \"txid\" (string, required) The transaction id (must be in mempool)\n"
- "2. verbose (boolean, optional, default=false) True for a json object, false for array of transaction ids\n"
+ RPCHelpMan{"getmempooldescendants",
+ "\nIf txid is in the mempool, returns all in-mempool descendants.\n",
+ {
+ {"txid", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The transaction id (must be in mempool)"},
+ {"verbose", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "True for a json object, false for array of transaction ids"},
+ }}
+ .ToString() +
"\nResult (for verbose = false):\n"
"[ (json array of strings)\n"
" \"transactionid\" (string) The transaction id of an in-mempool descendant transaction\n"
@@ -638,10 +652,12 @@ static UniValue getmempoolentry(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1) {
throw std::runtime_error(
- "getmempoolentry txid\n"
- "\nReturns mempool data for given transaction\n"
- "\nArguments:\n"
- "1. \"txid\" (string, required) The transaction id (must be in mempool)\n"
+ RPCHelpMan{"getmempoolentry",
+ "\nReturns mempool data for given transaction\n",
+ {
+ {"txid", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The transaction id (must be in mempool)"},
+ }}
+ .ToString() +
"\nResult:\n"
"{ (json object)\n"
+ EntryDescriptionString()
@@ -671,10 +687,12 @@ static UniValue getblockhash(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1)
throw std::runtime_error(
- "getblockhash height\n"
- "\nReturns hash of block in best-block-chain at height provided.\n"
- "\nArguments:\n"
- "1. height (numeric, required) The height index\n"
+ RPCHelpMan{"getblockhash",
+ "\nReturns hash of block in best-block-chain at height provided.\n",
+ {
+ {"height", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "The height index"},
+ }}
+ .ToString() +
"\nResult:\n"
"\"hash\" (string) The block hash\n"
"\nExamples:\n"
@@ -696,12 +714,14 @@ static UniValue getblockheader(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
throw std::runtime_error(
- "getblockheader \"hash\" ( verbose )\n"
- "\nIf verbose is false, returns a string that is serialized, hex-encoded data for blockheader 'hash'.\n"
- "If verbose is true, returns an Object with information about blockheader <hash>.\n"
- "\nArguments:\n"
- "1. \"hash\" (string, required) The block hash\n"
- "2. verbose (boolean, optional, default=true) true for a json object, false for the hex-encoded data\n"
+ RPCHelpMan{"getblockheader",
+ "\nIf verbose is false, returns a string that is serialized, hex-encoded data for blockheader 'hash'.\n"
+ "If verbose is true, returns an Object with information about blockheader <hash>.\n",
+ {
+ {"blockhash", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The block hash"},
+ {"verbose", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "true", "true for a json object, false for the hex-encoded data"},
+ }}
+ .ToString() +
"\nResult (for verbose = true):\n"
"{\n"
" \"hash\" : \"hash\", (string) the block hash (same as provided)\n"
@@ -727,15 +747,20 @@ static UniValue getblockheader(const JSONRPCRequest& request)
+ HelpExampleRpc("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
);
- LOCK(cs_main);
-
uint256 hash(ParseHashV(request.params[0], "hash"));
bool fVerbose = true;
if (!request.params[1].isNull())
fVerbose = request.params[1].get_bool();
- const CBlockIndex* pblockindex = LookupBlockIndex(hash);
+ const CBlockIndex* pblockindex;
+ const CBlockIndex* tip;
+ {
+ LOCK(cs_main);
+ pblockindex = LookupBlockIndex(hash);
+ tip = chainActive.Tip();
+ }
+
if (!pblockindex) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
}
@@ -748,7 +773,7 @@ static UniValue getblockheader(const JSONRPCRequest& request)
return strHex;
}
- return blockheaderToJSON(pblockindex);
+ return blockheaderToJSON(tip, pblockindex);
}
static CBlock GetBlockChecked(const CBlockIndex* pblockindex)
@@ -774,13 +799,15 @@ static UniValue getblock(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
throw std::runtime_error(
- "getblock \"blockhash\" ( verbosity ) \n"
- "\nIf verbosity is 0, returns a string that is serialized, hex-encoded data for block 'hash'.\n"
- "If verbosity is 1, returns an Object with information about block <hash>.\n"
- "If verbosity is 2, returns an Object with information about block <hash> and information about each transaction. \n"
- "\nArguments:\n"
- "1. \"blockhash\" (string, required) The block hash\n"
- "2. verbosity (numeric, optional, default=1) 0 for hex-encoded data, 1 for a json object, and 2 for json object with transaction data\n"
+ RPCHelpMan{"getblock",
+ "\nIf verbosity is 0, returns a string that is serialized, hex-encoded data for block 'hash'.\n"
+ "If verbosity is 1, returns an Object with information about block <hash>.\n"
+ "If verbosity is 2, returns an Object with information about block <hash> and information about each transaction. \n",
+ {
+ {"blockhash", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The block hash"},
+ {"verbosity", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "1", "0 for hex-encoded data, 1 for a json object, and 2 for json object with transaction data"},
+ }}
+ .ToString() +
"\nResult (for verbosity = 0):\n"
"\"data\" (string) A string that is serialized, hex-encoded data for block 'hash'.\n"
"\nResult (for verbosity = 1):\n"
@@ -848,7 +875,7 @@ static UniValue getblock(const JSONRPCRequest& request)
return strHex;
}
- return blockToJSON(block, pblockindex, verbosity >= 2);
+ return blockToJSON(block, chainActive.Tip(), pblockindex, verbosity >= 2);
}
struct CCoinsStats
@@ -926,10 +953,12 @@ static UniValue pruneblockchain(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1)
throw std::runtime_error(
- "pruneblockchain\n"
- "\nArguments:\n"
- "1. \"height\" (numeric, required) The block height to prune up to. May be set to a discrete height, or a unix timestamp\n"
- " to prune blocks whose block time is at least 2 hours older than the provided timestamp.\n"
+ RPCHelpMan{"pruneblockchain", "",
+ {
+ {"height", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "The block height to prune up to. May be set to a discrete height, or a unix timestamp\n"
+ " to prune blocks whose block time is at least 2 hours older than the provided timestamp."},
+ }}
+ .ToString() +
"\nResult:\n"
"n (numeric) Height of the last block pruned.\n"
"\nExamples:\n"
@@ -975,9 +1004,11 @@ static UniValue gettxoutsetinfo(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
throw std::runtime_error(
- "gettxoutsetinfo\n"
- "\nReturns statistics about the unspent transaction output set.\n"
- "Note this call may take some time.\n"
+ RPCHelpMan{"gettxoutsetinfo",
+ "\nReturns statistics about the unspent transaction output set.\n"
+ "Note this call may take some time.\n",
+ {}}
+ .ToString() +
"\nResult:\n"
"{\n"
" \"height\":n, (numeric) The current block height (index)\n"
@@ -1017,13 +1048,14 @@ UniValue gettxout(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() < 2 || request.params.size() > 3)
throw std::runtime_error(
- "gettxout \"txid\" n ( include_mempool )\n"
- "\nReturns details about an unspent transaction output.\n"
- "\nArguments:\n"
- "1. \"txid\" (string, required) The transaction id\n"
- "2. \"n\" (numeric, required) vout number\n"
- "3. \"include_mempool\" (boolean, optional) Whether to include the mempool. Default: true."
- " Note that an unspent output that is spent in the mempool won't appear.\n"
+ RPCHelpMan{"gettxout",
+ "\nReturns details about an unspent transaction output.\n",
+ {
+ {"txid", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The transaction id"},
+ {"n", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "vout number"},
+ {"include_mempool", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "true", "Whether to include the mempool. Note that an unspent output that is spent in the mempool won't appear."},
+ }}
+ .ToString() +
"\nResult:\n"
"{\n"
" \"bestblock\": \"hash\", (string) The hash of the block at the tip of the chain\n"
@@ -1097,11 +1129,13 @@ static UniValue verifychain(const JSONRPCRequest& request)
int nCheckDepth = gArgs.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS);
if (request.fHelp || request.params.size() > 2)
throw std::runtime_error(
- "verifychain ( checklevel nblocks )\n"
- "\nVerifies blockchain database.\n"
- "\nArguments:\n"
- "1. checklevel (numeric, optional, 0-4, default=" + strprintf("%d", nCheckLevel) + ") How thorough the block verification is.\n"
- "2. nblocks (numeric, optional, default=" + strprintf("%d", nCheckDepth) + ", 0=all) The number of blocks to check.\n"
+ RPCHelpMan{"verifychain",
+ "\nVerifies blockchain database.\n",
+ {
+ {"checklevel", RPCArg::Type::NUM, /* opt */ true, /* default_val */ strprintf("%d, range=0-4", nCheckLevel), "How thorough the block verification is."},
+ {"nblocks", RPCArg::Type::NUM, /* opt */ true, /* default_val */ strprintf("%d, 0=all", nCheckDepth), "The number of blocks to check."},
+ }}
+ .ToString() +
"\nResult:\n"
"true|false (boolean) Verified or not\n"
"\nExamples:\n"
@@ -1120,7 +1154,7 @@ static UniValue verifychain(const JSONRPCRequest& request)
}
/** Implementation of IsSuperMajority with better feedback */
-static UniValue SoftForkMajorityDesc(int version, CBlockIndex* pindex, const Consensus::Params& consensusParams)
+static UniValue SoftForkMajorityDesc(int version, const CBlockIndex* pindex, const Consensus::Params& consensusParams)
{
UniValue rv(UniValue::VOBJ);
bool activated = false;
@@ -1140,7 +1174,7 @@ static UniValue SoftForkMajorityDesc(int version, CBlockIndex* pindex, const Con
return rv;
}
-static UniValue SoftForkDesc(const std::string &name, int version, CBlockIndex* pindex, const Consensus::Params& consensusParams)
+static UniValue SoftForkDesc(const std::string &name, int version, const CBlockIndex* pindex, const Consensus::Params& consensusParams)
{
UniValue rv(UniValue::VOBJ);
rv.pushKV("id", name);
@@ -1194,8 +1228,9 @@ UniValue getblockchaininfo(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
throw std::runtime_error(
- "getblockchaininfo\n"
- "Returns an object containing various state info regarding blockchain processing.\n"
+ RPCHelpMan{"getblockchaininfo",
+ "Returns an object containing various state info regarding blockchain processing.\n", {}}
+ .ToString() +
"\nResult:\n"
"{\n"
" \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n"
@@ -1246,20 +1281,21 @@ UniValue getblockchaininfo(const JSONRPCRequest& request)
LOCK(cs_main);
+ const CBlockIndex* tip = chainActive.Tip();
UniValue obj(UniValue::VOBJ);
obj.pushKV("chain", Params().NetworkIDString());
obj.pushKV("blocks", (int)chainActive.Height());
obj.pushKV("headers", pindexBestHeader ? pindexBestHeader->nHeight : -1);
- obj.pushKV("bestblockhash", chainActive.Tip()->GetBlockHash().GetHex());
- obj.pushKV("difficulty", (double)GetDifficulty(chainActive.Tip()));
- obj.pushKV("mediantime", (int64_t)chainActive.Tip()->GetMedianTimePast());
- obj.pushKV("verificationprogress", GuessVerificationProgress(Params().TxData(), chainActive.Tip()));
+ obj.pushKV("bestblockhash", tip->GetBlockHash().GetHex());
+ obj.pushKV("difficulty", (double)GetDifficulty(tip));
+ obj.pushKV("mediantime", (int64_t)tip->GetMedianTimePast());
+ obj.pushKV("verificationprogress", GuessVerificationProgress(Params().TxData(), tip));
obj.pushKV("initialblockdownload", IsInitialBlockDownload());
- obj.pushKV("chainwork", chainActive.Tip()->nChainWork.GetHex());
+ obj.pushKV("chainwork", tip->nChainWork.GetHex());
obj.pushKV("size_on_disk", CalculateCurrentUsage());
obj.pushKV("pruned", fPruneMode);
if (fPruneMode) {
- CBlockIndex* block = chainActive.Tip();
+ const CBlockIndex* block = tip;
assert(block);
while (block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA)) {
block = block->pprev;
@@ -1276,7 +1312,6 @@ UniValue getblockchaininfo(const JSONRPCRequest& request)
}
const Consensus::Params& consensusParams = Params().GetConsensus();
- CBlockIndex* tip = chainActive.Tip();
UniValue softforks(UniValue::VARR);
UniValue bip9_softforks(UniValue::VOBJ);
softforks.push_back(SoftForkDesc("bip34", 2, tip, consensusParams));
@@ -1311,9 +1346,11 @@ static UniValue getchaintips(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
throw std::runtime_error(
- "getchaintips\n"
- "Return information about all known tips in the block tree,"
- " including the main chain as well as orphaned branches.\n"
+ RPCHelpMan{"getchaintips",
+ "Return information about all known tips in the block tree,"
+ " including the main chain as well as orphaned branches.\n",
+ {}}
+ .ToString() +
"\nResult:\n"
"[\n"
" {\n"
@@ -1389,7 +1426,7 @@ static UniValue getchaintips(const JSONRPCRequest& request)
} else if (block->nStatus & BLOCK_FAILED_MASK) {
// This block or one of its ancestors is invalid.
status = "invalid";
- } else if (block->nChainTx == 0) {
+ } else if (!block->HaveTxsDownloaded()) {
// This block cannot be connected because full block data for it or one of its parents is missing.
status = "headers-only";
} else if (block->IsValid(BLOCK_VALID_SCRIPTS)) {
@@ -1428,8 +1465,9 @@ static UniValue getmempoolinfo(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
throw std::runtime_error(
- "getmempoolinfo\n"
- "\nReturns details on the active state of the TX memory pool.\n"
+ RPCHelpMan{"getmempoolinfo",
+ "\nReturns details on the active state of the TX memory pool.\n", {}}
+ .ToString() +
"\nResult:\n"
"{\n"
" \"size\": xxxxx, (numeric) Current tx count\n"
@@ -1451,12 +1489,14 @@ static UniValue preciousblock(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1)
throw std::runtime_error(
- "preciousblock \"blockhash\"\n"
- "\nTreats a block as if it were received before others with the same work.\n"
- "\nA later preciousblock call can override the effect of an earlier one.\n"
- "\nThe effects of preciousblock are not retained across restarts.\n"
- "\nArguments:\n"
- "1. \"blockhash\" (string, required) the hash of the block to mark as precious\n"
+ RPCHelpMan{"preciousblock",
+ "\nTreats a block as if it were received before others with the same work.\n"
+ "\nA later preciousblock call can override the effect of an earlier one.\n"
+ "\nThe effects of preciousblock are not retained across restarts.\n",
+ {
+ {"blockhash", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "the hash of the block to mark as precious"},
+ }}
+ .ToString() +
"\nResult:\n"
"\nExamples:\n"
+ HelpExampleCli("preciousblock", "\"blockhash\"")
@@ -1488,10 +1528,12 @@ static UniValue invalidateblock(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1)
throw std::runtime_error(
- "invalidateblock \"blockhash\"\n"
- "\nPermanently marks a block as invalid, as if it violated a consensus rule.\n"
- "\nArguments:\n"
- "1. \"blockhash\" (string, required) the hash of the block to mark as invalid\n"
+ RPCHelpMan{"invalidateblock",
+ "\nPermanently marks a block as invalid, as if it violated a consensus rule.\n",
+ {
+ {"blockhash", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "the hash of the block to mark as invalid"},
+ }}
+ .ToString() +
"\nResult:\n"
"\nExamples:\n"
+ HelpExampleCli("invalidateblock", "\"blockhash\"")
@@ -1526,11 +1568,13 @@ static UniValue reconsiderblock(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1)
throw std::runtime_error(
- "reconsiderblock \"blockhash\"\n"
- "\nRemoves invalidity status of a block and its descendants, reconsider them for activation.\n"
- "This can be used to undo the effects of invalidateblock.\n"
- "\nArguments:\n"
- "1. \"blockhash\" (string, required) the hash of the block to reconsider\n"
+ RPCHelpMan{"reconsiderblock",
+ "\nRemoves invalidity status of a block, its ancestors and its descendants, reconsider them for activation.\n"
+ "This can be used to undo the effects of invalidateblock.\n",
+ {
+ {"blockhash", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "the hash of the block to reconsider"},
+ }}
+ .ToString() +
"\nResult:\n"
"\nExamples:\n"
+ HelpExampleCli("reconsiderblock", "\"blockhash\"")
@@ -1563,11 +1607,13 @@ static UniValue getchaintxstats(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() > 2)
throw std::runtime_error(
- "getchaintxstats ( nblocks blockhash )\n"
- "\nCompute statistics about the total number and rate of transactions in the chain.\n"
- "\nArguments:\n"
- "1. nblocks (numeric, optional) Size of the window in number of blocks (default: one month).\n"
- "2. \"blockhash\" (string, optional) The hash of the block that ends the window.\n"
+ RPCHelpMan{"getchaintxstats",
+ "\nCompute statistics about the total number and rate of transactions in the chain.\n",
+ {
+ {"nblocks", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "one month", "Size of the window in number of blocks"},
+ {"blockhash", RPCArg::Type::STR_HEX, /* opt */ true, /* default_val */ "chain tip", "The hash of the block that ends the window."},
+ }}
+ .ToString() +
"\nResult:\n"
"{\n"
" \"time\": xxxxx, (numeric) The timestamp for the final block in the window in UNIX format.\n"
@@ -1693,18 +1739,20 @@ static UniValue getblockstats(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() < 1 || request.params.size() > 4) {
throw std::runtime_error(
- "getblockstats hash_or_height ( stats )\n"
- "\nCompute per block statistics for a given window. All amounts are in satoshis.\n"
- "It won't work for some heights with pruning.\n"
- "It won't work without -txindex for utxo_size_inc, *fee or *feerate stats.\n"
- "\nArguments:\n"
- "1. \"hash_or_height\" (string or numeric, required) The block hash or height of the target block\n"
- "2. \"stats\" (array, optional) Values to plot, by default all values (see result below)\n"
- " [\n"
- " \"height\", (string, optional) Selected statistic\n"
- " \"time\", (string, optional) Selected statistic\n"
- " ,...\n"
- " ]\n"
+ RPCHelpMan{"getblockstats",
+ "\nCompute per block statistics for a given window. All amounts are in satoshis.\n"
+ "It won't work for some heights with pruning.\n"
+ "It won't work without -txindex for utxo_size_inc, *fee or *feerate stats.\n",
+ {
+ {"hash_or_height", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "The block hash or height of the target block", "", {"", "string or numeric"}},
+ {"stats", RPCArg::Type::ARR, /* opt */ true, /* default_val */ "all values", "Values to plot (see result below)",
+ {
+ {"height", RPCArg::Type::STR, /* opt */ true, /* default_val */ "", "Selected statistic"},
+ {"time", RPCArg::Type::STR, /* opt */ true, /* default_val */ "", "Selected statistic"},
+ },
+ "stats"},
+ }}
+ .ToString() +
"\nResult:\n"
"{ (json object)\n"
" \"avgfee\": xxxxx, (numeric) Average fee in the block\n"
@@ -1957,8 +2005,9 @@ static UniValue savemempool(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0) {
throw std::runtime_error(
- "savemempool\n"
- "\nDumps the mempool to disk. It will fail until the previous dump is fully loaded.\n"
+ RPCHelpMan{"savemempool",
+ "\nDumps the mempool to disk. It will fail until the previous dump is fully loaded.\n", {}}
+ .ToString() +
"\nExamples:\n"
+ HelpExampleCli("savemempool", "")
+ HelpExampleRpc("savemempool", "")
@@ -2040,34 +2089,39 @@ UniValue scantxoutset(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
throw std::runtime_error(
- "scantxoutset <action> ( <scanobjects> )\n"
- "\nEXPERIMENTAL warning: this call may be removed or changed in future releases.\n"
- "\nScans the unspent transaction output set for entries that match certain output descriptors.\n"
- "Examples of output descriptors are:\n"
- " addr(<address>) Outputs whose scriptPubKey corresponds to the specified address (does not include P2PK)\n"
- " raw(<hex script>) Outputs whose scriptPubKey equals the specified hex scripts\n"
- " combo(<pubkey>) P2PK, P2PKH, P2WPKH, and P2SH-P2WPKH outputs for the given pubkey\n"
- " pkh(<pubkey>) P2PKH outputs for the given pubkey\n"
- " sh(multi(<n>,<pubkey>,<pubkey>,...)) P2SH-multisig outputs for the given threshold and pubkeys\n"
- "\nIn the above, <pubkey> either refers to a fixed public key in hexadecimal notation, or to an xpub/xprv optionally followed by one\n"
- "or more path elements separated by \"/\", and optionally ending in \"/*\" (unhardened), or \"/*'\" or \"/*h\" (hardened) to specify all\n"
- "unhardened or hardened child keys.\n"
- "In the latter case, a range needs to be specified by below if different from 1000.\n"
- "For more information on output descriptors, see the documentation in the doc/descriptors.md file.\n"
- "\nArguments:\n"
- "1. \"action\" (string, required) The action to execute\n"
+ RPCHelpMan{"scantxoutset",
+ "\nEXPERIMENTAL warning: this call may be removed or changed in future releases.\n"
+ "\nScans the unspent transaction output set for entries that match certain output descriptors.\n"
+ "Examples of output descriptors are:\n"
+ " addr(<address>) Outputs whose scriptPubKey corresponds to the specified address (does not include P2PK)\n"
+ " raw(<hex script>) Outputs whose scriptPubKey equals the specified hex scripts\n"
+ " combo(<pubkey>) P2PK, P2PKH, P2WPKH, and P2SH-P2WPKH outputs for the given pubkey\n"
+ " pkh(<pubkey>) P2PKH outputs for the given pubkey\n"
+ " sh(multi(<n>,<pubkey>,<pubkey>,...)) P2SH-multisig outputs for the given threshold and pubkeys\n"
+ "\nIn the above, <pubkey> either refers to a fixed public key in hexadecimal notation, or to an xpub/xprv optionally followed by one\n"
+ "or more path elements separated by \"/\", and optionally ending in \"/*\" (unhardened), or \"/*'\" or \"/*h\" (hardened) to specify all\n"
+ "unhardened or hardened child keys.\n"
+ "In the latter case, a range needs to be specified by below if different from 1000.\n"
+ "For more information on output descriptors, see the documentation in the doc/descriptors.md file.\n",
+ {
+ {"action", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The action to execute\n"
" \"start\" for starting a scan\n"
" \"abort\" for aborting the current scan (returns true when abort was successful)\n"
- " \"status\" for progress report (in %) of the current scan\n"
- "2. \"scanobjects\" (array, required) Array of scan objects\n"
- " [ Every scan object is either a string descriptor or an object:\n"
- " \"descriptor\", (string, optional) An output descriptor\n"
- " { (object, optional) An object with output descriptor and metadata\n"
- " \"desc\": \"descriptor\", (string, required) An output descriptor\n"
- " \"range\": n, (numeric, optional) Up to what child index HD chains should be explored (default: 1000)\n"
- " },\n"
- " ...\n"
- " ]\n"
+ " \"status\" for progress report (in %) of the current scan"},
+ {"scanobjects", RPCArg::Type::ARR, /* opt */ false, /* default_val */ "", "Array of scan objects\n"
+ " Every scan object is either a string descriptor or an object:",
+ {
+ {"descriptor", RPCArg::Type::STR, /* opt */ true, /* default_val */ "", "An output descriptor"},
+ {"", RPCArg::Type::OBJ, /* opt */ true, /* default_val */ "", "An object with output descriptor and metadata",
+ {
+ {"desc", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "An output descriptor"},
+ {"range", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "1000", "Up to what child index HD chains should be explored"},
+ },
+ },
+ },
+ "[scanobjects,...]"},
+ }}
+ .ToString() +
"\nResult:\n"
"{\n"
" \"unspents\": [\n"
@@ -2075,6 +2129,7 @@ UniValue scantxoutset(const JSONRPCRequest& request)
" \"txid\" : \"transactionid\", (string) The transaction id\n"
" \"vout\": n, (numeric) the vout value\n"
" \"scriptPubKey\" : \"script\", (string) the script key\n"
+ " \"desc\" : \"descriptor\", (string) A specialized descriptor for the matched scriptPubKey\n"
" \"amount\" : x.xxx, (numeric) The total amount in " + CURRENCY_UNIT + " of the unspent output\n"
" \"height\" : n, (numeric) Height of the unspent transaction output\n"
" }\n"
@@ -2109,6 +2164,7 @@ UniValue scantxoutset(const JSONRPCRequest& request)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Scan already in progress, use action \"abort\" or \"status\"");
}
std::set<CScript> needles;
+ std::map<CScript, std::string> descriptors;
CAmount total_in = 0;
// loop through the scan objects
@@ -2141,7 +2197,11 @@ UniValue scantxoutset(const JSONRPCRequest& request)
if (!desc->Expand(i, provider, scripts, provider)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Cannot derive script without private keys: '%s'", desc_str));
}
- needles.insert(scripts.begin(), scripts.end());
+ for (const auto& script : scripts) {
+ std::string inferred = InferDescriptor(script, provider)->ToString();
+ needles.emplace(script);
+ descriptors.emplace(std::move(script), std::move(inferred));
+ }
}
}
@@ -2174,6 +2234,7 @@ UniValue scantxoutset(const JSONRPCRequest& request)
unspent.pushKV("txid", outpoint.hash.GetHex());
unspent.pushKV("vout", (int32_t)outpoint.n);
unspent.pushKV("scriptPubKey", HexStr(txo.scriptPubKey.begin(), txo.scriptPubKey.end()));
+ unspent.pushKV("desc", descriptors[txo.scriptPubKey]);
unspent.pushKV("amount", ValueFromAmount(txo.nValue));
unspent.pushKV("height", (int32_t)coin.nHeight);