mirror of
https://github.com/dashpay/dash.git
synced 2024-12-24 11:32:46 +01:00
Merge pull request #4601 from dzutte-cpp/merge_15497_15744
Backport bitcoin#15497 and bitcoin#15744
This commit is contained in:
commit
a490615a8b
@ -2492,7 +2492,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])"},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -2549,7 +2549,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()) {
|
||||
@ -2558,8 +2558,7 @@ 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 = ParseDescriptorRange(range_uni);
|
||||
}
|
||||
} else {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Scan object needs to be either a string or an object");
|
||||
@ -2570,8 +2569,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));
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include <spork.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <tuple>
|
||||
#ifdef HAVE_MALLOC_INFO
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
@ -341,7 +342,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"
|
||||
@ -354,8 +355,7 @@ 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, /* default */ "", "If a ranged descriptor is used, this specifies the beginning of the range to import"},
|
||||
{"end", RPCArg::Type::NUM, /* default */ "", "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) A json array of the derived addresses\n"
|
||||
@ -365,29 +365,19 @@ UniValue deriveaddresses(const JSONRPCRequest& request)
|
||||
},
|
||||
RPCExamples{
|
||||
"\nFirst three receive addresses\n"
|
||||
+ HelpExampleCli("deriveaddresses", "\"pkh([d34db33f/84h/0h/0h]xpub6DJ2dNUysrn5Vt36jH2KLBT2i1auw1tTSSomg8PhqNiUtx8QX2SvC9nrHu81fT41fvDUnhMjEzQgXnQjKEu3oaqMSzhSrHMxyyoEAmUHQbY/0/*)#trd0mf0l\" 0 2")
|
||||
+ HelpExampleCli("deriveaddresses", "\"pkh([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) {
|
||||
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 (request.params.size() >= 2 && !request.params[1].isNull()) {
|
||||
std::tie(range_begin, range_end) = ParseDescriptorRange(request.params[1]);
|
||||
}
|
||||
|
||||
FlatSigningProvider key_provider;
|
||||
|
@ -11,6 +11,8 @@
|
||||
#include <util/system.h>
|
||||
#include <util/strencodings.h>
|
||||
|
||||
#include <tuple>
|
||||
|
||||
InitInterfaces* g_rpc_interfaces = nullptr;
|
||||
|
||||
void RPCTypeCheck(const UniValue& params,
|
||||
@ -293,6 +295,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;
|
||||
@ -483,6 +486,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;
|
||||
@ -542,6 +549,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:
|
||||
@ -572,6 +581,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;
|
||||
@ -602,6 +612,36 @@ std::string RPCArg::ToString(const bool oneline) const
|
||||
assert(false);
|
||||
}
|
||||
|
||||
static 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]");
|
||||
}
|
||||
|
||||
std::pair<int64_t, int64_t> ParseDescriptorRange(const UniValue& value)
|
||||
{
|
||||
int64_t low, high;
|
||||
std::tie(low, high) = ParseRange(value);
|
||||
if (low < 0) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Range should be greater or equal than 0");
|
||||
}
|
||||
if ((high >> 31) != 0) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "End of range is too high");
|
||||
}
|
||||
if (high >= low + 1000000) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Range is too large");
|
||||
}
|
||||
return {low, high};
|
||||
}
|
||||
|
||||
RPCErrorCode RPCErrorFromTransactionError(TransactionError terr)
|
||||
{
|
||||
switch (terr) {
|
||||
|
@ -87,6 +87,9 @@ unsigned int ParseConfirmTarget(const UniValue& value, unsigned int max_target);
|
||||
/** Returns, given services flags, a list of humanly readable (known) network services */
|
||||
UniValue GetServicesNames(ServiceFlags services);
|
||||
|
||||
//! Parse a JSON range specified as int64, or [int64, int64]
|
||||
std::pair<int64_t, int64_t> ParseDescriptorRange(const UniValue& value);
|
||||
|
||||
struct RPCArg {
|
||||
enum class Type {
|
||||
OBJ,
|
||||
@ -97,6 +100,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 {
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <wallet/rpcwallet.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <tuple>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
@ -1297,15 +1298,7 @@ static UniValue ProcessImportDescriptor(ImportData& import_data, std::map<CKeyID
|
||||
if (!data.exists("range")) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Descriptor is ranged, please specify the range");
|
||||
}
|
||||
const UniValue& range = data["range"];
|
||||
range_start = range.exists("start") ? range["start"].get_int64() : 0;
|
||||
if (!range.exists("end")) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "End of range for descriptor must be specified");
|
||||
}
|
||||
range_end = range["end"].get_int64();
|
||||
if (range_end < range_start || range_start < 0) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid descriptor range specified");
|
||||
}
|
||||
std::tie(range_start, range_end) = ParseDescriptorRange(data["range"]);
|
||||
}
|
||||
|
||||
const UniValue& priv_keys = data.exists("keys") ? data["keys"].get_array() : UniValue();
|
||||
@ -1513,12 +1506,7 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
|
||||
{"key", RPCArg::Type::STR, RPCArg::Optional::OMITTED, ""},
|
||||
}
|
||||
},
|
||||
{"range", RPCArg::Type::OBJ, /* default */ "", "If a ranged descriptor is used, this specifies the start and end of the range to import",
|
||||
{
|
||||
{"start", RPCArg::Type::NUM, /* default */ "0", "Start of the range to import"},
|
||||
{"end", RPCArg::Type::NUM, RPCArg::Optional::NO, "End of the range to import (inclusive)"},
|
||||
}
|
||||
},
|
||||
{"range", RPCArg::Type::RANGE, RPCArg::Optional::OMITTED, "If a ranged descriptor is used, this specifies the end or the range (in the form [begin,end]) to import"},
|
||||
{"internal", RPCArg::Type::BOOL, /* default */ "false", "Stating whether matching outputs should be treated as not incoming payments (also known as change)"},
|
||||
{"watchonly", RPCArg::Type::BOOL, /* default */ "false", "Stating whether matching outputs should be considered watched even when not all private keys are provided."},
|
||||
{"label", RPCArg::Type::STR, /* default */ "''", "Label to assign to the address, only allowed with internal=false"},
|
||||
|
@ -27,17 +27,20 @@ class DeriveaddressesTest(BitcoinTestFramework):
|
||||
assert_equal(self.nodes[0].deriveaddresses(descriptor_pubkey), [address])
|
||||
|
||||
ranged_descriptor = "pkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)#77vpsvm5"
|
||||
assert_equal(self.nodes[0].deriveaddresses(ranged_descriptor, 0, 2), [address, "ydccVGNV2EcEouAxbbgdu8pi8gkdaqkiav", "yMENst4XYP3ZSNvsCEm587GbSSXZUfhpWG"])
|
||||
assert_equal(self.nodes[0].deriveaddresses(ranged_descriptor, [1, 2]), ["ydccVGNV2EcEouAxbbgdu8pi8gkdaqkiav", "yMENst4XYP3ZSNvsCEm587GbSSXZUfhpWG"])
|
||||
assert_equal(self.nodes[0].deriveaddresses(ranged_descriptor, 2), [address, "ydccVGNV2EcEouAxbbgdu8pi8gkdaqkiav", "yMENst4XYP3ZSNvsCEm587GbSSXZUfhpWG"])
|
||||
|
||||
assert_raises_rpc_error(-8, "Range should not be specified for an un-ranged descriptor", self.nodes[0].deriveaddresses, descsum_create("pkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/0)"), 0, 2)
|
||||
assert_raises_rpc_error(-8, "Range should not be specified for an un-ranged descriptor", self.nodes[0].deriveaddresses, descsum_create("pkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/0)"), [0, 2])
|
||||
|
||||
assert_raises_rpc_error(-8, "Range must be specified for a ranged descriptor", self.nodes[0].deriveaddresses, descsum_create("pkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)"))
|
||||
|
||||
assert_raises_rpc_error(-8, "Missing range end parameter", self.nodes[0].deriveaddresses, descsum_create("pkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)"), 0)
|
||||
assert_raises_rpc_error(-8, "End of range is too high", self.nodes[0].deriveaddresses, descsum_create("pkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)"), 10000000000)
|
||||
|
||||
assert_raises_rpc_error(-8, "Range end should be equal to or greater than begin", self.nodes[0].deriveaddresses, descsum_create("pkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)"), 2, 0)
|
||||
assert_raises_rpc_error(-8, "Range is too large", self.nodes[0].deriveaddresses, descsum_create("pkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)"), [1000000000, 2000000000])
|
||||
|
||||
assert_raises_rpc_error(-8, "Range should be greater or equal than 0", self.nodes[0].deriveaddresses, descsum_create("pkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)"), -1, 0)
|
||||
assert_raises_rpc_error(-8, "Range specified as [begin,end] must not have begin after end", self.nodes[0].deriveaddresses, descsum_create("pkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)"), [2, 0])
|
||||
|
||||
assert_raises_rpc_error(-8, "Range should be greater or equal than 0", self.nodes[0].deriveaddresses, descsum_create("pkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)"), [-1, 0])
|
||||
|
||||
combo_descriptor = descsum_create("combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/0)")
|
||||
assert_equal(self.nodes[0].deriveaddresses(combo_descriptor), ["yZTyMdEJjZWJi6CwY6g3WurLESH3UsWrrM", "yZTyMdEJjZWJi6CwY6g3WurLESH3UsWrrM", "93EpXofs6W7eNiuj4gu2LJh8L8opowW1jz"])
|
||||
|
@ -4,7 +4,7 @@
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
"""Test the scantxoutset rpc call."""
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.util import assert_equal, Decimal
|
||||
from test_framework.util import assert_equal, assert_raises_rpc_error, Decimal
|
||||
|
||||
import shutil
|
||||
import os
|
||||
@ -65,6 +65,13 @@ class ScantxoutsetTest(BitcoinTestFramework):
|
||||
assert_equal(self.nodes[0].scantxoutset("start", [ "addr(" + addr1 + ")", "addr(" + addr2 + ")", "addr(" + addr3 + ")"])['total_amount'], Decimal("0.007"))
|
||||
assert_equal(self.nodes[0].scantxoutset("start", [ "addr(" + addr1 + ")", "addr(" + addr2 + ")", "pkh(" + pubk3 + ")"])['total_amount'], Decimal("0.007"))
|
||||
|
||||
self.log.info("Test range validation.")
|
||||
assert_raises_rpc_error(-8, "End of range is too high", self.nodes[0].scantxoutset, "start", [ {"desc": "desc", "range": -1}])
|
||||
assert_raises_rpc_error(-8, "Range should be greater or equal than 0", self.nodes[0].scantxoutset, "start", [ {"desc": "desc", "range": [-1, 10]}])
|
||||
assert_raises_rpc_error(-8, "End of range is too high", self.nodes[0].scantxoutset, "start", [ {"desc": "desc", "range": [(2 << 31 + 1) - 1000000, (2 << 31 + 1)]}])
|
||||
assert_raises_rpc_error(-8, "Range specified as [begin,end] must not have begin after end", self.nodes[0].scantxoutset, "start", [ {"desc": "desc", "range": [2, 1]}])
|
||||
assert_raises_rpc_error(-8, "Range is too large", self.nodes[0].scantxoutset, "start", [ {"desc": "desc", "range": [0, 1000001]}])
|
||||
|
||||
self.log.info("Test extended key derivation.")
|
||||
# Run various scans, and verify that the sum of the amounts of the matches corresponds to the expected subset.
|
||||
# Note that all amounts in the UTXO set are powers of 2 multiplied by 0.001 BTC, so each amounts uniquely identifies a subset.
|
||||
@ -93,6 +100,7 @@ class ScantxoutsetTest(BitcoinTestFramework):
|
||||
assert_equal(self.nodes[0].scantxoutset("start", [ {"desc": "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)", "range": 1500}])['total_amount'], Decimal("28.672"))
|
||||
assert_equal(self.nodes[0].scantxoutset("start", [ {"desc": "combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/*)", "range": 1499}])['total_amount'], Decimal("12.288"))
|
||||
assert_equal(self.nodes[0].scantxoutset("start", [ {"desc": "combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/*)", "range": 1500}])['total_amount'], Decimal("28.672"))
|
||||
assert_equal(self.nodes[0].scantxoutset("start", [ {"desc": "combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/*)", "range": [1500,1500]}])['total_amount'], Decimal("16.384"))
|
||||
|
||||
# Test the reported descriptors for a few matches
|
||||
assert_equal(descriptors(self.nodes[0].scantxoutset("start", [ {"desc": "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0h/0'/*)", "range": 1499}])), ["pkh([0c5f9a1e/0'/0'/0]026dbd8b2315f296d36e6b6920b1579ca75569464875c7ebe869b536a7d9503c8c)#dzxw429x", "pkh([0c5f9a1e/0'/0'/1]033e6f25d76c00bedb3a8993c7d5739ee806397f0529b1b31dda31ef890f19a60c)#43rvceed"])
|
||||
|
@ -498,10 +498,25 @@ class ImportMultiTest(BitcoinTestFramework):
|
||||
self.log.info("Should import the ranged descriptor with specified range as solvable")
|
||||
self.test_importmulti({"desc": descsum_create(desc),
|
||||
"timestamp": "now",
|
||||
"range": {"end": 1}},
|
||||
"range": 1},
|
||||
success=True,
|
||||
warnings=["Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."])
|
||||
|
||||
self.test_importmulti({"desc": descsum_create(desc), "timestamp": "now", "range": -1},
|
||||
success=False, error_code=-8, error_message='End of range is too high')
|
||||
|
||||
self.test_importmulti({"desc": descsum_create(desc), "timestamp": "now", "range": [-1, 10]},
|
||||
success=False, error_code=-8, error_message='Range should be greater or equal than 0')
|
||||
|
||||
self.test_importmulti({"desc": descsum_create(desc), "timestamp": "now", "range": [(2 << 31 + 1) - 1000000, (2 << 31 + 1)]},
|
||||
success=False, error_code=-8, error_message='End of range is too high')
|
||||
|
||||
self.test_importmulti({"desc": descsum_create(desc), "timestamp": "now", "range": [2, 1]},
|
||||
success=False, error_code=-8, error_message='Range specified as [begin,end] must not have begin after end')
|
||||
|
||||
self.test_importmulti({"desc": descsum_create(desc), "timestamp": "now", "range": [0, 1000001]},
|
||||
success=False, error_code=-8, error_message='Range is too large')
|
||||
|
||||
# Test importing of a P2PKH address via descriptor
|
||||
key = self.get_key()
|
||||
self.log.info("Should import a p2pkh address from descriptor")
|
||||
|
Loading…
Reference in New Issue
Block a user