Skip to content

Commit 1de8a23

Browse files
committed
wallet: disallow migration of invalid or not-watched scripts
The legacy wallet allowed to import any raw script, without checking if it was valid or not. Appending it to the watch-only set. This causes a crash in the migration process because we are only expecting to find valid scripts inside the legacy spkm. These stored scripts internally map to `ISMINE_NO` (same as if they weren't stored at all..). So we need to check for these special case, and take into account that the legacy spkm could be storing invalid not watched scripts. Which, in code words, means IsMineInner() returning IsMineResult::INVALID for them.
1 parent d23fda0 commit 1de8a23

File tree

3 files changed

+36
-1
lines changed

3 files changed

+36
-1
lines changed

src/wallet/scriptpubkeyman.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1714,8 +1714,23 @@ std::unordered_set<CScript, SaltedSipHasher> LegacyScriptPubKeyMan::GetScriptPub
17141714
}
17151715

17161716
// All watchonly scripts are raw
1717-
spks.insert(setWatchOnly.begin(), setWatchOnly.end());
1717+
for (const CScript& script : setWatchOnly) {
1718+
// As the legacy wallet allowed to import any script, we need to verify the validity here.
1719+
// LegacyScriptPubKeyMan::IsMine() return 'ISMINE_NO' for invalid or not watched scripts (IsMineResult::INVALID or IsMineResult::NO).
1720+
// e.g. a "sh(sh(pkh()))" which legacy wallets allowed to import!.
1721+
if (IsMine(script) != ISMINE_NO) spks.insert(script);
1722+
}
1723+
1724+
return spks;
1725+
}
17181726

1727+
std::unordered_set<CScript, SaltedSipHasher> LegacyScriptPubKeyMan::GetNotMineScriptPubKeys() const
1728+
{
1729+
LOCK(cs_KeyStore);
1730+
std::unordered_set<CScript, SaltedSipHasher> spks;
1731+
for (const CScript& script : setWatchOnly) {
1732+
if (IsMine(script) == ISMINE_NO) spks.insert(script);
1733+
}
17191734
return spks;
17201735
}
17211736

src/wallet/scriptpubkeyman.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,12 @@ class LegacyScriptPubKeyMan : public ScriptPubKeyMan, public FillableSigningProv
523523
std::set<CKeyID> GetKeys() const override;
524524
std::unordered_set<CScript, SaltedSipHasher> GetScriptPubKeys() const override;
525525

526+
/**
527+
* Retrieves scripts that were imported by bugs into the legacy spkm and are
528+
* simply invalid, such as a sh(sh(pkh())) script, or not watched.
529+
*/
530+
std::unordered_set<CScript, SaltedSipHasher> GetNotMineScriptPubKeys() const;
531+
526532
/** Get the DescriptorScriptPubKeyMans (with private keys) that have the same scriptPubKeys as this LegacyScriptPubKeyMan.
527533
* Does not modify this ScriptPubKeyMan. */
528534
std::optional<MigrationData> MigrateToDescriptor();

src/wallet/wallet.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3920,6 +3920,13 @@ bool CWallet::ApplyMigrationData(MigrationData& data, bilingual_str& error)
39203920
return false;
39213921
}
39223922

3923+
// Get all invalid or non-watched scripts that will not be migrated
3924+
std::set<CTxDestination> not_migrated_dests;
3925+
for (const auto& script : legacy_spkm->GetNotMineScriptPubKeys()) {
3926+
CTxDestination dest;
3927+
if (ExtractDestination(script, dest)) not_migrated_dests.emplace(dest);
3928+
}
3929+
39233930
for (auto& desc_spkm : data.desc_spkms) {
39243931
if (m_spk_managers.count(desc_spkm->GetID()) > 0) {
39253932
error = _("Error: Duplicate descriptors created during migration. Your wallet may be corrupted.");
@@ -4026,6 +4033,13 @@ bool CWallet::ApplyMigrationData(MigrationData& data, bilingual_str& error)
40264033
continue;
40274034
}
40284035
}
4036+
4037+
// Skip invalid/non-watched scripts that will not be migrated
4038+
if (not_migrated_dests.count(addr_pair.first) > 0) {
4039+
dests_to_delete.push_back(addr_pair.first);
4040+
continue;
4041+
}
4042+
40294043
// Not ours, not in watchonly wallet, and not in solvable
40304044
error = _("Error: Address book data in wallet cannot be identified to belong to migrated wallets");
40314045
return false;

0 commit comments

Comments
 (0)