@@ -2977,7 +2977,8 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
2977
2977
if (dbw->Rewrite (" \x04 pool" ))
2978
2978
{
2979
2979
LOCK (cs_wallet);
2980
- setKeyPool.clear ();
2980
+ setInternalKeyPool.clear ();
2981
+ setExternalKeyPool.clear ();
2981
2982
// Note: can't top-up keypool here, because wallet is locked.
2982
2983
// User will be prompted to unlock wallet the next operation
2983
2984
// that requires a new key.
@@ -3005,7 +3006,8 @@ DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256
3005
3006
{
3006
3007
if (dbw->Rewrite (" \x04 pool" ))
3007
3008
{
3008
- setKeyPool.clear ();
3009
+ setInternalKeyPool.clear ();
3010
+ setExternalKeyPool.clear ();
3009
3011
// Note: can't top-up keypool here, because wallet is locked.
3010
3012
// User will be prompted to unlock wallet the next operation
3011
3013
// that requires a new key.
@@ -3030,7 +3032,8 @@ DBErrors CWallet::ZapWalletTx(std::vector<CWalletTx>& vWtx)
3030
3032
if (dbw->Rewrite (" \x04 pool" ))
3031
3033
{
3032
3034
LOCK (cs_wallet);
3033
- setKeyPool.clear ();
3035
+ setInternalKeyPool.clear ();
3036
+ setExternalKeyPool.clear ();
3034
3037
// Note: can't top-up keypool here, because wallet is locked.
3035
3038
// User will be prompted to unlock wallet the next operation
3036
3039
// that requires a new key.
@@ -3114,9 +3117,16 @@ bool CWallet::NewKeyPool()
3114
3117
{
3115
3118
LOCK (cs_wallet);
3116
3119
CWalletDB walletdb (*dbw);
3117
- for (int64_t nIndex : setKeyPool)
3120
+
3121
+ for (int64_t nIndex : setInternalKeyPool) {
3122
+ walletdb.ErasePool (nIndex);
3123
+ }
3124
+ setInternalKeyPool.clear ();
3125
+
3126
+ for (int64_t nIndex : setExternalKeyPool) {
3118
3127
walletdb.ErasePool (nIndex);
3119
- setKeyPool.clear ();
3128
+ }
3129
+ setExternalKeyPool.clear ();
3120
3130
3121
3131
if (!TopUpKeyPool ()) {
3122
3132
return false ;
@@ -3128,25 +3138,8 @@ bool CWallet::NewKeyPool()
3128
3138
3129
3139
size_t CWallet::KeypoolCountExternalKeys ()
3130
3140
{
3131
- AssertLockHeld (cs_wallet); // setKeyPool
3132
-
3133
- // immediately return setKeyPool's size if HD or HD_SPLIT is disabled or not supported
3134
- if (!IsHDEnabled () || !CanSupportFeature (FEATURE_HD_SPLIT))
3135
- return setKeyPool.size ();
3136
-
3137
- CWalletDB walletdb (*dbw);
3138
-
3139
- // count amount of external keys
3140
- size_t amountE = 0 ;
3141
- for (const int64_t & id : setKeyPool)
3142
- {
3143
- CKeyPool tmpKeypool;
3144
- if (!walletdb.ReadPool (id, tmpKeypool))
3145
- throw std::runtime_error (std::string (__func__) + " : read failed" );
3146
- amountE += !tmpKeypool.fInternal ;
3147
- }
3148
-
3149
- return amountE;
3141
+ AssertLockHeld (cs_wallet); // setExternalKeyPool
3142
+ return setExternalKeyPool.size ();
3150
3143
}
3151
3144
3152
3145
bool CWallet::TopUpKeyPool (unsigned int kpSize)
@@ -3166,10 +3159,8 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize)
3166
3159
3167
3160
// count amount of available keys (internal, external)
3168
3161
// make sure the keypool of external and internal keys fits the user selected target (-keypool)
3169
- int64_t amountExternal = KeypoolCountExternalKeys ();
3170
- int64_t amountInternal = setKeyPool.size () - amountExternal;
3171
- int64_t missingExternal = std::max (std::max ((int64_t ) nTargetSize, (int64_t ) 1 ) - amountExternal, (int64_t ) 0 );
3172
- int64_t missingInternal = std::max (std::max ((int64_t ) nTargetSize, (int64_t ) 1 ) - amountInternal, (int64_t ) 0 );
3162
+ int64_t missingExternal = std::max (std::max ((int64_t ) nTargetSize, (int64_t ) 1 ) - (int64_t )setExternalKeyPool.size (), (int64_t ) 0 );
3163
+ int64_t missingInternal = std::max (std::max ((int64_t ) nTargetSize, (int64_t ) 1 ) - (int64_t )setInternalKeyPool.size (), (int64_t ) 0 );
3173
3164
3174
3165
if (!IsHDEnabled () || !CanSupportFeature (FEATURE_HD_SPLIT))
3175
3166
{
@@ -3181,20 +3172,32 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize)
3181
3172
for (int64_t i = missingInternal + missingExternal; i--;)
3182
3173
{
3183
3174
int64_t nEnd = 1 ;
3184
- if (i < missingInternal)
3175
+ if (i < missingInternal) {
3185
3176
internal = true ;
3186
- if (!setKeyPool.empty ())
3187
- nEnd = *(--setKeyPool.end ()) + 1 ;
3177
+ }
3178
+
3179
+ if (!setInternalKeyPool.empty ()) {
3180
+ nEnd = *(setInternalKeyPool.rbegin ()) + 1 ;
3181
+ }
3182
+ if (!setExternalKeyPool.empty ()) {
3183
+ nEnd = std::max (nEnd, *(setExternalKeyPool.rbegin ()) + 1 );
3184
+ }
3185
+
3188
3186
if (!walletdb.WritePool (nEnd, CKeyPool (GenerateNewKey (internal), internal)))
3189
3187
throw std::runtime_error (std::string (__func__) + " : writing generated key failed" );
3190
- setKeyPool.insert (nEnd);
3191
- LogPrintf (" keypool added key %d, size=%u, internal=%d\n " , nEnd, setKeyPool.size (), internal);
3188
+
3189
+ if (internal) {
3190
+ setInternalKeyPool.insert (nEnd);
3191
+ } else {
3192
+ setExternalKeyPool.insert (nEnd);
3193
+ }
3194
+ LogPrintf (" keypool added key %d, size=%u (%u internal), new key is %s\n " , nEnd, setInternalKeyPool.size () + setExternalKeyPool.size (), setInternalKeyPool.size (), internal ? " internal" : " external" );
3192
3195
}
3193
3196
}
3194
3197
return true ;
3195
3198
}
3196
3199
3197
- void CWallet::ReserveKeyFromKeyPool (int64_t & nIndex, CKeyPool& keypool, bool internal )
3200
+ void CWallet::ReserveKeyFromKeyPool (int64_t & nIndex, CKeyPool& keypool, bool fRequestedInternal )
3198
3201
{
3199
3202
nIndex = -1 ;
3200
3203
keypool.vchPubKey = CPubKey ();
@@ -3204,30 +3207,30 @@ void CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool int
3204
3207
if (!IsLocked ())
3205
3208
TopUpKeyPool ();
3206
3209
3210
+ bool fReturningInternal = IsHDEnabled () && CanSupportFeature (FEATURE_HD_SPLIT) && fRequestedInternal ;
3211
+ std::set<int64_t >& setKeyPool = fReturningInternal ? setInternalKeyPool : setExternalKeyPool;
3212
+
3207
3213
// Get the oldest key
3208
3214
if (setKeyPool.empty ())
3209
3215
return ;
3210
3216
3211
3217
CWalletDB walletdb (*dbw);
3212
3218
3213
- // try to find a key that matches the internal/external filter
3214
- for (const int64_t & id : setKeyPool)
3215
- {
3216
- CKeyPool tmpKeypool;
3217
- if (!walletdb.ReadPool (id, tmpKeypool))
3218
- throw std::runtime_error (std::string (__func__) + " : read failed" );
3219
- if (!HaveKey (tmpKeypool.vchPubKey .GetID ()))
3220
- throw std::runtime_error (std::string (__func__) + " : unknown key in key pool" );
3221
- if (!IsHDEnabled () || !CanSupportFeature (FEATURE_HD_SPLIT) || tmpKeypool.fInternal == internal)
3222
- {
3223
- nIndex = id;
3224
- keypool = tmpKeypool;
3225
- setKeyPool.erase (id);
3226
- assert (keypool.vchPubKey .IsValid ());
3227
- LogPrintf (" keypool reserve %d\n " , nIndex);
3228
- return ;
3229
- }
3219
+ auto it = setKeyPool.begin ();
3220
+ nIndex = *it;
3221
+ setKeyPool.erase (it);
3222
+ if (!walletdb.ReadPool (nIndex, keypool)) {
3223
+ throw std::runtime_error (std::string (__func__) + " : read failed" );
3224
+ }
3225
+ if (!HaveKey (keypool.vchPubKey .GetID ())) {
3226
+ throw std::runtime_error (std::string (__func__) + " : unknown key in key pool" );
3230
3227
}
3228
+ if (keypool.fInternal != fReturningInternal ) {
3229
+ throw std::runtime_error (std::string (__func__) + " : keypool entry misclassified" );
3230
+ }
3231
+
3232
+ assert (keypool.vchPubKey .IsValid ());
3233
+ LogPrintf (" keypool reserve %d\n " , nIndex);
3231
3234
}
3232
3235
}
3233
3236
@@ -3239,12 +3242,16 @@ void CWallet::KeepKey(int64_t nIndex)
3239
3242
LogPrintf (" keypool keep %d\n " , nIndex);
3240
3243
}
3241
3244
3242
- void CWallet::ReturnKey (int64_t nIndex)
3245
+ void CWallet::ReturnKey (int64_t nIndex, bool fInternal )
3243
3246
{
3244
3247
// Return to key pool
3245
3248
{
3246
3249
LOCK (cs_wallet);
3247
- setKeyPool.insert (nIndex);
3250
+ if (fInternal ) {
3251
+ setInternalKeyPool.insert (nIndex);
3252
+ } else {
3253
+ setExternalKeyPool.insert (nIndex);
3254
+ }
3248
3255
}
3249
3256
LogPrintf (" keypool return %d\n " , nIndex);
3250
3257
}
@@ -3268,48 +3275,35 @@ bool CWallet::GetKeyFromPool(CPubKey& result, bool internal)
3268
3275
return true ;
3269
3276
}
3270
3277
3271
- int64_t CWallet::GetOldestKeyPoolTime ()
3272
- {
3273
- LOCK (cs_wallet);
3274
-
3275
- // if the keypool is empty, return <NOW>
3276
- if (setKeyPool.empty ())
3278
+ static int64_t GetOldestKeyTimeInPool (const std::set<int64_t >& setKeyPool, CWalletDB& walletdb) {
3279
+ if (setKeyPool.empty ()) {
3277
3280
return GetTime ();
3281
+ }
3278
3282
3279
3283
CKeyPool keypool;
3280
- CWalletDB walletdb (*dbw);
3281
-
3282
- if (IsHDEnabled () && CanSupportFeature (FEATURE_HD_SPLIT))
3283
- {
3284
- // if HD & HD Chain Split is enabled, response max(oldest-internal-key, oldest-external-key)
3285
- int64_t now = GetTime ();
3286
- int64_t oldest_external = now, oldest_internal = now;
3287
-
3288
- for (const int64_t & id : setKeyPool)
3289
- {
3290
- if (!walletdb.ReadPool (id, keypool)) {
3291
- throw std::runtime_error (std::string (__func__) + " : read failed" );
3292
- }
3293
- if (keypool.fInternal && keypool.nTime < oldest_internal) {
3294
- oldest_internal = keypool.nTime ;
3295
- }
3296
- else if (!keypool.fInternal && keypool.nTime < oldest_external) {
3297
- oldest_external = keypool.nTime ;
3298
- }
3299
- if (oldest_internal != now && oldest_external != now) {
3300
- break ;
3301
- }
3302
- }
3303
- return std::max (oldest_internal, oldest_external);
3304
- }
3305
- // load oldest key from keypool, get time and return
3306
3284
int64_t nIndex = *(setKeyPool.begin ());
3307
- if (!walletdb.ReadPool (nIndex, keypool))
3285
+ if (!walletdb.ReadPool (nIndex, keypool)) {
3308
3286
throw std::runtime_error (std::string (__func__) + " : read oldest key in keypool failed" );
3287
+ }
3309
3288
assert (keypool.vchPubKey .IsValid ());
3310
3289
return keypool.nTime ;
3311
3290
}
3312
3291
3292
+ int64_t CWallet::GetOldestKeyPoolTime ()
3293
+ {
3294
+ LOCK (cs_wallet);
3295
+
3296
+ CWalletDB walletdb (*dbw);
3297
+
3298
+ // load oldest key from keypool, get time and return
3299
+ int64_t oldestKey = GetOldestKeyTimeInPool (setExternalKeyPool, walletdb);
3300
+ if (IsHDEnabled () && CanSupportFeature (FEATURE_HD_SPLIT)) {
3301
+ oldestKey = std::max (GetOldestKeyTimeInPool (setInternalKeyPool, walletdb), oldestKey);
3302
+ }
3303
+
3304
+ return oldestKey;
3305
+ }
3306
+
3313
3307
std::map<CTxDestination, CAmount> CWallet::GetAddressBalances ()
3314
3308
{
3315
3309
std::map<CTxDestination, CAmount> balances;
@@ -3468,6 +3462,7 @@ bool CReserveKey::GetReservedKey(CPubKey& pubkey, bool internal)
3468
3462
else {
3469
3463
return false ;
3470
3464
}
3465
+ fInternal = keypool.fInternal ;
3471
3466
}
3472
3467
assert (vchPubKey.IsValid ());
3473
3468
pubkey = vchPubKey;
@@ -3484,32 +3479,42 @@ void CReserveKey::KeepKey()
3484
3479
3485
3480
void CReserveKey::ReturnKey ()
3486
3481
{
3487
- if (nIndex != -1 )
3488
- pwallet->ReturnKey (nIndex);
3482
+ if (nIndex != -1 ) {
3483
+ pwallet->ReturnKey (nIndex, fInternal );
3484
+ }
3489
3485
nIndex = -1 ;
3490
3486
vchPubKey = CPubKey ();
3491
3487
}
3492
3488
3493
- void CWallet::GetAllReserveKeys (std::set<CKeyID>& setAddress) const
3494
- {
3495
- setAddress.clear ();
3496
-
3497
- CWalletDB walletdb (*dbw);
3498
-
3499
- LOCK2 (cs_main, cs_wallet);
3489
+ static void LoadReserveKeysToSet (std::set<CKeyID>& setAddress, const std::set<int64_t >& setKeyPool, CWalletDB& walletdb) {
3500
3490
for (const int64_t & id : setKeyPool)
3501
3491
{
3502
3492
CKeyPool keypool;
3503
3493
if (!walletdb.ReadPool (id, keypool))
3504
3494
throw std::runtime_error (std::string (__func__) + " : read failed" );
3505
3495
assert (keypool.vchPubKey .IsValid ());
3506
3496
CKeyID keyID = keypool.vchPubKey .GetID ();
3507
- if (!HaveKey (keyID))
3508
- throw std::runtime_error (std::string (__func__) + " : unknown key in key pool" );
3509
3497
setAddress.insert (keyID);
3510
3498
}
3511
3499
}
3512
3500
3501
+ void CWallet::GetAllReserveKeys (std::set<CKeyID>& setAddress) const
3502
+ {
3503
+ setAddress.clear ();
3504
+
3505
+ CWalletDB walletdb (*dbw);
3506
+
3507
+ LOCK2 (cs_main, cs_wallet);
3508
+ LoadReserveKeysToSet (setAddress, setInternalKeyPool, walletdb);
3509
+ LoadReserveKeysToSet (setAddress, setExternalKeyPool, walletdb);
3510
+
3511
+ for (const CKeyID& keyID : setAddress) {
3512
+ if (!HaveKey (keyID)) {
3513
+ throw std::runtime_error (std::string (__func__) + " : unknown key in key pool" );
3514
+ }
3515
+ }
3516
+ }
3517
+
3513
3518
void CWallet::GetScriptForMining (std::shared_ptr<CReserveScript> &script)
3514
3519
{
3515
3520
std::shared_ptr<CReserveKey> rKey = std::make_shared<CReserveKey>(this );
0 commit comments