Changeset View
Changeset View
Standalone View
Standalone View
src/wallet/wallet.cpp
Show First 20 Lines • Show All 3,053 Lines • ▼ Show 20 Lines | txNew.nLockTime = GetLocktimeForNewTransaction(chain(), locked_chainIn); | ||||
// The drawback is that by not reusing a previous key, the | // The drawback is that by not reusing a previous key, the | ||||
// change may be lost if a backup is restored, if the backup | // change may be lost if a backup is restored, if the backup | ||||
// doesn't have the new private key for the change. If we | // doesn't have the new private key for the change. If we | ||||
// reused the old key, it would be possible to add code to look | // reused the old key, it would be possible to add code to look | ||||
// for and rediscover unknown transactions that were written | // for and rediscover unknown transactions that were written | ||||
// with keys of ours to recover post-backup change. | // with keys of ours to recover post-backup change. | ||||
// Reserve a new key pair from key pool | // Reserve a new key pair from key pool | ||||
if (IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { | if (!CanGetAddresses(true)) { | ||||
strFailReason = | strFailReason = | ||||
_("Can't generate a change-address key. Private keys " | _("Can't generate a change-address key. No keys in the " | ||||
"are disabled for this wallet.") | "internal keypool and can't generate any keys.") | ||||
.translated; | .translated; | ||||
return false; | return false; | ||||
} | } | ||||
CPubKey vchPubKey; | CPubKey vchPubKey; | ||||
bool ret; | bool ret; | ||||
ret = reservekey.GetReservedKey(vchPubKey, true); | ret = reservekey.GetReservedKey(vchPubKey, true); | ||||
if (!ret) { | if (!ret) { | ||||
strFailReason = | strFailReason = | ||||
▲ Show 20 Lines • Show All 608 Lines • ▼ Show 20 Lines | if (!CanGenerateKeys()) { | ||||
} | } | ||||
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? | |||||
assert(m_max_keypool_index < std::numeric_limits<int64_t>::max()); | |||||
int64_t index = ++m_max_keypool_index; | |||||
CPubKey pubkey(GenerateNewKey(batch, internal)); | CPubKey pubkey(GenerateNewKey(batch, internal)); | ||||
if (!batch.WritePool(index, CKeyPool(pubkey, internal))) { | AddKeypoolPubkeyWithDB(pubkey, internal, batch); | ||||
throw std::runtime_error(std::string(__func__) + | |||||
": writing generated key failed"); | |||||
} | |||||
if (internal) { | |||||
setInternalKeyPool.insert(index); | |||||
} else { | |||||
setExternalKeyPool.insert(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(); | NotifyCanGetAddressesChanged(); | ||||
return true; | return true; | ||||
} | } | ||||
void CWallet::AddKeypoolPubkey(const CPubKey &pubkey, const bool internal) { | |||||
WalletBatch batch(*database); | |||||
AddKeypoolPubkeyWithDB(pubkey, internal, batch); | |||||
NotifyCanGetAddressesChanged(); | |||||
} | |||||
void CWallet::AddKeypoolPubkeyWithDB(const CPubKey &pubkey, const bool internal, | |||||
WalletBatch &batch) { | |||||
LOCK(cs_wallet); | |||||
// How in the hell did you use so many keys? | |||||
assert(m_max_keypool_index < std::numeric_limits<int64_t>::max()); | |||||
int64_t index = ++m_max_keypool_index; | |||||
if (!batch.WritePool(index, CKeyPool(pubkey, internal))) { | |||||
throw std::runtime_error(std::string(__func__) + | |||||
": writing imported pubkey failed"); | |||||
} | |||||
if (internal) { | |||||
setInternalKeyPool.insert(index); | |||||
} else { | |||||
setExternalKeyPool.insert(index); | |||||
} | |||||
m_pool_key_to_index[pubkey.GetID()] = index; | |||||
} | |||||
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 = fRequestedInternal; | ||||
CanSupportFeature(FEATURE_HD_SPLIT) && | fReturningInternal &= | ||||
fRequestedInternal; | (IsHDEnabled() && CanSupportFeature(FEATURE_HD_SPLIT)) || | ||||
IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS); | |||||
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())) { | CPubKey pk; | ||||
if (!GetPubKey(keypool.vchPubKey.GetID(), pk)) { | |||||
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"); | ||||
} | } | ||||
Show All 37 Lines | |||||
bool CWallet::GetKeyFromPool(CPubKey &result, bool internal) { | bool CWallet::GetKeyFromPool(CPubKey &result, bool internal) { | ||||
if (!CanGetAddresses(internal)) { | if (!CanGetAddresses(internal)) { | ||||
return false; | return false; | ||||
} | } | ||||
CKeyPool keypool; | CKeyPool keypool; | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
int64_t nIndex; | int64_t nIndex; | ||||
if (!ReserveKeyFromKeyPool(nIndex, keypool, internal)) { | if (!ReserveKeyFromKeyPool(nIndex, keypool, internal) && | ||||
!IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { | |||||
if (IsLocked()) { | if (IsLocked()) { | ||||
return false; | return false; | ||||
} | } | ||||
WalletBatch batch(*database); | WalletBatch batch(*database); | ||||
result = GenerateNewKey(batch, internal); | result = GenerateNewKey(batch, internal); | ||||
return true; | return true; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 1,173 Lines • Show Last 20 Lines |