Skip to content

Commit 754f134

Browse files
committed
wallet: Add error message to GetReservedDestination
Adds an error output parameter to all GetReservedDestination functions so that callers can get the actual reason that a change address could not be fetched. This more closely matches GetNewDestination. This allows for more granular error messages, such as one that indicates that bech32m addresses cannot be generated yet.
1 parent 87a0e7a commit 754f134

File tree

8 files changed

+21
-18
lines changed

8 files changed

+21
-18
lines changed

src/wallet/scriptpubkeyman.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -295,19 +295,22 @@ bool LegacyScriptPubKeyMan::Encrypt(const CKeyingMaterial& master_key, WalletBat
295295
return true;
296296
}
297297

298-
bool LegacyScriptPubKeyMan::GetReservedDestination(const OutputType type, bool internal, CTxDestination& address, int64_t& index, CKeyPool& keypool)
298+
bool LegacyScriptPubKeyMan::GetReservedDestination(const OutputType type, bool internal, CTxDestination& address, int64_t& index, CKeyPool& keypool, std::string& error)
299299
{
300300
if (LEGACY_OUTPUT_TYPES.count(type) == 0) {
301+
error = _("Error: Legacy wallets only support the \"legacy\", \"p2sh-segwit\", and \"bech32\" address types").translated;
301302
return false;
302303
}
303304
assert(type != OutputType::BECH32M);
304305

305306
LOCK(cs_KeyStore);
306307
if (!CanGetAddresses(internal)) {
308+
error = _("Error: Keypool ran out, please call keypoolrefill first").translated;
307309
return false;
308310
}
309311

310312
if (!ReserveKeyFromKeyPool(index, keypool, internal)) {
313+
error = _("Error: Keypool ran out, please call keypoolrefill first").translated;
311314
return false;
312315
}
313316
address = GetDestinationForKey(keypool.vchPubKey, type);
@@ -1720,10 +1723,9 @@ bool DescriptorScriptPubKeyMan::Encrypt(const CKeyingMaterial& master_key, Walle
17201723
return true;
17211724
}
17221725

1723-
bool DescriptorScriptPubKeyMan::GetReservedDestination(const OutputType type, bool internal, CTxDestination& address, int64_t& index, CKeyPool& keypool)
1726+
bool DescriptorScriptPubKeyMan::GetReservedDestination(const OutputType type, bool internal, CTxDestination& address, int64_t& index, CKeyPool& keypool, std::string& error)
17241727
{
17251728
LOCK(cs_desc_man);
1726-
std::string error;
17271729
bool result = GetNewDestination(type, address, error);
17281730
index = m_wallet_descriptor.next_index - 1;
17291731
return result;

src/wallet/scriptpubkeyman.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ class ScriptPubKeyMan
181181
virtual bool CheckDecryptionKey(const CKeyingMaterial& master_key, bool accept_no_keys = false) { return false; }
182182
virtual bool Encrypt(const CKeyingMaterial& master_key, WalletBatch* batch) { return false; }
183183

184-
virtual bool GetReservedDestination(const OutputType type, bool internal, CTxDestination& address, int64_t& index, CKeyPool& keypool) { return false; }
184+
virtual bool GetReservedDestination(const OutputType type, bool internal, CTxDestination& address, int64_t& index, CKeyPool& keypool, std::string& error) { return false; }
185185
virtual void KeepDestination(int64_t index, const OutputType& type) {}
186186
virtual void ReturnDestination(int64_t index, bool internal, const CTxDestination& addr) {}
187187

@@ -364,7 +364,7 @@ class LegacyScriptPubKeyMan : public ScriptPubKeyMan, public FillableSigningProv
364364
bool CheckDecryptionKey(const CKeyingMaterial& master_key, bool accept_no_keys = false) override;
365365
bool Encrypt(const CKeyingMaterial& master_key, WalletBatch* batch) override;
366366

367-
bool GetReservedDestination(const OutputType type, bool internal, CTxDestination& address, int64_t& index, CKeyPool& keypool) override;
367+
bool GetReservedDestination(const OutputType type, bool internal, CTxDestination& address, int64_t& index, CKeyPool& keypool, std::string& error) override;
368368
void KeepDestination(int64_t index, const OutputType& type) override;
369369
void ReturnDestination(int64_t index, bool internal, const CTxDestination&) override;
370370

@@ -573,7 +573,7 @@ class DescriptorScriptPubKeyMan : public ScriptPubKeyMan
573573
bool CheckDecryptionKey(const CKeyingMaterial& master_key, bool accept_no_keys = false) override;
574574
bool Encrypt(const CKeyingMaterial& master_key, WalletBatch* batch) override;
575575

576-
bool GetReservedDestination(const OutputType type, bool internal, CTxDestination& address, int64_t& index, CKeyPool& keypool) override;
576+
bool GetReservedDestination(const OutputType type, bool internal, CTxDestination& address, int64_t& index, CKeyPool& keypool, std::string& error) override;
577577
void ReturnDestination(int64_t index, bool internal, const CTxDestination& addr) override;
578578

579579
// Tops up the descriptor cache and m_map_script_pub_keys. The cache is stored in the wallet file

src/wallet/spend.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -618,8 +618,9 @@ bool CWallet::CreateTransactionInternal(
618618
// Reserve a new key pair from key pool. If it fails, provide a dummy
619619
// destination in case we don't need change.
620620
CTxDestination dest;
621-
if (!reservedest.GetReservedDestination(dest, true)) {
622-
error = _("Transaction needs a change address, but we can't generate it. Please call keypoolrefill first.");
621+
std::string dest_err;
622+
if (!reservedest.GetReservedDestination(dest, true, dest_err)) {
623+
error = strprintf(_("Transaction needs a change address, but we can't generate it. %s"), dest_err);
623624
}
624625
scriptChange = GetScriptForDestination(dest);
625626
// A valid destination implies a change script (and

src/wallet/wallet.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2118,7 +2118,7 @@ bool CWallet::GetNewDestination(const OutputType type, const std::string label,
21182118
spk_man->TopUp();
21192119
result = spk_man->GetNewDestination(type, dest, error);
21202120
} else {
2121-
error = strprintf("Error: No %s addresses available.", FormatOutputType(type));
2121+
error = strprintf(_("Error: No %s addresses available."), FormatOutputType(type)).translated;
21222122
}
21232123
if (result) {
21242124
SetAddressBook(dest, label, "receive");
@@ -2133,8 +2133,7 @@ bool CWallet::GetNewChangeDestination(const OutputType type, CTxDestination& des
21332133
error.clear();
21342134

21352135
ReserveDestination reservedest(this, type);
2136-
if (!reservedest.GetReservedDestination(dest, true)) {
2137-
error = _("Error: Keypool ran out, please call keypoolrefill first").translated;
2136+
if (!reservedest.GetReservedDestination(dest, true, error)) {
21382137
return false;
21392138
}
21402139

@@ -2181,10 +2180,11 @@ std::set<CTxDestination> CWallet::GetLabelAddresses(const std::string& label) co
21812180
return result;
21822181
}
21832182

2184-
bool ReserveDestination::GetReservedDestination(CTxDestination& dest, bool internal)
2183+
bool ReserveDestination::GetReservedDestination(CTxDestination& dest, bool internal, std::string& error)
21852184
{
21862185
m_spk_man = pwallet->GetScriptPubKeyMan(type, internal);
21872186
if (!m_spk_man) {
2187+
error = strprintf(_("Error: No %s addresses available."), FormatOutputType(type)).translated;
21882188
return false;
21892189
}
21902190

@@ -2194,7 +2194,7 @@ bool ReserveDestination::GetReservedDestination(CTxDestination& dest, bool inter
21942194
m_spk_man->TopUp();
21952195

21962196
CKeyPool keypool;
2197-
if (!m_spk_man->GetReservedDestination(type, internal, address, nIndex, keypool)) {
2197+
if (!m_spk_man->GetReservedDestination(type, internal, address, nIndex, keypool, error)) {
21982198
return false;
21992199
}
22002200
fInternal = keypool.fInternal;

src/wallet/wallet.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ class ReserveDestination
181181
}
182182

183183
//! Reserve an address
184-
bool GetReservedDestination(CTxDestination& pubkey, bool internal);
184+
bool GetReservedDestination(CTxDestination& pubkey, bool internal, std::string& error);
185185
//! Return reserved address
186186
void ReturnDestination();
187187
//! Keep the address. Do not return it's key to the keypool when this object goes out of scope

test/functional/rpc_fundrawtransaction.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -551,7 +551,7 @@ def test_locked_wallet(self):
551551
# creating the key must be impossible because the wallet is locked
552552
outputs = {self.nodes[0].getnewaddress():1.1}
553553
rawtx = self.nodes[1].createrawtransaction(inputs, outputs)
554-
assert_raises_rpc_error(-4, "Transaction needs a change address, but we can't generate it. Please call keypoolrefill first.", self.nodes[1].fundrawtransaction, rawtx)
554+
assert_raises_rpc_error(-4, "Transaction needs a change address, but we can't generate it.", self.nodes[1].fundrawtransaction, rawtx)
555555

556556
# Refill the keypool.
557557
self.nodes[1].walletpassphrase("test", 100)

test/functional/wallet_address_types.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -374,10 +374,10 @@ def run_test(self):
374374
self.test_address(4, self.nodes[4].getrawchangeaddress('bech32'), multisig=False, typ='bech32')
375375

376376
if self.options.descriptors:
377-
self.log.info("Descriptor wallets do not have bech32m addreses by default yet")
377+
self.log.info("Descriptor wallets do not have bech32m addresses by default yet")
378378
# TODO: Remove this when they do
379379
assert_raises_rpc_error(-12, "Error: No bech32m addresses available", self.nodes[0].getnewaddress, "", "bech32m")
380-
assert_raises_rpc_error(-12, "Error: Keypool ran out, please call keypoolrefill first", self.nodes[0].getrawchangeaddress, "bech32m")
380+
assert_raises_rpc_error(-12, "Error: No bech32m addresses available", self.nodes[0].getrawchangeaddress, "bech32m")
381381
else:
382382
self.log.info("Legacy wallets cannot make bech32m addresses")
383383
assert_raises_rpc_error(-8, "Legacy wallets cannot provide bech32m addresses", self.nodes[0].getnewaddress, "", "bech32m")

test/functional/wallet_keypool.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ def run_test(self):
161161

162162
# Using a fee rate (10 sat / byte) well above the minimum relay rate
163163
# creating a 5,000 sat transaction with change should not be possible
164-
assert_raises_rpc_error(-4, "Transaction needs a change address, but we can't generate it. Please call keypoolrefill first.", w2.walletcreatefundedpsbt, inputs=[], outputs=[{addr.pop(): 0.00005000}], options={"subtractFeeFromOutputs": [0], "feeRate": 0.00010})
164+
assert_raises_rpc_error(-4, "Transaction needs a change address, but we can't generate it.", w2.walletcreatefundedpsbt, inputs=[], outputs=[{addr.pop(): 0.00005000}], options={"subtractFeeFromOutputs": [0], "feeRate": 0.00010})
165165

166166
# creating a 10,000 sat transaction without change, with a manual input, should still be possible
167167
res = w2.walletcreatefundedpsbt(inputs=w2.listunspent(), outputs=[{destination: 0.00010000}], options={"subtractFeeFromOutputs": [0], "feeRate": 0.00010})

0 commit comments

Comments
 (0)