0
0
Fork 0
mirror of https://github.com/bitcoin/bitcoin.git synced 2025-02-03 09:56:38 -05:00

Box the wallet: Add multiple keyman maps and loops

Add wallet logic for dealing with multiple ScriptPubKeyMan instances. This
doesn't change current behavior because there is still only a single
LegacyScriptPubKeyMan. But in the future the new logic will be used to support
descriptor wallets.
This commit is contained in:
Andrew Chow 2019-10-07 14:11:34 -04:00
parent 4977c30d59
commit c729afd0a3
4 changed files with 177 additions and 44 deletions

View file

@ -470,6 +470,34 @@ int64_t LegacyScriptPubKeyMan::GetTimeFirstKey() const
return nTimeFirstKey; return nTimeFirstKey;
} }
const SigningProvider* LegacyScriptPubKeyMan::GetSigningProvider(const CScript& script) const
{
return this;
}
bool LegacyScriptPubKeyMan::CanProvide(const CScript& script, SignatureData& sigdata)
{
if (IsMine(script) != ISMINE_NO) {
// If it IsMine, we can always provide in some way
return true;
} else if (HaveCScript(CScriptID(script))) {
// We can still provide some stuff if we have the script, but IsMine failed because we don't have keys
return true;
} else {
// If, given the stuff in sigdata, we could make a valid sigature, then we can provide for this script
ProduceSignature(*this, DUMMY_SIGNATURE_CREATOR, script, sigdata);
if (!sigdata.signatures.empty()) {
// If we could make signatures, make sure we have a private key to actually make a signature
bool has_privkeys = false;
for (const auto& key_sig_pair : sigdata.signatures) {
has_privkeys |= HaveKey(key_sig_pair.first);
}
return has_privkeys;
}
return false;
}
}
const CKeyMetadata* LegacyScriptPubKeyMan::GetMetadata(const CTxDestination& dest) const const CKeyMetadata* LegacyScriptPubKeyMan::GetMetadata(const CTxDestination& dest) const
{ {
LOCK(cs_KeyStore); LOCK(cs_KeyStore);
@ -491,6 +519,11 @@ const CKeyMetadata* LegacyScriptPubKeyMan::GetMetadata(const CTxDestination& des
return nullptr; return nullptr;
} }
uint256 LegacyScriptPubKeyMan::GetID() const
{
return UINT256_ONE();
}
/** /**
* Update wallet first key creation time. This should be called whenever keys * Update wallet first key creation time. This should be called whenever keys
* are added to the wallet, with the oldest key creation time. * are added to the wallet, with the oldest key creation time.

View file

@ -196,8 +196,16 @@ public:
virtual int64_t GetTimeFirstKey() const { return 0; } virtual int64_t GetTimeFirstKey() const { return 0; }
//! Return address metadata
virtual const CKeyMetadata* GetMetadata(const CTxDestination& dest) const { return nullptr; } virtual const CKeyMetadata* GetMetadata(const CTxDestination& dest) const { return nullptr; }
virtual const SigningProvider* GetSigningProvider(const CScript& script) const { return nullptr; }
/** Whether this ScriptPubKeyMan can provide a SigningProvider (via GetSigningProvider) that, combined with
* sigdata, can produce a valid signature.
*/
virtual bool CanProvide(const CScript& script, SignatureData& sigdata) { return false; }
virtual uint256 GetID() const { return uint256(); }
}; };
class LegacyScriptPubKeyMan : public ScriptPubKeyMan, public FillableSigningProvider class LegacyScriptPubKeyMan : public ScriptPubKeyMan, public FillableSigningProvider
@ -319,6 +327,12 @@ public:
bool CanGetAddresses(bool internal = false) override; bool CanGetAddresses(bool internal = false) override;
const SigningProvider* GetSigningProvider(const CScript& script) const override;
bool CanProvide(const CScript& script, SignatureData& sigdata) override;
uint256 GetID() const override;
// Map from Key ID to key metadata. // Map from Key ID to key metadata.
std::map<CKeyID, CKeyMetadata> mapKeyMetadata GUARDED_BY(cs_KeyStore); std::map<CKeyID, CKeyMetadata> mapKeyMetadata GUARDED_BY(cs_KeyStore);

