@@ -2941,7 +2941,8 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
2941
2941
if (dbw->Rewrite (" \x04 pool" ))
2942
2942
{
2943
2943
LOCK (cs_wallet);
2944
- setKeyPool.clear ();
2944
+ setInternalKeyPool.clear ();
2945
+ setExternalKeyPool.clear ();
2945
2946
// Note: can't top-up keypool here, because wallet is locked.
2946
2947
// User will be prompted to unlock wallet the next operation
2947
2948
// that requires a new key.
@@ -2969,7 +2970,8 @@ DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256
2969
2970
{
2970
2971
if (dbw->Rewrite (" \x04 pool" ))
2971
2972
{
2972
- setKeyPool.clear ();
2973
+ setInternalKeyPool.clear ();
2974
+ setExternalKeyPool.clear ();
2973
2975
// Note: can't top-up keypool here, because wallet is locked.
2974
2976
// User will be prompted to unlock wallet the next operation
2975
2977
// that requires a new key.
@@ -2994,7 +2996,8 @@ DBErrors CWallet::ZapWalletTx(std::vector<CWalletTx>& vWtx)
2994
2996
if (dbw->Rewrite (" \x04 pool" ))
2995
2997
{
2996
2998
LOCK (cs_wallet);
2997
- setKeyPool.clear ();
2999
+ setInternalKeyPool.clear ();
3000
+ setExternalKeyPool.clear ();
2998
3001
// Note: can't top-up keypool here, because wallet is locked.
2999
3002
// User will be prompted to unlock wallet the next operation
3000
3003
// that requires a new key.
@@ -3078,9 +3081,12 @@ bool CWallet::NewKeyPool()
3078
3081
{
3079
3082
LOCK (cs_wallet);
3080
3083
CWalletDB walletdb (*dbw);
3081
- for (int64_t nIndex : setKeyPool )
3084
+ for (int64_t nIndex : setInternalKeyPool )
3082
3085
walletdb.ErasePool (nIndex);
3083
- setKeyPool.clear ();
3086
+ setInternalKeyPool.clear ();
3087
+ BOOST_FOREACH (int64_t nIndex, setExternalKeyPool)
3088
+ walletdb.ErasePool (nIndex);
3089
+ setExternalKeyPool.clear ();
3084
3090
3085
3091
if (!TopUpKeyPool ()) {
3086
3092
return false ;
@@ -3092,25 +3098,8 @@ bool CWallet::NewKeyPool()
3092
3098
3093
3099
size_t CWallet::KeypoolCountExternalKeys ()
3094
3100
{
3095
- AssertLockHeld (cs_wallet); // setKeyPool
3096
-
3097
- // immediately return setKeyPool's size if HD or HD_SPLIT is disabled or not supported
3098
- if (!IsHDEnabled () || !CanSupportFeature (FEATURE_HD_SPLIT))
3099
- return setKeyPool.size ();
3100
-
3101
- CWalletDB walletdb (*dbw);
3102
-
3103
- // count amount of external keys
3104
- size_t amountE = 0 ;
3105
- for (const int64_t & id : setKeyPool)
3106
- {
3107
- CKeyPool tmpKeypool;
3108
- if (!walletdb.ReadPool (id, tmpKeypool))
3109
- throw std::runtime_error (std::string (__func__) + " : read failed" );
3110
- amountE += !tmpKeypool.fInternal ;
3111
- }
3112
-
3113
- return amountE;
3101
+ AssertLockHeld (cs_wallet); // setExternalKeyPool
3102
+ return setExternalKeyPool.size ();
3114
3103
}
3115
3104
3116
3105
bool CWallet::TopUpKeyPool (unsigned int kpSize)
@@ -3130,10 +3119,8 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize)
3130
3119
3131
3120
// count amount of available keys (internal, external)
3132
3121
// make sure the keypool of external and internal keys fits the user selected target (-keypool)
3133
- int64_t amountExternal = KeypoolCountExternalKeys ();
3134
- int64_t amountInternal = setKeyPool.size () - amountExternal;
3135
- int64_t missingExternal = std::max (std::max ((int64_t ) nTargetSize, (int64_t ) 1 ) - amountExternal, (int64_t ) 0 );
3136
- int64_t missingInternal = std::max (std::max ((int64_t ) nTargetSize, (int64_t ) 1 ) - amountInternal, (int64_t ) 0 );
3122
+ int64_t missingExternal = std::max (std::max ((int64_t ) nTargetSize, (int64_t ) 1 ) - (int64_t )setExternalKeyPool.size (), (int64_t ) 0 );
3123
+ int64_t missingInternal = std::max (std::max ((int64_t ) nTargetSize, (int64_t ) 1 ) - (int64_t )setInternalKeyPool.size (), (int64_t ) 0 );
3137
3124
3138
3125
if (!IsHDEnabled () || !CanSupportFeature (FEATURE_HD_SPLIT))
3139
3126
{
@@ -3147,18 +3134,26 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize)
3147
3134
int64_t nEnd = 1 ;
3148
3135
if (i < missingInternal)
3149
3136
internal = true ;
3150
- if (!setKeyPool.empty ())
3151
- nEnd = *(--setKeyPool.end ()) + 1 ;
3137
+ if (!setInternalKeyPool.empty ())
3138
+ nEnd = *(--setInternalKeyPool.end ()) + 1 ;
3139
+ if (!setExternalKeyPool.empty ())
3140
+ nEnd = std::max (nEnd, *(--setExternalKeyPool.end ()) + 1 );
3141
+
3152
3142
if (!walletdb.WritePool (nEnd, CKeyPool (GenerateNewKey (internal), internal)))
3153
3143
throw std::runtime_error (std::string (__func__) + " : writing generated key failed" );
3154
- setKeyPool.insert (nEnd);
3155
- LogPrintf (" keypool added key %d, size=%u, internal=%d\n " , nEnd, setKeyPool.size (), internal);
3144
+
3145
+ if (internal) {
3146
+ setInternalKeyPool.insert (nEnd);
3147
+ } else {
3148
+ setExternalKeyPool.insert (nEnd);
3149
+ }
3150
+ LogPrintf (" keypool added key %d, size=%u (%u internal), new key is %s\n " , nEnd, setInternalKeyPool.size () + setExternalKeyPool.size (), setInternalKeyPool.size (), internal ? " internal" : " external" );
3156
3151
}
3157
3152
}
3158
3153
return true ;
3159
3154
}
3160
3155
3161
- void CWallet::ReserveKeyFromKeyPool (int64_t & nIndex, CKeyPool& keypool, bool internal )
3156
+ void CWallet::ReserveKeyFromKeyPool (int64_t & nIndex, CKeyPool& keypool, bool fRequestedInternal )
3162
3157
{
3163
3158
nIndex = -1 ;
3164
3159
keypool.vchPubKey = CPubKey ();
@@ -3168,30 +3163,30 @@ void CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool int
3168
3163
if (!IsLocked ())
3169
3164
TopUpKeyPool ();
3170
3165
3166
+ bool fReturningInternal = IsHDEnabled () && CanSupportFeature (FEATURE_HD_SPLIT) && fRequestedInternal ;
3167
+ std::set<int64_t >& setKeyPool = fReturningInternal ? setInternalKeyPool : setExternalKeyPool;
3168
+
3171
3169
// Get the oldest key
3172
3170
if (setKeyPool.empty ())
3173
3171
return ;
3174
3172
3175
3173
CWalletDB walletdb (*dbw);
3176
3174
3177
- // try to find a key that matches the internal/external filter
3178
- for (const int64_t & id : setKeyPool)
3179
- {
3180
- CKeyPool tmpKeypool;
3181
- if (!walletdb.ReadPool (id, tmpKeypool))
3182
- throw std::runtime_error (std::string (__func__) + " : read failed" );
3183
- if (!HaveKey (tmpKeypool.vchPubKey .GetID ()))
3184
- throw std::runtime_error (std::string (__func__) + " : unknown key in key pool" );
3185
- if (!IsHDEnabled () || !CanSupportFeature (FEATURE_HD_SPLIT) || tmpKeypool.fInternal == internal)
3186
- {
3187
- nIndex = id;
3188
- keypool = tmpKeypool;
3189
- setKeyPool.erase (id);
3190
- assert (keypool.vchPubKey .IsValid ());
3191
- LogPrintf (" keypool reserve %d\n " , nIndex);
3192
- return ;
3193
- }
3175
+ auto it = setKeyPool.begin ();
3176
+ nIndex = *it;
3177
+ setKeyPool.erase (it);
3178
+ if (!walletdb.ReadPool (nIndex, keypool)) {
3179
+ throw std::runtime_error (std::string (__func__) + " : read failed" );
3194
3180
}
3181
+ if (!HaveKey (keypool.vchPubKey .GetID ())) {
3182
+ throw std::runtime_error (std::string (__func__) + " : unknown key in key pool" );
3183
+ }
3184
+ if (keypool.fInternal != fReturningInternal ) {
3185
+ throw std::runtime_error (std::string (__func__) + " : keypool entry misclassified" );
3186
+ }
3187
+
3188
+ assert (keypool.vchPubKey .IsValid ());
3189
+ LogPrintf (" keypool reserve %d\n " , nIndex);
3195
3190
}
3196
3191
}
3197
3192
@@ -3203,12 +3198,16 @@ void CWallet::KeepKey(int64_t nIndex)
3203
3198
LogPrintf (" keypool keep %d\n " , nIndex);
3204
3199
}
3205
3200
3206
- void CWallet::ReturnKey (int64_t nIndex)
3201
+ void CWallet::ReturnKey (int64_t nIndex, bool fInternal )
3207
3202
{
3208
3203
// Return to key pool
3209
3204
{
3210
3205
LOCK (cs_wallet);
3211
- setKeyPool.insert (nIndex);
3206
+ if (fInternal ) {
3207
+ setInternalKeyPool.insert (nIndex);
3208
+ } else {
3209
+ setExternalKeyPool.insert (nIndex);
3210
+ }
3212
3211
}
3213
3212
LogPrintf (" keypool return %d\n " , nIndex);
3214
3213
}
@@ -3232,48 +3231,34 @@ bool CWallet::GetKeyFromPool(CPubKey& result, bool internal)
3232
3231
return true ;
3233
3232
}
3234
3233
3235
- int64_t CWallet::GetOldestKeyPoolTime ()
3236
- {
3237
- LOCK (cs_wallet);
3238
-
3239
- // if the keypool is empty, return <NOW>
3240
- if (setKeyPool.empty ())
3234
+ static int64_t GetOldestKeyTimeInPool (const std::set<int64_t >& setKeyPool, CWalletDB& walletdb) {
3235
+ if (setKeyPool.empty ()) {
3241
3236
return GetTime ();
3237
+ }
3242
3238
3243
3239
CKeyPool keypool;
3244
- CWalletDB walletdb (*dbw);
3245
-
3246
- if (IsHDEnabled () && CanSupportFeature (FEATURE_HD_SPLIT))
3247
- {
3248
- // if HD & HD Chain Split is enabled, response max(oldest-internal-key, oldest-external-key)
3249
- int64_t now = GetTime ();
3250
- int64_t oldest_external = now, oldest_internal = now;
3251
-
3252
- for (const int64_t & id : setKeyPool)
3253
- {
3254
- if (!walletdb.ReadPool (id, keypool)) {
3255
- throw std::runtime_error (std::string (__func__) + " : read failed" );
3256
- }
3257
- if (keypool.fInternal && keypool.nTime < oldest_internal) {
3258
- oldest_internal = keypool.nTime ;
3259
- }
3260
- else if (!keypool.fInternal && keypool.nTime < oldest_external) {
3261
- oldest_external = keypool.nTime ;
3262
- }
3263
- if (oldest_internal != now && oldest_external != now) {
3264
- break ;
3265
- }
3266
- }
3267
- return std::max (oldest_internal, oldest_external);
3268
- }
3269
- // load oldest key from keypool, get time and return
3270
3240
int64_t nIndex = *(setKeyPool.begin ());
3271
3241
if (!walletdb.ReadPool (nIndex, keypool))
3272
3242
throw std::runtime_error (std::string (__func__) + " : read oldest key in keypool failed" );
3273
3243
assert (keypool.vchPubKey .IsValid ());
3274
3244
return keypool.nTime ;
3275
3245
}
3276
3246
3247
+ int64_t CWallet::GetOldestKeyPoolTime ()
3248
+ {
3249
+ LOCK (cs_wallet);
3250
+
3251
+ CWalletDB walletdb (*dbw);
3252
+
3253
+ // load oldest key from keypool, get time and return
3254
+ int64_t oldestKey = GetOldestKeyTimeInPool (setExternalKeyPool, walletdb);
3255
+ if (IsHDEnabled () && CanSupportFeature (FEATURE_HD_SPLIT)) {
3256
+ oldestKey = std::max (GetOldestKeyTimeInPool (setInternalKeyPool, walletdb), oldestKey);
3257
+ }
3258
+
3259
+ return oldestKey;
3260
+ }
3261
+
3277
3262
std::map<CTxDestination, CAmount> CWallet::GetAddressBalances ()
3278
3263
{
3279
3264
std::map<CTxDestination, CAmount> balances;
@@ -3432,6 +3417,7 @@ bool CReserveKey::GetReservedKey(CPubKey& pubkey, bool internal)
3432
3417
else {
3433
3418
return false ;
3434
3419
}
3420
+ fInternal = keypool.fInternal ;
3435
3421
}
3436
3422
assert (vchPubKey.IsValid ());
3437
3423
pubkey = vchPubKey;
@@ -3449,31 +3435,40 @@ void CReserveKey::KeepKey()
3449
3435
void CReserveKey::ReturnKey ()
3450
3436
{
3451
3437
if (nIndex != -1 )
3452
- pwallet->ReturnKey (nIndex);
3438
+ pwallet->ReturnKey (nIndex, fInternal );
3453
3439
nIndex = -1 ;
3454
3440
vchPubKey = CPubKey ();
3455
3441
}
3456
3442
3457
- void CWallet::GetAllReserveKeys (std::set<CKeyID>& setAddress) const
3458
- {
3459
- setAddress.clear ();
3460
-
3461
- CWalletDB walletdb (*dbw);
3462
-
3463
- LOCK2 (cs_main, cs_wallet);
3443
+ static void LoadReserveKeysToSet (std::set<CKeyID>& setAddress, const std::set<int64_t >& setKeyPool, CWalletDB& walletdb) {
3464
3444
for (const int64_t & id : setKeyPool)
3465
3445
{
3466
3446
CKeyPool keypool;
3467
3447
if (!walletdb.ReadPool (id, keypool))
3468
3448
throw std::runtime_error (std::string (__func__) + " : read failed" );
3469
3449
assert (keypool.vchPubKey .IsValid ());
3470
3450
CKeyID keyID = keypool.vchPubKey .GetID ();
3471
- if (!HaveKey (keyID))
3472
- throw std::runtime_error (std::string (__func__) + " : unknown key in key pool" );
3473
3451
setAddress.insert (keyID);
3474
3452
}
3475
3453
}
3476
3454
3455
+ void CWallet::GetAllReserveKeys (std::set<CKeyID>& setAddress) const
3456
+ {
3457
+ setAddress.clear ();
3458
+
3459
+ CWalletDB walletdb (*dbw);
3460
+
3461
+ LOCK2 (cs_main, cs_wallet);
3462
+ LoadReserveKeysToSet (setAddress, setInternalKeyPool, walletdb);
3463
+ LoadReserveKeysToSet (setAddress, setExternalKeyPool, walletdb);
3464
+
3465
+ for (const CKeyID& keyID : setAddress) {
3466
+ if (!HaveKey (keyID)) {
3467
+ throw std::runtime_error (std::string (__func__) + " : unknown key in key pool" );
3468
+ }
3469
+ }
3470
+ }
3471
+
3477
3472
void CWallet::GetScriptForMining (std::shared_ptr<CReserveScript> &script)
3478
3473
{
3479
3474
std::shared_ptr<CReserveKey> rKey = std::make_shared<CReserveKey>(this );
0 commit comments