diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -41,7 +41,7 @@ extern bool bSpendZeroConfChange; extern bool fSendFreeTransactions; -static const unsigned int DEFAULT_KEYPOOL_SIZE = 100; +static const unsigned int DEFAULT_KEYPOOL_SIZE = 1000; //! -paytxfee default static const Amount DEFAULT_TRANSACTION_FEE(0); //! -fallbackfee default @@ -635,8 +635,8 @@ CHDChain hdChain; /* HD derive new child key (on internal or external chain) */ - void DeriveNewChildKey(CKeyMetadata &metadata, CKey &secret, - bool internal = false); + void DeriveNewChildKey(CWalletDB &walletdb, CKeyMetadata &metadata, + CKey &secret, bool internal = false); std::set setInternalKeyPool; std::set setExternalKeyPool; @@ -791,9 +791,11 @@ * keystore implementation * Generate a new key */ - CPubKey GenerateNewKey(bool internal = false); + 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); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -93,7 +93,7 @@ return &(it->second); } -CPubKey CWallet::GenerateNewKey(bool internal) { +CPubKey CWallet::GenerateNewKey(CWalletDB &walletdb, bool internal) { // mapKeyMetadata AssertLockHeld(cs_wallet); // default to compressed public keys if we want 0.6.0 wallets @@ -108,7 +108,7 @@ // use HD key derivation if HD was enabled during wallet creation if (IsHDEnabled()) { DeriveNewChildKey( - metadata, secret, + walletdb, metadata, secret, (CanSupportFeature(FEATURE_HD_SPLIT) ? internal : false)); } else { secret.MakeNewKey(fCompressed); @@ -125,15 +125,15 @@ 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; } -void CWallet::DeriveNewChildKey(CKeyMetadata &metadata, CKey &secret, - bool internal) { +void CWallet::DeriveNewChildKey(CWalletDB &walletdb, CKeyMetadata &metadata, + CKey &secret, bool internal) { // for now we use a fixed keypath scheme of m/0'/0'/k // master key seed (256bit) CKey key; @@ -191,19 +191,36 @@ secret = childKey.key; metadata.hdMasterKeyID = hdChain.masterKeyID; // update the chain model in the database - if (!CWalletDB(*dbw).WriteHDChain(hdChain)) { + if (!walletdb.WriteHDChain(hdChain)) { 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) { // mapKeyMetadata AssertLockHeld(cs_wallet); + + // 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 = nullptr; + } return false; } + if (needsDB) { + pwalletdbEncryption = nullptr; + } + // Check if we need to remove from watch-only. CScript script; script = GetScriptForDestination(pubkey.GetID()); @@ -220,8 +237,13 @@ return true; } - return CWalletDB(*dbw).WriteKey(pubkey, secret.GetPrivKey(), - mapKeyMetadata[pubkey.GetID()]); + return walletdb.WriteKey(pubkey, secret.GetPrivKey(), + mapKeyMetadata[pubkey.GetID()]); +} + +bool CWallet::AddKeyPubKey(const CKey &secret, const CPubKey &pubkey) { + CWalletDB walletdb(*dbw); + return CWallet::AddKeyPubKeyWithDB(walletdb, secret, pubkey); } bool CWallet::AddCryptedKey(const CPubKey &vchPubKey, @@ -3283,8 +3305,8 @@ nEnd = std::max(nEnd, *(setExternalKeyPool.rbegin()) + 1); } - if (!walletdb.WritePool(nEnd, - CKeyPool(GenerateNewKey(internal), internal))) { + if (!walletdb.WritePool( + nEnd, CKeyPool(GenerateNewKey(walletdb, internal), internal))) { throw std::runtime_error(std::string(__func__) + ": writing generated key failed"); } @@ -3294,10 +3316,13 @@ } else { setExternalKeyPool.insert(nEnd); } + } + if (missingInternal + missingExternal > 0) { LogPrintf( - "keypool added key %d, size=%u (%u internal), new key is %s\n", - nEnd, setInternalKeyPool.size() + setExternalKeyPool.size(), - setInternalKeyPool.size(), internal ? "internal" : "external"); + "keypool added %d keys (%d internal), size=%u (%u internal)\n", + missingInternal + missingExternal, missingInternal, + setInternalKeyPool.size() + setExternalKeyPool.size(), + setInternalKeyPool.size()); } return true; @@ -3368,16 +3393,16 @@ } bool CWallet::GetKeyFromPool(CPubKey &result, bool internal) { - int64_t nIndex = 0; CKeyPool keypool; - LOCK(cs_wallet); + int64_t nIndex = 0; ReserveKeyFromKeyPool(nIndex, keypool, internal); if (nIndex == -1) { if (IsLocked()) { return false; } - result = GenerateNewKey(internal); + CWalletDB walletdb(*dbw); + result = GenerateNewKey(walletdb, internal); return true; }