aboutsummaryrefslogtreecommitdiff
path: root/src/rpc
diff options
context:
space:
mode:
Diffstat (limited to 'src/rpc')
-rw-r--r--src/rpc/blockchain.cpp350
-rw-r--r--src/rpc/blockchain.h2
-rw-r--r--src/rpc/client.cpp6
-rw-r--r--src/rpc/mining.cpp122
-rw-r--r--src/rpc/net.cpp200
-rw-r--r--src/rpc/rawtransaction.cpp213
-rw-r--r--src/rpc/rawtransaction_util.cpp17
-rw-r--r--src/rpc/server.cpp6
-rw-r--r--src/rpc/server.h4
9 files changed, 585 insertions, 335 deletions
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 033e00daf5..a162c1ee70 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -189,9 +189,9 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn
return result;
}
-static UniValue getblockcount(const JSONRPCRequest& request)
+static RPCHelpMan getblockcount()
{
- RPCHelpMan{"getblockcount",
+ return RPCHelpMan{"getblockcount",
"\nReturns the height of the most-work fully-validated chain.\n"
"The genesis block has height 0.\n",
{},
@@ -201,15 +201,17 @@ static UniValue getblockcount(const JSONRPCRequest& request)
HelpExampleCli("getblockcount", "")
+ HelpExampleRpc("getblockcount", "")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
LOCK(cs_main);
return ::ChainActive().Height();
+},
+ };
}
-static UniValue getbestblockhash(const JSONRPCRequest& request)
+static RPCHelpMan getbestblockhash()
{
- RPCHelpMan{"getbestblockhash",
+ return RPCHelpMan{"getbestblockhash",
"\nReturns the hash of the best (tip) block in the most-work fully-validated chain.\n",
{},
RPCResult{
@@ -218,10 +220,12 @@ static UniValue getbestblockhash(const JSONRPCRequest& request)
HelpExampleCli("getbestblockhash", "")
+ HelpExampleRpc("getbestblockhash", "")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
LOCK(cs_main);
return ::ChainActive().Tip()->GetBlockHash().GetHex();
+},
+ };
}
void RPCNotifyBlockChange(const CBlockIndex* pindex)
@@ -234,9 +238,9 @@ void RPCNotifyBlockChange(const CBlockIndex* pindex)
cond_blockchange.notify_all();
}
-static UniValue waitfornewblock(const JSONRPCRequest& request)
+static RPCHelpMan waitfornewblock()
{
- RPCHelpMan{"waitfornewblock",
+ return RPCHelpMan{"waitfornewblock",
"\nWaits for a specific new block and returns useful info about it.\n"
"\nReturns the current block on timeout or exit.\n",
{
@@ -252,7 +256,8 @@ static UniValue waitfornewblock(const JSONRPCRequest& request)
HelpExampleCli("waitfornewblock", "1000")
+ HelpExampleRpc("waitfornewblock", "1000")
},
- }.Check(request);
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
int timeout = 0;
if (!request.params[0].isNull())
timeout = request.params[0].get_int();
@@ -271,11 +276,13 @@ static UniValue waitfornewblock(const JSONRPCRequest& request)
ret.pushKV("hash", block.hash.GetHex());
ret.pushKV("height", block.height);
return ret;
+},
+ };
}
-static UniValue waitforblock(const JSONRPCRequest& request)
+static RPCHelpMan waitforblock()
{
- RPCHelpMan{"waitforblock",
+ return RPCHelpMan{"waitforblock",
"\nWaits for a specific new block and returns useful info about it.\n"
"\nReturns the current block on timeout or exit.\n",
{
@@ -292,7 +299,8 @@ static UniValue waitforblock(const JSONRPCRequest& request)
HelpExampleCli("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\" 1000")
+ HelpExampleRpc("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\", 1000")
},
- }.Check(request);
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
int timeout = 0;
uint256 hash(ParseHashV(request.params[0], "blockhash"));
@@ -314,11 +322,13 @@ static UniValue waitforblock(const JSONRPCRequest& request)
ret.pushKV("hash", block.hash.GetHex());
ret.pushKV("height", block.height);
return ret;
+},
+ };
}
-static UniValue waitforblockheight(const JSONRPCRequest& request)
+static RPCHelpMan waitforblockheight()
{
- RPCHelpMan{"waitforblockheight",
+ return 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",
@@ -336,7 +346,8 @@ static UniValue waitforblockheight(const JSONRPCRequest& request)
HelpExampleCli("waitforblockheight", "100 1000")
+ HelpExampleRpc("waitforblockheight", "100, 1000")
},
- }.Check(request);
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
int timeout = 0;
int height = request.params[0].get_int();
@@ -357,11 +368,13 @@ static UniValue waitforblockheight(const JSONRPCRequest& request)
ret.pushKV("hash", block.hash.GetHex());
ret.pushKV("height", block.height);
return ret;
+},
+ };
}
-static UniValue syncwithvalidationinterfacequeue(const JSONRPCRequest& request)
+static RPCHelpMan syncwithvalidationinterfacequeue()
{
- RPCHelpMan{"syncwithvalidationinterfacequeue",
+ return RPCHelpMan{"syncwithvalidationinterfacequeue",
"\nWaits for the validation interface queue to catch up on everything that was there when we entered this function.\n",
{},
RPCResult{RPCResult::Type::NONE, "", ""},
@@ -369,15 +382,17 @@ static UniValue syncwithvalidationinterfacequeue(const JSONRPCRequest& request)
HelpExampleCli("syncwithvalidationinterfacequeue","")
+ HelpExampleRpc("syncwithvalidationinterfacequeue","")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
SyncWithValidationInterfaceQueue();
return NullUniValue;
+},
+ };
}
-static UniValue getdifficulty(const JSONRPCRequest& request)
+static RPCHelpMan getdifficulty()
{
- RPCHelpMan{"getdifficulty",
+ return RPCHelpMan{"getdifficulty",
"\nReturns the proof-of-work difficulty as a multiple of the minimum difficulty.\n",
{},
RPCResult{
@@ -386,10 +401,12 @@ static UniValue getdifficulty(const JSONRPCRequest& request)
HelpExampleCli("getdifficulty", "")
+ HelpExampleRpc("getdifficulty", "")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
LOCK(cs_main);
return GetDifficulty(::ChainActive().Tip());
+},
+ };
}
static std::vector<RPCResult> MempoolEntryDescription() { return {
@@ -463,9 +480,9 @@ static void entryToJSON(const CTxMemPool& pool, UniValue& info, const CTxMemPool
UniValue spent(UniValue::VARR);
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());
+ const CTxMemPoolEntry::Children& children = it->GetMemPoolChildrenConst();
+ for (const CTxMemPoolEntry& child : children) {
+ spent.push_back(child.GetTx().GetHash().ToString());
}
info.pushKV("spentby", spent);
@@ -483,9 +500,12 @@ static void entryToJSON(const CTxMemPool& pool, UniValue& info, const CTxMemPool
info.pushKV("unbroadcast", pool.IsUnbroadcastTx(tx.GetHash()));
}
-UniValue MempoolToJSON(const CTxMemPool& pool, bool verbose)
+UniValue MempoolToJSON(const CTxMemPool& pool, bool verbose, bool include_mempool_sequence)
{
if (verbose) {
+ if (include_mempool_sequence) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Verbose results cannot contain mempool sequence values.");
+ }
LOCK(pool.cs);
UniValue o(UniValue::VOBJ);
for (const CTxMemPoolEntry& e : pool.mapTx) {
@@ -499,24 +519,36 @@ UniValue MempoolToJSON(const CTxMemPool& pool, bool verbose)
}
return o;
} else {
+ uint64_t mempool_sequence;
std::vector<uint256> vtxid;
- pool.queryHashes(vtxid);
-
+ {
+ LOCK(pool.cs);
+ pool.queryHashes(vtxid);
+ mempool_sequence = pool.GetSequence();
+ }
UniValue a(UniValue::VARR);
for (const uint256& hash : vtxid)
a.push_back(hash.ToString());
- return a;
+ if (!include_mempool_sequence) {
+ return a;
+ } else {
+ UniValue o(UniValue::VOBJ);
+ o.pushKV("txids", a);
+ o.pushKV("mempool_sequence", mempool_sequence);
+ return o;
+ }
}
}
-static UniValue getrawmempool(const JSONRPCRequest& request)
+static RPCHelpMan getrawmempool()
{
- RPCHelpMan{"getrawmempool",
+ return 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, /* default */ "false", "True for a json object, false for array of transaction ids"},
+ {"mempool_sequence", RPCArg::Type::BOOL, /* default */ "false", "If verbose=false, returns a json object with transaction list and mempool sequence number attached."},
},
{
RPCResult{"for verbose = false",
@@ -529,23 +561,39 @@ static UniValue getrawmempool(const JSONRPCRequest& request)
{
{RPCResult::Type::OBJ, "transactionid", "", MempoolEntryDescription()},
}},
+ RPCResult{"for verbose = false and mempool_sequence = true",
+ RPCResult::Type::OBJ, "", "",
+ {
+ {RPCResult::Type::ARR, "txids", "",
+ {
+ {RPCResult::Type::STR_HEX, "", "The transaction id"},
+ }},
+ {RPCResult::Type::NUM, "mempool_sequence", "The mempool sequence value."},
+ }},
},
RPCExamples{
HelpExampleCli("getrawmempool", "true")
+ HelpExampleRpc("getrawmempool", "true")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
bool fVerbose = false;
if (!request.params[0].isNull())
fVerbose = request.params[0].get_bool();
- return MempoolToJSON(EnsureMemPool(request.context), fVerbose);
+ bool include_mempool_sequence = false;
+ if (!request.params[1].isNull()) {
+ include_mempool_sequence = request.params[1].get_bool();
+ }
+
+ return MempoolToJSON(EnsureMemPool(request.context), fVerbose, include_mempool_sequence);
+},
+ };
}
-static UniValue getmempoolancestors(const JSONRPCRequest& request)
+static RPCHelpMan getmempoolancestors()
{
- RPCHelpMan{"getmempoolancestors",
+ return RPCHelpMan{"getmempoolancestors",
"\nIf txid is in the mempool, returns all in-mempool ancestors.\n",
{
{"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id (must be in mempool)"},
@@ -565,8 +613,8 @@ static UniValue getmempoolancestors(const JSONRPCRequest& request)
HelpExampleCli("getmempoolancestors", "\"mytxid\"")
+ HelpExampleRpc("getmempoolancestors", "\"mytxid\"")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
bool fVerbose = false;
if (!request.params[1].isNull())
fVerbose = request.params[1].get_bool();
@@ -603,11 +651,13 @@ static UniValue getmempoolancestors(const JSONRPCRequest& request)
}
return o;
}
+},
+ };
}
-static UniValue getmempooldescendants(const JSONRPCRequest& request)
+static RPCHelpMan getmempooldescendants()
{
- RPCHelpMan{"getmempooldescendants",
+ return RPCHelpMan{"getmempooldescendants",
"\nIf txid is in the mempool, returns all in-mempool descendants.\n",
{
{"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id (must be in mempool)"},
@@ -627,8 +677,8 @@ static UniValue getmempooldescendants(const JSONRPCRequest& request)
HelpExampleCli("getmempooldescendants", "\"mytxid\"")
+ HelpExampleRpc("getmempooldescendants", "\"mytxid\"")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
bool fVerbose = false;
if (!request.params[1].isNull())
fVerbose = request.params[1].get_bool();
@@ -666,11 +716,13 @@ static UniValue getmempooldescendants(const JSONRPCRequest& request)
}
return o;
}
+},
+ };
}
-static UniValue getmempoolentry(const JSONRPCRequest& request)
+static RPCHelpMan getmempoolentry()
{
- RPCHelpMan{"getmempoolentry",
+ return RPCHelpMan{"getmempoolentry",
"\nReturns mempool data for given transaction\n",
{
{"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id (must be in mempool)"},
@@ -681,8 +733,8 @@ static UniValue getmempoolentry(const JSONRPCRequest& request)
HelpExampleCli("getmempoolentry", "\"mytxid\"")
+ HelpExampleRpc("getmempoolentry", "\"mytxid\"")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
uint256 hash = ParseHashV(request.params[0], "parameter 1");
const CTxMemPool& mempool = EnsureMemPool(request.context);
@@ -697,11 +749,13 @@ static UniValue getmempoolentry(const JSONRPCRequest& request)
UniValue info(UniValue::VOBJ);
entryToJSON(mempool, info, e);
return info;
+},
+ };
}
-static UniValue getblockhash(const JSONRPCRequest& request)
+static RPCHelpMan getblockhash()
{
- RPCHelpMan{"getblockhash",
+ return RPCHelpMan{"getblockhash",
"\nReturns hash of block in best-block-chain at height provided.\n",
{
{"height", RPCArg::Type::NUM, RPCArg::Optional::NO, "The height index"},
@@ -712,8 +766,8 @@ static UniValue getblockhash(const JSONRPCRequest& request)
HelpExampleCli("getblockhash", "1000")
+ HelpExampleRpc("getblockhash", "1000")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
LOCK(cs_main);
int nHeight = request.params[0].get_int();
@@ -722,11 +776,13 @@ static UniValue getblockhash(const JSONRPCRequest& request)
CBlockIndex* pblockindex = ::ChainActive()[nHeight];
return pblockindex->GetBlockHash().GetHex();
+},
+ };
}
-static UniValue getblockheader(const JSONRPCRequest& request)
+static RPCHelpMan getblockheader()
{
- RPCHelpMan{"getblockheader",
+ return 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",
{
@@ -760,8 +816,8 @@ static UniValue getblockheader(const JSONRPCRequest& request)
HelpExampleCli("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
+ HelpExampleRpc("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
uint256 hash(ParseHashV(request.params[0], "hash"));
bool fVerbose = true;
@@ -789,6 +845,8 @@ static UniValue getblockheader(const JSONRPCRequest& request)
}
return blockheaderToJSON(tip, pblockindex);
+},
+ };
}
static CBlock GetBlockChecked(const CBlockIndex* pblockindex)
@@ -822,9 +880,9 @@ static CBlockUndo GetUndoChecked(const CBlockIndex* pblockindex)
return blockUndo;
}
-static UniValue getblock(const JSONRPCRequest& request)
+static RPCHelpMan getblock()
{
- RPCHelpMan{"getblock",
+ return 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",
@@ -870,15 +928,14 @@ static UniValue getblock(const JSONRPCRequest& request)
{RPCResult::Type::ELISION, "", "The transactions in the format of the getrawtransaction RPC. Different from verbosity = 1 \"tx\" result"},
}},
}},
- {RPCResult::Type::ELISION, "", "Same output as verbosity = 1"},
}},
},
RPCExamples{
HelpExampleCli("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
+ HelpExampleRpc("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
uint256 hash(ParseHashV(request.params[0], "blockhash"));
int verbosity = 1;
@@ -913,11 +970,13 @@ static UniValue getblock(const JSONRPCRequest& request)
}
return blockToJSON(block, tip, pblockindex, verbosity >= 2);
+},
+ };
}
-static UniValue pruneblockchain(const JSONRPCRequest& request)
+static RPCHelpMan pruneblockchain()
{
- RPCHelpMan{"pruneblockchain", "",
+ return RPCHelpMan{"pruneblockchain", "",
{
{"height", RPCArg::Type::NUM, RPCArg::Optional::NO, "The block height to prune up to. May be set to a discrete height, or to a " + UNIX_EPOCH_TIME + "\n"
" to prune blocks whose block time is at least 2 hours older than the provided timestamp."},
@@ -928,8 +987,8 @@ static UniValue pruneblockchain(const JSONRPCRequest& request)
HelpExampleCli("pruneblockchain", "1000")
+ HelpExampleRpc("pruneblockchain", "1000")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
if (!fPruneMode)
throw JSONRPCError(RPC_MISC_ERROR, "Cannot prune blocks because node is not in prune mode.");
@@ -968,11 +1027,13 @@ static UniValue pruneblockchain(const JSONRPCRequest& request)
block = block->pprev;
}
return uint64_t(block->nHeight);
+},
+ };
}
-static UniValue gettxoutsetinfo(const JSONRPCRequest& request)
+static RPCHelpMan gettxoutsetinfo()
{
- RPCHelpMan{"gettxoutsetinfo",
+ return RPCHelpMan{"gettxoutsetinfo",
"\nReturns statistics about the unspent transaction output set.\n"
"Note this call may take some time.\n",
{
@@ -994,8 +1055,8 @@ static UniValue gettxoutsetinfo(const JSONRPCRequest& request)
HelpExampleCli("gettxoutsetinfo", "")
+ HelpExampleRpc("gettxoutsetinfo", "")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
UniValue ret(UniValue::VOBJ);
CCoinsStats stats;
@@ -1020,11 +1081,13 @@ static UniValue gettxoutsetinfo(const JSONRPCRequest& request)
throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set");
}
return ret;
+},
+ };
}
-UniValue gettxout(const JSONRPCRequest& request)
+static RPCHelpMan gettxout()
{
- RPCHelpMan{"gettxout",
+ return RPCHelpMan{"gettxout",
"\nReturns details about an unspent transaction output.\n",
{
{"txid", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction id"},
@@ -1056,8 +1119,8 @@ UniValue gettxout(const JSONRPCRequest& request)
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("gettxout", "\"txid\", 1")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
LOCK(cs_main);
UniValue ret(UniValue::VOBJ);
@@ -1099,11 +1162,13 @@ UniValue gettxout(const JSONRPCRequest& request)
ret.pushKV("coinbase", (bool)coin.fCoinBase);
return ret;
+},
+ };
}
-static UniValue verifychain(const JSONRPCRequest& request)
+static RPCHelpMan verifychain()
{
- RPCHelpMan{"verifychain",
+ return RPCHelpMan{"verifychain",
"\nVerifies blockchain database.\n",
{
{"checklevel", RPCArg::Type::NUM, /* default */ strprintf("%d, range=0-4", DEFAULT_CHECKLEVEL),
@@ -1116,14 +1181,16 @@ static UniValue verifychain(const JSONRPCRequest& request)
HelpExampleCli("verifychain", "")
+ HelpExampleRpc("verifychain", "")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
const int check_level(request.params[0].isNull() ? DEFAULT_CHECKLEVEL : request.params[0].get_int());
const int check_depth{request.params[1].isNull() ? DEFAULT_CHECKBLOCKS : request.params[1].get_int()};
LOCK(cs_main);
return CVerifyDB().VerifyDB(Params(), &::ChainstateActive().CoinsTip(), check_level, check_depth);
+},
+ };
}
static void BuriedForkDescPushBack(UniValue& softforks, const std::string &name, int height) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
@@ -1192,9 +1259,9 @@ static void BIP9SoftForkDescPushBack(UniValue& softforks, const std::string &nam
softforks.pushKV(name, rv);
}
-UniValue getblockchaininfo(const JSONRPCRequest& request)
+RPCHelpMan getblockchaininfo()
{
- RPCHelpMan{"getblockchaininfo",
+ return RPCHelpMan{"getblockchaininfo",
"Returns an object containing various state info regarding blockchain processing.\n",
{},
RPCResult{
@@ -1245,8 +1312,8 @@ UniValue getblockchaininfo(const JSONRPCRequest& request)
HelpExampleCli("getblockchaininfo", "")
+ HelpExampleRpc("getblockchaininfo", "")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
LOCK(cs_main);
const CBlockIndex* tip = ::ChainActive().Tip();
@@ -1287,10 +1354,13 @@ UniValue getblockchaininfo(const JSONRPCRequest& request)
BuriedForkDescPushBack(softforks, "csv", consensusParams.CSVHeight);
BuriedForkDescPushBack(softforks, "segwit", consensusParams.SegwitHeight);
BIP9SoftForkDescPushBack(softforks, "testdummy", consensusParams, Consensus::DEPLOYMENT_TESTDUMMY);
+ BIP9SoftForkDescPushBack(softforks, "taproot", consensusParams, Consensus::DEPLOYMENT_TAPROOT);
obj.pushKV("softforks", softforks);
obj.pushKV("warnings", GetWarnings(false).original);
return obj;
+},
+ };
}
/** Comparison function for sorting the getchaintips heads. */
@@ -1308,9 +1378,9 @@ struct CompareBlocksByHeight
}
};
-static UniValue getchaintips(const JSONRPCRequest& request)
+static RPCHelpMan getchaintips()
{
- RPCHelpMan{"getchaintips",
+ return RPCHelpMan{"getchaintips",
"Return information about all known tips in the block tree,"
" including the main chain as well as orphaned branches.\n",
{},
@@ -1333,8 +1403,8 @@ static UniValue getchaintips(const JSONRPCRequest& request)
HelpExampleCli("getchaintips", "")
+ HelpExampleRpc("getchaintips", "")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
ChainstateManager& chainman = EnsureChainman(request.context);
LOCK(cs_main);
@@ -1401,6 +1471,8 @@ static UniValue getchaintips(const JSONRPCRequest& request)
}
return res;
+},
+ };
}
UniValue MempoolInfoToJSON(const CTxMemPool& pool)
@@ -1420,9 +1492,9 @@ UniValue MempoolInfoToJSON(const CTxMemPool& pool)
return ret;
}
-static UniValue getmempoolinfo(const JSONRPCRequest& request)
+static RPCHelpMan getmempoolinfo()
{
- RPCHelpMan{"getmempoolinfo",
+ return RPCHelpMan{"getmempoolinfo",
"\nReturns details on the active state of the TX memory pool.\n",
{},
RPCResult{
@@ -1441,14 +1513,16 @@ static UniValue getmempoolinfo(const JSONRPCRequest& request)
HelpExampleCli("getmempoolinfo", "")
+ HelpExampleRpc("getmempoolinfo", "")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
return MempoolInfoToJSON(EnsureMemPool(request.context));
+},
+ };
}
-static UniValue preciousblock(const JSONRPCRequest& request)
+static RPCHelpMan preciousblock()
{
- RPCHelpMan{"preciousblock",
+ return 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",
@@ -1460,8 +1534,8 @@ static UniValue preciousblock(const JSONRPCRequest& request)
HelpExampleCli("preciousblock", "\"blockhash\"")
+ HelpExampleRpc("preciousblock", "\"blockhash\"")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
uint256 hash(ParseHashV(request.params[0], "blockhash"));
CBlockIndex* pblockindex;
@@ -1481,11 +1555,13 @@ static UniValue preciousblock(const JSONRPCRequest& request)
}
return NullUniValue;
+},
+ };
}
-static UniValue invalidateblock(const JSONRPCRequest& request)
+static RPCHelpMan invalidateblock()
{
- RPCHelpMan{"invalidateblock",
+ return RPCHelpMan{"invalidateblock",
"\nPermanently marks a block as invalid, as if it violated a consensus rule.\n",
{
{"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hash of the block to mark as invalid"},
@@ -1495,8 +1571,8 @@ static UniValue invalidateblock(const JSONRPCRequest& request)
HelpExampleCli("invalidateblock", "\"blockhash\"")
+ HelpExampleRpc("invalidateblock", "\"blockhash\"")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
uint256 hash(ParseHashV(request.params[0], "blockhash"));
BlockValidationState state;
@@ -1519,11 +1595,13 @@ static UniValue invalidateblock(const JSONRPCRequest& request)
}
return NullUniValue;
+},
+ };
}
-static UniValue reconsiderblock(const JSONRPCRequest& request)
+static RPCHelpMan reconsiderblock()
{
- RPCHelpMan{"reconsiderblock",
+ return RPCHelpMan{"reconsiderblock",
"\nRemoves invalidity status of a block, its ancestors and its descendants, reconsider them for activation.\n"
"This can be used to undo the effects of invalidateblock.\n",
{
@@ -1534,8 +1612,8 @@ static UniValue reconsiderblock(const JSONRPCRequest& request)
HelpExampleCli("reconsiderblock", "\"blockhash\"")
+ HelpExampleRpc("reconsiderblock", "\"blockhash\"")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
uint256 hash(ParseHashV(request.params[0], "blockhash"));
{
@@ -1556,11 +1634,13 @@ static UniValue reconsiderblock(const JSONRPCRequest& request)
}
return NullUniValue;
+},
+ };
}
-static UniValue getchaintxstats(const JSONRPCRequest& request)
+static RPCHelpMan getchaintxstats()
{
- RPCHelpMan{"getchaintxstats",
+ return RPCHelpMan{"getchaintxstats",
"\nCompute statistics about the total number and rate of transactions in the chain.\n",
{
{"nblocks", RPCArg::Type::NUM, /* default */ "one month", "Size of the window in number of blocks"},
@@ -1582,8 +1662,8 @@ static UniValue getchaintxstats(const JSONRPCRequest& request)
HelpExampleCli("getchaintxstats", "")
+ HelpExampleRpc("getchaintxstats", "2016")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
const CBlockIndex* pindex;
int blockcount = 30 * 24 * 60 * 60 / Params().GetConsensus().nPowTargetSpacing; // By default: 1 month
@@ -1633,6 +1713,8 @@ static UniValue getchaintxstats(const JSONRPCRequest& request)
}
return ret;
+},
+ };
}
template<typename T>
@@ -1691,9 +1773,9 @@ static inline bool SetHasKeys(const std::set<T>& set, const Tk& key, const Args&
// outpoint (needed for the utxo index) + nHeight + fCoinBase
static constexpr size_t PER_UTXO_OVERHEAD = sizeof(COutPoint) + sizeof(uint32_t) + sizeof(bool);
-static UniValue getblockstats(const JSONRPCRequest& request)
+static RPCHelpMan getblockstats()
{
- RPCHelpMan{"getblockstats",
+ return 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",
{
@@ -1751,8 +1833,8 @@ static UniValue getblockstats(const JSONRPCRequest& request)
HelpExampleRpc("getblockstats", R"("00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09", ["minfeerate","avgfeerate"])") +
HelpExampleRpc("getblockstats", R"(1000, ["minfeerate","avgfeerate"])")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
LOCK(cs_main);
CBlockIndex* pindex;
@@ -1948,11 +2030,13 @@ static UniValue getblockstats(const JSONRPCRequest& request)
ret.pushKV(stat, value);
}
return ret;
+},
+ };
}
-static UniValue savemempool(const JSONRPCRequest& request)
+static RPCHelpMan savemempool()
{
- RPCHelpMan{"savemempool",
+ return RPCHelpMan{"savemempool",
"\nDumps the mempool to disk. It will fail until the previous dump is fully loaded.\n",
{},
RPCResult{RPCResult::Type::NONE, "", ""},
@@ -1960,8 +2044,8 @@ static UniValue savemempool(const JSONRPCRequest& request)
HelpExampleCli("savemempool", "")
+ HelpExampleRpc("savemempool", "")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
const CTxMemPool& mempool = EnsureMemPool(request.context);
if (!mempool.IsLoaded()) {
@@ -1973,6 +2057,8 @@ static UniValue savemempool(const JSONRPCRequest& request)
}
return NullUniValue;
+},
+ };
}
namespace {
@@ -2034,9 +2120,9 @@ public:
}
};
-UniValue scantxoutset(const JSONRPCRequest& request)
+static RPCHelpMan scantxoutset()
{
- RPCHelpMan{"scantxoutset",
+ return 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"
@@ -2090,8 +2176,8 @@ UniValue scantxoutset(const JSONRPCRequest& request)
{RPCResult::Type::STR_AMOUNT, "total_amount", "The total amount of all found unspent outputs in " + CURRENCY_UNIT},
}},
RPCExamples{""},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR});
UniValue result(UniValue::VOBJ);
@@ -2184,11 +2270,13 @@ UniValue scantxoutset(const JSONRPCRequest& request)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid command");
}
return result;
+},
+ };
}
-static UniValue getblockfilter(const JSONRPCRequest& request)
+static RPCHelpMan getblockfilter()
{
- RPCHelpMan{"getblockfilter",
+ return 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"},
@@ -2203,9 +2291,9 @@ static UniValue getblockfilter(const JSONRPCRequest& request)
RPCExamples{
HelpExampleCli("getblockfilter", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\" \"basic\"") +
HelpExampleRpc("getblockfilter", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\", \"basic\"")
- }
- }.Check(request);
-
+ },
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
uint256 block_hash = ParseHashV(request.params[0], "blockhash");
std::string filtertype_name = "basic";
if (!request.params[1].isNull()) {
@@ -2260,6 +2348,8 @@ static UniValue getblockfilter(const JSONRPCRequest& request)
ret.pushKV("filter", HexStr(filter.GetEncodedFilter()));
ret.pushKV("header", filter_header.GetHex());
return ret;
+},
+ };
}
/**
@@ -2267,9 +2357,9 @@ static UniValue getblockfilter(const JSONRPCRequest& request)
*
* @see SnapshotMetadata
*/
-UniValue dumptxoutset(const JSONRPCRequest& request)
+static RPCHelpMan dumptxoutset()
{
- RPCHelpMan{
+ return RPCHelpMan{
"dumptxoutset",
"\nWrite the serialized UTXO set to disk.\n",
{
@@ -2290,9 +2380,9 @@ UniValue dumptxoutset(const JSONRPCRequest& request)
},
RPCExamples{
HelpExampleCli("dumptxoutset", "utxo.dat")
- }
- }.Check(request);
-
+ },
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
fs::path path = fs::absolute(request.params[0].get_str(), GetDataDir());
// Write to a temporary path and then move into `path` on completion
// to avoid confusion due to an interruption.
@@ -2366,6 +2456,8 @@ UniValue dumptxoutset(const JSONRPCRequest& request)
result.pushKV("base_height", tip->nHeight);
result.pushKV("path", path.string());
return result;
+},
+ };
}
void RegisterBlockchainRPCCommands(CRPCTable &t)
@@ -2388,7 +2480,7 @@ static const CRPCCommand commands[] =
{ "blockchain", "getmempooldescendants", &getmempooldescendants, {"txid","verbose"} },
{ "blockchain", "getmempoolentry", &getmempoolentry, {"txid"} },
{ "blockchain", "getmempoolinfo", &getmempoolinfo, {} },
- { "blockchain", "getrawmempool", &getrawmempool, {"verbose"} },
+ { "blockchain", "getrawmempool", &getrawmempool, {"verbose", "mempool_sequence"} },
{ "blockchain", "gettxout", &gettxout, {"txid","n","include_mempool"} },
{ "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, {"hash_type"} },
{ "blockchain", "pruneblockchain", &pruneblockchain, {"height"} },
diff --git a/src/rpc/blockchain.h b/src/rpc/blockchain.h
index 5c9a43b13e..5b362bf211 100644
--- a/src/rpc/blockchain.h
+++ b/src/rpc/blockchain.h
@@ -43,7 +43,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn
UniValue MempoolInfoToJSON(const CTxMemPool& pool);
/** Mempool to JSON */
-UniValue MempoolToJSON(const CTxMemPool& pool, bool verbose = false);
+UniValue MempoolToJSON(const CTxMemPool& pool, bool verbose = false, bool include_mempool_sequence = false);
/** Block header to JSON */
UniValue blockheaderToJSON(const CBlockIndex* tip, const CBlockIndex* blockindex) LOCKS_EXCLUDED(cs_main);
diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp
index 4d08671bd2..88c8ebe1f6 100644
--- a/src/rpc/client.cpp
+++ b/src/rpc/client.cpp
@@ -41,6 +41,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "sendtoaddress", 5 , "replaceable" },
{ "sendtoaddress", 6 , "conf_target" },
{ "sendtoaddress", 8, "avoid_reuse" },
+ { "sendtoaddress", 9, "verbose"},
{ "settxfee", 0, "amount" },
{ "sethdseed", 0, "newkeypool" },
{ "getreceivedbyaddress", 1, "minconf" },
@@ -72,6 +73,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "sendmany", 4, "subtractfeefrom" },
{ "sendmany", 5 , "replaceable" },
{ "sendmany", 6 , "conf_target" },
+ { "sendmany", 8, "verbose" },
{ "deriveaddresses", 1, "range" },
{ "scantxoutset", 1, "scanobjects" },
{ "addmultisigaddress", 0, "nrequired" },
@@ -125,6 +127,9 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "gettxoutproof", 0, "txids" },
{ "lockunspent", 0, "unlock" },
{ "lockunspent", 1, "transactions" },
+ { "send", 0, "outputs" },
+ { "send", 1, "conf_target" },
+ { "send", 3, "options" },
{ "importprivkey", 2, "rescan" },
{ "importaddress", 2, "rescan" },
{ "importaddress", 3, "p2sh" },
@@ -139,6 +144,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "pruneblockchain", 0, "height" },
{ "keypoolrefill", 0, "newsize" },
{ "getrawmempool", 0, "verbose" },
+ { "getrawmempool", 1, "mempool_sequence" },
{ "estimatesmartfee", 0, "conf_target" },
{ "estimaterawfee", 0, "conf_target" },
{ "estimaterawfee", 1, "threshold" },
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index 661181850b..a561b7e93c 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -81,9 +81,9 @@ static UniValue GetNetworkHashPS(int lookup, int height) {
return workDiff.getdouble() / timeDiff;
}
-static UniValue getnetworkhashps(const JSONRPCRequest& request)
+static RPCHelpMan getnetworkhashps()
{
- RPCHelpMan{"getnetworkhashps",
+ return RPCHelpMan{"getnetworkhashps",
"\nReturns the estimated network hashes per second based on the last n blocks.\n"
"Pass in [blocks] to override # of blocks, -1 specifies since last difficulty change.\n"
"Pass in [height] to estimate the network speed at the time when a certain block was found.\n",
@@ -97,10 +97,12 @@ static UniValue getnetworkhashps(const JSONRPCRequest& request)
HelpExampleCli("getnetworkhashps", "")
+ HelpExampleRpc("getnetworkhashps", "")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
LOCK(cs_main);
return GetNetworkHashPS(!request.params[0].isNull() ? request.params[0].get_int() : 120, !request.params[1].isNull() ? request.params[1].get_int() : -1);
+},
+ };
}
static bool GenerateBlock(ChainstateManager& chainman, CBlock& block, uint64_t& max_tries, unsigned int& extra_nonce, uint256& block_hash)
@@ -200,9 +202,9 @@ static bool getScriptFromDescriptor(const std::string& descriptor, CScript& scri
}
}
-static UniValue generatetodescriptor(const JSONRPCRequest& request)
+static RPCHelpMan generatetodescriptor()
{
- RPCHelpMan{
+ return RPCHelpMan{
"generatetodescriptor",
"\nMine blocks immediately to a specified descriptor (before the RPC call returns)\n",
{
@@ -218,9 +220,8 @@ static UniValue generatetodescriptor(const JSONRPCRequest& request)
},
RPCExamples{
"\nGenerate 11 blocks to mydesc\n" + HelpExampleCli("generatetodescriptor", "11 \"mydesc\"")},
- }
- .Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
const int num_blocks{request.params[0].get_int()};
const uint64_t max_tries{request.params[2].isNull() ? DEFAULT_MAX_TRIES : request.params[2].get_int()};
@@ -234,22 +235,25 @@ static UniValue generatetodescriptor(const JSONRPCRequest& request)
ChainstateManager& chainman = EnsureChainman(request.context);
return generateBlocks(chainman, mempool, coinbase_script, num_blocks, max_tries);
+},
+ };
}
-static UniValue generate(const JSONRPCRequest& request)
+static RPCHelpMan generate()
{
- const std::string help_str{"generate ( nblocks maxtries ) has been replaced by the -generate cli option. Refer to -help for more information."};
+ return RPCHelpMan{"generate", "has been replaced by the -generate cli option. Refer to -help for more information.", {}, {}, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue {
if (request.fHelp) {
- throw std::runtime_error(help_str);
+ throw std::runtime_error(self.ToString());
} else {
- throw JSONRPCError(RPC_METHOD_NOT_FOUND, help_str);
+ throw JSONRPCError(RPC_METHOD_NOT_FOUND, self.ToString());
}
+ }};
}
-static UniValue generatetoaddress(const JSONRPCRequest& request)
+static RPCHelpMan generatetoaddress()
{
- RPCHelpMan{"generatetoaddress",
+ return RPCHelpMan{"generatetoaddress",
"\nMine blocks immediately to a specified address (before the RPC call returns)\n",
{
{"nblocks", RPCArg::Type::NUM, RPCArg::Optional::NO, "How many blocks are generated immediately."},
@@ -267,8 +271,8 @@ static UniValue generatetoaddress(const JSONRPCRequest& request)
+ "If you are using the " PACKAGE_NAME " wallet, you can get a new address to send the newly generated bitcoin to with:\n"
+ HelpExampleCli("getnewaddress", "")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
const int num_blocks{request.params[0].get_int()};
const uint64_t max_tries{request.params[2].isNull() ? DEFAULT_MAX_TRIES : request.params[2].get_int()};
@@ -283,11 +287,13 @@ static UniValue generatetoaddress(const JSONRPCRequest& request)
CScript coinbase_script = GetScriptForDestination(destination);
return generateBlocks(chainman, mempool, coinbase_script, num_blocks, max_tries);
+},
+ };
}
-static UniValue generateblock(const JSONRPCRequest& request)
+static RPCHelpMan generateblock()
{
- RPCHelpMan{"generateblock",
+ return RPCHelpMan{"generateblock",
"\nMine a block with a set of ordered transactions immediately to a specified address or descriptor (before the RPC call returns)\n",
{
{"output", RPCArg::Type::STR, RPCArg::Optional::NO, "The address or descriptor to send the newly generated bitcoin to."},
@@ -309,8 +315,8 @@ static UniValue generateblock(const JSONRPCRequest& request)
"\nGenerate a block to myaddress, with txs rawtx and mempool_txid\n"
+ HelpExampleCli("generateblock", R"("myaddress" '["rawtx", "mempool_txid"]')")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
const auto address_or_descriptor = request.params[0].get_str();
CScript coinbase_script;
std::string error;
@@ -390,11 +396,13 @@ static UniValue generateblock(const JSONRPCRequest& request)
UniValue obj(UniValue::VOBJ);
obj.pushKV("hash", block_hash.GetHex());
return obj;
+},
+ };
}
-static UniValue getmininginfo(const JSONRPCRequest& request)
+static RPCHelpMan getmininginfo()
{
- RPCHelpMan{"getmininginfo",
+ return RPCHelpMan{"getmininginfo",
"\nReturns a json object containing mining-related information.",
{},
RPCResult{
@@ -413,8 +421,8 @@ static UniValue getmininginfo(const JSONRPCRequest& request)
HelpExampleCli("getmininginfo", "")
+ HelpExampleRpc("getmininginfo", "")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
LOCK(cs_main);
const CTxMemPool& mempool = EnsureMemPool(request.context);
@@ -423,18 +431,20 @@ static UniValue getmininginfo(const JSONRPCRequest& request)
if (BlockAssembler::m_last_block_weight) obj.pushKV("currentblockweight", *BlockAssembler::m_last_block_weight);
if (BlockAssembler::m_last_block_num_txs) obj.pushKV("currentblocktx", *BlockAssembler::m_last_block_num_txs);
obj.pushKV("difficulty", (double)GetDifficulty(::ChainActive().Tip()));
- obj.pushKV("networkhashps", getnetworkhashps(request));
+ obj.pushKV("networkhashps", getnetworkhashps().HandleRequest(request));
obj.pushKV("pooledtx", (uint64_t)mempool.size());
obj.pushKV("chain", Params().NetworkIDString());
obj.pushKV("warnings", GetWarnings(false).original);
return obj;
+},
+ };
}
// NOTE: Unlike wallet RPC (which use BTC values), mining RPCs follow GBT (BIP 22) in using satoshi amounts
-static UniValue prioritisetransaction(const JSONRPCRequest& request)
+static RPCHelpMan prioritisetransaction()
{
- RPCHelpMan{"prioritisetransaction",
+ return RPCHelpMan{"prioritisetransaction",
"Accepts the transaction into mined blocks at a higher (or lower) priority\n",
{
{"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id."},
@@ -451,8 +461,8 @@ static UniValue prioritisetransaction(const JSONRPCRequest& request)
HelpExampleCli("prioritisetransaction", "\"txid\" 0.0 10000")
+ HelpExampleRpc("prioritisetransaction", "\"txid\", 0.0, 10000")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
LOCK(cs_main);
uint256 hash(ParseHashV(request.params[0], "txid"));
@@ -464,6 +474,8 @@ static UniValue prioritisetransaction(const JSONRPCRequest& request)
EnsureMemPool(request.context).PrioritiseTransaction(hash, nAmount);
return true;
+},
+ };
}
@@ -495,9 +507,9 @@ static std::string gbt_vb_name(const Consensus::DeploymentPos pos) {
return s;
}
-static UniValue getblocktemplate(const JSONRPCRequest& request)
+static RPCHelpMan getblocktemplate()
{
- RPCHelpMan{"getblocktemplate",
+ return RPCHelpMan{"getblocktemplate",
"\nIf the request parameters include a 'mode' key, that is used to explicitly select between the default 'template' request or a 'proposal'.\n"
"It returns data needed to construct a block to work on.\n"
"For full specification, see BIPs 22, 23, 9, and 145:\n"
@@ -578,8 +590,8 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
HelpExampleCli("getblocktemplate", "'{\"rules\": [\"segwit\"]}'")
+ HelpExampleRpc("getblocktemplate", "{\"rules\": [\"segwit\"]}")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
LOCK(cs_main);
std::string strMode = "template";
@@ -887,6 +899,8 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
}
return result;
+},
+ };
}
class submitblock_StateCatcher final : public CValidationInterface
@@ -907,10 +921,10 @@ protected:
}
};
-static UniValue submitblock(const JSONRPCRequest& request)
+static RPCHelpMan submitblock()
{
// We allow 2 arguments for compliance with BIP22. Argument 2 is ignored.
- RPCHelpMan{"submitblock",
+ return RPCHelpMan{"submitblock",
"\nAttempts to submit new block to network.\n"
"See https://en.bitcoin.it/wiki/BIP_0022 for full specification.\n",
{
@@ -922,8 +936,8 @@ static UniValue submitblock(const JSONRPCRequest& request)
HelpExampleCli("submitblock", "\"mydata\"")
+ HelpExampleRpc("submitblock", "\"mydata\"")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
std::shared_ptr<CBlock> blockptr = std::make_shared<CBlock>();
CBlock& block = *blockptr;
if (!DecodeHexBlk(block, request.params[0].get_str())) {
@@ -968,11 +982,13 @@ static UniValue submitblock(const JSONRPCRequest& request)
return "inconclusive";
}
return BIP22ValidationResult(sc->state);
+},
+ };
}
-static UniValue submitheader(const JSONRPCRequest& request)
+static RPCHelpMan submitheader()
{
- RPCHelpMan{"submitheader",
+ return RPCHelpMan{"submitheader",
"\nDecode the given hexdata as a header and submit it as a candidate chain tip if valid."
"\nThrows when the header is invalid.\n",
{
@@ -984,8 +1000,8 @@ static UniValue submitheader(const JSONRPCRequest& request)
HelpExampleCli("submitheader", "\"aabbcc\"") +
HelpExampleRpc("submitheader", "\"aabbcc\"")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
CBlockHeader h;
if (!DecodeHexBlockHeader(h, request.params[0].get_str())) {
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block header decode failed");
@@ -1004,11 +1020,13 @@ static UniValue submitheader(const JSONRPCRequest& request)
throw JSONRPCError(RPC_VERIFY_ERROR, state.ToString());
}
throw JSONRPCError(RPC_VERIFY_ERROR, state.GetRejectReason());
+},
+ };
}
-static UniValue estimatesmartfee(const JSONRPCRequest& request)
+static RPCHelpMan estimatesmartfee()
{
- RPCHelpMan{"estimatesmartfee",
+ return RPCHelpMan{"estimatesmartfee",
"\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n"
"confirmation within conf_target blocks if possible and return the number of blocks\n"
"for which the estimate is valid. Uses virtual transaction size as defined\n"
@@ -1042,8 +1060,8 @@ static UniValue estimatesmartfee(const JSONRPCRequest& request)
RPCExamples{
HelpExampleCli("estimatesmartfee", "6")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VSTR});
RPCTypeCheckArgument(request.params[0], UniValue::VNUM);
unsigned int max_target = ::feeEstimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE);
@@ -1069,11 +1087,13 @@ static UniValue estimatesmartfee(const JSONRPCRequest& request)
}
result.pushKV("blocks", feeCalc.returnedTarget);
return result;
+},
+ };
}
-static UniValue estimaterawfee(const JSONRPCRequest& request)
+static RPCHelpMan estimaterawfee()
{
- RPCHelpMan{"estimaterawfee",
+ return RPCHelpMan{"estimaterawfee",
"\nWARNING: This interface is unstable and may disappear or change!\n"
"\nWARNING: This is an advanced API call that is tightly coupled to the specific\n"
" implementation of fee estimation. The parameters it can be called with\n"
@@ -1125,8 +1145,8 @@ static UniValue estimaterawfee(const JSONRPCRequest& request)
RPCExamples{
HelpExampleCli("estimaterawfee", "6 0.9")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VNUM}, true);
RPCTypeCheckArgument(request.params[0], UniValue::VNUM);
unsigned int max_target = ::feeEstimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE);
@@ -1185,6 +1205,8 @@ static UniValue estimaterawfee(const JSONRPCRequest& request)
result.pushKV(StringForFeeEstimateHorizon(horizon), horizon_result);
}
return result;
+},
+ };
}
void RegisterMiningRPCCommands(CRPCTable &t)
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index 7e2052c7cb..b81e6414a5 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -29,9 +29,18 @@
#include <univalue.h>
-static UniValue getconnectioncount(const JSONRPCRequest& request)
+const std::vector<std::string> CONNECTION_TYPE_DOC{
+ "outbound-full-relay (default automatic connections)",
+ "block-relay-only (does not relay transactions or addresses)",
+ "inbound (initiated by the peer)",
+ "manual (added via addnode RPC or -addnode/-connect configuration options)",
+ "addr-fetch (short-lived automatic connection for soliciting addresses)",
+ "feeler (short-lived automatic connection for testing addresses)"
+};
+
+static RPCHelpMan getconnectioncount()
{
- RPCHelpMan{"getconnectioncount",
+ return RPCHelpMan{"getconnectioncount",
"\nReturns the number of connections to other nodes.\n",
{},
RPCResult{
@@ -41,18 +50,20 @@ static UniValue getconnectioncount(const JSONRPCRequest& request)
HelpExampleCli("getconnectioncount", "")
+ HelpExampleRpc("getconnectioncount", "")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
NodeContext& node = EnsureNodeContext(request.context);
if(!node.connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
return (int)node.connman->GetNodeCount(CConnman::CONNECTIONS_ALL);
+},
+ };
}
-static UniValue ping(const JSONRPCRequest& request)
+static RPCHelpMan ping()
{
- RPCHelpMan{"ping",
+ return RPCHelpMan{"ping",
"\nRequests that a ping be sent to all other nodes, to measure ping time.\n"
"Results provided in getpeerinfo, pingtime and pingwait fields are decimal seconds.\n"
"Ping command is handled in queue with all other commands, so it measures processing backlog, not just network ping.\n",
@@ -62,8 +73,8 @@ static UniValue ping(const JSONRPCRequest& request)
HelpExampleCli("ping", "")
+ HelpExampleRpc("ping", "")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
NodeContext& node = EnsureNodeContext(request.context);
if(!node.connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
@@ -73,11 +84,13 @@ static UniValue ping(const JSONRPCRequest& request)
pnode->fPingQueued = true;
});
return NullUniValue;
+},
+ };
}
-static UniValue getpeerinfo(const JSONRPCRequest& request)
+static RPCHelpMan getpeerinfo()
{
- RPCHelpMan{"getpeerinfo",
+ return RPCHelpMan{"getpeerinfo",
"\nReturns data about each connected network node as a json array of objects.\n",
{},
RPCResult{
@@ -90,6 +103,7 @@ static UniValue getpeerinfo(const JSONRPCRequest& request)
{RPCResult::Type::STR, "addr", "(host:port) The IP address and port of the peer"},
{RPCResult::Type::STR, "addrbind", "(ip:port) Bind address of the connection to the peer"},
{RPCResult::Type::STR, "addrlocal", "(ip:port) Local address as reported by the peer"},
+ {RPCResult::Type::STR, "network", "Network (ipv4, ipv6, or onion) the peer connected through"},
{RPCResult::Type::NUM, "mapped_as", "The AS in the BGP route to the peer used for diversifying\n"
"peer selection (only available if the asmap config flag is set)"},
{RPCResult::Type::STR_HEX, "services", "The services offered"},
@@ -112,7 +126,11 @@ static UniValue getpeerinfo(const JSONRPCRequest& request)
{RPCResult::Type::NUM, "version", "The peer version, such as 70001"},
{RPCResult::Type::STR, "subver", "The string version"},
{RPCResult::Type::BOOL, "inbound", "Inbound (true) or Outbound (false)"},
- {RPCResult::Type::BOOL, "addnode", "Whether connection was due to addnode/-connect or if it was an automatic/inbound connection"},
+ {RPCResult::Type::BOOL, "addnode", "Whether connection was due to addnode/-connect or if it was an automatic/inbound connection\n"
+ "(DEPRECATED, returned only if the config option -deprecatedrpc=getpeerinfo_addnode is passed)"},
+ {RPCResult::Type::STR, "connection_type", "Type of connection: \n" + Join(CONNECTION_TYPE_DOC, ",\n") + ".\n"
+ "Please note this output is unlikely to be stable in upcoming releases as we iterate to\n"
+ "best capture connection behaviors."},
{RPCResult::Type::NUM, "startingheight", "The starting height (block) of the peer"},
{RPCResult::Type::NUM, "banscore", "The ban score (DEPRECATED, returned only if config option -deprecatedrpc=banscore is passed)"},
{RPCResult::Type::NUM, "synced_headers", "The last header we have in common with this peer"},
@@ -121,7 +139,8 @@ static UniValue getpeerinfo(const JSONRPCRequest& request)
{
{RPCResult::Type::NUM, "n", "The heights of blocks we're currently asking from this peer"},
}},
- {RPCResult::Type::BOOL, "whitelisted", "Whether the peer is whitelisted"},
+ {RPCResult::Type::BOOL, "whitelisted", /* optional */ true, "Whether the peer is whitelisted with default permissions\n"
+ "(DEPRECATED, returned only if config option -deprecatedrpc=whitelisted is passed)"},
{RPCResult::Type::NUM, "minfeefilter", "The minimum fee rate for transactions this peer accepts"},
{RPCResult::Type::OBJ_DYN, "bytessent_per_msg", "",
{
@@ -133,7 +152,8 @@ static UniValue getpeerinfo(const JSONRPCRequest& request)
{
{RPCResult::Type::NUM, "msg", "The total bytes received aggregated by message type\n"
"When a message type is not listed in this json object, the bytes received are 0.\n"
- "Only known message types can appear as keys in the object and all bytes received of unknown message types are listed under '"+NET_MESSAGE_COMMAND_OTHER+"'."}
+ "Only known message types can appear as keys in the object and all bytes received\n"
+ "of unknown message types are listed under '"+NET_MESSAGE_COMMAND_OTHER+"'."}
}},
}},
}},
@@ -142,8 +162,8 @@ static UniValue getpeerinfo(const JSONRPCRequest& request)
HelpExampleCli("getpeerinfo", "")
+ HelpExampleRpc("getpeerinfo", "")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
NodeContext& node = EnsureNodeContext(request.context);
if(!node.connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
@@ -159,10 +179,13 @@ static UniValue getpeerinfo(const JSONRPCRequest& request)
bool fStateStats = GetNodeStateStats(stats.nodeid, statestats);
obj.pushKV("id", stats.nodeid);
obj.pushKV("addr", stats.addrName);
- if (!(stats.addrLocal.empty()))
- obj.pushKV("addrlocal", stats.addrLocal);
- if (stats.addrBind.IsValid())
+ if (stats.addrBind.IsValid()) {
obj.pushKV("addrbind", stats.addrBind.ToString());
+ }
+ if (!(stats.addrLocal.empty())) {
+ obj.pushKV("addrlocal", stats.addrLocal);
+ }
+ obj.pushKV("network", stats.m_network);
if (stats.m_mapped_as != 0) {
obj.pushKV("mapped_as", uint64_t(stats.m_mapped_as));
}
@@ -192,7 +215,10 @@ static UniValue getpeerinfo(const JSONRPCRequest& request)
// their ver message.
obj.pushKV("subver", stats.cleanSubVer);
obj.pushKV("inbound", stats.fInbound);
- obj.pushKV("addnode", stats.m_manual_connection);
+ if (IsDeprecatedRPCEnabled("getpeerinfo_addnode")) {
+ // addnode is deprecated in v0.21 for removal in v0.22
+ obj.pushKV("addnode", stats.m_manual_connection);
+ }
obj.pushKV("startingheight", stats.nStartingHeight);
if (fStateStats) {
if (IsDeprecatedRPCEnabled("banscore")) {
@@ -207,7 +233,10 @@ static UniValue getpeerinfo(const JSONRPCRequest& request)
}
obj.pushKV("inflight", heights);
}
- obj.pushKV("whitelisted", stats.m_legacyWhitelisted);
+ if (IsDeprecatedRPCEnabled("whitelisted")) {
+ // whitelisted is deprecated in v0.21 for removal in v0.22
+ obj.pushKV("whitelisted", stats.m_legacyWhitelisted);
+ }
UniValue permissions(UniValue::VARR);
for (const auto& permission : NetPermissions::ToStrings(stats.m_permissionFlags)) {
permissions.push_back(permission);
@@ -228,22 +257,19 @@ static UniValue getpeerinfo(const JSONRPCRequest& request)
recvPerMsgCmd.pushKV(i.first, i.second);
}
obj.pushKV("bytesrecv_per_msg", recvPerMsgCmd);
+ obj.pushKV("connection_type", stats.m_conn_type_string);
ret.push_back(obj);
}
return ret;
+},
+ };
}
-static UniValue addnode(const JSONRPCRequest& request)
+static RPCHelpMan addnode()
{
- std::string strCommand;
- if (!request.params[1].isNull())
- strCommand = request.params[1].get_str();
- if (request.fHelp || request.params.size() != 2 ||
- (strCommand != "onetry" && strCommand != "add" && strCommand != "remove"))
- throw std::runtime_error(
- RPCHelpMan{"addnode",
+ return RPCHelpMan{"addnode",
"\nAttempts to add or remove a node from the addnode list.\n"
"Or try a connection to a node once.\n"
"Nodes added using addnode (or -connect) are protected from DoS disconnection and are not required to be\n"
@@ -257,7 +283,15 @@ static UniValue addnode(const JSONRPCRequest& request)
HelpExampleCli("addnode", "\"192.168.0.6:8333\" \"onetry\"")
+ HelpExampleRpc("addnode", "\"192.168.0.6:8333\", \"onetry\"")
},
- }.ToString());
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
+ std::string strCommand;
+ if (!request.params[1].isNull())
+ strCommand = request.params[1].get_str();
+ if (request.fHelp || request.params.size() != 2 ||
+ (strCommand != "onetry" && strCommand != "add" && strCommand != "remove"))
+ throw std::runtime_error(
+ self.ToString());
NodeContext& node = EnsureNodeContext(request.context);
if(!node.connman)
@@ -284,11 +318,13 @@ static UniValue addnode(const JSONRPCRequest& request)
}
return NullUniValue;
+},
+ };
}
-static UniValue disconnectnode(const JSONRPCRequest& request)
+static RPCHelpMan disconnectnode()
{
- RPCHelpMan{"disconnectnode",
+ return RPCHelpMan{"disconnectnode",
"\nImmediately disconnects from the specified peer node.\n"
"\nStrictly one out of 'address' and 'nodeid' can be provided to identify the node.\n"
"\nTo disconnect by nodeid, either set 'address' to the empty string, or call using the named 'nodeid' argument only.\n",
@@ -303,8 +339,8 @@ static UniValue disconnectnode(const JSONRPCRequest& request)
+ HelpExampleRpc("disconnectnode", "\"192.168.0.6:8333\"")
+ HelpExampleRpc("disconnectnode", "\"\", 1")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
NodeContext& node = EnsureNodeContext(request.context);
if(!node.connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
@@ -329,11 +365,13 @@ static UniValue disconnectnode(const JSONRPCRequest& request)
}
return NullUniValue;
+},
+ };
}
-static UniValue getaddednodeinfo(const JSONRPCRequest& request)
+static RPCHelpMan getaddednodeinfo()
{
- RPCHelpMan{"getaddednodeinfo",
+ return RPCHelpMan{"getaddednodeinfo",
"\nReturns information about the given added node, or all added nodes\n"
"(note that onetry addnodes are not listed here)\n",
{
@@ -361,8 +399,8 @@ static UniValue getaddednodeinfo(const JSONRPCRequest& request)
HelpExampleCli("getaddednodeinfo", "\"192.168.0.201\"")
+ HelpExampleRpc("getaddednodeinfo", "\"192.168.0.201\"")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
NodeContext& node = EnsureNodeContext(request.context);
if(!node.connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
@@ -401,11 +439,13 @@ static UniValue getaddednodeinfo(const JSONRPCRequest& request)
}
return ret;
+},
+ };
}
-static UniValue getnettotals(const JSONRPCRequest& request)
+static RPCHelpMan getnettotals()
{
- RPCHelpMan{"getnettotals",
+ return RPCHelpMan{"getnettotals",
"\nReturns information about network traffic, including bytes in, bytes out,\n"
"and current time.\n",
{},
@@ -414,7 +454,7 @@ static UniValue getnettotals(const JSONRPCRequest& request)
{
{RPCResult::Type::NUM, "totalbytesrecv", "Total bytes received"},
{RPCResult::Type::NUM, "totalbytessent", "Total bytes sent"},
- {RPCResult::Type::NUM_TIME, "timemillis", "Current UNIX time in milliseconds"},
+ {RPCResult::Type::NUM_TIME, "timemillis", "Current " + UNIX_EPOCH_TIME + " in milliseconds"},
{RPCResult::Type::OBJ, "uploadtarget", "",
{
{RPCResult::Type::NUM, "timeframe", "Length of the measuring timeframe in seconds"},
@@ -430,7 +470,8 @@ static UniValue getnettotals(const JSONRPCRequest& request)
HelpExampleCli("getnettotals", "")
+ HelpExampleRpc("getnettotals", "")
},
- }.Check(request);
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
NodeContext& node = EnsureNodeContext(request.context);
if(!node.connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
@@ -449,6 +490,8 @@ static UniValue getnettotals(const JSONRPCRequest& request)
outboundLimit.pushKV("time_left_in_cycle", node.connman->GetMaxOutboundTimeLeftInCycle());
obj.pushKV("uploadtarget", outboundLimit);
return obj;
+},
+ };
}
static UniValue GetNetworksInfo()
@@ -472,9 +515,9 @@ static UniValue GetNetworksInfo()
return networks;
}
-static UniValue getnetworkinfo(const JSONRPCRequest& request)
+static RPCHelpMan getnetworkinfo()
{
- RPCHelpMan{"getnetworkinfo",
+ return RPCHelpMan{"getnetworkinfo",
"Returns an object containing various state info regarding P2P networking.\n",
{},
RPCResult{
@@ -490,7 +533,9 @@ static UniValue getnetworkinfo(const JSONRPCRequest& request)
}},
{RPCResult::Type::BOOL, "localrelay", "true if transaction relay is requested from peers"},
{RPCResult::Type::NUM, "timeoffset", "the time offset"},
- {RPCResult::Type::NUM, "connections", "the number of connections"},
+ {RPCResult::Type::NUM, "connections", "the total number of connections"},
+ {RPCResult::Type::NUM, "connections_in", "the number of inbound connections"},
+ {RPCResult::Type::NUM, "connections_out", "the number of outbound connections"},
{RPCResult::Type::BOOL, "networkactive", "whether p2p networking is enabled"},
{RPCResult::Type::ARR, "networks", "information per network",
{
@@ -521,8 +566,8 @@ static UniValue getnetworkinfo(const JSONRPCRequest& request)
HelpExampleCli("getnetworkinfo", "")
+ HelpExampleRpc("getnetworkinfo", "")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
LOCK(cs_main);
UniValue obj(UniValue::VOBJ);
obj.pushKV("version", CLIENT_VERSION);
@@ -538,7 +583,9 @@ static UniValue getnetworkinfo(const JSONRPCRequest& request)
obj.pushKV("timeoffset", GetTimeOffset());
if (node.connman) {
obj.pushKV("networkactive", node.connman->GetNetworkActive());
- obj.pushKV("connections", (int)node.connman->GetNodeCount(CConnman::CONNECTIONS_ALL));
+ obj.pushKV("connections", (int)node.connman->GetNodeCount(CConnman::CONNECTIONS_ALL));
+ obj.pushKV("connections_in", (int)node.connman->GetNodeCount(CConnman::CONNECTIONS_IN));
+ obj.pushKV("connections_out", (int)node.connman->GetNodeCount(CConnman::CONNECTIONS_OUT));
}
obj.pushKV("networks", GetNetworksInfo());
obj.pushKV("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK()));
@@ -558,11 +605,13 @@ static UniValue getnetworkinfo(const JSONRPCRequest& request)
obj.pushKV("localaddresses", localAddresses);
obj.pushKV("warnings", GetWarnings(false).original);
return obj;
+},
+ };
}
-static UniValue setban(const JSONRPCRequest& request)
+static RPCHelpMan setban()
{
- const RPCHelpMan help{"setban",
+ return RPCHelpMan{"setban",
"\nAttempts to add or remove an IP/Subnet from the banned list.\n",
{
{"subnet", RPCArg::Type::STR, RPCArg::Optional::NO, "The IP/Subnet (see getpeerinfo for nodes IP) with an optional netmask (default is /32 = single IP)"},
@@ -576,7 +625,8 @@ static UniValue setban(const JSONRPCRequest& request)
+ HelpExampleCli("setban", "\"192.168.0.0/24\" \"add\"")
+ HelpExampleRpc("setban", "\"192.168.0.6\", \"add\", 86400")
},
- };
+ [&](const RPCHelpMan& help, const JSONRPCRequest& request) -> UniValue
+{
std::string strCommand;
if (!request.params[1].isNull())
strCommand = request.params[1].get_str();
@@ -639,11 +689,13 @@ static UniValue setban(const JSONRPCRequest& request)
}
}
return NullUniValue;
+},
+ };
}
-static UniValue listbanned(const JSONRPCRequest& request)
+static RPCHelpMan listbanned()
{
- RPCHelpMan{"listbanned",
+ return RPCHelpMan{"listbanned",
"\nList all manually banned IPs/Subnets.\n",
{},
RPCResult{RPCResult::Type::ARR, "", "",
@@ -659,8 +711,8 @@ static UniValue listbanned(const JSONRPCRequest& request)
HelpExampleCli("listbanned", "")
+ HelpExampleRpc("listbanned", "")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
NodeContext& node = EnsureNodeContext(request.context);
if(!node.banman) {
throw JSONRPCError(RPC_DATABASE_ERROR, "Error: Ban database not loaded");
@@ -682,11 +734,13 @@ static UniValue listbanned(const JSONRPCRequest& request)
}
return bannedAddresses;
+},
+ };
}
-static UniValue clearbanned(const JSONRPCRequest& request)
+static RPCHelpMan clearbanned()
{
- RPCHelpMan{"clearbanned",
+ return RPCHelpMan{"clearbanned",
"\nClear all banned IPs.\n",
{},
RPCResult{RPCResult::Type::NONE, "", ""},
@@ -694,7 +748,8 @@ static UniValue clearbanned(const JSONRPCRequest& request)
HelpExampleCli("clearbanned", "")
+ HelpExampleRpc("clearbanned", "")
},
- }.Check(request);
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
NodeContext& node = EnsureNodeContext(request.context);
if (!node.banman) {
throw JSONRPCError(RPC_DATABASE_ERROR, "Error: Ban database not loaded");
@@ -703,19 +758,21 @@ static UniValue clearbanned(const JSONRPCRequest& request)
node.banman->ClearBanned();
return NullUniValue;
+},
+ };
}
-static UniValue setnetworkactive(const JSONRPCRequest& request)
+static RPCHelpMan setnetworkactive()
{
- RPCHelpMan{"setnetworkactive",
+ return RPCHelpMan{"setnetworkactive",
"\nDisable/enable all p2p network activity.\n",
{
{"state", RPCArg::Type::BOOL, RPCArg::Optional::NO, "true to enable networking, false to disable"},
},
RPCResult{RPCResult::Type::BOOL, "", "The value that was passed in"},
RPCExamples{""},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
NodeContext& node = EnsureNodeContext(request.context);
if (!node.connman) {
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
@@ -724,11 +781,13 @@ static UniValue setnetworkactive(const JSONRPCRequest& request)
node.connman->SetNetworkActive(request.params[0].get_bool());
return node.connman->GetNetworkActive();
+},
+ };
}
-static UniValue getnodeaddresses(const JSONRPCRequest& request)
+static RPCHelpMan getnodeaddresses()
{
- RPCHelpMan{"getnodeaddresses",
+ return RPCHelpMan{"getnodeaddresses",
"\nReturn known addresses which can potentially be used to find new nodes in the network\n",
{
{"count", RPCArg::Type::NUM, /* default */ "1", "The maximum number of addresses to return. Specify 0 to return all known addresses."},
@@ -749,7 +808,8 @@ static UniValue getnodeaddresses(const JSONRPCRequest& request)
HelpExampleCli("getnodeaddresses", "8")
+ HelpExampleRpc("getnodeaddresses", "8")
},
- }.Check(request);
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
NodeContext& node = EnsureNodeContext(request.context);
if (!node.connman) {
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
@@ -775,11 +835,13 @@ static UniValue getnodeaddresses(const JSONRPCRequest& request)
ret.push_back(obj);
}
return ret;
+},
+ };
}
-static UniValue addpeeraddress(const JSONRPCRequest& request)
+static RPCHelpMan addpeeraddress()
{
- RPCHelpMan{"addpeeraddress",
+ return RPCHelpMan{"addpeeraddress",
"\nAdd the address of a potential peer to the address manager. This RPC is for testing only.\n",
{
{"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The IP address of the peer"},
@@ -795,8 +857,8 @@ static UniValue addpeeraddress(const JSONRPCRequest& request)
HelpExampleCli("addpeeraddress", "\"1.2.3.4\" 8333")
+ HelpExampleRpc("addpeeraddress", "\"1.2.3.4\", 8333")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
NodeContext& node = EnsureNodeContext(request.context);
if (!node.connman) {
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
@@ -823,6 +885,8 @@ static UniValue addpeeraddress(const JSONRPCRequest& request)
obj.pushKV("success", true);
return obj;
+},
+ };
}
void RegisterNetRPCCommands(CRPCTable &t)
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 5354b4a681..c6d7fea443 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -67,9 +67,9 @@ static void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue&
}
}
-static UniValue getrawtransaction(const JSONRPCRequest& request)
+static RPCHelpMan getrawtransaction()
{
- RPCHelpMan{
+ return RPCHelpMan{
"getrawtransaction",
"\nReturn the raw transaction data.\n"
@@ -155,8 +155,8 @@ static UniValue getrawtransaction(const JSONRPCRequest& request)
+ HelpExampleCli("getrawtransaction", "\"mytxid\" false \"myblockhash\"")
+ HelpExampleCli("getrawtransaction", "\"mytxid\" true \"myblockhash\"")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
const NodeContext& node = EnsureNodeContext(request.context);
bool in_active_chain = true;
@@ -191,7 +191,7 @@ static UniValue getrawtransaction(const JSONRPCRequest& request)
}
uint256 hash_block;
- const CTransactionRef tx = GetTransaction(blockindex, node.mempool, hash, Params().GetConsensus(), hash_block);
+ const CTransactionRef tx = GetTransaction(blockindex, node.mempool.get(), hash, Params().GetConsensus(), hash_block);
if (!tx) {
std::string errmsg;
if (blockindex) {
@@ -217,11 +217,13 @@ static UniValue getrawtransaction(const JSONRPCRequest& request)
if (blockindex) result.pushKV("in_active_chain", in_active_chain);
TxToJSON(*tx, hash_block, result);
return result;
+},
+ };
}
-static UniValue gettxoutproof(const JSONRPCRequest& request)
+static RPCHelpMan gettxoutproof()
{
- RPCHelpMan{"gettxoutproof",
+ return RPCHelpMan{"gettxoutproof",
"\nReturns a hex-encoded proof that \"txid\" was included in a block.\n"
"\nNOTE: By default this function only works sometimes. This is when there is an\n"
"unspent output in the utxo for this transaction. To make it always work,\n"
@@ -239,8 +241,8 @@ static UniValue gettxoutproof(const JSONRPCRequest& request)
RPCResult::Type::STR, "data", "A string that is a serialized, hex-encoded data for the proof."
},
RPCExamples{""},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
std::set<uint256> setTxids;
uint256 oneTxid;
UniValue txids = request.params[0].get_array();
@@ -315,11 +317,13 @@ static UniValue gettxoutproof(const JSONRPCRequest& request)
ssMB << mb;
std::string strHex = HexStr(ssMB);
return strHex;
+},
+ };
}
-static UniValue verifytxoutproof(const JSONRPCRequest& request)
+static RPCHelpMan verifytxoutproof()
{
- RPCHelpMan{"verifytxoutproof",
+ return RPCHelpMan{"verifytxoutproof",
"\nVerifies that a proof points to a transaction in a block, returning the transaction it commits to\n"
"and throwing an RPC error if the block is not in our best chain\n",
{
@@ -332,8 +336,8 @@ static UniValue verifytxoutproof(const JSONRPCRequest& request)
}
},
RPCExamples{""},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
CDataStream ssMB(ParseHexV(request.params[0], "proof"), SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS);
CMerkleBlock merkleBlock;
ssMB >> merkleBlock;
@@ -360,11 +364,13 @@ static UniValue verifytxoutproof(const JSONRPCRequest& request)
}
return res;
+},
+ };
}
-static UniValue createrawtransaction(const JSONRPCRequest& request)
+static RPCHelpMan createrawtransaction()
{
- RPCHelpMan{"createrawtransaction",
+ return RPCHelpMan{"createrawtransaction",
"\nCreate a transaction spending the given inputs and creating new outputs.\n"
"Outputs can be addresses or data.\n"
"Returns hex-encoded raw transaction.\n"
@@ -412,8 +418,8 @@ static UniValue createrawtransaction(const JSONRPCRequest& request)
+ HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"[{\\\"address\\\":0.01}]\"")
+ HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"[{\\\"data\\\":\\\"00010203\\\"}]\"")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
RPCTypeCheck(request.params, {
UniValue::VARR,
UniValueType(), // ARR or OBJ, checked later
@@ -429,11 +435,13 @@ static UniValue createrawtransaction(const JSONRPCRequest& request)
CMutableTransaction rawTx = ConstructTransaction(request.params[0], request.params[1], request.params[2], rbf);
return EncodeHexTx(CTransaction(rawTx));
+},
+ };
}
-static UniValue decoderawtransaction(const JSONRPCRequest& request)
+static RPCHelpMan decoderawtransaction()
{
- RPCHelpMan{"decoderawtransaction",
+ return RPCHelpMan{"decoderawtransaction",
"\nReturn a JSON object representing the serialized, hex-encoded transaction.\n",
{
{"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction hex string"},
@@ -498,8 +506,8 @@ static UniValue decoderawtransaction(const JSONRPCRequest& request)
HelpExampleCli("decoderawtransaction", "\"hexstring\"")
+ HelpExampleRpc("decoderawtransaction", "\"hexstring\"")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL});
CMutableTransaction mtx;
@@ -515,6 +523,8 @@ static UniValue decoderawtransaction(const JSONRPCRequest& request)
TxToUniv(CTransaction(std::move(mtx)), uint256(), result, false);
return result;
+},
+ };
}
static std::string GetAllOutputTypes()
@@ -527,9 +537,9 @@ static std::string GetAllOutputTypes()
return Join(ret, ", ");
}
-static UniValue decodescript(const JSONRPCRequest& request)
+static RPCHelpMan decodescript()
{
- RPCHelpMan{"decodescript",
+ return RPCHelpMan{"decodescript",
"\nDecode a hex-encoded script.\n",
{
{"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hex-encoded script"},
@@ -563,8 +573,8 @@ static UniValue decodescript(const JSONRPCRequest& request)
HelpExampleCli("decodescript", "\"hexstring\"")
+ HelpExampleRpc("decodescript", "\"hexstring\"")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
RPCTypeCheck(request.params, {UniValue::VSTR});
UniValue r(UniValue::VOBJ);
@@ -616,18 +626,20 @@ static UniValue decodescript(const JSONRPCRequest& request)
}
return r;
+},
+ };
}
-static UniValue combinerawtransaction(const JSONRPCRequest& request)
+static RPCHelpMan combinerawtransaction()
{
- RPCHelpMan{"combinerawtransaction",
+ return RPCHelpMan{"combinerawtransaction",
"\nCombine multiple partially signed transactions into one transaction.\n"
"The combined transaction may be another partially signed transaction or a \n"
"fully signed transaction.",
{
{"txs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The hex strings of partially signed transactions",
{
- {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "A transaction hash"},
+ {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "A hex-encoded raw transaction"},
},
},
},
@@ -637,8 +649,8 @@ static UniValue combinerawtransaction(const JSONRPCRequest& request)
RPCExamples{
HelpExampleCli("combinerawtransaction", R"('["myhex1", "myhex2", "myhex3"]')")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
UniValue txs = request.params[0].get_array();
std::vector<CMutableTransaction> txVariants(txs.size());
@@ -699,11 +711,13 @@ static UniValue combinerawtransaction(const JSONRPCRequest& request)
}
return EncodeHexTx(CTransaction(mergedTx));
+},
+ };
}
-static UniValue signrawtransactionwithkey(const JSONRPCRequest& request)
+static RPCHelpMan signrawtransactionwithkey()
{
- RPCHelpMan{"signrawtransactionwithkey",
+ return RPCHelpMan{"signrawtransactionwithkey",
"\nSign inputs for raw transaction (serialized, hex-encoded).\n"
"The second argument is an array of base58-encoded private\n"
"keys that will be the only keys used to sign the transaction.\n"
@@ -761,8 +775,8 @@ static UniValue signrawtransactionwithkey(const JSONRPCRequest& request)
HelpExampleCli("signrawtransactionwithkey", "\"myhex\" \"[\\\"key1\\\",\\\"key2\\\"]\"")
+ HelpExampleRpc("signrawtransactionwithkey", "\"myhex\", \"[\\\"key1\\\",\\\"key2\\\"]\"")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR, UniValue::VARR, UniValue::VSTR}, true);
CMutableTransaction mtx;
@@ -795,11 +809,13 @@ static UniValue signrawtransactionwithkey(const JSONRPCRequest& request)
UniValue result(UniValue::VOBJ);
SignTransaction(mtx, &keystore, coins, request.params[3], result);
return result;
+},
+ };
}
-static UniValue sendrawtransaction(const JSONRPCRequest& request)
+static RPCHelpMan sendrawtransaction()
{
- RPCHelpMan{"sendrawtransaction",
+ return RPCHelpMan{"sendrawtransaction",
"\nSubmit a raw transaction (serialized, hex-encoded) to local node and network.\n"
"\nNote that the transaction will be sent unconditionally to all peers, so using this\n"
"for manual rebroadcast may degrade privacy by leaking the transaction's origin, as\n"
@@ -824,8 +840,8 @@ static UniValue sendrawtransaction(const JSONRPCRequest& request)
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("sendrawtransaction", "\"signedhex\"")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
RPCTypeCheck(request.params, {
UniValue::VSTR,
UniValueType(), // VNUM or VSTR, checked inside AmountFromValue()
@@ -853,11 +869,13 @@ static UniValue sendrawtransaction(const JSONRPCRequest& request)
}
return tx->GetHash().GetHex();
+},
+ };
}
-static UniValue testmempoolaccept(const JSONRPCRequest& request)
+static RPCHelpMan testmempoolaccept()
{
- RPCHelpMan{"testmempoolaccept",
+ return RPCHelpMan{"testmempoolaccept",
"\nReturns result of mempool acceptance tests indicating if raw transaction (serialized, hex-encoded) would be accepted by mempool.\n"
"\nThis checks if the transaction violates the consensus or policy rules.\n"
"\nSee sendrawtransaction call.\n",
@@ -878,6 +896,11 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request)
{
{RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"},
{RPCResult::Type::BOOL, "allowed", "If the mempool allows this tx to be inserted"},
+ {RPCResult::Type::NUM, "vsize", "Virtual transaction size as defined in BIP 141. This is different from actual serialized size for witness transactions as witness data is discounted (only present when 'allowed' is true)"},
+ {RPCResult::Type::OBJ, "fees", "Transaction fees (only present if 'allowed' is true)",
+ {
+ {RPCResult::Type::STR_AMOUNT, "base", "transaction fee in " + CURRENCY_UNIT},
+ }},
{RPCResult::Type::STR, "reject-reason", "Rejection string (only present when 'allowed' is false)"},
}},
}
@@ -892,8 +915,8 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request)
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("testmempoolaccept", "[\"signedhex\"]")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
RPCTypeCheck(request.params, {
UniValue::VARR,
UniValueType(), // VNUM or VSTR, checked inside AmountFromValue()
@@ -924,13 +947,30 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request)
TxValidationState state;
bool test_accept_res;
+ CAmount fee{0};
{
LOCK(cs_main);
test_accept_res = AcceptToMemoryPool(mempool, state, std::move(tx),
- nullptr /* plTxnReplaced */, false /* bypass_limits */, max_raw_tx_fee, /* test_accept */ true);
+ nullptr /* plTxnReplaced */, false /* bypass_limits */, /* test_accept */ true, &fee);
+ }
+
+ // Check that fee does not exceed maximum fee
+ if (test_accept_res && max_raw_tx_fee && fee > max_raw_tx_fee) {
+ result_0.pushKV("allowed", false);
+ result_0.pushKV("reject-reason", "max-fee-exceeded");
+ result.push_back(std::move(result_0));
+ return result;
}
result_0.pushKV("allowed", test_accept_res);
- if (!test_accept_res) {
+
+ // Only return the fee and vsize if the transaction would pass ATMP.
+ // These can be used to calculate the feerate.
+ if (test_accept_res) {
+ result_0.pushKV("vsize", virtual_size);
+ UniValue fees(UniValue::VOBJ);
+ fees.pushKV("base", ValueFromAmount(fee));
+ result_0.pushKV("fees", fees);
+ } else {
if (state.IsInvalid()) {
if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) {
result_0.pushKV("reject-reason", "missing-inputs");
@@ -944,11 +984,13 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request)
result.push_back(std::move(result_0));
return result;
+},
+ };
}
-UniValue decodepsbt(const JSONRPCRequest& request)
+static RPCHelpMan decodepsbt()
{
- RPCHelpMan{"decodepsbt",
+ return RPCHelpMan{"decodepsbt",
"\nReturn a JSON object representing the serialized, base64-encoded partially signed Bitcoin transaction.\n",
{
{"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "The PSBT base64 string"},
@@ -1060,8 +1102,8 @@ UniValue decodepsbt(const JSONRPCRequest& request)
RPCExamples{
HelpExampleCli("decodepsbt", "\"psbt\"")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
RPCTypeCheck(request.params, {UniValue::VSTR});
// Unserialize the transactions
@@ -1253,11 +1295,13 @@ UniValue decodepsbt(const JSONRPCRequest& request)
}
return result;
+},
+ };
}
-UniValue combinepsbt(const JSONRPCRequest& request)
+static RPCHelpMan combinepsbt()
{
- RPCHelpMan{"combinepsbt",
+ return RPCHelpMan{"combinepsbt",
"\nCombine multiple partially signed Bitcoin transactions into one transaction.\n"
"Implements the Combiner role.\n",
{
@@ -1273,8 +1317,8 @@ UniValue combinepsbt(const JSONRPCRequest& request)
RPCExamples{
HelpExampleCli("combinepsbt", R"('["mybase64_1", "mybase64_2", "mybase64_3"]')")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
RPCTypeCheck(request.params, {UniValue::VARR}, true);
// Unserialize the transactions
@@ -1301,11 +1345,13 @@ UniValue combinepsbt(const JSONRPCRequest& request)
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
ssTx << merged_psbt;
return EncodeBase64(MakeUCharSpan(ssTx));
+},
+ };
}
-UniValue finalizepsbt(const JSONRPCRequest& request)
+static RPCHelpMan finalizepsbt()
{
- RPCHelpMan{"finalizepsbt",
+ return RPCHelpMan{"finalizepsbt",
"Finalize the inputs of a PSBT. If the transaction is fully signed, it will produce a\n"
"network serialized transaction which can be broadcast with sendrawtransaction. Otherwise a PSBT will be\n"
"created which has the final_scriptSig and final_scriptWitness fields filled for inputs that are complete.\n"
@@ -1326,8 +1372,8 @@ UniValue finalizepsbt(const JSONRPCRequest& request)
RPCExamples{
HelpExampleCli("finalizepsbt", "\"psbt\"")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL}, true);
// Unserialize the transactions
@@ -1358,11 +1404,13 @@ UniValue finalizepsbt(const JSONRPCRequest& request)
result.pushKV("complete", complete);
return result;
+},
+ };
}
-UniValue createpsbt(const JSONRPCRequest& request)
+static RPCHelpMan createpsbt()
{
- RPCHelpMan{"createpsbt",
+ return RPCHelpMan{"createpsbt",
"\nCreates a transaction in the Partially Signed Transaction format.\n"
"Implements the Creator role.\n",
{
@@ -1404,8 +1452,8 @@ UniValue createpsbt(const JSONRPCRequest& request)
RPCExamples{
HelpExampleCli("createpsbt", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"[{\\\"data\\\":\\\"00010203\\\"}]\"")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
RPCTypeCheck(request.params, {
UniValue::VARR,
@@ -1436,11 +1484,13 @@ UniValue createpsbt(const JSONRPCRequest& request)
ssTx << psbtx;
return EncodeBase64(MakeUCharSpan(ssTx));
+},
+ };
}
-UniValue converttopsbt(const JSONRPCRequest& request)
+static RPCHelpMan converttopsbt()
{
- RPCHelpMan{"converttopsbt",
+ return RPCHelpMan{"converttopsbt",
"\nConverts a network serialized transaction to a PSBT. This should be used only with createrawtransaction and fundrawtransaction\n"
"createpsbt and walletcreatefundedpsbt should be used for new applications.\n",
{
@@ -1464,8 +1514,8 @@ UniValue converttopsbt(const JSONRPCRequest& request)
"\nConvert the transaction to a PSBT\n"
+ HelpExampleCli("converttopsbt", "\"rawtransaction\"")
},
- }.Check(request);
-
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL, UniValue::VBOOL}, true);
// parse hex string from parameter
@@ -1503,11 +1553,13 @@ UniValue converttopsbt(const JSONRPCRequest& request)
ssTx << psbtx;
return EncodeBase64(MakeUCharSpan(ssTx));
+},
+ };
}
-UniValue utxoupdatepsbt(const JSONRPCRequest& request)
+static RPCHelpMan utxoupdatepsbt()
{
- RPCHelpMan{"utxoupdatepsbt",
+ return RPCHelpMan{"utxoupdatepsbt",
"\nUpdates all segwit inputs and outputs in a PSBT with data from output descriptors, the UTXO set or the mempool.\n",
{
{"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "A base64 string of a PSBT"},
@@ -1524,8 +1576,9 @@ UniValue utxoupdatepsbt(const JSONRPCRequest& request)
},
RPCExamples {
HelpExampleCli("utxoupdatepsbt", "\"psbt\"")
- }}.Check(request);
-
+ },
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR}, true);
// Unserialize the transactions
@@ -1591,11 +1644,13 @@ UniValue utxoupdatepsbt(const JSONRPCRequest& request)
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
ssTx << psbtx;
return EncodeBase64(MakeUCharSpan(ssTx));
+},
+ };
}
-UniValue joinpsbts(const JSONRPCRequest& request)
+static RPCHelpMan joinpsbts()
{
- RPCHelpMan{"joinpsbts",
+ return RPCHelpMan{"joinpsbts",
"\nJoins multiple distinct PSBTs with different inputs and outputs into one PSBT with inputs and outputs from all of the PSBTs\n"
"No input in any of the PSBTs can be in more than one of the PSBTs.\n",
{
@@ -1609,8 +1664,9 @@ UniValue joinpsbts(const JSONRPCRequest& request)
},
RPCExamples {
HelpExampleCli("joinpsbts", "\"psbt\"")
- }}.Check(request);
-
+ },
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
RPCTypeCheck(request.params, {UniValue::VARR}, true);
// Unserialize the transactions
@@ -1684,11 +1740,13 @@ UniValue joinpsbts(const JSONRPCRequest& request)
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
ssTx << shuffled_psbt;
return EncodeBase64(MakeUCharSpan(ssTx));
+},
+ };
}
-UniValue analyzepsbt(const JSONRPCRequest& request)
+static RPCHelpMan analyzepsbt()
{
- RPCHelpMan{"analyzepsbt",
+ return RPCHelpMan{"analyzepsbt",
"\nAnalyzes and provides information about the current status of a PSBT and its inputs\n",
{
{"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "A base64 string of a PSBT"}
@@ -1727,8 +1785,9 @@ UniValue analyzepsbt(const JSONRPCRequest& request)
},
RPCExamples {
HelpExampleCli("analyzepsbt", "\"psbt\"")
- }}.Check(request);
-
+ },
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
RPCTypeCheck(request.params, {UniValue::VSTR});
// Unserialize the transaction
@@ -1792,6 +1851,8 @@ UniValue analyzepsbt(const JSONRPCRequest& request)
}
return result;
+},
+ };
}
void RegisterRawTransactionRPCCommands(CRPCTable &t)
diff --git a/src/rpc/rawtransaction_util.cpp b/src/rpc/rawtransaction_util.cpp
index 1031716b4a..f004ecc20c 100644
--- a/src/rpc/rawtransaction_util.cpp
+++ b/src/rpc/rawtransaction_util.cpp
@@ -21,10 +21,17 @@
CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, bool rbf)
{
- if (inputs_in.isNull() || outputs_in.isNull())
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, arguments 1 and 2 must be non-null");
+ if (outputs_in.isNull()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, output argument must be non-null");
+ }
+
+ UniValue inputs;
+ if (inputs_in.isNull()) {
+ inputs = UniValue::VARR;
+ } else {
+ inputs = inputs_in.get_array();
+ }
- UniValue inputs = inputs_in.get_array();
const bool outputs_is_obj = outputs_in.isObject();
UniValue outputs = outputs_is_obj ? outputs_in.get_obj() : outputs_in.get_array();
@@ -48,7 +55,7 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key");
int nOutput = vout_v.get_int();
if (nOutput < 0)
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout cannot be negative");
uint32_t nSequence;
if (rbf) {
@@ -170,7 +177,7 @@ void ParsePrevouts(const UniValue& prevTxsUnival, FillableSigningProvider* keyst
int nOut = find_value(prevOut, "vout").get_int();
if (nOut < 0) {
- throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive");
+ throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout cannot be negative");
}
COutPoint out(txid, nOut);
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index 9c8e7fe04a..f32d9abac6 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -261,13 +261,11 @@ CRPCTable::CRPCTable()
}
}
-bool CRPCTable::appendCommand(const std::string& name, const CRPCCommand* pcmd)
+void CRPCTable::appendCommand(const std::string& name, const CRPCCommand* pcmd)
{
- if (IsRPCRunning())
- return false;
+ CHECK_NONFATAL(!IsRPCRunning()); // Only add commands before rpc is running
mapCommands[name].push_back(pcmd);
- return true;
}
bool CRPCTable::removeCommand(const std::string& name, const CRPCCommand* pcmd)
diff --git a/src/rpc/server.h b/src/rpc/server.h
index 6da3e94ea2..b2358ac5b2 100644
--- a/src/rpc/server.h
+++ b/src/rpc/server.h
@@ -160,7 +160,7 @@ public:
/**
* Appends a CRPCCommand to the dispatch table.
*
- * Returns false if RPC server is already running (dump concurrency protection).
+ * Precondition: RPC server is not running
*
* Commands with different method names but the same unique_id will
* be considered aliases, and only the first registered method name will
@@ -169,7 +169,7 @@ public:
* between calls based on method name, and aliased commands can also
* register different names, types, and numbers of parameters.
*/
- bool appendCommand(const std::string& name, const CRPCCommand* pcmd);
+ void appendCommand(const std::string& name, const CRPCCommand* pcmd);
bool removeCommand(const std::string& name, const CRPCCommand* pcmd);
};