Skip to content

Commit

Permalink
Merge branch 'feature/electra' into electra
Browse files Browse the repository at this point in the history
  • Loading branch information
Tumas committed Jun 25, 2024
2 parents 5fe44f1 + d6bb1e9 commit d57bc1c
Show file tree
Hide file tree
Showing 24 changed files with 462 additions and 172 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 3 additions & 7 deletions eth1/src/genesis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,8 @@ use log::info;
use ssz::{SszRead as _, SszWrite as _};
use thiserror::Error;
use types::{
combined::BeaconState,
config::Config,
nonstandard::Phase,
phase0::{consts::GENESIS_SLOT, primitives::UnixSeconds},
preset::Preset,
traits::BeaconState as _,
combined::BeaconState, config::Config, nonstandard::Phase, phase0::primitives::UnixSeconds,
preset::Preset, traits::BeaconState as _,
};

use crate::Eth1Chain;
Expand Down Expand Up @@ -44,7 +40,7 @@ pub async fn wait<P: Preset>(
}

ensure!(
config.phase_at_slot::<P>(GENESIS_SLOT) < Phase::Bellatrix,
config.genesis_phase() < Phase::Bellatrix,
Error::PostBellatrixGenesisNotImplemented,
);

Expand Down
4 changes: 2 additions & 2 deletions execution_engine/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ pub use crate::{
EngineGetPayloadV1Response, EngineGetPayloadV2Response, EngineGetPayloadV3Response,
EngineGetPayloadV4Response, ExecutionPayloadV1, ExecutionPayloadV2, ExecutionPayloadV3,
ExecutionPayloadV4, ForkChoiceStateV1, ForkChoiceUpdatedResponse, PayloadAttributes,
PayloadAttributesV1, PayloadAttributesV2, PayloadAttributesV3, PayloadId, PayloadStatusV1,
PayloadValidationStatus,
PayloadAttributesV1, PayloadAttributesV2, PayloadAttributesV3, PayloadId, PayloadStatus,
PayloadStatusV1, PayloadStatusWithBlockHash, PayloadValidationStatus,
},
};

Expand Down
33 changes: 33 additions & 0 deletions execution_engine/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -885,6 +885,39 @@ pub enum PayloadId {
Electra(H64),
}

#[derive(Deserialize)]
#[serde(deny_unknown_fields)]
pub struct PayloadStatusWithBlockHash {
pub block_hash: ExecutionBlockHash,
pub payload_status: PayloadStatus,
}

// `PayloadStatusV1` is deserialized from data containing keys in `camelCase`,
// whereas `consensus-spec-tests` and `grandine-snapshot-tests` use `snake_case`.
#[derive(Deserialize)]
#[serde(deny_unknown_fields)]
pub struct PayloadStatus {
status: PayloadValidationStatus,
latest_valid_hash: Option<ExecutionBlockHash>,
validation_error: Option<String>,
}

impl From<PayloadStatus> for PayloadStatusV1 {
fn from(payload_status: PayloadStatus) -> Self {
let PayloadStatus {
status,
latest_valid_hash,
validation_error,
} = payload_status;

Self {
status,
latest_valid_hash,
validation_error,
}
}
}

