diff options
Diffstat (limited to 'src/rpc/blockchain.cpp')
-rw-r--r-- | src/rpc/blockchain.cpp | 449 |
1 files changed, 258 insertions, 191 deletions
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 51bc218d39..ec87f42c93 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -12,23 +12,26 @@ #include <checkpoints.h> #include <coins.h> #include <consensus/validation.h> -#include <validation.h> #include <core_io.h> +#include <hash.h> #include <index/txindex.h> #include <key_io.h> #include <policy/feerate.h> #include <policy/policy.h> +#include <policy/rbf.h> #include <primitives/transaction.h> #include <rpc/server.h> +#include <rpc/util.h> #include <script/descriptor.h> #include <streams.h> #include <sync.h> #include <txdb.h> #include <txmempool.h> -#include <util.h> -#include <utilstrencodings.h> -#include <hash.h> +#include <util/strencodings.h> +#include <util/system.h> +#include <validation.h> #include <validationinterface.h> +#include <versionbitsinfo.h> #include <warnings.h> #include <assert.h> @@ -36,7 +39,6 @@ #include <univalue.h> -#include <boost/algorithm/string.hpp> #include <boost/thread/thread.hpp> // boost::thread::interrupt #include <memory> @@ -49,7 +51,7 @@ struct CUpdatedBlock int height; }; -static std::mutex cs_blockchange; +static Mutex cs_blockchange; static std::condition_variable cond_blockchange; static CUpdatedBlock latestblock; @@ -120,8 +122,8 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx if (chainActive.Contains(blockindex)) confirmations = chainActive.Height() - blockindex->nHeight + 1; result.pushKV("confirmations", confirmations); - result.pushKV("strippedsize", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS)); - result.pushKV("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)); + result.pushKV("strippedsize", (int)::GetSerializeSize(block, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS)); + result.pushKV("size", (int)::GetSerializeSize(block, PROTOCOL_VERSION)); result.pushKV("weight", (int)::GetBlockWeight(block)); result.pushKV("height", blockindex->nHeight); result.pushKV("version", block.nVersion); @@ -160,8 +162,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" @@ -177,10 +180,11 @@ 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" + "\"hex\" (string) the block hash, hex-encoded\n" "\nExamples:\n" + HelpExampleCli("getbestblockhash", "") + HelpExampleRpc("getbestblockhash", "") @@ -204,11 +208,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" @@ -224,7 +230,7 @@ static UniValue waitfornewblock(const JSONRPCRequest& request) CUpdatedBlock block; { - std::unique_lock<std::mutex> lock(cs_blockchange); + WAIT_LOCK(cs_blockchange, lock); block = latestblock; if(timeout) cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&block]{return latestblock.height != block.height || latestblock.hash != block.hash || !IsRPCRunning(); }); @@ -242,12 +248,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" @@ -259,14 +267,14 @@ static UniValue waitforblock(const JSONRPCRequest& request) ); int timeout = 0; - uint256 hash = uint256S(request.params[0].get_str()); + uint256 hash(ParseHashV(request.params[0], "blockhash")); if (!request.params[1].isNull()) timeout = request.params[1].get_int(); CUpdatedBlock block; { - std::unique_lock<std::mutex> lock(cs_blockchange); + WAIT_LOCK(cs_blockchange, lock); if(timeout) cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&hash]{return latestblock.hash == hash || !IsRPCRunning();}); else @@ -284,13 +292,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" @@ -309,7 +319,7 @@ static UniValue waitforblockheight(const JSONRPCRequest& request) CUpdatedBlock block; { - std::unique_lock<std::mutex> lock(cs_blockchange); + WAIT_LOCK(cs_blockchange, lock); if(timeout) cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&height]{return latestblock.height >= height || !IsRPCRunning();}); else @@ -326,8 +336,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","") @@ -341,8 +352,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" @@ -379,7 +391,8 @@ static std::string EntryDescriptionString() " ... ]\n" " \"spentby\" : [ (array) unconfirmed transactions spending outputs from this transaction\n" " \"transactionid\", (string) child transaction id\n" - " ... ]\n"; + " ... ]\n" + " \"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) @@ -424,11 +437,22 @@ static void entryToJSON(UniValue &info, const CTxMemPoolEntry &e) EXCLUSIVE_LOCK UniValue spent(UniValue::VARR); const CTxMemPool::txiter &it = mempool.mapTx.find(tx.GetHash()); const CTxMemPool::setEntries &setChildren = mempool.GetMemPoolChildren(it); - for (const CTxMemPool::txiter &childiter : setChildren) { + for (CTxMemPool::txiter childiter : setChildren) { spent.push_back(childiter->GetTx().GetHash().ToString()); } info.pushKV("spentby", spent); + + // Add opt-in RBF status + bool rbfStatus = false; + RBFTransactionState rbfState = IsRBFOptIn(tx, mempool); + if (rbfState == RBFTransactionState::UNKNOWN) { + throw JSONRPCError(RPC_MISC_ERROR, "Transaction is not in mempool"); + } else if (rbfState == RBFTransactionState::REPLACEABLE_BIP125) { + rbfStatus = true; + } + + info.pushKV("bip125-replaceable", rbfStatus); } UniValue mempoolToJSON(bool fVerbose) @@ -463,11 +487,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" @@ -495,17 +521,19 @@ 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" - "\nResult (for verbose=false):\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" " ,...\n" "]\n" - "\nResult (for verbose=true):\n" + "\nResult (for verbose = true):\n" "{ (json object)\n" " \"transactionid\" : { (json object)\n" + EntryDescriptionString() @@ -559,17 +587,19 @@ 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" - "\nResult (for verbose=false):\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" " ,...\n" "]\n" - "\nResult (for verbose=true):\n" + "\nResult (for verbose = true):\n" "{ (json object)\n" " \"transactionid\" : { (json object)\n" + EntryDescriptionString() @@ -623,10 +653,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() @@ -656,10 +688,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" @@ -681,12 +715,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" @@ -714,8 +750,7 @@ static UniValue getblockheader(const JSONRPCRequest& request) LOCK(cs_main); - std::string strHash = request.params[0].get_str(); - uint256 hash(uint256S(strHash)); + uint256 hash(ParseHashV(request.params[0], "hash")); bool fVerbose = true; if (!request.params[1].isNull()) @@ -760,13 +795,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" @@ -809,8 +846,7 @@ static UniValue getblock(const JSONRPCRequest& request) LOCK(cs_main); - std::string strHash = request.params[0].get_str(); - uint256 hash(uint256S(strHash)); + uint256 hash(ParseHashV(request.params[0], "blockhash")); int verbosity = 1; if (!request.params[1].isNull()) { @@ -913,10 +949,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" @@ -962,9 +1000,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" @@ -1004,13 +1044,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" @@ -1034,7 +1075,7 @@ UniValue gettxout(const JSONRPCRequest& request) + HelpExampleCli("listunspent", "") + "\nView the details\n" + HelpExampleCli("gettxout", "\"txid\" 1") + - "\nAs a json rpc call\n" + "\nAs a JSON-RPC call\n" + HelpExampleRpc("gettxout", "\"txid\", 1") ); @@ -1042,8 +1083,7 @@ UniValue gettxout(const JSONRPCRequest& request) UniValue ret(UniValue::VOBJ); - std::string strHash = request.params[0].get_str(); - uint256 hash(uint256S(strHash)); + uint256 hash(ParseHashV(request.params[0], "txid")); int n = request.params[1].get_int(); COutPoint out(hash, n); bool fMempool = true; @@ -1085,11 +1125,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" @@ -1182,8 +1224,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" @@ -1299,9 +1342,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" @@ -1377,7 +1422,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)) { @@ -1416,8 +1461,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" @@ -1439,20 +1485,21 @@ 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\"") + HelpExampleRpc("preciousblock", "\"blockhash\"") ); - std::string strHash = request.params[0].get_str(); - uint256 hash(uint256S(strHash)); + uint256 hash(ParseHashV(request.params[0], "blockhash")); CBlockIndex* pblockindex; { @@ -1477,18 +1524,19 @@ 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\"") + HelpExampleRpc("invalidateblock", "\"blockhash\"") ); - std::string strHash = request.params[0].get_str(); - uint256 hash(uint256S(strHash)); + uint256 hash(ParseHashV(request.params[0], "blockhash")); CValidationState state; { @@ -1516,19 +1564,20 @@ 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 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\"") + HelpExampleRpc("reconsiderblock", "\"blockhash\"") ); - std::string strHash = request.params[0].get_str(); - uint256 hash(uint256S(strHash)); + uint256 hash(ParseHashV(request.params[0], "blockhash")); { LOCK(cs_main); @@ -1554,11 +1603,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" @@ -1581,7 +1632,7 @@ static UniValue getchaintxstats(const JSONRPCRequest& request) LOCK(cs_main); pindex = chainActive.Tip(); } else { - uint256 hash = uint256S(request.params[1].get_str()); + uint256 hash(ParseHashV(request.params[1], "blockhash")); LOCK(cs_main); pindex = LookupBlockIndex(hash); if (!pindex) { @@ -1684,18 +1735,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" @@ -1755,8 +1808,7 @@ static UniValue getblockstats(const JSONRPCRequest& request) pindex = chainActive[height]; } else { - const std::string strHash = request.params[0].get_str(); - const uint256 hash(uint256S(strHash)); + const uint256 hash(ParseHashV(request.params[0], "hash_or_height")); pindex = LookupBlockIndex(hash); if (!pindex) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); @@ -1791,6 +1843,10 @@ static UniValue getblockstats(const JSONRPCRequest& request) const bool do_calculate_weight = do_all || SetHasKeys(stats, "total_weight", "avgfeerate", "swtotal_weight", "avgfeerate", "feerate_percentiles", "minfeerate", "maxfeerate"); const bool do_calculate_sw = do_all || SetHasKeys(stats, "swtxs", "swtotal_size", "swtotal_weight"); + if (loop_inputs && !g_txindex) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "One or more of the selected stats requires -txindex enabled"); + } + CAmount maxfee = 0; CAmount maxfeerate = 0; CAmount minfee = MAX_MONEY; @@ -1818,7 +1874,7 @@ static UniValue getblockstats(const JSONRPCRequest& request) if (loop_outputs) { for (const CTxOut& out : tx->vout) { tx_total_out += out.nValue; - utxo_size_inc += GetSerializeSize(out, SER_NETWORK, PROTOCOL_VERSION) + PER_UTXO_OVERHEAD; + utxo_size_inc += GetSerializeSize(out, PROTOCOL_VERSION) + PER_UTXO_OVERHEAD; } } @@ -1854,10 +1910,6 @@ static UniValue getblockstats(const JSONRPCRequest& request) } if (loop_inputs) { - - if (!g_txindex) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "One or more of the selected stats requires -txindex enabled"); - } CAmount tx_total_in = 0; for (const CTxIn& in : tx->vin) { CTransactionRef tx_in; @@ -1869,7 +1921,7 @@ static UniValue getblockstats(const JSONRPCRequest& request) CTxOut prevoutput = tx_in->vout[in.prevout.n]; tx_total_in += prevoutput.nValue; - utxo_size_inc -= GetSerializeSize(prevoutput, SER_NETWORK, PROTOCOL_VERSION) + PER_UTXO_OVERHEAD; + utxo_size_inc -= GetSerializeSize(prevoutput, PROTOCOL_VERSION) + PER_UTXO_OVERHEAD; } CAmount txfee = tx_total_in - tx_total_out; @@ -1949,8 +2001,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", "") @@ -2032,34 +2085,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 at TODO\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" @@ -2067,6 +2125,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" @@ -2101,6 +2160,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 @@ -2133,7 +2193,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)); + } } } @@ -2166,6 +2230,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); @@ -2179,6 +2244,7 @@ UniValue scantxoutset(const JSONRPCRequest& request) return result; } +// clang-format off static const CRPCCommand commands[] = { // category name actor (function) argNames // --------------------- ------------------------ ----------------------- ---------- @@ -2214,6 +2280,7 @@ static const CRPCCommand commands[] = { "hidden", "waitforblockheight", &waitforblockheight, {"height","timeout"} }, { "hidden", "syncwithvalidationinterfacequeue", &syncwithvalidationinterfacequeue, {} }, }; +// clang-format on void RegisterBlockchainRPCCommands(CRPCTable &t) { |