diff --git a/src/wallet/scriptpubkeyman.h b/src/wallet/scriptpubkeyman.h --- a/src/wallet/scriptpubkeyman.h +++ b/src/wallet/scriptpubkeyman.h @@ -19,6 +19,7 @@ #include enum class OutputType; +class CChainParams; struct bilingual_str; // Wallet storage things that ScriptPubKeyMans need in order to be able to store @@ -33,6 +34,7 @@ virtual ~WalletStorage() = default; virtual const std::string GetDisplayName() const = 0; virtual WalletDatabase &GetDatabase() = 0; + virtual const CChainParams &GetChainParams() const = 0; virtual bool IsWalletFlagSet(uint64_t) const = 0; virtual void UnsetBlankWalletFlag(WalletBatch &) = 0; virtual bool CanSupportFeature(enum WalletFeature) const = 0; @@ -675,6 +677,9 @@ bool IsHDEnabled() const override; + //! Setup descriptors based on the given CExtkey + bool SetupDescriptorGeneration(const CExtKey &master_key); + bool HavePrivateKeys() const override; int64_t GetOldestKeyPoolTime() const override; diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -2,6 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include #include #include #include @@ -1600,6 +1601,69 @@ } } +bool DescriptorScriptPubKeyMan::SetupDescriptorGeneration( + const CExtKey &master_key) { + LOCK(cs_desc_man); + assert(m_storage.IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)); + + // Ignore when there is already a descriptor + if (m_wallet_descriptor.descriptor) { + return false; + } + + int64_t creation_time = GetTime(); + + std::string xpub = EncodeExtPubKey(master_key.Neuter()); + + // Build descriptor string + std::string desc_prefix; + std::string desc_suffix = "/*)"; + switch (m_address_type) { + case OutputType::LEGACY: { + desc_prefix = "pkh(" + xpub + "/44'"; + break; + } + default: + assert(false); + } + + // Mainnet derives at 0', testnet and regtest derive at 1' + if (m_storage.GetChainParams().IsTestChain()) { + desc_prefix += "/1'"; + } else { + desc_prefix += "/0'"; + } + + std::string internal_path = m_internal ? "/1" : "/0"; + std::string desc_str = desc_prefix + "/0'" + internal_path + desc_suffix; + + // Make the descriptor + FlatSigningProvider keys; + std::string error; + std::unique_ptr desc = Parse(desc_str, keys, error, false); + WalletDescriptor w_desc(std::move(desc), creation_time, 0, 0, 0); + m_wallet_descriptor = w_desc; + + // Store the master private key, and descriptor + WalletBatch batch(m_storage.GetDatabase()); + if (!AddDescriptorKeyWithDB(batch, master_key.key, + master_key.key.GetPubKey())) { + throw std::runtime_error( + std::string(__func__) + + ": writing descriptor master private key failed"); + } + if (!batch.WriteDescriptor(GetID(), m_wallet_descriptor)) { + throw std::runtime_error(std::string(__func__) + + ": writing descriptor failed"); + } + + // TopUp + TopUp(); + + m_storage.UnsetBlankWalletFlag(batch); + return true; +} + bool DescriptorScriptPubKeyMan::IsHDEnabled() const { LOCK(cs_desc_man); return m_wallet_descriptor.descriptor->IsRange(); diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -862,6 +862,9 @@ assert(NotifyUnload.empty()); } + /* Returns the chain params used by this wallet. */ + const CChainParams &GetChainParams() const override { return chainParams; } + bool IsCrypted() const; bool IsLocked() const override; bool Lock();