1use {
3 crate::{
4 error::SlashingError,
5 shred::{Shred, ShredType},
6 state::{ProofType, SlashingProofData},
7 },
8 bytemuck::try_from_bytes,
9 solana_program::{clock::Slot, msg, pubkey::Pubkey},
10 spl_pod::primitives::PodU32,
11};
12
13pub struct DuplicateBlockProofData<'a> {
15 pub shred1: &'a [u8],
17 pub shred2: &'a [u8],
19}
20
21impl<'a> DuplicateBlockProofData<'a> {
22 const LENGTH_SIZE: usize = std::mem::size_of::<PodU32>();
23
24 pub fn pack(self) -> Vec<u8> {
27 let mut buf = vec![];
28 buf.extend_from_slice(&(self.shred1.len() as u32).to_le_bytes());
29 buf.extend_from_slice(self.shred1);
30 buf.extend_from_slice(&(self.shred2.len() as u32).to_le_bytes());
31 buf.extend_from_slice(self.shred2);
32 buf
33 }
34
35 pub const fn size_of(shred_size: usize) -> usize {
39 2usize
40 .wrapping_mul(shred_size)
41 .saturating_add(2 * Self::LENGTH_SIZE)
42 }
43}
44
45impl<'a> SlashingProofData<'a> for DuplicateBlockProofData<'a> {
46 const PROOF_TYPE: ProofType = ProofType::DuplicateBlockProof;
47
48 fn verify_proof(self, slot: Slot, _node_pubkey: &Pubkey) -> Result<(), SlashingError> {
49 let shred1 = Shred::new_from_payload(self.shred1)?;
56 let shred2 = Shred::new_from_payload(self.shred2)?;
57 check_shreds(slot, &shred1, &shred2)
58 }
59
60 fn unpack(data: &'a [u8]) -> Result<Self, SlashingError>
61 where
62 Self: Sized,
63 {
64 if data.len() < Self::LENGTH_SIZE {
65 return Err(SlashingError::ProofBufferTooSmall);
66 }
67 let (length1, data) = data.split_at(Self::LENGTH_SIZE);
68 let shred1_length = try_from_bytes::<PodU32>(length1)
69 .map_err(|_| SlashingError::ProofBufferDeserializationError)?;
70 let shred1_length = u32::from(*shred1_length) as usize;
71
72 if data.len() < shred1_length {
73 return Err(SlashingError::ProofBufferTooSmall);
74 }
75 let (shred1, data) = data.split_at(shred1_length);
76
77 if data.len() < Self::LENGTH_SIZE {
78 return Err(SlashingError::ProofBufferTooSmall);
79 }
80 let (length2, shred2) = data.split_at(Self::LENGTH_SIZE);
81 let shred2_length = try_from_bytes::<PodU32>(length2)
82 .map_err(|_| SlashingError::ProofBufferDeserializationError)?;
83 let shred2_length = u32::from(*shred2_length) as usize;
84
85 if shred2.len() < shred2_length {
86 return Err(SlashingError::ProofBufferTooSmall);
87 }
88
89 Ok(Self { shred1, shred2 })
90 }
91}
92
93fn check_shreds(slot: Slot, shred1: &Shred, shred2: &Shred) -> Result<(), SlashingError> {
107 if shred1.slot()? != slot {
108 msg!(
109 "Invalid proof for different slots {} vs {}",
110 shred1.slot()?,
111 slot,
112 );
113 return Err(SlashingError::SlotMismatch);
114 }
115
116 if shred2.slot()? != slot {
117 msg!(
118 "Invalid proof for different slots {} vs {}",
119 shred1.slot()?,
120 slot,
121 );
122 return Err(SlashingError::SlotMismatch);
123 }
124
125 if shred1.version()? != shred2.version()? {
126 msg!(
127 "Invalid proof for different shred versions {} vs {}",
128 shred1.version()?,
129 shred2.version()?,
130 );
131 return Err(SlashingError::InvalidShredVersion);
132 }
133
134 if shred1.fec_set_index()? == shred2.fec_set_index()?
136 && shred1.merkle_root()? != shred2.merkle_root()?
137 {
138 msg!(
142 "Valid merkle root conflict for fec set {}, {:?} vs {:?}",
143 shred1.fec_set_index()?,
144 shred1.merkle_root()?,
145 shred2.merkle_root()?
146 );
147 return Ok(());
148 }
149
150 if shred1.shred_type() == ShredType::Code && shred1.fec_set_index()? < shred2.fec_set_index()? {
152 let next_fec_set_index = shred1.next_fec_set_index()?;
153 if next_fec_set_index > shred2.fec_set_index()? {
154 msg!(
155 "Valid overlapping fec set conflict. fec set {}'s next set is {} \
156 however we observed a shred with fec set index {}",
157 shred1.fec_set_index()?,
158 next_fec_set_index,
159 shred2.fec_set_index()?
160 );
161 return Ok(());
162 }
163 }
164
165 if shred2.shred_type() == ShredType::Code && shred1.fec_set_index()? > shred2.fec_set_index()? {
166 let next_fec_set_index = shred2.next_fec_set_index()?;
167 if next_fec_set_index > shred1.fec_set_index()? {
168 msg!(
169 "Valid overlapping fec set conflict. fec set {}'s next set is {} \
170 however we observed a shred with fec set index {}",
171 shred2.fec_set_index()?,
172 next_fec_set_index,
173 shred1.fec_set_index()?
174 );
175 return Ok(());
176 }
177 }
178
179 if shred1.shred_type() != shred2.shred_type() {
180 msg!(
181 "Invalid proof for different shred types {:?} vs {:?}",
182 shred1.shred_type(),
183 shred2.shred_type()
184 );
185 return Err(SlashingError::ShredTypeMismatch);
186 }
187
188 if shred1.index()? == shred2.index()? {
189 if shred1.is_shred_duplicate(shred2) {
190 msg!("Valid payload mismatch for shred index {}", shred1.index()?);
191 return Ok(());
192 }
193 msg!(
194 "Invalid proof, payload matches for index {}",
195 shred1.index()?
196 );
197 return Err(SlashingError::InvalidPayloadProof);
198 }
199
200 if shred1.shred_type() == ShredType::Data {
201 if shred1.last_in_slot()? && shred2.index()? > shred1.index()? {
202 msg!(
203 "Valid last in slot conflict last index {} but shred with index {} is present",
204 shred1.index()?,
205 shred2.index()?
206 );
207 return Ok(());
208 }
209 if shred2.last_in_slot()? && shred1.index()? > shred2.index()? {
210 msg!(
211 "Valid last in slot conflict last index {} but shred with index {} is present",
212 shred2.index()?,
213 shred1.index()?
214 );
215 return Ok(());
216 }
217 msg!(
218 "Invalid proof, no last in shred conflict for data shreds {} and {}",
219 shred1.index()?,
220 shred2.index()?
221 );
222 return Err(SlashingError::InvalidLastIndexConflict);
223 }
224
225 if shred1.fec_set_index() == shred2.fec_set_index()
226 && !shred1.check_erasure_consistency(shred2)?
227 {
228 msg!(
229 "Valid erasure meta conflict in fec set {}, config {:?} vs {:?}",
230 shred1.fec_set_index()?,
231 shred1.erasure_meta()?,
232 shred2.erasure_meta()?,
233 );
234 return Ok(());
235 }
236 msg!(
237 "Invalid proof, no erasure meta conflict for coding shreds set {} idx {} and set {} idx {}",
238 shred1.fec_set_index()?,
239 shred1.index()?,
240 shred2.fec_set_index()?,
241 shred2.index()?,
242 );
243 Err(SlashingError::InvalidErasureMetaConflict)
244}
245
246#[cfg(test)]
247mod tests {
248 use {
249 super::*,
250 crate::shred::{
251 tests::{new_rand_coding_shreds, new_rand_data_shred, new_rand_shreds},
252 SIZE_OF_SIGNATURE,
253 },
254 rand::Rng,
255 solana_ledger::shred::{Shred as SolanaShred, Shredder},
256 solana_sdk::signature::{Keypair, Signature, Signer},
257 std::sync::Arc,
258 };
259
260 const SLOT: Slot = 53084024;
261 const PARENT_SLOT: Slot = SLOT - 1;
262 const REFERENCE_TICK: u8 = 0;
263 const VERSION: u16 = 0;
264
265 fn generate_proof_data<'a>(
266 shred1: &'a SolanaShred,
267 shred2: &'a SolanaShred,
268 ) -> DuplicateBlockProofData<'a> {
269 DuplicateBlockProofData {
270 shred1: shred1.payload().as_slice(),
271 shred2: shred2.payload().as_slice(),
272 }
273 }
274
275 #[test]
276 fn test_legacy_shreds_invalid() {
277 let mut rng = rand::thread_rng();
278 let leader = Arc::new(Keypair::new());
279 let shredder = Shredder::new(SLOT, PARENT_SLOT, REFERENCE_TICK, VERSION).unwrap();
280 let next_shred_index = rng.gen_range(0..32_000);
281 let legacy_data_shred =
282 new_rand_data_shred(&mut rng, next_shred_index, &shredder, &leader, false, false);
283 let legacy_coding_shred =
284 new_rand_coding_shreds(&mut rng, next_shred_index, 5, &shredder, &leader, false)[0]
285 .clone();
286 let data_shred =
287 new_rand_data_shred(&mut rng, next_shred_index, &shredder, &leader, true, false);
288 let coding_shred =
289 new_rand_coding_shreds(&mut rng, next_shred_index, 5, &shredder, &leader, true)[0]
290 .clone();
291
292 let test_cases = [
293 (legacy_data_shred.clone(), legacy_data_shred.clone()),
294 (legacy_coding_shred.clone(), legacy_coding_shred.clone()),
295 (legacy_data_shred.clone(), legacy_coding_shred.clone()),
296 (legacy_data_shred.clone(), data_shred.clone()),
298 (legacy_coding_shred.clone(), coding_shred.clone()),
299 (legacy_data_shred.clone(), coding_shred.clone()),
300 (data_shred.clone(), legacy_coding_shred.clone()),
301 ];
302 for (shred1, shred2) in test_cases.iter().flat_map(|(a, b)| [(a, b), (b, a)]) {
303 let proof_data = generate_proof_data(shred1, shred2);
304 assert_eq!(
305 proof_data.verify_proof(SLOT, &leader.pubkey()).unwrap_err(),
306 SlashingError::LegacyShreds,
307 );
308 }
309 }
310
311 #[test]
312 fn test_slot_invalid() {
313 let mut rng = rand::thread_rng();
314 let leader = Arc::new(Keypair::new());
315 let shredder_slot = Shredder::new(SLOT, PARENT_SLOT, REFERENCE_TICK, VERSION).unwrap();
316 let shredder_bad_slot =
317 Shredder::new(SLOT + 1, PARENT_SLOT, REFERENCE_TICK, VERSION).unwrap();
318 let next_shred_index = rng.gen_range(0..32_000);
319 let data_shred = new_rand_data_shred(
320 &mut rng,
321 next_shred_index,
322 &shredder_slot,
323 &leader,
324 true,
325 false,
326 );
327 let data_shred_bad_slot = new_rand_data_shred(
328 &mut rng,
329 next_shred_index,
330 &shredder_bad_slot,
331 &leader,
332 true,
333 false,
334 );
335 let coding_shred =
336 new_rand_coding_shreds(&mut rng, next_shred_index, 5, &shredder_slot, &leader, true)[0]
337 .clone();
338
339 let coding_shred_bad_slot = new_rand_coding_shreds(
340 &mut rng,
341 next_shred_index,
342 5,
343 &shredder_bad_slot,
344 &leader,
345 true,
346 )[0]
347 .clone();
348
349 let test_cases = vec![
350 (data_shred_bad_slot.clone(), data_shred_bad_slot.clone()),
351 (coding_shred_bad_slot.clone(), coding_shred_bad_slot.clone()),
352 (data_shred_bad_slot.clone(), coding_shred_bad_slot.clone()),
353 (data_shred.clone(), data_shred_bad_slot.clone()),
354 (coding_shred.clone(), coding_shred_bad_slot.clone()),
355 (data_shred.clone(), coding_shred_bad_slot.clone()),
356 (data_shred_bad_slot.clone(), coding_shred.clone()),
357 ];
358
359 for (shred1, shred2) in test_cases.iter().flat_map(|(a, b)| [(a, b), (b, a)]) {
360 let proof_data = generate_proof_data(shred1, shred2);
361 assert_eq!(
362 proof_data.verify_proof(SLOT, &leader.pubkey()).unwrap_err(),
363 SlashingError::SlotMismatch
364 );
365 }
366 }
367
368 #[test]
369 fn test_payload_proof_valid() {
370 let mut rng = rand::thread_rng();
371 let leader = Arc::new(Keypair::new());
372 let shredder = Shredder::new(SLOT, PARENT_SLOT, REFERENCE_TICK, VERSION).unwrap();
373 let next_shred_index = rng.gen_range(0..32_000);
374 let shred1 =
375 new_rand_data_shred(&mut rng, next_shred_index, &shredder, &leader, true, true);
376 let shred2 =
377 new_rand_data_shred(&mut rng, next_shred_index, &shredder, &leader, true, true);
378 let proof_data = generate_proof_data(&shred1, &shred2);
379 proof_data.verify_proof(SLOT, &leader.pubkey()).unwrap();
380 }
381
382 #[test]
383 fn test_payload_proof_invalid() {
384 let mut rng = rand::thread_rng();
385 let leader = Arc::new(Keypair::new());
386 let shredder = Shredder::new(SLOT, PARENT_SLOT, REFERENCE_TICK, VERSION).unwrap();
387 let next_shred_index = rng.gen_range(0..32_000);
388 let data_shred =
389 new_rand_data_shred(&mut rng, next_shred_index, &shredder, &leader, true, true);
390 let coding_shreds =
391 new_rand_coding_shreds(&mut rng, next_shred_index, 10, &shredder, &leader, true);
392 let test_cases = vec![
393 (data_shred.clone(), data_shred),
395 (coding_shreds[0].clone(), coding_shreds[0].clone()),
397 ];
398
399 for (shred1, shred2) in test_cases.into_iter() {
400 let proof_data = generate_proof_data(&shred1, &shred2);
401 assert_eq!(
402 proof_data.verify_proof(SLOT, &leader.pubkey()).unwrap_err(),
403 SlashingError::InvalidPayloadProof
404 );
405 }
406 }
407
408 #[test]
409 fn test_merkle_root_proof_valid() {
410 let mut rng = rand::thread_rng();
411 let leader = Arc::new(Keypair::new());
412 let shredder = Shredder::new(SLOT, PARENT_SLOT, REFERENCE_TICK, VERSION).unwrap();
413 let next_shred_index = rng.gen_range(0..32_000);
414 let (data_shreds, coding_shreds) = new_rand_shreds(
415 &mut rng,
416 next_shred_index,
417 next_shred_index,
418 10,
419 true, &shredder,
421 &leader,
422 false,
423 );
424
425 let (diff_data_shreds, diff_coding_shreds) = new_rand_shreds(
426 &mut rng,
427 next_shred_index,
428 next_shred_index,
429 10,
430 true, &shredder,
432 &leader,
433 false,
434 );
435
436 let test_cases = vec![
437 (data_shreds[0].clone(), diff_data_shreds[1].clone()),
438 (coding_shreds[0].clone(), diff_coding_shreds[1].clone()),
439 (data_shreds[0].clone(), diff_coding_shreds[0].clone()),
440 (coding_shreds[0].clone(), diff_data_shreds[0].clone()),
441 ];
442
443 for (shred1, shred2) in test_cases.iter().flat_map(|(a, b)| [(a, b), (b, a)]) {
444 let proof_data = generate_proof_data(shred1, shred2);
445 proof_data.verify_proof(SLOT, &leader.pubkey()).unwrap();
446 }
447 }
448
449 #[test]
450 fn test_merkle_root_proof_invalid() {
451 let mut rng = rand::thread_rng();
452 let leader = Arc::new(Keypair::new());
453 let shredder = Shredder::new(SLOT, PARENT_SLOT, REFERENCE_TICK, VERSION).unwrap();
454 let next_shred_index = rng.gen_range(0..32_000);
455 let (data_shreds, coding_shreds) = new_rand_shreds(
456 &mut rng,
457 next_shred_index,
458 next_shred_index,
459 10,
460 true,
461 &shredder,
462 &leader,
463 true,
464 );
465
466 let (next_data_shreds, next_coding_shreds) = new_rand_shreds(
467 &mut rng,
468 next_shred_index + 33,
469 next_shred_index + 33,
470 10,
471 true,
472 &shredder,
473 &leader,
474 true,
475 );
476
477 let test_cases = vec![
478 (coding_shreds[0].clone(), data_shreds[0].clone()),
480 (coding_shreds[0].clone(), next_data_shreds[0].clone()),
482 (next_coding_shreds[0].clone(), data_shreds[0].clone()),
483 ];
484
485 for (shred1, shred2) in test_cases.iter().flat_map(|(a, b)| [(a, b), (b, a)]) {
486 let proof_data = generate_proof_data(shred1, shred2);
487 assert_eq!(
488 proof_data.verify_proof(SLOT, &leader.pubkey()).unwrap_err(),
489 SlashingError::ShredTypeMismatch
490 );
491 }
492 }
493
494 #[test]
495 fn test_last_index_conflict_valid() {
496 let mut rng = rand::thread_rng();
497 let leader = Arc::new(Keypair::new());
498 let shredder = Shredder::new(SLOT, PARENT_SLOT, REFERENCE_TICK, VERSION).unwrap();
499 let next_shred_index = rng.gen_range(0..32_000);
500 let test_cases = vec![
501 (
502 new_rand_data_shred(&mut rng, next_shred_index, &shredder, &leader, true, true),
503 new_rand_data_shred(
504 &mut rng,
505 next_shred_index + 30,
508 &shredder,
509 &leader,
510 true,
511 false,
512 ),
513 ),
514 (
515 new_rand_data_shred(
516 &mut rng,
517 next_shred_index + 100,
518 &shredder,
519 &leader,
520 true,
521 true,
522 ),
523 new_rand_data_shred(&mut rng, next_shred_index, &shredder, &leader, true, true),
524 ),
525 ];
526
527 for (shred1, shred2) in test_cases.iter().flat_map(|(a, b)| [(a, b), (b, a)]) {
528 let proof_data = generate_proof_data(shred1, shred2);
529 proof_data.verify_proof(SLOT, &leader.pubkey()).unwrap();
530 }
531 }
532
533 #[test]
534 fn test_last_index_conflict_invalid() {
535 let mut rng = rand::thread_rng();
536 let leader = Arc::new(Keypair::new());
537 let shredder = Shredder::new(SLOT, PARENT_SLOT, REFERENCE_TICK, VERSION).unwrap();
538 let next_shred_index = rng.gen_range(0..32_000);
539 let test_cases = vec![
540 (
541 new_rand_data_shred(&mut rng, next_shred_index, &shredder, &leader, true, false),
542 new_rand_data_shred(
543 &mut rng,
544 next_shred_index + 1,
545 &shredder,
546 &leader,
547 true,
548 true,
549 ),
550 ),
551 (
552 new_rand_data_shred(
553 &mut rng,
554 next_shred_index + 1,
555 &shredder,
556 &leader,
557 true,
558 true,
559 ),
560 new_rand_data_shred(&mut rng, next_shred_index, &shredder, &leader, true, false),
561 ),
562 (
563 new_rand_data_shred(
564 &mut rng,
565 next_shred_index + 100,
566 &shredder,
567 &leader,
568 true,
569 false,
570 ),
571 new_rand_data_shred(&mut rng, next_shred_index, &shredder, &leader, true, false),
572 ),
573 (
574 new_rand_data_shred(&mut rng, next_shred_index, &shredder, &leader, true, false),
575 new_rand_data_shred(
576 &mut rng,
577 next_shred_index + 100,
578 &shredder,
579 &leader,
580 true,
581 false,
582 ),
583 ),
584 ];
585
586 for (shred1, shred2) in test_cases.iter().flat_map(|(a, b)| [(a, b), (b, a)]) {
587 let proof_data = generate_proof_data(shred1, shred2);
588 assert_eq!(
589 proof_data.verify_proof(SLOT, &leader.pubkey()).unwrap_err(),
590 SlashingError::InvalidLastIndexConflict
591 );
592 }
593 }
594
595 #[test]
596 fn test_erasure_meta_conflict_valid() {
597 let mut rng = rand::thread_rng();
598 let leader = Arc::new(Keypair::new());
599 let shredder = Shredder::new(SLOT, PARENT_SLOT, REFERENCE_TICK, VERSION).unwrap();
600 let next_shred_index = rng.gen_range(0..32_000);
601 let coding_shreds =
602 new_rand_coding_shreds(&mut rng, next_shred_index, 10, &shredder, &leader, true);
603 let coding_shreds_bigger =
604 new_rand_coding_shreds(&mut rng, next_shred_index, 13, &shredder, &leader, true);
605 let coding_shreds_smaller =
606 new_rand_coding_shreds(&mut rng, next_shred_index, 7, &shredder, &leader, true);
607
608 let test_cases = vec![
610 (coding_shreds[0].clone(), coding_shreds_bigger[1].clone()),
611 (coding_shreds[0].clone(), coding_shreds_smaller[1].clone()),
612 ];
613 for (shred1, shred2) in test_cases.iter().flat_map(|(a, b)| [(a, b), (b, a)]) {
614 let proof_data = generate_proof_data(shred1, shred2);
615 proof_data.verify_proof(SLOT, &leader.pubkey()).unwrap();
616 }
617 }
618
619 #[test]
620 fn test_erasure_meta_conflict_invalid() {
621 let mut rng = rand::thread_rng();
622 let leader = Arc::new(Keypair::new());
623 let shredder = Shredder::new(SLOT, PARENT_SLOT, REFERENCE_TICK, VERSION).unwrap();
624 let next_shred_index = rng.gen_range(0..32_000);
625 let coding_shreds =
626 new_rand_coding_shreds(&mut rng, next_shred_index, 10, &shredder, &leader, true);
627 let coding_shreds_different_fec = new_rand_coding_shreds(
628 &mut rng,
629 next_shred_index + 100,
630 10,
631 &shredder,
632 &leader,
633 true,
634 );
635 let coding_shreds_different_fec_and_size = new_rand_coding_shreds(
636 &mut rng,
637 next_shred_index + 100,
638 13,
639 &shredder,
640 &leader,
641 true,
642 );
643
644 let test_cases = vec![
645 (
647 coding_shreds[0].clone(),
648 coding_shreds_different_fec[1].clone(),
649 ),
650 (
652 coding_shreds[0].clone(),
653 coding_shreds_different_fec_and_size[1].clone(),
654 ),
655 (coding_shreds[0].clone(), coding_shreds[1].clone()),
657 (
658 coding_shreds_different_fec[0].clone(),
659 coding_shreds_different_fec[1].clone(),
660 ),
661 (
662 coding_shreds_different_fec_and_size[0].clone(),
663 coding_shreds_different_fec_and_size[1].clone(),
664 ),
665 ];
666
667 for (shred1, shred2) in test_cases.iter().flat_map(|(a, b)| [(a, b), (b, a)]) {
668 let proof_data = generate_proof_data(shred1, shred2);
669 assert_eq!(
670 proof_data.verify_proof(SLOT, &leader.pubkey()).unwrap_err(),
671 SlashingError::InvalidErasureMetaConflict
672 );
673 }
674 }
675
676 #[test]
677 fn test_shred_version_invalid() {
678 let mut rng = rand::thread_rng();
679 let leader = Arc::new(Keypair::new());
680 let shredder = Shredder::new(SLOT, PARENT_SLOT, REFERENCE_TICK, VERSION).unwrap();
681 let next_shred_index = rng.gen_range(0..32_000);
682 let (data_shreds, coding_shreds) = new_rand_shreds(
683 &mut rng,
684 next_shred_index,
685 next_shred_index,
686 10,
687 true,
688 &shredder,
689 &leader,
690 true,
691 );
692
693 let shredder = Shredder::new(SLOT, PARENT_SLOT, REFERENCE_TICK, VERSION + 1).unwrap();
695 let (wrong_data_shreds, wrong_coding_shreds) = new_rand_shreds(
696 &mut rng,
697 next_shred_index,
698 next_shred_index,
699 10,
700 true,
701 &shredder,
702 &leader,
703 true,
704 );
705 let test_cases = vec![
706 (coding_shreds[0].clone(), wrong_coding_shreds[0].clone()),
708 (coding_shreds[0].clone(), wrong_data_shreds[0].clone()),
709 (data_shreds[0].clone(), wrong_coding_shreds[0].clone()),
710 (data_shreds[0].clone(), wrong_data_shreds[0].clone()),
711 ];
712
713 for (shred1, shred2) in test_cases.iter().flat_map(|(a, b)| [(a, b), (b, a)]) {
714 let proof_data = generate_proof_data(shred1, shred2);
715 assert_eq!(
716 proof_data.verify_proof(SLOT, &leader.pubkey()).unwrap_err(),
717 SlashingError::InvalidShredVersion
718 );
719 }
720 }
721
722 #[test]
723 fn test_retransmitter_signature_payload_proof_invalid() {
724 const DATA_SHRED_OFFSET: usize = 1139;
727 const CODING_SHRED_OFFSET: usize = 1164;
728
729 let mut rng = rand::thread_rng();
730 let leader = Arc::new(Keypair::new());
731 let shredder = Shredder::new(SLOT, PARENT_SLOT, REFERENCE_TICK, VERSION).unwrap();
732 let next_shred_index = rng.gen_range(0..32_000);
733 let data_shred =
734 new_rand_data_shred(&mut rng, next_shred_index, &shredder, &leader, true, true);
735 let coding_shred =
736 new_rand_coding_shreds(&mut rng, next_shred_index, 10, &shredder, &leader, true)[0]
737 .clone();
738
739 let mut data_shred_different_retransmitter_payload = data_shred.clone().into_payload();
740 let buffer = data_shred_different_retransmitter_payload
741 .get_mut(DATA_SHRED_OFFSET..DATA_SHRED_OFFSET + SIZE_OF_SIGNATURE)
742 .unwrap();
743 buffer.copy_from_slice(Signature::new_unique().as_ref());
744 let data_shred_different_retransmitter =
745 SolanaShred::new_from_serialized_shred(data_shred_different_retransmitter_payload)
746 .unwrap();
747
748 let mut coding_shred_different_retransmitter_payload = coding_shred.clone().into_payload();
749 let buffer = coding_shred_different_retransmitter_payload
750 .get_mut(CODING_SHRED_OFFSET..CODING_SHRED_OFFSET + SIZE_OF_SIGNATURE)
751 .unwrap();
752 buffer.copy_from_slice(Signature::new_unique().as_ref());
753 let coding_shred_different_retransmitter =
754 SolanaShred::new_from_serialized_shred(coding_shred_different_retransmitter_payload)
755 .unwrap();
756
757 let test_cases = vec![
758 (data_shred, data_shred_different_retransmitter),
760 (coding_shred, coding_shred_different_retransmitter),
762 ];
763 for (shred1, shred2) in test_cases.iter().flat_map(|(a, b)| [(a, b), (b, a)]) {
764 let proof_data = generate_proof_data(shred1, shred2);
765 assert_eq!(
766 proof_data.verify_proof(SLOT, &leader.pubkey()).unwrap_err(),
767 SlashingError::InvalidPayloadProof
768 );
769 }
770 }
771
772 #[test]
773 fn test_overlapping_erasure_meta_proof_valid() {
774 let mut rng = rand::thread_rng();
775 let leader = Arc::new(Keypair::new());
776 let shredder = Shredder::new(SLOT, PARENT_SLOT, REFERENCE_TICK, VERSION).unwrap();
777 let next_shred_index = rng.gen_range(0..32_000);
778 let coding_shreds =
779 new_rand_coding_shreds(&mut rng, next_shred_index, 10, &shredder, &leader, true);
780 let (data_shred_next, coding_shred_next) = new_rand_shreds(
781 &mut rng,
782 next_shred_index + 1,
783 next_shred_index + 33,
784 10,
785 true,
786 &shredder,
787 &leader,
788 true,
789 );
790
791 let test_cases = vec![
793 (coding_shreds[0].clone(), coding_shred_next[0].clone()),
794 (coding_shreds[0].clone(), data_shred_next[0].clone()),
795 (
796 coding_shreds[2].clone(),
797 coding_shred_next.last().unwrap().clone(),
798 ),
799 (
800 coding_shreds[2].clone(),
801 data_shred_next.last().unwrap().clone(),
802 ),
803 ];
804 for (shred1, shred2) in test_cases.iter().flat_map(|(a, b)| [(a, b), (b, a)]) {
805 let proof_data = generate_proof_data(shred1, shred2);
806 proof_data.verify_proof(SLOT, &leader.pubkey()).unwrap();
807 }
808 }
809
810 #[test]
811 fn test_overlapping_erasure_meta_proof_invalid() {
812 let mut rng = rand::thread_rng();
813 let leader = Arc::new(Keypair::new());
814 let shredder = Shredder::new(SLOT, PARENT_SLOT, REFERENCE_TICK, VERSION).unwrap();
815 let next_shred_index = rng.gen_range(0..32_000);
816 let (data_shred, coding_shred) = new_rand_shreds(
817 &mut rng,
818 next_shred_index,
819 next_shred_index,
820 10,
821 true,
822 &shredder,
823 &leader,
824 true,
825 );
826 let next_shred_index = next_shred_index + data_shred.len() as u32;
827 let next_code_index = next_shred_index + coding_shred.len() as u32;
828 let (data_shred_next, coding_shred_next) = new_rand_shreds(
829 &mut rng,
830 next_shred_index,
831 next_code_index,
832 10,
833 true,
834 &shredder,
835 &leader,
836 true,
837 );
838 let test_cases = vec![
839 (
840 coding_shred[0].clone(),
841 data_shred_next[0].clone(),
842 SlashingError::ShredTypeMismatch,
843 ),
844 (
845 coding_shred[0].clone(),
846 coding_shred_next[0].clone(),
847 SlashingError::InvalidErasureMetaConflict,
848 ),
849 (
850 coding_shred[0].clone(),
851 data_shred_next.last().unwrap().clone(),
852 SlashingError::ShredTypeMismatch,
853 ),
854 (
855 coding_shred[0].clone(),
856 coding_shred_next.last().unwrap().clone(),
857 SlashingError::InvalidErasureMetaConflict,
858 ),
859 ];
860
861 for (shred1, shred2, expected) in test_cases
862 .iter()
863 .flat_map(|(a, b, c)| [(a, b, c), (b, a, c)])
864 {
865 let proof_data = generate_proof_data(shred1, shred2);
866 assert_eq!(
867 proof_data.verify_proof(SLOT, &leader.pubkey()).unwrap_err(),
868 *expected,
869 );
870 }
871 }
872}