#[cfg(test)]
mod tests {
use anyhow::Result;
Expand Down
1 change: 1 addition & 0 deletions features/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ static FEATURES: [AtomicBool; Feature::CARDINALITY] = [FALSE; Feature::CARDINALI
)]
pub enum Feature {
AlwaysPrepackAttestations,
AlwaysPrepareExecutionPayload,
CacheTargetStates,
DebugEth1,
DebugP2p,
Expand Down
59 changes: 17 additions & 42 deletions fork_choice_control/src/spec_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::{path::PathBuf, sync::Arc};

use clock::Tick;
use duplicate::duplicate_item;
use execution_engine::{PayloadStatusV1, PayloadValidationStatus};
use execution_engine::PayloadStatusWithBlockHash;
use helper_functions::misc;
use serde::Deserialize;
use spec_test_utils::Case;
Expand All @@ -17,7 +17,7 @@ use types::{
nonstandard::{Phase, TimedPowBlock},
phase0::{
containers::Checkpoint,
primitives::{ExecutionBlockHash, Slot, UnixSeconds, H256},
primitives::{Slot, UnixSeconds, H256},
},
preset::{Mainnet, Minimal, Preset},
traits::{BeaconState as _, PostDenebBeaconBlockBody, SignedBeaconBlock as _},
Expand All @@ -44,10 +44,7 @@ enum Step {
MergeBlock {
pow_block: PathBuf,
},
PayloadStatus {
block_hash: ExecutionBlockHash,
payload_status: PayloadStatus,
},
PayloadStatus(PayloadStatusWithBlockHash),
AttesterSlashing {
attester_slashing: PathBuf,
},
Expand All @@ -56,32 +53,6 @@ enum Step {
},
}

// `PayloadStatusV1` is deserialized from data containing keys in `camelCase`,
// whereas `consensus-spec-tests` uses `snake_case`.
#[derive(Deserialize)]
#[serde(deny_unknown_fields)]
struct PayloadStatus {
status: PayloadValidationStatus,
latest_valid_hash: Option<ExecutionBlockHash>,
validation_error: Option<String>,
}

impl From<PayloadStatus> for PayloadStatusV1 {
fn from(payload_status: PayloadStatus) -> Self {
let PayloadStatus {
status,
latest_valid_hash,
validation_error,
} = payload_status;

Self {
status,
latest_valid_hash,
validation_error,
}
}
}

#[derive(Deserialize)]
#[serde(deny_unknown_fields)]
struct Checks {
Expand Down Expand Up @@ -194,10 +165,7 @@ fn run_case<P: Preset>(config: &Arc<Config>, case: Case) {
context.on_tick(tick);
}
Step::Attestation { attestation } => {
let attestation = case
.try_ssz::<_, Attestation<P>>(config, attestation)
.expect("test attestation is available");

let attestation = case.ssz::<_, Attestation<P>>(config, attestation);
context.on_test_attestation(attestation);
}
Step::Block {
Expand Down Expand Up @@ -262,16 +230,23 @@ fn run_case<P: Preset>(config: &Arc<Config>, case: Case) {

context.on_merge_block(block_hash, timed_pow_block);
}
Step::PayloadStatus {
Step::PayloadStatus(PayloadStatusWithBlockHash {
block_hash,
payload_status,
} => {
}) => {
context.on_notified_new_payload(block_hash, payload_status.into());
}
Step::AttesterSlashing { attester_slashing } => {
let attester_slashing = case
.try_ssz::<_, AttesterSlashing<P>>(config, attester_slashing)
.expect("test attester_slashing is available");
Step::AttesterSlashing {
attester_slashing: file_name,
} => {
let attester_slashing = match config.genesis_phase() {
Phase::Phase0
| Phase::Altair
| Phase::Bellatrix
| Phase::Capella
| Phase::Deneb => AttesterSlashing::Phase0(case.ssz(config, file_name)),
Phase::Electra => AttesterSlashing::Electra(case.ssz(config, file_name)),
};

context.on_attester_slashing(attester_slashing);
}
Expand Down
9 changes: 3 additions & 6 deletions fork_choice_store/src/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1333,12 +1333,9 @@ impl<P: Preset> Store<P> {
}
}

let AttestationData {
slot,
index,
target,
..
} = attestation.data();
let index = misc::committee_index(&attestation);

let AttestationData { slot, target, .. } = attestation.data();

// TODO(feature/deneb): Figure out why this validation is split over 2 methods.
// TODO(feature/deneb): This appears to be unfinished.
Expand Down
2 changes: 1 addition & 1 deletion grandine-snapshot-tests
5 changes: 4 additions & 1 deletion helper_functions/src/electra.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,10 @@ pub fn get_attesting_indices<P: Preset>(
// This works the same as `assert len(attestation.aggregation_bits) == participants_count`
ensure!(
committee_offset == attestation.aggregation_bits.len(),
Error::ParticipantsCountMismatch,
Error::ParticipantsCountMismatch {
aggregation_bitlist_length: attestation.aggregation_bits.len(),
participants_count: committee_offset
},
);

Ok(output)
Expand Down
14 changes: 10 additions & 4 deletions helper_functions/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@ pub(crate) enum Error {
AttestingIndicesNotSortedAndUnique,
#[error("commitee index is out of bounds")]
CommitteeIndexOutOfBounds,
#[error("aggregation bitlist length does not match committee length")]
CommitteeLengthMismatch,
#[error("aggregation bitlist length {aggregation_bitlist_length} does not match committee length {committee_length}")]
CommitteeLengthMismatch {
aggregation_bitlist_length: usize,
committee_length: usize,
},
#[error("epoch is after next one relative to state")]
EpochAfterNext,
#[error("epoch is before previous one relative to state")]
Expand All @@ -25,8 +28,11 @@ pub(crate) enum Error {
FailedToSelectProposer,
#[error("no validators are active")]
NoActiveValidators,
#[error("aggregation bitlist length does not match participants count")]
ParticipantsCountMismatch,
#[error("aggregation bitlist length {aggregation_bitlist_length} does not match participants count {participants_count}")]
ParticipantsCountMismatch {
aggregation_bitlist_length: usize,
participants_count: usize,
},
#[error("permutated prefix maximum overflowed")]
PermutatedPrefixMaximumOverflow,
#[error("{0} is invalid")]
Expand Down
12 changes: 11 additions & 1 deletion helper_functions/src/misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use typenum::Unsigned as _;
use types::{
altair::{consts::SyncCommitteeSubnetCount, primitives::SyncCommitteePeriod},
cache::PackedIndices,
combined::SignedBeaconBlock,
combined::{Attestation, SignedBeaconBlock},
config::Config,
deneb::{
consts::{BlobCommitmentTreeDepth, BlobSidecarSubnetCount, VERSIONED_HASH_VERSION_KZG},
Expand Down Expand Up @@ -506,6 +506,16 @@ pub fn construct_blob_sidecars<P: Preset>(
.collect()
}

#[must_use]
pub fn committee_index<P: Preset>(attestation: &Attestation<P>) -> CommitteeIndex {
match attestation {
Attestation::Phase0(attestation) => attestation.data.index,
Attestation::Electra(attestation) => get_committee_indices::<P>(attestation.committee_bits)
.next()
.unwrap_or_default(),
}
}

#[must_use]
pub fn get_committee_indices<P: Preset>(
committee_bits: BitVector<P::MaxCommitteesPerSlot>,
Expand Down
5 changes: 4 additions & 1 deletion helper_functions/src/phase0.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,10 @@ pub fn get_attesting_indices<'all, P: Preset>(

ensure!(
committee.len() == aggregation_bits.len(),
Error::CommitteeLengthMismatch,
Error::CommitteeLengthMismatch {
aggregation_bitlist_length: aggregation_bits.len(),
committee_length: committee.len(),
},
);

// `Itertools::zip_eq` is slower than `Iterator::zip` when iterating over packed indices.
Expand Down
1 change: 1 addition & 0 deletions http_api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ dedicated_executor = { workspace = true }
deposit_tree = { workspace = true }
eth1 = { workspace = true }
eth2_cache_utils = { workspace = true }
execution_engine = { workspace = true }
factory = { workspace = true }
fork_choice_store = { workspace = true }
hex-literal = { workspace = true }
Expand Down
4 changes: 4 additions & 0 deletions http_api/src/routing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,10 @@ pub fn test_routes<P: Preset>(
) -> Router {
Router::new()
.route("/test/tick", post(test_endpoints::post_tick))
.route(
"/test/payload_status",
post(test_endpoints::post_payload_status),
)
.with_state(normal_state)
.route(
"/test/take_messages",
Expand Down
34 changes: 32 additions & 2 deletions http_api/src/standard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,36 @@ pub struct MetaPeersResponse {
count: usize,
}

#[derive(Serialize)]
pub struct NodePeerCountResponse {
#[serde(with = "serde_utils::string_or_native")]
connected: u64,
#[serde(with = "serde_utils::string_or_native")]
connecting: u64,
#[serde(with = "serde_utils::string_or_native")]
disconnected: u64,
#[serde(with = "serde_utils::string_or_native")]
disconnecting: u64,
}

impl From<NodePeerCount> for NodePeerCountResponse {
fn from(node_peer_count: NodePeerCount) -> Self {
let NodePeerCount {
connected,
connecting,
disconnected,
disconnecting,
} = node_peer_count;

Self {
connected,
connecting,
disconnected,
disconnecting,
}
}
}

#[derive(Serialize)]
struct NodeVersionResponse<'version> {
version: Option<&'version str>,
Expand Down Expand Up @@ -1612,14 +1642,14 @@ pub async fn node_peer<P: Preset>(
/// `GET /eth/v1/node/peer_count`
pub async fn node_peer_count<P: Preset>(
State(api_to_p2p_tx): State<UnboundedSender<ApiToP2p<P>>>,
) -> Result<EthResponse<NodePeerCount>, Error> {
) -> Result<EthResponse<NodePeerCountResponse>, Error> {
let (sender, receiver) = futures::channel::oneshot::channel();

ApiToP2p::RequestPeerCount(sender).send(&api_to_p2p_tx);

let data = receiver.await?;

Ok(EthResponse::json(data))
Ok(EthResponse::json(data.into()))
}

/// `GET /eth/v1/node/version`
Expand Down
14 changes: 14 additions & 0 deletions http_api/src/test_endpoints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

use axum::{extract::State, Json};
use clock::Tick;
use execution_engine::PayloadStatusWithBlockHash;
use fork_choice_control::{P2pMessage, SyncMessage};
use operation_pools::PoolToP2pMessage;
use p2p::{ApiToP2p, ValidatorToP2p};
Expand Down Expand Up @@ -32,6 +33,19 @@ pub async fn post_tick<P: Preset>(
controller.on_tick(tick);
}

/// `POST /test/payload_status`
pub async fn post_payload_status<P: Preset>(
State(controller): State<TestApiController<P>>,
Json(payload_status_with_block_hash): Json<PayloadStatusWithBlockHash>,
) {
let PayloadStatusWithBlockHash {
block_hash,
payload_status,
} = payload_status_with_block_hash;

controller.on_notified_new_payload(block_hash, payload_status.into());
}

/// `POST /test/take_messages`
pub async fn post_take_messages<P: Preset>(
State(test_state): State<TestState<P>>,
Expand Down
Loading

0 comments on commit d57bc1c

Please sign in to comment.