Skip to content
fundamentals

How do Solana shred indexes and ordering work?

Solana data shreds use slot-local indexes to define ledger order regardless of UDP arrival order. Coding shreds have a separate type index and a coding position inside their FEC set. The FEC set index anchors a source range. Receivers deduplicate by slot, type, and index, recover gaps by FEC coordinates, and decode only consecutive data ranges.

protocol desk · updated 2026-08-31

4 coordinates appear in one pipeline

A shred receiver encounters slot, common shred index, FEC set index, and, for coding shreds, coding position. These are not interchangeable counters.

Slot selects the leader opportunity and the top-level assembly bucket. Common index identifies a shred within the slot and type. FEC set index anchors a recovery group in data-index coordinates. Coding position selects a parity row inside that group.

Most ordering bugs begin by collapsing two of these coordinates. A coding common index is not a missing data index. FEC set index is not an ordinal set number. Arrival sequence is not protocol order. Keep the coordinate names explicit in types and metrics.

Data index defines byte order

Data shreds begin at index zero for a slot and increase as the leader produces more serialized entry bytes. Consecutive indexes establish concatenation order.

If indexes 40, 42, and 41 arrive in that order, assembly still emits 40, 41, 42. Index 42 can be parsed at the header level immediately, but its data bytes cannot close a consecutive range while 41 is absent.

The index belongs to the data-shred namespace. A coding shred carrying the same numeric common index does not occupy the same ledger position. Identity and duplicate tables must include type.

UDP arrival order has no authority

Raw UDP supplies datagrams independently. Turbine paths, kernel queues, fanout scheduling, and network routing can reorder them. Duplicate copies can arrive at different times. A coding packet can precede every source packet in its set.

Never append ledger bytes in receive order. Place sanitized, authenticated data by index. Maintain a contiguous frontier representing the lowest missing data index after the already consumed range.

Arrival time remains valuable for latency measurement and conflict policy, but it cannot rewrite index order. Store a monotonic receive timestamp beside the protocol coordinates rather than using one in place of the other.

Identity is slot, type, index

The basic shred identity is the tuple of slot, shred type, and common index. That key supports deduplication, storage, and conflict detection.

Two byte-identical packets under the same identity are duplicates. A data shred and coding shred with equal slot and numeric index are distinct. Two different authenticated byte strings under one identity are a conflict that requires isolation.

Shred version is an admission condition and cluster context. A multi-cluster capture should also namespace by configured cluster identity. Within an accepted single-cluster slot view, storing several versions under one identity would hide a filtering error.

FEC anchor defines a source range

Every shred carries an FEC set index. For a validated set with anchor 96 and data count 32, source data indexes occupy 96 through 127.

Data membership can be checked directly against that range after the shape is known. Coding shreds share the anchor but do not consume source indexes. Their parity rows are placed with coding position.

The last set in a batch can be smaller, so the next anchor should not be inferred from a universal step without on-wire and implementation context. Code can observe a typical 32-index stride while still validating declared dimensions and actual members.

Coding index and position coexist

A coding shred has the common index from the slot-wide coding namespace and a position from zero through coding count minus one inside its FEC set.

Common index answers which coding packet this is for identity. Position answers where its bytes enter the Reed-Solomon shard vector. One should not be recalculated from the other unless the supported protocol implementation explicitly enforces that relationship.

Use field names coding_index and coding_position. Avoid parity_index for both. During debugging, log both alongside FEC anchor. A message saying duplicate coding 7 is ambiguous when index 7 and position 7 refer to different scopes.

The contiguous frontier controls decoding

Maintain next_data_index, the first source position not yet consumed for a slot. When that index arrives or is recovered, advance through all consecutive present indexes.

Do not immediately discard bytes while advancing. A serialized entry batch ends only at a DATA_COMPLETE marker. The decoder needs the meaningful data ranges from the start of the current batch through that marker.

The frontier can pass several FEC boundaries before reaching a completion marker. Conversely, a data-complete marker can appear within available data while later source indexes for the slot remain absent. Entry-batch readiness and slot readiness are separate.

Completion flags add boundaries, not order

