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.cpp795
1 files changed, 438 insertions, 357 deletions
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index e3d9357358..672fc69673 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Copyright (c) 2009-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -7,13 +7,14 @@
#include <amount.h>
#include <base58.h>
+#include <blockfilter.h>
#include <chain.h>
#include <chainparams.h>
-#include <checkpoints.h>
#include <coins.h>
#include <consensus/validation.h>
#include <core_io.h>
#include <hash.h>
+#include <index/blockfilterindex.h>
#include <index/txindex.h>
#include <key_io.h>
#include <policy/feerate.h>
@@ -29,6 +30,7 @@
#include <txmempool.h>
#include <util/strencodings.h>
#include <util/system.h>
+#include <util/validation.h>
#include <validation.h>
#include <validationinterface.h>
#include <versionbitsinfo.h>
@@ -59,10 +61,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 =
@@ -82,15 +81,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);
@@ -106,21 +112,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));
@@ -152,7 +154,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,14 +164,16 @@ static UniValue getblockcount(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() != 0)
throw std::runtime_error(
RPCHelpMan{"getblockcount",
- "\nReturns the number of blocks in the longest blockchain.\n", {}}
- .ToString() +
- "\nResult:\n"
+ "\nReturns the number of blocks in the longest blockchain.\n",
+ {},
+ RPCResult{
"n (numeric) The current block count\n"
- "\nExamples:\n"
- + HelpExampleCli("getblockcount", "")
+ },
+ RPCExamples{
+ HelpExampleCli("getblockcount", "")
+ HelpExampleRpc("getblockcount", "")
- );
+ },
+ }.ToString());
LOCK(cs_main);
return chainActive.Height();
@@ -181,14 +184,16 @@ static UniValue getbestblockhash(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() != 0)
throw std::runtime_error(
RPCHelpMan{"getbestblockhash",
- "\nReturns the hash of the best (tip) block in the longest blockchain.\n", {}}
- .ToString() +
- "\nResult:\n"
+ "\nReturns the hash of the best (tip) block in the longest blockchain.\n",
+ {},
+ RPCResult{
"\"hex\" (string) the block hash, hex-encoded\n"
- "\nExamples:\n"
- + HelpExampleCli("getbestblockhash", "")
+ },
+ RPCExamples{
+ HelpExampleCli("getbestblockhash", "")
+ HelpExampleRpc("getbestblockhash", "")
- );
+ },
+ }.ToString());
LOCK(cs_main);
return chainActive.Tip()->GetBlockHash().GetHex();
@@ -212,20 +217,19 @@ static UniValue waitfornewblock(const JSONRPCRequest& request)
"\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, true},
- }}
- .ToString() +
- "\nArguments:\n"
- "1. timeout (int, optional, default=0) Time in milliseconds to wait for a response. 0 indicates no timeout.\n"
- "\nResult:\n"
+ {"timeout", RPCArg::Type::NUM, /* default */ "0", "Time in milliseconds to wait for a response. 0 indicates no timeout."},
+ },
+ RPCResult{
"{ (json object)\n"
" \"hash\" : { (string) The blockhash\n"
" \"height\" : { (int) Block height\n"
"}\n"
- "\nExamples:\n"
- + HelpExampleCli("waitfornewblock", "1000")
+ },
+ RPCExamples{
+ HelpExampleCli("waitfornewblock", "1000")
+ HelpExampleRpc("waitfornewblock", "1000")
- );
+ },
+ }.ToString());
int timeout = 0;
if (!request.params[0].isNull())
timeout = request.params[0].get_int();
@@ -254,22 +258,20 @@ static UniValue waitforblock(const JSONRPCRequest& request)
"\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, false},
- {"timeout", RPCArg::Type::NUM, true},
- }}
- .ToString() +
- "\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"
- "\nResult:\n"
+ {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "Block hash to wait for."},
+ {"timeout", RPCArg::Type::NUM, /* default */ "0", "Time in milliseconds to wait for a response. 0 indicates no timeout."},
+ },
+ RPCResult{
"{ (json object)\n"
" \"hash\" : { (string) The blockhash\n"
" \"height\" : { (int) Block height\n"
"}\n"
- "\nExamples:\n"
- + HelpExampleCli("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\", 1000")
+ },
+ RPCExamples{
+ HelpExampleCli("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\", 1000")
+ HelpExampleRpc("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\", 1000")
- );
+ },
+ }.ToString());
int timeout = 0;
uint256 hash(ParseHashV(request.params[0], "blockhash"));
@@ -302,22 +304,20 @@ static UniValue waitforblockheight(const JSONRPCRequest& request)
"of the current tip.\n"
"\nReturns the current block on timeout or exit.\n",
{
- {"height", RPCArg::Type::NUM, false},
- {"timeout", RPCArg::Type::NUM, true},
- }}
- .ToString() +
- "\nArguments:\n"
- "1. height (int, required) Block height to wait for.\n"
- "2. timeout (int, optional, default=0) Time in milliseconds to wait for a response. 0 indicates no timeout.\n"
- "\nResult:\n"
+ {"height", RPCArg::Type::NUM, RPCArg::Optional::NO, "Block height to wait for."},
+ {"timeout", RPCArg::Type::NUM, /* default */ "0", "Time in milliseconds to wait for a response. 0 indicates no timeout."},
+ },
+ RPCResult{
"{ (json object)\n"
" \"hash\" : { (string) The blockhash\n"
" \"height\" : { (int) Block height\n"
"}\n"
- "\nExamples:\n"
- + HelpExampleCli("waitforblockheight", "\"100\", 1000")
+ },
+ RPCExamples{
+ HelpExampleCli("waitforblockheight", "\"100\", 1000")
+ HelpExampleRpc("waitforblockheight", "\"100\", 1000")
- );
+ },
+ }.ToString());
int timeout = 0;
int height = request.params[0].get_int();
@@ -345,12 +345,14 @@ static UniValue syncwithvalidationinterfacequeue(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() > 0) {
throw std::runtime_error(
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","")
+ "\nWaits for the validation interface queue to catch up on everything that was there when we entered this function.\n",
+ {},
+ RPCResults{},
+ RPCExamples{
+ HelpExampleCli("syncwithvalidationinterfacequeue","")
+ HelpExampleRpc("syncwithvalidationinterfacequeue","")
- );
+ },
+ }.ToString());
}
SyncWithValidationInterfaceQueue();
return NullUniValue;
@@ -361,14 +363,16 @@ static UniValue getdifficulty(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() != 0)
throw std::runtime_error(
RPCHelpMan{"getdifficulty",
- "\nReturns the proof-of-work difficulty as a multiple of the minimum difficulty.\n", {}}
- .ToString() +
- "\nResult:\n"
+ "\nReturns the proof-of-work difficulty as a multiple of the minimum difficulty.\n",
+ {},
+ RPCResult{
"n.nnn (numeric) the proof-of-work difficulty as a multiple of the minimum difficulty.\n"
- "\nExamples:\n"
- + HelpExampleCli("getdifficulty", "")
+ },
+ RPCExamples{
+ HelpExampleCli("getdifficulty", "")
+ HelpExampleRpc("getdifficulty", "")
- );
+ },
+ }.ToString());
LOCK(cs_main);
return GetDifficulty(chainActive.Tip());
@@ -376,7 +380,9 @@ static UniValue getdifficulty(const JSONRPCRequest& request)
static std::string EntryDescriptionString()
{
- return " \"size\" : n, (numeric) virtual transaction size as defined in BIP 141. This is different from actual serialized size for witness transactions as witness data is discounted.\n"
+ return " \"vsize\" : n, (numeric) virtual transaction size as defined in BIP 141. This is different from actual serialized size for witness transactions as witness data is discounted.\n"
+ " \"size\" : n, (numeric) (DEPRECATED) same as vsize. Only returned if bitcoind is started with -deprecatedrpc=size\n"
+ " size will be completely removed in v0.20.\n"
" \"fee\" : n, (numeric) transaction fee in " + CURRENCY_UNIT + " (DEPRECATED)\n"
" \"modifiedfee\" : n, (numeric) transaction fee with fee deltas used for mining priority (DEPRECATED)\n"
" \"time\" : n, (numeric) local time transaction entered pool in seconds since 1 Jan 1970 GMT\n"
@@ -403,9 +409,9 @@ static std::string EntryDescriptionString()
" \"bip125-replaceable\" : true|false, (boolean) Whether this transaction could be replaced due to BIP125 (replace-by-fee)\n";
}
-static void entryToJSON(UniValue &info, const CTxMemPoolEntry &e) EXCLUSIVE_LOCKS_REQUIRED(::mempool.cs)
+static void entryToJSON(const CTxMemPool& pool, UniValue& info, const CTxMemPoolEntry& e) EXCLUSIVE_LOCKS_REQUIRED(pool.cs)
{
- AssertLockHeld(mempool.cs);
+ AssertLockHeld(pool.cs);
UniValue fees(UniValue::VOBJ);
fees.pushKV("base", ValueFromAmount(e.GetFee()));
@@ -414,7 +420,8 @@ static void entryToJSON(UniValue &info, const CTxMemPoolEntry &e) EXCLUSIVE_LOCK
fees.pushKV("descendant", ValueFromAmount(e.GetModFeesWithDescendants()));
info.pushKV("fees", fees);
- info.pushKV("size", (int)e.GetTxSize());
+ info.pushKV("vsize", (int)e.GetTxSize());
+ if (IsDeprecatedRPCEnabled("size")) info.pushKV("size", (int)e.GetTxSize());
info.pushKV("fee", ValueFromAmount(e.GetFee()));
info.pushKV("modifiedfee", ValueFromAmount(e.GetModifiedFee()));
info.pushKV("time", e.GetTime());
@@ -425,12 +432,12 @@ static void entryToJSON(UniValue &info, const CTxMemPoolEntry &e) EXCLUSIVE_LOCK
info.pushKV("ancestorcount", e.GetCountWithAncestors());
info.pushKV("ancestorsize", e.GetSizeWithAncestors());
info.pushKV("ancestorfees", e.GetModFeesWithAncestors());
- info.pushKV("wtxid", mempool.vTxHashes[e.vTxHashesIdx].first.ToString());
+ info.pushKV("wtxid", pool.vTxHashes[e.vTxHashesIdx].first.ToString());
const CTransaction& tx = e.GetTx();
std::set<std::string> setDepends;
for (const CTxIn& txin : tx.vin)
{
- if (mempool.exists(txin.prevout.hash))
+ if (pool.exists(txin.prevout.hash))
setDepends.insert(txin.prevout.hash.ToString());
}
@@ -443,8 +450,8 @@ static void entryToJSON(UniValue &info, const CTxMemPoolEntry &e) EXCLUSIVE_LOCK
info.pushKV("depends", depends);
UniValue spent(UniValue::VARR);
- const CTxMemPool::txiter &it = mempool.mapTx.find(tx.GetHash());
- const CTxMemPool::setEntries &setChildren = mempool.GetMemPoolChildren(it);
+ const CTxMemPool::txiter& it = pool.mapTx.find(tx.GetHash());
+ const CTxMemPool::setEntries& setChildren = pool.GetMemPoolChildren(it);
for (CTxMemPool::txiter childiter : setChildren) {
spent.push_back(childiter->GetTx().GetHash().ToString());
}
@@ -453,7 +460,7 @@ static void entryToJSON(UniValue &info, const CTxMemPoolEntry &e) EXCLUSIVE_LOCK
// Add opt-in RBF status
bool rbfStatus = false;
- RBFTransactionState rbfState = IsRBFOptIn(tx, mempool);
+ RBFTransactionState rbfState = IsRBFOptIn(tx, pool);
if (rbfState == RBFTransactionState::UNKNOWN) {
throw JSONRPCError(RPC_MISC_ERROR, "Transaction is not in mempool");
} else if (rbfState == RBFTransactionState::REPLACEABLE_BIP125) {
@@ -463,25 +470,21 @@ static void entryToJSON(UniValue &info, const CTxMemPoolEntry &e) EXCLUSIVE_LOCK
info.pushKV("bip125-replaceable", rbfStatus);
}
-UniValue mempoolToJSON(bool fVerbose)
+UniValue MempoolToJSON(const CTxMemPool& pool, bool verbose)
{
- if (fVerbose)
- {
- LOCK(mempool.cs);
+ if (verbose) {
+ LOCK(pool.cs);
UniValue o(UniValue::VOBJ);
- for (const CTxMemPoolEntry& e : mempool.mapTx)
- {
+ for (const CTxMemPoolEntry& e : pool.mapTx) {
const uint256& hash = e.GetTx().GetHash();
UniValue info(UniValue::VOBJ);
- entryToJSON(info, e);
+ entryToJSON(pool, info, e);
o.pushKV(hash.ToString(), info);
}
return o;
- }
- else
- {
+ } else {
std::vector<uint256> vtxid;
- mempool.queryHashes(vtxid);
+ pool.queryHashes(vtxid);
UniValue a(UniValue::VARR);
for (const uint256& hash : vtxid)
@@ -496,15 +499,12 @@ static UniValue getrawmempool(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() > 1)
throw std::runtime_error(
RPCHelpMan{"getrawmempool",
- "\nReturns all transaction ids in memory pool as a json array of string transaction ids.\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",
{
- {"verbose", RPCArg::Type::BOOL, true},
- }}
- .ToString() +
- "\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"
- "\nResult: (for verbose = false):\n"
+ {"verbose", RPCArg::Type::BOOL, /* default */ "false", "True for a json object, false for array of transaction ids"},
+ },
+ RPCResult{"for verbose = false",
"[ (json array of string)\n"
" \"transactionid\" (string) The transaction id\n"
" ,...\n"
@@ -515,16 +515,18 @@ static UniValue getrawmempool(const JSONRPCRequest& request)
+ EntryDescriptionString()
+ " }, ...\n"
"}\n"
- "\nExamples:\n"
- + HelpExampleCli("getrawmempool", "true")
+ },
+ RPCExamples{
+ HelpExampleCli("getrawmempool", "true")
+ HelpExampleRpc("getrawmempool", "true")
- );
+ },
+ }.ToString());
bool fVerbose = false;
if (!request.params[0].isNull())
fVerbose = request.params[0].get_bool();
- return mempoolToJSON(fVerbose);
+ return MempoolToJSON(::mempool, fVerbose);
}
static UniValue getmempoolancestors(const JSONRPCRequest& request)
@@ -534,28 +536,29 @@ static UniValue getmempoolancestors(const JSONRPCRequest& request)
RPCHelpMan{"getmempoolancestors",
"\nIf txid is in the mempool, returns all in-mempool ancestors.\n",
{
- {"txid", RPCArg::Type::STR_HEX, false},
- {"verbose", RPCArg::Type::BOOL, true},
- }}
- .ToString() +
- "\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"
- "\nResult (for verbose = false):\n"
+ {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id (must be in mempool)"},
+ {"verbose", RPCArg::Type::BOOL, /* default */ "false", "True for a json object, false for array of transaction ids"},
+ },
+ {
+ RPCResult{"for verbose = false",
"[ (json array of strings)\n"
" \"transactionid\" (string) The transaction id of an in-mempool ancestor transaction\n"
" ,...\n"
"]\n"
- "\nResult (for verbose = true):\n"
+ },
+ RPCResult{"for verbose = true",
"{ (json object)\n"
" \"transactionid\" : { (json object)\n"
+ EntryDescriptionString()
+ " }, ...\n"
"}\n"
- "\nExamples:\n"
- + HelpExampleCli("getmempoolancestors", "\"mytxid\"")
+ },
+ },
+ RPCExamples{
+ HelpExampleCli("getmempoolancestors", "\"mytxid\"")
+ HelpExampleRpc("getmempoolancestors", "\"mytxid\"")
- );
+ },
+ }.ToString());
}
bool fVerbose = false;
@@ -589,7 +592,7 @@ static UniValue getmempoolancestors(const JSONRPCRequest& request)
const CTxMemPoolEntry &e = *ancestorIt;
const uint256& _hash = e.GetTx().GetHash();
UniValue info(UniValue::VOBJ);
- entryToJSON(info, e);
+ entryToJSON(::mempool, info, e);
o.pushKV(_hash.ToString(), info);
}
return o;
@@ -603,28 +606,29 @@ static UniValue getmempooldescendants(const JSONRPCRequest& request)
RPCHelpMan{"getmempooldescendants",
"\nIf txid is in the mempool, returns all in-mempool descendants.\n",
{
- {"txid", RPCArg::Type::STR_HEX, false},
- {"verbose", RPCArg::Type::BOOL, true},
- }}
- .ToString() +
- "\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"
- "\nResult (for verbose = false):\n"
+ {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id (must be in mempool)"},
+ {"verbose", RPCArg::Type::BOOL, /* default */ "false", "True for a json object, false for array of transaction ids"},
+ },
+ {
+ RPCResult{"for verbose = false",
"[ (json array of strings)\n"
" \"transactionid\" (string) The transaction id of an in-mempool descendant transaction\n"
" ,...\n"
"]\n"
- "\nResult (for verbose = true):\n"
+ },
+ RPCResult{"for verbose = true",
"{ (json object)\n"
" \"transactionid\" : { (json object)\n"
+ EntryDescriptionString()
+ " }, ...\n"
"}\n"
- "\nExamples:\n"
- + HelpExampleCli("getmempooldescendants", "\"mytxid\"")
+ },
+ },
+ RPCExamples{
+ HelpExampleCli("getmempooldescendants", "\"mytxid\"")
+ HelpExampleRpc("getmempooldescendants", "\"mytxid\"")
- );
+ },
+ }.ToString());
}
bool fVerbose = false;
@@ -658,7 +662,7 @@ static UniValue getmempooldescendants(const JSONRPCRequest& request)
const CTxMemPoolEntry &e = *descendantIt;
const uint256& _hash = e.GetTx().GetHash();
UniValue info(UniValue::VOBJ);
- entryToJSON(info, e);
+ entryToJSON(::mempool, info, e);
o.pushKV(_hash.ToString(), info);
}
return o;
@@ -672,19 +676,18 @@ static UniValue getmempoolentry(const JSONRPCRequest& request)
RPCHelpMan{"getmempoolentry",
"\nReturns mempool data for given transaction\n",
{
- {"txid", RPCArg::Type::STR_HEX, false},
- }}
- .ToString() +
- "\nArguments:\n"
- "1. \"txid\" (string, required) The transaction id (must be in mempool)\n"
- "\nResult:\n"
+ {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id (must be in mempool)"},
+ },
+ RPCResult{
"{ (json object)\n"
+ EntryDescriptionString()
+ "}\n"
- "\nExamples:\n"
- + HelpExampleCli("getmempoolentry", "\"mytxid\"")
+ },
+ RPCExamples{
+ HelpExampleCli("getmempoolentry", "\"mytxid\"")
+ HelpExampleRpc("getmempoolentry", "\"mytxid\"")
- );
+ },
+ }.ToString());
}
uint256 hash = ParseHashV(request.params[0], "parameter 1");
@@ -698,7 +701,7 @@ static UniValue getmempoolentry(const JSONRPCRequest& request)
const CTxMemPoolEntry &e = *it;
UniValue info(UniValue::VOBJ);
- entryToJSON(info, e);
+ entryToJSON(::mempool, info, e);
return info;
}
@@ -709,17 +712,16 @@ static UniValue getblockhash(const JSONRPCRequest& request)
RPCHelpMan{"getblockhash",
"\nReturns hash of block in best-block-chain at height provided.\n",
{
- {"height", RPCArg::Type::NUM, false},
- }}
- .ToString() +
- "\nArguments:\n"
- "1. height (numeric, required) The height index\n"
- "\nResult:\n"
+ {"height", RPCArg::Type::NUM, RPCArg::Optional::NO, "The height index"},
+ },
+ RPCResult{
"\"hash\" (string) The block hash\n"
- "\nExamples:\n"
- + HelpExampleCli("getblockhash", "1000")
+ },
+ RPCExamples{
+ HelpExampleCli("getblockhash", "1000")
+ HelpExampleRpc("getblockhash", "1000")
- );
+ },
+ }.ToString());
LOCK(cs_main);
@@ -739,14 +741,11 @@ static UniValue getblockheader(const JSONRPCRequest& request)
"\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, false},
- {"verbose", RPCArg::Type::BOOL, true},
- }}
- .ToString() +
- "\nArguments:\n"
- "1. \"blockhash\" (string, required) The block hash\n"
- "2. verbose (boolean, optional, default=true) true for a json object, false for the hex-encoded data\n"
- "\nResult (for verbose = true):\n"
+ {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash"},
+ {"verbose", RPCArg::Type::BOOL, /* default */ "true", "true for a json object, false for the hex-encoded data"},
+ },
+ {
+ RPCResult{"for verbose = true",
"{\n"
" \"hash\" : \"hash\", (string) the block hash (same as provided)\n"
" \"confirmations\" : n, (numeric) The number of confirmations, or -1 if the block is not on the main chain\n"
@@ -764,14 +763,16 @@ static UniValue getblockheader(const JSONRPCRequest& request)
" \"previousblockhash\" : \"hash\", (string) The hash of the previous block\n"
" \"nextblockhash\" : \"hash\", (string) The hash of the next block\n"
"}\n"
- "\nResult (for verbose=false):\n"
+ },
+ RPCResult{"for verbose=false",
"\"data\" (string) A string that is serialized, hex-encoded data for block 'hash'.\n"
- "\nExamples:\n"
- + HelpExampleCli("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
+ },
+ },
+ RPCExamples{
+ HelpExampleCli("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
+ HelpExampleRpc("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
- );
-
- LOCK(cs_main);
+ },
+ }.ToString());
uint256 hash(ParseHashV(request.params[0], "hash"));
@@ -779,7 +780,14 @@ static UniValue getblockheader(const JSONRPCRequest& request)
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");
}
@@ -792,7 +800,7 @@ static UniValue getblockheader(const JSONRPCRequest& request)
return strHex;
}
- return blockheaderToJSON(pblockindex);
+ return blockheaderToJSON(tip, pblockindex);
}
static CBlock GetBlockChecked(const CBlockIndex* pblockindex)
@@ -823,16 +831,14 @@ static UniValue getblock(const JSONRPCRequest& request)
"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, false},
- {"verbosity", RPCArg::Type::NUM, true},
- }}
- .ToString() +
- "\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"
- "\nResult (for verbosity = 0):\n"
+ {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash"},
+ {"verbosity", RPCArg::Type::NUM, /* default */ "1", "0 for hex-encoded data, 1 for a json object, and 2 for json object with transaction data"},
+ },
+ {
+ RPCResult{"for verbosity = 0",
"\"data\" (string) A string that is serialized, hex-encoded data for block 'hash'.\n"
- "\nResult (for verbosity = 1):\n"
+ },
+ RPCResult{"for verbosity = 1",
"{\n"
" \"hash\" : \"hash\", (string) the block hash (same as provided)\n"
" \"confirmations\" : n, (numeric) The number of confirmations, or -1 if the block is not on the main chain\n"
@@ -857,7 +863,8 @@ static UniValue getblock(const JSONRPCRequest& request)
" \"previousblockhash\" : \"hash\", (string) The hash of the previous block\n"
" \"nextblockhash\" : \"hash\" (string) The hash of the next block\n"
"}\n"
- "\nResult (for verbosity = 2):\n"
+ },
+ RPCResult{"for verbosity = 2",
"{\n"
" ..., Same output as verbosity = 1.\n"
" \"tx\" : [ (array of Objects) The transactions in the format of the getrawtransaction RPC. Different from verbosity = 1 \"tx\" result.\n"
@@ -865,10 +872,13 @@ static UniValue getblock(const JSONRPCRequest& request)
" ],\n"
" ,... Same output as verbosity = 1.\n"
"}\n"
- "\nExamples:\n"
- + HelpExampleCli("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
+ },
+ },
+ RPCExamples{
+ HelpExampleCli("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
+ HelpExampleRpc("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
- );
+ },
+ }.ToString());
LOCK(cs_main);
@@ -897,7 +907,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
@@ -977,17 +987,17 @@ static UniValue pruneblockchain(const JSONRPCRequest& request)
throw std::runtime_error(
RPCHelpMan{"pruneblockchain", "",
{
- {"height", RPCArg::Type::NUM, false},
- }}
- .ToString() +
- "\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"
- "\nResult:\n"
+ {"height", RPCArg::Type::NUM, RPCArg::Optional::NO, "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."},
+ },
+ RPCResult{
"n (numeric) Height of the last block pruned.\n"
- "\nExamples:\n"
- + HelpExampleCli("pruneblockchain", "1000")
- + HelpExampleRpc("pruneblockchain", "1000"));
+ },
+ RPCExamples{
+ HelpExampleCli("pruneblockchain", "1000")
+ + HelpExampleRpc("pruneblockchain", "1000")
+ },
+ }.ToString());
if (!fPruneMode)
throw JSONRPCError(RPC_MISC_ERROR, "Cannot prune blocks because node is not in prune mode.");
@@ -1002,7 +1012,7 @@ static UniValue pruneblockchain(const JSONRPCRequest& request)
// too low to be a block time (corresponds to timestamp from Sep 2001).
if (heightParam > 1000000000) {
// Add a 2 hour buffer to include blocks which might have had old timestamps
- CBlockIndex* pindex = chainActive.FindEarliestAtLeast(heightParam - TIMESTAMP_WINDOW);
+ CBlockIndex* pindex = chainActive.FindEarliestAtLeast(heightParam - TIMESTAMP_WINDOW, 0);
if (!pindex) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Could not find block with at least the specified timestamp.");
}
@@ -1031,9 +1041,8 @@ static UniValue gettxoutsetinfo(const JSONRPCRequest& request)
RPCHelpMan{"gettxoutsetinfo",
"\nReturns statistics about the unspent transaction output set.\n"
"Note this call may take some time.\n",
- {}}
- .ToString() +
- "\nResult:\n"
+ {},
+ RPCResult{
"{\n"
" \"height\":n, (numeric) The current block height (index)\n"
" \"bestblock\": \"hex\", (string) The hash of the block at the tip of the chain\n"
@@ -1044,10 +1053,12 @@ static UniValue gettxoutsetinfo(const JSONRPCRequest& request)
" \"disk_size\": n, (numeric) The estimated size of the chainstate on disk\n"
" \"total_amount\": x.xxx (numeric) The total amount\n"
"}\n"
- "\nExamples:\n"
- + HelpExampleCli("gettxoutsetinfo", "")
+ },
+ RPCExamples{
+ HelpExampleCli("gettxoutsetinfo", "")
+ HelpExampleRpc("gettxoutsetinfo", "")
- );
+ },
+ }.ToString());
UniValue ret(UniValue::VOBJ);
@@ -1075,17 +1086,11 @@ UniValue gettxout(const JSONRPCRequest& request)
RPCHelpMan{"gettxout",
"\nReturns details about an unspent transaction output.\n",
{
- {"txid", RPCArg::Type::STR, false},
- {"n", RPCArg::Type::NUM, false},
- {"include_mempool", RPCArg::Type::BOOL, true},
- }}
- .ToString() +
- "\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"
- "\nResult:\n"
+ {"txid", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction id"},
+ {"n", RPCArg::Type::NUM, RPCArg::Optional::NO, "vout number"},
+ {"include_mempool", RPCArg::Type::BOOL, /* default */ "true", "Whether to include the mempool. Note that an unspent output that is spent in the mempool won't appear."},
+ },
+ RPCResult{
"{\n"
" \"bestblock\": \"hash\", (string) The hash of the block at the tip of the chain\n"
" \"confirmations\" : n, (numeric) The number of confirmations\n"
@@ -1102,15 +1107,16 @@ UniValue gettxout(const JSONRPCRequest& request)
" },\n"
" \"coinbase\" : true|false (boolean) Coinbase or not\n"
"}\n"
-
- "\nExamples:\n"
+ },
+ RPCExamples{
"\nGet unspent transactions\n"
+ HelpExampleCli("listunspent", "") +
"\nView the details\n"
+ HelpExampleCli("gettxout", "\"txid\" 1") +
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("gettxout", "\"txid\", 1")
- );
+ },
+ }.ToString());
LOCK(cs_main);
@@ -1161,19 +1167,17 @@ static UniValue verifychain(const JSONRPCRequest& request)
RPCHelpMan{"verifychain",
"\nVerifies blockchain database.\n",
{
- {"checklevel", RPCArg::Type::NUM, true},
- {"nblocks", RPCArg::Type::NUM, true},
- }}
- .ToString() +
- "\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"
- "\nResult:\n"
+ {"checklevel", RPCArg::Type::NUM, /* default */ strprintf("%d, range=0-4", nCheckLevel), "How thorough the block verification is."},
+ {"nblocks", RPCArg::Type::NUM, /* default */ strprintf("%d, 0=all", nCheckDepth), "The number of blocks to check."},
+ },
+ RPCResult{
"true|false (boolean) Verified or not\n"
- "\nExamples:\n"
- + HelpExampleCli("verifychain", "")
+ },
+ RPCExamples{
+ HelpExampleCli("verifychain", "")
+ HelpExampleRpc("verifychain", "")
- );
+ },
+ }.ToString());
LOCK(cs_main);
@@ -1186,7 +1190,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;
@@ -1206,7 +1210,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);
@@ -1261,9 +1265,9 @@ UniValue getblockchaininfo(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() != 0)
throw std::runtime_error(
RPCHelpMan{"getblockchaininfo",
- "Returns an object containing various state info regarding blockchain processing.\n", {}}
- .ToString() +
- "\nResult:\n"
+ "Returns an object containing various state info regarding blockchain processing.\n",
+ {},
+ RPCResult{
"{\n"
" \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n"
" \"blocks\": xxxxxx, (numeric) the current number of blocks processed in the server\n"
@@ -1306,27 +1310,30 @@ UniValue getblockchaininfo(const JSONRPCRequest& request)
" }\n"
" \"warnings\" : \"...\", (string) any network and blockchain warnings.\n"
"}\n"
- "\nExamples:\n"
- + HelpExampleCli("getblockchaininfo", "")
+ },
+ RPCExamples{
+ HelpExampleCli("getblockchaininfo", "")
+ HelpExampleRpc("getblockchaininfo", "")
- );
+ },
+ }.ToString());
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;
@@ -1343,7 +1350,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));
@@ -1381,9 +1387,8 @@ static UniValue getchaintips(const JSONRPCRequest& request)
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"
+ {},
+ RPCResult{
"[\n"
" {\n"
" \"height\": xxxx, (numeric) height of the chain tip\n"
@@ -1404,10 +1409,12 @@ static UniValue getchaintips(const JSONRPCRequest& request)
"3. \"valid-headers\" All blocks are available for this branch, but they were never fully validated\n"
"4. \"valid-fork\" This branch is not part of the active chain, but is fully validated\n"
"5. \"active\" This is the tip of the active main chain, which is certainly valid\n"
- "\nExamples:\n"
- + HelpExampleCli("getchaintips", "")
+ },
+ RPCExamples{
+ HelpExampleCli("getchaintips", "")
+ HelpExampleRpc("getchaintips", "")
- );
+ },
+ }.ToString());
LOCK(cs_main);
@@ -1458,7 +1465,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)) {
@@ -1479,15 +1486,17 @@ static UniValue getchaintips(const JSONRPCRequest& request)
return res;
}
-UniValue mempoolInfoToJSON()
+UniValue MempoolInfoToJSON(const CTxMemPool& pool)
{
+ // Make sure this call is atomic in the pool.
+ LOCK(pool.cs);
UniValue ret(UniValue::VOBJ);
- ret.pushKV("size", (int64_t) mempool.size());
- ret.pushKV("bytes", (int64_t) mempool.GetTotalTxSize());
- ret.pushKV("usage", (int64_t) mempool.DynamicMemoryUsage());
+ ret.pushKV("size", (int64_t)pool.size());
+ ret.pushKV("bytes", (int64_t)pool.GetTotalTxSize());
+ ret.pushKV("usage", (int64_t)pool.DynamicMemoryUsage());
size_t maxmempool = gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;
ret.pushKV("maxmempool", (int64_t) maxmempool);
- ret.pushKV("mempoolminfee", ValueFromAmount(std::max(mempool.GetMinFee(maxmempool), ::minRelayTxFee).GetFeePerK()));
+ ret.pushKV("mempoolminfee", ValueFromAmount(std::max(pool.GetMinFee(maxmempool), ::minRelayTxFee).GetFeePerK()));
ret.pushKV("minrelaytxfee", ValueFromAmount(::minRelayTxFee.GetFeePerK()));
return ret;
@@ -1498,9 +1507,9 @@ static UniValue getmempoolinfo(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() != 0)
throw std::runtime_error(
RPCHelpMan{"getmempoolinfo",
- "\nReturns details on the active state of the TX memory pool.\n", {}}
- .ToString() +
- "\nResult:\n"
+ "\nReturns details on the active state of the TX memory pool.\n",
+ {},
+ RPCResult{
"{\n"
" \"size\": xxxxx, (numeric) Current tx count\n"
" \"bytes\": xxxxx, (numeric) Sum of all virtual transaction sizes as defined in BIP 141. Differs from actual serialized size because witness data is discounted\n"
@@ -1509,12 +1518,14 @@ static UniValue getmempoolinfo(const JSONRPCRequest& request)
" \"mempoolminfee\": xxxxx (numeric) Minimum fee rate in " + CURRENCY_UNIT + "/kB for tx to be accepted. Is the maximum of minrelaytxfee and minimum mempool fee\n"
" \"minrelaytxfee\": xxxxx (numeric) Current minimum relay fee for transactions\n"
"}\n"
- "\nExamples:\n"
- + HelpExampleCli("getmempoolinfo", "")
+ },
+ RPCExamples{
+ HelpExampleCli("getmempoolinfo", "")
+ HelpExampleRpc("getmempoolinfo", "")
- );
+ },
+ }.ToString());
- return mempoolInfoToJSON();
+ return MempoolInfoToJSON(::mempool);
}
static UniValue preciousblock(const JSONRPCRequest& request)
@@ -1526,16 +1537,14 @@ static UniValue preciousblock(const JSONRPCRequest& request)
"\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, false},
- }}
- .ToString() +
- "\nArguments:\n"
- "1. \"blockhash\" (string, required) the hash of the block to mark as precious\n"
- "\nResult:\n"
- "\nExamples:\n"
- + HelpExampleCli("preciousblock", "\"blockhash\"")
+ {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hash of the block to mark as precious"},
+ },
+ RPCResults{},
+ RPCExamples{
+ HelpExampleCli("preciousblock", "\"blockhash\"")
+ HelpExampleRpc("preciousblock", "\"blockhash\"")
- );
+ },
+ }.ToString());
uint256 hash(ParseHashV(request.params[0], "blockhash"));
CBlockIndex* pblockindex;
@@ -1565,29 +1574,27 @@ static UniValue invalidateblock(const JSONRPCRequest& request)
RPCHelpMan{"invalidateblock",
"\nPermanently marks a block as invalid, as if it violated a consensus rule.\n",
{
- {"blockhash", RPCArg::Type::STR_HEX, false},
- }}
- .ToString() +
- "\nArguments:\n"
- "1. \"blockhash\" (string, required) the hash of the block to mark as invalid\n"
- "\nResult:\n"
- "\nExamples:\n"
- + HelpExampleCli("invalidateblock", "\"blockhash\"")
+ {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hash of the block to mark as invalid"},
+ },
+ RPCResults{},
+ RPCExamples{
+ HelpExampleCli("invalidateblock", "\"blockhash\"")
+ HelpExampleRpc("invalidateblock", "\"blockhash\"")
- );
+ },
+ }.ToString());
uint256 hash(ParseHashV(request.params[0], "blockhash"));
CValidationState state;
+ CBlockIndex* pblockindex;
{
LOCK(cs_main);
- CBlockIndex* pblockindex = LookupBlockIndex(hash);
+ pblockindex = LookupBlockIndex(hash);
if (!pblockindex) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
}
-
- InvalidateBlock(state, Params(), pblockindex);
}
+ InvalidateBlock(state, Params(), pblockindex);
if (state.IsValid()) {
ActivateBestChain(state, Params());
@@ -1605,19 +1612,17 @@ static UniValue reconsiderblock(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() != 1)
throw std::runtime_error(
RPCHelpMan{"reconsiderblock",
- "\nRemoves invalidity status of a block and its descendants, reconsider them for activation.\n"
+ "\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, false},
- }}
- .ToString() +
- "\nArguments:\n"
- "1. \"blockhash\" (string, required) the hash of the block to reconsider\n"
- "\nResult:\n"
- "\nExamples:\n"
- + HelpExampleCli("reconsiderblock", "\"blockhash\"")
+ {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hash of the block to reconsider"},
+ },
+ RPCResults{},
+ RPCExamples{
+ HelpExampleCli("reconsiderblock", "\"blockhash\"")
+ HelpExampleRpc("reconsiderblock", "\"blockhash\"")
- );
+ },
+ }.ToString());
uint256 hash(ParseHashV(request.params[0], "blockhash"));
@@ -1648,14 +1653,10 @@ static UniValue getchaintxstats(const JSONRPCRequest& request)
RPCHelpMan{"getchaintxstats",
"\nCompute statistics about the total number and rate of transactions in the chain.\n",
{
- {"nblocks", RPCArg::Type::NUM, true},
- {"blockhash", RPCArg::Type::STR_HEX, true},
- }}
- .ToString() +
- "\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"
- "\nResult:\n"
+ {"nblocks", RPCArg::Type::NUM, /* default */ "one month", "Size of the window in number of blocks"},
+ {"blockhash", RPCArg::Type::STR_HEX, /* default */ "chain tip", "The hash of the block that ends the window."},
+ },
+ RPCResult{
"{\n"
" \"time\": xxxxx, (numeric) The timestamp for the final block in the window in UNIX format.\n"
" \"txcount\": xxxxx, (numeric) The total number of transactions in the chain up to that point.\n"
@@ -1665,10 +1666,12 @@ static UniValue getchaintxstats(const JSONRPCRequest& request)
" \"window_interval\": xxxxx, (numeric) The elapsed time in the window in seconds. Only returned if \"window_block_count\" is > 0.\n"
" \"txrate\": x.xx, (numeric) The average rate of transactions per second in the window. Only returned if \"window_interval\" is > 0.\n"
"}\n"
- "\nExamples:\n"
- + HelpExampleCli("getchaintxstats", "")
+ },
+ RPCExamples{
+ HelpExampleCli("getchaintxstats", "")
+ HelpExampleRpc("getchaintxstats", "2016")
- );
+ },
+ }.ToString());
const CBlockIndex* pindex;
int blockcount = 30 * 24 * 60 * 60 / Params().GetConsensus().nPowTargetSpacing; // By default: 1 month
@@ -1778,31 +1781,20 @@ static constexpr size_t PER_UTXO_OVERHEAD = sizeof(COutPoint) + sizeof(uint32_t)
static UniValue getblockstats(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() < 1 || request.params.size() > 4) {
- throw std::runtime_error(
- RPCHelpMan{"getblockstats",
+ const RPCHelpMan help{"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, false},
- {"stats", RPCArg::Type::ARR,
+ {"hash_or_height", RPCArg::Type::NUM, RPCArg::Optional::NO, "The block hash or height of the target block", "", {"", "string or numeric"}},
+ {"stats", RPCArg::Type::ARR, /* default */ "all values", "Values to plot (see result below)",
{
- {"height", RPCArg::Type::STR, true},
- {"time", RPCArg::Type::STR, true},
+ {"height", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Selected statistic"},
+ {"time", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Selected statistic"},
},
- true, "stats"},
- }}
- .ToString() +
- "\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"
- "\nResult:\n"
+ "stats"},
+ },
+ RPCResult{
"{ (json object)\n"
" \"avgfee\": xxxxx, (numeric) Average fee in the block\n"
" \"avgfeerate\": xxxxx, (numeric) Average feerate (in satoshis per virtual byte)\n"
@@ -1840,10 +1832,14 @@ static UniValue getblockstats(const JSONRPCRequest& request)
" \"utxo_increase\": xxxxx, (numeric) The increase/decrease in the number of unspent outputs\n"
" \"utxo_size_inc\": xxxxx, (numeric) The increase/decrease in size for the utxo index (not discounting op_return and similar)\n"
"}\n"
- "\nExamples:\n"
- + HelpExampleCli("getblockstats", "1000 '[\"minfeerate\",\"avgfeerate\"]'")
+ },
+ RPCExamples{
+ HelpExampleCli("getblockstats", "1000 '[\"minfeerate\",\"avgfeerate\"]'")
+ HelpExampleRpc("getblockstats", "1000 '[\"minfeerate\",\"avgfeerate\"]'")
- );
+ },
+ };
+ if (request.fHelp || !help.IsValidNumArgs(request.params.size())) {
+ throw std::runtime_error(help.ToString());
}
LOCK(cs_main);
@@ -1967,7 +1963,7 @@ static UniValue getblockstats(const JSONRPCRequest& request)
for (const CTxIn& in : tx->vin) {
CTransactionRef tx_in;
uint256 hashBlock;
- if (!GetTransaction(in.prevout.hash, tx_in, Params().GetConsensus(), hashBlock, false)) {
+ if (!GetTransaction(in.prevout.hash, tx_in, Params().GetConsensus(), hashBlock)) {
throw JSONRPCError(RPC_INTERNAL_ERROR, std::string("Unexpected internal error (tx index seems corrupt)"));
}
@@ -2055,12 +2051,14 @@ static UniValue savemempool(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() != 0) {
throw std::runtime_error(
RPCHelpMan{"savemempool",
- "\nDumps the mempool to disk. It will fail until the previous dump is fully loaded.\n", {}}
- .ToString() +
- "\nExamples:\n"
- + HelpExampleCli("savemempool", "")
+ "\nDumps the mempool to disk. It will fail until the previous dump is fully loaded.\n",
+ {},
+ RPCResults{},
+ RPCExamples{
+ HelpExampleCli("savemempool", "")
+ HelpExampleRpc("savemempool", "")
- );
+ },
+ }.ToString());
}
if (!g_is_mempool_loaded) {
@@ -2153,46 +2151,40 @@ UniValue scantxoutset(const JSONRPCRequest& request)
"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, false},
- {"scanobjects", RPCArg::Type::ARR,
+ {"action", RPCArg::Type::STR, RPCArg::Optional::NO, "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"},
+ {"scanobjects", RPCArg::Type::ARR, RPCArg::Optional::NO, "Array of scan objects\n"
+ " Every scan object is either a string descriptor or an object:",
{
- {"descriptor", RPCArg::Type::OBJ,
+ {"descriptor", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "An output descriptor"},
+ {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "An object with output descriptor and metadata",
{
- {"desc", RPCArg::Type::STR, false},
- {"range", RPCArg::Type::NUM, true},
+ {"desc", RPCArg::Type::STR, RPCArg::Optional::NO, "An output descriptor"},
+ {"range", RPCArg::Type::RANGE, /* default */ "1000", "The range of HD chain indexes to explore (either end or [begin,end])"},
},
- false, "scanobjects"},
+ },
},
- false},
- }}
- .ToString() +
- "\nArguments:\n"
- "1. \"action\" (string, required) 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"
- "\nResult:\n"
+ "[scanobjects,...]"},
+ },
+ RPCResult{
"{\n"
" \"unspents\": [\n"
" {\n"
" \"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"
" ,...], \n"
" \"total_amount\" : x.xxx, (numeric) The total amount of all found unspent outputs in " + CURRENCY_UNIT + "\n"
"]\n"
+ },
+ RPCExamples{""},
+ }.ToString()
);
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR});
@@ -2221,12 +2213,13 @@ 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
for (const UniValue& scanobject : request.params[1].get_array().getValues()) {
std::string desc_str;
- int range = 1000;
+ std::pair<int64_t, int64_t> range = {0, 1000};
if (scanobject.isStr()) {
desc_str = scanobject.get_str();
} else if (scanobject.isObject()) {
@@ -2235,8 +2228,8 @@ UniValue scantxoutset(const JSONRPCRequest& request)
desc_str = desc_uni.get_str();
UniValue range_uni = find_value(scanobject, "range");
if (!range_uni.isNull()) {
- range = range_uni.get_int();
- if (range < 0 || range > 1000000) throw JSONRPCError(RPC_INVALID_PARAMETER, "range out of range");
+ range = ParseRange(range_uni);
+ if (range.first < 0 || (range.second >> 31) != 0 || range.second >= range.first + 1000000) throw JSONRPCError(RPC_INVALID_PARAMETER, "range out of range");
}
} else {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Scan object needs to be either a string or an object");
@@ -2247,13 +2240,20 @@ UniValue scantxoutset(const JSONRPCRequest& request)
if (!desc) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Invalid descriptor '%s'", desc_str));
}
- if (!desc->IsRange()) range = 0;
- for (int i = 0; i <= range; ++i) {
+ if (!desc->IsRange()) {
+ range.first = 0;
+ range.second = 0;
+ }
+ for (int i = range.first; i <= range.second; ++i) {
std::vector<CScript> scripts;
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));
+ }
}
}
@@ -2286,6 +2286,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);
@@ -2299,6 +2300,85 @@ UniValue scantxoutset(const JSONRPCRequest& request)
return result;
}
+static UniValue getblockfilter(const JSONRPCRequest& request)
+{
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) {
+ throw std::runtime_error(
+ RPCHelpMan{"getblockfilter",
+ "\nRetrieve a BIP 157 content filter for a particular block.\n",
+ {
+ {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hash of the block"},
+ {"filtertype", RPCArg::Type::STR, /*default*/ "basic", "The type name of the filter"},
+ },
+ RPCResult{
+ "{\n"
+ " \"filter\" : (string) the hex-encoded filter data\n"
+ " \"header\" : (string) the hex-encoded filter header\n"
+ "}\n"
+ },
+ RPCExamples{
+ HelpExampleCli("getblockfilter", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\" \"basic\"")
+ }
+ }.ToString()
+ );
+ }
+
+ uint256 block_hash = ParseHashV(request.params[0], "blockhash");
+ std::string filtertype_name = "basic";
+ if (!request.params[1].isNull()) {
+ filtertype_name = request.params[1].get_str();
+ }
+
+ BlockFilterType filtertype;
+ if (!BlockFilterTypeByName(filtertype_name, filtertype)) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unknown filtertype");
+ }
+
+ BlockFilterIndex* index = GetBlockFilterIndex(filtertype);
+ if (!index) {
+ throw JSONRPCError(RPC_MISC_ERROR, "Index is not enabled for filtertype " + filtertype_name);
+ }
+
+ const CBlockIndex* block_index;
+ bool block_was_connected;
+ {
+ LOCK(cs_main);
+ block_index = LookupBlockIndex(block_hash);
+ if (!block_index) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
+ }
+ block_was_connected = block_index->IsValid(BLOCK_VALID_SCRIPTS);
+ }
+
+ bool index_ready = index->BlockUntilSyncedToCurrentChain();
+
+ BlockFilter filter;
+ uint256 filter_header;
+ if (!index->LookupFilter(block_index, filter) ||
+ !index->LookupFilterHeader(block_index, filter_header)) {
+ int err_code;
+ std::string errmsg = "Filter not found.";
+
+ if (!block_was_connected) {
+ err_code = RPC_INVALID_ADDRESS_OR_KEY;
+ errmsg += " Block was not connected to active chain.";
+ } else if (!index_ready) {
+ err_code = RPC_MISC_ERROR;
+ errmsg += " Block filters are still in the process of being indexed.";
+ } else {
+ err_code = RPC_INTERNAL_ERROR;
+ errmsg += " This error is unexpected and indicates index corruption.";
+ }
+
+ throw JSONRPCError(err_code, errmsg);
+ }
+
+ UniValue ret(UniValue::VOBJ);
+ ret.pushKV("filter", HexStr(filter.GetEncodedFilter()));
+ ret.pushKV("header", filter_header.GetHex());
+ return ret;
+}
+
// clang-format off
static const CRPCCommand commands[] =
{ // category name actor (function) argNames
@@ -2326,6 +2406,7 @@ static const CRPCCommand commands[] =
{ "blockchain", "preciousblock", &preciousblock, {"blockhash"} },
{ "blockchain", "scantxoutset", &scantxoutset, {"action", "scanobjects"} },
+ { "blockchain", "getblockfilter", &getblockfilter, {"blockhash", "filtertype"} },
/* Not shown in help */
{ "hidden", "invalidateblock", &invalidateblock, {"blockhash"} },