@@ -61,6 +61,8 @@ int64_t nStartupTime = GetTime(); //!< Client startup time for use with automint
6161 */
6262CFeeRate CWallet::minTxFee = CFeeRate(10000 );
6363
64+ const uint256 CMerkleTx::ABANDON_HASH (uint256S(" 0000000000000000000000000000000000000000000000000000000000000001" ));
65+
6466/* * @defgroup mapWallet
6567 *
6668 * @{
@@ -469,8 +471,11 @@ bool CWallet::IsSpent(const uint256& hash, unsigned int n) const
469471 for (TxSpends::const_iterator it = range.first ; it != range.second ; ++it) {
470472 const uint256& wtxid = it->second ;
471473 std::map<uint256, CWalletTx>::const_iterator mit = mapWallet.find (wtxid);
472- if (mit != mapWallet.end () && mit->second .GetDepthInMainChain () >= 0 )
473- return true ; // Spent
474+ if (mit != mapWallet.end ()) {
475+ int depth = mit->second .GetDepthInMainChain ();
476+ if (depth > 0 || (depth == 0 && !mit->second .isAbandoned ()))
477+ return true ; // Spent
478+ }
474479 }
475480 return false ;
476481}
@@ -694,7 +699,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletD
694699 for (const CTxIn& txin : wtx.vin ) {
695700 if (mapWallet.count (txin.prevout .hash )) {
696701 CWalletTx& prevtx = mapWallet[txin.prevout .hash ];
697- if (prevtx.nIndex == -1 && !prevtx.hashBlock . IsNull ()) {
702+ if (prevtx.nIndex == -1 && !prevtx.hashUnset ()) {
698703 MarkConflicted (prevtx.hashBlock , wtx.GetHash ());
699704 }
700705 }
@@ -704,7 +709,12 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletD
704709 bool fUpdated = false ;
705710 if (!fInsertedNew ) {
706711 // Merge
707- if (wtxIn.hashBlock != 0 && wtxIn.hashBlock != wtx.hashBlock ) {
712+ if (!wtxIn.hashUnset () && wtxIn.hashBlock != wtx.hashBlock ) {
713+ wtx.hashBlock = wtxIn.hashBlock ;
714+ fUpdated = true ;
715+ }
716+ // If no longer abandoned, update
717+ if (wtxIn.hashBlock .IsNull () && wtx.isAbandoned ()) {
708718 wtx.hashBlock = wtxIn.hashBlock ;
709719 fUpdated = true ;
710720 }
@@ -752,7 +762,7 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pbl
752762{
753763 {
754764 AssertLockHeld (cs_wallet);
755-
765+
756766 if (pblock) {
757767 for (const CTxIn& txin : tx.vin ) {
758768 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range (txin.prevout );
@@ -765,7 +775,7 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pbl
765775 }
766776 }
767777 }
768-
778+
769779 bool fExisted = mapWallet.count (tx.GetHash ()) != 0 ;
770780 if (fExisted && !fUpdate ) return false ;
771781 if (fExisted || IsMine (tx) || IsFromMe (tx)) {
@@ -783,6 +793,63 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pbl
783793 return false ;
784794}
785795
796+ bool CWallet::AbandonTransaction (const uint256& hashTx)
797+ {
798+ LOCK2 (cs_main, cs_wallet);
799+
800+ // Do not flush the wallet here for performance reasons
801+ CWalletDB walletdb (strWalletFile, " r+" , false );
802+
803+ std::set<uint256> todo;
804+ std::set<uint256> done;
805+
806+ // Can't mark abandoned if confirmed or in mempool
807+ assert (mapWallet.count (hashTx));
808+ CWalletTx& origtx = mapWallet[hashTx];
809+ if (origtx.GetDepthInMainChain () > 0 || origtx.InMempool ()) {
810+ return false ;
811+ }
812+
813+ todo.insert (hashTx);
814+
815+ while (!todo.empty ()) {
816+ uint256 now = *todo.begin ();
817+ todo.erase (now);
818+ done.insert (now);
819+ assert (mapWallet.count (now));
820+ CWalletTx& wtx = mapWallet[now];
821+ int currentconfirm = wtx.GetDepthInMainChain ();
822+ // If the orig tx was not in block, none of its spends can be
823+ assert (currentconfirm <= 0 );
824+ // if (currentconfirm < 0) {Tx and spends are already conflicted, no need to abandon}
825+ if (currentconfirm == 0 && !wtx.isAbandoned ()) {
826+ // If the orig tx was not in block/mempool, none of its spends can be in mempool
827+ assert (!wtx.InMempool ());
828+ wtx.nIndex = -1 ;
829+ wtx.setAbandoned ();
830+ wtx.MarkDirty ();
831+ wtx.WriteToDisk (&walletdb);
832+ // Iterate over all its outputs, and mark transactions in the wallet that spend them abandoned too
833+ TxSpends::const_iterator iter = mapTxSpends.lower_bound (COutPoint (hashTx, 0 ));
834+ while (iter != mapTxSpends.end () && iter->first .hash == now) {
835+ if (!done.count (iter->second )) {
836+ todo.insert (iter->second );
837+ }
838+ iter++;
839+ }
840+ // If a transaction changes 'conflicted' state, that changes the balance
841+ // available of the outputs it spends. So force those to be recomputed
842+ for (const CTxIn& txin: wtx.vin )
843+ {
844+ if (mapWallet.count (txin.prevout .hash ))
845+ mapWallet[txin.prevout .hash ].MarkDirty ();
846+ }
847+ }
848+ }
849+
850+ return true ;
851+ }
852+
786853void CWallet::MarkConflicted (const uint256& hashBlock, const uint256& hashTx)
787854{
788855 LOCK2 (cs_main, cs_wallet);
@@ -828,7 +895,7 @@ void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx)
828895 }
829896 // If a transaction changes 'conflicted' state, that changes the balance
830897 // available of the outputs it spends. So force those to be recomputed
831- BOOST_FOREACH (const CTxIn& txin, wtx.vin )
898+ for (const CTxIn& txin: wtx.vin )
832899 {
833900 if (mapWallet.count (txin.prevout .hash ))
834901 mapWallet[txin.prevout .hash ].MarkDirty ();
@@ -987,7 +1054,7 @@ int CWalletTx::GetRequestCount() const
9871054 LOCK (pwallet->cs_wallet );
9881055 if (IsCoinBase ()) {
9891056 // Generated block
990- if (hashBlock != 0 ) {
1057+ if (! hashUnset () ) {
9911058 std::map<uint256, int >::const_iterator mi = pwallet->mapRequestCount .find (hashBlock);
9921059 if (mi != pwallet->mapRequestCount .end ())
9931060 nRequests = (*mi).second ;
@@ -999,7 +1066,7 @@ int CWalletTx::GetRequestCount() const
9991066 nRequests = (*mi).second ;
10001067
10011068 // How about the block it's in?
1002- if (nRequests == 0 && hashBlock != 0 ) {
1069+ if (nRequests == 0 && ! hashUnset () ) {
10031070 std::map<uint256, int >::const_iterator mi = pwallet->mapRequestCount .find (hashBlock);
10041071 if (mi != pwallet->mapRequestCount .end ())
10051072 nRequests = (*mi).second ;
@@ -1451,7 +1518,7 @@ void CWallet::ReacceptWalletTransactions()
14511518
14521519 int nDepth = wtx.GetDepthInMainChain ();
14531520
1454- if (!wtx.IsCoinBase () && !wtx.IsCoinStake () && nDepth == 0 ) {
1521+ if (!wtx.IsCoinBase () && !wtx.IsCoinStake () && nDepth == 0 && !wtx. isAbandoned () ) {
14551522 // Try to add to memory pool
14561523 LOCK (mempool.cs );
14571524 wtx.AcceptToMemoryPool (false );
@@ -1472,7 +1539,7 @@ void CWalletTx::RelayWalletTransaction(std::string strCommand)
14721539{
14731540 LOCK (cs_main);
14741541 if (!IsCoinBase ()) {
1475- if (GetDepthInMainChain () == 0 ) {
1542+ if (GetDepthInMainChain () == 0 && ! isAbandoned () ) {
14761543 uint256 hash = GetHash ();
14771544 LogPrintf (" Relaying wtx %s\n " , hash.ToString ());
14781545
@@ -3748,7 +3815,7 @@ int CMerkleTx::SetMerkleBranch(const CBlock& block)
37483815
37493816int CMerkleTx::GetDepthInMainChainINTERNAL (const CBlockIndex*& pindexRet) const
37503817{
3751- if (hashBlock == 0 )
3818+ if (hashUnset () )
37523819 return 0 ;
37533820 AssertLockHeld (cs_main);
37543821
@@ -5463,7 +5530,7 @@ bool CWalletTx::IsTrusted() const
54635530 return false ;
54645531 if (!bSpendZeroConfChange || !IsFromMe (ISMINE_ALL)) // using wtx's cached debit
54655532 return false ;
5466-
5533+
54675534 // Don't trust unconfirmed transactions from us unless they are in the mempool.
54685535 {
54695536 LOCK (mempool.cs );
0 commit comments