Skip to content

Deduplicate incoming RE-CONFIG requests to prevent new stream destruction#30

Open
timwu20 wants to merge 3 commits intoalgesten:mainfrom
ChainSafe:tim/deduplicate-reconfig
Open

Deduplicate incoming RE-CONFIG requests to prevent new stream destruction#30
timwu20 wants to merge 3 commits intoalgesten:mainfrom
ChainSafe:tim/deduplicate-reconfig

Conversation

@timwu20
Copy link

@timwu20 timwu20 commented Feb 27, 2026

Problem

handle_reconfig_param() in src/association/mod.rs does not deduplicate incoming ParamOutgoingResetRequest chunks. When the remote peer retransmits a RE-CONFIG request (because its SCTP RTO expired before our response arrived), we process it a second time. If the stream ID was reused between the first and second processing, reset_streams_if_any() destroys the new stream.

Reproduction sequence

  1. Remote sends RE-CONFIG(reset stream 1, seq=N)
  2. We process it: unregister_stream(1) removes stream 1. We send a RE-CONFIG response
  3. Application calls open_stream(1) — creates a new stream 1 in self.streams
  4. Remote retransmits RE-CONFIG(reset stream 1, seq=N) — RTO fired before our response arrived
  5. We process it again: self.streams.contains_key(&1) returns true (the new stream), so unregister_stream(1) removes the new stream
  6. Application calls stream(1) -> ErrStreamNotExisted. The new channel is dead

Impact

This bug causes WebRTC data channel failures in production when a data channel is opened shortly after another channel on the same SCTP stream ID is closed. It kills the block-announces notification protocol in Polkadot light client WebRTC connections, leaving the peer permanently unable to sync.

Fix

Add a FxHashSet<u32> field (reconfig_requests_seen) to the Association struct that tracks all incoming reconfig request sequence numbers. Before processing a ParamOutgoingResetRequest, check if we have already seen this sequence number. If so, resend a SuccessPerformed response without reprocessing the stream resets.

A separate set is needed because the existing reconfig_requests map cannot serve as a dedup mechanism — entries are removed after successful processing in reset_streams_if_any(), and that removal is required for the InProgress retry loop that re-evaluates pending requests as TSN advances.

Changes

  • src/association/mod.rs: Added reconfig_requests_seen: FxHashSet<u32> field and dedup guard in handle_reconfig_param()
  • src/endpoint/endpoint_test.rs: Added test_assoc_reset_duplicate_reconfig_request that verifies a replayed reconfig packet does not destroy a newly opened stream

Test plan

  • New test test_assoc_reset_duplicate_reconfig_request validates the dedup behavior by capturing reconfig packet bytes, completing the reset, reopening the stream, replaying the captured packets, and asserting the new stream survives
  • All 109 existing tests pass
  • cargo clippy reports no new warnings

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.

1 participant