mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-03-05 14:06:27 -05:00
wallet, rpc: Allow importdescriptors to import multipath descriptors
Multipath descriptors will be imported as multiple separate descriptors. When there are 2 multipath items, the first descriptor will be for receiving addresses and the second for change. This mirrors importmulti.
This commit is contained in:
parent
32dcbca3fb
commit
f97d5c137d
1 changed files with 76 additions and 56 deletions
|
@ -1463,7 +1463,6 @@ static UniValue ProcessDescriptorImport(CWallet& wallet, const UniValue& data, c
|
|||
|
||||
const std::string& descriptor = data["desc"].get_str();
|
||||
const bool active = data.exists("active") ? data["active"].get_bool() : false;
|
||||
const bool internal = data.exists("internal") ? data["internal"].get_bool() : false;
|
||||
const std::string label{LabelFromValue(data["label"])};
|
||||
|
||||
// Parse descriptor string
|
||||
|
@ -1473,13 +1472,19 @@ static UniValue ProcessDescriptorImport(CWallet& wallet, const UniValue& data, c
|
|||
if (parsed_descs.empty()) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, error);
|
||||
}
|
||||
auto& parsed_desc = parsed_descs.at(0);
|
||||
std::optional<bool> internal;
|
||||
if (data.exists("internal")) {
|
||||
if (parsed_descs.size() > 1) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Cannot have multipath descriptor while also specifying \'internal\'");
|
||||
}
|
||||
internal = data["internal"].get_bool();
|
||||
}
|
||||
|
||||
// Range check
|
||||
int64_t range_start = 0, range_end = 1, next_index = 0;
|
||||
if (!parsed_desc->IsRange() && data.exists("range")) {
|
||||
if (!parsed_descs.at(0)->IsRange() && data.exists("range")) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Range should not be specified for an un-ranged descriptor");
|
||||
} else if (parsed_desc->IsRange()) {
|
||||
} else if (parsed_descs.at(0)->IsRange()) {
|
||||
if (data.exists("range")) {
|
||||
auto range = ParseDescriptorRange(data["range"]);
|
||||
range_start = range.first;
|
||||
|
@ -1501,10 +1506,15 @@ static UniValue ProcessDescriptorImport(CWallet& wallet, const UniValue& data, c
|
|||
}
|
||||
|
||||
// Active descriptors must be ranged
|
||||
if (active && !parsed_desc->IsRange()) {
|
||||
if (active && !parsed_descs.at(0)->IsRange()) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Active descriptors must be ranged");
|
||||
}
|
||||
|
||||
// Multipath descriptors should not have a label
|
||||
if (parsed_descs.size() > 1 && data.exists("label")) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Multipath descriptors should not have a label");
|
||||
}
|
||||
|
||||
// Ranged descriptors should not have a label
|
||||
if (data.exists("range") && data.exists("label")) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Ranged descriptors should not have a label");
|
||||
|
@ -1516,7 +1526,7 @@ static UniValue ProcessDescriptorImport(CWallet& wallet, const UniValue& data, c
|
|||
}
|
||||
|
||||
// Combo descriptor check
|
||||
if (active && !parsed_desc->IsSingleType()) {
|
||||
if (active && !parsed_descs.at(0)->IsSingleType()) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Combo descriptors cannot be set to active");
|
||||
}
|
||||
|
||||
|
@ -1525,6 +1535,14 @@ static UniValue ProcessDescriptorImport(CWallet& wallet, const UniValue& data, c
|
|||
throw JSONRPCError(RPC_WALLET_ERROR, "Cannot import private keys to a wallet with private keys disabled");
|
||||
}
|
||||
|
||||
for (size_t j = 0; j < parsed_descs.size(); ++j) {
|
||||
auto parsed_desc = std::move(parsed_descs[j]);
|
||||
bool desc_internal = internal.has_value() && internal.value();
|
||||
if (parsed_descs.size() == 2) {
|
||||
desc_internal = j == 1;
|
||||
} else if (parsed_descs.size() > 2) {
|
||||
CHECK_NONFATAL(!desc_internal);
|
||||
}
|
||||
// Need to ExpandPrivate to check if private keys are available for all pubkeys
|
||||
FlatSigningProvider expand_keys;
|
||||
std::vector<CScript> scripts;
|
||||
|
@ -1565,7 +1583,7 @@ static UniValue ProcessDescriptorImport(CWallet& wallet, const UniValue& data, c
|
|||
}
|
||||
|
||||
// Add descriptor to the wallet
|
||||
auto spk_manager = wallet.AddWalletDescriptor(w_desc, keys, label, internal);
|
||||
auto spk_manager = wallet.AddWalletDescriptor(w_desc, keys, label, desc_internal);
|
||||
if (spk_manager == nullptr) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Could not add descriptor '%s'", descriptor));
|
||||
}
|
||||
|
@ -1575,11 +1593,12 @@ static UniValue ProcessDescriptorImport(CWallet& wallet, const UniValue& data, c
|
|||
if (!w_desc.descriptor->GetOutputType()) {
|
||||
warnings.push_back("Unknown output type, cannot set descriptor to active.");
|
||||
} else {
|
||||
wallet.AddActiveScriptPubKeyMan(spk_manager->GetID(), *w_desc.descriptor->GetOutputType(), internal);
|
||||
wallet.AddActiveScriptPubKeyMan(spk_manager->GetID(), *w_desc.descriptor->GetOutputType(), desc_internal);
|
||||
}
|
||||
} else {
|
||||
if (w_desc.descriptor->GetOutputType()) {
|
||||
wallet.DeactivateScriptPubKeyMan(spk_manager->GetID(), *w_desc.descriptor->GetOutputType(), internal);
|
||||
wallet.DeactivateScriptPubKeyMan(spk_manager->GetID(), *w_desc.descriptor->GetOutputType(), desc_internal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1596,6 +1615,7 @@ RPCHelpMan importdescriptors()
|
|||
{
|
||||
return RPCHelpMan{"importdescriptors",
|
||||
"\nImport descriptors. This will trigger a rescan of the blockchain based on the earliest timestamp of all descriptors being imported. Requires a new wallet backup.\n"
|
||||
"When importing descriptors with multipath key expressions, if the multipath specifier contains exactly two elements, the descriptor produced from the second elements will be imported as an internal descriptor.\n"
|
||||
"\nNote: This call can take over an hour to complete if using an early timestamp; during that time, other rpc calls\n"
|
||||
"may report that the imported keys, addresses or scripts exist but related transactions are still missing.\n"
|
||||
"The rescan is significantly faster if block filters are available (using startup option \"-blockfilterindex=1\").\n",
|
||||
|
|
Loading…
Add table
Reference in a new issue