aboutsummaryrefslogtreecommitdiff
path: root/src/rpc
diff options
context:
space:
mode:
Diffstat (limited to 'src/rpc')
-rw-r--r--src/rpc/blockchain.cpp32
-rw-r--r--src/rpc/client.cpp8
-rw-r--r--src/rpc/mining.cpp213
-rw-r--r--src/rpc/misc.cpp16
-rw-r--r--src/rpc/net.cpp2
-rw-r--r--src/rpc/rawtransaction.cpp36
-rw-r--r--src/rpc/rawtransaction_util.cpp2
-rw-r--r--src/rpc/rawtransaction_util.h2
-rw-r--r--src/rpc/util.cpp36
-rw-r--r--src/rpc/util.h14
10 files changed, 262 insertions, 99 deletions
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index f71ed99652..827b83d67e 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -375,8 +375,6 @@ static UniValue getdifficulty(const JSONRPCRequest& request)
static std::vector<RPCResult> MempoolEntryDescription() { return {
RPCResult{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."},
- RPCResult{RPCResult::Type::NUM, "size", "(DEPRECATED) same as vsize. Only returned if bitcoind is started with -deprecatedrpc=size\n"
- "size will be completely removed in v0.20."},
RPCResult{RPCResult::Type::NUM, "weight", "transaction weight as defined in BIP 141."},
RPCResult{RPCResult::Type::STR_AMOUNT, "fee", "transaction fee in " + CURRENCY_UNIT + " (DEPRECATED)"},
RPCResult{RPCResult::Type::STR_AMOUNT, "modifiedfee", "transaction fee with fee deltas used for mining priority (DEPRECATED)"},
@@ -415,7 +413,6 @@ static void entryToJSON(const CTxMemPool& pool, UniValue& info, const CTxMemPool
info.pushKV("fees", fees);
info.pushKV("vsize", (int)e.GetTxSize());
- if (IsDeprecatedRPCEnabled("size")) info.pushKV("size", (int)e.GetTxSize());
info.pushKV("weight", (int)e.GetTxWeight());
info.pushKV("fee", ValueFromAmount(e.GetFee()));
info.pushKV("modifiedfee", ValueFromAmount(e.GetModifiedFee()));
@@ -812,7 +809,7 @@ static UniValue getblock(const JSONRPCRequest& request)
"If verbosity is 2, returns an Object with information about block <hash> and information about each transaction. \n",
{
{"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash"},
- {"verbosity", RPCArg::Type::NUM, /* default */ "1", "0 for hex-encoded data, 1 for a json object, and 2 for json object with transaction data"},
+ {"verbosity|verbose", RPCArg::Type::NUM, /* default */ "1", "0 for hex-encoded data, 1 for a json object, and 2 for json object with transaction data"},
},
{
RPCResult{"for verbosity = 0",
@@ -1078,13 +1075,11 @@ UniValue gettxout(const JSONRPCRequest& request)
static UniValue verifychain(const JSONRPCRequest& request)
{
- int nCheckLevel = gArgs.GetArg("-checklevel", DEFAULT_CHECKLEVEL);
- int nCheckDepth = gArgs.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS);
RPCHelpMan{"verifychain",
"\nVerifies blockchain database.\n",
{
- {"checklevel", RPCArg::Type::NUM, /* default */ strprintf("%d, range=0-4", nCheckLevel), "How thorough the block verification is."},
- {"nblocks", RPCArg::Type::NUM, /* default */ strprintf("%d, 0=all", nCheckDepth), "The number of blocks to check."},
+ {"checklevel", RPCArg::Type::NUM, /* default */ strprintf("%d, range=0-4", DEFAULT_CHECKLEVEL), "How thorough the block verification is."},
+ {"nblocks", RPCArg::Type::NUM, /* default */ strprintf("%d, 0=all", DEFAULT_CHECKBLOCKS), "The number of blocks to check."},
},
RPCResult{
RPCResult::Type::BOOL, "", "Verified or not"},
@@ -1094,15 +1089,12 @@ static UniValue verifychain(const JSONRPCRequest& request)
},
}.Check(request);
- LOCK(cs_main);
+ 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()};
- if (!request.params[0].isNull())
- nCheckLevel = request.params[0].get_int();
- if (!request.params[1].isNull())
- nCheckDepth = request.params[1].get_int();
+ LOCK(cs_main);
- return CVerifyDB().VerifyDB(
- Params(), &::ChainstateActive().CoinsTip(), nCheckLevel, nCheckDepth);
+ 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)
@@ -1319,7 +1311,7 @@ static UniValue getchaintips(const JSONRPCRequest& request)
/*
* Idea: the set of chain tips is ::ChainActive().tip, plus orphan blocks which do not have another orphan building off of them.
* Algorithm:
- * - Make one pass through g_blockman.m_block_index, picking out the orphan blocks, and also storing a set of the orphan block's pprev pointers.
+ * - Make one pass through BlockIndex(), picking out the orphan blocks, and also storing a set of the orphan block's pprev pointers.
* - Iterate through the orphan blocks. If the block isn't pointed to by another orphan, it is a chain tip.
* - add ::ChainActive().Tip()
*/
@@ -1726,8 +1718,10 @@ static UniValue getblockstats(const JSONRPCRequest& request)
{RPCResult::Type::NUM, "utxo_size_inc", "The increase/decrease in size for the utxo index (not discounting op_return and similar)"},
}},
RPCExamples{
- HelpExampleCli("getblockstats", "1000 '[\"minfeerate\",\"avgfeerate\"]'")
- + HelpExampleRpc("getblockstats", "1000 '[\"minfeerate\",\"avgfeerate\"]'")
+ HelpExampleCli("getblockstats", R"('"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09"' '["minfeerate","avgfeerate"]')") +
+ HelpExampleCli("getblockstats", R"(1000 '["minfeerate","avgfeerate"]')") +
+ HelpExampleRpc("getblockstats", R"("00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09", ["minfeerate","avgfeerate"])") +
+ HelpExampleRpc("getblockstats", R"(1000, ["minfeerate","avgfeerate"])")
},
}.Check(request);
diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp
index c1762483e9..3045a74d7a 100644
--- a/src/rpc/client.cpp
+++ b/src/rpc/client.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -33,6 +33,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "generatetoaddress", 2, "maxtries" },
{ "generatetodescriptor", 0, "num_blocks" },
{ "generatetodescriptor", 2, "maxtries" },
+ { "generateblock", 1, "transactions" },
{ "getnetworkhashps", 0, "nblocks" },
{ "getnetworkhashps", 1, "height" },
{ "sendtoaddress", 1, "amount" },
@@ -97,10 +98,8 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "signrawtransactionwithkey", 1, "privkeys" },
{ "signrawtransactionwithkey", 2, "prevtxs" },
{ "signrawtransactionwithwallet", 1, "prevtxs" },
- { "sendrawtransaction", 1, "allowhighfees" },
{ "sendrawtransaction", 1, "maxfeerate" },
{ "testmempoolaccept", 0, "rawtxs" },
- { "testmempoolaccept", 1, "allowhighfees" },
{ "testmempoolaccept", 1, "maxfeerate" },
{ "combinerawtransaction", 0, "txs" },
{ "fundrawtransaction", 1, "options" },
@@ -132,6 +131,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "importpubkey", 2, "rescan" },
{ "importmulti", 0, "requests" },
{ "importmulti", 1, "options" },
+ { "importdescriptors", 0, "requests" },
{ "verifychain", 0, "checklevel" },
{ "verifychain", 1, "nblocks" },
{ "getblockstats", 0, "hash_or_height" },
@@ -154,6 +154,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "logging", 0, "include" },
{ "logging", 1, "exclude" },
{ "disconnectnode", 1, "nodeid" },
+ { "upgradewallet", 0, "version" },
// Echo with conversion (For testing only)
{ "echojson", 0, "arg0" },
{ "echojson", 1, "arg1" },
@@ -170,6 +171,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "createwallet", 1, "disable_private_keys"},
{ "createwallet", 2, "blank"},
{ "createwallet", 4, "avoid_reuse"},
+ { "createwallet", 5, "descriptors"},
{ "getnodeaddresses", 0, "count"},
{ "stop", 0, "wait" },
};
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index da9d583fa7..05d3fd6afb 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -101,6 +101,36 @@ static UniValue getnetworkhashps(const JSONRPCRequest& request)
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(CBlock& block, uint64_t& max_tries, unsigned int& extra_nonce, uint256& block_hash)
+{
+ block_hash.SetNull();
+
+ {
+ LOCK(cs_main);
+ IncrementExtraNonce(&block, ::ChainActive().Tip(), extra_nonce);
+ }
+
+ CChainParams chainparams(Params());
+
+ while (max_tries > 0 && block.nNonce < std::numeric_limits<uint32_t>::max() && !CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus()) && !ShutdownRequested()) {
+ ++block.nNonce;
+ --max_tries;
+ }
+ if (max_tries == 0 || ShutdownRequested()) {
+ return false;
+ }
+ if (block.nNonce == std::numeric_limits<uint32_t>::max()) {
+ return true;
+ }
+
+ std::shared_ptr<const CBlock> shared_pblock = std::make_shared<const CBlock>(block);
+ if (!ProcessNewBlock(chainparams, shared_pblock, true, nullptr))
+ throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted");
+
+ block_hash = block.GetHash();
+ return true;
+}
+
static UniValue generateBlocks(const CTxMemPool& mempool, const CScript& coinbase_script, int nGenerate, uint64_t nMaxTries)
{
int nHeightEnd = 0;
@@ -119,29 +149,54 @@ static UniValue generateBlocks(const CTxMemPool& mempool, const CScript& coinbas
if (!pblocktemplate.get())
throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block");
CBlock *pblock = &pblocktemplate->block;
- {
- LOCK(cs_main);
- IncrementExtraNonce(pblock, ::ChainActive().Tip(), nExtraNonce);
- }
- while (nMaxTries > 0 && pblock->nNonce < std::numeric_limits<uint32_t>::max() && !CheckProofOfWork(pblock->GetHash(), pblock->nBits, Params().GetConsensus()) && !ShutdownRequested()) {
- ++pblock->nNonce;
- --nMaxTries;
- }
- if (nMaxTries == 0 || ShutdownRequested()) {
+
+ uint256 block_hash;
+ if (!GenerateBlock(*pblock, nMaxTries, nExtraNonce, block_hash)) {
break;
}
- if (pblock->nNonce == std::numeric_limits<uint32_t>::max()) {
- continue;
+
+ if (!block_hash.IsNull()) {
+ ++nHeight;
+ blockHashes.push_back(block_hash.GetHex());
}
- std::shared_ptr<const CBlock> shared_pblock = std::make_shared<const CBlock>(*pblock);
- if (!ProcessNewBlock(Params(), shared_pblock, true, nullptr))
- throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted");
- ++nHeight;
- blockHashes.push_back(pblock->GetHash().GetHex());
}
return blockHashes;
}
+static bool getScriptFromDescriptor(const std::string& descriptor, CScript& script, std::string& error)
+{
+ FlatSigningProvider key_provider;
+ const auto desc = Parse(descriptor, key_provider, error, /* require_checksum = */ false);
+ if (desc) {
+ if (desc->IsRange()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Ranged descriptor not accepted. Maybe pass through deriveaddresses first?");
+ }
+
+ FlatSigningProvider provider;
+ std::vector<CScript> scripts;
+ if (!desc->Expand(0, key_provider, scripts, provider)) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Cannot derive script without private keys"));
+ }
+
+ // Combo desriptors can have 2 or 4 scripts, so we can't just check scripts.size() == 1
+ CHECK_NONFATAL(scripts.size() > 0 && scripts.size() <= 4);
+
+ if (scripts.size() == 1) {
+ script = scripts.at(0);
+ } else if (scripts.size() == 4) {
+ // For uncompressed keys, take the 3rd script, since it is p2wpkh
+ script = scripts.at(2);
+ } else {
+ // Else take the 2nd script, since it is p2pkh
+ script = scripts.at(1);
+ }
+
+ return true;
+ } else {
+ return false;
+ }
+}
+
static UniValue generatetodescriptor(const JSONRPCRequest& request)
{
RPCHelpMan{
@@ -166,27 +221,15 @@ static UniValue generatetodescriptor(const JSONRPCRequest& request)
const int num_blocks{request.params[0].get_int()};
const int64_t max_tries{request.params[2].isNull() ? 1000000 : request.params[2].get_int()};
- FlatSigningProvider key_provider;
+ CScript coinbase_script;
std::string error;
- const auto desc = Parse(request.params[1].get_str(), key_provider, error, /* require_checksum = */ false);
- if (!desc) {
+ if (!getScriptFromDescriptor(request.params[1].get_str(), coinbase_script, error)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, error);
}
- if (desc->IsRange()) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Ranged descriptor not accepted. Maybe pass through deriveaddresses first?");
- }
-
- FlatSigningProvider provider;
- std::vector<CScript> coinbase_script;
- if (!desc->Expand(0, key_provider, coinbase_script, provider)) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Cannot derive script without private keys"));
- }
const CTxMemPool& mempool = EnsureMemPool();
- CHECK_NONFATAL(coinbase_script.size() == 1);
-
- return generateBlocks(mempool, coinbase_script.at(0), num_blocks, max_tries);
+ return generateBlocks(mempool, coinbase_script, num_blocks, max_tries);
}
static UniValue generatetoaddress(const JSONRPCRequest& request)
@@ -229,6 +272,113 @@ static UniValue generatetoaddress(const JSONRPCRequest& request)
return generateBlocks(mempool, coinbase_script, nGenerate, nMaxTries);
}
+static UniValue generateblock(const JSONRPCRequest& request)
+{
+ 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."},
+ {"transactions", RPCArg::Type::ARR, RPCArg::Optional::NO, "An array of hex strings which are either txids or raw transactions.\n"
+ "Txids must reference transactions currently in the mempool.\n"
+ "All transactions must be valid and in valid order, otherwise the block will be rejected.",
+ {
+ {"rawtx/txid", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, ""},
+ },
+ },
+ },
+ RPCResult{
+ RPCResult::Type::OBJ, "", "",
+ {
+ {RPCResult::Type::STR_HEX, "hash", "hash of generated block"},
+ }
+ },
+ RPCExamples{
+ "\nGenerate a block to myaddress, with txs rawtx and mempool_txid\n"
+ + HelpExampleCli("generateblock", R"("myaddress" '["rawtx", "mempool_txid"]')")
+ },
+ }.Check(request);
+
+ const auto address_or_descriptor = request.params[0].get_str();
+ CScript coinbase_script;
+ std::string error;
+
+ if (!getScriptFromDescriptor(address_or_descriptor, coinbase_script, error)) {
+ const auto destination = DecodeDestination(address_or_descriptor);
+ if (!IsValidDestination(destination)) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Error: Invalid address or descriptor");
+ }
+
+ coinbase_script = GetScriptForDestination(destination);
+ }
+
+ const CTxMemPool& mempool = EnsureMemPool();
+
+ std::vector<CTransactionRef> txs;
+ const auto raw_txs_or_txids = request.params[1].get_array();
+ for (size_t i = 0; i < raw_txs_or_txids.size(); i++) {
+ const auto str(raw_txs_or_txids[i].get_str());
+
+ uint256 hash;
+ CMutableTransaction mtx;
+ if (ParseHashStr(str, hash)) {
+
+ const auto tx = mempool.get(hash);
+ if (!tx) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Transaction %s not in mempool.", str));
+ }
+
+ txs.emplace_back(tx);
+
+ } else if (DecodeHexTx(mtx, str)) {
+ txs.push_back(MakeTransactionRef(std::move(mtx)));
+
+ } else {
+ throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("Transaction decode failed for %s", str));
+ }
+ }
+
+ CChainParams chainparams(Params());
+ CBlock block;
+
+ {
+ LOCK(cs_main);
+
+ CTxMemPool empty_mempool;
+ std::unique_ptr<CBlockTemplate> blocktemplate(BlockAssembler(empty_mempool, chainparams).CreateNewBlock(coinbase_script));
+ if (!blocktemplate) {
+ throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block");
+ }
+ block = blocktemplate->block;
+ }
+
+ CHECK_NONFATAL(block.vtx.size() == 1);
+
+ // Add transactions
+ block.vtx.insert(block.vtx.end(), txs.begin(), txs.end());
+ RegenerateCommitments(block);
+
+ {
+ LOCK(cs_main);
+
+ BlockValidationState state;
+ if (!TestBlockValidity(state, chainparams, block, LookupBlockIndex(block.hashPrevBlock), false, false)) {
+ throw JSONRPCError(RPC_VERIFY_ERROR, strprintf("TestBlockValidity failed: %s", state.ToString()));
+ }
+ }
+
+ uint256 block_hash;
+ uint64_t max_tries{1000000};
+ unsigned int extra_nonce{0};
+
+ if (!GenerateBlock(block, max_tries, extra_nonce, block_hash) || block_hash.IsNull()) {
+ throw JSONRPCError(RPC_MISC_ERROR, "Failed to make block.");
+ }
+
+ UniValue obj(UniValue::VOBJ);
+ obj.pushKV("hash", block_hash.GetHex());
+ return obj;
+}
+
static UniValue getmininginfo(const JSONRPCRequest& request)
{
RPCHelpMan{"getmininginfo",
@@ -1038,6 +1188,7 @@ static const CRPCCommand commands[] =
{ "generating", "generatetoaddress", &generatetoaddress, {"nblocks","address","maxtries"} },
{ "generating", "generatetodescriptor", &generatetodescriptor, {"num_blocks","descriptor","maxtries"} },
+ { "generating", "generateblock", &generateblock, {"output","transactions"} },
{ "util", "estimatesmartfee", &estimatesmartfee, {"conf_target", "estimate_mode"} },
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index 51a9581349..f3c5fed858 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -1,9 +1,10 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <httpserver.h>
+#include <interfaces/chain.h>
#include <key_io.h>
#include <node/context.h>
#include <outputtype.h>
@@ -363,7 +364,13 @@ static UniValue setmocktime(const JSONRPCRequest& request)
LOCK(cs_main);
RPCTypeCheck(request.params, {UniValue::VNUM});
- SetMockTime(request.params[0].get_int64());
+ int64_t time = request.params[0].get_int64();
+ SetMockTime(time);
+ if (g_rpc_node) {
+ for (const auto& chain_client : g_rpc_node->chain_clients) {
+ chain_client->setMockTime(time);
+ }
+ }
return NullUniValue;
}
@@ -509,7 +516,7 @@ UniValue logging(const JSONRPCRequest& request)
"When called with arguments, adds or removes categories from debug logging and return the lists above.\n"
"The arguments are evaluated in order \"include\", \"exclude\".\n"
"If an item is both included and excluded, it will thus end up being excluded.\n"
- "The valid logging categories are: " + ListLogCategories() + "\n"
+ "The valid logging categories are: " + LogInstance().LogCategoriesString() + "\n"
"In addition, the following are available as category names with special meanings:\n"
" - \"all\", \"1\" : represent all logging categories.\n"
" - \"none\", \"0\" : even if other logging categories are specified, ignore all of them.\n"
@@ -561,8 +568,7 @@ UniValue logging(const JSONRPCRequest& request)
}
UniValue result(UniValue::VOBJ);
- std::vector<CLogCategoryActive> vLogCatActive = ListActiveLogCategories();
- for (const auto& logCatActive : vLogCatActive) {
+ for (const auto& logCatActive : LogInstance().LogCategoriesList()) {
result.pushKV(logCatActive.category, logCatActive.active);
}
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index 10562126db..d6d15f8b56 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 3c0b060439..063ee1697c 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -40,12 +40,6 @@
#include <univalue.h>
-/** Maximum fee rate for sendrawtransaction and testmempoolaccept.
- * By default, a transaction with a fee rate higher than this will be rejected
- * by the RPCs. This can be overridden with the maxfeerate argument.
- */
-static const CFeeRate DEFAULT_MAX_RAW_TX_FEE_RATE{COIN / 10};
-
static void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
{
// Call into TxToUniv() in bitcoin-common to decode the transaction hex.
@@ -825,7 +819,7 @@ static UniValue sendrawtransaction(const JSONRPCRequest& request)
RPCTypeCheck(request.params, {
UniValue::VSTR,
- UniValueType(), // NUM or BOOL, checked later
+ UniValueType(), // VNUM or VSTR, checked inside AmountFromValue()
});
// parse hex string from parameter
@@ -834,13 +828,9 @@ static UniValue sendrawtransaction(const JSONRPCRequest& request)
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
CTransactionRef tx(MakeTransactionRef(std::move(mtx)));
- CFeeRate max_raw_tx_fee_rate = DEFAULT_MAX_RAW_TX_FEE_RATE;
- // TODO: temporary migration code for old clients. Remove in v0.20
- if (request.params[1].isBool()) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Second argument must be numeric (maxfeerate) and no longer supports a boolean. To allow a transaction with high fees, set maxfeerate to 0.");
- } else if (!request.params[1].isNull()) {
- max_raw_tx_fee_rate = CFeeRate(AmountFromValue(request.params[1]));
- }
+ const CFeeRate max_raw_tx_fee_rate = request.params[1].isNull() ?
+ DEFAULT_MAX_RAW_TX_FEE_RATE :
+ CFeeRate(AmountFromValue(request.params[1]));
int64_t virtual_size = GetVirtualTransactionSize(*tx);
CAmount max_raw_tx_fee = max_raw_tx_fee_rate.GetFee(virtual_size);
@@ -896,7 +886,7 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request)
RPCTypeCheck(request.params, {
UniValue::VARR,
- UniValueType(), // NUM or BOOL, checked later
+ UniValueType(), // VNUM or VSTR, checked inside AmountFromValue()
});
if (request.params[0].get_array().size() != 1) {
@@ -910,13 +900,9 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request)
CTransactionRef tx(MakeTransactionRef(std::move(mtx)));
const uint256& tx_hash = tx->GetHash();
- CFeeRate max_raw_tx_fee_rate = DEFAULT_MAX_RAW_TX_FEE_RATE;
- // TODO: temporary migration code for old clients. Remove in v0.20
- if (request.params[1].isBool()) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Second argument must be numeric (maxfeerate) and no longer supports a boolean. To allow a transaction with high fees, set maxfeerate to 0.");
- } else if (!request.params[1].isNull()) {
- max_raw_tx_fee_rate = CFeeRate(AmountFromValue(request.params[1]));
- }
+ const CFeeRate max_raw_tx_fee_rate = request.params[1].isNull() ?
+ DEFAULT_MAX_RAW_TX_FEE_RATE :
+ CFeeRate(AmountFromValue(request.params[1]));
CTxMemPool& mempool = EnsureMemPool();
int64_t virtual_size = GetVirtualTransactionSize(*tx);
@@ -1823,10 +1809,10 @@ static const CRPCCommand commands[] =
{ "rawtransactions", "createrawtransaction", &createrawtransaction, {"inputs","outputs","locktime","replaceable"} },
{ "rawtransactions", "decoderawtransaction", &decoderawtransaction, {"hexstring","iswitness"} },
{ "rawtransactions", "decodescript", &decodescript, {"hexstring"} },
- { "rawtransactions", "sendrawtransaction", &sendrawtransaction, {"hexstring","allowhighfees|maxfeerate"} },
+ { "rawtransactions", "sendrawtransaction", &sendrawtransaction, {"hexstring","maxfeerate"} },
{ "rawtransactions", "combinerawtransaction", &combinerawtransaction, {"txs"} },
{ "rawtransactions", "signrawtransactionwithkey", &signrawtransactionwithkey, {"hexstring","privkeys","prevtxs","sighashtype"} },
- { "rawtransactions", "testmempoolaccept", &testmempoolaccept, {"rawtxs","allowhighfees|maxfeerate"} },
+ { "rawtransactions", "testmempoolaccept", &testmempoolaccept, {"rawtxs","maxfeerate"} },
{ "rawtransactions", "decodepsbt", &decodepsbt, {"psbt"} },
{ "rawtransactions", "combinepsbt", &combinepsbt, {"txs"} },
{ "rawtransactions", "finalizepsbt", &finalizepsbt, {"psbt", "extract"} },
diff --git a/src/rpc/rawtransaction_util.cpp b/src/rpc/rawtransaction_util.cpp
index 7b701a2bbe..bd82773bf2 100644
--- a/src/rpc/rawtransaction_util.cpp
+++ b/src/rpc/rawtransaction_util.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/rpc/rawtransaction_util.h b/src/rpc/rawtransaction_util.h
index 436db5dc60..942314eccf 100644
--- a/src/rpc/rawtransaction_util.h
+++ b/src/rpc/rawtransaction_util.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019 The Bitcoin Core developers
+// Copyright (c) 2017-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp
index 7e1fb7a59d..860fa198d5 100644
--- a/src/rpc/util.cpp
+++ b/src/rpc/util.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019 The Bitcoin Core developers
+// Copyright (c) 2017-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -13,6 +13,9 @@
#include <tuple>
+#include <boost/algorithm/string/classification.hpp>
+#include <boost/algorithm/string/split.hpp>
+
const std::string UNIX_EPOCH_TIME = "UNIX epoch time";
const std::string EXAMPLE_ADDRESS[2] = {"bc1q09vm5lfy0j5reeulh4x5752q25uqqvz34hufdl", "bc1q02ad21edsxd23d32dfgqqsz4vv4nmtfzuklhy3"};
@@ -330,7 +333,7 @@ struct Sections {
if (outer_type == OuterType::NONE) return; // Nothing more to do for non-recursive types on first recursion
auto left = indent;
if (arg.m_type_str.size() != 0 && push_name) {
- left += "\"" + arg.m_name + "\": " + arg.m_type_str.at(0);
+ left += "\"" + arg.GetName() + "\": " + arg.m_type_str.at(0);
} else {
left += push_name ? arg.ToStringObj(/* oneline */ false) : arg.ToString(/* oneline */ false);
}
@@ -341,7 +344,7 @@ struct Sections {
case RPCArg::Type::OBJ:
case RPCArg::Type::OBJ_USER_KEYS: {
const auto right = outer_type == OuterType::NONE ? "" : arg.ToDescriptionString();
- PushSection({indent + (push_name ? "\"" + arg.m_name + "\": " : "") + "{", right});
+ PushSection({indent + (push_name ? "\"" + arg.GetName() + "\": " : "") + "{", right});
for (const auto& arg_inner : arg.m_inner) {
Push(arg_inner, current_indent + 2, OuterType::OBJ);
}
@@ -353,7 +356,7 @@ struct Sections {
}
case RPCArg::Type::ARR: {
auto left = indent;
- left += push_name ? "\"" + arg.m_name + "\": " : "";
+ left += push_name ? "\"" + arg.GetName() + "\": " : "";
left += "[";
const auto right = outer_type == OuterType::NONE ? "" : arg.ToDescriptionString();
PushSection({left, right});
@@ -419,8 +422,12 @@ RPCHelpMan::RPCHelpMan(std::string name, std::string description, std::vector<RP
{
std::set<std::string> named_args;
for (const auto& arg : m_args) {
+ std::vector<std::string> names;
+ boost::split(names, arg.m_names, boost::is_any_of("|"));
// Should have unique named arguments
- CHECK_NONFATAL(named_args.insert(arg.m_name).second);
+ for (const std::string& name : names) {
+ CHECK_NONFATAL(named_args.insert(name).second);
+ }
}
}
@@ -489,7 +496,7 @@ std::string RPCHelpMan::ToString() const
if (i == 0) ret += "\nArguments:\n";
// Push named argument name and description
- sections.m_sections.emplace_back(::ToString(i + 1) + ". " + arg.m_name, arg.ToDescriptionString());
+ sections.m_sections.emplace_back(::ToString(i + 1) + ". " + arg.GetFirstName(), arg.ToDescriptionString());
sections.m_max_pad = std::max(sections.m_max_pad, sections.m_sections.back().m_left.size());
// Recursively push nested args
@@ -506,6 +513,17 @@ std::string RPCHelpMan::ToString() const
return ret;
}
+std::string RPCArg::GetFirstName() const
+{
+ return m_names.substr(0, m_names.find("|"));
+}
+
+std::string RPCArg::GetName() const
+{
+ CHECK_NONFATAL(std::string::npos == m_names.find("|"));
+ return m_names;
+}
+
bool RPCArg::IsOptional() const
{
if (m_fallback.which() == 1) {
@@ -681,7 +699,7 @@ std::string RPCArg::ToStringObj(const bool oneline) const
{
std::string res;
res += "\"";
- res += m_name;
+ res += GetFirstName();
if (oneline) {
res += "\":";
} else {
@@ -723,13 +741,13 @@ std::string RPCArg::ToString(const bool oneline) const
switch (m_type) {
case Type::STR_HEX:
case Type::STR: {
- return "\"" + m_name + "\"";
+ return "\"" + GetFirstName() + "\"";
}
case Type::NUM:
case Type::RANGE:
case Type::AMOUNT:
case Type::BOOL: {
- return m_name;
+ return GetFirstName();
}
case Type::OBJ:
case Type::OBJ_USER_KEYS: {
diff --git a/src/rpc/util.h b/src/rpc/util.h
index f65ad1246b..53dce2c397 100644
--- a/src/rpc/util.h
+++ b/src/rpc/util.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019 The Bitcoin Core developers
+// Copyright (c) 2017-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -142,7 +142,7 @@ struct RPCArg {
OMITTED,
};
using Fallback = boost::variant<Optional, /* default value for optional args */ std::string>;
- const std::string m_name; //!< The name of the arg (can be empty for inner args)
+ const std::string m_names; //!< The name of the arg (can be empty for inner args, can contain multiple aliases separated by | for named request arguments)
const Type m_type;
const std::vector<RPCArg> m_inner; //!< Only used for arrays or dicts
const Fallback m_fallback;
@@ -157,7 +157,7 @@ struct RPCArg {
const std::string description,
const std::string oneline_description = "",
const std::vector<std::string> type_str = {})
- : m_name{std::move(name)},
+ : m_names{std::move(name)},
m_type{std::move(type)},
m_fallback{std::move(fallback)},
m_description{std::move(description)},
@@ -175,7 +175,7 @@ struct RPCArg {
const std::vector<RPCArg> inner,
const std::string oneline_description = "",
const std::vector<std::string> type_str = {})
- : m_name{std::move(name)},
+ : m_names{std::move(name)},
m_type{std::move(type)},
m_inner{std::move(inner)},
m_fallback{std::move(fallback)},
@@ -188,6 +188,12 @@ struct RPCArg {
bool IsOptional() const;
+ /** Return the first of all aliases */
+ std::string GetFirstName() const;
+
+ /** Return the name, throws when there are aliases */
+ std::string GetName() const;
+
/**
* Return the type string of the argument.
* Set oneline to allow it to be overridden by a custom oneline type string (m_oneline_description).