aboutsummaryrefslogtreecommitdiff
path: root/src/wallet
diff options
context:
space:
mode:
Diffstat (limited to 'src/wallet')
-rw-r--r--src/wallet/rpcdump.cpp7
-rw-r--r--src/wallet/rpcwallet.cpp2
-rw-r--r--src/wallet/test/coinselector_tests.cpp9
-rw-r--r--src/wallet/test/psbt_wallet_tests.cpp6
-rw-r--r--src/wallet/test/wallet_tests.cpp17
-rw-r--r--src/wallet/wallet.cpp106
-rw-r--r--src/wallet/wallet.h39
-rw-r--r--src/wallet/walletdb.cpp70
-rw-r--r--src/wallet/walletdb.h4
9 files changed, 126 insertions, 134 deletions
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index c863d22530..7bf3d169c3 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -345,7 +345,6 @@ UniValue importprunedfunds(const JSONRPCRequest& request)
if (!DecodeHexTx(tx, request.params[0].get_str()))
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
uint256 hashTx = tx.GetHash();
- CWalletTx wtx(pwallet, MakeTransactionRef(std::move(tx)));
CDataStream ssMB(ParseHexV(request.params[1], "proof"), SER_NETWORK, PROTOCOL_VERSION);
CMerkleBlock merkleBlock;
@@ -372,10 +371,10 @@ UniValue importprunedfunds(const JSONRPCRequest& request)
unsigned int txnIndex = vIndex[it - vMatch.begin()];
CWalletTx::Confirmation confirm(CWalletTx::Status::CONFIRMED, height, merkleBlock.header.GetHash(), txnIndex);
- wtx.m_confirm = confirm;
- if (pwallet->IsMine(*wtx.tx)) {
- pwallet->AddToWallet(wtx, false);
+ CTransactionRef tx_ref = MakeTransactionRef(tx);
+ if (pwallet->IsMine(*tx_ref)) {
+ pwallet->AddToWallet(std::move(tx_ref), confirm);
return NullUniValue;
}
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index e666d55e11..dda00f1fe7 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -1583,7 +1583,7 @@ static UniValue listsinceblock(const JSONRPCRequest& request)
UniValue transactions(UniValue::VARR);
for (const std::pair<const uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
- CWalletTx tx = pairWtx.second;
+ const CWalletTx& tx = pairWtx.second;
if (depth == -1 || abs(tx.GetDepthInMainChain()) < depth) {
ListTransactions(pwallet, tx, 0, true, transactions, filter, nullptr /* filter_label */);
diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp
index 66f4542cf9..657d0828f2 100644
--- a/src/wallet/test/coinselector_tests.cpp
+++ b/src/wallet/test/coinselector_tests.cpp
@@ -24,8 +24,6 @@ BOOST_FIXTURE_TEST_SUITE(coinselector_tests, WalletTestingSetup)
// we repeat those tests this many times and only complain if all iterations of the test fail
#define RANDOM_REPEATS 5
-std::vector<std::unique_ptr<CWalletTx>> wtxn;
-
typedef std::set<CInputCoin> CoinSet;
static std::vector<COutput> vCoins;
@@ -74,16 +72,14 @@ static void add_coin(CWallet& wallet, const CAmount& nValue, int nAge = 6*24, bo
// so stop vin being empty, and cache a non-zero Debit to fake out IsFromMe()
tx.vin.resize(1);
}
- std::unique_ptr<CWalletTx> wtx = MakeUnique<CWalletTx>(&wallet, MakeTransactionRef(std::move(tx)));
+ CWalletTx* wtx = wallet.AddToWallet(MakeTransactionRef(std::move(tx)), /* confirm= */ {});
if (fIsFromMe)
{
wtx->m_amounts[CWalletTx::DEBIT].Set(ISMINE_SPENDABLE, 1);
wtx->m_is_cache_empty = false;
}
- COutput output(wtx.get(), nInput, nAge, true /* spendable */, true /* solvable */, true /* safe */);
+ COutput output(wtx, nInput, nAge, true /* spendable */, true /* solvable */, true /* safe */);
vCoins.push_back(output);
- wallet.AddToWallet(*wtx.get());
- wtxn.emplace_back(std::move(wtx));
}
static void add_coin(const CAmount& nValue, int nAge = 6*24, bool fIsFromMe = false, int nInput=0, bool spendable = false)
{
@@ -93,7 +89,6 @@ static void add_coin(const CAmount& nValue, int nAge = 6*24, bool fIsFromMe = fa
static void empty_wallet(void)
{
vCoins.clear();
- wtxn.clear();
balance = 0;
}
diff --git a/src/wallet/test/psbt_wallet_tests.cpp b/src/wallet/test/psbt_wallet_tests.cpp
index 35860577cd..b4c65a8665 100644
--- a/src/wallet/test/psbt_wallet_tests.cpp
+++ b/src/wallet/test/psbt_wallet_tests.cpp
@@ -22,14 +22,12 @@ BOOST_AUTO_TEST_CASE(psbt_updater_test)
CDataStream s_prev_tx1(ParseHex("0200000000010158e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7501000000171600145f275f436b09a8cc9a2eb2a2f528485c68a56323feffffff02d8231f1b0100000017a914aed962d6654f9a2b36608eb9d64d2b260db4f1118700c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88702483045022100a22edcc6e5bc511af4cc4ae0de0fcd75c7e04d8c1c3a8aa9d820ed4b967384ec02200642963597b9b1bc22c75e9f3e117284a962188bf5e8a74c895089046a20ad770121035509a48eb623e10aace8bfd0212fdb8a8e5af3c94b0b133b95e114cab89e4f7965000000"), SER_NETWORK, PROTOCOL_VERSION);
CTransactionRef prev_tx1;
s_prev_tx1 >> prev_tx1;
- CWalletTx prev_wtx1(&m_wallet, prev_tx1);
- m_wallet.mapWallet.emplace(prev_wtx1.GetHash(), std::move(prev_wtx1));
+ m_wallet.mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(prev_tx1->GetHash()), std::forward_as_tuple(&m_wallet, prev_tx1));
CDataStream s_prev_tx2(ParseHex("0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f618765000000"), 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.GetHash(), std::move(prev_wtx2));
+ m_wallet.mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(prev_tx2->GetHash()), std::forward_as_tuple(&m_wallet, prev_tx2));
// Add scripts
CScript rs1;
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index 0826b88f0a..3dba106c41 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -332,6 +332,7 @@ BOOST_FIXTURE_TEST_CASE(coin_mark_dirty_immature_credit, TestChain100Setup)
static int64_t AddTx(CWallet& wallet, uint32_t lockTime, int64_t mockTime, int64_t blockTime)
{
CMutableTransaction tx;
+ CWalletTx::Confirmation confirm;
tx.nLockTime = lockTime;
SetMockTime(mockTime);
CBlockIndex* block = nullptr;
@@ -342,23 +343,15 @@ static int64_t AddTx(CWallet& wallet, uint32_t lockTime, int64_t mockTime, int64
block = inserted.first->second;
block->nTime = blockTime;
block->phashBlock = &hash;
+ confirm = {CWalletTx::Status::CONFIRMED, block->nHeight, hash, 0};
}
- CWalletTx wtx(&wallet, MakeTransactionRef(tx));
- LOCK(wallet.cs_wallet);
// If transaction is already in map, to avoid inconsistencies, unconfirmation
// is needed before confirm again with different block.
- std::map<uint256, CWalletTx>::iterator it = wallet.mapWallet.find(wtx.GetHash());
- if (it != wallet.mapWallet.end()) {
+ return wallet.AddToWallet(MakeTransactionRef(tx), confirm, [&](CWalletTx& wtx, bool /* new_tx */) {
wtx.setUnconfirmed();
- wallet.AddToWallet(wtx);
- }
- if (block) {
- CWalletTx::Confirmation confirm(CWalletTx::Status::CONFIRMED, block->nHeight, block->GetBlockHash(), 0);
- wtx.m_confirm = confirm;
- }
- wallet.AddToWallet(wtx);
- return wallet.mapWallet.at(wtx.GetHash()).nTimeSmart;
+ return true;
+ })->nTimeSmart;
}
// Simple test to verify assignment of CWalletTx::nSmartTime value. Could be
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index a893548971..004ec57eb6 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -784,19 +784,19 @@ bool CWallet::IsSpentKey(const uint256& hash, unsigned int n) const
return false;
}
-bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
+CWalletTx* CWallet::AddToWallet(CTransactionRef tx, const CWalletTx::Confirmation& confirm, const UpdateWalletTxFn& update_wtx, bool fFlushOnClose)
{
LOCK(cs_wallet);
WalletBatch batch(*database, "r+", fFlushOnClose);
- uint256 hash = wtxIn.GetHash();
+ uint256 hash = tx->GetHash();
if (IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE)) {
// Mark used destinations
std::set<CTxDestination> tx_destinations;
- for (const CTxIn& txin : wtxIn.tx->vin) {
+ for (const CTxIn& txin : tx->vin) {
const COutPoint& op = txin.prevout;
SetSpentKeyState(batch, op.hash, op.n, true, tx_destinations);
}
@@ -805,11 +805,12 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
}
// Inserts only if not already there, returns tx inserted or tx found
- std::pair<std::map<uint256, CWalletTx>::iterator, bool> ret = mapWallet.insert(std::make_pair(hash, wtxIn));
+ auto ret = mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(hash), std::forward_as_tuple(this, tx));
CWalletTx& wtx = (*ret.first).second;
- wtx.BindWallet(this);
bool fInsertedNew = ret.second;
+ bool fUpdated = update_wtx && update_wtx(wtx, fInsertedNew);
if (fInsertedNew) {
+ wtx.m_confirm = confirm;
wtx.nTimeReceived = chain().getAdjustedTime();
wtx.nOrderPos = IncOrderPosNext(&batch);
wtx.m_it_wtxOrdered = wtxOrdered.insert(std::make_pair(wtx.nOrderPos, &wtx));
@@ -817,43 +818,37 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
AddToSpends(hash);
}
- bool fUpdated = false;
if (!fInsertedNew)
{
- if (wtxIn.m_confirm.status != wtx.m_confirm.status) {
- wtx.m_confirm.status = wtxIn.m_confirm.status;
- wtx.m_confirm.nIndex = wtxIn.m_confirm.nIndex;
- wtx.m_confirm.hashBlock = wtxIn.m_confirm.hashBlock;
- wtx.m_confirm.block_height = wtxIn.m_confirm.block_height;
+ if (confirm.status != wtx.m_confirm.status) {
+ wtx.m_confirm.status = confirm.status;
+ wtx.m_confirm.nIndex = confirm.nIndex;
+ wtx.m_confirm.hashBlock = confirm.hashBlock;
+ wtx.m_confirm.block_height = confirm.block_height;
fUpdated = true;
} else {
- assert(wtx.m_confirm.nIndex == wtxIn.m_confirm.nIndex);
- assert(wtx.m_confirm.hashBlock == wtxIn.m_confirm.hashBlock);
- assert(wtx.m_confirm.block_height == wtxIn.m_confirm.block_height);
- }
- if (wtxIn.fFromMe && wtxIn.fFromMe != wtx.fFromMe)
- {
- wtx.fFromMe = wtxIn.fFromMe;
- fUpdated = true;
+ assert(wtx.m_confirm.nIndex == confirm.nIndex);
+ assert(wtx.m_confirm.hashBlock == confirm.hashBlock);
+ assert(wtx.m_confirm.block_height == confirm.block_height);
}
// If we have a witness-stripped version of this transaction, and we
// see a new version with a witness, then we must be upgrading a pre-segwit
// wallet. Store the new version of the transaction with the witness,
// as the stripped-version must be invalid.
// TODO: Store all versions of the transaction, instead of just one.
- if (wtxIn.tx->HasWitness() && !wtx.tx->HasWitness()) {
- wtx.SetTx(wtxIn.tx);
+ if (tx->HasWitness() && !wtx.tx->HasWitness()) {
+ wtx.SetTx(tx);
fUpdated = true;
}
}
//// debug print
- WalletLogPrintf("AddToWallet %s %s%s\n", wtxIn.GetHash().ToString(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : ""));
+ WalletLogPrintf("AddToWallet %s %s%s\n", hash.ToString(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : ""));
// Write to disk
if (fInsertedNew || fUpdated)
if (!batch.WriteTx(wtx))
- return false;
+ return nullptr;
// Break debit/credit balance caches:
wtx.MarkDirty();
@@ -867,7 +862,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
if (!strCmd.empty())
{
- boost::replace_all(strCmd, "%s", wtxIn.GetHash().GetHex());
+ boost::replace_all(strCmd, "%s", hash.GetHex());
#ifndef WIN32
// Substituting the wallet name isn't currently supported on windows
// because windows shell escaping has not been implemented yet:
@@ -881,35 +876,36 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
}
#endif
- return true;
+ return &wtx;
}
-void CWallet::LoadToWallet(CWalletTx& wtxIn)
+bool CWallet::LoadToWallet(const uint256& hash, const UpdateWalletTxFn& fill_wtx)
{
+ const auto& ins = mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(hash), std::forward_as_tuple(this, nullptr));
+ CWalletTx& wtx = ins.first->second;
+ if (!fill_wtx(wtx, ins.second)) {
+ return false;
+ }
// If wallet doesn't have a chain (e.g wallet-tool), don't bother to update txn.
if (HaveChain()) {
- Optional<int> block_height = chain().getBlockHeight(wtxIn.m_confirm.hashBlock);
+ Optional<int> block_height = chain().getBlockHeight(wtx.m_confirm.hashBlock);
if (block_height) {
// Update cached block height variable since it not stored in the
// serialized transaction.
- wtxIn.m_confirm.block_height = *block_height;
- } else if (wtxIn.isConflicted() || wtxIn.isConfirmed()) {
+ wtx.m_confirm.block_height = *block_height;
+ } else if (wtx.isConflicted() || wtx.isConfirmed()) {
// If tx block (or conflicting block) was reorged out of chain
// while the wallet was shutdown, change tx status to UNCONFIRMED
// and reset block height, hash, and index. ABANDONED tx don't have
// associated blocks and don't need to be updated. The case where a
// transaction was reorged out while online and then reconfirmed
// while offline is covered by the rescan logic.
- wtxIn.setUnconfirmed();
- wtxIn.m_confirm.hashBlock = uint256();
- wtxIn.m_confirm.block_height = 0;
- wtxIn.m_confirm.nIndex = 0;
+ wtx.setUnconfirmed();
+ wtx.m_confirm.hashBlock = uint256();
+ wtx.m_confirm.block_height = 0;
+ wtx.m_confirm.nIndex = 0;
}
}
- uint256 hash = wtxIn.GetHash();
- const auto& ins = mapWallet.emplace(hash, wtxIn);
- CWalletTx& wtx = ins.first->second;
- wtx.BindWallet(this);
if (/* insertion took place */ ins.second) {
wtx.m_it_wtxOrdered = wtxOrdered.insert(std::make_pair(wtx.nOrderPos, &wtx));
}
@@ -923,6 +919,7 @@ void CWallet::LoadToWallet(CWalletTx& wtxIn)
}
}
}
+ return true;
}
bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, CWalletTx::Confirmation confirm, bool fUpdate)
@@ -961,13 +958,9 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, CWalletTx::Co
}
}
- CWalletTx wtx(this, ptx);
-
// Block disconnection override an abandoned tx as unconfirmed
// which means user may have to call abandontransaction again
- wtx.m_confirm = confirm;
-
- return AddToWallet(wtx, false);
+ return AddToWallet(MakeTransactionRef(tx), confirm, /* update_wtx= */ nullptr, /* fFlushOnClose= */ false);
}
}
return false;
@@ -3008,29 +3001,30 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac
void CWallet::CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::vector<std::pair<std::string, std::string>> orderForm)
{
LOCK(cs_wallet);
-
- CWalletTx wtxNew(this, std::move(tx));
- wtxNew.mapValue = std::move(mapValue);
- wtxNew.vOrderForm = std::move(orderForm);
- wtxNew.fTimeReceivedIsTxTime = true;
- wtxNew.fFromMe = true;
-
- WalletLogPrintf("CommitTransaction:\n%s", wtxNew.tx->ToString()); /* Continued */
+ WalletLogPrintf("CommitTransaction:\n%s", tx->ToString()); /* Continued */
// Add tx to wallet, because if it has change it's also ours,
// otherwise just for transaction history.
- AddToWallet(wtxNew);
+ AddToWallet(tx, {}, [&](CWalletTx& wtx, bool new_tx) {
+ CHECK_NONFATAL(wtx.mapValue.empty());
+ CHECK_NONFATAL(wtx.vOrderForm.empty());
+ wtx.mapValue = std::move(mapValue);
+ wtx.vOrderForm = std::move(orderForm);
+ wtx.fTimeReceivedIsTxTime = true;
+ wtx.fFromMe = true;
+ return true;
+ });
// Notify that old coins are spent
- for (const CTxIn& txin : wtxNew.tx->vin) {
+ for (const CTxIn& txin : tx->vin) {
CWalletTx &coin = mapWallet.at(txin.prevout.hash);
- coin.BindWallet(this);
+ coin.MarkDirty();
NotifyTransactionChanged(this, coin.GetHash(), CT_UPDATED);
}
// Get the inserted-CWalletTx from mapWallet so that the
// fInMempool flag is cached properly
- CWalletTx& wtx = mapWallet.at(wtxNew.GetHash());
+ CWalletTx& wtx = mapWallet.at(tx->GetHash());
if (!fBroadcastTransactions) {
// Don't submit tx to the mempool
@@ -3102,7 +3096,7 @@ DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256
return DBErrors::LOAD_OK;
}
-DBErrors CWallet::ZapWalletTx(std::vector<CWalletTx>& vWtx)
+DBErrors CWallet::ZapWalletTx(std::list<CWalletTx>& vWtx)
{
DBErrors nZapWalletTxRet = WalletBatch(*database,"cr+").ZapWalletTx(vWtx);
if (nZapWalletTxRet == DBErrors::NEED_REWRITE)
@@ -3714,7 +3708,7 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
const std::string walletFile = WalletDataFilePath(location.GetPath()).string();
// needed to restore wallet transaction meta data after -zapwallettxes
- std::vector<CWalletTx> vWtx;
+ std::list<CWalletTx> vWtx;
if (gArgs.GetBoolArg("-zapwallettxes", false)) {
chain.initMessage(_("Zapping all transactions from wallet...").translated);
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 3be3435596..8f624c25d7 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -340,15 +340,15 @@ public:
mutable bool fInMempool;
mutable CAmount nChangeCached;
- CWalletTx(const CWallet* pwalletIn, CTransactionRef arg)
- : tx(std::move(arg))
+ CWalletTx(const CWallet* wallet, CTransactionRef arg)
+ : pwallet(wallet),
+ tx(std::move(arg))
{
- Init(pwalletIn);
+ Init();
}
- void Init(const CWallet* pwalletIn)
+ void Init()
{
- pwallet = pwalletIn;
mapValue.clear();
vOrderForm.clear();
fTimeReceivedIsTxTime = false;
@@ -416,7 +416,7 @@ public:
template<typename Stream>
void Unserialize(Stream& s)
{
- Init(nullptr);
+ Init();
std::vector<uint256> dummy_vector1; //!< Used to be vMerkleBranch
std::vector<CMerkleTx> dummy_vector2; //!< Used to be vtxPrev
@@ -465,12 +465,6 @@ public:
m_is_cache_empty = true;
}
- void BindWallet(CWallet *pwalletIn)
- {
- pwallet = pwalletIn;
- MarkDirty();
- }
-
//! filter decides which addresses will count towards the debit
CAmount GetDebit(const isminefilter& filter) const;
CAmount GetCredit(const isminefilter& filter) const;
@@ -555,6 +549,12 @@ public:
const uint256& GetHash() const { return tx->GetHash(); }
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
@@ -888,8 +888,17 @@ public:
DBErrors ReorderTransactions();
void MarkDirty();
- bool AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose=true);
- void LoadToWallet(CWalletTx& wtxIn) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+
+ //! Callback for updating transaction metadata in mapWallet.
+ //!
+ //! @param wtx - reference to mapWallet transaction to update
+ //! @param new_tx - true if wtx is newly inserted, false if it previously existed
+ //!
+ //! @return true if wtx is changed and needs to be saved to disk, otherwise false
+ using UpdateWalletTxFn = std::function<bool(CWalletTx& wtx, bool new_tx)>;
+
+ CWalletTx* AddToWallet(CTransactionRef tx, const CWalletTx::Confirmation& confirm, const UpdateWalletTxFn& update_wtx=nullptr, bool fFlushOnClose=true);
+ bool LoadToWallet(const uint256& hash, const UpdateWalletTxFn& fill_wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
void transactionAddedToMempool(const CTransactionRef& tx) override;
void blockConnected(const CBlock& block, int height) override;
void blockDisconnected(const CBlock& block, int height) override;
@@ -1050,7 +1059,7 @@ public:
void chainStateFlushed(const CBlockLocator& loc) override;
DBErrors LoadWallet(bool& fFirstRunRet);
- DBErrors ZapWalletTx(std::vector<CWalletTx>& vWtx);
+ DBErrors ZapWalletTx(std::list<CWalletTx>& vWtx);
DBErrors ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256>& vHashOut) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
bool SetAddressBook(const CTxDestination& address, const std::string& strName, const std::string& purpose);
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index 45033f9bac..98597bdb0f 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -272,36 +272,43 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
} else if (strType == DBKeys::TX) {
uint256 hash;
ssKey >> hash;
- CWalletTx wtx(nullptr /* pwallet */, MakeTransactionRef());
- ssValue >> wtx;
- if (wtx.GetHash() != hash)
- return false;
+ // LoadToWallet call below creates a new CWalletTx that fill_wtx
+ // callback fills with transaction metadata.
+ auto fill_wtx = [&](CWalletTx& wtx, bool new_tx) {
+ assert(new_tx);
+ ssValue >> wtx;
+ if (wtx.GetHash() != hash)
+ return false;
- // Undo serialize changes in 31600
- if (31404 <= wtx.fTimeReceivedIsTxTime && wtx.fTimeReceivedIsTxTime <= 31703)
- {
- if (!ssValue.empty())
- {
- char fTmp;
- char fUnused;
- std::string unused_string;
- ssValue >> fTmp >> fUnused >> unused_string;
- strErr = strprintf("LoadWallet() upgrading tx ver=%d %d %s",
- wtx.fTimeReceivedIsTxTime, fTmp, hash.ToString());
- wtx.fTimeReceivedIsTxTime = fTmp;
- }
- else
+ // Undo serialize changes in 31600
+ if (31404 <= wtx.fTimeReceivedIsTxTime && wtx.fTimeReceivedIsTxTime <= 31703)
{
- strErr = strprintf("LoadWallet() repairing tx ver=%d %s", wtx.fTimeReceivedIsTxTime, hash.ToString());
- wtx.fTimeReceivedIsTxTime = 0;
+ if (!ssValue.empty())
+ {
+ char fTmp;
+ char fUnused;
+ std::string unused_string;
+ ssValue >> fTmp >> fUnused >> unused_string;
+ strErr = strprintf("LoadWallet() upgrading tx ver=%d %d %s",
+ wtx.fTimeReceivedIsTxTime, fTmp, hash.ToString());
+ wtx.fTimeReceivedIsTxTime = fTmp;
+ }
+ else
+ {
+ strErr = strprintf("LoadWallet() repairing tx ver=%d %s", wtx.fTimeReceivedIsTxTime, hash.ToString());
+ wtx.fTimeReceivedIsTxTime = 0;
+ }
+ wss.vWalletUpgrade.push_back(hash);
}
- wss.vWalletUpgrade.push_back(hash);
- }
- if (wtx.nOrderPos == -1)
- wss.fAnyUnordered = true;
+ if (wtx.nOrderPos == -1)
+ wss.fAnyUnordered = true;
- pwallet->LoadToWallet(wtx);
+ return true;
+ };
+ if (!pwallet->LoadToWallet(hash, fill_wtx)) {
+ return false;
+ }
} else if (strType == DBKeys::WATCHS) {
wss.nWatchKeys++;
CScript script;
@@ -731,7 +738,7 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
return result;
}
-DBErrors WalletBatch::FindWalletTx(std::vector<uint256>& vTxHash, std::vector<CWalletTx>& vWtx)
+DBErrors WalletBatch::FindWalletTx(std::vector<uint256>& vTxHash, std::list<CWalletTx>& vWtx)
{
DBErrors result = DBErrors::LOAD_OK;
@@ -769,12 +776,9 @@ DBErrors WalletBatch::FindWalletTx(std::vector<uint256>& vTxHash, std::vector<CW
if (strType == DBKeys::TX) {
uint256 hash;
ssKey >> hash;
-
- CWalletTx wtx(nullptr /* pwallet */, MakeTransactionRef());
- ssValue >> wtx;
-
vTxHash.push_back(hash);
- vWtx.push_back(wtx);
+ vWtx.emplace_back(nullptr /* wallet */, nullptr /* tx */);
+ ssValue >> vWtx.back();
}
}
pcursor->close();
@@ -793,7 +797,7 @@ DBErrors WalletBatch::ZapSelectTx(std::vector<uint256>& vTxHashIn, std::vector<u
{
// build list of wallet TXs and hashes
std::vector<uint256> vTxHash;
- std::vector<CWalletTx> vWtx;
+ std::list<CWalletTx> vWtx;
DBErrors err = FindWalletTx(vTxHash, vWtx);
if (err != DBErrors::LOAD_OK) {
return err;
@@ -827,7 +831,7 @@ DBErrors WalletBatch::ZapSelectTx(std::vector<uint256>& vTxHashIn, std::vector<u
return DBErrors::LOAD_OK;
}
-DBErrors WalletBatch::ZapWalletTx(std::vector<CWalletTx>& vWtx)
+DBErrors WalletBatch::ZapWalletTx(std::list<CWalletTx>& vWtx)
{
// build list of wallet TXs
std::vector<uint256> vTxHash;
diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h
index ae72a5b265..e2bf229c68 100644
--- a/src/wallet/walletdb.h
+++ b/src/wallet/walletdb.h
@@ -260,8 +260,8 @@ public:
bool WriteActiveScriptPubKeyMan(uint8_t type, const uint256& id, bool internal);
DBErrors LoadWallet(CWallet* pwallet);
- DBErrors FindWalletTx(std::vector<uint256>& vTxHash, std::vector<CWalletTx>& vWtx);
- DBErrors ZapWalletTx(std::vector<CWalletTx>& vWtx);
+ DBErrors FindWalletTx(std::vector<uint256>& vTxHash, std::list<CWalletTx>& vWtx);
+ DBErrors ZapWalletTx(std::list<CWalletTx>& vWtx);
DBErrors ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256>& vHashOut);
/* Try to (very carefully!) recover wallet database (with a possible key type filter) */
static bool Recover(const fs::path& wallet_path, void *callbackDataIn, bool (*recoverKVcallback)(void* callbackData, CDataStream ssKey, CDataStream ssValue), std::string& out_backup_filename);