Skip to content

Commit 0b01935

Browse files
committed
Merge #10831: Batch flushing operations to the walletdb during top up and increase keypool size.
b0e8e2d Print one log message per keypool top-up, not one per key. (Gregory Maxwell) 41dc163 Increase wallet default keypool size to 1000. (Gregory Maxwell) 30d8f3a Pushdown walletdb though CWallet::AddKeyPubKey to avoid flushes. (Gregory Maxwell) 3a53f19 Pushdown walletdb object through GenerateNewKey/DeriveNewChildKey. (Gregory Maxwell) Pull request description: This carries the walletdb object from top-up through GenerateNewKey/DeriveNewChildKey/CWallet::AddKeyPubKey, which allows us to avoid the flush on destruction until the top up finishes instead of flushing the wallet for every key. This speeds up adding keys by well over 10x on my laptop (actually something like 17x), I wouldn't be surprised if it were an even bigger speedup on spinning rust. Then it increases the keypool size to 1000. I would have preferred to use 10,000 but in the case where the user creates a new wallet and then turns on encryption it seems kind of dumb to have >400KB of marked-used born unencrypted keys just laying around. (Thanks to Matt for cluesticking me on how to bypass the crypter spaghetti) Tree-SHA512: 868303de38fce4c3f67d7fe133f765f15435c94b39d252d7450b5fee5c607a3cc2f5e531861a69d8c8877bf130e0ff4c539f97500a6bc0ff6d67e4a42c9385c7
2 parents 89bb036 + b0e8e2d commit 0b01935

File tree

2 files changed

+43
-17
lines changed

2 files changed

+43
-17
lines changed

src/wallet/wallet.cpp

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const
8787
return &(it->second);
8888
}
8989

90-
CPubKey CWallet::GenerateNewKey(bool internal)
90+
CPubKey CWallet::GenerateNewKey(CWalletDB &walletdb, bool internal)
9191
{
9292
AssertLockHeld(cs_wallet); // mapKeyMetadata
9393
bool fCompressed = CanSupportFeature(FEATURE_COMPRPUBKEY); // default to compressed public keys if we want 0.6.0 wallets
@@ -100,27 +100,29 @@ CPubKey CWallet::GenerateNewKey(bool internal)
100100

101101
// use HD key derivation if HD was enabled during wallet creation
102102
if (IsHDEnabled()) {
103-
DeriveNewChildKey(metadata, secret, (CanSupportFeature(FEATURE_HD_SPLIT) ? internal : false));
103+
DeriveNewChildKey(walletdb, metadata, secret, (CanSupportFeature(FEATURE_HD_SPLIT) ? internal : false));
104104
} else {
105105
secret.MakeNewKey(fCompressed);
106106
}
107107

108108
// Compressed public keys were introduced in version 0.6.0
109-
if (fCompressed)
109+
if (fCompressed) {
110110
SetMinVersion(FEATURE_COMPRPUBKEY);
111+
}
111112

112113
CPubKey pubkey = secret.GetPubKey();
113114
assert(secret.VerifyPubKey(pubkey));
114115

115116
mapKeyMetadata[pubkey.GetID()] = metadata;
116117
UpdateTimeFirstKey(nCreationTime);
117118

118-
if (!AddKeyPubKey(secret, pubkey))
119+
if (!AddKeyPubKeyWithDB(walletdb, secret, pubkey)) {
119120
throw std::runtime_error(std::string(__func__) + ": AddKey failed");
121+
}
120122
return pubkey;
121123
}
122124

