clone_solana_ledger/shred/
shred_code.rs1use {
2 crate::shred::{
3 common::dispatch,
4 legacy, merkle,
5 payload::Payload,
6 traits::{Shred, ShredCode as ShredCodeTrait},
7 CodingShredHeader, Error, ShredCommonHeader, ShredType, SignedData,
8 DATA_SHREDS_PER_FEC_BLOCK, MAX_DATA_SHREDS_PER_SLOT, SIZE_OF_NONCE,
9 },
10 clone_solana_sdk::{clock::Slot, hash::Hash, packet::PACKET_DATA_SIZE, signature::Signature},
11 static_assertions::const_assert_eq,
12};
13
14const_assert_eq!(MAX_CODE_SHREDS_PER_SLOT, 32_768);
15pub const MAX_CODE_SHREDS_PER_SLOT: usize = MAX_DATA_SHREDS_PER_SLOT;
16
17const_assert_eq!(ShredCode::SIZE_OF_PAYLOAD, 1228);
18
19#[derive(Clone, Debug, Eq, PartialEq)]
20pub enum ShredCode {
21 Legacy(legacy::ShredCode),
22 Merkle(merkle::ShredCode),
23}
24
25impl ShredCode {
26 pub(super) const SIZE_OF_PAYLOAD: usize = PACKET_DATA_SIZE - SIZE_OF_NONCE;
27
28 dispatch!(fn coding_header(&self) -> &CodingShredHeader);
29
30 dispatch!(pub(super) fn common_header(&self) -> &ShredCommonHeader);
31 dispatch!(pub(super) fn erasure_shard(&self) -> Result<&[u8], Error>);
32 dispatch!(pub(super) fn erasure_shard_index(&self) -> Result<usize, Error>);
33 dispatch!(pub(super) fn first_coding_index(&self) -> Option<u32>);
34 dispatch!(pub(super) fn into_payload(self) -> Payload);
35 dispatch!(pub(super) fn payload(&self) -> &Payload);
36 dispatch!(pub(super) fn sanitize(&self) -> Result<(), Error>);
37 dispatch!(pub(super) fn set_signature(&mut self, signature: Signature));
38
39 dispatch!(pub(super) fn set_index(&mut self, index: u32));
41 dispatch!(pub(super) fn set_slot(&mut self, slot: Slot));
42
43 pub(super) fn signed_data(&self) -> Result<SignedData, Error> {
44 match self {
45 Self::Legacy(shred) => Ok(SignedData::Chunk(shred.signed_data()?)),
46 Self::Merkle(shred) => Ok(SignedData::MerkleRoot(shred.signed_data()?)),
47 }
48 }
49
50 pub(super) fn chained_merkle_root(&self) -> Result<Hash, Error> {
51 match self {
52 Self::Legacy(_) => Err(Error::InvalidShredType),
53 Self::Merkle(shred) => shred.chained_merkle_root(),
54 }
55 }
56
57 pub(super) fn merkle_root(&self) -> Result<Hash, Error> {
58 match self {
59 Self::Legacy(_) => Err(Error::InvalidShredType),
60 Self::Merkle(shred) => shred.merkle_root(),
61 }
62 }
63
64 pub(super) fn new_from_parity_shard(
65 slot: Slot,
66 index: u32,
67 parity_shard: &[u8],
68 fec_set_index: u32,
69 num_data_shreds: u16,
70 num_coding_shreds: u16,
71 position: u16,
72 version: u16,
73 ) -> Self {
74 Self::from(legacy::ShredCode::new_from_parity_shard(
75 slot,
76 index,
77 parity_shard,
78 fec_set_index,
79 num_data_shreds,
80 num_coding_shreds,
81 position,
82 version,
83 ))
84 }
85
86 pub(super) fn num_data_shreds(&self) -> u16 {
87 self.coding_header().num_data_shreds
88 }
89
90 pub(super) fn num_coding_shreds(&self) -> u16 {
91 self.coding_header().num_coding_shreds
92 }
93
94 pub(super) fn erasure_mismatch(&self, other: &ShredCode) -> bool {
96 match (self, other) {
97 (Self::Legacy(shred), Self::Legacy(other)) => erasure_mismatch(shred, other),
98 (Self::Legacy(_), Self::Merkle(_)) => true,
99 (Self::Merkle(_), Self::Legacy(_)) => true,
100 (Self::Merkle(shred), Self::Merkle(other)) => {
101 erasure_mismatch(shred, other)
105 || shred.common_header().signature != other.common_header().signature
106 }
107 }
108 }
109
110 pub(super) fn retransmitter_signature(&self) -> Result<Signature, Error> {
111 match self {
112 Self::Legacy(_) => Err(Error::InvalidShredVariant),
113 Self::Merkle(shred) => shred.retransmitter_signature(),
114 }
115 }
116}
117
118impl From<legacy::ShredCode> for ShredCode {
119 fn from(shred: legacy::ShredCode) -> Self {
120 Self::Legacy(shred)
121 }
122}
123
124impl From<merkle::ShredCode> for ShredCode {
125 fn from(shred: merkle::ShredCode) -> Self {
126 Self::Merkle(shred)
127 }
128}
129
130#[inline]
131pub(super) fn erasure_shard_index<T: ShredCodeTrait>(shred: &T) -> Option<usize> {
132 let common_header = shred.common_header();
135 let coding_header = shred.coding_header();
136 if common_header
137 .fec_set_index
138 .checked_add(u32::from(coding_header.num_data_shreds.checked_sub(1)?))? as usize
139 >= MAX_DATA_SHREDS_PER_SLOT
140 {
141 return None;
142 }
143 if shred
144 .first_coding_index()?
145 .checked_add(u32::from(coding_header.num_coding_shreds.checked_sub(1)?))? as usize
146 >= MAX_CODE_SHREDS_PER_SLOT
147 {
148 return None;
149 }
150 let num_data_shreds = usize::from(coding_header.num_data_shreds);
151 let num_coding_shreds = usize::from(coding_header.num_coding_shreds);
152 let position = usize::from(coding_header.position);
153 let fec_set_size = num_data_shreds.checked_add(num_coding_shreds)?;
154 let index = position.checked_add(num_data_shreds)?;
155 (index < fec_set_size).then_some(index)
156}
157
158pub(super) fn sanitize<T: ShredCodeTrait>(shred: &T) -> Result<(), Error> {
159 if shred.payload().len() != T::SIZE_OF_PAYLOAD {
160 return Err(Error::InvalidPayloadSize(shred.payload().len()));
161 }
162 let common_header = shred.common_header();
163 let coding_header = shred.coding_header();
164 if common_header.index as usize >= MAX_CODE_SHREDS_PER_SLOT {
165 return Err(Error::InvalidShredIndex(
166 ShredType::Code,
167 common_header.index,
168 ));
169 }
170 let num_coding_shreds = usize::from(coding_header.num_coding_shreds);
171 if num_coding_shreds > 8 * DATA_SHREDS_PER_FEC_BLOCK {
172 return Err(Error::InvalidNumCodingShreds(
173 coding_header.num_coding_shreds,
174 ));
175 }
176 let _shard_index = shred.erasure_shard_index()?;
177 let _erasure_shard = shred.erasure_shard()?;
178 Ok(())
179}
180
181pub(super) fn erasure_mismatch<T: ShredCodeTrait>(shred: &T, other: &T) -> bool {
182 let CodingShredHeader {
183 num_data_shreds,
184 num_coding_shreds,
185 position: _,
186 } = shred.coding_header();
187 *num_coding_shreds != other.coding_header().num_coding_shreds
188 || *num_data_shreds != other.coding_header().num_data_shreds
189 || shred.first_coding_index() != other.first_coding_index()
190}