Changeset View
Changeset View
Standalone View
Standalone View
src/wallet/wallet.cpp
Show First 20 Lines • Show All 1,571 Lines • ▼ Show 20 Lines | void CWallet::SetHDSeed(const CPubKey &seed) { | ||||
// Store the keyid (hash160) together with the child index counter in the | // Store the keyid (hash160) together with the child index counter in the | ||||
// database as a hdchain object. | // database as a hdchain object. | ||||
CHDChain newHdChain; | CHDChain newHdChain; | ||||
newHdChain.nVersion = CanSupportFeature(FEATURE_HD_SPLIT) | newHdChain.nVersion = CanSupportFeature(FEATURE_HD_SPLIT) | ||||
? CHDChain::VERSION_HD_CHAIN_SPLIT | ? CHDChain::VERSION_HD_CHAIN_SPLIT | ||||
: CHDChain::VERSION_HD_BASE; | : CHDChain::VERSION_HD_BASE; | ||||
newHdChain.seed_id = seed.GetID(); | newHdChain.seed_id = seed.GetID(); | ||||
SetHDChain(newHdChain, false); | SetHDChain(newHdChain, false); | ||||
NotifyCanGetAddressesChanged(); | |||||
} | } | ||||
void CWallet::SetHDChain(const CHDChain &chain, bool memonly) { | void CWallet::SetHDChain(const CHDChain &chain, bool memonly) { | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
if (!memonly && !WalletBatch(*database).WriteHDChain(chain)) { | if (!memonly && !WalletBatch(*database).WriteHDChain(chain)) { | ||||
throw std::runtime_error(std::string(__func__) + | throw std::runtime_error(std::string(__func__) + | ||||
": writing chain failed"); | ": writing chain failed"); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 2,023 Lines • ▼ Show 20 Lines | if (mapKeyMetadata.count(keyid) == 0) { | ||||
mapKeyMetadata[keyid] = CKeyMetadata(keypool.nTime); | mapKeyMetadata[keyid] = CKeyMetadata(keypool.nTime); | ||||
} | } | ||||
} | } | ||||
bool CWallet::TopUpKeyPool(unsigned int kpSize) { | bool CWallet::TopUpKeyPool(unsigned int kpSize) { | ||||
if (IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { | if (IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { | ||||
return false; | return false; | ||||
} | } | ||||
{ | |||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
if (IsLocked()) { | if (IsLocked()) { | ||||
return false; | return false; | ||||
} | } | ||||
// Top up key pool | // Top up key pool | ||||
unsigned int nTargetSize; | unsigned int nTargetSize; | ||||
if (kpSize > 0) { | if (kpSize > 0) { | ||||
nTargetSize = kpSize; | nTargetSize = kpSize; | ||||
} else { | } else { | ||||
nTargetSize = std::max<int64_t>( | nTargetSize = std::max<int64_t>( | ||||
gArgs.GetArg("-keypool", DEFAULT_KEYPOOL_SIZE), 0); | gArgs.GetArg("-keypool", DEFAULT_KEYPOOL_SIZE), 0); | ||||
} | } | ||||
// count amount of available keys (internal, external) | // count amount of available keys (internal, external) | ||||
// make sure the keypool of external and internal keys fits the user | // make sure the keypool of external and internal keys fits the user | ||||
// selected target (-keypool) | // selected target (-keypool) | ||||
int64_t missingExternal = std::max<int64_t>( | int64_t missingExternal = std::max<int64_t>( | ||||
std::max<int64_t>(nTargetSize, 1) - setExternalKeyPool.size(), 0); | std::max<int64_t>(nTargetSize, 1) - setExternalKeyPool.size(), 0); | ||||
int64_t missingInternal = std::max<int64_t>( | int64_t missingInternal = std::max<int64_t>( | ||||
std::max<int64_t>(nTargetSize, 1) - setInternalKeyPool.size(), 0); | std::max<int64_t>(nTargetSize, 1) - setInternalKeyPool.size(), 0); | ||||
if (!IsHDEnabled() || !CanSupportFeature(FEATURE_HD_SPLIT)) { | if (!IsHDEnabled() || !CanSupportFeature(FEATURE_HD_SPLIT)) { | ||||
// don't create extra internal keys | // don't create extra internal keys | ||||
missingInternal = 0; | missingInternal = 0; | ||||
} | } | ||||
bool internal = false; | bool internal = false; | ||||
WalletBatch batch(*database); | WalletBatch batch(*database); | ||||
for (int64_t i = missingInternal + missingExternal; i--;) { | for (int64_t i = missingInternal + missingExternal; i--;) { | ||||
if (i < missingInternal) { | if (i < missingInternal) { | ||||
internal = true; | internal = true; | ||||
} | } | ||||
// How in the hell did you use so many keys? | // How in the hell did you use so many keys? | ||||
assert(m_max_keypool_index < std::numeric_limits<int64_t>::max()); | assert(m_max_keypool_index < std::numeric_limits<int64_t>::max()); | ||||
int64_t index = ++m_max_keypool_index; | int64_t index = ++m_max_keypool_index; | ||||
CPubKey pubkey(GenerateNewKey(batch, internal)); | CPubKey pubkey(GenerateNewKey(batch, internal)); | ||||
if (!batch.WritePool(index, CKeyPool(pubkey, internal))) { | if (!batch.WritePool(index, CKeyPool(pubkey, internal))) { | ||||
throw std::runtime_error(std::string(__func__) + | throw std::runtime_error(std::string(__func__) + | ||||
": writing generated key failed"); | ": writing generated key failed"); | ||||
} | } | ||||
if (internal) { | if (internal) { | ||||
setInternalKeyPool.insert(index); | setInternalKeyPool.insert(index); | ||||
} else { | } else { | ||||
setExternalKeyPool.insert(index); | setExternalKeyPool.insert(index); | ||||
} | } | ||||
m_pool_key_to_index[pubkey.GetID()] = index; | m_pool_key_to_index[pubkey.GetID()] = index; | ||||
} | } | ||||
if (missingInternal + missingExternal > 0) { | if (missingInternal + missingExternal > 0) { | ||||
WalletLogPrintf( | WalletLogPrintf( | ||||
"keypool added %d keys (%d internal), size=%u (%u internal)\n", | "keypool added %d keys (%d internal), size=%u (%u internal)\n", | ||||
missingInternal + missingExternal, missingInternal, | missingInternal + missingExternal, missingInternal, | ||||
setInternalKeyPool.size() + setExternalKeyPool.size() + | setInternalKeyPool.size() + setExternalKeyPool.size() + | ||||
set_pre_split_keypool.size(), | set_pre_split_keypool.size(), | ||||
setInternalKeyPool.size()); | setInternalKeyPool.size()); | ||||
} | } | ||||
} | |||||
NotifyCanGetAddressesChanged(); | |||||
return true; | return true; | ||||
} | } | ||||
bool CWallet::ReserveKeyFromKeyPool(int64_t &nIndex, CKeyPool &keypool, | bool CWallet::ReserveKeyFromKeyPool(int64_t &nIndex, CKeyPool &keypool, | ||||
bool fRequestedInternal) { | bool fRequestedInternal) { | ||||
nIndex = -1; | nIndex = -1; | ||||
keypool.vchPubKey = CPubKey(); | keypool.vchPubKey = CPubKey(); | ||||
{ | |||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
if (!IsLocked()) { | if (!IsLocked()) { | ||||
TopUpKeyPool(); | TopUpKeyPool(); | ||||
} | } | ||||
bool fReturningInternal = IsHDEnabled() && | bool fReturningInternal = IsHDEnabled() && | ||||
CanSupportFeature(FEATURE_HD_SPLIT) && | CanSupportFeature(FEATURE_HD_SPLIT) && | ||||
fRequestedInternal; | fRequestedInternal; | ||||
bool use_split_keypool = set_pre_split_keypool.empty(); | bool use_split_keypool = set_pre_split_keypool.empty(); | ||||
std::set<int64_t> &setKeyPool = | std::set<int64_t> &setKeyPool = | ||||
use_split_keypool | use_split_keypool | ||||
? (fReturningInternal ? setInternalKeyPool : setExternalKeyPool) | ? (fReturningInternal ? setInternalKeyPool : setExternalKeyPool) | ||||
: set_pre_split_keypool; | : set_pre_split_keypool; | ||||
// Get the oldest key | // Get the oldest key | ||||
if (setKeyPool.empty()) { | if (setKeyPool.empty()) { | ||||
return false; | return false; | ||||
} | } | ||||
WalletBatch batch(*database); | WalletBatch batch(*database); | ||||
auto it = setKeyPool.begin(); | auto it = setKeyPool.begin(); | ||||
nIndex = *it; | nIndex = *it; | ||||
setKeyPool.erase(it); | setKeyPool.erase(it); | ||||
if (!batch.ReadPool(nIndex, keypool)) { | if (!batch.ReadPool(nIndex, keypool)) { | ||||
throw std::runtime_error(std::string(__func__) + ": read failed"); | throw std::runtime_error(std::string(__func__) + ": read failed"); | ||||
} | } | ||||
if (!HaveKey(keypool.vchPubKey.GetID())) { | if (!HaveKey(keypool.vchPubKey.GetID())) { | ||||
throw std::runtime_error(std::string(__func__) + | throw std::runtime_error(std::string(__func__) + | ||||
": unknown key in key pool"); | ": unknown key in key pool"); | ||||
} | } | ||||
// If the key was pre-split keypool, we don't care about what type it is | // If the key was pre-split keypool, we don't care about what type it is | ||||
if (use_split_keypool && keypool.fInternal != fReturningInternal) { | if (use_split_keypool && keypool.fInternal != fReturningInternal) { | ||||
throw std::runtime_error(std::string(__func__) + | throw std::runtime_error(std::string(__func__) + | ||||
": keypool entry misclassified"); | ": keypool entry misclassified"); | ||||
} | } | ||||
if (!keypool.vchPubKey.IsValid()) { | if (!keypool.vchPubKey.IsValid()) { | ||||
throw std::runtime_error(std::string(__func__) + | throw std::runtime_error(std::string(__func__) + | ||||
": keypool entry invalid"); | ": keypool entry invalid"); | ||||
} | } | ||||
m_pool_key_to_index.erase(keypool.vchPubKey.GetID()); | m_pool_key_to_index.erase(keypool.vchPubKey.GetID()); | ||||
WalletLogPrintf("keypool reserve %d\n", nIndex); | WalletLogPrintf("keypool reserve %d\n", nIndex); | ||||
} | |||||
NotifyCanGetAddressesChanged(); | |||||
return true; | return true; | ||||
} | } | ||||
void CWallet::KeepKey(int64_t nIndex) { | void CWallet::KeepKey(int64_t nIndex) { | ||||
// Remove from key pool. | // Remove from key pool. | ||||
WalletBatch batch(*database); | WalletBatch batch(*database); | ||||
batch.ErasePool(nIndex); | batch.ErasePool(nIndex); | ||||
WalletLogPrintf("keypool keep %d\n", nIndex); | WalletLogPrintf("keypool keep %d\n", nIndex); | ||||
} | } | ||||
void CWallet::ReturnKey(int64_t nIndex, bool fInternal, const CPubKey &pubkey) { | void CWallet::ReturnKey(int64_t nIndex, bool fInternal, const CPubKey &pubkey) { | ||||
// Return to key pool | // Return to key pool | ||||
{ | { | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
if (fInternal) { | if (fInternal) { | ||||
setInternalKeyPool.insert(nIndex); | setInternalKeyPool.insert(nIndex); | ||||
} else if (!set_pre_split_keypool.empty()) { | } else if (!set_pre_split_keypool.empty()) { | ||||
set_pre_split_keypool.insert(nIndex); | set_pre_split_keypool.insert(nIndex); | ||||
} else { | } else { | ||||
setExternalKeyPool.insert(nIndex); | setExternalKeyPool.insert(nIndex); | ||||
} | } | ||||
m_pool_key_to_index[pubkey.GetID()] = nIndex; | m_pool_key_to_index[pubkey.GetID()] = nIndex; | ||||
NotifyCanGetAddressesChanged(); | |||||
} | } | ||||
WalletLogPrintf("keypool return %d\n", nIndex); | WalletLogPrintf("keypool return %d\n", nIndex); | ||||
} | } | ||||
bool CWallet::GetKeyFromPool(CPubKey &result, bool internal) { | bool CWallet::GetKeyFromPool(CPubKey &result, bool internal) { | ||||
if (IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { | if (IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { | ||||
return false; | return false; | ||||
▲ Show 20 Lines • Show All 1,134 Lines • Show Last 20 Lines |