DATA_COMPLETE marks the end of a serialized vector of entries. LAST_IN_SLOT marks the terminal data shred and also implies data completion. The flags do not override indexes.

A last-in-slot packet arriving at index 211 does not let the receiver skip missing index 87. It reveals the proposed terminal index, which makes the gap explicit. Slot data becomes locally complete only when every data index from zero through 211 is present and the terminal flag is valid.

An authenticated data index above a previously accepted terminal index is a conflict or invalid condition. Extending the slot because a later packet arrived would make completion non-monotonic and combine incompatible claims.

Gaps are normal until they persist

Seeing index 102 before 101 is reordering, not immediate proof of loss. The receiver records the gap and continues admitting later packets. A short timer, completion marker, or FEC threshold can trigger recovery.

Gap age should use monotonic arrival time. Gap priority should consider whether it blocks the current entry-batch frontier. A missing index far beyond the frontier matters less to immediate decoding than the first absent index.

If enough members of the relevant FEC set arrive, local recovery fills the position. Otherwise the consumer waits, requests repair, uses another source, or expires the state based on its latency and completeness goals.

Duplicate delivery needs content comparison

Multiple network paths can deliver the same shred. Fast-path deduplication often hashes or compares the authenticated packet bytes after finding an existing identity.

An identical copy can update path statistics without entering FEC or assembly again. A different copy must not overwrite the first. Verify it independently enough to distinguish malformed spam from an authenticated conflict.

For Merkle shreds, equal root signatures across different identities are normal. For the same identity, different leaf content that reaches another valid root is serious evidence. Deduplication keyed only by signature will discard most of a valid Merkle set.

Buffer shape follows sparse arrival

A dense vector sized from an untrusted maximum index is unsafe. One forged packet claiming index 4,000,000,000 could request enormous memory before signature verification.

Use a sparse bounded map or validate indexes against protocol and active-slot limits before dense allocation. Once a terminal index and credible shape are known, a bounded bitmap can track presence efficiently.

Separate raw packet storage from metadata. A compact presence structure and per-index handle reduce cache pressure. Release coding positions after source completion and data bytes after completed entry batches are consumed, subject to a short conflict-diagnostic policy.

Ordering across slots is not concatenation

Data index resets for each slot. Slot 400 index zero does not follow slot 399's last data index by one global packet counter.

The parent offset in data headers expresses the proposed ledger edge. Skipped slots mean the parent can be lower than slot minus one. Forks can present alternative ancestry. Slot-number order alone does not select one canonical chain.

A live parser can maintain several recent slot assemblies independently. A replay or consensus layer later connects them by parent relationship and fork state. Do not concatenate entry bytes across slot boundaries even when the next numeric slot arrives immediately.

Parallel processing preserves order at merge

Header parsing, signature checks, Merkle proof work, and FEC recovery can run across workers. The merge point must still place results by protocol coordinates.

Tag every work item with slot, type, index, FEC anchor, set view, and receive sequence for diagnostics. When a worker completes, recheck that the slot state has not expired and that no conflicting terminal claim was accepted.

Per-slot assembly can be single-writer without making the entire pipeline single-threaded. This reduces lock complexity around the contiguous frontier and completion markers. Cryptographic and recovery work remain parallel upstream.

Useful ordering metrics

Track reorder distance as arrived_index minus current frontier when positive. Track gap age, highest observed data index, contiguous frontier, terminal index if known, recovered count, duplicate count, and authenticated conflicts.

Large reorder distance with rapid gap closure suggests path diversity rather than permanent loss. A stable frontier with ample later data and insufficient FEC members suggests concentrated loss. A known terminal index with one old gap gives a precise repair target.

Percentiles should separate slots and transport paths. One aggregate value can hide a feed where most packets are ordered but rare current-frontier gaps dominate strategy latency.

Ordered bytes remain provisional

Correct index order reconstructs the leader's proposed serialization. It does not establish execution or consensus. A fully ordered slot can later be abandoned.

Entry decoding can reveal transaction messages before execution results are known. A transaction can fail. Another fork can become canonical. Low-latency systems must attach commitment state after the fact.

Ordering is still essential. Acting on misordered bytes produces decoder errors or invented transactions. The right model is precise but provisional: authenticated bytes in leader-declared order, reconciled later against executed and rooted ledger state.

