Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 22 additions & 2 deletions crates/blockchain/state_transition/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use std::collections::HashMap;
use std::collections::{HashMap, HashSet};

use ethlambda_types::{
ShortRoot,
attestation::AttestationData,
block::{AggregatedAttestations, Block, BlockHeader},
block::{AggregatedAttestations, Block, BlockHeader, MAX_ATTESTATIONS_DATA},
checkpoint::Checkpoint,
primitives::{H256, HashTreeRoot as _},
state::{HISTORICAL_ROOTS_LIMIT, JustificationValidators, State},
Expand Down Expand Up @@ -48,6 +48,8 @@ pub enum Error {
index: usize,
validator_count: usize,
},
#[error("block carries {count} distinct AttestationData entries; maximum is {max}")]
TooManyAttestationData { count: usize, max: usize },
}

/// Transition the given pre-state to the block's post-state.
Expand Down Expand Up @@ -243,6 +245,24 @@ fn process_attestations(
) -> Result<(), Error> {
let _timing = metrics::time_attestations_processing();

// Cap the distinct attestation data a block may carry (leanSpec #536).
//
// Each distinct data allocates a tally sized to the validator set below, so the
// distinct count, not the attestation count, is what drives the work here. Split
// aggregates over one data share their tally and count once.
//
// `on_block` re-checks this before signature verification so a crafted block is
// rejected cheaply, but the bound belongs to the transition: this is the only
// entry point block production and fixture replay share with block import.
let distinct_attestation_data: HashSet<&AttestationData> =
attestations.iter().map(|att| &att.data).collect();
if distinct_attestation_data.len() > MAX_ATTESTATIONS_DATA {
return Err(Error::TooManyAttestationData {
count: distinct_attestation_data.len(),
max: MAX_ATTESTATIONS_DATA,
});
}

// Validate the justification bookkeeping before unpacking the flat vote list
// (leanSpec #1178). A `State` decoded from untrusted bytes (e.g. checkpoint
// sync) can satisfy SSZ yet still violate these cross-field invariants; without
Expand Down