View file

@ -220,7 +220,7 @@ WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString&
// Set a seed for the wallet // Set a seed for the wallet
{ {
LOCK(wallet->cs_wallet); LOCK(wallet->cs_wallet);
if (auto spk_man = wallet->m_spk_man.get()) { for (auto spk_man : wallet->GetActiveScriptPubKeyMans()) {
if (!spk_man->SetupGeneration()) { if (!spk_man->SetupGeneration()) {
error = "Unable to generate initial keys"; error = "Unable to generate initial keys";
return WalletCreationStatus::CREATION_FAILED; return WalletCreationStatus::CREATION_FAILED;
@ -551,7 +551,8 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
} }
encrypted_batch->WriteMasterKey(nMasterKeyMaxID, kMasterKey); encrypted_batch->WriteMasterKey(nMasterKeyMaxID, kMasterKey);
if (auto spk_man = m_spk_man.get()) { for (const auto& spk_man_pair : m_spk_managers) {
auto spk_man = spk_man_pair.second.get();
if (!spk_man->Encrypt(_vMasterKey, encrypted_batch)) { if (!spk_man->Encrypt(_vMasterKey, encrypted_batch)) {
encrypted_batch->TxnAbort(); encrypted_batch->TxnAbort();
delete encrypted_batch; delete encrypted_batch;
@ -580,7 +581,7 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
Unlock(strWalletPassphrase); Unlock(strWalletPassphrase);
// if we are using HD, replace the HD seed with a new one // if we are using HD, replace the HD seed with a new one
if (auto spk_man = m_spk_man.get()) { if (auto spk_man = GetLegacyScriptPubKeyMan()) {
if (spk_man->IsHDEnabled()) { if (spk_man->IsHDEnabled()) {
if (!spk_man->SetupGeneration(true)) { if (!spk_man->SetupGeneration(true)) {
return false; return false;
@ -925,8 +926,8 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, CWalletTx::Co
// loop though all outputs // loop though all outputs
for (const CTxOut& txout: tx.vout) { for (const CTxOut& txout: tx.vout) {
if (auto spk_man = m_spk_man.get()) { for (const auto& spk_man_pair : m_spk_managers) {
spk_man->MarkUnusedAddresses(txout.scriptPubKey); spk_man_pair.second->MarkUnusedAddresses(txout.scriptPubKey);
} }
} }
@ -1197,8 +1198,8 @@ isminetype CWallet::IsMine(const CTxDestination& dest) const
isminetype CWallet::IsMine(const CScript& script) const isminetype CWallet::IsMine(const CScript& script) const
{ {
isminetype result = ISMINE_NO; isminetype result = ISMINE_NO;
if (auto spk_man = m_spk_man.get()) { for (const auto& spk_man_pair : m_spk_managers) {
result = spk_man->IsMine(script); result = std::max(result, spk_man_pair.second->IsMine(script));
} }
return result; return result;
} }
@ -1317,8 +1318,8 @@ CAmount CWallet::GetChange(const CTransaction& tx) const
bool CWallet::IsHDEnabled() const bool CWallet::IsHDEnabled() const
{ {
bool result = true; bool result = true;
if (auto spk_man = m_spk_man.get()) { for (const auto& spk_man_pair : m_spk_managers) {
result &= spk_man->IsHDEnabled(); result &= spk_man_pair.second->IsHDEnabled();
} }
return result; return result;
} }
@ -1326,8 +1327,9 @@ bool CWallet::IsHDEnabled() const
bool CWallet::CanGetAddresses(bool internal) bool CWallet::CanGetAddresses(bool internal)
{ {
LOCK(cs_wallet); LOCK(cs_wallet);
{ if (m_spk_managers.empty()) return false;
auto spk_man = m_spk_man.get(); for (OutputType t : OUTPUT_TYPES) {
auto spk_man = GetScriptPubKeyMan(t, internal);
if (spk_man && spk_man->CanGetAddresses(internal)) { if (spk_man && spk_man->CanGetAddresses(internal)) {
return true; return true;
} }
@ -2990,16 +2992,17 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
{ {
if (database->Rewrite("\x04pool")) if (database->Rewrite("\x04pool"))
{ {
if (auto spk_man = m_spk_man.get()) { for (const auto& spk_man_pair : m_spk_managers) {
spk_man->RewriteDB(); spk_man_pair.second->RewriteDB();
} }
} }
} }
// This wallet is in its first run if there are no ScriptPubKeyMans and it isn't blank or no privkeys // This wallet is in its first run if there are no ScriptPubKeyMans and it isn't blank or no privkeys
{ fFirstRunRet = m_spk_managers.empty() && !IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && !IsWalletFlagSet(WALLET_FLAG_BLANK_WALLET);
fFirstRunRet = !m_spk_man if (fFirstRunRet) {
&& !IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && !IsWalletFlagSet(WALLET_FLAG_BLANK_WALLET); assert(m_external_spk_managers.empty());
assert(m_internal_spk_managers.empty());
} }
if (nLoadWalletRet != DBErrors::LOAD_OK) if (nLoadWalletRet != DBErrors::LOAD_OK)
@ -3023,8 +3026,8 @@ DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256
{ {
if (database->Rewrite("\x04pool")) if (database->Rewrite("\x04pool"))
{ {
if (auto spk_man = m_spk_man.get()) { for (const auto& spk_man_pair : m_spk_managers) {
spk_man->RewriteDB(); spk_man_pair.second->RewriteDB();
} }
} }
} }
@ -3044,8 +3047,8 @@ DBErrors CWallet::ZapWalletTx(std::vector<CWalletTx>& vWtx)
{ {
if (database->Rewrite("\x04pool")) if (database->Rewrite("\x04pool"))
{ {
if (auto spk_man = m_spk_man.get()) { for (const auto& spk_man_pair : m_spk_managers) {
spk_man->RewriteDB(); spk_man_pair.second->RewriteDB();
} }
} }
} }
@ -3105,7 +3108,7 @@ size_t CWallet::KeypoolCountExternalKeys()
AssertLockHeld(cs_wallet); AssertLockHeld(cs_wallet);
unsigned int count = 0; unsigned int count = 0;
if (auto spk_man = m_spk_man.get()) { for (auto spk_man : GetActiveScriptPubKeyMans()) {
count += spk_man->KeypoolCountExternalKeys(); count += spk_man->KeypoolCountExternalKeys();
} }
@ -3117,7 +3120,7 @@ unsigned int CWallet::GetKeyPoolSize() const
AssertLockHeld(cs_wallet); AssertLockHeld(cs_wallet);
unsigned int count = 0; unsigned int count = 0;
if (auto spk_man = m_spk_man.get()) { for (auto spk_man : GetActiveScriptPubKeyMans()) {
count += spk_man->GetKeyPoolSize(); count += spk_man->GetKeyPoolSize();
} }
return count; return count;
@ -3127,7 +3130,7 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize)
{ {
LOCK(cs_wallet); LOCK(cs_wallet);
bool res = true; bool res = true;
if (auto spk_man = m_spk_man.get()) { for (auto spk_man : GetActiveScriptPubKeyMans()) {
res &= spk_man->TopUp(kpSize); res &= spk_man->TopUp(kpSize);
} }
return res; return res;
@ -3138,7 +3141,7 @@ bool CWallet::GetNewDestination(const OutputType type, const std::string label,
LOCK(cs_wallet); LOCK(cs_wallet);
error.clear(); error.clear();
bool result = false; bool result = false;
auto spk_man = m_spk_man.get(); auto spk_man = GetScriptPubKeyMan(type, false /* internal */);
if (spk_man) { if (spk_man) {
spk_man->TopUp(); spk_man->TopUp();
result = spk_man->GetNewDestination(type, dest, error); result = spk_man->GetNewDestination(type, dest, error);
@ -3169,8 +3172,8 @@ int64_t CWallet::GetOldestKeyPoolTime()
{ {
LOCK(cs_wallet); LOCK(cs_wallet);
int64_t oldestKey = std::numeric_limits<int64_t>::max(); int64_t oldestKey = std::numeric_limits<int64_t>::max();
if (auto spk_man = m_spk_man.get()) { for (const auto& spk_man_pair : m_spk_managers) {
oldestKey = spk_man->GetOldestKeyPoolTime(); oldestKey = std::min(oldestKey, spk_man_pair.second->GetOldestKeyPoolTime());
} }
return oldestKey; return oldestKey;
} }
@ -3339,7 +3342,7 @@ std::set<CTxDestination> CWallet::GetLabelAddresses(const std::string& label) co
bool ReserveDestination::GetReservedDestination(CTxDestination& dest, bool internal) bool ReserveDestination::GetReservedDestination(CTxDestination& dest, bool internal)
{ {
m_spk_man = pwallet->GetLegacyScriptPubKeyMan(); m_spk_man = pwallet->GetScriptPubKeyMan(type, internal);
if (!m_spk_man) { if (!m_spk_man) {
return false; return false;
} }
@ -3716,7 +3719,7 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
return nullptr; return nullptr;
} }
if (auto spk_man = walletInstance->m_spk_man.get()) { for (auto spk_man : walletInstance->GetActiveScriptPubKeyMans()) {
if (!spk_man->Upgrade(prev_version, error)) { if (!spk_man->Upgrade(prev_version, error)) {
return nullptr; return nullptr;
} }
@ -3735,7 +3738,7 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
if (!(wallet_creation_flags & (WALLET_FLAG_DISABLE_PRIVATE_KEYS | WALLET_FLAG_BLANK_WALLET))) { if (!(wallet_creation_flags & (WALLET_FLAG_DISABLE_PRIVATE_KEYS | WALLET_FLAG_BLANK_WALLET))) {
LOCK(walletInstance->cs_wallet); LOCK(walletInstance->cs_wallet);
if (auto spk_man = walletInstance->m_spk_man.get()) { for (auto spk_man : walletInstance->GetActiveScriptPubKeyMans()) {
if (!spk_man->SetupGeneration()) { if (!spk_man->SetupGeneration()) {
error = _("Unable to generate initial keys").translated; error = _("Unable to generate initial keys").translated;
return nullptr; return nullptr;
@ -3750,9 +3753,10 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
error = strprintf(_("Error loading %s: Private keys can only be disabled during creation").translated, walletFile); error = strprintf(_("Error loading %s: Private keys can only be disabled during creation").translated, walletFile);
return NULL; return NULL;
} else if (walletInstance->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { } else if (walletInstance->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
if (walletInstance->m_spk_man) { for (auto spk_man : walletInstance->GetActiveScriptPubKeyMans()) {
if (walletInstance->m_spk_man->HavePrivateKeys()) { if (spk_man->HavePrivateKeys()) {
warnings.push_back(strprintf(_("Warning: Private keys detected in wallet {%s} with disabled private keys").translated, walletFile)); warnings.push_back(strprintf(_("Warning: Private keys detected in wallet {%s} with disabled private keys").translated, walletFile));
break;
} }
} }
} }
@ -3906,7 +3910,7 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
// No need to read and scan block if block was created before // No need to read and scan block if block was created before
// our wallet birthday (as adjusted for block time variability) // our wallet birthday (as adjusted for block time variability)
Optional<int64_t> time_first_key; Optional<int64_t> time_first_key;
if (auto spk_man = walletInstance->m_spk_man.get()) { for (auto spk_man : walletInstance->GetAllScriptPubKeyMans()) {
int64_t time = spk_man->GetTimeFirstKey(); int64_t time = spk_man->GetTimeFirstKey();
if (!time_first_key || time < *time_first_key) time_first_key = time; if (!time_first_key || time < *time_first_key) time_first_key = time;
} }
@ -4096,8 +4100,8 @@ bool CWallet::Unlock(const CKeyingMaterial& vMasterKeyIn, bool accept_no_keys)
{ {
{ {
LOCK(cs_wallet); LOCK(cs_wallet);
if (m_spk_man) { for (const auto& spk_man_pair : m_spk_managers) {
if (!m_spk_man->CheckDecryptionKey(vMasterKeyIn, accept_no_keys)) { if (!spk_man_pair.second->CheckDecryptionKey(vMasterKeyIn, accept_no_keys)) {
return false; return false;
} }
} }
@ -4107,24 +4111,82 @@ bool CWallet::Unlock(const CKeyingMaterial& vMasterKeyIn, bool accept_no_keys)
return true; return true;
} }
std::set<ScriptPubKeyMan*> CWallet::GetActiveScriptPubKeyMans() const
{
std::set<ScriptPubKeyMan*> spk_mans;
for (bool internal : {false, true}) {
for (OutputType t : OUTPUT_TYPES) {
auto spk_man = GetScriptPubKeyMan(t, internal);
if (spk_man) {
spk_mans.insert(spk_man);
}
}
}
return spk_mans;
}
std::set<ScriptPubKeyMan*> CWallet::GetAllScriptPubKeyMans() const
{
std::set<ScriptPubKeyMan*> spk_mans;
for (const auto& spk_man_pair : m_spk_managers) {
spk_mans.insert(spk_man_pair.second.get());
}
return spk_mans;
}
ScriptPubKeyMan* CWallet::GetScriptPubKeyMan(const OutputType& type, bool internal) const
{
const std::map<OutputType, ScriptPubKeyMan*>& spk_managers = internal ? m_internal_spk_managers : m_external_spk_managers;
std::map<OutputType, ScriptPubKeyMan*>::const_iterator it = spk_managers.find(type);
if (it == spk_managers.end()) {
WalletLogPrintf("%s scriptPubKey Manager for output type %d does not exist\n", internal ? "Internal" : "External", static_cast<int>(type));
return nullptr;
}
return it->second;
}
ScriptPubKeyMan* CWallet::GetScriptPubKeyMan(const CScript& script) const ScriptPubKeyMan* CWallet::GetScriptPubKeyMan(const CScript& script) const
{ {
return m_spk_man.get(); SignatureData sigdata;
for (const auto& spk_man_pair : m_spk_managers) {
if (spk_man_pair.second->CanProvide(script, sigdata)) {
return spk_man_pair.second.get();
}
}
return nullptr;
}
ScriptPubKeyMan* CWallet::GetScriptPubKeyMan(const uint256& id) const
{
if (m_spk_managers.count(id) > 0) {
return m_spk_managers.at(id).get();
}
return nullptr;
} }
const SigningProvider* CWallet::GetSigningProvider(const CScript& script) const const SigningProvider* CWallet::GetSigningProvider(const CScript& script) const
{ {
return m_spk_man.get(); SignatureData sigdata;
return GetSigningProvider(script, sigdata);
} }
const SigningProvider* CWallet::GetSigningProvider(const CScript& script, SignatureData& sigdata) const const SigningProvider* CWallet::GetSigningProvider(const CScript& script, SignatureData& sigdata) const
{ {
return m_spk_man.get(); for (const auto& spk_man_pair : m_spk_managers) {
if (spk_man_pair.second->CanProvide(script, sigdata)) {
return spk_man_pair.second->GetSigningProvider(script);
}
}
return nullptr;
} }
LegacyScriptPubKeyMan* CWallet::GetLegacyScriptPubKeyMan() const LegacyScriptPubKeyMan* CWallet::GetLegacyScriptPubKeyMan() const
{ {
return m_spk_man.get(); // Legacy wallets only have one ScriptPubKeyMan which is a LegacyScriptPubKeyMan.
// Everything in m_internal_spk_managers and m_external_spk_managers point to the same legacyScriptPubKeyMan.
auto it = m_internal_spk_managers.find(OutputType::LEGACY);
if (it == m_internal_spk_managers.end()) return nullptr;
return dynamic_cast<LegacyScriptPubKeyMan*>(it->second);
} }
LegacyScriptPubKeyMan* CWallet::GetOrCreateLegacyScriptPubKeyMan() LegacyScriptPubKeyMan* CWallet::GetOrCreateLegacyScriptPubKeyMan()
@ -4135,7 +4197,16 @@ LegacyScriptPubKeyMan* CWallet::GetOrCreateLegacyScriptPubKeyMan()
void CWallet::SetupLegacyScriptPubKeyMan() void CWallet::SetupLegacyScriptPubKeyMan()
{ {
if (!m_spk_man) m_spk_man = MakeUnique<LegacyScriptPubKeyMan>(*this); if (!m_internal_spk_managers.empty() || !m_external_spk_managers.empty() || !m_spk_managers.empty()) {
return;
}
auto spk_manager = std::unique_ptr<ScriptPubKeyMan>(new LegacyScriptPubKeyMan(*this));
for (const auto& type : OUTPUT_TYPES) {
m_internal_spk_managers[type] = spk_manager.get();
m_external_spk_managers[type] = spk_manager.get();
}
m_spk_managers[spk_manager->GetID()] = std::move(spk_manager);
} }
const CKeyingMaterial& CWallet::GetEncryptionKey() const const CKeyingMaterial& CWallet::GetEncryptionKey() const

View file

@ -702,6 +702,13 @@ private:
*/ */
int m_last_block_processed_height GUARDED_BY(cs_wallet) = -1; int m_last_block_processed_height GUARDED_BY(cs_wallet) = -1;
std::map<OutputType, ScriptPubKeyMan*> m_external_spk_managers;
std::map<OutputType, ScriptPubKeyMan*> m_internal_spk_managers;
// Indexed by a unique identifier produced by each ScriptPubKeyMan using
// ScriptPubKeyMan::GetID. In many cases it will be the hash of an internal structure
std::map<uint256, std::unique_ptr<ScriptPubKeyMan>> m_spk_managers;
public: public:
/* /*
* Main wallet lock. * Main wallet lock.
@ -1132,13 +1139,25 @@ public:
LogPrintf(("%s " + fmt).c_str(), GetDisplayName(), parameters...); LogPrintf(("%s " + fmt).c_str(), GetDisplayName(), parameters...);
}; };
//! Returns all unique ScriptPubKeyMans in m_internal_spk_managers and m_external_spk_managers
std::set<ScriptPubKeyMan*> GetActiveScriptPubKeyMans() const;
//! Returns all unique ScriptPubKeyMans
std::set<ScriptPubKeyMan*> GetAllScriptPubKeyMans() const;
//! Get the ScriptPubKeyMan for the given OutputType and internal/external chain.
ScriptPubKeyMan* GetScriptPubKeyMan(const OutputType& type, bool internal) const;
//! Get the ScriptPubKeyMan for a script //! Get the ScriptPubKeyMan for a script
ScriptPubKeyMan* GetScriptPubKeyMan(const CScript& script) const; ScriptPubKeyMan* GetScriptPubKeyMan(const CScript& script) const;
//! Get the ScriptPubKeyMan by id
ScriptPubKeyMan* GetScriptPubKeyMan(const uint256& id) const;
//! Get the SigningProvider for a script //! Get the SigningProvider for a script
const SigningProvider* GetSigningProvider(const CScript& script) const; const SigningProvider* GetSigningProvider(const CScript& script) const;
const SigningProvider* GetSigningProvider(const CScript& script, SignatureData& sigdata) const; const SigningProvider* GetSigningProvider(const CScript& script, SignatureData& sigdata) const;
//! Get the LegacyScriptPubKeyMan which is used for all types, internal, and external.
LegacyScriptPubKeyMan* GetLegacyScriptPubKeyMan() const; LegacyScriptPubKeyMan* GetLegacyScriptPubKeyMan() const;
LegacyScriptPubKeyMan* GetOrCreateLegacyScriptPubKeyMan(); LegacyScriptPubKeyMan* GetOrCreateLegacyScriptPubKeyMan();
@ -1148,10 +1167,6 @@ public:
const CKeyingMaterial& GetEncryptionKey() const override; const CKeyingMaterial& GetEncryptionKey() const override;
bool HasEncryptionKeys() const override; bool HasEncryptionKeys() const override;
// Temporary LegacyScriptPubKeyMan accessors and aliases.
friend class LegacyScriptPubKeyMan;
std::unique_ptr<LegacyScriptPubKeyMan> m_spk_man;
/** Get last block processed height */ /** Get last block processed height */
int GetLastBlockHeight() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) int GetLastBlockHeight() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
{ {