mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-18 21:35:13 +01:00
descriptors: Change Parse to return vector of descriptors
When given a descriptor which contins a multipath derivation specifier, a vector of descriptors will be returned.
This commit is contained in:
parent
0d640c6f02
commit
1bbf46e2da
@ -18,12 +18,12 @@ static void ExpandDescriptor(benchmark::Bench& bench)
|
||||
const std::pair<int64_t, int64_t> range = {0, 1000};
|
||||
FlatSigningProvider provider;
|
||||
std::string error;
|
||||
auto desc = Parse(desc_str, provider, error);
|
||||
auto descs = Parse(desc_str, provider, error);
|
||||
|
||||
bench.run([&] {
|
||||
for (int i = range.first; i <= range.second; ++i) {
|
||||
std::vector<CScript> scripts;
|
||||
bool success = desc->Expand(i, provider, scripts, provider);
|
||||
bool success = descs[0]->Expand(i, provider, scripts, provider);
|
||||
assert(success);
|
||||
}
|
||||
});
|
||||
|
@ -43,8 +43,8 @@ static void WalletIsMine(benchmark::Bench& bench, bool legacy_wallet, int num_co
|
||||
key.MakeNewKey(/*fCompressed=*/true);
|
||||
FlatSigningProvider keys;
|
||||
std::string error;
|
||||
std::unique_ptr<Descriptor> desc = Parse("combo(" + EncodeSecret(key) + ")", keys, error, /*require_checksum=*/false);
|
||||
WalletDescriptor w_desc(std::move(desc), /*creation_time=*/0, /*range_start=*/0, /*range_end=*/0, /*next_index=*/0);
|
||||
std::vector<std::unique_ptr<Descriptor>> desc = Parse("combo(" + EncodeSecret(key) + ")", keys, error, /*require_checksum=*/false);
|
||||
WalletDescriptor w_desc(std::move(desc.at(0)), /*creation_time=*/0, /*range_start=*/0, /*range_end=*/0, /*next_index=*/0);
|
||||
auto spkm = wallet->AddWalletDescriptor(w_desc, keys, /*label=*/"", /*internal=*/false);
|
||||
assert(spkm);
|
||||
}
|
||||
|
@ -218,8 +218,10 @@ std::shared_ptr<CWallet> SetupDescriptorsWallet(interfaces::Node& node, TestChai
|
||||
// Add the coinbase key
|
||||
FlatSigningProvider provider;
|
||||
std::string error;
|
||||
std::unique_ptr<Descriptor> desc = Parse("combo(" + EncodeSecret(test.coinbaseKey) + ")", provider, error, /* require_checksum=*/ false);
|
||||
assert(desc);
|
||||
auto descs = Parse("combo(" + EncodeSecret(test.coinbaseKey) + ")", provider, error, /* require_checksum=*/ false);
|
||||
assert(!descs.empty());
|
||||
assert(descs.size() == 1);
|
||||
auto& desc = descs.at(0);
|
||||
WalletDescriptor w_desc(std::move(desc), 0, 0, 1, 1);
|
||||
if (!wallet->AddWalletDescriptor(w_desc, provider, "", false)) assert(false);
|
||||
CTxDestination dest = GetDestinationForKey(test.coinbaseKey.GetPubKey(), wallet->m_default_address_type);
|
||||
|
@ -180,35 +180,36 @@ static UniValue generateBlocks(ChainstateManager& chainman, Mining& miner, const
|
||||
static bool getScriptFromDescriptor(const std::string& descriptor, CScript& script, std::string& error)
|
||||
{
|
||||
FlatSigningProvider key_provider;
|
||||
const auto desc = Parse(descriptor, key_provider, error, /* require_checksum = */ false);
|
||||
if (desc) {
|
||||
if (desc->IsRange()) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Ranged descriptor not accepted. Maybe pass through deriveaddresses first?");
|
||||
}
|
||||
|
||||
FlatSigningProvider provider;
|
||||
std::vector<CScript> scripts;
|
||||
if (!desc->Expand(0, key_provider, scripts, provider)) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Cannot derive script without private keys");
|
||||
}
|
||||
|
||||
// Combo descriptors can have 2 or 4 scripts, so we can't just check scripts.size() == 1
|
||||
CHECK_NONFATAL(scripts.size() > 0 && scripts.size() <= 4);
|
||||
|
||||
if (scripts.size() == 1) {
|
||||
script = scripts.at(0);
|
||||
} else if (scripts.size() == 4) {
|
||||
// For uncompressed keys, take the 3rd script, since it is p2wpkh
|
||||
script = scripts.at(2);
|
||||
} else {
|
||||
// Else take the 2nd script, since it is p2pkh
|
||||
script = scripts.at(1);
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
const auto descs = Parse(descriptor, key_provider, error, /* require_checksum = */ false);
|
||||
if (descs.empty()) return false;
|
||||
if (descs.size() > 1) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Multipath descriptor not accepted");
|
||||
}
|
||||
const auto& desc = descs.at(0);
|
||||
if (desc->IsRange()) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Ranged descriptor not accepted. Maybe pass through deriveaddresses first?");
|
||||
}
|
||||
|
||||
FlatSigningProvider provider;
|
||||
std::vector<CScript> scripts;
|
||||
if (!desc->Expand(0, key_provider, scripts, provider)) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Cannot derive script without private keys");
|
||||
}
|
||||
|
||||
// Combo descriptors can have 2 or 4 scripts, so we can't just check scripts.size() == 1
|
||||
CHECK_NONFATAL(scripts.size() > 0 && scripts.size() <= 4);
|
||||
|
||||
if (scripts.size() == 1) {
|
||||
script = scripts.at(0);
|
||||
} else if (scripts.size() == 4) {
|
||||
// For uncompressed keys, take the 3rd script, since it is p2wpkh
|
||||
script = scripts.at(2);
|
||||
} else {
|
||||
// Else take the 2nd script, since it is p2pkh
|
||||
script = scripts.at(1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static RPCHelpMan generatetodescriptor()
|
||||
|
@ -175,7 +175,11 @@ static RPCHelpMan getdescriptorinfo()
|
||||
RPCResult{
|
||||
RPCResult::Type::OBJ, "", "",
|
||||
{
|
||||
{RPCResult::Type::STR, "descriptor", "The descriptor in canonical form, without private keys"},
|
||||
{RPCResult::Type::STR, "descriptor", "The descriptor in canonical form, without private keys. For a multipath descriptor, only the first will be returned."},
|
||||
{RPCResult::Type::ARR, "multipath_expansion", /*optional=*/true, "All descriptors produced by expanding multipath derivation elements. Only if the provided descriptor specifies multipath derivation elements.",
|
||||
{
|
||||
{RPCResult::Type::STR, "", ""},
|
||||
}},
|
||||
{RPCResult::Type::STR, "checksum", "The checksum for the input descriptor"},
|
||||
{RPCResult::Type::BOOL, "isrange", "Whether the descriptor is ranged"},
|
||||
{RPCResult::Type::BOOL, "issolvable", "Whether the descriptor is solvable"},
|
||||
@ -191,16 +195,25 @@ static RPCHelpMan getdescriptorinfo()
|
||||
{
|
||||
FlatSigningProvider provider;
|
||||
std::string error;
|
||||
auto desc = Parse(request.params[0].get_str(), provider, error);
|
||||
if (!desc) {
|
||||
auto descs = Parse(request.params[0].get_str(), provider, error);
|
||||
if (descs.empty()) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, error);
|
||||
}
|
||||
|
||||
UniValue result(UniValue::VOBJ);
|
||||
result.pushKV("descriptor", desc->ToString());
|
||||
result.pushKV("descriptor", descs.at(0)->ToString());
|
||||
|
||||
if (descs.size() > 1) {
|
||||
UniValue multipath_descs(UniValue::VARR);
|
||||
for (const auto& d : descs) {
|
||||
multipath_descs.push_back(d->ToString());
|
||||
}
|
||||
result.pushKV("multipath_expansion", multipath_descs);
|
||||
}
|
||||
|
||||
result.pushKV("checksum", GetDescriptorChecksum(request.params[0].get_str()));
|
||||
result.pushKV("isrange", desc->IsRange());
|
||||
result.pushKV("issolvable", desc->IsSolvable());
|
||||
result.pushKV("isrange", descs.at(0)->IsRange());
|
||||
result.pushKV("issolvable", descs.at(0)->IsSolvable());
|
||||
result.pushKV("hasprivatekeys", provider.keys.size() > 0);
|
||||
return result;
|
||||
},
|
||||
@ -221,7 +234,8 @@ static RPCHelpMan deriveaddresses()
|
||||
" tr(<pubkey>,multi_a(<n>,<pubkey>,<pubkey>,...)) P2TR-multisig outputs for the given threshold and pubkeys\n"
|
||||
"\nIn the above, <pubkey> either refers to a fixed public key in hexadecimal notation, or to an xpub/xprv optionally followed by one\n"
|
||||
"or more path elements separated by \"/\", where \"h\" represents a hardened child key.\n"
|
||||
"For more information on output descriptors, see the documentation in the doc/descriptors.md file.\n"},
|
||||
"For more information on output descriptors, see the documentation in the doc/descriptors.md file.\n"
|
||||
"Note that only descriptors that specify a single derivation path can be derived.\n"},
|
||||
{
|
||||
{"descriptor", RPCArg::Type::STR, RPCArg::Optional::NO, "The descriptor."},
|
||||
{"range", RPCArg::Type::RANGE, RPCArg::Optional::OMITTED, "If a ranged descriptor is used, this specifies the end or the range (in [begin,end] notation) to derive."},
|
||||
@ -250,11 +264,14 @@ static RPCHelpMan deriveaddresses()
|
||||
|
||||
FlatSigningProvider key_provider;
|
||||
std::string error;
|
||||
auto desc = Parse(desc_str, key_provider, error, /* require_checksum = */ true);
|
||||
if (!desc) {
|
||||
auto descs = Parse(desc_str, key_provider, error, /* require_checksum = */ true);
|
||||
if (descs.empty()) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, error);
|
||||
}
|
||||
|
||||
if (descs.size() > 1) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Descriptor with multipath derivation path specifiers are not allowed");
|
||||
}
|
||||
auto& desc = descs.at(0);
|
||||
if (!desc->IsRange() && request.params.size() > 1) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Range should not be specified for an un-ranged descriptor");
|
||||
}
|
||||
|
@ -1337,24 +1337,26 @@ std::vector<CScript> EvalDescriptorStringOrObject(const UniValue& scanobject, Fl
|
||||
}
|
||||
|
||||
std::string error;
|
||||
auto desc = Parse(desc_str, provider, error);
|
||||
if (!desc) {
|
||||
auto descs = Parse(desc_str, provider, error);
|
||||
if (descs.empty()) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, error);
|
||||
}
|
||||
if (!desc->IsRange()) {
|
||||
if (!descs.at(0)->IsRange()) {
|
||||
range.first = 0;
|
||||
range.second = 0;
|
||||
}
|
||||
std::vector<CScript> ret;
|
||||
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));
|
||||
for (const auto& desc : descs) {
|
||||
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));
|
||||
}
|
||||
if (expand_priv) {
|
||||
desc->ExpandPrivate(/*pos=*/i, provider, /*out=*/provider);
|
||||
}
|
||||
std::move(scripts.begin(), scripts.end(), std::back_inserter(ret));
|
||||
}
|
||||
if (expand_priv) {
|
||||
desc->ExpandPrivate(/*pos=*/i, provider, /*out=*/provider);
|
||||
}
|
||||
std::move(scripts.begin(), scripts.end(), std::back_inserter(ret));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -2364,14 +2364,21 @@ bool CheckChecksum(Span<const char>& sp, bool require_checksum, std::string& err
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<Descriptor> Parse(const std::string& descriptor, FlatSigningProvider& out, std::string& error, bool require_checksum)
|
||||
std::vector<std::unique_ptr<Descriptor>> Parse(const std::string& descriptor, FlatSigningProvider& out, std::string& error, bool require_checksum)
|
||||
{
|
||||
Span<const char> sp{descriptor};
|
||||
if (!CheckChecksum(sp, require_checksum, error)) return nullptr;
|
||||
if (!CheckChecksum(sp, require_checksum, error)) return {};
|
||||
uint32_t key_exp_index = 0;
|
||||
auto ret = ParseScript(key_exp_index, sp, ParseScriptContext::TOP, out, error);
|
||||
if (sp.size() == 0 && !ret.empty()) return std::unique_ptr<Descriptor>(std::move(ret.at(0)));
|
||||
return nullptr;
|
||||
if (sp.size() == 0 && !ret.empty()) {
|
||||
std::vector<std::unique_ptr<Descriptor>> descs;
|
||||
descs.reserve(ret.size());
|
||||
for (auto& r : ret) {
|
||||
descs.emplace_back(std::unique_ptr<Descriptor>(std::move(r)));
|
||||
}
|
||||
return descs;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string GetDescriptorChecksum(const std::string& descriptor)
|
||||
|
@ -173,9 +173,9 @@ struct Descriptor {
|
||||
* is set, the checksum is mandatory - otherwise it is optional.
|
||||
*
|
||||
* If a parse error occurs, or the checksum is missing/invalid, or anything
|
||||
* else is wrong, `nullptr` is returned.
|
||||
* else is wrong, an empty vector is returned.
|
||||
*/
|
||||
std::unique_ptr<Descriptor> Parse(const std::string& descriptor, FlatSigningProvider& out, std::string& error, bool require_checksum = false);
|
||||
std::vector<std::unique_ptr<Descriptor>> Parse(const std::string& descriptor, FlatSigningProvider& out, std::string& error, bool require_checksum = false);
|
||||
|
||||
/** Get the checksum for a `descriptor`.
|
||||
*
|
||||
|
@ -25,8 +25,8 @@ void CheckUnparsable(const std::string& prv, const std::string& pub, const std::
|
||||
std::string error;
|
||||
auto parse_priv = Parse(prv, keys_priv, error);
|
||||
auto parse_pub = Parse(pub, keys_pub, error);
|
||||
BOOST_CHECK_MESSAGE(!parse_priv, prv);
|
||||
BOOST_CHECK_MESSAGE(!parse_pub, pub);
|
||||
BOOST_CHECK_MESSAGE(parse_priv.empty(), prv);
|
||||
BOOST_CHECK_MESSAGE(parse_pub.empty(), pub);
|
||||
BOOST_CHECK_EQUAL(error, expected_error);
|
||||
}
|
||||
|
||||
@ -139,19 +139,22 @@ void DoCheck(std::string prv, std::string pub, const std::string& norm_pub, int
|
||||
std::set<std::vector<uint32_t>> left_paths = paths;
|
||||
std::string error;
|
||||
|
||||
std::unique_ptr<Descriptor> parse_priv;
|
||||
std::unique_ptr<Descriptor> parse_pub;
|
||||
std::vector<std::unique_ptr<Descriptor>> parse_privs;
|
||||
std::vector<std::unique_ptr<Descriptor>> parse_pubs;
|
||||
// Check that parsing succeeds.
|
||||
if (replace_apostrophe_with_h_in_prv) {
|
||||
prv = UseHInsteadOfApostrophe(prv);
|
||||
}
|
||||
parse_priv = Parse(prv, keys_priv, error);
|
||||
BOOST_CHECK_MESSAGE(parse_priv, error);
|
||||
parse_privs = Parse(prv, keys_priv, error);
|
||||
BOOST_CHECK_MESSAGE(!parse_privs.empty(), error);
|
||||
if (replace_apostrophe_with_h_in_pub) {
|
||||
pub = UseHInsteadOfApostrophe(pub);
|
||||
}
|
||||
parse_pub = Parse(pub, keys_pub, error);
|
||||
BOOST_CHECK_MESSAGE(parse_pub, error);
|
||||
parse_pubs = Parse(pub, keys_pub, error);
|
||||
BOOST_CHECK_MESSAGE(!parse_pubs.empty(), error);
|
||||
|
||||
auto& parse_priv = parse_privs.at(0);
|
||||
auto& parse_pub = parse_pubs.at(0);
|
||||
|
||||
// We must be able to estimate the max satisfaction size for any solvable descriptor top descriptor (but combo).
|
||||
const bool is_nontop_or_nonsolvable{!parse_priv->IsSolvable() || !parse_priv->GetOutputType()};
|
||||
|
@ -15,14 +15,24 @@
|
||||
MockedDescriptorConverter MOCKED_DESC_CONVERTER;
|
||||
|
||||
/** Test a successfully parsed descriptor. */
|
||||
static void TestDescriptor(const Descriptor& desc, FlatSigningProvider& sig_provider, std::string& dummy)
|
||||
static void TestDescriptor(const Descriptor& desc, FlatSigningProvider& sig_provider, std::string& dummy, std::optional<bool>& is_ranged, std::optional<bool>& is_solvable)
|
||||
{
|
||||
// Trivial helpers.
|
||||
(void)desc.IsRange();
|
||||
const bool is_solvable{desc.IsSolvable()};
|
||||
(void)desc.IsSingleType();
|
||||
(void)desc.GetOutputType();
|
||||
|
||||
if (is_ranged.has_value()) {
|
||||
assert(desc.IsRange() == *is_ranged);
|
||||
} else {
|
||||
is_ranged = desc.IsRange();
|
||||
}
|
||||
if (is_solvable.has_value()) {
|
||||
assert(desc.IsSolvable() == *is_solvable);
|
||||
} else {
|
||||
is_solvable = desc.IsSolvable();
|
||||
}
|
||||
|
||||
// Serialization to string representation.
|
||||
(void)desc.ToString();
|
||||
(void)desc.ToPrivateString(sig_provider, dummy);
|
||||
@ -48,7 +58,7 @@ static void TestDescriptor(const Descriptor& desc, FlatSigningProvider& sig_prov
|
||||
const auto max_sat_nonmaxsig{desc.MaxSatisfactionWeight(true)};
|
||||
const auto max_elems{desc.MaxSatisfactionElems()};
|
||||
// We must be able to estimate the max satisfaction size for any solvable descriptor (but combo).
|
||||
const bool is_nontop_or_nonsolvable{!is_solvable || !desc.GetOutputType()};
|
||||
const bool is_nontop_or_nonsolvable{!*is_solvable || !desc.GetOutputType()};
|
||||
const bool is_input_size_info_set{max_sat_maxsig && max_sat_nonmaxsig && max_elems};
|
||||
assert(is_input_size_info_set || is_nontop_or_nonsolvable);
|
||||
}
|
||||
@ -77,7 +87,12 @@ FUZZ_TARGET(mocked_descriptor_parse, .init = initialize_mocked_descriptor_parse)
|
||||
FlatSigningProvider signing_provider;
|
||||
std::string error;
|
||||
const auto desc = Parse(*descriptor, signing_provider, error);
|
||||
if (desc) TestDescriptor(*desc, signing_provider, error);
|
||||
std::optional<bool> is_ranged;
|
||||
std::optional<bool> is_solvable;
|
||||
for (const auto& d : desc) {
|
||||
assert(d);
|
||||
TestDescriptor(*d, signing_provider, error, is_ranged, is_solvable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -91,6 +106,11 @@ FUZZ_TARGET(descriptor_parse, .init = initialize_descriptor_parse)
|
||||
std::string error;
|
||||
for (const bool require_checksum : {true, false}) {
|
||||
const auto desc = Parse(descriptor, signing_provider, error, require_checksum);
|
||||
if (desc) TestDescriptor(*desc, signing_provider, error);
|
||||
std::optional<bool> is_ranged;
|
||||
std::optional<bool> is_solvable;
|
||||
for (const auto& d : desc) {
|
||||
assert(d);
|
||||
TestDescriptor(*d, signing_provider, error, is_ranged, is_solvable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1061,10 +1061,11 @@ static UniValue ProcessImportDescriptor(ImportData& import_data, std::map<CKeyID
|
||||
const std::string& descriptor = data["desc"].get_str();
|
||||
FlatSigningProvider keys;
|
||||
std::string error;
|
||||
auto parsed_desc = Parse(descriptor, keys, error, /* require_checksum = */ true);
|
||||
if (!parsed_desc) {
|
||||
auto parsed_descs = Parse(descriptor, keys, error, /* require_checksum = */ true);
|
||||
if (parsed_descs.empty()) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, error);
|
||||
}
|
||||
const auto& parsed_desc = parsed_descs.at(0);
|
||||
if (parsed_desc->GetOutputType() == OutputType::BECH32M) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Bech32m descriptors cannot be imported into legacy wallets");
|
||||
}
|
||||
@ -1452,10 +1453,11 @@ static UniValue ProcessDescriptorImport(CWallet& wallet, const UniValue& data, c
|
||||
// Parse descriptor string
|
||||
FlatSigningProvider keys;
|
||||
std::string error;
|
||||
auto parsed_desc = Parse(descriptor, keys, error, /* require_checksum = */ true);
|
||||
if (!parsed_desc) {
|
||||
auto parsed_descs = Parse(descriptor, keys, error, /* require_checksum = */ true);
|
||||
if (parsed_descs.empty()) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, error);
|
||||
}
|
||||
auto& parsed_desc = parsed_descs.at(0);
|
||||
|
||||
// Range check
|
||||
int64_t range_start = 0, range_end = 1, next_index = 0;
|
||||
|
@ -660,11 +660,13 @@ CreatedTransactionResult FundTransaction(CWallet& wallet, const CMutableTransact
|
||||
FlatSigningProvider desc_out;
|
||||
std::string error;
|
||||
std::vector<CScript> scripts_temp;
|
||||
std::unique_ptr<Descriptor> desc = Parse(desc_str, desc_out, error, true);
|
||||
if (!desc) {
|
||||
auto descs = Parse(desc_str, desc_out, error, true);
|
||||
if (descs.empty()) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Unable to parse descriptor '%s': %s", desc_str, error));
|
||||
}
|
||||
desc->Expand(0, desc_out, scripts_temp, desc_out);
|
||||
for (auto& desc : descs) {
|
||||
desc->Expand(0, desc_out, scripts_temp, desc_out);
|
||||
}
|
||||
coinControl.m_external_provider.Merge(std::move(desc_out));
|
||||
}
|
||||
}
|
||||
|
@ -1812,8 +1812,9 @@ std::optional<MigrationData> LegacyScriptPubKeyMan::MigrateToDescriptor()
|
||||
std::string desc_str = "combo(" + origin_str + HexStr(key.GetPubKey()) + ")";
|
||||
FlatSigningProvider keys;
|
||||
std::string error;
|
||||
std::unique_ptr<Descriptor> desc = Parse(desc_str, keys, error, false);
|
||||
WalletDescriptor w_desc(std::move(desc), creation_time, 0, 0, 0);
|
||||
std::vector<std::unique_ptr<Descriptor>> descs = Parse(desc_str, keys, error, false);
|
||||
CHECK_NONFATAL(descs.size() == 1); // It shouldn't be possible to have an invalid or multipath descriptor
|
||||
WalletDescriptor w_desc(std::move(descs.at(0)), creation_time, 0, 0, 0);
|
||||
|
||||
// Make the DescriptorScriptPubKeyMan and get the scriptPubKeys
|
||||
auto desc_spk_man = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(m_storage, w_desc, m_keypool_size));
|
||||
@ -1856,9 +1857,10 @@ std::optional<MigrationData> LegacyScriptPubKeyMan::MigrateToDescriptor()
|
||||
std::string desc_str = "combo(" + xpub + "/0h/" + ToString(i) + "h/*h)";
|
||||
FlatSigningProvider keys;
|
||||
std::string error;
|
||||
std::unique_ptr<Descriptor> desc = Parse(desc_str, keys, error, false);
|
||||
std::vector<std::unique_ptr<Descriptor>> descs = Parse(desc_str, keys, error, false);
|
||||
CHECK_NONFATAL(descs.size() == 1); // It shouldn't be possible to have an invalid or multipath descriptor
|
||||
uint32_t chain_counter = std::max((i == 1 ? chain.nInternalChainCounter : chain.nExternalChainCounter), (uint32_t)0);
|
||||
WalletDescriptor w_desc(std::move(desc), 0, 0, chain_counter, 0);
|
||||
WalletDescriptor w_desc(std::move(descs.at(0)), 0, 0, chain_counter, 0);
|
||||
|
||||
// Make the DescriptorScriptPubKeyMan and get the scriptPubKeys
|
||||
auto desc_spk_man = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(m_storage, w_desc, m_keypool_size));
|
||||
|
@ -68,7 +68,7 @@ void ImportDescriptors(CWallet& wallet, const std::string& seed_insecure)
|
||||
|
||||
FlatSigningProvider keys;
|
||||
std::string error;
|
||||
auto parsed_desc = Parse(descriptor, keys, error, /*require_checksum=*/false);
|
||||
auto parsed_desc = std::move(Parse(descriptor, keys, error, /*require_checksum=*/false).at(0));
|
||||
assert(parsed_desc);
|
||||
assert(error.empty());
|
||||
assert(parsed_desc->IsRange());
|
||||
|
@ -69,10 +69,10 @@ static std::optional<std::pair<WalletDescriptor, FlatSigningProvider>> CreateWal
|
||||
|
||||
FlatSigningProvider keys;
|
||||
std::string error;
|
||||
std::unique_ptr<Descriptor> parsed_desc{Parse(desc_str.value(), keys, error, false)};
|
||||
if (!parsed_desc) return std::nullopt;
|
||||
std::vector<std::unique_ptr<Descriptor>> parsed_descs = Parse(desc_str.value(), keys, error, false);
|
||||
if (parsed_descs.empty()) return std::nullopt;
|
||||
|
||||
WalletDescriptor w_desc{std::move(parsed_desc), /*creation_time=*/0, /*range_start=*/0, /*range_end=*/1, /*next_index=*/1};
|
||||
WalletDescriptor w_desc{std::move(parsed_descs.at(0)), /*creation_time=*/0, /*range_start=*/0, /*range_end=*/1, /*next_index=*/1};
|
||||
return std::make_pair(w_desc, keys);
|
||||
}
|
||||
|
||||
|
@ -25,13 +25,14 @@ wallet::ScriptPubKeyMan* CreateDescriptor(CWallet& keystore, const std::string&
|
||||
|
||||
FlatSigningProvider keys;
|
||||
std::string error;
|
||||
std::unique_ptr<Descriptor> parsed_desc = Parse(desc_str, keys, error, false);
|
||||
BOOST_CHECK(success == (parsed_desc != nullptr));
|
||||
auto parsed_descs = Parse(desc_str, keys, error, false);
|
||||
BOOST_CHECK(success == (!parsed_descs.empty()));
|
||||
if (!success) return nullptr;
|
||||
auto& desc = parsed_descs.at(0);
|
||||
|
||||
const int64_t range_start = 0, range_end = 1, next_index = 0, timestamp = 1;
|
||||
|
||||
WalletDescriptor w_desc(std::move(parsed_desc), timestamp, range_start, range_end, next_index);
|
||||
WalletDescriptor w_desc(std::move(desc), timestamp, range_start, range_end, next_index);
|
||||
|
||||
LOCK(keystore.cs_wallet);
|
||||
|
||||
|
@ -21,8 +21,9 @@ static void import_descriptor(CWallet& wallet, const std::string& descriptor)
|
||||
AssertLockHeld(wallet.cs_wallet);
|
||||
FlatSigningProvider provider;
|
||||
std::string error;
|
||||
std::unique_ptr<Descriptor> desc = Parse(descriptor, provider, error, /* require_checksum=*/ false);
|
||||
assert(desc);
|
||||
auto descs = Parse(descriptor, provider, error, /* require_checksum=*/ false);
|
||||
assert(descs.size() == 1);
|
||||
auto& desc = descs.at(0);
|
||||
WalletDescriptor w_desc(std::move(desc), 0, 0, 10, 0);
|
||||
wallet.AddWalletDescriptor(w_desc, provider, "", false);
|
||||
}
|
||||
|
@ -31,8 +31,9 @@ std::unique_ptr<CWallet> CreateSyncedWallet(interfaces::Chain& chain, CChain& cc
|
||||
|
||||
FlatSigningProvider provider;
|
||||
std::string error;
|
||||
std::unique_ptr<Descriptor> desc = Parse("combo(" + EncodeSecret(key) + ")", provider, error, /* require_checksum=*/ false);
|
||||
assert(desc);
|
||||
auto descs = Parse("combo(" + EncodeSecret(key) + ")", provider, error, /* require_checksum=*/ false);
|
||||
assert(descs.size() == 1);
|
||||
auto& desc = descs.at(0);
|
||||
WalletDescriptor w_desc(std::move(desc), 0, 0, 1, 1);
|
||||
if (!wallet->AddWalletDescriptor(w_desc, provider, "", false)) assert(false);
|
||||
}
|
||||
|
@ -65,8 +65,9 @@ static void AddKey(CWallet& wallet, const CKey& key)
|
||||
LOCK(wallet.cs_wallet);
|
||||
FlatSigningProvider provider;
|
||||
std::string error;
|
||||
std::unique_ptr<Descriptor> desc = Parse("combo(" + EncodeSecret(key) + ")", provider, error, /* require_checksum=*/ false);
|
||||
assert(desc);
|
||||
auto descs = Parse("combo(" + EncodeSecret(key) + ")", provider, error, /* require_checksum=*/ false);
|
||||
assert(descs.size() == 1);
|
||||
auto& desc = descs.at(0);
|
||||
WalletDescriptor w_desc(std::move(desc), 0, 0, 1, 1);
|
||||
if (!wallet.AddWalletDescriptor(w_desc, provider, "", false)) assert(false);
|
||||
}
|
||||
|
@ -3743,10 +3743,11 @@ void CWallet::SetupDescriptorScriptPubKeyMans()
|
||||
const std::string& desc_str = desc_val.getValStr();
|
||||
FlatSigningProvider keys;
|
||||
std::string desc_error;
|
||||
std::unique_ptr<Descriptor> desc = Parse(desc_str, keys, desc_error, false);
|
||||
if (desc == nullptr) {
|
||||
auto descs = Parse(desc_str, keys, desc_error, false);
|
||||
if (descs.empty()) {
|
||||
throw std::runtime_error(std::string(__func__) + ": Invalid descriptor \"" + desc_str + "\" (" + desc_error + ")");
|
||||
}
|
||||
auto& desc = descs.at(0);
|
||||
if (!desc->GetOutputType()) {
|
||||
continue;
|
||||
}
|
||||
@ -4285,12 +4286,12 @@ bool DoMigration(CWallet& wallet, WalletContext& context, bilingual_str& error,
|
||||
// Parse the descriptor
|
||||
FlatSigningProvider keys;
|
||||
std::string parse_err;
|
||||
std::unique_ptr<Descriptor> desc = Parse(desc_str, keys, parse_err, /* require_checksum */ true);
|
||||
assert(desc); // It shouldn't be possible to have the LegacyScriptPubKeyMan make an invalid descriptor
|
||||
assert(!desc->IsRange()); // It shouldn't be possible to have LegacyScriptPubKeyMan make a ranged watchonly descriptor
|
||||
std::vector<std::unique_ptr<Descriptor>> descs = Parse(desc_str, keys, parse_err, /* require_checksum */ true);
|
||||
assert(descs.size() == 1); // It shouldn't be possible to have the LegacyScriptPubKeyMan make an invalid descriptor or a multipath descriptors
|
||||
assert(!descs.at(0)->IsRange()); // It shouldn't be possible to have LegacyScriptPubKeyMan make a ranged watchonly descriptor
|
||||
|
||||
// Add to the wallet
|
||||
WalletDescriptor w_desc(std::move(desc), creation_time, 0, 0, 0);
|
||||
WalletDescriptor w_desc(std::move(descs.at(0)), creation_time, 0, 0, 0);
|
||||
data->watchonly_wallet->AddWalletDescriptor(w_desc, keys, "", false);
|
||||
}
|
||||
|
||||
@ -4322,12 +4323,12 @@ bool DoMigration(CWallet& wallet, WalletContext& context, bilingual_str& error,
|
||||
// Parse the descriptor
|
||||
FlatSigningProvider keys;
|
||||
std::string parse_err;
|
||||
std::unique_ptr<Descriptor> desc = Parse(desc_str, keys, parse_err, /* require_checksum */ true);
|
||||
assert(desc); // It shouldn't be possible to have the LegacyScriptPubKeyMan make an invalid descriptor
|
||||
assert(!desc->IsRange()); // It shouldn't be possible to have LegacyScriptPubKeyMan make a ranged watchonly descriptor
|
||||
std::vector<std::unique_ptr<Descriptor>> descs = Parse(desc_str, keys, parse_err, /* require_checksum */ true);
|
||||
assert(descs.size() == 1); // It shouldn't be possible to have the LegacyScriptPubKeyMan make an invalid descriptor or a multipath descriptors
|
||||
assert(!descs.at(0)->IsRange()); // It shouldn't be possible to have LegacyScriptPubKeyMan make a ranged watchonly descriptor
|
||||
|
||||
// Add to the wallet
|
||||
WalletDescriptor w_desc(std::move(desc), creation_time, 0, 0, 0);
|
||||
WalletDescriptor w_desc(std::move(descs.at(0)), creation_time, 0, 0, 0);
|
||||
data->solvable_wallet->AddWalletDescriptor(w_desc, keys, "", false);
|
||||
}
|
||||
|
||||
|
@ -94,8 +94,8 @@ WalletDescriptor GenerateWalletDescriptor(const CExtPubKey& master_key, const Ou
|
||||
// Make the descriptor
|
||||
FlatSigningProvider keys;
|
||||
std::string error;
|
||||
std::unique_ptr<Descriptor> desc = Parse(desc_str, keys, error, false);
|
||||
WalletDescriptor w_desc(std::move(desc), creation_time, 0, 0, 0);
|
||||
std::vector<std::unique_ptr<Descriptor>> desc = Parse(desc_str, keys, error, false);
|
||||
WalletDescriptor w_desc(std::move(desc.at(0)), creation_time, 0, 0, 0);
|
||||
return w_desc;
|
||||
}
|
||||
|
||||
|
@ -96,10 +96,14 @@ public:
|
||||
{
|
||||
std::string error;
|
||||
FlatSigningProvider keys;
|
||||
descriptor = Parse(str, keys, error, true);
|
||||
if (!descriptor) {
|
||||
auto descs = Parse(str, keys, error, true);
|
||||
if (descs.empty()) {
|
||||
throw std::ios_base::failure("Invalid descriptor: " + error);
|
||||
}
|
||||
if (descs.size() > 1) {
|
||||
throw std::ios_base::failure("Can't load a multipath descriptor from databases");
|
||||
}
|
||||
descriptor = std::move(descs.at(0));
|
||||
id = DescriptorID(*descriptor);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user