Skip to content

Commit 2b9cba2

Browse files
committed
Remove CWalletTx merging logic from AddToWallet
Instead of AddToWallet taking a temporary CWalletTx object and then potentially merging it with a pre-existing CWalletTx, have it take a callback so callers can update the pre-existing CWalletTx directly. This makes AddToWallet simpler because now it is only has to be concerned with saving CWalletTx objects and not merging them. This makes AddToWallet calls clearer because they can now make direct updates to CWalletTx entries without having to make temporary objects and then worry about how they will be merged. This is a pure refactoring, no behavior is changing.
1 parent 608359b commit 2b9cba2

File tree

5 files changed

+53
-64
lines changed

5 files changed

+53
-64
lines changed

src/wallet/rpcdump.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,6 @@ UniValue importprunedfunds(const JSONRPCRequest& request)
345345
if (!DecodeHexTx(tx, request.params[0].get_str()))
346346
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
347347
uint256 hashTx = tx.GetHash();
348-
CWalletTx wtx(pwallet, MakeTransactionRef(std::move(tx)));
349348

350349
CDataStream ssMB(ParseHexV(request.params[1], "proof"), SER_NETWORK, PROTOCOL_VERSION);
351350
CMerkleBlock merkleBlock;
@@ -372,10 +371,10 @@ UniValue importprunedfunds(const JSONRPCRequest& request)
372371
unsigned int txnIndex = vIndex[it - vMatch.begin()];
373372

374373
CWalletTx::Confirmation confirm(CWalletTx::Status::CONFIRMED, height, merkleBlock.header.GetHash(), txnIndex);
375-
wtx.m_confirm = confirm;
376374

