aboutsummaryrefslogtreecommitdiff
path: root/src/rpc
diff options
context:
space:
mode:
Diffstat (limited to 'src/rpc')
-rw-r--r--src/rpc/blockchain.cpp102
-rw-r--r--src/rpc/client.cpp2
-rw-r--r--src/rpc/mining.cpp46
-rw-r--r--src/rpc/misc.cpp45
-rw-r--r--src/rpc/net.cpp43
-rw-r--r--src/rpc/protocol.cpp21
-rw-r--r--src/rpc/protocol.h4
-rw-r--r--src/rpc/rawtransaction.cpp193
-rw-r--r--src/rpc/safemode.cpp14
-rw-r--r--src/rpc/safemode.h12
-rw-r--r--src/rpc/server.cpp33
-rw-r--r--src/rpc/server.h5
12 files changed, 307 insertions, 213 deletions
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 6178a1c7ab..ef61e5a55d 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -48,9 +48,9 @@ extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue&
double GetDifficulty(const CBlockIndex* blockindex)
{
- if (blockindex == NULL)
+ if (blockindex == nullptr)
{
- if (chainActive.Tip() == NULL)
+ if (chainActive.Tip() == nullptr)
return 1.0;
else
blockindex = chainActive.Tip();
@@ -125,7 +125,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx
if(txDetails)
{
UniValue objTx(UniValue::VOBJ);
- TxToUniv(*tx, uint256(), objTx);
+ TxToUniv(*tx, uint256(), objTx, true, RPCSerializationFlags());
txs.push_back(objTx);
}
else
@@ -210,7 +210,7 @@ UniValue waitfornewblock(const JSONRPCRequest& request)
+ HelpExampleRpc("waitfornewblock", "1000")
);
int timeout = 0;
- if (request.params.size() > 0)
+ if (!request.params[0].isNull())
timeout = request.params[0].get_int();
CUpdatedBlock block;
@@ -252,7 +252,7 @@ UniValue waitforblock(const JSONRPCRequest& request)
uint256 hash = uint256S(request.params[0].get_str());
- if (request.params.size() > 1)
+ if (!request.params[1].isNull())
timeout = request.params[1].get_int();
CUpdatedBlock block;
@@ -295,7 +295,7 @@ UniValue waitforblockheight(const JSONRPCRequest& request)
int height = request.params[0].get_int();
- if (request.params.size() > 1)
+ if (!request.params[1].isNull())
timeout = request.params[1].get_int();
CUpdatedBlock block;
@@ -434,7 +434,7 @@ UniValue getrawmempool(const JSONRPCRequest& request)
);
bool fVerbose = false;
- if (request.params.size() > 0)
+ if (!request.params[0].isNull())
fVerbose = request.params[0].get_bool();
return mempoolToJSON(fVerbose);
@@ -467,7 +467,7 @@ UniValue getmempoolancestors(const JSONRPCRequest& request)
}
bool fVerbose = false;
- if (request.params.size() > 1)
+ if (!request.params[1].isNull())
fVerbose = request.params[1].get_bool();
uint256 hash = ParseHashV(request.params[0], "parameter 1");
@@ -531,7 +531,7 @@ UniValue getmempooldescendants(const JSONRPCRequest& request)
}
bool fVerbose = false;
- if (request.params.size() > 1)
+ if (!request.params[1].isNull())
fVerbose = request.params[1].get_bool();
uint256 hash = ParseHashV(request.params[0], "parameter 1");
@@ -666,7 +666,7 @@ UniValue getblockheader(const JSONRPCRequest& request)
uint256 hash(uint256S(strHash));
bool fVerbose = true;
- if (request.params.size() > 1)
+ if (!request.params[1].isNull())
fVerbose = request.params[1].get_bool();
if (mapBlockIndex.count(hash) == 0)
@@ -741,7 +741,7 @@ UniValue getblock(const JSONRPCRequest& request)
uint256 hash(uint256S(strHash));
int verbosity = 1;
- if (request.params.size() > 1) {
+ if (!request.params[1].isNull()) {
if(request.params[1].isNum())
verbosity = request.params[1].get_int();
else
@@ -944,9 +944,10 @@ UniValue gettxout(const JSONRPCRequest& request)
"gettxout \"txid\" n ( include_mempool )\n"
"\nReturns details about an unspent transaction output.\n"
"\nArguments:\n"
- "1. \"txid\" (string, required) The transaction id\n"
- "2. n (numeric, required) vout number\n"
- "3. include_mempool (boolean, optional) Whether to include the mempool\n"
+ "1. \"txid\" (string, required) The transaction id\n"
+ "2. \"n\" (numeric, required) vout number\n"
+ "3. \"include_mempool\" (boolean, optional) Whether to include the mempool. Default: true."
+ " Note that an unspent output that is spent in the mempool won't appear.\n"
"\nResult:\n"
"{\n"
" \"bestblock\" : \"hash\", (string) the block hash\n"
@@ -962,7 +963,6 @@ UniValue gettxout(const JSONRPCRequest& request)
" ,...\n"
" ]\n"
" },\n"
- " \"version\" : n, (numeric) The version\n"
" \"coinbase\" : true|false (boolean) Coinbase or not\n"
"}\n"
@@ -984,7 +984,7 @@ UniValue gettxout(const JSONRPCRequest& request)
int n = request.params[1].get_int();
COutPoint out(hash, n);
bool fMempool = true;
- if (request.params.size() > 2)
+ if (!request.params[2].isNull())
fMempool = request.params[2].get_bool();
Coin coin;
@@ -1019,8 +1019,8 @@ UniValue gettxout(const JSONRPCRequest& request)
UniValue verifychain(const JSONRPCRequest& request)
{
- int nCheckLevel = GetArg("-checklevel", DEFAULT_CHECKLEVEL);
- int nCheckDepth = GetArg("-checkblocks", DEFAULT_CHECKBLOCKS);
+ int nCheckLevel = gArgs.GetArg("-checklevel", DEFAULT_CHECKLEVEL);
+ int nCheckDepth = gArgs.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS);
if (request.fHelp || request.params.size() > 2)
throw std::runtime_error(
"verifychain ( checklevel nblocks )\n"
@@ -1037,9 +1037,9 @@ UniValue verifychain(const JSONRPCRequest& request)
LOCK(cs_main);
- if (request.params.size() > 0)
+ if (!request.params[0].isNull())
nCheckLevel = request.params[0].get_int();
- if (request.params.size() > 1)
+ if (!request.params[1].isNull())
nCheckDepth = request.params[1].get_int();
return CVerifyDB().VerifyDB(Params(), pcoinsTip, nCheckLevel, nCheckDepth);
@@ -1325,7 +1325,7 @@ UniValue mempoolInfoToJSON()
ret.push_back(Pair("size", (int64_t) mempool.size()));
ret.push_back(Pair("bytes", (int64_t) mempool.GetTotalTxSize()));
ret.push_back(Pair("usage", (int64_t) mempool.DynamicMemoryUsage()));
- size_t maxmempool = GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;
+ size_t maxmempool = gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;
ret.push_back(Pair("maxmempool", (int64_t) maxmempool));
ret.push_back(Pair("mempoolminfee", ValueFromAmount(mempool.GetMinFee(maxmempool).GetFeePerK())));
@@ -1344,7 +1344,7 @@ UniValue getmempoolinfo(const JSONRPCRequest& request)
" \"bytes\": xxxxx, (numeric) Sum of all virtual transaction sizes as defined in BIP 141. Differs from actual serialized size because witness data is discounted\n"
" \"usage\": xxxxx, (numeric) Total memory usage for the mempool\n"
" \"maxmempool\": xxxxx, (numeric) Maximum memory usage for the mempool\n"
- " \"mempoolminfee\": xxxxx (numeric) Minimum feerate (" + CURRENCY_UNIT + " per KB) for tx to be accepted\n"
+ " \"mempoolminfee\": xxxxx (numeric) Minimum fee rate in " + CURRENCY_UNIT + "/kB for tx to be accepted\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("getmempoolinfo", "")
@@ -1490,11 +1490,11 @@ UniValue getchaintxstats(const JSONRPCRequest& request)
const CBlockIndex* pindex;
int blockcount = 30 * 24 * 60 * 60 / Params().GetConsensus().nPowTargetSpacing; // By default: 1 month
- if (request.params.size() > 0 && !request.params[0].isNull()) {
+ if (!request.params[0].isNull()) {
blockcount = request.params[0].get_int();
}
- bool havehash = request.params.size() > 1 && !request.params[1].isNull();
+ bool havehash = !request.params[1].isNull();
uint256 hash;
if (havehash) {
hash = uint256S(request.params[1].get_str());
@@ -1533,35 +1533,35 @@ UniValue getchaintxstats(const JSONRPCRequest& request)
}
static const CRPCCommand commands[] =
-{ // category name actor (function) okSafe argNames
- // --------------------- ------------------------ ----------------------- ------ ----------
- { "blockchain", "getblockchaininfo", &getblockchaininfo, true, {} },
- { "blockchain", "getchaintxstats", &getchaintxstats, true, {"nblocks", "blockhash"} },
- { "blockchain", "getbestblockhash", &getbestblockhash, true, {} },
- { "blockchain", "getblockcount", &getblockcount, true, {} },
- { "blockchain", "getblock", &getblock, true, {"blockhash","verbosity|verbose"} },
- { "blockchain", "getblockhash", &getblockhash, true, {"height"} },
- { "blockchain", "getblockheader", &getblockheader, true, {"blockhash","verbose"} },
- { "blockchain", "getchaintips", &getchaintips, true, {} },
- { "blockchain", "getdifficulty", &getdifficulty, true, {} },
- { "blockchain", "getmempoolancestors", &getmempoolancestors, true, {"txid","verbose"} },
- { "blockchain", "getmempooldescendants", &getmempooldescendants, true, {"txid","verbose"} },
- { "blockchain", "getmempoolentry", &getmempoolentry, true, {"txid"} },
- { "blockchain", "getmempoolinfo", &getmempoolinfo, true, {} },
- { "blockchain", "getrawmempool", &getrawmempool, true, {"verbose"} },
- { "blockchain", "gettxout", &gettxout, true, {"txid","n","include_mempool"} },
- { "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, true, {} },
- { "blockchain", "pruneblockchain", &pruneblockchain, true, {"height"} },
- { "blockchain", "verifychain", &verifychain, true, {"checklevel","nblocks"} },
-
- { "blockchain", "preciousblock", &preciousblock, true, {"blockhash"} },
+{ // category name actor (function) argNames
+ // --------------------- ------------------------ ----------------------- ----------
+ { "blockchain", "getblockchaininfo", &getblockchaininfo, {} },
+ { "blockchain", "getchaintxstats", &getchaintxstats, {"nblocks", "blockhash"} },
+ { "blockchain", "getbestblockhash", &getbestblockhash, {} },
+ { "blockchain", "getblockcount", &getblockcount, {} },
+ { "blockchain", "getblock", &getblock, {"blockhash","verbosity|verbose"} },
+ { "blockchain", "getblockhash", &getblockhash, {"height"} },
+ { "blockchain", "getblockheader", &getblockheader, {"blockhash","verbose"} },
+ { "blockchain", "getchaintips", &getchaintips, {} },
+ { "blockchain", "getdifficulty", &getdifficulty, {} },
+ { "blockchain", "getmempoolancestors", &getmempoolancestors, {"txid","verbose"} },
+ { "blockchain", "getmempooldescendants", &getmempooldescendants, {"txid","verbose"} },
+ { "blockchain", "getmempoolentry", &getmempoolentry, {"txid"} },
+ { "blockchain", "getmempoolinfo", &getmempoolinfo, {} },
+ { "blockchain", "getrawmempool", &getrawmempool, {"verbose"} },
+ { "blockchain", "gettxout", &gettxout, {"txid","n","include_mempool"} },
+ { "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, {} },
+ { "blockchain", "pruneblockchain", &pruneblockchain, {"height"} },
+ { "blockchain", "verifychain", &verifychain, {"checklevel","nblocks"} },
+
+ { "blockchain", "preciousblock", &preciousblock, {"blockhash"} },
/* Not shown in help */
- { "hidden", "invalidateblock", &invalidateblock, true, {"blockhash"} },
- { "hidden", "reconsiderblock", &reconsiderblock, true, {"blockhash"} },
- { "hidden", "waitfornewblock", &waitfornewblock, true, {"timeout"} },
- { "hidden", "waitforblock", &waitforblock, true, {"blockhash","timeout"} },
- { "hidden", "waitforblockheight", &waitforblockheight, true, {"height","timeout"} },
+ { "hidden", "invalidateblock", &invalidateblock, {"blockhash"} },
+ { "hidden", "reconsiderblock", &reconsiderblock, {"blockhash"} },
+ { "hidden", "waitfornewblock", &waitfornewblock, {"timeout"} },
+ { "hidden", "waitforblock", &waitforblock, {"blockhash","timeout"} },
+ { "hidden", "waitforblockheight", &waitforblockheight, {"height","timeout"} },
};
void RegisterBlockchainRPCCommands(CRPCTable &t)
diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp
index 1ab1956124..4179453782 100644
--- a/src/rpc/client.cpp
+++ b/src/rpc/client.cpp
@@ -68,6 +68,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "getblocktemplate", 0, "template_request" },
{ "listsinceblock", 1, "target_confirmations" },
{ "listsinceblock", 2, "include_watchonly" },
+ { "listsinceblock", 3, "include_removed" },
{ "sendmany", 1, "amounts" },
{ "sendmany", 2, "minconf" },
{ "sendmany", 4, "subtractfeefrom" },
@@ -95,6 +96,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "signrawtransaction", 1, "prevtxs" },
{ "signrawtransaction", 2, "privkeys" },
{ "sendrawtransaction", 1, "allowhighfees" },
+ { "combinerawtransaction", 0, "txs" },
{ "fundrawtransaction", 1, "options" },
{ "gettxout", 1, "n" },
{ "gettxout", 2, "include_mempool" },
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index 4fd632dfc5..73860f375f 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -24,6 +24,7 @@
#include "util.h"
#include "utilstrencodings.h"
#include "validationinterface.h"
+#include "warnings.h"
#include <memory>
#include <stdint.h>
@@ -51,7 +52,7 @@ UniValue GetNetworkHashPS(int lookup, int height) {
if (height >= 0 && height < chainActive.Height())
pb = chainActive[height];
- if (pb == NULL || !pb->nHeight)
+ if (pb == nullptr || !pb->nHeight)
return 0;
// If lookup is -1, then use blocks since last difficulty change.
@@ -101,7 +102,7 @@ UniValue getnetworkhashps(const JSONRPCRequest& request)
);
LOCK(cs_main);
- return GetNetworkHashPS(request.params.size() > 0 ? request.params[0].get_int() : 120, request.params.size() > 1 ? request.params[1].get_int() : -1);
+ return GetNetworkHashPS(!request.params[0].isNull() ? request.params[0].get_int() : 120, !request.params[1].isNull() ? request.params[1].get_int() : -1);
}
UniValue generateBlocks(std::shared_ptr<CReserveScript> coinbaseScript, int nGenerate, uint64_t nMaxTries, bool keepScript)
@@ -138,7 +139,7 @@ UniValue generateBlocks(std::shared_ptr<CReserveScript> coinbaseScript, int nGen
continue;
}
std::shared_ptr<const CBlock> shared_pblock = std::make_shared<const CBlock>(*pblock);
- if (!ProcessNewBlock(Params(), shared_pblock, true, NULL))
+ if (!ProcessNewBlock(Params(), shared_pblock, true, nullptr))
throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted");
++nHeight;
blockHashes.push_back(pblock->GetHash().GetHex());
@@ -171,7 +172,7 @@ UniValue generatetoaddress(const JSONRPCRequest& request)
int nGenerate = request.params[0].get_int();
uint64_t nMaxTries = 1000000;
- if (request.params.size() > 2) {
+ if (!request.params[2].isNull()) {
nMaxTries = request.params[2].get_int();
}
@@ -335,7 +336,7 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
" n (numeric) transactions before this one (by 1-based index in 'transactions' list) that must be present in the final block if this one is\n"
" ,...\n"
" ],\n"
- " \"fee\": n, (numeric) difference in value between transaction inputs and outputs (in Satoshis); for coinbase transactions, this is a negative Number of the total collected block fees (ie, not including the block subsidy); if key is not present, fee is unknown and clients MUST NOT assume there isn't one\n"
+ " \"fee\": n, (numeric) difference in value between transaction inputs and outputs (in satoshis); for coinbase transactions, this is a negative Number of the total collected block fees (ie, not including the block subsidy); if key is not present, fee is unknown and clients MUST NOT assume there isn't one\n"
" \"sigops\" : n, (numeric) total SigOps cost, as counted for purposes of block limits; if key is not present, sigop cost is unknown and clients MUST NOT assume it is zero\n"
" \"weight\" : n, (numeric) total transaction weight, as counted for purposes of block limits\n"
" \"required\" : true|false (boolean) if provided and true, this transaction must be in the final block\n"
@@ -345,7 +346,7 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
" \"coinbaseaux\" : { (json object) data that should be included in the coinbase's scriptSig content\n"
" \"flags\" : \"xx\" (string) key name is to be ignored, and value included in scriptSig\n"
" },\n"
- " \"coinbasevalue\" : n, (numeric) maximum allowable input to coinbase transaction, including the generation award and transaction fees (in Satoshis)\n"
+ " \"coinbasevalue\" : n, (numeric) maximum allowable input to coinbase transaction, including the generation award and transaction fees (in satoshis)\n"
" \"coinbasetxn\" : { ... }, (json object) information for coinbase transaction\n"
" \"target\" : \"xxxx\", (string) The hash target\n"
" \"mintime\" : xxx, (numeric) The minimum timestamp appropriate for next block time in seconds since epoch (Jan 1 1970 GMT)\n"
@@ -373,7 +374,7 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
UniValue lpval = NullUniValue;
std::set<std::string> setClientRules;
int64_t nMaxVersionPreVB = -1;
- if (request.params.size() > 0)
+ if (!request.params[0].isNull())
{
const UniValue& oparam = request.params[0].get_obj();
const UniValue& modeval = find_value(oparam, "mode");
@@ -685,7 +686,7 @@ public:
bool found;
CValidationState state;
- submitblock_StateCatcher(const uint256 &hashIn) : hash(hashIn), found(false), state() {}
+ explicit submitblock_StateCatcher(const uint256 &hashIn) : hash(hashIn), found(false), state() {}
protected:
void BlockChecked(const CBlock& block, const CValidationState& stateIn) override {
@@ -753,7 +754,7 @@ UniValue submitblock(const JSONRPCRequest& request)
submitblock_StateCatcher sc(block.GetHash());
RegisterValidationInterface(&sc);
- bool fAccepted = ProcessNewBlock(Params(), blockptr, true, NULL);
+ bool fAccepted = ProcessNewBlock(Params(), blockptr, true, nullptr);
UnregisterValidationInterface(&sc);
if (fBlockPresent) {
if (fAccepted && !sc.found) {
@@ -824,7 +825,7 @@ UniValue estimatesmartfee(const JSONRPCRequest& request)
" \"CONSERVATIVE\"\n"
"\nResult:\n"
"{\n"
- " \"feerate\" : x.x, (numeric, optional) estimate fee-per-kilobyte (in BTC)\n"
+ " \"feerate\" : x.x, (numeric, optional) estimate fee rate in " + CURRENCY_UNIT + "/kB\n"
" \"errors\": [ str... ] (json array of strings, optional) Errors encountered during processing\n"
" \"blocks\" : n (numeric) block number where estimate was found\n"
"}\n"
@@ -841,7 +842,7 @@ UniValue estimatesmartfee(const JSONRPCRequest& request)
RPCTypeCheckArgument(request.params[0], UniValue::VNUM);
unsigned int conf_target = ParseConfirmTarget(request.params[0]);
bool conservative = true;
- if (request.params.size() > 1 && !request.params[1].isNull()) {
+ if (!request.params[1].isNull()) {
FeeEstimateMode fee_mode;
if (!FeeModeFromString(request.params[1].get_str(), fee_mode)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter");
@@ -883,7 +884,7 @@ UniValue estimaterawfee(const JSONRPCRequest& request)
"\nResult:\n"
"{\n"
" \"short\" : { (json object, optional) estimate for short time horizon\n"
- " \"feerate\" : x.x, (numeric, optional) estimate fee-per-kilobyte (in BTC)\n"
+ " \"feerate\" : x.x, (numeric, optional) estimate fee rate in " + CURRENCY_UNIT + "/kB\n"
" \"decay\" : x.x, (numeric) exponential decay (per block) for historical moving average of confirmation data\n"
" \"scale\" : x, (numeric) The resolution of confirmation targets at this time horizon\n"
" \"pass\" : { (json object, optional) information about the lowest range of feerates to succeed in meeting the threshold\n"
@@ -966,20 +967,21 @@ UniValue estimaterawfee(const JSONRPCRequest& request)
}
static const CRPCCommand commands[] =
-{ // category name actor (function) okSafeMode
+{ // category name actor (function) argNames
// --------------------- ------------------------ ----------------------- ----------
- { "mining", "getnetworkhashps", &getnetworkhashps, true, {"nblocks","height"} },
- { "mining", "getmininginfo", &getmininginfo, true, {} },
- { "mining", "prioritisetransaction", &prioritisetransaction, true, {"txid","dummy","fee_delta"} },
- { "mining", "getblocktemplate", &getblocktemplate, true, {"template_request"} },
- { "mining", "submitblock", &submitblock, true, {"hexdata","dummy"} },
+ { "mining", "getnetworkhashps", &getnetworkhashps, {"nblocks","height"} },
+ { "mining", "getmininginfo", &getmininginfo, {} },
+ { "mining", "prioritisetransaction", &prioritisetransaction, {"txid","dummy","fee_delta"} },
+ { "mining", "getblocktemplate", &getblocktemplate, {"template_request"} },
+ { "mining", "submitblock", &submitblock, {"hexdata","dummy"} },
+
- { "generating", "generatetoaddress", &generatetoaddress, true, {"nblocks","address","maxtries"} },
+ { "generating", "generatetoaddress", &generatetoaddress, {"nblocks","address","maxtries"} },
- { "util", "estimatefee", &estimatefee, true, {"nblocks"} },
- { "util", "estimatesmartfee", &estimatesmartfee, true, {"conf_target", "estimate_mode"} },
+ { "util", "estimatefee", &estimatefee, {"nblocks"} },
+ { "util", "estimatesmartfee", &estimatesmartfee, {"nblocks", "estimate_mode"} },
- { "hidden", "estimaterawfee", &estimaterawfee, true, {"conf_target", "threshold"} },
+ { "hidden", "estimaterawfee", &estimaterawfee, {"conf_target", "threshold"} },
};
void RegisterMiningRPCCommands(CRPCTable &t)
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index fcbbe1ceed..76eefabd29 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -6,6 +6,7 @@
#include "base58.h"
#include "chain.h"
#include "clientversion.h"
+#include "core_io.h"
#include "init.h"
#include "validation.h"
#include "httpserver.h"
@@ -21,6 +22,7 @@
#include "wallet/wallet.h"
#include "wallet/walletdb.h"
#endif
+#include "warnings.h"
#include <stdint.h>
#ifdef HAVE_MALLOC_INFO
@@ -50,6 +52,7 @@ UniValue getinfo(const JSONRPCRequest& request)
"\nDEPRECATED. Returns an object containing various state info.\n"
"\nResult:\n"
"{\n"
+ " \"deprecation-warning\": \"...\" (string) warning that the getinfo command is deprecated and will be removed in 0.16\n"
" \"version\": xxxxx, (numeric) the server version\n"
" \"protocolversion\": xxxxx, (numeric) the protocol version\n"
" \"walletversion\": xxxxx, (numeric) the wallet version\n"
@@ -57,7 +60,7 @@ UniValue getinfo(const JSONRPCRequest& request)
" \"blocks\": xxxxxx, (numeric) the current number of blocks processed in the server\n"
" \"timeoffset\": xxxxx, (numeric) the time offset\n"
" \"connections\": xxxxx, (numeric) the number of connections\n"
- " \"proxy\": \"host:port\", (string, optional) the proxy used by the server\n"
+ " \"proxy\": \"host:port\", (string, optional) the proxy used by the server\n"
" \"difficulty\": xxxxxx, (numeric) the current difficulty\n"
" \"testnet\": true|false, (boolean) if the server is using testnet or not\n"
" \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since Unix epoch) of the oldest pre-generated key in the key pool\n"
@@ -65,7 +68,7 @@ UniValue getinfo(const JSONRPCRequest& request)
" \"unlocked_until\": ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n"
" \"paytxfee\": x.xxxx, (numeric) the transaction fee set in " + CURRENCY_UNIT + "/kB\n"
" \"relayfee\": x.xxxx, (numeric) minimum relay fee for transactions in " + CURRENCY_UNIT + "/kB\n"
- " \"errors\": \"...\" (string) any error messages\n"
+ " \"errors\": \"...\" (string) any error messages\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("getinfo", "")
@@ -75,7 +78,7 @@ UniValue getinfo(const JSONRPCRequest& request)
#ifdef ENABLE_WALLET
CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
- LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);
+ LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : nullptr);
#else
LOCK(cs_main);
#endif
@@ -84,6 +87,8 @@ UniValue getinfo(const JSONRPCRequest& request)
GetProxy(NET_IPV4, proxy);
UniValue obj(UniValue::VOBJ);
+ obj.push_back(Pair("deprecation-warning", "WARNING: getinfo is deprecated and will be fully removed in 0.16."
+ " Projects should transition to using getblockchaininfo, getnetworkinfo, and getwalletinfo before upgrading to 0.16"));
obj.push_back(Pair("version", CLIENT_VERSION));
obj.push_back(Pair("protocolversion", PROTOCOL_VERSION));
#ifdef ENABLE_WALLET
@@ -120,7 +125,7 @@ class DescribeAddressVisitor : public boost::static_visitor<UniValue>
public:
CWallet * const pwallet;
- DescribeAddressVisitor(CWallet *_pwallet) : pwallet(_pwallet) {}
+ explicit DescribeAddressVisitor(CWallet *_pwallet) : pwallet(_pwallet) {}
UniValue operator()(const CNoDestination &dest) const { return UniValue(UniValue::VOBJ); }
@@ -197,7 +202,7 @@ UniValue validateaddress(const JSONRPCRequest& request)
#ifdef ENABLE_WALLET
CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
- LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);
+ LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : nullptr);
#else
LOCK(cs_main);
#endif
@@ -317,7 +322,7 @@ UniValue createmultisig(const JSONRPCRequest& request)
#ifdef ENABLE_WALLET
CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
#else
- CWallet * const pwallet = NULL;
+ CWallet * const pwallet = nullptr;
#endif
if (request.fHelp || request.params.size() < 2 || request.params.size() > 2)
@@ -547,7 +552,7 @@ UniValue getmemoryinfo(const JSONRPCRequest& request)
+ HelpExampleRpc("getmemoryinfo", "")
);
- std::string mode = (request.params.size() < 1 || request.params[0].isNull()) ? "stats" : request.params[0].get_str();
+ std::string mode = request.params[0].isNull() ? "stats" : request.params[0].get_str();
if (mode == "stats") {
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("locked", RPCLockedMemoryInfo()));
@@ -598,11 +603,11 @@ UniValue logging(const JSONRPCRequest& request)
}
uint32_t originalLogCategories = logCategories;
- if (request.params.size() > 0 && request.params[0].isArray()) {
+ if (request.params[0].isArray()) {
logCategories |= getCategoryMask(request.params[0]);
}
- if (request.params.size() > 1 && request.params[1].isArray()) {
+ if (request.params[1].isArray()) {
logCategories &= ~getCategoryMask(request.params[1]);
}
@@ -644,20 +649,20 @@ UniValue echo(const JSONRPCRequest& request)
}
static const CRPCCommand commands[] =
-{ // category name actor (function) okSafeMode
+{ // category name actor (function) argNames
// --------------------- ------------------------ ----------------------- ----------
- { "control", "getinfo", &getinfo, true, {} }, /* uses wallet if enabled */
- { "control", "getmemoryinfo", &getmemoryinfo, true, {"mode"} },
- { "util", "validateaddress", &validateaddress, true, {"address"} }, /* uses wallet if enabled */
- { "util", "createmultisig", &createmultisig, true, {"nrequired","keys"} },
- { "util", "verifymessage", &verifymessage, true, {"address","signature","message"} },
- { "util", "signmessagewithprivkey", &signmessagewithprivkey, true, {"privkey","message"} },
+ { "control", "getinfo", &getinfo, {} }, /* uses wallet if enabled */
+ { "control", "getmemoryinfo", &getmemoryinfo, {"mode"} },
+ { "util", "validateaddress", &validateaddress, {"address"} }, /* uses wallet if enabled */
+ { "util", "createmultisig", &createmultisig, {"nrequired","keys"} },
+ { "util", "verifymessage", &verifymessage, {"address","signature","message"} },
+ { "util", "signmessagewithprivkey", &signmessagewithprivkey, {"privkey","message"} },
/* Not shown in help */
- { "hidden", "setmocktime", &setmocktime, true, {"timestamp"}},
- { "hidden", "echo", &echo, true, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}},
- { "hidden", "echojson", &echo, true, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}},
- { "hidden", "logging", &logging, true, {"include", "exclude"}},
+ { "hidden", "setmocktime", &setmocktime, {"timestamp"}},
+ { "hidden", "echo", &echo, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}},
+ { "hidden", "echojson", &echo, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}},
+ { "hidden", "logging", &logging, {"include", "exclude"}},
};
void RegisterMiscRPCCommands(CRPCTable &t)
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index ed452fcb02..7faf216047 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -6,6 +6,7 @@
#include "chainparams.h"
#include "clientversion.h"
+#include "core_io.h"
#include "validation.h"
#include "net.h"
#include "net_processing.h"
@@ -18,7 +19,7 @@
#include "util.h"
#include "utilstrencodings.h"
#include "version.h"
-
+#include "warnings.h"
#include <univalue.h>
@@ -192,7 +193,7 @@ UniValue getpeerinfo(const JSONRPCRequest& request)
UniValue addnode(const JSONRPCRequest& request)
{
std::string strCommand;
- if (request.params.size() == 2)
+ if (!request.params[1].isNull())
strCommand = request.params[1].get_str();
if (request.fHelp || request.params.size() != 2 ||
(strCommand != "onetry" && strCommand != "add" && strCommand != "remove"))
@@ -216,7 +217,7 @@ UniValue addnode(const JSONRPCRequest& request)
if (strCommand == "onetry")
{
CAddress addr;
- g_connman->OpenNetworkConnection(addr, false, NULL, strNode.c_str());
+ g_connman->OpenNetworkConnection(addr, false, nullptr, strNode.c_str());
return NullUniValue;
}
@@ -257,7 +258,7 @@ UniValue disconnectnode(const JSONRPCRequest& request)
bool success;
const UniValue &address_arg = request.params[0];
- const UniValue &id_arg = request.params.size() < 2 ? NullUniValue : request.params[1];
+ const UniValue &id_arg = request.params[1];
if (!address_arg.isNull() && id_arg.isNull()) {
/* handle disconnect-by-address */
@@ -310,7 +311,7 @@ UniValue getaddednodeinfo(const JSONRPCRequest& request)
std::vector<AddedNodeInfo> vInfo = g_connman->GetAddedNodeInfo();
- if (request.params.size() == 1) {
+ if (!request.params[0].isNull()) {
bool found = false;
for (const AddedNodeInfo& info : vInfo) {
if (info.strAddedNode == request.params[0].get_str()) {
@@ -489,7 +490,7 @@ UniValue getnetworkinfo(const JSONRPCRequest& request)
UniValue setban(const JSONRPCRequest& request)
{
std::string strCommand;
- if (request.params.size() >= 2)
+ if (!request.params[1].isNull())
strCommand = request.params[1].get_str();
if (request.fHelp || request.params.size() < 2 ||
(strCommand != "add" && strCommand != "remove"))
@@ -533,11 +534,11 @@ UniValue setban(const JSONRPCRequest& request)
throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: IP/Subnet already banned");
int64_t banTime = 0; //use standard bantime if not specified
- if (request.params.size() >= 3 && !request.params[2].isNull())
+ if (!request.params[2].isNull())
banTime = request.params[2].get_int64();
bool absolute = false;
- if (request.params.size() == 4 && request.params[3].isTrue())
+ if (request.params[3].isTrue())
absolute = true;
isSubnet ? g_connman->Ban(subNet, BanReasonManuallyAdded, banTime, absolute) : g_connman->Ban(netAddr, BanReasonManuallyAdded, banTime, absolute);
@@ -622,20 +623,20 @@ UniValue setnetworkactive(const JSONRPCRequest& request)
}
static const CRPCCommand commands[] =
-{ // category name actor (function) okSafeMode
+{ // category name actor (function) argNames
// --------------------- ------------------------ ----------------------- ----------
- { "network", "getconnectioncount", &getconnectioncount, true, {} },
- { "network", "ping", &ping, true, {} },
- { "network", "getpeerinfo", &getpeerinfo, true, {} },
- { "network", "addnode", &addnode, true, {"node","command"} },
- { "network", "disconnectnode", &disconnectnode, true, {"address", "nodeid"} },
- { "network", "getaddednodeinfo", &getaddednodeinfo, true, {"node"} },
- { "network", "getnettotals", &getnettotals, true, {} },
- { "network", "getnetworkinfo", &getnetworkinfo, true, {} },
- { "network", "setban", &setban, true, {"subnet", "command", "bantime", "absolute"} },
- { "network", "listbanned", &listbanned, true, {} },
- { "network", "clearbanned", &clearbanned, true, {} },
- { "network", "setnetworkactive", &setnetworkactive, true, {"state"} },
+ { "network", "getconnectioncount", &getconnectioncount, {} },
+ { "network", "ping", &ping, {} },
+ { "network", "getpeerinfo", &getpeerinfo, {} },
+ { "network", "addnode", &addnode, {"node","command"} },
+ { "network", "disconnectnode", &disconnectnode, {"address", "nodeid"} },
+ { "network", "getaddednodeinfo", &getaddednodeinfo, {"node"} },
+ { "network", "getnettotals", &getnettotals, {} },
+ { "network", "getnetworkinfo", &getnetworkinfo, {} },
+ { "network", "setban", &setban, {"subnet", "command", "bantime", "absolute"} },
+ { "network", "listbanned", &listbanned, {} },
+ { "network", "clearbanned", &clearbanned, {} },
+ { "network", "setnetworkactive", &setnetworkactive, {"state"} },
};
void RegisterNetRPCCommands(CRPCTable &t)
diff --git a/src/rpc/protocol.cpp b/src/rpc/protocol.cpp
index 823a5775f6..dc6bcec382 100644
--- a/src/rpc/protocol.cpp
+++ b/src/rpc/protocol.cpp
@@ -66,9 +66,14 @@ static const std::string COOKIEAUTH_USER = "__cookie__";
/** Default name for auth cookie file */
static const std::string COOKIEAUTH_FILE = ".cookie";
-fs::path GetAuthCookieFile()
+/** Get name of RPC authentication cookie file */
+static fs::path GetAuthCookieFile(bool temp=false)
{
- fs::path path(GetArg("-rpccookiefile", COOKIEAUTH_FILE));
+ std::string arg = gArgs.GetArg("-rpccookiefile", COOKIEAUTH_FILE);
+ if (temp) {
+ arg += ".tmp";
+ }
+ fs::path path(arg);
if (!path.is_complete()) path = GetDataDir() / path;
return path;
}
@@ -84,14 +89,20 @@ bool GenerateAuthCookie(std::string *cookie_out)
* these are set to 077 in init.cpp unless overridden with -sysperms.
*/
std::ofstream file;
- fs::path filepath = GetAuthCookieFile();
- file.open(filepath.string().c_str());
+ fs::path filepath_tmp = GetAuthCookieFile(true);
+ file.open(filepath_tmp.string().c_str());
if (!file.is_open()) {
- LogPrintf("Unable to open cookie authentication file %s for writing\n", filepath.string());
+ LogPrintf("Unable to open cookie authentication file %s for writing\n", filepath_tmp.string());
return false;
}
file << cookie;
file.close();
+
+ fs::path filepath = GetAuthCookieFile(false);
+ if (!RenameOver(filepath_tmp, filepath)) {
+ LogPrintf("Unable to rename cookie authentication file %s to %s\n", filepath_tmp.string(), filepath.string());
+ return false;
+ }
LogPrintf("Generated RPC authentication cookie %s\n", filepath.string());
if (cookie_out)
diff --git a/src/rpc/protocol.h b/src/rpc/protocol.h
index 70f7092cfe..5c9c64f67d 100644
--- a/src/rpc/protocol.h
+++ b/src/rpc/protocol.h
@@ -82,6 +82,8 @@ enum RPCErrorCode
RPC_WALLET_WRONG_ENC_STATE = -15, //!< Command given in wrong wallet encryption state (encrypting an encrypted wallet etc.)
RPC_WALLET_ENCRYPTION_FAILED = -16, //!< Failed to encrypt the wallet
RPC_WALLET_ALREADY_UNLOCKED = -17, //!< Wallet is already unlocked
+ RPC_WALLET_NOT_FOUND = -18, //!< Invalid wallet specified
+ RPC_WALLET_NOT_SPECIFIED = -19, //!< No wallet specified (error when there are multiple wallets loaded)
};
UniValue JSONRPCRequestObj(const std::string& strMethod, const UniValue& params, const UniValue& id);
@@ -89,8 +91,6 @@ UniValue JSONRPCReplyObj(const UniValue& result, const UniValue& error, const Un
std::string JSONRPCReply(const UniValue& result, const UniValue& error, const UniValue& id);
UniValue JSONRPCError(int code, const std::string& message);
-/** Get name of RPC authentication cookie file */
-fs::path GetAuthCookieFile();
/** Generate a new RPC authentication cookie and write it to disk */
bool GenerateAuthCookie(std::string *cookie_out);
/** Read the RPC authentication cookie from disk */
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index b878624df8..27daefaf5a 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -16,6 +16,7 @@
#include "policy/policy.h"
#include "policy/rbf.h"
#include "primitives/transaction.h"
+#include "rpc/safemode.h"
#include "rpc/server.h"
#include "script/script.h"
#include "script/script_error.h"
@@ -41,7 +42,7 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
// Blockchain contextual information (confirmations and blocktime) is not
// available to code in bitcoin-common, so we query them here and push the
// data into the returned UniValue.
- TxToUniv(tx, uint256(), entry);
+ TxToUniv(tx, uint256(), entry, true, RPCSerializationFlags());
if (!hashBlock.IsNull()) {
entry.push_back(Pair("blockhash", hashBlock.GetHex()));
@@ -137,7 +138,7 @@ UniValue getrawtransaction(const JSONRPCRequest& request)
// Accept either a bool (true) or a num (>=1) to indicate verbose output.
bool fVerbose = false;
- if (request.params.size() > 1) {
+ if (!request.params[1].isNull()) {
if (request.params[1].isNum()) {
if (request.params[1].get_int() != 0) {
fVerbose = true;
@@ -160,13 +161,10 @@ UniValue getrawtransaction(const JSONRPCRequest& request)
: "No such mempool transaction. Use -txindex to enable blockchain transaction queries") +
". Use gettransaction for wallet transactions.");
- std::string strHex = EncodeHexTx(*tx, RPCSerializationFlags());
-
if (!fVerbose)
- return strHex;
+ return EncodeHexTx(*tx, RPCSerializationFlags());
UniValue result(UniValue::VOBJ);
- result.push_back(Pair("hex", strHex));
TxToJSON(*tx, hashBlock, result);
return result;
}
@@ -208,10 +206,10 @@ UniValue gettxoutproof(const JSONRPCRequest& request)
LOCK(cs_main);
- CBlockIndex* pblockindex = NULL;
+ CBlockIndex* pblockindex = nullptr;
uint256 hashBlock;
- if (request.params.size() > 1)
+ if (!request.params[1].isNull())
{
hashBlock = uint256S(request.params[1].get_str());
if (!mapBlockIndex.count(hashBlock))
@@ -228,7 +226,7 @@ UniValue gettxoutproof(const JSONRPCRequest& request)
}
}
- if (pblockindex == NULL)
+ if (pblockindex == nullptr)
{
CTransactionRef tx;
if (!GetTransaction(oneTxid, tx, Params().GetConsensus(), hashBlock, false) || hashBlock.IsNull())
@@ -339,14 +337,14 @@ UniValue createrawtransaction(const JSONRPCRequest& request)
CMutableTransaction rawTx;
- if (request.params.size() > 2 && !request.params[2].isNull()) {
+ if (!request.params[2].isNull()) {
int64_t nLockTime = request.params[2].get_int64();
if (nLockTime < 0 || nLockTime > std::numeric_limits<uint32_t>::max())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, locktime out of range");
rawTx.nLockTime = nLockTime;
}
- bool rbfOptIn = request.params.size() > 3 ? request.params[3].isTrue() : false;
+ bool rbfOptIn = request.params[3].isTrue();
for (unsigned int idx = 0; idx < inputs.size(); idx++) {
const UniValue& input = inputs[idx];
@@ -412,7 +410,7 @@ UniValue createrawtransaction(const JSONRPCRequest& request)
}
}
- if (request.params.size() > 3 && rbfOptIn != SignalsOptInRBF(rawTx)) {
+ if (!request.params[3].isNull() && rbfOptIn != SignalsOptInRBF(rawTx)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter combination: Sequence number(s) contradict replaceable option");
}
@@ -483,7 +481,7 @@ UniValue decoderawtransaction(const JSONRPCRequest& request)
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
UniValue result(UniValue::VOBJ);
- TxToUniv(CTransaction(std::move(mtx)), uint256(), result);
+ TxToUniv(CTransaction(std::move(mtx)), uint256(), result, false);
return result;
}
@@ -554,6 +552,93 @@ static void TxInErrorToJSON(const CTxIn& txin, UniValue& vErrorsRet, const std::
vErrorsRet.push_back(entry);
}
+UniValue combinerawtransaction(const JSONRPCRequest& request)
+{
+
+ if (request.fHelp || request.params.size() != 1)
+ throw std::runtime_error(
+ "combinerawtransaction [\"hexstring\",...]\n"
+ "\nCombine multiple partially signed transactions into one transaction.\n"
+ "The combined transaction may be another partially signed transaction or a \n"
+ "fully signed transaction."
+
+ "\nArguments:\n"
+ "1. \"txs\" (string) A json array of hex strings of partially signed transactions\n"
+ " [\n"
+ " \"hexstring\" (string) A transaction hash\n"
+ " ,...\n"
+ " ]\n"
+
+ "\nResult:\n"
+ "\"hex\" (string) The hex-encoded raw transaction with signature(s)\n"
+
+ "\nExamples:\n"
+ + HelpExampleCli("combinerawtransaction", "[\"myhex1\", \"myhex2\", \"myhex3\"]")
+ );
+
+
+ UniValue txs = request.params[0].get_array();
+ std::vector<CMutableTransaction> txVariants(txs.size());
+
+ for (unsigned int idx = 0; idx < txs.size(); idx++) {
+ if (!DecodeHexTx(txVariants[idx], txs[idx].get_str(), true)) {
+ throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed for tx %d", idx));
+ }
+ }
+
+ if (txVariants.empty()) {
+ throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Missing transactions");
+ }
+
+ // mergedTx will end up with all the signatures; it
+ // starts as a clone of the rawtx:
+ CMutableTransaction mergedTx(txVariants[0]);
+
+ // Fetch previous transactions (inputs):
+ CCoinsView viewDummy;
+ CCoinsViewCache view(&viewDummy);
+ {
+ LOCK(cs_main);
+ LOCK(mempool.cs);
+ CCoinsViewCache &viewChain = *pcoinsTip;
+ CCoinsViewMemPool viewMempool(&viewChain, mempool);
+ view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view
+
+ for (const CTxIn& txin : mergedTx.vin) {
+ view.AccessCoin(txin.prevout); // Load entries from viewChain into view; can fail.
+ }
+
+ view.SetBackend(viewDummy); // switch back to avoid locking mempool for too long
+ }
+
+ // Use CTransaction for the constant parts of the
+ // transaction to avoid rehashing.
+ const CTransaction txConst(mergedTx);
+ // Sign what we can:
+ for (unsigned int i = 0; i < mergedTx.vin.size(); i++) {
+ CTxIn& txin = mergedTx.vin[i];
+ const Coin& coin = view.AccessCoin(txin.prevout);
+ if (coin.IsSpent()) {
+ throw JSONRPCError(RPC_VERIFY_ERROR, "Input not found or already spent");
+ }
+ const CScript& prevPubKey = coin.out.scriptPubKey;
+ const CAmount& amount = coin.out.nValue;
+
+ SignatureData sigdata;
+
+ // ... and merge in other signatures:
+ for (const CMutableTransaction& txv : txVariants) {
+ if (txv.vin.size() > i) {
+ sigdata = CombineSignatures(prevPubKey, TransactionSignatureChecker(&txConst, i, amount), sigdata, DataFromTransaction(txv, i));
+ }
+ }
+
+ UpdateTransaction(mergedTx, i, sigdata);
+ }
+
+ return EncodeHexTx(mergedTx);
+}
+
UniValue signrawtransaction(const JSONRPCRequest& request)
{
#ifdef ENABLE_WALLET
@@ -619,33 +704,17 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
+ HelpExampleRpc("signrawtransaction", "\"myhex\"")
);
+ ObserveSafeMode();
#ifdef ENABLE_WALLET
- LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);
+ LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : nullptr);
#else
LOCK(cs_main);
#endif
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR, UniValue::VARR, UniValue::VSTR}, true);
- std::vector<unsigned char> txData(ParseHexV(request.params[0], "argument 1"));
- CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
- std::vector<CMutableTransaction> txVariants;
- while (!ssData.empty()) {
- try {
- CMutableTransaction tx;
- ssData >> tx;
- txVariants.push_back(tx);
- }
- catch (const std::exception&) {
- throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
- }
- }
-
- if (txVariants.empty())
- throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Missing transaction");
-
- // mergedTx will end up with all the signatures; it
- // starts as a clone of the rawtx:
- CMutableTransaction mergedTx(txVariants[0]);
+ CMutableTransaction mtx;
+ if (!DecodeHexTx(mtx, request.params[0].get_str(), true))
+ throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
// Fetch previous transactions (inputs):
CCoinsView viewDummy;
@@ -656,7 +725,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
CCoinsViewMemPool viewMempool(&viewChain, mempool);
view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view
- for (const CTxIn& txin : mergedTx.vin) {
+ for (const CTxIn& txin : mtx.vin) {
view.AccessCoin(txin.prevout); // Load entries from viewChain into view; can fail.
}
@@ -665,7 +734,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
bool fGivenKeys = false;
CBasicKeyStore tempKeystore;
- if (request.params.size() > 2 && !request.params[2].isNull()) {
+ if (!request.params[2].isNull()) {
fGivenKeys = true;
UniValue keys = request.params[2].get_array();
for (unsigned int idx = 0; idx < keys.size(); idx++) {
@@ -687,7 +756,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
#endif
// Add previous txouts given in the RPC call:
- if (request.params.size() > 1 && !request.params[1].isNull()) {
+ if (!request.params[1].isNull()) {
UniValue prevTxs = request.params[1].get_array();
for (unsigned int idx = 0; idx < prevTxs.size(); idx++) {
const UniValue& p = prevTxs[idx];
@@ -758,7 +827,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
#endif
int nHashType = SIGHASH_ALL;
- if (request.params.size() > 3 && !request.params[3].isNull()) {
+ if (!request.params[3].isNull()) {
static std::map<std::string, int> mapSigHashValues = {
{std::string("ALL"), int(SIGHASH_ALL)},
{std::string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY)},
@@ -781,10 +850,10 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
// Use CTransaction for the constant parts of the
// transaction to avoid rehashing.
- const CTransaction txConst(mergedTx);
+ const CTransaction txConst(mtx);
// Sign what we can:
- for (unsigned int i = 0; i < mergedTx.vin.size(); i++) {
- CTxIn& txin = mergedTx.vin[i];
+ for (unsigned int i = 0; i < mtx.vin.size(); i++) {
+ CTxIn& txin = mtx.vin[i];
const Coin& coin = view.AccessCoin(txin.prevout);
if (coin.IsSpent()) {
TxInErrorToJSON(txin, vErrors, "Input not found or already spent");
@@ -795,17 +864,11 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
SignatureData sigdata;
// Only sign SIGHASH_SINGLE if there's a corresponding output:
- if (!fHashSingle || (i < mergedTx.vout.size()))
- ProduceSignature(MutableTransactionSignatureCreator(&keystore, &mergedTx, i, amount, nHashType), prevPubKey, sigdata);
+ if (!fHashSingle || (i < mtx.vout.size()))
+ ProduceSignature(MutableTransactionSignatureCreator(&keystore, &mtx, i, amount, nHashType), prevPubKey, sigdata);
+ sigdata = CombineSignatures(prevPubKey, TransactionSignatureChecker(&txConst, i, amount), sigdata, DataFromTransaction(mtx, i));
- // ... and merge in other signatures:
- for (const CMutableTransaction& txv : txVariants) {
- if (txv.vin.size() > i) {
- sigdata = CombineSignatures(prevPubKey, TransactionSignatureChecker(&txConst, i, amount), sigdata, DataFromTransaction(txv, i));
- }
- }
-
- UpdateTransaction(mergedTx, i, sigdata);
+ UpdateTransaction(mtx, i, sigdata);
ScriptError serror = SCRIPT_ERR_OK;
if (!VerifyScript(txin.scriptSig, prevPubKey, &txin.scriptWitness, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker(&txConst, i, amount), &serror)) {
@@ -815,7 +878,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
bool fComplete = vErrors.empty();
UniValue result(UniValue::VOBJ);
- result.push_back(Pair("hex", EncodeHexTx(mergedTx)));
+ result.push_back(Pair("hex", EncodeHexTx(mtx)));
result.push_back(Pair("complete", fComplete));
if (!vErrors.empty()) {
result.push_back(Pair("errors", vErrors));
@@ -847,6 +910,7 @@ UniValue sendrawtransaction(const JSONRPCRequest& request)
+ HelpExampleRpc("sendrawtransaction", "\"signedhex\"")
);
+ ObserveSafeMode();
LOCK(cs_main);
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL});
@@ -858,7 +922,7 @@ UniValue sendrawtransaction(const JSONRPCRequest& request)
const uint256& hashTx = tx->GetHash();
CAmount nMaxRawTxFee = maxTxFee;
- if (request.params.size() > 1 && request.params[1].get_bool())
+ if (!request.params[1].isNull() && request.params[1].get_bool())
nMaxRawTxFee = 0;
CCoinsViewCache &view = *pcoinsTip;
@@ -873,7 +937,7 @@ UniValue sendrawtransaction(const JSONRPCRequest& request)
CValidationState state;
bool fMissingInputs;
bool fLimitFree = true;
- if (!AcceptToMemoryPool(mempool, state, std::move(tx), fLimitFree, &fMissingInputs, NULL, false, nMaxRawTxFee)) {
+ if (!AcceptToMemoryPool(mempool, state, std::move(tx), fLimitFree, &fMissingInputs, nullptr, false, nMaxRawTxFee)) {
if (state.IsInvalid()) {
throw JSONRPCError(RPC_TRANSACTION_REJECTED, strprintf("%i: %s", state.GetRejectCode(), state.GetRejectReason()));
} else {
@@ -898,17 +962,18 @@ UniValue sendrawtransaction(const JSONRPCRequest& request)
}
static const CRPCCommand commands[] =
-{ // category name actor (function) okSafeMode
+{ // category name actor (function) argNames
// --------------------- ------------------------ ----------------------- ----------
- { "rawtransactions", "getrawtransaction", &getrawtransaction, true, {"txid","verbose"} },
- { "rawtransactions", "createrawtransaction", &createrawtransaction, true, {"inputs","outputs","locktime","replaceable"} },
- { "rawtransactions", "decoderawtransaction", &decoderawtransaction, true, {"hexstring"} },
- { "rawtransactions", "decodescript", &decodescript, true, {"hexstring"} },
- { "rawtransactions", "sendrawtransaction", &sendrawtransaction, false, {"hexstring","allowhighfees"} },
- { "rawtransactions", "signrawtransaction", &signrawtransaction, false, {"hexstring","prevtxs","privkeys","sighashtype"} }, /* uses wallet if enabled */
-
- { "blockchain", "gettxoutproof", &gettxoutproof, true, {"txids", "blockhash"} },
- { "blockchain", "verifytxoutproof", &verifytxoutproof, true, {"proof"} },
+ { "rawtransactions", "getrawtransaction", &getrawtransaction, {"txid","verbose"} },
+ { "rawtransactions", "createrawtransaction", &createrawtransaction, {"inputs","outputs","locktime","replaceable"} },
+ { "rawtransactions", "decoderawtransaction", &decoderawtransaction, {"hexstring"} },
+ { "rawtransactions", "decodescript", &decodescript, {"hexstring"} },
+ { "rawtransactions", "sendrawtransaction", &sendrawtransaction, {"hexstring","allowhighfees"} },
+ { "rawtransactions", "combinerawtransaction", &combinerawtransaction, {"txs"} },
+ { "rawtransactions", "signrawtransaction", &signrawtransaction, {"hexstring","prevtxs","privkeys","sighashtype"} }, /* uses wallet if enabled */
+
+ { "blockchain", "gettxoutproof", &gettxoutproof, {"txids", "blockhash"} },
+ { "blockchain", "verifytxoutproof", &verifytxoutproof, {"proof"} },
};
void RegisterRawTransactionRPCCommands(CRPCTable &t)
diff --git a/src/rpc/safemode.cpp b/src/rpc/safemode.cpp
new file mode 100644
index 0000000000..24770ad47f
--- /dev/null
+++ b/src/rpc/safemode.cpp
@@ -0,0 +1,14 @@
+#include "safemode.h"
+
+#include "rpc/protocol.h"
+#include "util.h"
+#include "warnings.h"
+
+void ObserveSafeMode()
+{
+ std::string warning = GetWarnings("rpc");
+ if (warning != "" && !gArgs.GetBoolArg("-disablesafemode", DEFAULT_DISABLE_SAFEMODE)) {
+ throw JSONRPCError(RPC_FORBIDDEN_BY_SAFE_MODE, std::string("Safe mode: ") + warning);
+ }
+}
+
diff --git a/src/rpc/safemode.h b/src/rpc/safemode.h
new file mode 100644
index 0000000000..8466d6b2f9
--- /dev/null
+++ b/src/rpc/safemode.h
@@ -0,0 +1,12 @@
+// Copyright (c) 2017 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_RPC_SAFEMODE_H
+#define BITCOIN_RPC_SAFEMODE_H
+
+static const bool DEFAULT_DISABLE_SAFEMODE = true;
+
+void ObserveSafeMode();
+
+#endif // BITCOIN_RPC_SAFEMODE_H
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index 63e4e9c630..428ab3b9b0 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -30,7 +30,7 @@ static bool fRPCInWarmup = true;
static std::string rpcWarmupStatus("RPC server started");
static CCriticalSection cs_rpcWarmup;
/* Timer-creating functions */
-static RPCTimerInterface* timerInterface = NULL;
+static RPCTimerInterface* timerInterface = nullptr;
/* Map of name to timer. */
static std::map<std::string, std::unique_ptr<RPCTimerBase> > deadlineTimers;
@@ -51,11 +51,6 @@ void RPCServer::OnStopped(std::function<void ()> slot)
g_rpcSignals.Stopped.connect(slot);
}
-void RPCServer::OnPreCommand(std::function<void (const CRPCCommand&)> slot)
-{
- g_rpcSignals.PreCommand.connect(boost::bind(slot, _1));
-}
-
void RPCTypeCheck(const UniValue& params,
const std::list<UniValue::VType>& typesExpected,
bool fAllowNull)
@@ -123,16 +118,6 @@ CAmount AmountFromValue(const UniValue& value)
return amount;
}
-UniValue ValueFromAmount(const CAmount& amount)
-{
- bool sign = amount < 0;
- int64_t n_abs = (sign ? -amount : amount);
- int64_t quotient = n_abs / COIN;
- int64_t remainder = n_abs % COIN;
- return UniValue(UniValue::VNUM,
- strprintf("%s%d.%08d", sign ? "-" : "", quotient, remainder));
-}
-
uint256 ParseHashV(const UniValue& v, std::string strName)
{
std::string strHex;
@@ -277,12 +262,12 @@ UniValue uptime(const JSONRPCRequest& jsonRequest)
* Call Table
*/
static const CRPCCommand vRPCCommands[] =
-{ // category name actor (function) okSafe argNames
- // --------------------- ------------------------ ----------------------- ------ ----------
+{ // category name actor (function) argNames
+ // --------------------- ------------------------ ----------------------- ----------
/* Overall control/query calls */
- { "control", "help", &help, true, {"command"} },
- { "control", "stop", &stop, true, {} },
- { "control", "uptime", &uptime, true, {} },
+ { "control", "help", &help, {"command"} },
+ { "control", "stop", &stop, {} },
+ { "control", "uptime", &uptime, {} },
};
CRPCTable::CRPCTable()
@@ -301,7 +286,7 @@ const CRPCCommand *CRPCTable::operator[](const std::string &name) const
{
std::map<std::string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
if (it == mapCommands.end())
- return NULL;
+ return nullptr;
return (*it).second;
}
@@ -547,7 +532,7 @@ void RPCSetTimerInterface(RPCTimerInterface *iface)
void RPCUnsetTimerInterface(RPCTimerInterface *iface)
{
if (timerInterface == iface)
- timerInterface = NULL;
+ timerInterface = nullptr;
}
void RPCRunLater(const std::string& name, std::function<void(void)> func, int64_t nSeconds)
@@ -562,7 +547,7 @@ void RPCRunLater(const std::string& name, std::function<void(void)> func, int64_
int RPCSerializationFlags()
{
int flag = 0;
- if (GetArg("-rpcserialversion", DEFAULT_RPC_SERIALIZE_VERSION) == 0)
+ if (gArgs.GetArg("-rpcserialversion", DEFAULT_RPC_SERIALIZE_VERSION) == 0)
flag |= SERIALIZE_TRANSACTION_NO_WITNESS;
return flag;
}
diff --git a/src/rpc/server.h b/src/rpc/server.h
index b20c827727..777acbcb94 100644
--- a/src/rpc/server.h
+++ b/src/rpc/server.h
@@ -25,13 +25,12 @@ namespace RPCServer
{
void OnStarted(std::function<void ()> slot);
void OnStopped(std::function<void ()> slot);
- void OnPreCommand(std::function<void (const CRPCCommand&)> slot);
}
/** Wrapper for UniValue::VType, which includes typeAny:
* Used to denote don't care type. Only used by RPCTypeCheckObj */
struct UniValueType {
- UniValueType(UniValue::VType _type) : typeAny(false), type(_type) {}
+ explicit UniValueType(UniValue::VType _type) : typeAny(false), type(_type) {}
UniValueType() : typeAny(true) {}
bool typeAny;
UniValue::VType type;
@@ -134,7 +133,6 @@ public:
std::string category;
std::string name;
rpcfn_type actor;
- bool okSafeMode;
std::vector<std::string> argNames;
};
@@ -185,7 +183,6 @@ extern std::vector<unsigned char> ParseHexV(const UniValue& v, std::string strNa
extern std::vector<unsigned char> ParseHexO(const UniValue& o, std::string strKey);
extern CAmount AmountFromValue(const UniValue& value);
-extern UniValue ValueFromAmount(const CAmount& amount);
extern std::string HelpExampleCli(const std::string& methodname, const std::string& args);
extern std::string HelpExampleRpc(const std::string& methodname, const std::string& args);