@@ -999,9 +999,10 @@ bool LegacyScriptPubKeyMan::GetKeyOrigin(const CKeyID& keyID, KeyOriginInfo& inf
999
999
{
1000
1000
LOCK (cs_KeyStore);
1001
1001
auto it = mapKeyMetadata.find (keyID);
1002
- if (it ! = mapKeyMetadata.end ()) {
1003
- meta = it-> second ;
1002
+ if (it = = mapKeyMetadata.end ()) {
1003
+ return false ;
1004
1004
}
1005
+ meta = it->second ;
1005
1006
}
1006
1007
if (meta.has_key_origin ) {
1007
1008
std::copy (meta.key_origin .fingerprint , meta.key_origin .fingerprint + 4 , info.fingerprint );
@@ -1711,6 +1712,258 @@ const std::unordered_set<CScript, SaltedSipHasher> LegacyScriptPubKeyMan::GetScr
1711
1712
return spks;
1712
1713
}
1713
1714
1715
+ std::optional<MigrationData> LegacyScriptPubKeyMan::MigrateToDescriptor ()
1716
+ {
1717
+ LOCK (cs_KeyStore);
1718
+ if (m_storage.IsLocked ()) {
1719
+ return std::nullopt;
1720
+ }
1721
+
1722
+ MigrationData out;
1723
+
1724
+ std::unordered_set<CScript, SaltedSipHasher> spks{GetScriptPubKeys ()};
1725
+
1726
+ // Get all key ids
1727
+ std::set<CKeyID> keyids;
1728
+ for (const auto & key_pair : mapKeys) {
1729
+ keyids.insert (key_pair.first );
1730
+ }
1731
+ for (const auto & key_pair : mapCryptedKeys) {
1732
+ keyids.insert (key_pair.first );
1733
+ }
1734
+
1735
+ // Get key metadata and figure out which keys don't have a seed
1736
+ // Note that we do not ignore the seeds themselves because they are considered IsMine!
1737
+ for (auto keyid_it = keyids.begin (); keyid_it != keyids.end ();) {
1738
+ const CKeyID& keyid = *keyid_it;
1739
+ const auto & it = mapKeyMetadata.find (keyid);
1740
+ if (it != mapKeyMetadata.end ()) {
1741
+ const CKeyMetadata& meta = it->second ;
1742
+ if (meta.hdKeypath == " s" || meta.hdKeypath == " m" ) {
1743
+ keyid_it++;
1744
+ continue ;
1745
+ }
1746
+ if (m_hd_chain.seed_id == meta.hd_seed_id || m_inactive_hd_chains.count (meta.hd_seed_id ) > 0 ) {
1747
+ keyid_it = keyids.erase (keyid_it);
1748
+ continue ;
1749
+ }
1750
+ }
1751
+ keyid_it++;
1752
+ }
1753
+
1754
+ // keyids is now all non-HD keys. Each key will have its own combo descriptor
1755
+ for (const CKeyID& keyid : keyids) {
1756
+ CKey key;
1757
+ if (!GetKey (keyid, key)) {
1758
+ assert (false );
1759
+ }
1760
+
1761
+ // Get birthdate from key meta
1762
+ uint64_t creation_time = 0 ;
1763
+ const auto & it = mapKeyMetadata.find (keyid);
1764
+ if (it != mapKeyMetadata.end ()) {
1765
+ creation_time = it->second .nCreateTime ;
1766
+ }
1767
+
1768
+ // Get the key origin
1769
+ // Maybe this doesn't matter because floating keys here shouldn't have origins
1770
+ KeyOriginInfo info;
1771
+ bool has_info = GetKeyOrigin (keyid, info);
1772
+ std::string origin_str = has_info ? " [" + HexStr (info.fingerprint ) + FormatHDKeypath (info.path ) + " ]" : " " ;
1773
+
1774
+ // Construct the combo descriptor
1775
+ std::string desc_str = " combo(" + origin_str + HexStr (key.GetPubKey ()) + " )" ;
1776
+ FlatSigningProvider keys;
1777
+ std::string error;
1778
+ std::unique_ptr<Descriptor> desc = Parse (desc_str, keys, error, false );
1779
+ WalletDescriptor w_desc (std::move (desc), creation_time, 0 , 0 , 0 );
1780
+
1781
+ // Make the DescriptorScriptPubKeyMan and get the scriptPubKeys
1782
+ auto desc_spk_man = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan (m_storage, w_desc));
1783
+ desc_spk_man->AddDescriptorKey (key, key.GetPubKey ());
1784
+ desc_spk_man->TopUp ();
1785
+ auto desc_spks = desc_spk_man->GetScriptPubKeys ();
1786
+
1787
+ // Remove the scriptPubKeys from our current set
1788
+ for (const CScript& spk : desc_spks) {
1789
+ size_t erased = spks.erase (spk);
1790
+ assert (erased == 1 );
1791
+ assert (IsMine (spk) == ISMINE_SPENDABLE);
1792
+ }
1793
+
1794
+ out.desc_spkms .push_back (std::move (desc_spk_man));
1795
+ }
1796
+
1797
+ // Handle HD keys by using the CHDChains
1798
+ std::vector<CHDChain> chains;
1799
+ chains.push_back (m_hd_chain);
1800
+ for (const auto & chain_pair : m_inactive_hd_chains) {
1801
+ chains.push_back (chain_pair.second );
1802
+ }
1803
+ for (const CHDChain& chain : chains) {
1804
+ for (int i = 0 ; i < 2 ; ++i) {
1805
+ // Skip if doing internal chain and split chain is not supported
1806
+ if (chain.seed_id .IsNull () || (i == 1 && !m_storage.CanSupportFeature (FEATURE_HD_SPLIT))) {
1807
+ continue ;
1808
+ }
1809
+ // Get the master xprv
1810
+ CKey seed_key;
1811
+ if (!GetKey (chain.seed_id , seed_key)) {
1812
+ assert (false );
1813
+ }
1814
+ CExtKey master_key;
1815
+ master_key.SetSeed (seed_key);
1816
+
1817
+ // Make the combo descriptor
1818
+ std::string xpub = EncodeExtPubKey (master_key.Neuter ());
1819
+ std::string desc_str = " combo(" + xpub + " /0'/" + ToString (i) + " '/*')" ;
1820
+ FlatSigningProvider keys;
1821
+ std::string error;
1822
+ std::unique_ptr<Descriptor> desc = Parse (desc_str, keys, error, false );
1823
+ uint32_t chain_counter = std::max ((i == 1 ? chain.nInternalChainCounter : chain.nExternalChainCounter ), (uint32_t )0 );
1824
+ WalletDescriptor w_desc (std::move (desc), 0 , 0 , chain_counter, 0 );
1825
+
1826
+ // Make the DescriptorScriptPubKeyMan and get the scriptPubKeys
1827
+ auto desc_spk_man = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan (m_storage, w_desc));
1828
+ desc_spk_man->AddDescriptorKey (master_key.key , master_key.key .GetPubKey ());
1829
+ desc_spk_man->TopUp ();
1830
+ auto desc_spks = desc_spk_man->GetScriptPubKeys ();
1831
+
1832
+ // Remove the scriptPubKeys from our current set
1833
+ for (const CScript& spk : desc_spks) {
1834
+ size_t erased = spks.erase (spk);
1835
+ assert (erased == 1 );
1836
+ assert (IsMine (spk) == ISMINE_SPENDABLE);
1837
+ }
1838
+
1839
+ out.desc_spkms .push_back (std::move (desc_spk_man));
1840
+ }
1841
+ }
1842
+ // Add the current master seed to the migration data
1843
+ if (!m_hd_chain.seed_id .IsNull ()) {
1844
+ CKey seed_key;
1845
+ if (!GetKey (m_hd_chain.seed_id , seed_key)) {
1846
+ assert (false );
1847
+ }
1848
+ out.master_key .SetSeed (seed_key);
1849
+ }
1850
+
1851
+ // Handle the rest of the scriptPubKeys which must be imports and may not have all info
1852
+ for (auto it = spks.begin (); it != spks.end ();) {
1853
+ const CScript& spk = *it;
1854
+
1855
+ // Get birthdate from script meta
1856
+ uint64_t creation_time = 0 ;
1857
+ const auto & mit = m_script_metadata.find (CScriptID (spk));
1858
+ if (mit != m_script_metadata.end ()) {
1859
+ creation_time = mit->second .nCreateTime ;
1860
+ }
1861
+
1862
+ // InferDescriptor as that will get us all the solving info if it is there
1863
+ std::unique_ptr<Descriptor> desc = InferDescriptor (spk, *GetSolvingProvider (spk));
1864
+ // Get the private keys for this descriptor
1865
+ std::vector<CScript> scripts;
1866
+ FlatSigningProvider keys;
1867
+ if (!desc->Expand (0 , DUMMY_SIGNING_PROVIDER, scripts, keys)) {
1868
+ assert (false );
1869
+ }
1870
+ std::set<CKeyID> privkeyids;
1871
+ for (const auto & key_orig_pair : keys.origins ) {
1872
+ privkeyids.insert (key_orig_pair.first );
1873
+ }
1874
+
1875
+ std::vector<CScript> desc_spks;
1876
+
1877
+ // Make the descriptor string with private keys
1878
+ std::string desc_str;
1879
+ bool watchonly = !desc->ToPrivateString (*this , desc_str);
1880
+ if (watchonly && !m_storage.IsWalletFlagSet (WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
1881
+ out.watch_descs .push_back ({desc->ToString (), creation_time});
1882
+
1883
+ // Get the scriptPubKeys without writing this to the wallet
1884
+ FlatSigningProvider provider;
1885
+ desc->Expand (0 , provider, desc_spks, provider);
1886
+ } else {
1887
+ // Make the DescriptorScriptPubKeyMan and get the scriptPubKeys
1888
+ WalletDescriptor w_desc (std::move (desc), creation_time, 0 , 0 , 0 );
1889
+ auto desc_spk_man = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan (m_storage, w_desc));
1890
+ for (const auto & keyid : privkeyids) {
1891
+ CKey key;
1892
+ if (!GetKey (keyid, key)) {
1893
+ continue ;
1894
+ }
1895
+ desc_spk_man->AddDescriptorKey (key, key.GetPubKey ());
1896
+ }
1897
+ desc_spk_man->TopUp ();
1898
+ auto desc_spks_set = desc_spk_man->GetScriptPubKeys ();
1899
+ desc_spks.insert (desc_spks.end (), desc_spks_set.begin (), desc_spks_set.end ());
1900
+
1901
+ out.desc_spkms .push_back (std::move (desc_spk_man));
1902
+ }
1903
+
1904
+ // Remove the scriptPubKeys from our current set
1905
+ for (const CScript& desc_spk : desc_spks) {
1906
+ auto del_it = spks.find (desc_spk);
1907
+ assert (del_it != spks.end ());
1908
+ assert (IsMine (desc_spk) != ISMINE_NO);
1909
+ it = spks.erase (del_it);
1910
+ }
1911
+ }
1912
+
1913
+ // Multisigs are special. They don't show up as ISMINE_SPENDABLE unless they are in a P2SH
1914
+ // So we have to check if any of our scripts are a multisig and if so, add the P2SH
1915
+ for (const auto & script_pair : mapScripts) {
1916
+ const CScript script = script_pair.second ;
1917
+
1918
+ // Get birthdate from script meta
1919
+ uint64_t creation_time = 0 ;
1920
+ const auto & it = m_script_metadata.find (CScriptID (script));
1921
+ if (it != m_script_metadata.end ()) {
1922
+ creation_time = it->second .nCreateTime ;
1923
+ }
1924
+
1925
+ std::vector<std::vector<unsigned char >> sols;
1926
+ TxoutType type = Solver (script, sols);
1927
+ if (type == TxoutType::MULTISIG) {
1928
+ CScript sh_spk = GetScriptForDestination (ScriptHash (script));
1929
+ CTxDestination witdest = WitnessV0ScriptHash (script);
1930
+ CScript witprog = GetScriptForDestination (witdest);
1931
+ CScript sh_wsh_spk = GetScriptForDestination (ScriptHash (witprog));
1932
+
1933
+ // We only want the multisigs that we have not already seen, i.e. they are not watchonly and not spendable
1934
+ // For P2SH, a multisig is not ISMINE_NO when:
1935
+ // * All keys are in the wallet
1936
+ // * The multisig itself is watch only
1937
+ // * The P2SH is watch only
1938
+ // For P2SH-P2WSH, if the script is in the wallet, then it will have the same conditions as P2SH.
1939
+ // For P2WSH, a multisig is not ISMINE_NO when, other than the P2SH conditions:
1940
+ // * The P2WSH script is in the wallet and it is being watched
1941
+ std::vector<std::vector<unsigned char >> keys (sols.begin () + 1 , sols.begin () + sols.size () - 1 );
1942
+ if (HaveWatchOnly (sh_spk) || HaveWatchOnly (script) || HaveKeys (keys, *this ) || (HaveCScript (CScriptID (witprog)) && HaveWatchOnly (witprog))) {
1943
+ // The above emulates IsMine for these 3 scriptPubKeys, so double check that by running IsMine
1944
+ assert (IsMine (sh_spk) != ISMINE_NO || IsMine (witprog) != ISMINE_NO || IsMine (sh_wsh_spk) != ISMINE_NO);
1945
+ continue ;
1946
+ }
1947
+ assert (IsMine (sh_spk) == ISMINE_NO && IsMine (witprog) == ISMINE_NO && IsMine (sh_wsh_spk) == ISMINE_NO);
1948
+
1949
+ std::unique_ptr<Descriptor> sh_desc = InferDescriptor (sh_spk, *GetSolvingProvider (sh_spk));
1950
+ out.solvable_descs .push_back ({sh_desc->ToString (), creation_time});
1951
+
1952
+ const auto desc = InferDescriptor (witprog, *this );
1953
+ if (desc->IsSolvable ()) {
1954
+ std::unique_ptr<Descriptor> wsh_desc = InferDescriptor (witprog, *GetSolvingProvider (witprog));
1955
+ out.solvable_descs .push_back ({wsh_desc->ToString (), creation_time});
1956
+ std::unique_ptr<Descriptor> sh_wsh_desc = InferDescriptor (sh_wsh_spk, *GetSolvingProvider (sh_wsh_spk));
1957
+ out.solvable_descs .push_back ({sh_wsh_desc->ToString (), creation_time});
1958
+ }
1959
+ }
1960
+ }
1961
+
1962
+ // Make sure that we have accounted for all scriptPubKeys
1963
+ assert (spks.size () == 0 );
1964
+ return out;
1965
+ }
1966
+
1714
1967
util::Result<CTxDestination> DescriptorScriptPubKeyMan::GetNewDestination (const OutputType type)
1715
1968
{
1716
1969
// Returns true if this descriptor supports getting new addresses. Conditions where we may be unable to fetch them (e.g. locked) are caught later
0 commit comments