377-
if (pwallet->IsMine(*wtx.tx)) {
378-
pwallet->AddToWallet(wtx, false);
375+
CTransactionRef tx_ref = MakeTransactionRef(tx);
376+
if (pwallet->IsMine(*tx_ref)) {
377+
pwallet->AddToWallet(std::move(tx_ref), confirm);
379378
return NullUniValue;
380379
}
381380

src/wallet/test/coinselector_tests.cpp

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@ BOOST_FIXTURE_TEST_SUITE(coinselector_tests, WalletTestingSetup)
2424
// we repeat those tests this many times and only complain if all iterations of the test fail
2525
#define RANDOM_REPEATS 5
2626

27-
std::vector<std::unique_ptr<CWalletTx>> wtxn;
28-
2927
typedef std::set<CInputCoin> CoinSet;
3028

3129
static std::vector<COutput> vCoins;
@@ -74,16 +72,14 @@ static void add_coin(CWallet& wallet, const CAmount& nValue, int nAge = 6*24, bo
7472
// so stop vin being empty, and cache a non-zero Debit to fake out IsFromMe()
7573
tx.vin.resize(1);
7674
}
77-
std::unique_ptr<CWalletTx> wtx = MakeUnique<CWalletTx>(&wallet, MakeTransactionRef(std::move(tx)));
75+
CWalletTx* wtx = wallet.AddToWallet(MakeTransactionRef(std::move(tx)), /* confirm= */ {});
7876
if (fIsFromMe)
7977
{
8078
wtx->m_amounts[CWalletTx::DEBIT].Set(ISMINE_SPENDABLE, 1);
8179
wtx->m_is_cache_empty = false;
8280
}
83-
COutput output(wtx.get(), nInput, nAge, true /* spendable */, true /* solvable */, true /* safe */);
81+
COutput output(wtx, nInput, nAge, true /* spendable */, true /* solvable */, true /* safe */);
8482
vCoins.push_back(output);
85-
wallet.AddToWallet(*wtx.get());
86-
wtxn.emplace_back(std::move(wtx));
8783
}
8884
static void add_coin(const CAmount& nValue, int nAge = 6*24, bool fIsFromMe = false, int nInput=0, bool spendable = false)
8985
{
@@ -93,7 +89,6 @@ static void add_coin(const CAmount& nValue, int nAge = 6*24, bool fIsFromMe = fa
9389
static void empty_wallet(void)
9490
{
9591
vCoins.clear();
96-
wtxn.clear();
9792
balance = 0;
9893
}
9994

src/wallet/test/wallet_tests.cpp

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,7 @@ BOOST_FIXTURE_TEST_CASE(coin_mark_dirty_immature_credit, TestChain100Setup)
331331
static int64_t AddTx(CWallet& wallet, uint32_t lockTime, int64_t mockTime, int64_t blockTime)
332332
{
333333
CMutableTransaction tx;
334+
CWalletTx::Confirmation confirm;
334335
tx.nLockTime = lockTime;
335336
SetMockTime(mockTime);
336337
CBlockIndex* block = nullptr;
@@ -341,23 +342,15 @@ static int64_t AddTx(CWallet& wallet, uint32_t lockTime, int64_t mockTime, int64
341342
block = inserted.first->second;
342343
block->nTime = blockTime;
343344
block->phashBlock = &hash;
345+
confirm = {CWalletTx::Status::CONFIRMED, block->nHeight, hash, 0};
344346
}
345347

346-
CWalletTx wtx(&wallet, MakeTransactionRef(tx));
347-
LOCK(wallet.cs_wallet);
348348
// If transaction is already in map, to avoid inconsistencies, unconfirmation
349349
// is needed before confirm again with different block.
350-
std::map<uint256, CWalletTx>::iterator it = wallet.mapWallet.find(wtx.GetHash());
351-
if (it != wallet.mapWallet.end()) {
350+
return wallet.AddToWallet(MakeTransactionRef(tx), confirm, [&](CWalletTx& wtx, bool /* new_tx */) {
352351
wtx.setUnconfirmed();
353-
wallet.AddToWallet(wtx);
354-
}
355-
if (block) {
356-
CWalletTx::Confirmation confirm(CWalletTx::Status::CONFIRMED, block->nHeight, block->GetBlockHash(), 0);
357-
wtx.m_confirm = confirm;
358-
}
359-
wallet.AddToWallet(wtx);
360-
return wallet.mapWallet.at(wtx.GetHash()).nTimeSmart;
352+
return true;
353+
})->nTimeSmart;
361354
}
362355

363356
// Simple test to verify assignment of CWalletTx::nSmartTime value. Could be

src/wallet/wallet.cpp

Lines changed: 33 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -783,19 +783,19 @@ bool CWallet::IsSpentKey(const uint256& hash, unsigned int n) const
783783
return false;
784784
}
785785

786-
bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
786+
CWalletTx* CWallet::AddToWallet(CTransactionRef tx, const CWalletTx::Confirmation& confirm, const UpdateWalletTxFn& update_wtx, bool fFlushOnClose)
787787
{
788788
LOCK(cs_wallet);
789789

790790
WalletBatch batch(*database, "r+", fFlushOnClose);
791791

792-
uint256 hash = wtxIn.GetHash();
792+
uint256 hash = tx->GetHash();
793793

794794
if (IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE)) {
795795
// Mark used destinations
796796
std::set<CTxDestination> tx_destinations;
797797

798-
for (const CTxIn& txin : wtxIn.tx->vin) {
798+
for (const CTxIn& txin : tx->vin) {
799799
const COutPoint& op = txin.prevout;
800800
SetSpentKeyState(batch, op.hash, op.n, true, tx_destinations);
801801
}
@@ -804,55 +804,51 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
804804
}
805805

806806
// Inserts only if not already there, returns tx inserted or tx found
807-
std::pair<std::map<uint256, CWalletTx>::iterator, bool> ret = mapWallet.insert(std::make_pair(hash, wtxIn));
807+
auto ret = mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(hash), std::forward_as_tuple(this, tx));
808808
CWalletTx& wtx = (*ret.first).second;
809809
wtx.BindWallet(this);
810810
bool fInsertedNew = ret.second;
811+
bool fUpdated = update_wtx && update_wtx(wtx, fInsertedNew);
811812
if (fInsertedNew) {
813+
wtx.m_confirm = confirm;
812814
wtx.nTimeReceived = chain().getAdjustedTime();
813815
wtx.nOrderPos = IncOrderPosNext(&batch);
814816
wtx.m_it_wtxOrdered = wtxOrdered.insert(std::make_pair(wtx.nOrderPos, &wtx));
815817
wtx.nTimeSmart = ComputeTimeSmart(wtx);
816818
AddToSpends(hash);
817819
}
818820

819-
bool fUpdated = false;
820821
if (!fInsertedNew)
821822
{
822-
if (wtxIn.m_confirm.status != wtx.m_confirm.status) {
823-
wtx.m_confirm.status = wtxIn.m_confirm.status;
824-
wtx.m_confirm.nIndex = wtxIn.m_confirm.nIndex;
825-
wtx.m_confirm.hashBlock = wtxIn.m_confirm.hashBlock;
826-
wtx.m_confirm.block_height = wtxIn.m_confirm.block_height;
823+
if (confirm.status != wtx.m_confirm.status) {
824+
wtx.m_confirm.status = confirm.status;
825+
wtx.m_confirm.nIndex = confirm.nIndex;
826+
wtx.m_confirm.hashBlock = confirm.hashBlock;
827+
wtx.m_confirm.block_height = confirm.block_height;
827828
fUpdated = true;
828829
} else {
829-
assert(wtx.m_confirm.nIndex == wtxIn.m_confirm.nIndex);
830-
assert(wtx.m_confirm.hashBlock == wtxIn.m_confirm.hashBlock);
831-
assert(wtx.m_confirm.block_height == wtxIn.m_confirm.block_height);
832-
}
833-
if (wtxIn.fFromMe && wtxIn.fFromMe != wtx.fFromMe)
834-
{
835-
wtx.fFromMe = wtxIn.fFromMe;
836-
fUpdated = true;
830+
assert(wtx.m_confirm.nIndex == confirm.nIndex);
831+
assert(wtx.m_confirm.hashBlock == confirm.hashBlock);
832+
assert(wtx.m_confirm.block_height == confirm.block_height);
837833
}
838834
// If we have a witness-stripped version of this transaction, and we
839835
// see a new version with a witness, then we must be upgrading a pre-segwit
840836
// wallet. Store the new version of the transaction with the witness,
841837
// as the stripped-version must be invalid.
842838
// TODO: Store all versions of the transaction, instead of just one.
843-
if (wtxIn.tx->HasWitness() && !wtx.tx->HasWitness()) {
844-
wtx.SetTx(wtxIn.tx);
839+
if (tx->HasWitness() && !wtx.tx->HasWitness()) {
840+
wtx.SetTx(tx);
845841
fUpdated = true;
846842
}
847843
}
848844

849845
//// debug print
850-
WalletLogPrintf("AddToWallet %s %s%s\n", wtxIn.GetHash().ToString(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : ""));
846+
WalletLogPrintf("AddToWallet %s %s%s\n", hash.ToString(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : ""));
851847

852848
// Write to disk
853849
if (fInsertedNew || fUpdated)
854850
if (!batch.WriteTx(wtx))
855-
return false;
851+
return nullptr;
856852

857853
// Break debit/credit balance caches:
858854
wtx.MarkDirty();
@@ -866,7 +862,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
866862

867863
if (!strCmd.empty())
868864
{
869-
boost::replace_all(strCmd, "%s", wtxIn.GetHash().GetHex());
865+
boost::replace_all(strCmd, "%s", hash.GetHex());
870866
#ifndef WIN32
871867
// Substituting the wallet name isn't currently supported on windows
872868
// because windows shell escaping has not been implemented yet:
@@ -880,7 +876,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
880876
}
881877
#endif
882878

883-
return true;
879+
return &wtx;
884880
}
885881

886882
void CWallet::LoadToWallet(CWalletTx& wtxIn)
@@ -960,13 +956,9 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, CWalletTx::Co
960956
}
961957
}
962958

