connectd: swallow channel-scoped error instead of queuing it - #9436
connectd: swallow channel-scoped error instead of queuing it#9436vincenzopalazzo wants to merge 2 commits into
Conversation
BOLT ElementsProject#1 says upon receiving a channel-scoped error the node MUST fail that channel. connectd only told lightningd about WIRE_ERROR when find_subd failed; if a dying channeld still existed the error was queued and never read, so the channel stayed CHANNELD_NORMAL. The test rolls l2's db back after a payment, freezes l1's channeld after reestablish, then lets l2 send "Awaiting unilateral close". It fails until the next commit. Reproduces: ElementsProject#9424 Reported-by: Leo Nash (@tankyleo) Signed-off-by: Vincenzo Palazzo <vincenzopalazzodev@gmail.com>
5e70d0d to
cf9378e
Compare
channeld abort()s on WIRE_ERROR ("swallowed by connectd"), but we
only told lightningd when find_subd failed. If a subd existed we
enqueued the error; a dying channeld never read it, and a live
one would abort, so the channel stayed up.
Always tell lightningd via CONNECTD_PEER_SPOKE and do not enqueue.
handle_peer_spoke already permanently fails the channel.
Fixes: ElementsProject#9424
Changelog-Fixed: Protocol: fail the channel on a peer error even if channeld is exiting.
Reported-by: Leo Nash (@tankyleo)
Signed-off-by: Vincenzo Palazzo <vincenzopalazzodev@gmail.com>
cf9378e to
996dc6e
Compare
| l1.pay(l2, 200000000) | ||
|
|
||
|
|
||
| @unittest.skipIf(os.getenv('TEST_DB_PROVIDER', 'sqlite3') != 'sqlite3', "sqlite3-specific DB rollback") |
There was a problem hiding this comment.
tests/test_closing.py has three pre-existing tests (test_onchain_reestablish_reply at line 4632, and two more around lines 4661 and 4753) that reconnect a peer to an already-closed channel and then call daemon.wait_for_log("peer_in WIRE_ERROR"). That log line is produced by peer_read() in common/peer_io.c at lines 18-27 via status_peer_io(), which only runs inside the subd (channeld/closingd), when it reads the message off its own socketpair to connectd. But with this fix, connectd/multiplex.c new block runs before find_subd() and returns immediately - the message is never written to subd->outq, so the subd peer_read() never sees it, and "peer_in WIRE_ERROR" is never logged again for a channel-scoped error. The new connectd branch also doesnt call status_peer_io() itself, so this specific log line disappears entirely, not just for one path. these three tests use that log line as their synchronization point before asserting the channel state. If the line never appears, wait_for_log will time out and the tests will fail. Maybe we need to run these three tests against this branch to confirm. If they do fail, either add an equivalent debug log call in the new connectd branch (status_peer_io(LOG_IO_IN, &peer->id, decrypted)) before forwarding, so the same observability is kept, and update the tests to match the new log source, or drop the log-based wait in these tests in favor of the state check that already follows it?
BOLT #1 says upon receiving a channel-scoped
errorthe node MUST fail that channel. connectd only told lightningd aboutWIRE_ERRORwhenfind_subdfailed; if a subd existed the error was queued to it.channeldabort()s if it ever seesWIRE_ERROR("swallowed by connectd"), and a dyingchanneldnever reads the queue, so the channel stayedCHANNELD_NORMAL.Always swallow a channel-scoped
WIRE_ERRORin connectd: tell lightningd viaCONNECTD_PEER_SPOKEand do not enqueue, whether or not a subd exists.handle_peer_spokealready permanently fails the channel. Do not create a dummy subd just to carry the error.Two commits, failing test then fix:
tests: reproduce lost channel error while channeld is exiting(@pytest.mark.xfail(strict=True))connectd: swallow channel-scoped error instead of queuing it(removes the xfail)Local
test_channel_error_not_lost_while_channeld_exits:Timeout while waiting for AWAITING_UNILATERAL)Thanks to Leo Nash (@tankyleo) for the report.
Fixes: #9424
Reported-by: Leo Nash (@tankyleo)
Changelog-Fixed: Protocol: fail the channel on a peer error even if channeld is exiting.