Skip to content

Commit 8d12860

Browse files
committed
Merge #16237: Have the wallet give out destinations instead of keys
8e7f930 Add GetNewChangeDestination for getting new change Destinations (Andrew Chow) 33d13ed Replace CReserveKey with ReserveDestinatoin (Andrew Chow) 172213b Add GetNewDestination to CWallet to fetch new destinations (Andrew Chow) Pull request description: The wallet should give out destinations instead of keys. It should be the one that handles the conversion from key to destination and the setting of the label, not the caller. In order to do this, two new member functions are introduced `GetNewDestination()` and `GetNewChangeDestination()`. Additionally, `CReserveKey` is changed to be `ReserveDestination` and represents destinations whose keys can be returned to the keypool. ACKs for top commit: instagibbs: re-utACK bitcoin/bitcoin@8e7f930 sipa: ACK 8e7f930. Concept ACK as this gives a much cleaner abstraction to work with, and light code review ACK. laanwj: ACK 8e7f930 Tree-SHA512: 5be7051409232b71e0ef2c1fd1a3e76964ed2f5b14d47d06edc2ad3b3687abd0be2803a1adc45c0433aa2c3bed172e14f8a7e9f4a23bff70f86260b5a0497500
2 parents 357488f + 8e7f930 commit 8d12860

File tree

10 files changed

+144
-121
lines changed

10 files changed

+144
-121
lines changed

src/interfaces/wallet.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ namespace {
3636
class PendingWalletTxImpl : public PendingWalletTx
3737
{
3838
public:
39-
explicit PendingWalletTxImpl(CWallet& wallet) : m_wallet(wallet), m_key(&wallet) {}
39+
explicit PendingWalletTxImpl(CWallet& wallet) : m_wallet(wallet), m_dest(&wallet) {}
4040

4141
const CTransaction& get() override { return *m_tx; }
4242

@@ -47,7 +47,7 @@ class PendingWalletTxImpl : public PendingWalletTx
4747
auto locked_chain = m_wallet.chain().lock();
4848
LOCK(m_wallet.cs_wallet);
4949
CValidationState state;
50-
if (!m_wallet.CommitTransaction(m_tx, std::move(value_map), std::move(order_form), m_key, state)) {
50+
if (!m_wallet.CommitTransaction(m_tx, std::move(value_map), std::move(order_form), m_dest, state)) {
5151
reject_reason = state.GetRejectReason();
5252
return false;
5353
}
@@ -56,7 +56,7 @@ class PendingWalletTxImpl : public PendingWalletTx
5656

5757
CTransactionRef m_tx;
5858
CWallet& m_wallet;
59-
CReserveKey m_key;
59+
ReserveDestination m_dest;
6060
};
6161

6262
//! Construct wallet tx struct.
@@ -140,9 +140,11 @@ class WalletImpl : public Wallet
140140
void abortRescan() override { m_wallet->AbortRescan(); }
141141
bool backupWallet(const std::string& filename) override { return m_wallet->BackupWallet(filename); }
142142
std::string getWalletName() override { return m_wallet->GetName(); }
143-
bool getKeyFromPool(bool internal, CPubKey& pub_key) override
143+
bool getNewDestination(const OutputType type, const std::string label, CTxDestination& dest) override
144144
{
145-
return m_wallet->GetKeyFromPool(pub_key, internal);
145+
LOCK(m_wallet->cs_wallet);
146+
std::string error;
147+
return m_wallet->GetNewDestination(type, label, dest, error);
146148
}
147149
bool getPubKey(const CKeyID& address, CPubKey& pub_key) override { return m_wallet->GetPubKey(address, pub_key); }
148150
bool getPrivKey(const CKeyID& address, CKey& key) override { return m_wallet->GetKey(address, key); }
@@ -236,7 +238,7 @@ class WalletImpl : public Wallet
236238
auto locked_chain = m_wallet->chain().lock();
237239
LOCK(m_wallet->cs_wallet);
238240
auto pending = MakeUnique<PendingWalletTxImpl>(*m_wallet);
239-
if (!m_wallet->CreateTransaction(*locked_chain, recipients, pending->m_tx, pending->m_key, fee, change_pos,
241+
if (!m_wallet->CreateTransaction(*locked_chain, recipients, pending->m_tx, pending->m_dest, fee, change_pos,
240242
fail_reason, coin_control, sign)) {
241243
return {};
242244
}

src/interfaces/wallet.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ class Wallet
7878
//! Get wallet name.
7979
virtual std::string getWalletName() = 0;
8080

81-
// Get key from pool.
82-
virtual bool getKeyFromPool(bool internal, CPubKey& pub_key) = 0;
81+
// Get a new address.
82+
virtual bool getNewDestination(const OutputType type, const std::string label, CTxDestination& dest) = 0;
8383

8484
//! Get public key.
8585
virtual bool getPubKey(const CKeyID& address, CPubKey& pub_key) = 0;

src/qt/addresstablemodel.cpp

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -358,12 +358,15 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con
358358
return QString();
359359
}
360360
}
361+
362+
// Add entry
363+
walletModel->wallet().setAddressBook(DecodeDestination(strAddress), strLabel, "send");
361364
}
362365
else if(type == Receive)
363366
{
364367
// Generate a new address to associate with given label
365-
CPubKey newKey;
366-
if(!walletModel->wallet().getKeyFromPool(false /* internal */, newKey))
368+
CTxDestination dest;
369+
if(!walletModel->wallet().getNewDestination(address_type, strLabel, dest))
367370
{
368371
WalletModel::UnlockContext ctx(walletModel->requestUnlock());
369372
if(!ctx.isValid())
@@ -372,23 +375,18 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con
372375
editStatus = WALLET_UNLOCK_FAILURE;
373376
return QString();
374377
}
375-
if(!walletModel->wallet().getKeyFromPool(false /* internal */, newKey))
378+
if(!walletModel->wallet().getNewDestination(address_type, strLabel, dest))
376379
{
377380
editStatus = KEY_GENERATION_FAILURE;
378381
return QString();
379382
}
380383
}
381-
walletModel->wallet().learnRelatedScripts(newKey, address_type);
382-
strAddress = EncodeDestination(GetDestinationForKey(newKey, address_type));
384+
strAddress = EncodeDestination(dest);
383385
}
384386
else
385387
{
386388
return QString();
387389
}
388-
389-
// Add entry
390-
walletModel->wallet().setAddressBook(DecodeDestination(strAddress), strLabel,
391-
(type == Send ? "send" : "receive"));
392390
return QString::fromStdString(strAddress);
393391
}
394392