Watermarks make progress explicit

A receiver benefits from three separate watermarks. highest_seen is the greatest authenticated data index observed. contiguous_ready is the first missing index after a gap-free prefix. decoded_through is the last data index whose completed entry batch has been successfully deserialized.

highest_seen can jump far ahead during reordering. It never authorizes decoding. contiguous_ready advances only through present or recovered packets. decoded_through can trail contiguous_ready when the available prefix has no DATA_COMPLETE boundary yet.

Expose all three to scheduling. FEC priority goes to the first gap below a known completion marker. Entry-decoder work begins when contiguous_ready crosses that marker. Memory reclamation follows decoded_through rather than highest_seen.

terminal_index adds a fourth bound after LAST_IN_SLOT arrives. When contiguous_ready passes terminal_index plus one and decoded_through reaches the terminal batch, local slot data is complete. Before that, a large highest_seen value says only that later packets arrived.

Monotonic watermarks also simplify concurrency. Worker threads submit admitted packets, while one slot owner updates presence and advances frontiers. Late duplicates do not move a watermark backward. Authenticated conflicts create another block view instead of mutating coordinates already emitted.

Persist watermark transitions in compact metrics rather than logging every packet. A stall record should name slot, block view, first missing data index, nearest completion marker, FEC anchor, member count, and gap age. That snapshot tells an operator whether the bottleneck is reordering, insufficient parity, a recovery queue, or entry deserialization.

It also makes receiver comparisons use the same progress definition.

In practice

Slot 351,220,844 has data shreds through a terminal index of 143. The receiver has consumed completed entry batches through index 95.

Packets then arrive with data indexes 98, 96, 100, and 99. Index 97 is missing. The contiguous frontier advances from 96 to 97 after index 96 is placed, then stops. Index 100 carries DATA_COMPLETE, but the batch cannot be decoded because 97 is absent.

The relevant FEC set is anchored at 96 and declares 16 data shreds. Fifteen data members plus one coding position reach the threshold. Recovery reconstructs data index 97. The frontier advances through 100, the receiver concatenates meaningful bytes from indexes 96 through 100 in numeric order, and the completion flag releases the batch. Receive order never changes serialization order.

What this does not cover

This page covers receiver ordering and coordinate separation. It does not publish maximum valid slot indexes or coding-index formulas as timeless constants. Those bounds and relationships belong to the supported Agave implementation and active protocol rules.

Correct ordering reconstructs proposed entry bytes only. The page does not cover fork choice, repair protocol scheduling, transaction execution, or how blockstore persists alternative authenticated slot views.

Related questions

Does UDP arrival order match shred order?
No. Raw UDP and Turbine propagation can reorder, duplicate, and delay packets. Data shreds must be placed by slot-local data index. Arrival timestamps remain useful for latency measurement, but the index determines ledger byte order. Coding packets use separate recovery coordinates and can arrive before source data.
What key should deduplicate shreds?
Use slot, shred type, and common shred index as the basic identity within one configured cluster context. Data and coding indexes occupy separate type namespaces. Compare authenticated content for repeated identities: identical bytes are duplicates, while different authenticated bytes represent a conflict and must not overwrite each other.
What is the difference between coding index and coding position?
Coding index identifies a coding shred in the slot-wide coding namespace. Coding position identifies its parity row within one FEC set and ranges below the declared coding count. Storage and deduplication use the common index. Reed-Solomon shard placement uses coding position together with the set dimensions.
Can a last-in-slot shred close a slot with earlier gaps?
No. The flag reveals the leader's claimed terminal data index. Local slot data is complete only when every data index from zero through that terminal position is present, directly or after recovery. A terminal packet arriving early makes missing positions known but does not allow the receiver to skip them.
When should a receiver declare a packet lost?
A gap first indicates reordering. Loss becomes operationally relevant when the gap ages, blocks a completed entry batch, or remains after enough surrounding traffic has arrived. Receivers can attempt FEC recovery when the set reaches threshold, then use repair, another source, or policy-based expiry if recovery remains impossible.

Read next

Ready to build against this? The documentation covers the implementation.