@@ -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