Skip to content

Commit a16a0fd

Browse files
laanwjjonspock
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 022d94b commit a16a0fd

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
@@ -4135,7 +4135,7 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize) {
41354135
return true;
41364136
}
41374137

4138-
void CWallet::ReserveKeyFromKeyPool(int64_t &nIndex, CKeyPool &keypool,
4138+
bool CWallet::ReserveKeyFromKeyPool(int64_t &nIndex, CKeyPool &keypool,
41394139
bool fRequestedInternal) {
41404140
nIndex = -1;
41414141
keypool.vchPubKey = CPubKey();
@@ -4146,12 +4146,11 @@ void CWallet::ReserveKeyFromKeyPool(int64_t &nIndex, CKeyPool &keypool,
41464146
TopUpKeyPool();
41474147
}
41484148
bool fReturningInternal = fRequestedInternal;
4149-
std::set<int64_t> &setKeyPool =
4150-
fReturningInternal ? setInternalKeyPool : setExternalKeyPool;
4149+
std::set<int64_t> &setKeyPool = (fReturningInternal) ? setInternalKeyPool : setExternalKeyPool;
41514150

41524151
// Get the oldest key
41534152
if (setKeyPool.empty()) {
4154-
return;
4153+
return false;
41554154
}
41564155

41574156
WalletBatch batch(*database);
@@ -4178,13 +4177,21 @@ void CWallet::ReserveKeyFromKeyPool(int64_t &nIndex, CKeyPool &keypool,
41784177
} else {
41794178
m_pool_key_to_index.erase(keypool.vchPubKey.GetKeyID());
41804179
}
4181-
4182-
4183-
if (keypool.fInternal != fReturningInternal) {
4180+
// If the key was pre-split keypool, we don't care about what type it is
4181+
/*
4182+
if (use_split_keypool && keypool.fInternal != fReturningInternal) {
41844183
throw std::runtime_error(std::string(__func__) +
41854184
": keypool entry misclassified");
41864185
}
4186+
*/
4187+
if (!keypool.vchPubKey.IsValid()) {
4188+
throw std::runtime_error(std::string(__func__) +
4189+
": keypool entry invalid");
4190+
}
4191+
41874192
LogPrintf("keypool reserve %d\n", nIndex);
4193+
4194+
return true;
41884195
}
41894196

41904197
void CWallet::KeepKey(int64_t nIndex) {
@@ -4215,9 +4222,8 @@ void CWallet::ReturnKey(int64_t nIndex, bool fInternal, const CPubKey &pubkey) {
42154222
bool CWallet::GetKeyFromPool(CPubKey &result, bool internal) {
42164223
CKeyPool keypool;
42174224
LOCK(cs_wallet);
4218-
int64_t nIndex = 0;
4219-
ReserveKeyFromKeyPool(nIndex, keypool, internal);
4220-
if (nIndex == -1) {
4225+
int64_t nIndex;
4226+
if (!ReserveKeyFromKeyPool(nIndex, keypool, internal)) {
42214227
if (IsLocked()) {
42224228
return false;
42234229
}
@@ -4460,8 +4466,7 @@ CWallet::GetLabelAddresses(const std::string &label) const {
44604466
bool CReserveKey::GetReservedKey(CPubKey &pubkey, bool internal) {
44614467
if (nIndex == -1) {
44624468
CKeyPool keypool;
4463-
pwallet->ReserveKeyFromKeyPool(nIndex, keypool, internal);
4464-
if (nIndex == -1) {
4469+
if (!pwallet->ReserveKeyFromKeyPool(nIndex, keypool, internal)) {
44654470
return false;
44664471
}
44674472

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)