MF-M02: fix(rpc): release Serve wait group on processSink overflow#732
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
ihsraham
left a comment
There was a problem hiding this comment.
approved for the m-02 fix. the queue-full read path now calls the shared closure hook before returning, so the connection wait group can finish and the outer handler can remove the websocket from the hub.
that closes the unauthenticated resource-exhaustion path from the finding, and the regression test covers the stuck cleanup case directly.
readMessages returned without invoking handleClosure when processSink was full, leaving the Serve wait group stuck at one outstanding Done. The parent closure callback never fired, the underlying WebSocket was never closed, and the outer HTTP handler stayed blocked, preventing its deferred connHub.Remove. An unauthenticated client could exhaust server resources by sending messages faster than the queue drained. Call handleClosure(nil) before returning from the queue-full branch so the wait group invariant holds. Add a regression test that fills processSink without a consumer and asserts the parent closure fires plus the underlying connection is closed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
3f0abd4 to
3bbcab0
Compare
- MF-L01: fix(contracts/ChannelHub): cap ERC20 transfer returndata copy to 32 bytes (#726) - MF-H01: fix(nitronode): paginate get_last_key_states endpoints (#724) - MF-I01-I02: fix(contracts): address security audit findings I-01 and I-02 (#728) - MF-C01: rpc: cap inbound WebSocket frame size and rate-limit per connection (#723) - MF-L02: docs(protocol): qualify enforcement guarantee for intent-specific execution paths (#737) - MF-L02-I03-I04_I05: fix(contracts): add more Node trust assumptions and requirements (#738) - MF-M01: backfill state user_sig from on-chain events (#731) - MF-M02: fix(rpc): release Serve wait group on processSink overflow (#732) - Fix SDK acknowledgement before home channel creation (#734) - MF-I06: fix(nitronode): gate escrow transitions on home channel onchain materialization (#730) - MF-M05: fix(nitronode): enforce TLS by default for Postgres (#733) - MF-M07: Unblock receiver states after finalized escrow operations (#735) - MF-M04: feat: provide tooling for and enhance docs on ValidatorRegistered event (#744) - MF-L04: fix(contracts): reject redundant native value (#741) - MF-H02: bind session key registration to a single owner per kind (#739) - MF-I07: fix(contracts): enforce max challenge duration (#752) - MF-M08: fix(rpc): replace Origin label with application_id on connection gauge (#745) - MF-C02: fix(core): add ChannelStatusClosing to gate post-finalize state transitions (#746) - MF-L06: fix(contracts): clear stale challengeExpireAt on cooperative escrow finalization (#754) - MF-I08: docs: document ChannelClosed event orientation ambiguity during abandoned migration (#755) - MF-M09: fix(nitronode): auto-challenge home channel on withheld escrow finalize (#753) - MF-L09: fix(nitronode): validate parsed app session nonce (#751) - MF-L05: docs(contracts): document informational events not guaranteed to emit (#756) - MF-L08: fix(nitronode/api): default get_last_key_states to active-only with include_inactive opt-in (#749) - MF-L10: fix: emit escrowIds array in EscrowDepositsPurged event and handle it in Nitronode (#757)
Summary
readMessagesreturned without callinghandleClosurewhenprocessSinkwas full, leaving theServewait group stuck at one outstandingDone. The parent closure callback never fired, the WebSocket was never closed, and the outer HTTP handler stayed blocked —connHub.Removenever ran. Unauthenticated clients could exhaust server resources by flooding messages faster than the queue drained.handleClosure(nil)before returning from the queue-full branch so the wait group invariant (every early return decrements exactly once) holds.processSinkwithout a consumer and asserts the parent closure fires and the underlying connection is closed.Notes
fix/nitronode-mf-c01(part of broader frame-size + rate-limiter hardening). Three-way merge between this branch and c01 is clean — identical line addition, non-overlapping hunks.frameRateLimiter.Admitearly-return path with the samehandleClosure(nil)shape.Test plan
go test ./pkg/rpc/... -count=1passesparent handleClosure not invoked after processSink overflow; goroutine leak)go vet ./pkg/rpc/...clean🤖 Generated with Claude Code