mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-02 14:37:42 -03: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
1 changed files with 37 additions and 23 deletions
|
@ -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)
|
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);
|
UniValue warnings(UniValue::VARR);
|
||||||
|
|
||||||
const std::string& descriptor = data["desc"].get_str();
|
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()) {
|
if (parsed_descs.empty()) {
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, error);
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, error);
|
||||||
}
|
}
|
||||||
const auto& parsed_desc = parsed_descs.at(0);
|
if (parsed_descs.at(0)->GetOutputType() == OutputType::BECH32M) {
|
||||||
if (parsed_desc->GetOutputType() == OutputType::BECH32M) {
|
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Bech32m descriptors cannot be imported into legacy wallets");
|
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;
|
const bool watch_only = data.exists("watchonly") ? data["watchonly"].get_bool() : false;
|
||||||
|
|
||||||
int64_t range_start = 0, range_end = 0;
|
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");
|
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")) {
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Descriptor is ranged, please specify the 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();
|
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 (size_t j = 0; j < parsed_descs.size(); ++j) {
|
||||||
for (int i = range_start; i <= range_end; ++i) {
|
const auto& parsed_desc = parsed_descs.at(j);
|
||||||
FlatSigningProvider out_keys;
|
bool desc_internal = internal.has_value() && internal.value();
|
||||||
std::vector<CScript> scripts_temp;
|
if (parsed_descs.size() == 2) {
|
||||||
parsed_desc->Expand(i, keys, scripts_temp, out_keys);
|
desc_internal = j == 1;
|
||||||
std::copy(scripts_temp.begin(), scripts_temp.end(), std::inserter(script_pub_keys, script_pub_keys.end()));
|
} else if (parsed_descs.size() > 2) {
|
||||||
for (const auto& key_pair : out_keys.pubkeys) {
|
CHECK_NONFATAL(!desc_internal);
|
||||||
ordered_pubkeys.emplace_back(key_pair.first, 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) {
|
for (const auto& x : out_keys.scripts) {
|
||||||
import_data.import_scripts.emplace(x.second);
|
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) {
|
for (size_t i = 0; i < priv_keys.size(); ++i) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue