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 std::string& descriptor = data["desc"].get_str();
|
||||||
const bool active = data.exists("active") ? data["active"].get_bool() : false;
|
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"])};
|
const std::string label{LabelFromValue(data["label"])};
|
||||||
|
|
||||||
// Parse descriptor string
|
// Parse descriptor string
|
||||||
|
@ -1473,13 +1472,19 @@ static UniValue ProcessDescriptorImport(CWallet& wallet, const UniValue& data, c
|
||||||
if (parsed_descs.empty()) {
|
if (parsed_descs.empty()) {
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, error);
|
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
|
// Range check
|
||||||
int64_t range_start = 0, range_end = 1, next_index = 0;
|
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");
|
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")) {
|
if (data.exists("range")) {
|
||||||
auto range = ParseDescriptorRange(data["range"]);
|
auto range = ParseDescriptorRange(data["range"]);
|
||||||
range_start = range.first;
|
range_start = range.first;
|
||||||
|
@ -1501,10 +1506,15 @@ static UniValue ProcessDescriptorImport(CWallet& wallet, const UniValue& data, c
|
||||||
}
|
}
|
||||||
|
|
||||||
// Active descriptors must be ranged
|
// 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");
|
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
|
// Ranged descriptors should not have a label
|
||||||
if (data.exists("range") && data.exists("label")) {
|
if (data.exists("range") && data.exists("label")) {
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Ranged descriptors should not have a 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
|
// 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");
|
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");
|
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
|
// Need to ExpandPrivate to check if private keys are available for all pubkeys
|
||||||
FlatSigningProvider expand_keys;
|
FlatSigningProvider expand_keys;
|
||||||
std::vector<CScript> scripts;
|
std::vector<CScript> scripts;
|
||||||
|
@ -1565,7 +1583,7 @@ static UniValue ProcessDescriptorImport(CWallet& wallet, const UniValue& data, c
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add descriptor to the wallet
|
// 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) {
|
if (spk_manager == nullptr) {
|
||||||
throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Could not add descriptor '%s'", descriptor));
|
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()) {
|
if (!w_desc.descriptor->GetOutputType()) {
|
||||||
warnings.push_back("Unknown output type, cannot set descriptor to active.");
|
warnings.push_back("Unknown output type, cannot set descriptor to active.");
|
||||||
} else {
|
} else {
|
||||||
wallet.AddActiveScriptPubKeyMan(spk_manager->GetID(), *w_desc.descriptor->GetOutputType(), internal);
|
wallet.AddActiveScriptPubKeyMan(spk_manager->GetID(), *w_desc.descriptor->GetOutputType(), desc_internal);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (w_desc.descriptor->GetOutputType()) {
|
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",
|
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"
|
"\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"
|
"\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"
|
"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",
|
"The rescan is significantly faster if block filters are available (using startup option \"-blockfilterindex=1\").\n",
|
||||||
|
|
Loading…
Add table
Reference in a new issue