Skip to content

Commit 5ad79b2

Browse files
committed
Merge bitcoin/bitcoin#32593: wallet, rpc: Move (Un)LockCoin WalletBatch creation out of RPC
6135e05 wallet, rpc: Move (Un)LockCoin WalletBatch creation out of RPC (Ava Chow) Pull request description: If the locked coin needs to be persisted to the wallet database, insteead of having the RPC figure out when to create a WalletBatch and having LockCoin's behavior depend on it, have LockCoin take whether to persist as a parameter so it makes the batch. Since unlocking a persisted locked coin requires a database write as well, we need to track whether the locked coin was persisted to the wallet database so that it can erase the locked coin when necessary. Keeping track of whether a locked coin was persisted is also useful information for future PRs. Split from #32489 ACKs for top commit: rkrux: ACK 6135e05 Sjors: ACK 6135e05 w0xlt: ACK bitcoin/bitcoin@6135e05 Tree-SHA512: 0e2367fc4d50c62ec41443374b64c4c5ecf679998677df47fb8776cfb44704713bc45547e32e96cd30d1dbed766f5d333efb6f10eb0e71271606638e07e61a01
2 parents e17fb86 + 6135e05 commit 5ad79b2

File tree

8 files changed

+49
-47
lines changed

8 files changed

+49
-47
lines changed

src/wallet/interfaces.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -249,14 +249,12 @@ class WalletImpl : public Wallet
249249
bool lockCoin(const COutPoint& output, const bool write_to_db) override
250250
{
251251
LOCK(m_wallet->cs_wallet);
252-
std::unique_ptr<WalletBatch> batch = write_to_db ? std::make_unique<WalletBatch>(m_wallet->GetDatabase()) : nullptr;
253-
return m_wallet->LockCoin(output, batch.get());
252+
return m_wallet->LockCoin(output, write_to_db);
254253
}
255254
bool unlockCoin(const COutPoint& output) override
256255
{
257256
LOCK(m_wallet->cs_wallet);
258-
std::unique_ptr<WalletBatch> batch = std::make_unique<WalletBatch>(m_wallet->GetDatabase());
259-
return m_wallet->UnlockCoin(output, batch.get());
257+
return m_wallet->UnlockCoin(output);
260258
}
261259
bool isLockedCoin(const COutPoint& output) override
262260
{

src/wallet/rpc/coins.cpp

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -331,16 +331,12 @@ RPCHelpMan lockunspent()
331331
outputs.push_back(outpt);
332332
}
333333

334-
std::unique_ptr<WalletBatch> batch = nullptr;
335-
// Unlock is always persistent
336-
if (fUnlock || persistent) batch = std::make_unique<WalletBatch>(pwallet->GetDatabase());
337-
338334
// Atomically set (un)locked status for the outputs.
339335
for (const COutPoint& outpt : outputs) {
340336
if (fUnlock) {
341-
if (!pwallet->UnlockCoin(outpt, batch.get())) throw JSONRPCError(RPC_WALLET_ERROR, "Unlocking coin failed");
337+
if (!pwallet->UnlockCoin(outpt)) throw JSONRPCError(RPC_WALLET_ERROR, "Unlocking coin failed");
342338
} else {
343-
if (!pwallet->LockCoin(outpt, batch.get())) throw JSONRPCError(RPC_WALLET_ERROR, "Locking coin failed");
339+
if (!pwallet->LockCoin(outpt, persistent)) throw JSONRPCError(RPC_WALLET_ERROR, "Locking coin failed");
344340
}
345341
}
346342

src/wallet/rpc/spend.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1561,7 +1561,7 @@ RPCHelpMan sendall()
15611561
const bool lock_unspents{options.exists("lock_unspents") ? options["lock_unspents"].get_bool() : false};
15621562
if (lock_unspents) {
15631563
for (const CTxIn& txin : rawTx.vin) {
1564-
pwallet->LockCoin(txin.prevout);
1564+
pwallet->LockCoin(txin.prevout, /*persist=*/false);
15651565
}
15661566
}
15671567

