Skip to content
This repository was archived by the owner on Jan 22, 2025. It is now read-only.

Commit 4d7f20b

Browse files
bypasses merkle proof verification for recovered merkle shreds (backport #28076) (#28089)
bypasses merkle proof verification for recovered merkle shreds (#28076) Merkle proof for shreds recovered from erasure codes are generated locally, and it is superfluous to verify them when sanitizing recovered shreds: https://github.com/solana-labs/solana/blob/a0f49c2e4/ledger/src/shred/merkle.rs#L727-L760 (cherry picked from commit b984917) Co-authored-by: behzad nouri <[email protected]>
1 parent 3570e16 commit 4d7f20b

File tree

1 file changed

+49
-36
lines changed

1 file changed

+49
-36
lines changed

ledger/src/shred/merkle.rs

Lines changed: 49 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ impl Shred {
9191
dispatch!(fn erasure_shard_index(&self) -> Result<usize, Error>);
9292
dispatch!(fn merkle_tree_node(&self) -> Result<Hash, Error>);
9393
dispatch!(fn payload(&self) -> &Vec<u8>);
94-
dispatch!(fn sanitize(&self) -> Result<(), Error>);
94+
dispatch!(fn sanitize(&self, verify_merkle_proof: bool) -> Result<(), Error>);
9595
dispatch!(fn set_merkle_branch(&mut self, merkle_branch: MerkleBranch) -> Result<(), Error>);
9696
dispatch!(fn set_signature(&mut self, signature: Signature));
9797
dispatch!(fn signed_message(&self) -> &[u8]);
@@ -219,6 +219,23 @@ impl ShredData {
219219
self.merkle_branch = merkle_branch;
220220
Ok(())
221221
}
222+
223+
fn sanitize(&self, verify_merkle_proof: bool) -> Result<(), Error> {
224+
match self.common_header.shred_variant {
225+
ShredVariant::MerkleData(proof_size) => {
226+
if self.merkle_branch.proof.len() != usize::from(proof_size) {
227+
return Err(Error::InvalidProofSize(proof_size));
228+
}
229+
}
230+
_ => return Err(Error::InvalidShredVariant),
231+
}
232+
if !verify_merkle_proof {
233+
debug_assert_matches!(self.verify_merkle_proof(), Ok(true));
234+
} else if !self.verify_merkle_proof()? {
235+
return Err(Error::InvalidMerkleProof);
236+
}
237+
shred_data::sanitize(self)
238+
}
222239
}
223240

224241
impl ShredCode {
@@ -317,6 +334,23 @@ impl ShredCode {
317334
self.merkle_branch = merkle_branch;
318335
Ok(())
319336
}
337+
338+
fn sanitize(&self, verify_merkle_proof: bool) -> Result<(), Error> {
339+
match self.common_header.shred_variant {
340+
ShredVariant::MerkleCode(proof_size) => {
341+
if self.merkle_branch.proof.len() != usize::from(proof_size) {
342+
return Err(Error::InvalidProofSize(proof_size));
343+
}
344+
}
345+
_ => return Err(Error::InvalidShredVariant),
346+
}
347+
if !verify_merkle_proof {
348+
debug_assert_matches!(self.verify_merkle_proof(), Ok(true));
349+
} else if !self.verify_merkle_proof()? {
350+
return Err(Error::InvalidMerkleProof);
351+
}
352+
shred_code::sanitize(self)
353+
}
320354
}
321355

322356
impl MerkleBranch {
@@ -368,7 +402,8 @@ impl ShredTrait for ShredData {
368402
merkle_branch,
369403
payload,
370404
};
371-
shred.sanitize().map(|_| shred)
405+
shred.sanitize(/*verify_merkle_proof:*/ true)?;
406+
Ok(shred)
372407
}
373408

374409
fn erasure_shard_index(&self) -> Result<usize, Error> {
@@ -402,18 +437,7 @@ impl ShredTrait for ShredData {
402437
}
403438

404439
fn sanitize(&self) -> Result<(), Error> {
405-
match self.common_header.shred_variant {
406-
ShredVariant::MerkleData(proof_size) => {
407-
if self.merkle_branch.proof.len() != usize::from(proof_size) {
408-
return Err(Error::InvalidProofSize(proof_size));
409-
}
410-
}
411-
_ => return Err(Error::InvalidShredVariant),
412-
}
413-
if !self.verify_merkle_proof()? {
414-
return Err(Error::InvalidMerkleProof);
415-
}
416-
shred_data::sanitize(self)
440+
self.sanitize(/*verify_merkle_proof:*/ true)
417441
}
418442

419443
fn signed_message(&self) -> &[u8] {
@@ -452,7 +476,8 @@ impl ShredTrait for ShredCode {
452476
merkle_branch,
453477
payload,
454478
};
455-
shred.sanitize().map(|_| shred)
479+
shred.sanitize(/*verify_merkle_proof:*/ true)?;
480+
Ok(shred)
456481
}
457482

458483
fn erasure_shard_index(&self) -> Result<usize, Error> {
@@ -486,18 +511,7 @@ impl ShredTrait for ShredCode {
486511
}
487512

488513
fn sanitize(&self) -> Result<(), Error> {
489-
match self.common_header.shred_variant {
490-
ShredVariant::MerkleCode(proof_size) => {
491-
if self.merkle_branch.proof.len() != usize::from(proof_size) {
492-
return Err(Error::InvalidProofSize(proof_size));
493-
}
494-
}
495-
_ => return Err(Error::InvalidShredVariant),
496-
}
497-
if !self.verify_merkle_proof()? {
498-
return Err(Error::InvalidMerkleProof);
499-
}
500-
shred_code::sanitize(self)
514+
self.sanitize(/*verify_merkle_proof:*/ true)
501515
}
502516

503517
fn signed_message(&self) -> &[u8] {
@@ -619,10 +633,7 @@ pub(super) fn recover(
619633
Some((common_header, coding_header))
620634
});
621635
let (common_header, coding_header) = headers.ok_or(TooFewParityShards)?;
622-
debug_assert!(matches!(
623-
common_header.shred_variant,
624-
ShredVariant::MerkleCode(_)
625-
));
636+
debug_assert_matches!(common_header.shred_variant, ShredVariant::MerkleCode(_));
626637
let proof_size = match common_header.shred_variant {
627638
ShredVariant::MerkleCode(proof_size) => proof_size,
628639
ShredVariant::MerkleData(_) | ShredVariant::LegacyCode | ShredVariant::LegacyData => {
@@ -751,12 +762,14 @@ pub(super) fn recover(
751762
});
752763
}
753764
}
754-
// TODO: No need to verify merkle proof in sanitize here.
755765
shreds
756766
.into_iter()
757767
.zip(mask)
758768
.filter(|(_, mask)| !mask)
759-
.map(|(shred, _)| shred.sanitize().map(|_| shred))
769+
.map(|(shred, _)| {
770+
shred.sanitize(/*verify_merkle_proof:*/ false)?;
771+
Ok(shred)
772+
})
760773
.collect()
761774
}
762775

@@ -1018,7 +1031,7 @@ fn make_erasure_batch(
10181031
shred.set_merkle_branch(merkle_branch)?;
10191032
shred.set_signature(signature);
10201033
debug_assert!(shred.verify(&keypair.pubkey()));
1021-
debug_assert_matches!(shred.sanitize(), Ok(()));
1034+
debug_assert_matches!(shred.sanitize(/*verify_merkle_proof:*/ true), Ok(()));
10221035
// Assert that shred payload is fully populated.
10231036
debug_assert_eq!(shred, {
10241037
let shred = shred.payload().clone();
@@ -1247,7 +1260,7 @@ mod test {
12471260
let signature = keypair.sign_message(shred.signed_message());
12481261
shred.set_signature(signature);
12491262
assert!(shred.verify(&keypair.pubkey()));
1250-
assert_matches!(shred.sanitize(), Ok(()));
1263+
assert_matches!(shred.sanitize(/*verify_merkle_proof:*/ true), Ok(()));
12511264
}
12521265
assert_eq!(shreds.iter().map(Shred::signature).dedup().count(), 1);
12531266
for size in num_data_shreds..num_shreds {
@@ -1382,7 +1395,7 @@ mod test {
13821395
// Assert that shreds sanitize and verify.
13831396
for shred in &shreds {
13841397
assert!(shred.verify(&keypair.pubkey()));
1385-
assert_matches!(shred.sanitize(), Ok(()));
1398+
assert_matches!(shred.sanitize(/*verify_merkle_proof:*/ true), Ok(()));
13861399
let ShredCommonHeader {
13871400
signature,
13881401
shred_variant,

0 commit comments

Comments
 (0)