Skip to content

fix: handle ChannelReady replay on reconnect#1562

Open
chenyukang wants to merge 1 commit into
nervosnetwork:developfrom
chenyukang:fix/channel-ready-reconnect
Open

fix: handle ChannelReady replay on reconnect#1562
chenyukang wants to merge 1 commit into
nervosnetwork:developfrom
chenyukang:fix/channel-ready-reconnect

Conversation

@chenyukang

@chenyukang chenyukang commented Jul 15, 2026

Copy link
Copy Markdown
Collaborator

Fixes #1544.

Summary

Recover channels that remain in AwaitingChannelReady when the peer's
ChannelReady message was lost before a disconnect.

This PR:

  • treats a duplicate ChannelReady received by an already-ready channel as an
    idempotent no-op;
  • replays the local ChannelReady only when the peer's commitment numbers
    identify the initial ready-handshake gap;
  • requires a persisted local funding confirmation and no pending commitment or
    TLC work before taking the replay path;
  • verifies that normal ready-channel reconnections do not replay
    ChannelReady.

Background

A channel may reach the following state if one ChannelReady message is lost:

Node State Commitment numbers
A ChannelReady 2/2
B AwaitingChannelReady(OUR_CHANNEL_READY) 1/1

Both nodes have observed the funding transaction confirmation and sent their
own ChannelReady. B's message reached A, allowing A to enter
ChannelReady, but A's message did not reach B.

When the peers reconnect, B resends its ChannelReady. Previously, A rejected
that duplicate because it was already in ChannelReady, while A did not replay
its own ChannelReady. B therefore remained stuck.

@chenyukang

Copy link
Copy Markdown
Collaborator Author

The regression test originally proposed in #1544 first created a fully
established channel and then changed only B's state enum back to
AwaitingChannelReady(OUR_CHANNEL_READY).

Creating a fully established channel has already executed
on_new_channel_ready() on both nodes. That transition changes the state to
ChannelReady and advances both commitment numbers from 1/1 to 2/2.
Changing only the enum therefore produced this inconsistent state:

Node State Commitment numbers
A ChannelReady 2/2
B AwaitingChannelReady(OUR_CHANNEL_READY) 2/2

B cannot naturally remain in AwaitingChannelReady after its counters have
been advanced by on_new_channel_ready().

This distinction matters because ReestablishChannel carries commitment
numbers, not the peer's local channel state or ready flags. A peer reporting
2/2 is indistinguishable from an ordinary fully-ready peer. Making the
original fixture pass would therefore require replaying ChannelReady during
normal ready-channel reconnections.

The updated regression fixture models the reachable state by keeping the
already-ready side at 2/2 and restoring the waiting side to 1/1.

@gpBlockchain

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Channel can remain stuck in AwaitingChannelReady after peers reconnect if peer ChannelReady was lost

1 participant