| 3937 | } |
| 3938 | |
| 3939 | util::Result<void> CWallet::ApplyMigrationData(WalletBatch& local_wallet_batch, MigrationData& data) |
| 3940 | { |
| 3941 | AssertLockHeld(cs_wallet); |
| 3942 | |
| 3943 | LegacyDataSPKM* legacy_spkm = GetLegacyDataSPKM(); |
| 3944 | if (!Assume(legacy_spkm)) { |
| 3945 | // This shouldn't happen |
| 3946 | return util::Error{Untranslated(STR_INTERNAL_BUG("Error: Legacy wallet data missing"))}; |
| 3947 | } |
| 3948 | |
| 3949 | // Note: when the legacy wallet has no spendable scripts, it must be empty at the end of the process. |
| 3950 | bool has_spendable_material = !data.desc_spkms.empty() || data.master_key.key.IsValid(); |
| 3951 | |
| 3952 | // Get all invalid or non-watched scripts that will not be migrated |
| 3953 | std::set<CTxDestination> not_migrated_dests; |
| 3954 | for (const auto& script : legacy_spkm->GetNotMineScriptPubKeys()) { |
| 3955 | CTxDestination dest; |
| 3956 | if (ExtractDestination(script, dest)) not_migrated_dests.emplace(dest); |
| 3957 | } |
| 3958 | |
| 3959 | // When the legacy wallet has no spendable scripts, the main wallet will be empty, leaving its script cache empty as well. |
| 3960 | // The watch-only and/or solvable wallet(s) will contain the scripts in their respective caches. |
| 3961 | if (!data.desc_spkms.empty()) Assume(!m_cached_spks.empty()); |
| 3962 | if (!data.watch_descs.empty()) Assume(!data.watchonly_wallet->m_cached_spks.empty()); |
| 3963 | if (!data.solvable_descs.empty()) Assume(!data.solvable_wallet->m_cached_spks.empty()); |
| 3964 | |
| 3965 | for (auto& desc_spkm : data.desc_spkms) { |
| 3966 | if (m_spk_managers.contains(desc_spkm->GetID())) { |
| 3967 | return util::Error{_("Error: Duplicate descriptors created during migration. Your wallet may be corrupted.")}; |
| 3968 | } |
| 3969 | uint256 id = desc_spkm->GetID(); |
| 3970 | AddScriptPubKeyMan(id, std::move(desc_spkm)); |
| 3971 | } |
| 3972 | |
| 3973 | // Remove the LegacyScriptPubKeyMan from disk |
| 3974 | if (!legacy_spkm->DeleteRecordsWithDB(local_wallet_batch)) { |
| 3975 | return util::Error{_("Error: cannot remove legacy wallet records")}; |
| 3976 | } |
| 3977 | |
| 3978 | // Remove the LegacyScriptPubKeyMan from memory |
| 3979 | m_spk_managers.erase(legacy_spkm->GetID()); |
| 3980 | m_external_spk_managers.clear(); |
| 3981 | m_internal_spk_managers.clear(); |
| 3982 | |
| 3983 | // Setup new descriptors (only if we are migrating any key material) |
| 3984 | SetWalletFlagWithDB(local_wallet_batch, WALLET_FLAG_DESCRIPTORS | WALLET_FLAG_LAST_HARDENED_XPUB_CACHED); |
| 3985 | if (has_spendable_material && !IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { |
| 3986 | // Use the existing master key if we have it |
| 3987 | if (data.master_key.key.IsValid()) { |
| 3988 | SetupDescriptorScriptPubKeyMans(local_wallet_batch, data.master_key); |
| 3989 | } else { |
| 3990 | // Setup with a new seed if we don't. |
| 3991 | SetupOwnDescriptorScriptPubKeyMans(local_wallet_batch); |
| 3992 | } |
| 3993 | } |
| 3994 | |
| 3995 | // Get best block locator so that we can copy it to the watchonly and solvables |
| 3996 | // Note: The best block locator was introduced in #152 so ancient wallets do not have it |
no test coverage detected