diff --git a/beacon_node/http_api/src/lib.rs b/beacon_node/http_api/src/lib.rs index 6656485dceb..3adf84fee13 100644 --- a/beacon_node/http_api/src/lib.rs +++ b/beacon_node/http_api/src/lib.rs @@ -1834,18 +1834,35 @@ pub fn serve( .filter(|&att| query_filter(att.data())) .cloned(), ); - let slot = query - .slot - .or_else(|| { - attestations - .first() - .map(|att| att.data().slot) - .or_else(|| chain.slot_clock.now()) - }) - .ok_or(warp_utils::reject::custom_server_error( - "unable to read slot clock".to_string(), - ))?; - let fork_name = chain.spec.fork_name_at_slot::(slot); + // Use the current slot to find the fork version, and convert all messages to the + // current fork's format. This is to ensure consistent message types matching + // `Eth-Consensus-Version`. + let current_slot = + chain + .slot_clock + .now() + .ok_or(warp_utils::reject::custom_server_error( + "unable to read slot clock".to_string(), + ))?; + let fork_name = chain.spec.fork_name_at_slot::(current_slot); + + let attestations = if fork_name.electra_enabled() { + attestations + .into_iter() + .map(|att| match att { + Attestation::Base(a) => Ok(Attestation::Electra(a.try_into()?)), + Attestation::Electra(a) => Ok(Attestation::Electra(a)), + }) + .collect::, types::attestation::Error>>() + .map_err(|e| { + warp_utils::reject::custom_server_error(format!( + "could not convert base attestations to electra {e:?}" + )) + })? + } else { + attestations + }; + let res = fork_versioned_response(endpoint_version, fork_name, &attestations)?; Ok(add_consensus_version_header( warp::reply::json(&res).into_response(), @@ -1914,14 +1931,30 @@ pub fn serve( chain: Arc>| { task_spawner.blocking_response_task(Priority::P1, move || { let slashings = chain.op_pool.get_all_attester_slashings(); - let slot = slashings - .first() - .map(|slashing| slashing.attestation_1().data().slot) - .or_else(|| chain.slot_clock.now()) - .ok_or(warp_utils::reject::custom_server_error( - "unable to read slot clock".to_string(), - ))?; - let fork_name = chain.spec.fork_name_at_slot::(slot); + + // Use the current slot to find the fork version, and convert all messages to the + // current fork's format. This is to ensure consistent message types matching + // `Eth-Consensus-Version`. + let current_slot = + chain + .slot_clock + .now() + .ok_or(warp_utils::reject::custom_server_error( + "unable to read slot clock".to_string(), + ))?; + let fork_name = chain.spec.fork_name_at_slot::(current_slot); + + let slashings = if fork_name.electra_enabled() { + slashings + .into_iter() + .map(|att| match att { + AttesterSlashing::Base(a) => AttesterSlashing::Electra(a.into()), + AttesterSlashing::Electra(a) => AttesterSlashing::Electra(a), + }) + .collect::>() + } else { + slashings + }; let res = fork_versioned_response(endpoint_version, fork_name, &slashings)?; Ok(add_consensus_version_header( warp::reply::json(&res).into_response(), diff --git a/consensus/types/src/attestation.rs b/consensus/types/src/attestation.rs index 1ee6c437c90..f12f84a447d 100644 --- a/consensus/types/src/attestation.rs +++ b/consensus/types/src/attestation.rs @@ -26,6 +26,12 @@ pub enum Error { InvalidCommitteeIndex, } +impl From for Error { + fn from(e: ssz_types::Error) -> Self { + Error::SszTypesError(e) + } +} + #[superstruct( variants(Base, Electra), variant_attributes( @@ -416,6 +422,35 @@ impl AttestationBase { } } +impl TryFrom> for AttestationElectra { + type Error = Error; + fn try_from(att: AttestationBase) -> Result { + // Extend the aggregation bits list. + let aggregation_bits = att.extend_aggregation_bits()?; + let AttestationBase { + aggregation_bits: _, + mut data, + signature, + } = att; + + // Set the committee index based on the index field. + let mut committee_bits: BitVector = BitVector::default(); + committee_bits + .set(data.index as usize, true) + .map_err(|_| Error::InvalidCommitteeIndex)?; + + // Set the attestation data's index to zero. + data.index = 0; + + Ok(Self { + aggregation_bits, + data, + committee_bits, + signature, + }) + } +} + impl SlotData for Attestation { fn get_slot(&self) -> Slot { self.data().slot diff --git a/consensus/types/src/attester_slashing.rs b/consensus/types/src/attester_slashing.rs index f6aa654d445..18ab63ad44e 100644 --- a/consensus/types/src/attester_slashing.rs +++ b/consensus/types/src/attester_slashing.rs @@ -1,5 +1,5 @@ use crate::indexed_attestation::{ - IndexedAttestationBase, IndexedAttestationElectra, IndexedAttestationRef, + IndexedAttestation, IndexedAttestationBase, IndexedAttestationElectra, IndexedAttestationRef, }; use crate::{test_utils::TestRandom, EthSpec}; use derivative::Derivative; @@ -161,6 +161,19 @@ impl AttesterSlashing { } } +impl From> for AttesterSlashingElectra { + fn from(attester_slashing: AttesterSlashingBase) -> Self { + let AttesterSlashingBase { + attestation_1, + attestation_2, + } = attester_slashing; + AttesterSlashingElectra { + attestation_1: IndexedAttestation::Base(attestation_1).to_electra(), + attestation_2: IndexedAttestation::Base(attestation_2).to_electra(), + } + } +} + impl TestRandom for AttesterSlashing { fn random_for_test(rng: &mut impl RngCore) -> Self { if rng.gen_bool(0.5) {