Skip to content
Docs

Solana shred anatomy reference

Identify every logical region needed to parse, authenticate, recover, and reassemble a shred.

Before you start

  • A captured UDP datagram no larger than 1,228 bytes
  • A pinned Agave release

Read a shred as four regions

A raw datagram contains one shred. Its four logical regions are the common header, the type-specific header, erasure-coded material, and Merkle material determined by the variant. Serialized ledger bytes belong to data shreds. Reed-Solomon parity over that data material belongs to coding shreds. Both types participate in one FEC set.

Datagram length never exceeds 1,228 bytes. That limit does not reveal useful data capacity. Merkle proof size and retransmitter-signature presence change the space available to a data shred. Ask the parser for data() or capacity for the parsed variant.

Common header

The current Agave wire implementation serializes an 83-byte common header. These byte ranges are verified against its public wire readers and serialization tests:

RangeWidthFieldMeaning
0..6464signatureEd25519 leader signature
64..651variantType, proof-size bits, and variant flags
65..738slotLittle-endian slot number
73..774indexLittle-endian index within its shred type
77..792versionLittle-endian shred version
79..834fec_set_indexLittle-endian first data index of the erasure set

Treat the signature as opaque until the variant parser defines the signed message. In current Merkle forms, the reconstructed Merkle root is what the leader signs, not an arbitrary fixed slice selected by application code.

The two shred types use separate index spaces. A shred's identity is (slot, index, shred_type). Without type, equal numeric indexes from one data and one coding shred would collide.

Data header

The current data header follows the common header and ends at byte 88:

RangeWidthFieldMeaning
83..852parent_offsetSlot minus parent slot, validated against the slot
85..861flagsReference tick plus completion bits
86..882sizeEnd of the declared header plus ledger data

The low six flag bits hold a saturated reference-tick value. 0x40 is DATA_COMPLETE_SHRED. 0xC0 represents LAST_SHRED_IN_SLOT and also implies data complete. Use the bitflag implementation from the pinned release rather than accepting arbitrary bits.

The size field is not the UDP datagram length. It identifies how much of the data shred contains headers plus ledger data. Padding and Merkle material can follow. A typed parser validates the declared size against the parsed variant and returns only the ledger data slice.

Coding header

The current coding header ends at byte 89:

RangeWidthFieldMeaning
83..852num_data_shredsData shard count k
85..872num_coding_shredsParity shard count m
87..892positionCoding position in 0..m

A coding shred's erasure-shard position is k + position. Its numeric shred index is not that local array position. Coding shreds in one set must agree on k, m, the first coding index derived as index - position, version, slot, FEC-set index, proof form, root, and leader signature.

Current Agave usually targets 32 data shreds plus 32 coding shreds in each FEC block. A final block may be shorter. Derive k and m from its sanitized coding header instead of allocating every set under a permanent 32 by 32 assumption.

Merkle regions

The variant byte's low four bits encode proof entry count. High bits select data or coding and whether a retransmitter signature is present. Layout after the erasure-coded region depends on those values. Current Agave computes capacity and offsets from the parsed variant, hashes a leaf with the protocol prefix, walks the proof using the erasure-shard index, and obtains the leader-signed root.

Do not copy a proof offset from a packet capture. The exact proof start depends on whether the shred is data or coding, proof entry count, payload size, and retransmitter-signature variant. The stable mechanism is: parse variant, sanitize the typed shred, and ask it for its Merkle root or proof-related accessors. Obtain the scheduled leader assigned to that slot, then use the corresponding key for verification.

Chained Merkle data commits an FEC set to the preceding set's root. Retransmitter-signed variants carry an additional signature at the end while leaving the leader signature intact. The service forwards raw shreds without substituting its own signature for the leader's.

Parse with checked slices

This small parser is suitable for header inspection. It is not a full validator:

rust

fn le_u32(bytes: &[u8], range: std::ops::Range<usize>) -> Option<u32> {    Some(u32::from_le_bytes(bytes.get(range)?.try_into().ok()?))}fn le_u64(bytes: &[u8], range: std::ops::Range<usize>) -> Option<u64> {    Some(u64::from_le_bytes(bytes.get(range)?.try_into().ok()?))} fn common(bytes: &[u8]) -> Option<(u8, u64, u32, u32)> {    let variant = *bytes.get(64)?;    let slot = le_u64(bytes, 65..73)?;    let index = le_u32(bytes, 73..77)?;    let fec = le_u32(bytes, 79..83)?;    Some((variant, slot, index, fec))} fn main() {    if common(&[0u8; 82]).is_some() { std::process::exit(1); }}

Use these ranges only in tests, capture tools, and the minimal receiver tied to the documented format. Production code should construct solana_ledger::shred::Shred from serialized bytes and call sanitize. Keep raw bytes because recovery and duplicate-conflict evidence may need the canonical packet.

Record the parser revision beside every stored fixture. A byte map without its release identity becomes misleading after a format transition.

Parameters

NameTypeDefaultNotes
common_header_sizebytes83Current Agave common header, pin to the tested release.
data_header_sizebytes88Current total common plus data header size.
coding_header_sizebytes89Current total common plus coding header size.
max_datagram_sizebytes1228Maximum UDP datagram delivered by this product.

When it goes wrong

Invalid payload size: N

Cause. The packet is too short or does not match the capacity required by its variant.

Fix. Reject it and retain a sampled packet plus the pinned Agave revision for diagnosis.

Invalid shred variant

Cause. The variant byte is unknown to the parser or a legacy form is disabled in that release.

Fix. Use the Agave revision matching the network; do not add a guessed variant mask.

Invalid data size: size=N, payload=M

Cause. The data header's declared size is outside the legal region for that variant.

Fix. Reject the shred before exposing data bytes.

Questions

Is a shred always 1,228 bytes?
No. A service datagram may reach 1,228 bytes, while smaller lengths also occur. Parsed shred size and useful data capacity depend on the variant and Merkle material. Allocate for the maximum, use the received datagram length, and let the matching parser validate it.
Can the data size field be used as the UDP length?
No. The data size marks the end of common header, data header, and ledger data inside a data shred. Padding, chained-root data, Merkle proof entries, or a retransmitter signature can occupy other regions. The receive length and declared data size serve different purposes.
Why is shred type part of the identity?
Data indexes advance independently of coding indexes. Both types can share a slot and numeric index without representing the same packet. Deduplicate with an identity key ordered as shred type, slot, then index. FEC grouping instead combines FEC-set index with its slot.