From 30d8f3a18e7d927459e409a38ee1c0d1ddf054ad Mon Sep 17 00:00:00 2001 From: Gregory Maxwell Date: Sat, 15 Jul 2017 01:00:30 +0000 Subject: [PATCH] Pushdown walletdb though CWallet::AddKeyPubKey to avoid flushes. This prevents the wallet from being flushed between each and every key during top-up. This results in a >10x speed-up for the top-up. --- src/wallet/wallet.cpp | 35 ++++++++++++++++++++++++++++------- src/wallet/wallet.h | 1 + 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index b3b3c1c10a..d8c1dd94fc 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -106,8 +106,9 @@ CPubKey CWallet::GenerateNewKey(CWalletDB &walletdb, bool internal) } // Compressed public keys were introduced in version 0.6.0 - if (fCompressed) + if (fCompressed) { SetMinVersion(FEATURE_COMPRPUBKEY); + } CPubKey pubkey = secret.GetPubKey(); assert(secret.VerifyPubKey(pubkey)); @@ -115,8 +116,9 @@ CPubKey CWallet::GenerateNewKey(CWalletDB &walletdb, bool internal) mapKeyMetadata[pubkey.GetID()] = metadata; UpdateTimeFirstKey(nCreationTime); - if (!AddKeyPubKey(secret, pubkey)) + if (!AddKeyPubKeyWithDB(walletdb, secret, pubkey)) { throw std::runtime_error(std::string(__func__) + ": AddKey failed"); + } return pubkey; } @@ -166,29 +168,48 @@ void CWallet::DeriveNewChildKey(CWalletDB &walletdb, CKeyMetadata& metadata, CKe throw std::runtime_error(std::string(__func__) + ": Writing HD chain model failed"); } -bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey) +bool CWallet::AddKeyPubKeyWithDB(CWalletDB &walletdb, const CKey& secret, const CPubKey &pubkey) { AssertLockHeld(cs_wallet); // mapKeyMetadata - if (!CCryptoKeyStore::AddKeyPubKey(secret, pubkey)) + + // CCryptoKeyStore has no concept of wallet databases, but calls AddCryptedKey + // which is overridden below. To avoid flushes, the database handle is + // tunneled through to it. + bool needsDB = !pwalletdbEncryption; + if (needsDB) { + pwalletdbEncryption = &walletdb; + } + if (!CCryptoKeyStore::AddKeyPubKey(secret, pubkey)) { + if (needsDB) pwalletdbEncryption = NULL; return false; + } + if (needsDB) pwalletdbEncryption = NULL; // check if we need to remove from watch-only CScript script; script = GetScriptForDestination(pubkey.GetID()); - if (HaveWatchOnly(script)) + if (HaveWatchOnly(script)) { RemoveWatchOnly(script); + } script = GetScriptForRawPubKey(pubkey); - if (HaveWatchOnly(script)) + if (HaveWatchOnly(script)) { RemoveWatchOnly(script); + } if (!IsCrypted()) { - return CWalletDB(*dbw).WriteKey(pubkey, + return walletdb.WriteKey(pubkey, secret.GetPrivKey(), mapKeyMetadata[pubkey.GetID()]); } return true; } +bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey) +{ + CWalletDB walletdb(*dbw); + return CWallet::AddKeyPubKeyWithDB(walletdb, secret, pubkey); +} + bool CWallet::AddCryptedKey(const CPubKey &vchPubKey, const std::vector &vchCryptedSecret) { diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index e91a6effd3..0bf6ccf722 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -869,6 +869,7 @@ public: CPubKey GenerateNewKey(CWalletDB& walletdb, bool internal = false); //! Adds a key to the store, and saves it to disk. bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey) override; + bool AddKeyPubKeyWithDB(CWalletDB &walletdb,const CKey& key, const CPubKey &pubkey); //! Adds a key to the store, without saving it to disk (used by LoadWallet) bool LoadKey(const CKey& key, const CPubKey &pubkey) { return CCryptoKeyStore::AddKeyPubKey(key, pubkey); } //! Load metadata (used by LoadWallet)