963-
CWalletTx wtx(this, ptx);
964-
965959
// Block disconnection override an abandoned tx as unconfirmed
966960
// which means user may have to call abandontransaction again
967-
wtx.m_confirm = confirm;
968-
969-
return AddToWallet(wtx, false);
961+
return AddToWallet(MakeTransactionRef(tx), confirm, /* update_wtx= */ nullptr, /* fFlushOnClose= */ false);
970962
}
971963
}
972964
return false;
@@ -3007,29 +2999,30 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac
30072999
void CWallet::CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::vector<std::pair<std::string, std::string>> orderForm)
30083000
{
30093001
LOCK(cs_wallet);
3010-
3011-
CWalletTx wtxNew(this, std::move(tx));
3012-
wtxNew.mapValue = std::move(mapValue);
3013-
wtxNew.vOrderForm = std::move(orderForm);
3014-
wtxNew.fTimeReceivedIsTxTime = true;
3015-
wtxNew.fFromMe = true;
3016-
3017-
WalletLogPrintf("CommitTransaction:\n%s", wtxNew.tx->ToString()); /* Continued */
3002+
WalletLogPrintf("CommitTransaction:\n%s", tx->ToString()); /* Continued */
30183003

30193004
// Add tx to wallet, because if it has change it's also ours,
30203005
// otherwise just for transaction history.
3021-
AddToWallet(wtxNew);
3006+
AddToWallet(tx, {}, [&](CWalletTx& wtx, bool new_tx) {
3007+
CHECK_NONFATAL(wtx.mapValue.empty());
3008+
CHECK_NONFATAL(wtx.vOrderForm.empty());
3009+
wtx.mapValue = std::move(mapValue);
3010+
wtx.vOrderForm = std::move(orderForm);
3011+
wtx.fTimeReceivedIsTxTime = true;
3012+
wtx.fFromMe = true;
3013+
return true;
3014+
});
30223015

30233016
// Notify that old coins are spent
3024-
for (const CTxIn& txin : wtxNew.tx->vin) {
3017+
for (const CTxIn& txin : tx->vin) {
30253018
CWalletTx &coin = mapWallet.at(txin.prevout.hash);
30263019
coin.BindWallet(this);
30273020
NotifyTransactionChanged(this, coin.GetHash(), CT_UPDATED);
30283021
}
30293022

30303023
// Get the inserted-CWalletTx from mapWallet so that the
30313024
// fInMempool flag is cached properly
3032-
CWalletTx& wtx = mapWallet.at(wtxNew.GetHash());
3025+
CWalletTx& wtx = mapWallet.at(tx->GetHash());
30333026

30343027
if (!fBroadcastTransactions) {
30353028
// Don't submit tx to the mempool

src/wallet/wallet.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -886,7 +886,16 @@ class CWallet final : public WalletStorage, public interfaces::Chain::Notificati
886886
DBErrors ReorderTransactions();
887887

888888
void MarkDirty();
889-
bool AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose=true);
889+
890+
//! Callback for updating transaction metadata in mapWallet.
891+
//!
892+
//! @param wtx - reference to mapWallet transaction to update
893+
//! @param new_tx - true if wtx is newly inserted, false if it previously existed
894+
//!
895+
//! @return true if wtx is changed and needs to be saved to disk, otherwise false
896+
using UpdateWalletTxFn = std::function<bool(CWalletTx& wtx, bool new_tx)>;
897+
898+
CWalletTx* AddToWallet(CTransactionRef tx, const CWalletTx::Confirmation& confirm, const UpdateWalletTxFn& update_wtx=nullptr, bool fFlushOnClose=true);
890899
void LoadToWallet(CWalletTx& wtxIn) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
891900
void transactionAddedToMempool(const CTransactionRef& tx) override;
892901
void blockConnected(const CBlock& block, int height) override;

0 commit comments

Comments
 (0)