src/qt/paymentserver.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -666,16 +666,14 @@ void PaymentServer::fetchPaymentACK(WalletModel* walletModel, const SendCoinsRec
666666
payment.add_transactions(transaction.data(), transaction.size());
667667

668668
// Create a new refund address, or re-use:
669-
CPubKey newKey;
670-
if (walletModel->wallet().getKeyFromPool(false /* internal */, newKey)) {
669+
CTxDestination dest;
670+
const OutputType change_type = walletModel->wallet().getDefaultChangeType() != OutputType::CHANGE_AUTO ? walletModel->wallet().getDefaultChangeType() : walletModel->wallet().getDefaultAddressType();
671+
if (walletModel->wallet().getNewDestination(change_type, "", dest)) {
671672
// BIP70 requests encode the scriptPubKey directly, so we are not restricted to address
672673
// types supported by the receiver. As a result, we choose the address format we also
673674
// use for change. Despite an actual payment and not change, this is a close match:
674675
// it's the output type we use subject to privacy issues, but not restricted by what
675676
// other software supports.
676-
const OutputType change_type = walletModel->wallet().getDefaultChangeType() != OutputType::CHANGE_AUTO ? walletModel->wallet().getDefaultChangeType() : walletModel->wallet().getDefaultAddressType();
677-
walletModel->wallet().learnRelatedScripts(newKey, change_type);
678-
CTxDestination dest = GetDestinationForKey(newKey, change_type);
679677
std::string label = tr("Refund from %1").arg(recipient.authenticatedMerchant).toStdString();
680678
walletModel->wallet().setAddressBook(dest, label, "refund");
681679

src/test/util.cpp

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,9 @@ const std::string ADDRESS_BCRT1_UNSPENDABLE = "bcrt1qqqqqqqqqqqqqqqqqqqqqqqqqqqq
2323
std::string getnewaddress(CWallet& w)
2424
{
2525
constexpr auto output_type = OutputType::BECH32;
26-
27-
CPubKey new_key;
28-
if (!w.GetKeyFromPool(new_key)) assert(false);
29-
30-
w.LearnRelatedScripts(new_key, output_type);
31-
const auto dest = GetDestinationForKey(new_key, output_type);
32-
33-
w.SetAddressBook(dest, /* label */ "", "receive");
26+
CTxDestination dest;
27+
std::string error;
28+
if (!w.GetNewDestination(output_type, "", dest, error)) assert(false);
3429

3530
return EncodeDestination(dest);
3631
}

src/wallet/feebumper.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -272,17 +272,17 @@ Result CreateRateBumpTransaction(CWallet* wallet, const uint256& txid, const CCo
272272
new_coin_control.m_min_depth = 1;
273273

274274
CTransactionRef tx_new = MakeTransactionRef();
275-
CReserveKey reservekey(wallet);
275+
ReserveDestination reservedest(wallet);
276276
CAmount fee_ret;
277277
int change_pos_in_out = -1; // No requested location for change
278278
std::string fail_reason;
279-
if (!wallet->CreateTransaction(*locked_chain, recipients, tx_new, reservekey, fee_ret, change_pos_in_out, fail_reason, new_coin_control, false)) {
279+
if (!wallet->CreateTransaction(*locked_chain, recipients, tx_new, reservedest, fee_ret, change_pos_in_out, fail_reason, new_coin_control, false)) {
280280
errors.push_back("Unable to create transaction: " + fail_reason);
281281
return Result::WALLET_ERROR;
282282
}
283283

284284
// If change key hasn't been ReturnKey'ed by this point, we take it out of keypool
285-
reservekey.KeepKey();
285+
reservedest.KeepDestination();
286286

287287
// Write back new fee if successful
288288
new_fee = fee_ret;
@@ -330,9 +330,9 @@ Result CommitTransaction(CWallet* wallet, const uint256& txid, CMutableTransacti
330330
mapValue_t mapValue = oldWtx.mapValue;
331331
mapValue["replaces_txid"] = oldWtx.GetHash().ToString();
332332

333-
CReserveKey reservekey(wallet);
333+
ReserveDestination reservedest(wallet);
334334
CValidationState state;
335-
if (!wallet->CommitTransaction(tx, std::move(mapValue), oldWtx.vOrderForm, reservekey, state)) {
335+
if (!wallet->CommitTransaction(tx, std::move(mapValue), oldWtx.vOrderForm, reservedest, state)) {
336336
// NOTE: CommitTransaction never returns false, so this should never happen.
337337
errors.push_back(strprintf("The transaction was rejected: %s", FormatStateMessage(state)));
338338
return Result::WALLET_ERROR;

src/wallet/rpcwallet.cpp

Lines changed: 15 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -194,19 +194,11 @@ static UniValue getnewaddress(const JSONRPCRequest& request)
194194
}
195195
}
196196

197-
if (!pwallet->IsLocked()) {
198-
pwallet->TopUpKeyPool();
199-
}
200-
201-
// Generate a new key that is added to wallet
202-
CPubKey newKey;
203-
if (!pwallet->GetKeyFromPool(newKey)) {
204-
throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
197+
CTxDestination dest;
198+
std::string error;
199+
if (!pwallet->GetNewDestination(output_type, label, dest, error)) {
200+
throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, error);
205201
}
206-
pwallet->LearnRelatedScripts(newKey, output_type);
207-
CTxDestination dest = GetDestinationForKey(newKey, output_type);
208-
209-
pwallet->SetAddressBook(dest, label, "receive");
210202

211203
return EncodeDestination(dest);
212204
}
@@ -241,27 +233,18 @@ static UniValue getrawchangeaddress(const JSONRPCRequest& request)
241233
throw JSONRPCError(RPC_WALLET_ERROR, "Error: This wallet has no available keys");
242234
}
243235

244-
if (!pwallet->IsLocked()) {
245-
pwallet->TopUpKeyPool();
246-
}
247-
248236
OutputType output_type = pwallet->m_default_change_type != OutputType::CHANGE_AUTO ? pwallet->m_default_change_type : pwallet->m_default_address_type;
249237
if (!request.params[0].isNull()) {
250238
if (!ParseOutputType(request.params[0].get_str(), output_type)) {
251239
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[0].get_str()));
252240
}
253241
}
254242

255-
CReserveKey reservekey(pwallet);
256-
CPubKey vchPubKey;
257-
if (!reservekey.GetReservedKey(vchPubKey, true))
258-
throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
259-
260-
reservekey.KeepKey();
261-
262-
pwallet->LearnRelatedScripts(vchPubKey, output_type);
263-
CTxDestination dest = GetDestinationForKey(vchPubKey, output_type);
264-
243+
CTxDestination dest;
244+
std::string error;
245+
if (!pwallet->GetNewChangeDestination(output_type, dest, error)) {
246+
throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, error);
247+
}
265248
return EncodeDestination(dest);
266249
}
267250

