@@ -1700,59 +1700,62 @@ std::set<CKeyID> LegacyScriptPubKeyMan::GetKeys() const
1700
1700
return set_address;
1701
1701
}
1702
1702
1703
- std::unordered_set<CScript, SaltedSipHasher> LegacyDataSPKM::GetScriptPubKeys () const
1703
+ std::unordered_set<CScript, SaltedSipHasher> LegacyDataSPKM::GetCandidateScriptPubKeys () const
1704
1704
{
1705
1705
LOCK (cs_KeyStore);
1706
- std::unordered_set<CScript, SaltedSipHasher> spks ;
1706
+ std::unordered_set<CScript, SaltedSipHasher> candidate_spks ;
1707
1707
1708
- // All keys have at least P2PK and P2PKH
1709
- for (const auto & key_pair : mapKeys) {
1710
- const CPubKey& pub = key_pair.second .GetPubKey ();
1711
- spks.insert (GetScriptForRawPubKey (pub));
1712
- spks.insert (GetScriptForDestination (PKHash (pub)));
1708
+ // For every private key in the wallet, there should be a P2PK, P2PKH, P2WPKH, and P2SH-P2WPKH
1709
+ const auto & add_pubkey = [&candidate_spks](const CPubKey& pub) -> void {
1710
+ candidate_spks.insert (GetScriptForRawPubKey (pub));
1711
+ candidate_spks.insert (GetScriptForDestination (PKHash (pub)));
1712
+
1713
+ CScript wpkh = GetScriptForDestination (WitnessV0KeyHash (pub));
1714
+ candidate_spks.insert (wpkh);
1715
+ candidate_spks.insert (GetScriptForDestination (ScriptHash (wpkh)));
1716
+ };
1717
+ for (const auto & [_, key] : mapKeys) {
1718
+ add_pubkey (key.GetPubKey ());
1713
1719
}
1714
- for (const auto & key_pair : mapCryptedKeys) {
1715
- const CPubKey& pub = key_pair.second .first ;
1716
- spks.insert (GetScriptForRawPubKey (pub));
1717
- spks.insert (GetScriptForDestination (PKHash (pub)));
1720
+ for (const auto & [_, ckeypair] : mapCryptedKeys) {
1721
+ add_pubkey (ckeypair.first );
1718
1722
}
1719
1723
1720
- // For every script in mapScript, only the ISMINE_SPENDABLE ones are being tracked.
1721
- // The watchonly ones will be in setWatchOnly which we deal with later
1722
- // For all keys, if they have segwit scripts, those scripts will end up in mapScripts
1723
- for (const auto & script_pair : mapScripts) {
1724
- const CScript& script = script_pair.second ;
1725
- if (IsMine (script) == ISMINE_SPENDABLE) {
1726
- // Add ScriptHash for scripts that are not already P2SH
1727
- if (!script.IsPayToScriptHash ()) {
1728
- spks.insert (GetScriptForDestination (ScriptHash (script)));
1729
- }
1730
- // For segwit scripts, we only consider them spendable if we have the segwit spk
1731
- int wit_ver = -1 ;
1732
- std::vector<unsigned char > witprog;
1733
- if (script.IsWitnessProgram (wit_ver, witprog) && wit_ver == 0 ) {
1734
- spks.insert (script);
1735
- }
1736
- } else {
1737
- // Multisigs are special. They don't show up as ISMINE_SPENDABLE unless they are in a P2SH
1738
- // So check the P2SH of a multisig to see if we should insert it
1739
- std::vector<std::vector<unsigned char >> sols;
1740
- TxoutType type = Solver (script, sols);
1741
- if (type == TxoutType::MULTISIG) {
1742
- CScript ms_spk = GetScriptForDestination (ScriptHash (script));
1743
- if (IsMine (ms_spk) != ISMINE_NO) {
1744
- spks.insert (ms_spk);
1745
- }
1746
- }
1747
- }
1724
+ // mapScripts contains all redeemScripts and witnessScripts. Therefore each script in it has
1725
+ // itself, P2SH, P2WSH, and P2SH-P2WSH as a candidate.
1726
+ // Invalid scripts such as P2SH-P2SH and P2WSH-P2SH, among others, will be added as candidates.
1727
+ // Callers of this function will need to remove such scripts.
1728
+ const auto & add_script = [&candidate_spks](const CScript& script) -> void {
1729
+ candidate_spks.insert (script);
1730
+ candidate_spks.insert (GetScriptForDestination (ScriptHash (script)));
1731
+
1732
+ CScript wsh = GetScriptForDestination (WitnessV0ScriptHash (script));
1733
+ candidate_spks.insert (wsh);
1734
+ candidate_spks.insert (GetScriptForDestination (ScriptHash (wsh)));
1735
+ };
1736
+ for (const auto & [_, script] : mapScripts) {
1737
+ add_script (script);
1748
1738
}
1749
1739
1750
- // All watchonly scripts are raw
1751
- for (const CScript& script : setWatchOnly) {
1752
- // As the legacy wallet allowed to import any script, we need to verify the validity here.
1753
- // LegacyScriptPubKeyMan::IsMine() return 'ISMINE_NO' for invalid or not watched scripts (IsMineResult::INVALID or IsMineResult::NO).
1754
- // e.g. a "sh(sh(pkh()))" which legacy wallets allowed to import!.
1755
- if (IsMine (script) != ISMINE_NO) spks.insert (script);
1740
+ // Although setWatchOnly should only contain output scripts, we will also include each script's
1741
+ // P2SH, P2WSH, and P2SH-P2WSH as a precaution.
1742
+ for (const auto & script : setWatchOnly) {
1743
+ add_script (script);
1744
+ }
1745
+
1746
+ return candidate_spks;
1747
+ }
1748
+
1749
+ std::unordered_set<CScript, SaltedSipHasher> LegacyDataSPKM::GetScriptPubKeys () const
1750
+ {
1751
+ // Run IsMine() on each candidate output script. Any script that is not ISMINE_NO is an output
1752
+ // script to return.
1753
+ // This both filters out things that are not watched by the wallet, and things that are invalid.
1754
+ std::unordered_set<CScript, SaltedSipHasher> spks;
1755
+ for (const CScript& script : GetCandidateScriptPubKeys ()) {
1756
+ if (IsMine (script) != ISMINE_NO) {
1757
+ spks.insert (script);
1758
+ }
1756
1759
}
1757
1760
1758
1761
return spks;
0 commit comments