Skip to content

Commit 756cade

Browse files
laanwjproteanx
authored andcommitted
Merge #13252: Wallet: Refactor ReserveKeyFromKeyPool for safety
Summary: 4b62bdf5136c174621509bf7866fbd89b61cc66a Wallet: Refactor ReserveKeyFromKeyPool for safety (Ben Woosley) Pull request description: ReserveKeyFromKeyPool's previous behaviour is to set nIndex to -1 if the keypool is empty, OR throw an exception for technical failures. Instead, we now return false if the keypool is empty, true if the operation succeeded. This is to make failure more easily detectable by calling code. Tree-SHA512: 753f057ad13bd4c28d121f426bf0967ed72b827d97fb24582f9326ec60072abc5482e3db69ccada7c5fc66de9957fc59098432dd223fc4116991cab44c6d7aef Backport of Core PR13252 bitcoin/bitcoin#13252 Depends on D4207 Test Plan: make check test_runner.py Reviewers: deadalnix, Fabien, jasonbcox, O1 Bitcoin ABC, #bitcoin_abc Reviewed By: deadalnix, O1 Bitcoin ABC, #bitcoin_abc Differential Revision: https://reviews.bitcoinabc.org/D4166
1 parent 04d1a4c commit 756cade

File tree

2 files changed

+33
-13
lines changed

2 files changed

+33
-13
lines changed

src/wallet/wallet.cpp

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4150,7 +4150,7 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize) {
41504150
return true;
41514151
}
41524152

4153-
void CWallet::ReserveKeyFromKeyPool(int64_t &nIndex, CKeyPool &keypool,
4153+
bool CWallet::ReserveKeyFromKeyPool(int64_t &nIndex, CKeyPool &keypool,
41544154
bool fRequestedInternal) {
41554155
nIndex = -1;
41564156
keypool.vchPubKey = CPubKey();
@@ -4161,12 +4161,11 @@ void CWallet::ReserveKeyFromKeyPool(int64_t &nIndex, CKeyPool &keypool,
41614161
TopUpKeyPool();
41624162
}
41634163
bool fReturningInternal = fRequestedInternal;
4164-
std::set<int64_t> &setKeyPool =
4165-
fReturningInternal ? setInternalKeyPool : setExternalKeyPool;
4164+
std::set<int64_t> &setKeyPool = (fReturningInternal) ? setInternalKeyPool : setExternalKeyPool;
41664165

41674166
// Get the oldest key
41684167
if (setKeyPool.empty()) {
4169-
return;
4168+
return false;
41704169
}
41714170

41724171
WalletBatch batch(*database);
@@ -4193,13 +4192,21 @@ void CWallet::ReserveKeyFromKeyPool(int64_t &nIndex, CKeyPool &keypool,
41934192
} else {
41944193
m_pool_key_to_index.erase(keypool.vchPubKey.GetKeyID());
41954194
}
4196-
4197-
4198-
if (keypool.fInternal != fReturningInternal) {
4195+
// If the key was pre-split keypool, we don't care about what type it is
4196+
/*
4197+
if (use_split_keypool && keypool.fInternal != fReturningInternal) {
41994198
throw std::runtime_error(std::string(__func__) +
42004199
": keypool entry misclassified");
42014200
}
4201+
*/
4202+
if (!keypool.vchPubKey.IsValid()) {
4203+
throw std::runtime_error(std::string(__func__) +
4204+
": keypool entry invalid");
4205+
}
4206+
42024207
LogPrintf("keypool reserve %d\n", nIndex);
4208+
4209+
return true;
42034210
}
42044211

42054212
void CWallet::KeepKey(int64_t nIndex) {
@@ -4230,9 +4237,8 @@ void CWallet::ReturnKey(int64_t nIndex, bool fInternal, const CPubKey &pubkey) {
42304237
bool CWallet::GetKeyFromPool(CPubKey &result, bool internal) {
42314238
CKeyPool keypool;
42324239
LOCK(cs_wallet);
4233-
int64_t nIndex = 0;
4234-
ReserveKeyFromKeyPool(nIndex, keypool, internal);
4235-
if (nIndex == -1) {
4240+
int64_t nIndex;
4241+
if (!ReserveKeyFromKeyPool(nIndex, keypool, internal)) {
42364242
if (IsLocked()) {
42374243
return false;
42384244
}
@@ -4475,8 +4481,7 @@ CWallet::GetLabelAddresses(const std::string &label) const {
44754481
bool CReserveKey::GetReservedKey(CPubKey &pubkey, bool internal) {
44764482
if (nIndex == -1) {
44774483
CKeyPool keypool;
4478-
pwallet->ReserveKeyFromKeyPool(nIndex, keypool, internal);
4479-
if (nIndex == -1) {
4484+
if (!pwallet->ReserveKeyFromKeyPool(nIndex, keypool, internal)) {
44804485
return false;
44814486
}
44824487

src/wallet/wallet.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1075,7 +1075,22 @@ class CWallet final : public CCryptoKeyStore, public CValidationInterface {
10751075
bool NewKeyPool();
10761076
size_t KeypoolCountExternalKeys() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
10771077
bool TopUpKeyPool(unsigned int kpSize = 0);
1078-
void ReserveKeyFromKeyPool(int64_t &nIndex, CKeyPool &keypool,
1078+
1079+
/**
1080+
* Reserves a key from the keypool and sets nIndex to its index
1081+
*
1082+
* @param[out] nIndex the index of the key in keypool
1083+
* @param[out] keypool the keypool the key was drawn from, which could be
1084+
* the the pre-split pool if present, or the internal or external pool
1085+
* @param fRequestedInternal true if the caller would like the key drawn
1086+
* from the internal keypool, false if external is preferred
1087+
*
1088+
* @return true if succeeded, false if failed due to empty keypool
1089+
* @throws std::runtime_error if keypool read failed, key was invalid,
1090+
* was not found in the wallet, or was misclassified in the internal
1091+
* or external keypool
1092+
*/
1093+
bool ReserveKeyFromKeyPool(int64_t &nIndex, CKeyPool &keypool,
10791094
bool fRequestedInternal);
10801095
void KeepKey(int64_t nIndex);
10811096
void ReturnKey(int64_t nIndex, bool fInternal, const CPubKey &pubkey);

0 commit comments

Comments
 (0)