-
Notifications
You must be signed in to change notification settings - Fork 191
Description
Summary
When a taker client fails to broadcast a transaction due to spent inputs (bad-txns-inputs-missingorspent), the retry mechanism never triggers, leaving the client in a zombie state that polls indefinitely without recovery.
Disclaimer
The issue has been encountered within an emulated environment (https://github.com/DavidRajnoha/coinjoin-simulator) – the conditions under which the bug occurs (availability of makers, frequency of taker coinjoin requests) might be different from real environment.
Steps to reproduce
- Start tumbler/RPC coinjoin
- Maker's UTXO gets spent between negotiation and broadcast
- Broadcast fails: error pushing = -25 bad-txns-inputs-missingorspent
- RPC Client becomes unresponsive to further rpc commands
Probable root cause
Missing Callback in handle_unbroadcast_transaction()
Location: src/jmclient/taker.py:932-934
if not self.push_ourselves():
jlog.error("Failed to broadcast transaction: ")
jlog.info(btc.human_readable_transaction(tx))
# MISSING: self.on_finished_callback(False, fromtx=True)
When self-broadcast fails, the error is logged but on_finished_callback() is never called to trigger retry logic.
Compare to push() method (lines 981-982) which correctly handles failure:
if not pushed:
self.on_finished_callback(False, fromtx=True) # Triggers retry
Issue 2: Flawed Stall Monitor Logic
Location: src/jmclient/client_protocol.py:645-652
if not self.client.txid:
jlog.info("Stall detected. Retrying transaction if possible ...")
self.client.on_finished_callback(False, True, 0.0)
else:
jlog.info("Tx was already pushed; ignoring")
Problem: Assumes if txid is set, broadcast succeeded. However, txid is calculated and set before broadcast attempt (line 941 in push()), so it's set regardless of success/failure.
Logs
06:13:01 [INFO] all makers have sent their signatures
06:13:02 [INFO] txid = 8062310600b7db8f... # txid set BEFORE broadcast
06:16:02 [WARN] error pushing = -25 bad-txns-inputs-missingorspent
06:16:02 [ERROR] Failed to broadcast transaction: # No callback triggered!
06:30:00 [INFO] STALL MONITOR: Tx was already pushed; ignoring # Wrong!
06:31:24 [DEBUG] rpc: getwalletinfo [] # Called by external client, polls forever...