Skip to main content

Module frames

Module frames 

Source
Expand description

Per-subscriber fan-out of the frames arriving on a pooled peer’s session.

§Why the pool needs this at all

A pooled session’s inbound mpsc::Receiver<Message> is consumed by ONE task. Before this module that task folded NewPeakWallet into an atomic and discarded everything else, so a consumer that needs the frames themselves — a wallet replica following CoinStateUpdate — could not be served from a pooled session and had to dial its own. That is the reason the node ran several independent peer stacks (dig_ecosystem#2761).

§Every frame names the session it came from

The pool holds many peers at once and fans all of their frames into one subscription, so a frame that does not say who sent it is a claim from the pool, which no peer in it is entitled to make. CoinStateUpdate is an UNSOLICITED push carrying no request id, so an unattributed fan-out lets any held peer inject fabricated coin states that a subscriber cannot tell from the peer it deliberately followed — and cannot eject, because nothing knows who sent them.

Attribution lives on SourcedFrame, the envelope, rather than on the individual PoolFrame variants. A variant added later cannot forget to carry it, and a subscriber cannot read a frame without having its source in hand.

§Sessions, not a pool-wide generation

A SessionId identifies ONE peer connection for the life of the pool. It is allocated when that connection is admitted and never changes, so the identity a frame carries stays true whatever else the pool does afterwards.

This is deliberately not a pool-wide counter. A pool of N independent sessions has no single “current” generation to be in: a counter bumped by every reconnect makes every OTHER session’s frames look stale, so a consumer honouring it discards N-1 peers’ frames on every ordinary refill. Staleness is a property of one peer’s stream, and it is signalled on that stream.

PoolFrame::Reset opens a session, PoolFrame::SessionEnded closes it, and between them everything a subscriber sees from that source belongs to one continuous connection.

§Overflow terminates the subscriber; it never skips a frame

Each subscriber gets a BOUNDED channel, because an unbounded one turns a slow consumer into unbounded memory. When that channel is full the subscription is DROPPED and its receiver observes the stream end.

The tempting alternative — drop the frame, keep the subscription — is the failure this ordering exists to prevent. A missed CoinStateUpdate is a coin whose spend the replica never learns about, so the replica goes on reporting Synced while reading spent money as present. A terminated stream is a fact the consumer can act on; a gap is indistinguishable from quiet.

Structs§

FrameFanout
The pool’s fan-out: many subscribers, each with its own bounded queue.
FrameSource
WHO a frame came from.
FrameSubscription
The receiving half of a subscription.
SessionId
One peer connection, for the life of the pool.
SourcedFrame
A frame together with the session that produced it.

Enums§

PoolFrame
One frame from a pooled peer session, as a subscriber sees it.
SessionEndReason
Why a session stopped producing frames.