mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-18 21:35:13 +01:00
rpc: Allow importmulti to import multipath descriptors correctly
Multipath descriptors will be imported as multiple separate descriptors. When there are exactly 2 multipath items, the first descriptor will be for receiving addreses, and the second for change addresses. When importing a multipath descriptor, 'internal' cannot be specified.
This commit is contained in:
parent
64dfe3ce4b
commit
32dcbca3fb
@ -1056,8 +1056,6 @@ static UniValue ProcessImportLegacy(ImportData& import_data, std::map<CKeyID, CP
|
||||
|
||||
static UniValue ProcessImportDescriptor(ImportData& import_data, std::map<CKeyID, CPubKey>& pubkey_map, std::map<CKeyID, CKey>& privkey_map, std::set<CScript>& script_pub_keys, bool& have_solving_data, const UniValue& data, std::vector<std::pair<CKeyID, bool>>& ordered_pubkeys)
|
||||
{
|
||||
const bool internal = data.exists("internal") ? data["internal"].get_bool() : false;
|
||||
|
||||
UniValue warnings(UniValue::VARR);
|
||||
|
||||
const std::string& descriptor = data["desc"].get_str();
|
||||
@ -1067,18 +1065,25 @@ static UniValue ProcessImportDescriptor(ImportData& import_data, std::map<CKeyID
|
||||
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) {
|
||||
if (parsed_descs.at(0)->GetOutputType() == OutputType::BECH32M) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Bech32m descriptors cannot be imported into legacy wallets");
|
||||
}
|
||||
|
||||
have_solving_data = parsed_desc->IsSolvable();
|
||||
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();
|
||||
}
|
||||
|
||||
have_solving_data = parsed_descs.at(0)->IsSolvable();
|
||||
const bool watch_only = data.exists("watchonly") ? data["watchonly"].get_bool() : false;
|
||||
|
||||
int64_t range_start = 0, range_end = 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")) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Descriptor is ranged, please specify the range");
|
||||
}
|
||||
@ -1087,25 +1092,34 @@ static UniValue ProcessImportDescriptor(ImportData& import_data, std::map<CKeyID
|
||||
|
||||
const UniValue& priv_keys = data.exists("keys") ? data["keys"].get_array() : UniValue();
|
||||
|
||||
// Expand all descriptors to get public keys and scripts, and private keys if available.
|
||||
for (int i = range_start; i <= range_end; ++i) {
|
||||
FlatSigningProvider out_keys;
|
||||
std::vector<CScript> scripts_temp;
|
||||
parsed_desc->Expand(i, keys, scripts_temp, out_keys);
|
||||
std::copy(scripts_temp.begin(), scripts_temp.end(), std::inserter(script_pub_keys, script_pub_keys.end()));
|
||||
for (const auto& key_pair : out_keys.pubkeys) {
|
||||
ordered_pubkeys.emplace_back(key_pair.first, internal);
|
||||
for (size_t j = 0; j < parsed_descs.size(); ++j) {
|
||||
const auto& parsed_desc = parsed_descs.at(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);
|
||||
}
|
||||
// Expand all descriptors to get public keys and scripts, and private keys if available.
|
||||
for (int i = range_start; i <= range_end; ++i) {
|
||||
FlatSigningProvider out_keys;
|
||||
std::vector<CScript> scripts_temp;
|
||||
parsed_desc->Expand(i, keys, scripts_temp, out_keys);
|
||||
std::copy(scripts_temp.begin(), scripts_temp.end(), std::inserter(script_pub_keys, script_pub_keys.end()));
|
||||
for (const auto& key_pair : out_keys.pubkeys) {
|
||||
ordered_pubkeys.emplace_back(key_pair.first, desc_internal);
|
||||
}
|
||||
|
||||
for (const auto& x : out_keys.scripts) {
|
||||
import_data.import_scripts.emplace(x.second);
|
||||
for (const auto& x : out_keys.scripts) {
|
||||
import_data.import_scripts.emplace(x.second);
|
||||
}
|
||||
|
||||
parsed_desc->ExpandPrivate(i, keys, out_keys);
|
||||
|
||||
std::copy(out_keys.pubkeys.begin(), out_keys.pubkeys.end(), std::inserter(pubkey_map, pubkey_map.end()));
|
||||
std::copy(out_keys.keys.begin(), out_keys.keys.end(), std::inserter(privkey_map, privkey_map.end()));
|
||||
import_data.key_origins.insert(out_keys.origins.begin(), out_keys.origins.end());
|
||||
}
|
||||
|
||||
parsed_desc->ExpandPrivate(i, keys, out_keys);
|
||||
|
||||
std::copy(out_keys.pubkeys.begin(), out_keys.pubkeys.end(), std::inserter(pubkey_map, pubkey_map.end()));
|
||||
std::copy(out_keys.keys.begin(), out_keys.keys.end(), std::inserter(privkey_map, privkey_map.end()));
|
||||
import_data.key_origins.insert(out_keys.origins.begin(), out_keys.origins.end());
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < priv_keys.size(); ++i) {
|
||||
|
Loading…
Reference in New Issue
Block a user