@ -2977,7 +2977,8 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
@@ -2977,7 +2977,8 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
if ( dbw - > Rewrite ( " \x04 pool " ) )
{
LOCK ( cs_wallet ) ;
setKeyPool . clear ( ) ;
setInternalKeyPool . clear ( ) ;
setExternalKeyPool . clear ( ) ;
// Note: can't top-up keypool here, because wallet is locked.
// User will be prompted to unlock wallet the next operation
// that requires a new key.
@ -3005,7 +3006,8 @@ DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256
@@ -3005,7 +3006,8 @@ DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256
{
if ( dbw - > Rewrite ( " \x04 pool " ) )
{
setKeyPool . clear ( ) ;
setInternalKeyPool . clear ( ) ;
setExternalKeyPool . clear ( ) ;
// Note: can't top-up keypool here, because wallet is locked.
// User will be prompted to unlock wallet the next operation
// that requires a new key.
@ -3030,7 +3032,8 @@ DBErrors CWallet::ZapWalletTx(std::vector<CWalletTx>& vWtx)
@@ -3030,7 +3032,8 @@ DBErrors CWallet::ZapWalletTx(std::vector<CWalletTx>& vWtx)
if ( dbw - > Rewrite ( " \x04 pool " ) )
{
LOCK ( cs_wallet ) ;
setKeyPool . clear ( ) ;
setInternalKeyPool . clear ( ) ;
setExternalKeyPool . clear ( ) ;
// Note: can't top-up keypool here, because wallet is locked.
// User will be prompted to unlock wallet the next operation
// that requires a new key.
@ -3114,9 +3117,16 @@ bool CWallet::NewKeyPool()
@@ -3114,9 +3117,16 @@ bool CWallet::NewKeyPool()
{
LOCK ( cs_wallet ) ;
CWalletDB walletdb ( * dbw ) ;
for ( int64_t nIndex : setKeyPool )
for ( int64_t nIndex : setInternalKeyPool ) {
walletdb . ErasePool ( nIndex ) ;
}
setInternalKeyPool . clear ( ) ;
for ( int64_t nIndex : setExternalKeyPool ) {
walletdb . ErasePool ( nIndex ) ;
setKeyPool . clear ( ) ;
}
setExternalKeyPool . clear ( ) ;
if ( ! TopUpKeyPool ( ) ) {
return false ;
@ -3128,25 +3138,8 @@ bool CWallet::NewKeyPool()
@@ -3128,25 +3138,8 @@ bool CWallet::NewKeyPool()
size_t CWallet : : KeypoolCountExternalKeys ( )
{
AssertLockHeld ( cs_wallet ) ; // setKeyPool
// immediately return setKeyPool's size if HD or HD_SPLIT is disabled or not supported
if ( ! IsHDEnabled ( ) | | ! CanSupportFeature ( FEATURE_HD_SPLIT ) )
return setKeyPool . size ( ) ;
CWalletDB walletdb ( * dbw ) ;
// count amount of external keys
size_t amountE = 0 ;
for ( const int64_t & id : setKeyPool )
{
CKeyPool tmpKeypool ;
if ( ! walletdb . ReadPool ( id , tmpKeypool ) )
throw std : : runtime_error ( std : : string ( __func__ ) + " : read failed " ) ;
amountE + = ! tmpKeypool . fInternal ;
}
return amountE ;
AssertLockHeld ( cs_wallet ) ; // setExternalKeyPool
return setExternalKeyPool . size ( ) ;
}
bool CWallet : : TopUpKeyPool ( unsigned int kpSize )
@ -3166,10 +3159,8 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize)
@@ -3166,10 +3159,8 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize)
// count amount of available keys (internal, external)
// make sure the keypool of external and internal keys fits the user selected target (-keypool)
int64_t amountExternal = KeypoolCountExternalKeys ( ) ;
int64_t amountInternal = setKeyPool . size ( ) - amountExternal ;
int64_t missingExternal = std : : max ( std : : max ( ( int64_t ) nTargetSize , ( int64_t ) 1 ) - amountExternal , ( int64_t ) 0 ) ;
int64_t missingInternal = std : : max ( std : : max ( ( int64_t ) nTargetSize , ( int64_t ) 1 ) - amountInternal , ( int64_t ) 0 ) ;
int64_t missingExternal = std : : max ( std : : max ( ( int64_t ) nTargetSize , ( int64_t ) 1 ) - ( int64_t ) setExternalKeyPool . size ( ) , ( int64_t ) 0 ) ;
int64_t missingInternal = std : : max ( std : : max ( ( int64_t ) nTargetSize , ( int64_t ) 1 ) - ( int64_t ) setInternalKeyPool . size ( ) , ( int64_t ) 0 ) ;
if ( ! IsHDEnabled ( ) | | ! CanSupportFeature ( FEATURE_HD_SPLIT ) )
{
@ -3181,20 +3172,32 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize)
@@ -3181,20 +3172,32 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize)
for ( int64_t i = missingInternal + missingExternal ; i - - ; )
{
int64_t nEnd = 1 ;
if ( i < missingInternal )
if ( i < missingInternal ) {
internal = true ;
if ( ! setKeyPool . empty ( ) )
nEnd = * ( - - setKeyPool . end ( ) ) + 1 ;
}
if ( ! setInternalKeyPool . empty ( ) ) {
nEnd = * ( setInternalKeyPool . rbegin ( ) ) + 1 ;
}
if ( ! setExternalKeyPool . empty ( ) ) {
nEnd = std : : max ( nEnd , * ( setExternalKeyPool . rbegin ( ) ) + 1 ) ;
}
if ( ! walletdb . WritePool ( nEnd , CKeyPool ( GenerateNewKey ( internal ) , internal ) ) )
throw std : : runtime_error ( std : : string ( __func__ ) + " : writing generated key failed " ) ;
setKeyPool . insert ( nEnd ) ;
LogPrintf ( " keypool added key %d, size=%u, internal=%d \n " , nEnd , setKeyPool . size ( ) , internal ) ;
if ( internal ) {
setInternalKeyPool . insert ( nEnd ) ;
} else {
setExternalKeyPool . insert ( nEnd ) ;
}
LogPrintf ( " keypool added key %d, size=%u (%u internal), new key is %s \n " , nEnd , setInternalKeyPool . size ( ) + setExternalKeyPool . size ( ) , setInternalKeyPool . size ( ) , internal ? " internal " : " external " ) ;
}
}
return true ;
}
void CWallet : : ReserveKeyFromKeyPool ( int64_t & nIndex , CKeyPool & keypool , bool i nternal)
void CWallet : : ReserveKeyFromKeyPool ( int64_t & nIndex , CKeyPool & keypool , bool fRequestedI nternal)
{
nIndex = - 1 ;
keypool . vchPubKey = CPubKey ( ) ;
@ -3204,30 +3207,30 @@ void CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool int
@@ -3204,30 +3207,30 @@ void CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool int
if ( ! IsLocked ( ) )
TopUpKeyPool ( ) ;
bool fReturningInternal = IsHDEnabled ( ) & & CanSupportFeature ( FEATURE_HD_SPLIT ) & & fRequestedInternal ;
std : : set < int64_t > & setKeyPool = fReturningInternal ? setInternalKeyPool : setExternalKeyPool ;
// Get the oldest key
if ( setKeyPool . empty ( ) )
return ;
CWalletDB walletdb ( * dbw ) ;
// try to find a key that matches the internal/external filter
for ( const int64_t & id : setKeyPool )
{
CKeyPool tmpKeypool ;
if ( ! walletdb . ReadPool ( id , tmpKeypool ) )
auto it = setKeyPool . begin ( ) ;
nIndex = * it ;
setKeyPool . erase ( it ) ;
if ( ! walletdb . ReadPool ( nIndex , keypool ) ) {
throw std : : runtime_error ( std : : string ( __func__ ) + " : read failed " ) ;
if ( ! HaveKey ( tmpKeypool . vchPubKey . GetID ( ) ) )
}
if ( ! HaveKey ( keypool . vchPubKey . GetID ( ) ) ) {
throw std : : runtime_error ( std : : string ( __func__ ) + " : unknown key in key pool " ) ;
if ( ! IsHDEnabled ( ) | | ! CanSupportFeature ( FEATURE_HD_SPLIT ) | | tmpKeypool . fInternal = = internal )
{
nIndex = id ;
keypool = tmpKeypool ;
setKeyPool . erase ( id ) ;
assert ( keypool . vchPubKey . IsValid ( ) ) ;
LogPrintf ( " keypool reserve %d \n " , nIndex ) ;
return ;
}
if ( keypool . fInternal ! = fReturningInternal ) {
throw std : : runtime_error ( std : : string ( __func__ ) + " : keypool entry misclassified " ) ;
}
assert ( keypool . vchPubKey . IsValid ( ) ) ;
LogPrintf ( " keypool reserve %d \n " , nIndex ) ;
}
}
@ -3239,12 +3242,16 @@ void CWallet::KeepKey(int64_t nIndex)
@@ -3239,12 +3242,16 @@ void CWallet::KeepKey(int64_t nIndex)
LogPrintf ( " keypool keep %d \n " , nIndex ) ;
}
void CWallet : : ReturnKey ( int64_t nIndex )
void CWallet : : ReturnKey ( int64_t nIndex , bool fInternal )
{
// Return to key pool
{
LOCK ( cs_wallet ) ;
setKeyPool . insert ( nIndex ) ;
if ( fInternal ) {
setInternalKeyPool . insert ( nIndex ) ;
} else {
setExternalKeyPool . insert ( nIndex ) ;
}
}
LogPrintf ( " keypool return %d \n " , nIndex ) ;
}
@ -3268,48 +3275,35 @@ bool CWallet::GetKeyFromPool(CPubKey& result, bool internal)
@@ -3268,48 +3275,35 @@ bool CWallet::GetKeyFromPool(CPubKey& result, bool internal)
return true ;
}
int64_t CWallet : : GetOldestKeyPoolTime ( )
{
LOCK ( cs_wallet ) ;
// if the keypool is empty, return <NOW>
if ( setKeyPool . empty ( ) )
static int64_t GetOldestKeyTimeInPool ( const std : : set < int64_t > & setKeyPool , CWalletDB & walletdb ) {
if ( setKeyPool . empty ( ) ) {
return GetTime ( ) ;
}
CKeyPool keypool ;
CWalletDB walletdb ( * dbw ) ;
if ( IsHDEnabled ( ) & & CanSupportFeature ( FEATURE_HD_SPLIT ) )
{
// if HD & HD Chain Split is enabled, response max(oldest-internal-key, oldest-external-key)
int64_t now = GetTime ( ) ;
int64_t oldest_external = now , oldest_internal = now ;
for ( const int64_t & id : setKeyPool )
{
if ( ! walletdb . ReadPool ( id , keypool ) ) {
throw std : : runtime_error ( std : : string ( __func__ ) + " : read failed " ) ;
}
if ( keypool . fInternal & & keypool . nTime < oldest_internal ) {
oldest_internal = keypool . nTime ;
}
else if ( ! keypool . fInternal & & keypool . nTime < oldest_external ) {
oldest_external = keypool . nTime ;
}
if ( oldest_internal ! = now & & oldest_external ! = now ) {
break ;
}
}
return std : : max ( oldest_internal , oldest_external ) ;
}
// load oldest key from keypool, get time and return
int64_t nIndex = * ( setKeyPool . begin ( ) ) ;
if ( ! walletdb . ReadPool ( nIndex , keypool ) )
if ( ! walletdb . ReadPool ( nIndex , keypool ) ) {
throw std : : runtime_error ( std : : string ( __func__ ) + " : read oldest key in keypool failed " ) ;
}
assert ( keypool . vchPubKey . IsValid ( ) ) ;
return keypool . nTime ;
}
int64_t CWallet : : GetOldestKeyPoolTime ( )
{
LOCK ( cs_wallet ) ;
CWalletDB walletdb ( * dbw ) ;
// load oldest key from keypool, get time and return
int64_t oldestKey = GetOldestKeyTimeInPool ( setExternalKeyPool , walletdb ) ;
if ( IsHDEnabled ( ) & & CanSupportFeature ( FEATURE_HD_SPLIT ) ) {
oldestKey = std : : max ( GetOldestKeyTimeInPool ( setInternalKeyPool , walletdb ) , oldestKey ) ;
}
return oldestKey ;
}
std : : map < CTxDestination , CAmount > CWallet : : GetAddressBalances ( )
{
std : : map < CTxDestination , CAmount > balances ;
@ -3468,6 +3462,7 @@ bool CReserveKey::GetReservedKey(CPubKey& pubkey, bool internal)
@@ -3468,6 +3462,7 @@ bool CReserveKey::GetReservedKey(CPubKey& pubkey, bool internal)
else {
return false ;
}
fInternal = keypool . fInternal ;
}
assert ( vchPubKey . IsValid ( ) ) ;
pubkey = vchPubKey ;
@ -3484,19 +3479,14 @@ void CReserveKey::KeepKey()
@@ -3484,19 +3479,14 @@ void CReserveKey::KeepKey()
void CReserveKey : : ReturnKey ( )
{
if ( nIndex ! = - 1 )
pwallet - > ReturnKey ( nIndex ) ;
if ( nIndex ! = - 1 ) {
pwallet - > ReturnKey ( nIndex , fInternal ) ;
}
nIndex = - 1 ;
vchPubKey = CPubKey ( ) ;
}
void CWallet : : GetAllReserveKeys ( std : : set < CKeyID > & setAddress ) const
{
setAddress . clear ( ) ;
CWalletDB walletdb ( * dbw ) ;
LOCK2 ( cs_main , cs_wallet ) ;
static void LoadReserveKeysToSet ( std : : set < CKeyID > & setAddress , const std : : set < int64_t > & setKeyPool , CWalletDB & walletdb ) {
for ( const int64_t & id : setKeyPool )
{
CKeyPool keypool ;
@ -3504,12 +3494,27 @@ void CWallet::GetAllReserveKeys(std::set<CKeyID>& setAddress) const
@@ -3504,12 +3494,27 @@ void CWallet::GetAllReserveKeys(std::set<CKeyID>& setAddress) const
throw std : : runtime_error ( std : : string ( __func__ ) + " : read failed " ) ;
assert ( keypool . vchPubKey . IsValid ( ) ) ;
CKeyID keyID = keypool . vchPubKey . GetID ( ) ;
if ( ! HaveKey ( keyID ) )
throw std : : runtime_error ( std : : string ( __func__ ) + " : unknown key in key pool " ) ;
setAddress . insert ( keyID ) ;
}
}
void CWallet : : GetAllReserveKeys ( std : : set < CKeyID > & setAddress ) const
{
setAddress . clear ( ) ;
CWalletDB walletdb ( * dbw ) ;
LOCK2 ( cs_main , cs_wallet ) ;
LoadReserveKeysToSet ( setAddress , setInternalKeyPool , walletdb ) ;
LoadReserveKeysToSet ( setAddress , setExternalKeyPool , walletdb ) ;
for ( const CKeyID & keyID : setAddress ) {
if ( ! HaveKey ( keyID ) ) {
throw std : : runtime_error ( std : : string ( __func__ ) + " : unknown key in key pool " ) ;
}
}
}
void CWallet : : GetScriptForMining ( std : : shared_ptr < CReserveScript > & script )
{
std : : shared_ptr < CReserveKey > rKey = std : : make_shared < CReserveKey > ( this ) ;