src/wallet/spend.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1472,7 +1472,7 @@ util::Result<CreatedTransactionResult> FundTransaction(CWallet& wallet, const CM
14721472

14731473
if (lockUnspents) {
14741474
for (const CTxIn& txin : res->tx->vin) {
1475-
wallet.LockCoin(txin.prevout);
1475+
wallet.LockCoin(txin.prevout, /*persist=*/false);
14761476
}
14771477
}
14781478

src/wallet/test/wallet_tests.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,7 @@ BOOST_FIXTURE_TEST_CASE(ListCoinsTest, ListCoinsTestingSetup)
429429
for (const auto& group : list) {
430430
for (const auto& coin : group.second) {
431431
LOCK(wallet->cs_wallet);
432-
wallet->LockCoin(coin.outpoint);
432+
wallet->LockCoin(coin.outpoint, /*persist=*/false);
433433
}
434434
}
435435
{
@@ -457,7 +457,7 @@ void TestCoinsResult(ListCoinsTest& context, OutputType out_type, CAmount amount
457457
filter.skip_locked = false;
458458
CoinsResult available_coins = AvailableCoins(*context.wallet, nullptr, std::nullopt, filter);
459459
// Lock outputs so they are not spent in follow-up transactions
460-
for (uint32_t i = 0; i < wtx.tx->vout.size(); i++) context.wallet->LockCoin({wtx.GetHash(), i});
460+
for (uint32_t i = 0; i < wtx.tx->vout.size(); i++) context.wallet->LockCoin({wtx.GetHash(), i}, /*persist=*/false);
461461
for (const auto& [type, size] : expected_coins_sizes) BOOST_CHECK_EQUAL(size, available_coins.coins[type].size());
462462
}
463463

src/wallet/wallet.cpp

Lines changed: 31 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -754,30 +754,25 @@ bool CWallet::IsSpent(const COutPoint& outpoint) const
754754
return false;
755755
}
756756

757-
void CWallet::AddToSpends(const COutPoint& outpoint, const Txid& txid, WalletBatch* batch)
757+
void CWallet::AddToSpends(const COutPoint& outpoint, const Txid& txid)
758758
{
759759
mapTxSpends.insert(std::make_pair(outpoint, txid));
760760

761-
if (batch) {
762-
UnlockCoin(outpoint, batch);
763-
} else {
764-
WalletBatch temp_batch(GetDatabase());
765-
UnlockCoin(outpoint, &temp_batch);
766-
}
761+
UnlockCoin(outpoint);
767762

768763
std::pair<TxSpends::iterator, TxSpends::iterator> range;
769764
range = mapTxSpends.equal_range(outpoint);
770765
SyncMetaData(range);
771766
}
772767

773768

774-
void CWallet::AddToSpends(const CWalletTx& wtx, WalletBatch* batch)
769+
void CWallet::AddToSpends(const CWalletTx& wtx)
775770
{
776771
if (wtx.IsCoinBase()) // Coinbases don't spend anything!
777772
return;
778773

779774
for (const CTxIn& txin : wtx.tx->vin)
780-
AddToSpends(txin.prevout, wtx.GetHash(), batch);
775+
AddToSpends(txin.prevout, wtx.GetHash());
781776
}
782777

783778
bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
@@ -1030,7 +1025,7 @@ CWalletTx* CWallet::AddToWallet(CTransactionRef tx, const TxState& state, const
10301025
wtx.nOrderPos = IncOrderPosNext(&batch);
10311026
wtx.m_it_wtxOrdered = wtxOrdered.insert(std::make_pair(wtx.nOrderPos, &wtx));
10321027
wtx.nTimeSmart = ComputeTimeSmart(wtx, rescanning_old_block);
1033-
AddToSpends(wtx, &batch);
1028+
AddToSpends(wtx);
10341029

10351030
// Update birth time when tx time is older than it.
10361031
MaybeUpdateBirthTime(wtx.GetTxTime());
@@ -2587,22 +2582,34 @@ util::Result<void> CWallet::DisplayAddress(const CTxDestination& dest)
25872582
return util::Error{_("There is no ScriptPubKeyManager for this address")};
25882583
}
25892584

2590-
bool CWallet::LockCoin(const COutPoint& output, WalletBatch* batch)
2585+
void CWallet::LoadLockedCoin(const COutPoint& coin, bool persistent)
25912586
{
25922587
AssertLockHeld(cs_wallet);
2593-
setLockedCoins.insert(output);
2594-
if (batch) {
2595-
return batch->WriteLockedUTXO(output);
2588+
m_locked_coins.emplace(coin, persistent);
2589+
}
2590+
2591+
bool CWallet::LockCoin(const COutPoint& output, bool persist)
2592+
{
2593+
AssertLockHeld(cs_wallet);
2594+
LoadLockedCoin(output, persist);
2595+
if (persist) {
2596+
WalletBatch batch(GetDatabase());
2597+
return batch.WriteLockedUTXO(output);
25962598
}
25972599
return true;
25982600
}
25992601

2600-
bool CWallet::UnlockCoin(const COutPoint& output, WalletBatch* batch)
2602+
bool CWallet::UnlockCoin(const COutPoint& output)
26012603
{
26022604
AssertLockHeld(cs_wallet);
2603-
bool was_locked = setLockedCoins.erase(output);
2604-
if (batch && was_locked) {
2605-
return batch->EraseLockedUTXO(output);
2605+
auto locked_coin_it = m_locked_coins.find(output);
2606+
if (locked_coin_it != m_locked_coins.end()) {
2607+
bool persisted = locked_coin_it->second;
2608+
m_locked_coins.erase(locked_coin_it);
2609+
if (persisted) {
2610+
WalletBatch batch(GetDatabase());
2611+
return batch.EraseLockedUTXO(output);
2612+
}
26062613
}
26072614
return true;
26082615
}
@@ -2612,26 +2619,24 @@ bool CWallet::UnlockAllCoins()
26122619
AssertLockHeld(cs_wallet);
26132620
bool success = true;
26142621
WalletBatch batch(GetDatabase());
2615-
for (auto it = setLockedCoins.begin(); it != setLockedCoins.end(); ++it) {
2616-
success &= batch.EraseLockedUTXO(*it);
2622+
for (const auto& [coin, persistent] : m_locked_coins) {
2623+
if (persistent) success = success && batch.EraseLockedUTXO(coin);
26172624
}
2618-
setLockedCoins.clear();
2625+
m_locked_coins.clear();
26192626
return success;
26202627
}
26212628

26222629
bool CWallet::IsLockedCoin(const COutPoint& output) const
26232630
{
26242631
AssertLockHeld(cs_wallet);
2625-
return setLockedCoins.count(output) > 0;
2632+
return m_locked_coins.count(output) > 0;
26262633
}
26272634

26282635
void CWallet::ListLockedCoins(std::vector<COutPoint>& vOutpts) const
26292636
{
26302637
AssertLockHeld(cs_wallet);
2631-
for (std::set<COutPoint>::iterator it = setLockedCoins.begin();
2632-
it != setLockedCoins.end(); it++) {
2633-
COutPoint outpt = (*it);
2634-
vOutpts.push_back(outpt);
2638+
for (const auto& [coin, _] : m_locked_coins) {
2639+
vOutpts.push_back(coin);
26352640
}
26362641
}
26372642

src/wallet/wallet.h

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -343,8 +343,8 @@ class CWallet final : public WalletStorage, public interfaces::Chain::Notificati
343343
*/
344344
typedef std::unordered_multimap<COutPoint, Txid, SaltedOutpointHasher> TxSpends;
345345
TxSpends mapTxSpends GUARDED_BY(cs_wallet);
346-
void AddToSpends(const COutPoint& outpoint, const Txid& txid, WalletBatch* batch = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
347-
void AddToSpends(const CWalletTx& wtx, WalletBatch* batch = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
346+
void AddToSpends(const COutPoint& outpoint, const Txid& txid) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
347+
void AddToSpends(const CWalletTx& wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
348348

349349
/**
350350
* Add a transaction to the wallet, or update it. confirm.block_* should
@@ -510,8 +510,10 @@ class CWallet final : public WalletStorage, public interfaces::Chain::Notificati
510510
/** Set of Coins owned by this wallet that we won't try to spend from. A
511511
* Coin may be locked if it has already been used to fund a transaction
512512
* that hasn't confirmed yet. We wouldn't consider the Coin spent already,
513-
* but also shouldn't try to use it again. */
514-
std::set<COutPoint> setLockedCoins GUARDED_BY(cs_wallet);
513+
* but also shouldn't try to use it again.
514+
* bool to track whether this locked coin is persisted to disk.
515+
*/
516+
std::map<COutPoint, bool> m_locked_coins GUARDED_BY(cs_wallet);
515517

516518
/** Registered interfaces::Chain::Notifications handler. */
517519
std::unique_ptr<interfaces::Handler> m_chain_notifications_handler;
@@ -567,8 +569,9 @@ class CWallet final : public WalletStorage, public interfaces::Chain::Notificati
567569
util::Result<void> DisplayAddress(const CTxDestination& dest) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
568570

569571
bool IsLockedCoin(const COutPoint& output) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
570-
bool LockCoin(const COutPoint& output, WalletBatch* batch = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
571-
bool UnlockCoin(const COutPoint& output, WalletBatch* batch = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
572+
void LoadLockedCoin(const COutPoint& coin, bool persistent) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
573+
bool LockCoin(const COutPoint& output, bool persist) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
574+
bool UnlockCoin(const COutPoint& output) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
572575
bool UnlockAllCoins() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
573576
void ListLockedCoins(std::vector<COutPoint>& vOutpts) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
574577

src/wallet/walletdb.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1050,7 +1050,7 @@ static DBErrors LoadTxRecords(CWallet* pwallet, DatabaseBatch& batch, bool& any_
10501050
uint32_t n;
10511051
key >> hash;
10521052
key >> n;
1053-
pwallet->LockCoin(COutPoint(hash, n));
1053+
pwallet->LoadLockedCoin(COutPoint(hash, n), /*persistent=*/true);
10541054
return DBErrors::LOAD_OK;
10551055
});
10561056
result = std::max(result, locked_utxo_res.m_result);

0 commit comments

Comments
 (0)