mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-11-13 15:39:05 +01:00
add importdescriptors RPC and tests for native descriptor wallets
Co-authored-by: Andrew Chow <achow101-github@achow101.com>
This commit is contained in:
@@ -4399,6 +4399,7 @@ void CWallet::SetupDescriptorScriptPubKeyMans()
|
||||
|
||||
void CWallet::SetActiveScriptPubKeyMan(uint256 id, OutputType type, bool internal, bool memonly)
|
||||
{
|
||||
WalletLogPrintf("Setting spkMan to active: id = %s, type = %d, internal = %d\n", id.ToString(), static_cast<int>(type), static_cast<int>(internal));
|
||||
auto& spk_mans = internal ? m_internal_spk_managers : m_external_spk_managers;
|
||||
auto spk_man = m_spk_managers.at(id).get();
|
||||
spk_man->SetType(type, internal);
|
||||
@@ -4421,3 +4422,88 @@ bool CWallet::IsLegacy() const
|
||||
auto spk_man = dynamic_cast<LegacyScriptPubKeyMan*>(m_internal_spk_managers.at(OutputType::LEGACY));
|
||||
return spk_man != nullptr;
|
||||
}
|
||||
|
||||
DescriptorScriptPubKeyMan* CWallet::GetDescriptorScriptPubKeyMan(const WalletDescriptor& desc) const
|
||||
{
|
||||
for (auto& spk_man_pair : m_spk_managers) {
|
||||
// Try to downcast to DescriptorScriptPubKeyMan then check if the descriptors match
|
||||
DescriptorScriptPubKeyMan* spk_manager = dynamic_cast<DescriptorScriptPubKeyMan*>(spk_man_pair.second.get());
|
||||
if (spk_manager != nullptr && spk_manager->HasWalletDescriptor(desc)) {
|
||||
return spk_manager;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ScriptPubKeyMan* CWallet::AddWalletDescriptor(WalletDescriptor& desc, const FlatSigningProvider& signing_provider, const std::string& label)
|
||||
{
|
||||
if (!IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
|
||||
WalletLogPrintf("Cannot add WalletDescriptor to a non-descriptor wallet\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LOCK(cs_wallet);
|
||||
auto new_spk_man = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this, desc));
|
||||
|
||||
// If we already have this descriptor, remove it from the maps but add the existing cache to desc
|
||||
auto old_spk_man = GetDescriptorScriptPubKeyMan(desc);
|
||||
if (old_spk_man) {
|
||||
WalletLogPrintf("Update existing descriptor: %s\n", desc.descriptor->ToString());
|
||||
|
||||
{
|
||||
LOCK(old_spk_man->cs_desc_man);
|
||||
new_spk_man->SetCache(old_spk_man->GetWalletDescriptor().cache);
|
||||
}
|
||||
|
||||
// Remove from maps of active spkMans
|
||||
auto old_spk_man_id = old_spk_man->GetID();
|
||||
for (bool internal : {false, true}) {
|
||||
for (OutputType t : OUTPUT_TYPES) {
|
||||
auto active_spk_man = GetScriptPubKeyMan(t, internal);
|
||||
if (active_spk_man && active_spk_man->GetID() == old_spk_man_id) {
|
||||
if (internal) {
|
||||
m_internal_spk_managers.erase(t);
|
||||
} else {
|
||||
m_external_spk_managers.erase(t);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_spk_managers.erase(old_spk_man_id);
|
||||
}
|
||||
|
||||
// Add the private keys to the descriptor
|
||||
for (const auto& entry : signing_provider.keys) {
|
||||
const CKey& key = entry.second;
|
||||
new_spk_man->AddDescriptorKey(key, key.GetPubKey());
|
||||
}
|
||||
|
||||
// Top up key pool, the manager will generate new scriptPubKeys internally
|
||||
new_spk_man->TopUp();
|
||||
|
||||
// Apply the label if necessary
|
||||
// Note: we disable labels for ranged descriptors
|
||||
if (!desc.descriptor->IsRange()) {
|
||||
auto script_pub_keys = new_spk_man->GetScriptPubKeys();
|
||||
if (script_pub_keys.empty()) {
|
||||
WalletLogPrintf("Could not generate scriptPubKeys (cache is empty)\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CTxDestination dest;
|
||||
if (ExtractDestination(script_pub_keys.at(0), dest)) {
|
||||
SetAddressBook(dest, label, "receive");
|
||||
}
|
||||
}
|
||||
|
||||
// Save the descriptor to memory
|
||||
auto ret = new_spk_man.get();
|
||||
m_spk_managers[new_spk_man->GetID()] = std::move(new_spk_man);
|
||||
|
||||
// Save the descriptor to DB
|
||||
ret->WriteDescriptor();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user