Skip to content

Commit 6eba251

Browse files
authored
fix(leiosfetch): retain range delivery through terminal response (#2173)
Retain streaming range responses through the terminal message. Signed-off-by: Chris Gianelloni <wolf31o2@blinklabs.io>
1 parent 2c0a01f commit 6eba251

7 files changed

Lines changed: 861 additions & 276 deletions

File tree

protocol/leiosfetch/README.md

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -188,16 +188,44 @@ whole node-to-node connection.
188188

189189
## Optional server responders
190190

191-
Leios fetch is optional, but not every request has a safe empty response. An
192-
unconfigured `VotesRequestFunc` returns `Votes` with an empty CBOR array,
193-
returning the protocol to `Idle` without a connection-level error. When a
194-
block, block-transactions, or block-range callback is unconfigured, the server
195-
enters the corresponding server-agency state and leaves the request pending.
196-
It sends no response because the available absence replies are either
197-
placeholder wire IDs or ambiguous with a real response. The requester cannot
198-
start another Leios fetch exchange, but other mini-protocols on the bearer
199-
remain usable. Errors from configured callbacks and transport failures are
200-
still propagated.
191+
Leios fetch is optional, but an unconfigured responder must never retain server
192+
agency. A server that accepts a request and never answers wedges the
193+
requester's client for the life of the connection: `protocol.sendLoop` waits
194+
for agency that only the missing response returns, so the requester can neither
195+
issue another Leios fetch request nor detect the condition.
196+
197+
- An unconfigured `VotesRequestFunc` returns `Votes` with an empty CBOR array.
198+
- An unconfigured `BlockRequestFunc` returns `NoBlock`, and an unconfigured
199+
`BlockTxsRequestFunc` returns `NoBlockTxs`. Both wire IDs are still
200+
placeholders, but the configured not-available path already emits them, so
201+
declining here adds no wire risk that the normal path does not already take.
202+
- An unconfigured `BlockRangeRequestFunc` returns a protocol error, because
203+
`LastBlockAndTxsInRange` carries a mandatory block and there is no absence
204+
reply to send. A connection-level error is diagnosable and lets the
205+
requester's peer governance replace the peer; a silent hang is neither.
206+
207+
Errors from configured callbacks and transport failures are still propagated.
208+
209+
## Abandoned requests
210+
211+
`BlockRequest`, `BlockTxsRequest`, `VotesRequest`, and `BlockRangeRequest` are
212+
bounded by the caller's context. These requests share one connection-wide slot
213+
because their responses carry no request identifier. A request whose context
214+
expires is abandoned: its delivery channel is cleared so a late response is
215+
dropped rather than mis-delivered, and the slot stays busy so the next request
216+
cannot be correlated with the outstanding response. For `BlockRangeRequest`,
217+
this applies to the whole streaming exchange; the terminal response drains the
218+
abandoned slot.
219+
220+
A later request waits a bounded grace period for that response to drain. If it
221+
arrives, the connection continues normally. If it does not, the exchange is
222+
desynchronised beyond recovery and the client fails the connection with
223+
`ErrRequestSlotAbandoned` so peer governance can drop and replace the peer.
224+
This is deliberately narrower than a protocol-level state timeout, which would
225+
also fire for a healthy relay that merely responded slowly. `StateBlock` and
226+
`StateBlockTxs` still carry no `StateMap` timeout; `StateVotes` and
227+
`StateBlockRange` retain their protocol-level timeout for exchanges that never
228+
return agency.
201229

202230
## Notes
203231

0 commit comments

Comments
 (0)