Compare commits

...

2 Commits

Author SHA1 Message Date
Michael Sproul
d65fd5a495 Cap validator index at 8M in slasher 2026-04-08 12:51:22 +10:00
Michael Sproul
10ddeb8f10 Avoid double processing indexed attestations for slasher 2026-04-08 12:02:29 +10:00
2 changed files with 17 additions and 10 deletions

View File

@@ -507,11 +507,6 @@ impl<'a, T: BeaconChainTypes> IndexedAggregatedAttestation<'a, T> {
chain: &BeaconChain<T>, chain: &BeaconChain<T>,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
Self::verify_slashable(signed_aggregate, chain) Self::verify_slashable(signed_aggregate, chain)
.inspect(|verified_aggregate| {
if let Some(slasher) = chain.slasher.as_ref() {
slasher.accept_attestation(verified_aggregate.indexed_attestation.clone());
}
})
.map_err(|slash_info| process_slash_info(slash_info, chain)) .map_err(|slash_info| process_slash_info(slash_info, chain))
} }
@@ -933,11 +928,6 @@ impl<'a, T: BeaconChainTypes> IndexedUnaggregatedAttestation<'a, T> {
chain: &BeaconChain<T>, chain: &BeaconChain<T>,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
Self::verify_slashable(attestation, subnet_id, chain) Self::verify_slashable(attestation, subnet_id, chain)
.inspect(|verified_unaggregated| {
if let Some(slasher) = chain.slasher.as_ref() {
slasher.accept_attestation(verified_unaggregated.indexed_attestation.clone());
}
})
.map_err(|slash_info| process_slash_info(slash_info, chain)) .map_err(|slash_info| process_slash_info(slash_info, chain))
} }

View File

@@ -2,8 +2,17 @@ use crate::{AttesterRecord, Config, IndexedAttesterRecord};
use parking_lot::Mutex; use parking_lot::Mutex;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::sync::{Arc, Weak}; use std::sync::{Arc, Weak};
use tracing::warn;
use types::{EthSpec, Hash256, IndexedAttestation}; use types::{EthSpec, Hash256, IndexedAttestation};
/// Hard cap on validator indices accepted by the slasher.
///
/// Any attestation referencing a validator index above this limit is silently dropped during
/// grouping. This is a defence-in-depth measure to prevent pathological memory allocation if an
/// attestation with a bogus index somehow reaches the slasher. The value (2^23 = 8,388,608)
/// provides generous headroom above the current mainnet validator set (~2M).
const MAX_VALIDATOR_INDEX: u64 = 8_388_608;
/// Staging area for attestations received from the network. /// Staging area for attestations received from the network.
/// ///
/// Attestations are not grouped by validator index at this stage so that they can be easily /// Attestations are not grouped by validator index at this stage so that they can be easily
@@ -72,6 +81,14 @@ impl<E: EthSpec> AttestationBatch<E> {
let mut grouped_attestations = GroupedAttestations { subqueues: vec![] }; let mut grouped_attestations = GroupedAttestations { subqueues: vec![] };
for ((validator_index, _), indexed_record) in self.attesters { for ((validator_index, _), indexed_record) in self.attesters {
if validator_index >= MAX_VALIDATOR_INDEX {
warn!(
validator_index,
"Dropping slasher attestation with out-of-range validator index"
);
continue;
}
let subqueue_id = config.validator_chunk_index(validator_index); let subqueue_id = config.validator_chunk_index(validator_index);
if subqueue_id >= grouped_attestations.subqueues.len() { if subqueue_id >= grouped_attestations.subqueues.len() {