aboutsummaryrefslogtreecommitdiff
path: root/src/rpc
diff options
context:
space:
mode:
Diffstat (limited to 'src/rpc')
-rw-r--r--src/rpc/blockchain.cpp24
-rw-r--r--src/rpc/client.cpp8
-rw-r--r--src/rpc/mining.cpp210
-rw-r--r--src/rpc/mining.h3
-rw-r--r--src/rpc/misc.cpp16
-rw-r--r--src/rpc/net.cpp4
-rw-r--r--src/rpc/protocol.h2
-rw-r--r--src/rpc/rawtransaction.cpp141
8 files changed, 271 insertions, 137 deletions
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index c17ca2fa3a..d65e107e3c 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -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
@@ -798,7 +798,7 @@ static void ApplyStats(CCoinsStats &stats, CHashWriter& ss, const uint256& hash,
stats.nTransactions++;
for (const auto output : outputs) {
ss << VARINT(output.first + 1);
- ss << *(const CScriptBase*)(&output.second.out.scriptPubKey);
+ ss << output.second.out.scriptPubKey;
ss << VARINT(output.second.out.nValue);
stats.nTransactionOutputs++;
stats.nTotalAmount += output.second.out.nValue;
@@ -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;
@@ -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);
diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp
index 8fac8af3ec..4179453782 100644
--- a/src/rpc/client.cpp
+++ b/src/rpc/client.cpp
@@ -37,6 +37,8 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "getnetworkhashps", 1, "height" },
{ "sendtoaddress", 1, "amount" },
{ "sendtoaddress", 4, "subtractfeefromamount" },
+ { "sendtoaddress", 5 , "replaceable" },
+ { "sendtoaddress", 6 , "conf_target" },
{ "settxfee", 0, "amount" },
{ "getreceivedbyaddress", 1, "minconf" },
{ "getreceivedbyaccount", 1, "minconf" },
@@ -66,9 +68,12 @@ 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" },
+ { "sendmany", 5 , "replaceable" },
+ { "sendmany", 6 , "conf_target" },
{ "addmultisigaddress", 0, "nrequired" },
{ "addmultisigaddress", 1, "keys" },
{ "createmultisig", 0, "nrequired" },
@@ -91,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" },
@@ -110,10 +116,8 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "getrawmempool", 0, "verbose" },
{ "estimatefee", 0, "nblocks" },
{ "estimatesmartfee", 0, "nblocks" },
- { "estimatesmartfee", 1, "conservative" },
{ "estimaterawfee", 0, "nblocks" },
{ "estimaterawfee", 1, "threshold" },
- { "estimaterawfee", 2, "horizon" },
{ "prioritisetransaction", 1, "dummy" },
{ "prioritisetransaction", 2, "fee_delta" },
{ "setban", 2, "bantime" },
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index e50742f36e..7d292a4635 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -24,12 +24,23 @@
#include "util.h"
#include "utilstrencodings.h"
#include "validationinterface.h"
+#include "warnings.h"
#include <memory>
#include <stdint.h>
#include <univalue.h>
+unsigned int ParseConfirmTarget(const UniValue& value)
+{
+ int target = value.get_int();
+ unsigned int max_target = ::feeEstimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE);
+ if (target < 1 || (unsigned int)target > max_target) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid conf_target, must be between %u - %u", 1, max_target));
+ }
+ return (unsigned int)target;
+}
+
/**
* Return average network hashes per second based on the last 'lookup' blocks,
* or from the last difficulty change if 'lookup' is nonpositive.
@@ -91,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)
@@ -161,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();
}
@@ -363,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");
@@ -645,15 +656,16 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
result.push_back(Pair("mutable", aMutable));
result.push_back(Pair("noncerange", "00000000ffffffff"));
int64_t nSigOpLimit = MAX_BLOCK_SIGOPS_COST;
+ int64_t nSizeLimit = MAX_BLOCK_SERIALIZED_SIZE;
if (fPreSegWit) {
assert(nSigOpLimit % WITNESS_SCALE_FACTOR == 0);
nSigOpLimit /= WITNESS_SCALE_FACTOR;
+ assert(nSizeLimit % WITNESS_SCALE_FACTOR == 0);
+ nSizeLimit /= WITNESS_SCALE_FACTOR;
}
result.push_back(Pair("sigoplimit", nSigOpLimit));
- if (fPreSegWit) {
- result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_BASE_SIZE));
- } else {
- result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_SERIALIZED_SIZE));
+ result.push_back(Pair("sizelimit", nSizeLimit));
+ if (!fPreSegWit) {
result.push_back(Pair("weightlimit", (int64_t)MAX_BLOCK_WEIGHT));
}
result.push_back(Pair("curtime", pblock->GetBlockTime()));
@@ -795,126 +807,162 @@ UniValue estimatesmartfee(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
throw std::runtime_error(
- "estimatesmartfee nblocks (conservative)\n"
+ "estimatesmartfee conf_target (\"estimate_mode\")\n"
"\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n"
- "confirmation within nblocks blocks if possible and return the number of blocks\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"
"in BIP 141 (witness data is discounted).\n"
"\nArguments:\n"
- "1. nblocks (numeric)\n"
- "2. conservative (bool, optional, default=true) Whether to return a more conservative estimate which\n"
- " also satisfies a longer history. A conservative estimate potentially returns a higher\n"
- " feerate and is more likely to be sufficient for the desired target, but is not as\n"
- " responsive to short term drops in the prevailing fee market\n"
+ "1. conf_target (numeric) Confirmation target in blocks (1 - 1008)\n"
+ "2. \"estimate_mode\" (string, optional, default=CONSERVATIVE) The fee estimate mode.\n"
+ " Whether to return a more conservative estimate which also satisfies\n"
+ " a longer history. A conservative estimate potentially returns a\n"
+ " higher feerate and is more likely to be sufficient for the desired\n"
+ " target, but is not as responsive to short term drops in the\n"
+ " prevailing fee market. Must be one of:\n"
+ " \"UNSET\" (defaults to CONSERVATIVE)\n"
+ " \"ECONOMICAL\"\n"
+ " \"CONSERVATIVE\"\n"
"\nResult:\n"
"{\n"
- " \"feerate\" : x.x, (numeric) estimate fee-per-kilobyte (in BTC)\n"
+ " \"feerate\" : x.x, (numeric, optional) estimate fee-per-kilobyte (in BTC)\n"
+ " \"errors\": [ str... ] (json array of strings, optional) Errors encountered during processing\n"
" \"blocks\" : n (numeric) block number where estimate was found\n"
"}\n"
"\n"
- "A negative value is returned if not enough transactions and blocks\n"
+ "The request target will be clamped between 2 and the highest target\n"
+ "fee estimation is able to return based on how long it has been running.\n"
+ "An error is returned if not enough transactions and blocks\n"
"have been observed to make an estimate for any number of blocks.\n"
- "However it will not return a value below the mempool reject fee.\n"
"\nExample:\n"
+ HelpExampleCli("estimatesmartfee", "6")
);
- RPCTypeCheck(request.params, {UniValue::VNUM});
-
- int nBlocks = request.params[0].get_int();
+ RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VSTR});
+ 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()) {
- RPCTypeCheckArgument(request.params[1], UniValue::VBOOL);
- conservative = request.params[1].get_bool();
+ FeeEstimateMode fee_mode;
+ if (!FeeModeFromString(request.params[1].get_str(), fee_mode)) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter");
+ }
+ if (fee_mode == FeeEstimateMode::ECONOMICAL) conservative = false;
}
UniValue result(UniValue::VOBJ);
+ UniValue errors(UniValue::VARR);
FeeCalculation feeCalc;
- CFeeRate feeRate = ::feeEstimator.estimateSmartFee(nBlocks, &feeCalc, ::mempool, conservative);
- result.push_back(Pair("feerate", feeRate == CFeeRate(0) ? -1.0 : ValueFromAmount(feeRate.GetFeePerK())));
+ CFeeRate feeRate = ::feeEstimator.estimateSmartFee(conf_target, &feeCalc, conservative);
+ if (feeRate != CFeeRate(0)) {
+ result.push_back(Pair("feerate", ValueFromAmount(feeRate.GetFeePerK())));
+ } else {
+ errors.push_back("Insufficient data or no feerate found");
+ result.push_back(Pair("errors", errors));
+ }
result.push_back(Pair("blocks", feeCalc.returnedTarget));
return result;
}
UniValue estimaterawfee(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() < 1|| request.params.size() > 3)
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
throw std::runtime_error(
- "estimaterawfee nblocks (threshold horizon)\n"
+ "estimaterawfee conf_target (threshold)\n"
"\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"
" and the results it returns will change if the internal implementation changes.\n"
"\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n"
- "confirmation within nblocks blocks if possible. Uses virtual transaction size as defined\n"
- "in BIP 141 (witness data is discounted).\n"
+ "confirmation within conf_target blocks if possible. Uses virtual transaction size as\n"
+ "defined in BIP 141 (witness data is discounted).\n"
"\nArguments:\n"
- "1. nblocks (numeric)\n"
+ "1. conf_target (numeric) Confirmation target in blocks (1 - 1008)\n"
"2. threshold (numeric, optional) The proportion of transactions in a given feerate range that must have been\n"
- " confirmed within nblocks in order to consider those feerates as high enough and proceed to check\n"
+ " confirmed within conf_target in order to consider those feerates as high enough and proceed to check\n"
" lower buckets. Default: 0.95\n"
- "3. horizon (numeric, optional) How long a history of estimates to consider. 0=short, 1=medium, 2=long.\n"
- " Default: 1\n"
"\nResult:\n"
"{\n"
- " \"feerate\" : x.x, (numeric) estimate fee-per-kilobyte (in BTC)\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) information about the lowest range of feerates to succeed in meeting the threshold\n"
- " \"startrange\" : x.x, (numeric) start of feerate range\n"
- " \"endrange\" : x.x, (numeric) end of feerate range\n"
- " \"withintarget\" : x.x, (numeric) number of txs over history horizon in the feerate range that were confirmed within target\n"
- " \"totalconfirmed\" : x.x, (numeric) number of txs over history horizon in the feerate range that were confirmed at any point\n"
- " \"inmempool\" : x.x, (numeric) current number of txs in mempool in the feerate range unconfirmed for at least target blocks\n"
- " \"leftmempool\" : x.x, (numeric) number of txs over history horizon in the feerate range that left mempool unconfirmed after target\n"
- " }\n"
- " \"fail\" : { ... } (json object) information about the highest range of feerates to fail to meet the threshold\n"
+ " \"short\" : { (json object, optional) estimate for short time horizon\n"
+ " \"feerate\" : x.x, (numeric, optional) estimate fee-per-kilobyte (in BTC)\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"
+ " \"startrange\" : x.x, (numeric) start of feerate range\n"
+ " \"endrange\" : x.x, (numeric) end of feerate range\n"
+ " \"withintarget\" : x.x, (numeric) number of txs over history horizon in the feerate range that were confirmed within target\n"
+ " \"totalconfirmed\" : x.x, (numeric) number of txs over history horizon in the feerate range that were confirmed at any point\n"
+ " \"inmempool\" : x.x, (numeric) current number of txs in mempool in the feerate range unconfirmed for at least target blocks\n"
+ " \"leftmempool\" : x.x, (numeric) number of txs over history horizon in the feerate range that left mempool unconfirmed after target\n"
+ " },\n"
+ " \"fail\" : { ... }, (json object, optional) information about the highest range of feerates to fail to meet the threshold\n"
+ " \"errors\": [ str... ] (json array of strings, optional) Errors encountered during processing\n"
+ " },\n"
+ " \"medium\" : { ... }, (json object, optional) estimate for medium time horizon\n"
+ " \"long\" : { ... } (json object) estimate for long time horizon\n"
"}\n"
"\n"
- "A negative feerate is returned if no answer can be given.\n"
+ "Results are returned for any horizon which tracks blocks up to the confirmation target.\n"
"\nExample:\n"
- + HelpExampleCli("estimaterawfee", "6 0.9 1")
+ + HelpExampleCli("estimaterawfee", "6 0.9")
);
- RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VNUM, UniValue::VNUM}, true);
+ RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VNUM}, true);
RPCTypeCheckArgument(request.params[0], UniValue::VNUM);
- int nBlocks = request.params[0].get_int();
+ unsigned int conf_target = ParseConfirmTarget(request.params[0]);
double threshold = 0.95;
- if (!request.params[1].isNull())
+ if (!request.params[1].isNull()) {
threshold = request.params[1].get_real();
- FeeEstimateHorizon horizon = FeeEstimateHorizon::MED_HALFLIFE;
- if (!request.params[2].isNull()) {
- int horizonInt = request.params[2].get_int();
- if (horizonInt < 0 || horizonInt > 2) {
- throw JSONRPCError(RPC_TYPE_ERROR, "Invalid horizon for fee estimates");
+ }
+ if (threshold < 0 || threshold > 1) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid threshold");
+ }
+
+ UniValue result(UniValue::VOBJ);
+
+ for (FeeEstimateHorizon horizon : {FeeEstimateHorizon::SHORT_HALFLIFE, FeeEstimateHorizon::MED_HALFLIFE, FeeEstimateHorizon::LONG_HALFLIFE}) {
+ CFeeRate feeRate;
+ EstimationResult buckets;
+
+ // Only output results for horizons which track the target
+ if (conf_target > ::feeEstimator.HighestTargetTracked(horizon)) continue;
+
+ feeRate = ::feeEstimator.estimateRawFee(conf_target, threshold, horizon, &buckets);
+ UniValue horizon_result(UniValue::VOBJ);
+ UniValue errors(UniValue::VARR);
+ UniValue passbucket(UniValue::VOBJ);
+ passbucket.push_back(Pair("startrange", round(buckets.pass.start)));
+ passbucket.push_back(Pair("endrange", round(buckets.pass.end)));
+ passbucket.push_back(Pair("withintarget", round(buckets.pass.withinTarget * 100.0) / 100.0));
+ passbucket.push_back(Pair("totalconfirmed", round(buckets.pass.totalConfirmed * 100.0) / 100.0));
+ passbucket.push_back(Pair("inmempool", round(buckets.pass.inMempool * 100.0) / 100.0));
+ passbucket.push_back(Pair("leftmempool", round(buckets.pass.leftMempool * 100.0) / 100.0));
+ UniValue failbucket(UniValue::VOBJ);
+ failbucket.push_back(Pair("startrange", round(buckets.fail.start)));
+ failbucket.push_back(Pair("endrange", round(buckets.fail.end)));
+ failbucket.push_back(Pair("withintarget", round(buckets.fail.withinTarget * 100.0) / 100.0));
+ failbucket.push_back(Pair("totalconfirmed", round(buckets.fail.totalConfirmed * 100.0) / 100.0));
+ failbucket.push_back(Pair("inmempool", round(buckets.fail.inMempool * 100.0) / 100.0));
+ failbucket.push_back(Pair("leftmempool", round(buckets.fail.leftMempool * 100.0) / 100.0));
+
+ // CFeeRate(0) is used to indicate error as a return value from estimateRawFee
+ if (feeRate != CFeeRate(0)) {
+ horizon_result.push_back(Pair("feerate", ValueFromAmount(feeRate.GetFeePerK())));
+ horizon_result.push_back(Pair("decay", buckets.decay));
+ horizon_result.push_back(Pair("scale", (int)buckets.scale));
+ horizon_result.push_back(Pair("pass", passbucket));
+ // buckets.fail.start == -1 indicates that all buckets passed, there is no fail bucket to output
+ if (buckets.fail.start != -1) horizon_result.push_back(Pair("fail", failbucket));
} else {
- horizon = (FeeEstimateHorizon)horizonInt;
+ // Output only information that is still meaningful in the event of error
+ horizon_result.push_back(Pair("decay", buckets.decay));
+ horizon_result.push_back(Pair("scale", (int)buckets.scale));
+ horizon_result.push_back(Pair("fail", failbucket));
+ errors.push_back("Insufficient data or no feerate found which meets threshold");
+ horizon_result.push_back(Pair("errors",errors));
}
+ result.push_back(Pair(StringForFeeEstimateHorizon(horizon), horizon_result));
}
- UniValue result(UniValue::VOBJ);
- CFeeRate feeRate;
- EstimationResult buckets;
- feeRate = ::feeEstimator.estimateRawFee(nBlocks, threshold, horizon, &buckets);
-
- result.push_back(Pair("feerate", feeRate == CFeeRate(0) ? -1.0 : ValueFromAmount(feeRate.GetFeePerK())));
- result.push_back(Pair("decay", buckets.decay));
- result.push_back(Pair("scale", (int)buckets.scale));
- UniValue passbucket(UniValue::VOBJ);
- passbucket.push_back(Pair("startrange", round(buckets.pass.start)));
- passbucket.push_back(Pair("endrange", round(buckets.pass.end)));
- passbucket.push_back(Pair("withintarget", round(buckets.pass.withinTarget * 100.0) / 100.0));
- passbucket.push_back(Pair("totalconfirmed", round(buckets.pass.totalConfirmed * 100.0) / 100.0));
- passbucket.push_back(Pair("inmempool", round(buckets.pass.inMempool * 100.0) / 100.0));
- passbucket.push_back(Pair("leftmempool", round(buckets.pass.leftMempool * 100.0) / 100.0));
- result.push_back(Pair("pass", passbucket));
- UniValue failbucket(UniValue::VOBJ);
- failbucket.push_back(Pair("startrange", round(buckets.fail.start)));
- failbucket.push_back(Pair("endrange", round(buckets.fail.end)));
- failbucket.push_back(Pair("withintarget", round(buckets.fail.withinTarget * 100.0) / 100.0));
- failbucket.push_back(Pair("totalconfirmed", round(buckets.fail.totalConfirmed * 100.0) / 100.0));
- failbucket.push_back(Pair("inmempool", round(buckets.fail.inMempool * 100.0) / 100.0));
- failbucket.push_back(Pair("leftmempool", round(buckets.fail.leftMempool * 100.0) / 100.0));
- result.push_back(Pair("fail", failbucket));
return result;
}
@@ -930,9 +978,9 @@ static const CRPCCommand commands[] =
{ "generating", "generatetoaddress", &generatetoaddress, true, {"nblocks","address","maxtries"} },
{ "util", "estimatefee", &estimatefee, true, {"nblocks"} },
- { "util", "estimatesmartfee", &estimatesmartfee, true, {"nblocks", "conservative"} },
+ { "util", "estimatesmartfee", &estimatesmartfee, true, {"conf_target", "estimate_mode"} },
- { "hidden", "estimaterawfee", &estimaterawfee, true, {"nblocks", "threshold", "horizon"} },
+ { "hidden", "estimaterawfee", &estimaterawfee, true, {"conf_target", "threshold"} },
};
void RegisterMiningRPCCommands(CRPCTable &t)
diff --git a/src/rpc/mining.h b/src/rpc/mining.h
index a148d851da..868d7002b5 100644
--- a/src/rpc/mining.h
+++ b/src/rpc/mining.h
@@ -12,4 +12,7 @@
/** Generate blocks (mine) */
UniValue generateBlocks(std::shared_ptr<CReserveScript> coinbaseScript, int nGenerate, uint64_t nMaxTries, bool keepScript);
+/** Check bounds on a command line confirm target */
+unsigned int ParseConfirmTarget(const UniValue& value);
+
#endif
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index ef19e481c2..f3c86038a3 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -21,6 +21,7 @@
#include "wallet/wallet.h"
#include "wallet/walletdb.h"
#endif
+#include "warnings.h"
#include <stdint.h>
#ifdef HAVE_MALLOC_INFO
@@ -50,6 +51,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 +59,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 +67,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", "")
@@ -84,6 +86,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
@@ -174,6 +178,14 @@ UniValue validateaddress(const JSONRPCRequest& request)
" \"ismine\" : true|false, (boolean) If the address is yours or not\n"
" \"iswatchonly\" : true|false, (boolean) If the address is watchonly\n"
" \"isscript\" : true|false, (boolean) If the key is a script\n"
+ " \"script\" : \"type\" (string, optional) The output script type. Possible types: nonstandard, pubkey, pubkeyhash, scripthash, multisig, nulldata, witness_v0_keyhash, witness_v0_scripthash\n"
+ " \"hex\" : \"hex\", (string, optional) The redeemscript for the p2sh address\n"
+ " \"addresses\" (string, optional) Array of addresses associated with the known redeemscript\n"
+ " [\n"
+ " \"address\"\n"
+ " ,...\n"
+ " ]\n"
+ " \"sigsrequired\" : xxxxx (numeric, optional) Number of signatures required to spend multisig output\n"
" \"pubkey\" : \"publickeyhex\", (string) The hex value of the raw public key\n"
" \"iscompressed\" : true|false, (boolean) If the address is compressed\n"
" \"account\" : \"account\" (string) DEPRECATED. The account associated with the address, \"\" is the default account\n"
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index ed452fcb02..b4d6795e62 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -18,7 +18,7 @@
#include "util.h"
#include "utilstrencodings.h"
#include "version.h"
-
+#include "warnings.h"
#include <univalue.h>
@@ -310,7 +310,7 @@ UniValue getaddednodeinfo(const JSONRPCRequest& request)
std::vector<AddedNodeInfo> vInfo = g_connman->GetAddedNodeInfo();
- if (request.params.size() == 1) {
+ if (request.params.size() == 1 && !request.params[0].isNull()) {
bool found = false;
for (const AddedNodeInfo& info : vInfo) {
if (info.strAddedNode == request.params[0].get_str()) {
diff --git a/src/rpc/protocol.h b/src/rpc/protocol.h
index 70f7092cfe..4bd4702d62 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);
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index b878624df8..b967f2dbf8 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -137,7 +137,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;
@@ -211,7 +211,7 @@ UniValue gettxoutproof(const JSONRPCRequest& request)
CBlockIndex* pblockindex = NULL;
uint256 hashBlock;
- if (request.params.size() > 1)
+ if (!request.params[1].isNull())
{
hashBlock = uint256S(request.params[1].get_str());
if (!mapBlockIndex.count(hashBlock))
@@ -412,7 +412,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");
}
@@ -554,6 +554,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\" : \"value\", (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
@@ -626,26 +713,9 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
#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 +726,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.
}
@@ -781,10 +851,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 +865,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 +879,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));
@@ -905,6 +969,7 @@ static const CRPCCommand commands[] =
{ "rawtransactions", "decoderawtransaction", &decoderawtransaction, true, {"hexstring"} },
{ "rawtransactions", "decodescript", &decodescript, true, {"hexstring"} },
{ "rawtransactions", "sendrawtransaction", &sendrawtransaction, false, {"hexstring","allowhighfees"} },
+ { "rawtransactions", "combinerawtransaction", &combinerawtransaction, true, {"txs"} },
{ "rawtransactions", "signrawtransaction", &signrawtransaction, false, {"hexstring","prevtxs","privkeys","sighashtype"} }, /* uses wallet if enabled */
{ "blockchain", "gettxoutproof", &gettxoutproof, true, {"txids", "blockhash"} },