wallet: Assertion `!wtx.isConfirmed()` failed #34599

issue dergoegge opened this issue on February 16, 2026
  1. dergoegge commented at 1:28 PM on February 16, 2026: member

    This assertion may fail if the abandontransaction RPC is invoked.

    2026-02-14T22:10:25Z [validation:debug] TransactionAddedToMempool: txid=9b7c74aa66902368b7c802b4316116820928c94f59ab149b6d2d5f626e3087d7 wtxid=8f74ad52785dc43786cd10d74aa902af6250367b695da94a5253afffd620d525
    2026-02-14T22:10:25Z [validation:debug] TransactionAddedToMempool: txid=4ab2539222a69a6d1b2a024c3440e79c39a6e0e960a43c817b6251a59a97dc30 wtxid=bbb480078ed2cd7ade22877e63357daac28f9e1cfbe73a8f483ac938a9d4bc40
    2026-02-14T22:10:25Z [net:debug] received: inv (37 bytes) peer=0
    2026-02-14T22:10:25Z [net:debug] got inv: wtx 0a5e16ee258b32dd6a63885aad733ca1e5f1a00acde6e61740904c1af72937f6  new peer=0
    2026-02-14T22:10:26Z [http:debug] Received a POST request for / from 10.89.0.6:38644
    2026-02-14T22:10:26Z [rpc:debug] ThreadRPCServer method=listtransactions user=user
    2026-02-14T22:10:27Z [net:debug] sending inv (73 bytes) peer=1
    2026-02-14T22:10:27Z [net:debug] Requesting wtx 0a5e16ee258b32dd6a63885aad733ca1e5f1a00acde6e61740904c1af72937f6 peer=0
    2026-02-14T22:10:27Z [net:debug] sending getdata (37 bytes) peer=0
    2026-02-14T22:10:27Z [http:debug] Received a POST request for / from 10.89.0.6:38644
    2026-02-14T22:10:27Z [rpc:debug] ThreadRPCServer method=abandontransaction user=user
    bitcoind: wallet/wallet.cpp:1307: auto wallet::CWallet::AbandonTransaction(CWalletTx &)::(anonymous class)::operator()(CWalletTx &) const: Assertion `!wtx.isConfirmed()' failed.
    

    Debug logs for the node that hit the assertion as well as the full test logs can be found here.

    This was found with a test running on Antithesis.

  2. fanquake added the label Wallet on Feb 16, 2026
  3. fanquake renamed this:
    wallet: Assertion `!wtx.isConfirmed()' failed
    wallet: Assertion `!wtx.isConfirmed()` failed
    on Feb 16, 2026
  4. tony-ku referenced this in commit 0bb1746283 on Apr 19, 2026
  5. tony-ku commented at 5:19 PM on April 19, 2026: none

    Opened a fix in #35115.

  6. Luquitasjeffrey commented at 4:41 AM on April 21, 2026: none

    I was able to reproduce the issue locally by altering the wallet.dat file specifically in the part that stores wallet transaction states. To reproduce it on demand I created a patch that intentionally corrupted the wallet.dat file by randomly Serializing transactions as "Inactive" but they were confirmed:

    diff --git a/src/wallet/transaction.h b/src/wallet/transaction.h index 29baf6695a..b3ff344ee1 100644 --- a/src/wallet/transaction.h +++ b/src/wallet/transaction.h @@ -300,12 +300,20 @@ public: uint32_t dummy_int = 0; // Used to be fTimeReceivedIsTxTime uint256 serializedHash = TxStateSerializedBlockHash(m_state); int serializedIndex = TxStateSerializedIndex(m_state);

    •    if (rand() % 5 == 0)
    •    {
    •        std::cout<< "[ljeffrey]: "<<"Corrupting state on transaction "<<tx->GetHash().ToString()<<std::endl;
    •        TxState inactive = TxStateInactive{};
    •        serializedHash = TxStateSerializedBlockHash(inactive);
    •        serializedIndex = TxStateSerializedIndex(inactive);
    •    }
         s << TX_WITH_WITNESS(tx) << serializedHash << dummy_vector1 << serializedIndex << dummy_vector2 << mapValueCopy << vOrderForm << dummy_int << nTimeReceived << dummy_bool << dummy_bool;

      }

      template<typename Stream> void Unserialize(Stream& s) {

    •    // Sera que el problema es que no estoy revalidando aca la transaccion?
         Init();
      
         std::vector<uint256> dummy_vector1; // Used to be vMerkleBranch

    The root issue is not in the abandonTransaction call itself but is that the wallet is blindly trusting the transactions status in the wallet.dat file, and it's not double checking them after recovering from a file. As conclusion, a carefully corrupted wallet.dat file can crash a bitcoin-core node. The wallet should rescan transactions and double-check them. I will create a pr on this week trying to solve this problem

  7. Luquitasjeffrey commented at 4:34 AM on April 22, 2026: none

    I was able to create an unit test that reproduces the bug without touching the wallet internal state, it touches only the wallet database. Currently working on this branch: https://github.com/Luquitasjeffrey/bitcoin/tree/issue34599

  8. achow101 commented at 9:12 PM on May 14, 2026: member

    This appears to be caused by a very unlucky race that occurs during loading.

    The crash requires an unclean shutdown and a parent transaction that ends up with an Inactive state, and a child that ends up with a Confirmed state. When the node restarts after the unclean shutdown, it's chainstate is behind where the wallet last recorded it's tip. As the wallet loads transactions, it will check to see whether Confirmed transactions are still confirmed according to the node's current chain state. If the confirming block is not yet in the chain, the transaction will be reset to Inactive. This is how the parent becomes Inactive.

    As the wallet continues loading, the chain is also advancing. The issue is that when the wallet starts AttachChain, the chain may have advanced past the block confirming the parent transaction. When AttachChain finishes connecting the signals and doing rescans, it does so from the current tip at the time that AttachChain starts. When the child transaction is confirmed in a block that is processed after AttachChain, it's status becomes Confirmed. Crucially, some blocks that were reprocessed end up being missed, so the parent transaction's state is never corrected.

    When abandontransaction is called on the parent transaction, it finds that it is allowed to be abandoned because it's state is Inactive. Since abandoning also abandons all of the children, it will attempt to abandon the child transaction, but then run into the assertion because the state of the child is Confirmed.

    The solution is to fix this state updating during loading that is missing blocks. The assertion is correct as it enforces the invariants for abandoning transactions.

    Unfortunately I don't know how to write a functional test that can exercise this case, and I don't think a unit test would be sufficient. I have some ideas on the fix though.

    Edit: I have a test

  9. achow101 commented at 12:15 AM on May 15, 2026: member

    #35294 should be the fix. @dergoegge can you try that in antithesis?

  10. dergoegge commented at 9:02 AM on May 18, 2026: member

    can you try that in antithesis?

    Yes, but I'll wait for the CI to be green first


github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-05-19 06:51 UTC