You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The mempool rescan code introduced by bitcoin#25351 (commit f89f8a1) calls requestMempoolTransactions while holding cs_wallet, creating a cs_wallet → cs_main lock ordering that conflicts with the existing cs_main → cs_wallet ordering in the mempool acceptance path.
requestMempoolTransactions takes LOCK2(cs_main, mempool->cs) and then calls CWallet::transactionAddedToMempool which does LOCK(cs_wallet) (reentrant on same thread).
Called while holding cs_main + mempool->cs. The signal is dispatched asynchronously via ENQUEUE_AND_LOG_EVENT to the scheduler thread. On the scheduler thread, NotificationsProxy::TransactionAddedToMempool calls CWallet::transactionAddedToMempool → LOCK(cs_wallet).
Lock order: cs_main → (async) → cs_wallet
Practical Impact
The actual deadlock risk is very low because the cs_main → cs_wallet path goes through the async validation interface scheduler — cs_main is released before the scheduler thread acquires cs_wallet. A real deadlock would require a synchronous path holding cs_main while trying to acquire cs_wallet, which doesn't currently exist.
However, the lock order debug assertions (-DDEBUG_LOCKORDER) would flag this as an inconsistency.
Note
Bitcoin Core still has the identical pattern on current master (wallet.cpp L2007). The fix would be to remove the outer WITH_LOCK(cs_wallet, ...) wrapper since transactionAddedToMempool acquires cs_wallet internally per-transaction:
Additionally, Dash-specific code in coinjoin/util.cpp has two instances of LOCK2(m_wallet.cs_wallet, ::cs_main) (lines 290, 334), which establishes the same cs_wallet → cs_main ordering and could interact with any future synchronous cs_main → cs_wallet path.
Summary
The mempool rescan code introduced by bitcoin#25351 (commit f89f8a1) calls
requestMempoolTransactionswhile holdingcs_wallet, creating acs_wallet → cs_mainlock ordering that conflicts with the existingcs_main → cs_walletordering in the mempool acceptance path.Lock Order Analysis
Path 1 — Wallet rescan (
src/wallet/wallet.cpp:2014):requestMempoolTransactionstakesLOCK2(cs_main, mempool->cs)and then callsCWallet::transactionAddedToMempoolwhich doesLOCK(cs_wallet)(reentrant on same thread).Lock order: cs_wallet → cs_main
Path 2 — Mempool acceptance (
src/validation.cpp:1185):Called while holding
cs_main+mempool->cs. The signal is dispatched asynchronously viaENQUEUE_AND_LOG_EVENTto the scheduler thread. On the scheduler thread,NotificationsProxy::TransactionAddedToMempoolcallsCWallet::transactionAddedToMempool→LOCK(cs_wallet).Lock order: cs_main → (async) → cs_wallet
Practical Impact
The actual deadlock risk is very low because the
cs_main → cs_walletpath goes through the async validation interface scheduler —cs_mainis released before the scheduler thread acquirescs_wallet. A real deadlock would require a synchronous path holdingcs_mainwhile trying to acquirecs_wallet, which doesn't currently exist.However, the lock order debug assertions (
-DDEBUG_LOCKORDER) would flag this as an inconsistency.Note
Bitcoin Core still has the identical pattern on current master (wallet.cpp L2007). The fix would be to remove the outer
WITH_LOCK(cs_wallet, ...)wrapper sincetransactionAddedToMempoolacquirescs_walletinternally per-transaction:Additionally, Dash-specific code in
coinjoin/util.cpphas two instances ofLOCK2(m_wallet.cs_wallet, ::cs_main)(lines 290, 334), which establishes the samecs_wallet → cs_mainordering and could interact with any future synchronouscs_main → cs_walletpath.Introduced By
/cc @UdjinM6