diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -1934,7 +1934,7 @@ UniValue transactions(UniValue::VARR); for (const std::pair &pairWtx : pwallet->mapWallet) { - CWalletTx tx = pairWtx.second; + const CWalletTx &tx = pairWtx.second; if (depth == -1 || tx.GetDepthInMainChain() < depth) { ListTransactions(pwallet, tx, 0, true, transactions, filter, diff --git a/src/wallet/test/psbt_wallet_tests.cpp b/src/wallet/test/psbt_wallet_tests.cpp --- a/src/wallet/test/psbt_wallet_tests.cpp +++ b/src/wallet/test/psbt_wallet_tests.cpp @@ -30,8 +30,9 @@ CTransactionRef prev_tx1; s_prev_tx1 >> prev_tx1; - CWalletTx prev_wtx1(&m_wallet, prev_tx1); - m_wallet.mapWallet.emplace(prev_wtx1.GetId(), std::move(prev_wtx1)); + m_wallet.mapWallet.emplace(std::piecewise_construct, + std::forward_as_tuple(prev_tx1->GetId()), + std::forward_as_tuple(&m_wallet, prev_tx1)); CDataStream s_prev_tx2( ParseHex( @@ -44,8 +45,9 @@ SER_NETWORK, PROTOCOL_VERSION); CTransactionRef prev_tx2; s_prev_tx2 >> prev_tx2; - CWalletTx prev_wtx2(&m_wallet, prev_tx2); - m_wallet.mapWallet.emplace(prev_wtx2.GetId(), std::move(prev_wtx2)); + m_wallet.mapWallet.emplace(std::piecewise_construct, + std::forward_as_tuple(prev_tx2->GetId()), + std::forward_as_tuple(&m_wallet, prev_tx2)); // Add scripts CScript rs1; diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -592,6 +592,12 @@ TxId GetId() const { return tx->GetId(); } bool IsCoinBase() const { return tx->IsCoinBase(); } bool IsImmatureCoinBase() const; + + // Disable copying of CWalletTx objects to prevent bugs where instances get + // copied in and out of the mapWallet map, and fields are updated in the + // wrong copy. + CWalletTx(CWalletTx const &) = delete; + void operator=(CWalletTx const &x) = delete; }; class COutput { @@ -1271,7 +1277,7 @@ void chainStateFlushed(const CBlockLocator &loc) override; DBErrors LoadWallet(bool &fFirstRunRet); - DBErrors ZapWalletTx(std::vector &vWtx); + DBErrors ZapWalletTx(std::list &vWtx); DBErrors ZapSelectTx(std::vector &txIdsIn, std::vector &txIdsOut) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -3511,7 +3511,7 @@ return DBErrors::LOAD_OK; } -DBErrors CWallet::ZapWalletTx(std::vector &vWtx) { +DBErrors CWallet::ZapWalletTx(std::list &vWtx) { DBErrors nZapWalletTxRet = WalletBatch(*database, "cr+").ZapWalletTx(vWtx); if (nZapWalletTxRet == DBErrors::NEED_REWRITE) { if (database->Rewrite("\x04pool")) { @@ -4171,7 +4171,7 @@ WalletDataFilePath(location.GetPath()).string(); // Needed to restore wallet transaction meta data after -zapwallettxes - std::vector vWtx; + std::list vWtx; if (gArgs.GetBoolArg("-zapwallettxes", false)) { chain.initMessage( diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -272,9 +272,8 @@ bool internal); DBErrors LoadWallet(CWallet *pwallet); - DBErrors FindWalletTx(std::vector &txIds, - std::vector &vWtx); - DBErrors ZapWalletTx(std::vector &vWtx); + DBErrors FindWalletTx(std::vector &txIds, std::list &vWtx); + DBErrors ZapWalletTx(std::list &vWtx); DBErrors ZapSelectTx(std::vector &txIdsIn, std::vector &txIdsOut); /* Function to determine if a certain KV/key-type is a key (cryptographical diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -825,7 +825,7 @@ } DBErrors WalletBatch::FindWalletTx(std::vector &txIds, - std::vector &vWtx) { + std::list &vWtx) { DBErrors result = DBErrors::LOAD_OK; try { @@ -862,12 +862,9 @@ if (strType == DBKeys::TX) { TxId txid; ssKey >> txid; - - CWalletTx wtx(nullptr /* pwallet */, MakeTransactionRef()); - ssValue >> wtx; - txIds.push_back(txid); - vWtx.push_back(wtx); + vWtx.emplace_back(nullptr /* wallet */, nullptr /* tx */); + ssValue >> vWtx.back(); } } pcursor->close(); @@ -882,7 +879,7 @@ std::vector &txIdsOut) { // Build list of wallet TXs and hashes. std::vector txIds; - std::vector vWtx; + std::list vWtx; DBErrors err = FindWalletTx(txIds, vWtx); if (err != DBErrors::LOAD_OK) { return err; @@ -920,7 +917,7 @@ return DBErrors::LOAD_OK; } -DBErrors WalletBatch::ZapWalletTx(std::vector &vWtx) { +DBErrors WalletBatch::ZapWalletTx(std::list &vWtx) { // Build list of wallet TXs. std::vector txIds; DBErrors err = FindWalletTx(txIds, vWtx);