Skip to main content

Crate sc_network_statement

Crate sc_network_statement 

Source
Expand description

Statement handling to plug on top of the network service.

This crate implements gossip-based propagation of statements between nodes, layered on the substrate notifications protocol. Two protocol versions are negotiated per peer: statement/2 (preferred) with statement/1 as a fallback.

§Propagation

  • During major chain synchronization, statement gossip is paused so peers prioritize downloading blocks; it resumes automatically once the node is fully synced (peers are reconnected to recover statements missed while syncing).
  • A propagation loop runs every second (config::PROPAGATE_TIMEOUT): it takes all statements added since the previous round and queues their hashes to a per-peer outbox. Each peer has at most one propagation chunk in flight at a time. When its send slot is free, statements are fetched from the store, filtered and encoded up to the maximum notification size (config::MAX_STATEMENT_NOTIFICATION_SIZE, ~1 MiB).
  • Incoming statements are pushed onto a bounded validation queue (config::MAX_PENDING_STATEMENTS); if the queue is full, incoming statements are dropped.
  • Peer reputation is adjusted based on statement quality (good, duplicate, invalid, flooding).

§Tracking received statements

There is no per-peer record of delivered statements. A statement is propagated once, on the tick after its import: the propagation pass drains the store’s recent set, so no later pass can pick it up again. The only duplicates worth preventing are statements sent back to the peers they came from.

While a statement waits for validation, the peers it came from are recorded in pending_statements_peers. On import they move to recently_received_statements, and a peer that resends the statement before its tick is added there too. Propagation and initial-sync chunks both skip the recorded peers, and the propagation pass clears recently_received_statements when done.

§Initial sync

A peer joining (or changing its topic affinity) receives the store’s existing statements through a cursor over the store’s admission journal: scheduling captures the journal’s watermark, and bursts walk the admissions below it chunk by chunk, advancing the cursor as each send is confirmed — a failed chunk is resent from the same position. The watermark also splits delivery ownership between the two paths: admissions below the peer’s highest watermark are the sync cursor’s job, and propagation skips them, so within one sync a statement reaches the peer through at most one path. Duplicates stay possible at the edges — an affinity-change re-sync restarts the cursor from zero and redelivers earlier admissions, and a chunk whose send timed out may have arrived regardless, so its resend repeats it.

§Send scheduling

Every peer has one send slot, shared by propagation and initial sync, so at most one chunk per connection is in flight. Each chunk carries a fresh id, so the result of a send left over from a previous connection cannot free the current one’s slot. A completed chunk frees the slot at once and the next propagation chunk follows, a failed send included: a failed propagation chunk is not retried, but the rest of the backlog keeps draining, while a failed initial-sync chunk is resent from the sync’s cursor.

Propagation queues hashes in a per-peer outbox and fetches, filters and encodes them only when the slot is free, so a slow peer holds one encoded chunk rather than its whole backlog. An outbox past config::MAX_PROPAGATION_OUTBOX_LEN drops its oldest hashes, since the freshest statements are the ones still worth delivering. Dropped hashes are counted in undelivered_statements.

In-flight bytes of both kinds are held against the shared config::MAX_SEND_IN_FLIGHT_BYTES budget. A peer that finds the budget full, or whose store fetch fails, is parked once and refilled in parking order as completed sends free bytes and on propagation ticks. While initial syncs are pending, propagation parks config::INITIAL_SYNC_RESERVED_BYTES early: refills reclaim freed bytes synchronously, while the timer-driven sync bursts would otherwise always find the budget full.

§Topic affinity and light nodes

The statement/2 protocol lets a peer advertise which topics it cares about as a bloom filter (“topic affinity”). Once a peer has an active affinity filter, only matching statements are forwarded to it; when its affinity changes, newly relevant statements are re-sent. Affinity advertisements are rate-limited. See the affinity module.

Light-client peers on statement/2 must advertise an affinity before receiving any statements: a light V2 peer pulls only the topics it cares about instead of the full feed, and is synced those statements in an initial burst on connect. Full nodes receive all statements unless they opt into an affinity.

§Usage

Modules§

config
Configuration of the statement protocol

Structs§

StatementHandler
Handler for statements. Call StatementHandler::run to start the processing.
StatementHandlerPrototype
Prototype for a StatementHandler.

Type Aliases§

StatementImportFuture
Future resolving to statement import result.
Statements
A set of statements.