aboutsummaryrefslogtreecommitdiff
path: root/src/rpc
diff options
context:
space:
mode:
Diffstat (limited to 'src/rpc')
-rw-r--r--src/rpc/blockchain.cpp15
-rw-r--r--src/rpc/misc.cpp32
-rw-r--r--src/rpc/util.cpp22
-rw-r--r--src/rpc/util.h4
4 files changed, 51 insertions, 22 deletions
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index c73a8d48cf..7e8e5e07d0 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -2159,7 +2159,7 @@ UniValue scantxoutset(const JSONRPCRequest& request)
{"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "An object with output descriptor and metadata",
{
{"desc", RPCArg::Type::STR, RPCArg::Optional::NO, "An output descriptor"},
- {"range", RPCArg::Type::NUM, /* default */ "1000", "Up to what child index HD chains should be explored"},
+ {"range", RPCArg::Type::RANGE, /* default */ "1000", "The range of HD chain indexes to explore (either end or [begin,end])"},
},
},
},
@@ -2216,7 +2216,7 @@ UniValue scantxoutset(const JSONRPCRequest& request)
// loop through the scan objects
for (const UniValue& scanobject : request.params[1].get_array().getValues()) {
std::string desc_str;
- int range = 1000;
+ std::pair<int64_t, int64_t> range = {0, 1000};
if (scanobject.isStr()) {
desc_str = scanobject.get_str();
} else if (scanobject.isObject()) {
@@ -2225,8 +2225,8 @@ UniValue scantxoutset(const JSONRPCRequest& request)
desc_str = desc_uni.get_str();
UniValue range_uni = find_value(scanobject, "range");
if (!range_uni.isNull()) {
- range = range_uni.get_int();
- if (range < 0 || range > 1000000) throw JSONRPCError(RPC_INVALID_PARAMETER, "range out of range");
+ range = ParseRange(range_uni);
+ if (range.first < 0 || (range.second >> 31) != 0 || range.second >= range.first + 1000000) throw JSONRPCError(RPC_INVALID_PARAMETER, "range out of range");
}
} else {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Scan object needs to be either a string or an object");
@@ -2237,8 +2237,11 @@ UniValue scantxoutset(const JSONRPCRequest& request)
if (!desc) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Invalid descriptor '%s'", desc_str));
}
- if (!desc->IsRange()) range = 0;
- for (int i = 0; i <= range; ++i) {
+ if (!desc->IsRange()) {
+ range.first = 0;
+ range.second = 0;
+ }
+ for (int i = range.first; i <= range.second; ++i) {
std::vector<CScript> scripts;
if (!desc->Expand(i, provider, scripts, provider)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Cannot derive script without private keys: '%s'", desc_str));
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index 999a307e2b..765fd772fe 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -185,7 +185,7 @@ UniValue getdescriptorinfo(const JSONRPCRequest& request)
UniValue deriveaddresses(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.empty() || request.params.size() > 3) {
+ if (request.fHelp || request.params.empty() || request.params.size() > 2) {
throw std::runtime_error(
RPCHelpMan{"deriveaddresses",
{"\nDerives one or more addresses corresponding to an output descriptor.\n"
@@ -199,37 +199,37 @@ UniValue deriveaddresses(const JSONRPCRequest& request)
"For more information on output descriptors, see the documentation in the doc/descriptors.md file.\n"},
{
{"descriptor", RPCArg::Type::STR, RPCArg::Optional::NO, "The descriptor."},
- {"begin", RPCArg::Type::NUM, RPCArg::Optional::OMITTED_NAMED_ARG, "If a ranged descriptor is used, this specifies the beginning of the range to import."},
- {"end", RPCArg::Type::NUM, RPCArg::Optional::OMITTED_NAMED_ARG, "If a ranged descriptor is used, this specifies the end of the range to import."}
+ {"range", RPCArg::Type::RANGE, RPCArg::Optional::OMITTED_NAMED_ARG, "If a ranged descriptor is used, this specifies the end or the range (in [begin,end] notation) to derive."},
},
RPCResult{
"[ address ] (array) the derived addresses\n"
},
RPCExamples{
"First three native segwit receive addresses\n" +
- HelpExampleCli("deriveaddresses", "\"wpkh([d34db33f/84h/0h/0h]xpub6DJ2dNUysrn5Vt36jH2KLBT2i1auw1tTSSomg8PhqNiUtx8QX2SvC9nrHu81fT41fvDUnhMjEzQgXnQjKEu3oaqMSzhSrHMxyyoEAmUHQbY/0/*)#trd0mf0l\" 0 2")
+ HelpExampleCli("deriveaddresses", "\"wpkh([d34db33f/84h/0h/0h]xpub6DJ2dNUysrn5Vt36jH2KLBT2i1auw1tTSSomg8PhqNiUtx8QX2SvC9nrHu81fT41fvDUnhMjEzQgXnQjKEu3oaqMSzhSrHMxyyoEAmUHQbY/0/*)#trd0mf0l\" \"[0,2]\"")
}}.ToString()
);
}
- RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VNUM, UniValue::VNUM});
+ RPCTypeCheck(request.params, {UniValue::VSTR, UniValueType()}); // Range argument is checked later
const std::string desc_str = request.params[0].get_str();
- int range_begin = 0;
- int range_end = 0;
+ int64_t range_begin = 0;
+ int64_t range_end = 0;
- if (request.params.size() >= 2) {
- if (request.params.size() == 2) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Missing range end parameter");
- }
- range_begin = request.params[1].get_int();
- range_end = request.params[2].get_int();
- if (range_begin < 0) {
+ if (request.params.size() >= 2 && !request.params[1].isNull()) {
+ auto range = ParseRange(request.params[1]);
+ if (range.first < 0) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Range should be greater or equal than 0");
}
- if (range_begin > range_end) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Range end should be equal to or greater than begin");
+ if ((range.second >> 31) != 0) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "End of range is too high");
+ }
+ if (range.second >= range.first + 1000000) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Range is too large");
}
+ range_begin = range.first;
+ range_end = range.second;
}
FlatSigningProvider provider;
diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp
index 86695bc1a5..40ac133186 100644
--- a/src/rpc/util.cpp
+++ b/src/rpc/util.cpp
@@ -200,6 +200,7 @@ struct Sections {
case RPCArg::Type::STR:
case RPCArg::Type::NUM:
case RPCArg::Type::AMOUNT:
+ case RPCArg::Type::RANGE:
case RPCArg::Type::BOOL: {
if (outer_type == OuterType::NAMED_ARG) return; // Nothing more to do for non-recursive types on first recursion
auto left = indent;
@@ -405,6 +406,10 @@ std::string RPCArg::ToDescriptionString() const
ret += "numeric or string";
break;
}
+ case Type::RANGE: {
+ ret += "numeric or array";
+ break;
+ }
case Type::BOOL: {
ret += "boolean";
break;
@@ -464,6 +469,8 @@ std::string RPCArg::ToStringObj(const bool oneline) const
return res + "\"hex\"";
case Type::NUM:
return res + "n";
+ case Type::RANGE:
+ return res + "n or [n,n]";
case Type::AMOUNT:
return res + "amount";
case Type::BOOL:
@@ -494,6 +501,7 @@ std::string RPCArg::ToString(const bool oneline) const
return "\"" + m_name + "\"";
}
case Type::NUM:
+ case Type::RANGE:
case Type::AMOUNT:
case Type::BOOL: {
return m_name;
@@ -523,3 +531,17 @@ std::string RPCArg::ToString(const bool oneline) const
}
assert(false);
}
+
+std::pair<int64_t, int64_t> ParseRange(const UniValue& value)
+{
+ if (value.isNum()) {
+ return {0, value.get_int64()};
+ }
+ if (value.isArray() && value.size() == 2 && value[0].isNum() && value[1].isNum()) {
+ int64_t low = value[0].get_int64();
+ int64_t high = value[1].get_int64();
+ if (low > high) throw JSONRPCError(RPC_INVALID_PARAMETER, "Range specified as [begin,end] must not have begin after end");
+ return {low, high};
+ }
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Range must be specified as end or as [begin,end]");
+}
diff --git a/src/rpc/util.h b/src/rpc/util.h
index 06800ad63c..f1bd2c89df 100644
--- a/src/rpc/util.h
+++ b/src/rpc/util.h
@@ -38,6 +38,9 @@ unsigned int ParseConfirmTarget(const UniValue& value);
RPCErrorCode RPCErrorFromTransactionError(TransactionError terr);
UniValue JSONRPCTransactionError(TransactionError terr, const std::string& err_string = "");
+//! Parse a JSON range specified as int64, or [int64, int64]
+std::pair<int64_t, int64_t> ParseRange(const UniValue& value);
+
struct RPCArg {
enum class Type {
OBJ,
@@ -48,6 +51,7 @@ struct RPCArg {
OBJ_USER_KEYS, //!< Special type where the user must set the keys e.g. to define multiple addresses; as opposed to e.g. an options object where the keys are predefined
AMOUNT, //!< Special type representing a floating point amount (can be either NUM or STR)
STR_HEX, //!< Special type that is a STR with only hex chars
+ RANGE, //!< Special type that is a NUM or [NUM,NUM]
};
enum class Optional {