123-
void CWallet::DeriveNewChildKey(CKeyMetadata& metadata, CKey& secret, bool internal)
125+
void CWallet::DeriveNewChildKey(CWalletDB &walletdb, CKeyMetadata& metadata, CKey& secret, bool internal)
124126
{
125127
// for now we use a fixed keypath scheme of m/0'/0'/k
126128
CKey key; //master key seed (256bit)
@@ -162,33 +164,52 @@ void CWallet::DeriveNewChildKey(CKeyMetadata& metadata, CKey& secret, bool inter
162164
secret = childKey.key;
163165
metadata.hdMasterKeyID = hdChain.masterKeyID;
164166
// update the chain model in the database
165-
if (!CWalletDB(*dbw).WriteHDChain(hdChain))
167+
if (!walletdb.WriteHDChain(hdChain))
166168
throw std::runtime_error(std::string(__func__) + ": Writing HD chain model failed");
167169
}
168170

169-
bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey)
171+
bool CWallet::AddKeyPubKeyWithDB(CWalletDB &walletdb, const CKey& secret, const CPubKey &pubkey)
170172
{
171173
AssertLockHeld(cs_wallet); // mapKeyMetadata
172-
if (!CCryptoKeyStore::AddKeyPubKey(secret, pubkey))
174+
175+
// CCryptoKeyStore has no concept of wallet databases, but calls AddCryptedKey
176+
// which is overridden below. To avoid flushes, the database handle is
177+
// tunneled through to it.
178+
bool needsDB = !pwalletdbEncryption;
179+
if (needsDB) {
180+
pwalletdbEncryption = &walletdb;
181+
}
182+
if (!CCryptoKeyStore::AddKeyPubKey(secret, pubkey)) {
183+
if (needsDB) pwalletdbEncryption = NULL;
173184
return false;
185+
}
186+
if (needsDB) pwalletdbEncryption = NULL;
174187

175188
// check if we need to remove from watch-only
176189
CScript script;
177190
script = GetScriptForDestination(pubkey.GetID());
178-
if (HaveWatchOnly(script))
191+
if (HaveWatchOnly(script)) {
179192
RemoveWatchOnly(script);
193+
}
180194
script = GetScriptForRawPubKey(pubkey);
181-
if (HaveWatchOnly(script))
195+
if (HaveWatchOnly(script)) {
182196
RemoveWatchOnly(script);
197+
}
183198

184199
if (!IsCrypted()) {
185-
return CWalletDB(*dbw).WriteKey(pubkey,
200+
return walletdb.WriteKey(pubkey,
186201
secret.GetPrivKey(),
187202
mapKeyMetadata[pubkey.GetID()]);
188203
}
189204
return true;
190205
}
191206

207+
bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey)
208+
{
209+
CWalletDB walletdb(*dbw);
210+
return CWallet::AddKeyPubKeyWithDB(walletdb, secret, pubkey);
211+
}
212+
192213
bool CWallet::AddCryptedKey(const CPubKey &vchPubKey,
193214
const std::vector<unsigned char> &vchCryptedSecret)
194215
{
@@ -3197,15 +3218,18 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize)
31973218
nEnd = std::max(nEnd, *(setExternalKeyPool.rbegin()) + 1);
31983219
}
31993220

3200-
if (!walletdb.WritePool(nEnd, CKeyPool(GenerateNewKey(internal), internal)))
3221+
if (!walletdb.WritePool(nEnd, CKeyPool(GenerateNewKey(walletdb, internal), internal))) {
32013222
throw std::runtime_error(std::string(__func__) + ": writing generated key failed");
3223+
}
32023224

32033225
if (internal) {
32043226
setInternalKeyPool.insert(nEnd);
32053227
} else {
32063228
setExternalKeyPool.insert(nEnd);
32073229
}
3208-
LogPrintf("keypool added key %d, size=%u (%u internal), new key is %s\n", nEnd, setInternalKeyPool.size() + setExternalKeyPool.size(), setInternalKeyPool.size(), internal ? "internal" : "external");
3230+
}
3231+
if (missingInternal + missingExternal > 0) {
3232+
LogPrintf("keypool added %d keys (%d internal), size=%u (%u internal)\n", missingInternal + missingExternal, missingInternal, setInternalKeyPool.size() + setExternalKeyPool.size(), setInternalKeyPool.size());
32093233
}
32103234
}
32113235
return true;
@@ -3280,7 +3304,8 @@ bool CWallet::GetKeyFromPool(CPubKey& result, bool internal)
32803304
if (nIndex == -1)
32813305
{
32823306
if (IsLocked()) return false;
3283-
result = GenerateNewKey(internal);
3307+
CWalletDB walletdb(*dbw);
3308+
result = GenerateNewKey(walletdb, internal);
32843309
return true;
32853310
}
32863311
KeepKey(nIndex);

src/wallet/wallet.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ extern unsigned int nTxConfirmTarget;
4040
extern bool bSpendZeroConfChange;
4141
extern bool fWalletRbf;
4242

43-
static const unsigned int DEFAULT_KEYPOOL_SIZE = 100;
43+
static const unsigned int DEFAULT_KEYPOOL_SIZE = 1000;
4444
//! -paytxfee default
4545
static const CAmount DEFAULT_TRANSACTION_FEE = 0;
4646
//! -fallbackfee default
@@ -697,7 +697,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface
697697
CHDChain hdChain;
698698

699699
/* HD derive new child key (on internal or external chain) */
700-
void DeriveNewChildKey(CKeyMetadata& metadata, CKey& secret, bool internal = false);
700+
void DeriveNewChildKey(CWalletDB &walletdb, CKeyMetadata& metadata, CKey& secret, bool internal = false);
701701

702702
std::set<int64_t> setInternalKeyPool;
703703
std::set<int64_t> setExternalKeyPool;
@@ -866,9 +866,10 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface
866866
* keystore implementation
867867
* Generate a new key
868868
*/
869-
CPubKey GenerateNewKey(bool internal = false);
869+
CPubKey GenerateNewKey(CWalletDB& walletdb, bool internal = false);
870870
//! Adds a key to the store, and saves it to disk.
871871
bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey) override;
872+
bool AddKeyPubKeyWithDB(CWalletDB &walletdb,const CKey& key, const CPubKey &pubkey);
872873
//! Adds a key to the store, without saving it to disk (used by LoadWallet)
873874
bool LoadKey(const CKey& key, const CPubKey &pubkey) { return CCryptoKeyStore::AddKeyPubKey(key, pubkey); }
874875
//! Load metadata (used by LoadWallet)

0 commit comments

Comments
 (0)