@@ -326,21 +309,21 @@ static CTransactionRef SendMoney(interfaces::Chain::Lock& locked_chain, CWallet
326309
CScript scriptPubKey = GetScriptForDestination(address);
327310

328311
// Create and send the transaction
329-
CReserveKey reservekey(pwallet);
312+
ReserveDestination reservedest(pwallet);
330313
CAmount nFeeRequired;
331314
std::string strError;
332315
std::vector<CRecipient> vecSend;
333316
int nChangePosRet = -1;
334317
CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount};
335318
vecSend.push_back(recipient);
336319
CTransactionRef tx;
337-
if (!pwallet->CreateTransaction(locked_chain, vecSend, tx, reservekey, nFeeRequired, nChangePosRet, strError, coin_control)) {
320+
if (!pwallet->CreateTransaction(locked_chain, vecSend, tx, reservedest, nFeeRequired, nChangePosRet, strError, coin_control)) {
338321
if (!fSubtractFeeFromAmount && nValue + nFeeRequired > curBalance)
339322
strError = strprintf("Error: This transaction requires a transaction fee of at least %s", FormatMoney(nFeeRequired));
340323
throw JSONRPCError(RPC_WALLET_ERROR, strError);
341324
}
342325
CValidationState state;
343-
if (!pwallet->CommitTransaction(tx, std::move(mapValue), {} /* orderForm */, reservekey, state)) {
326+
if (!pwallet->CommitTransaction(tx, std::move(mapValue), {} /* orderForm */, reservedest, state)) {
344327
strError = strprintf("Error: The transaction was rejected! Reason given: %s", FormatStateMessage(state));
345328
throw JSONRPCError(RPC_WALLET_ERROR, strError);
346329
}
@@ -924,16 +907,16 @@ static UniValue sendmany(const JSONRPCRequest& request)
924907
std::shuffle(vecSend.begin(), vecSend.end(), FastRandomContext());
925908

926909
// Send
927-
CReserveKey keyChange(pwallet);
910+
ReserveDestination changedest(pwallet);
928911
CAmount nFeeRequired = 0;
929912
int nChangePosRet = -1;
930913
std::string strFailReason;
931914
CTransactionRef tx;
932-
bool fCreated = pwallet->CreateTransaction(*locked_chain, vecSend, tx, keyChange, nFeeRequired, nChangePosRet, strFailReason, coin_control);
915+
bool fCreated = pwallet->CreateTransaction(*locked_chain, vecSend, tx, changedest, nFeeRequired, nChangePosRet, strFailReason, coin_control);
933916
if (!fCreated)
934917
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason);
935918
CValidationState state;
936-
if (!pwallet->CommitTransaction(tx, std::move(mapValue), {} /* orderForm */, keyChange, state)) {
919+
if (!pwallet->CommitTransaction(tx, std::move(mapValue), {} /* orderForm */, changedest, state)) {
937920
strFailReason = strprintf("Transaction commit failed:: %s", FormatStateMessage(state));
938921
throw JSONRPCError(RPC_WALLET_ERROR, strFailReason);
939922
}

src/wallet/test/wallet_tests.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -361,17 +361,17 @@ class ListCoinsTestingSetup : public TestChain100Setup
361361
CWalletTx& AddTx(CRecipient recipient)
362362
{
363363
CTransactionRef tx;
364-
CReserveKey reservekey(wallet.get());
364+
ReserveDestination reservedest(wallet.get());
365365
CAmount fee;
366366
int changePos = -1;
367367
std::string error;
368368
CCoinControl dummy;
369369
{
370370
auto locked_chain = m_chain->lock();
371-
BOOST_CHECK(wallet->CreateTransaction(*locked_chain, {recipient}, tx, reservekey, fee, changePos, error, dummy));
371+
BOOST_CHECK(wallet->CreateTransaction(*locked_chain, {recipient}, tx, reservedest, fee, changePos, error, dummy));
372372
}
373373
CValidationState state;
374-
BOOST_CHECK(wallet->CommitTransaction(tx, {}, {}, reservekey, state));
374+
BOOST_CHECK(wallet->CommitTransaction(tx, {}, {}, reservedest, state));
375375
CMutableTransaction blocktx;
376376
{
377377
LOCK(wallet->cs_wallet);
@@ -464,8 +464,9 @@ BOOST_FIXTURE_TEST_CASE(wallet_disableprivkeys, TestChain100Setup)
464464
wallet->SetMinVersion(FEATURE_LATEST);
465465
wallet->SetWalletFlag(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
466466
BOOST_CHECK(!wallet->TopUpKeyPool(1000));
467-
CPubKey pubkey;
468-
BOOST_CHECK(!wallet->GetKeyFromPool(pubkey, false));
467+
CTxDestination dest;
468+
std::string error;
469+
BOOST_CHECK(!wallet->GetNewDestination(OutputType::BECH32, "", dest, error));
469470
}
470471

471472
// Explicit calculation which is used to test the wallet constant

0 commit comments

Comments
 (0)