diff --git a/core/src/serve_repair.rs b/core/src/serve_repair.rs index 9020d70b5a..6adb669fba 100644 --- a/core/src/serve_repair.rs +++ b/core/src/serve_repair.rs @@ -1027,11 +1027,17 @@ impl ServeRepair { continue; } if let Ok(RepairResponse::Ping(ping)) = packet.deserialize_slice(..) { - packet.meta.set_discard(true); if !ping.verify() { + // Do _not_ set `discard` to allow shred processing to attempt to + // handle the packet. + // Ping error count may include false posities for shreds of size + // `REPAIR_RESPONSE_SERIALIZED_PING_BYTES` whose first 4 bytes + // match `RepairResponse` discriminator (these 4 bytes overlap + // with the shred signature field). stats.ping_err_verify_count += 1; continue; } + packet.meta.set_discard(true); stats.ping_count += 1; if let Ok(pong) = Pong::new(&ping, keypair) { let pong = RepairProtocol::Pong(pong); @@ -1262,6 +1268,32 @@ mod tests { assert_eq!(pkt.meta.size, REPAIR_RESPONSE_SERIALIZED_PING_BYTES); } + #[test] + fn test_deserialize_shred_as_ping() { + let data_buf = vec![7u8, 44]; // REPAIR_RESPONSE_SERIALIZED_PING_BYTES - SIZE_OF_DATA_SHRED_HEADERS + let keypair = Keypair::new(); + let mut shred = Shred::new_from_data( + 123, // slot + 456, // index + 111, // parent_offset + &data_buf, + ShredFlags::empty(), + 222, // reference_tick + 333, // version + 444, // fec_set_index + ); + shred.sign(&keypair); + let mut pkt = Packet::default(); + shred.copy_to_packet(&mut pkt); + pkt.meta.size = REPAIR_RESPONSE_SERIALIZED_PING_BYTES; + let res = pkt.deserialize_slice::(..); + if let Ok(RepairResponse::Ping(ping)) = res { + assert!(!ping.verify()); + } else { + assert!(res.is_err()); + } + } + #[test] fn test_serialize_deserialize_signed_request() { let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000);