diff --git a/Cargo.lock b/Cargo.lock index f37840497e9..17281298b46 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7242,6 +7242,7 @@ dependencies = [ "execution_layer", "flate2", "hex", + "metrics", "reqwest", "serde", "serde_json", diff --git a/beacon_node/beacon_chain/src/execution_proof_verification/gossip_verified_execution_proof.rs b/beacon_node/beacon_chain/src/execution_proof_verification/gossip_verified_execution_proof.rs index 611e9c6ec51..e4d7e1bab02 100644 --- a/beacon_node/beacon_chain/src/execution_proof_verification/gossip_verified_execution_proof.rs +++ b/beacon_node/beacon_chain/src/execution_proof_verification/gossip_verified_execution_proof.rs @@ -4,6 +4,7 @@ use crate::canonical_head::CanonicalHead; use crate::execution_proof_verification::observed_execution_proofs::{ ObservedExecutionProofs, ProofObservation, }; +use crate::metrics; use crate::pending_payload_cache::PendingPayloadCache; use crate::shuffling_cache::{ShufflingCache, with_cached_shuffling}; use crate::validator_pubkey_cache::ValidatorPubkeyCache; @@ -260,19 +261,32 @@ impl BeaconChain { self: &Arc, proof: Arc, ) -> Result { + let proof_type = proof.proof_type(); let chain = self.clone(); - self.task_executor - .clone() - .spawn_blocking_handle( - move || { - let ctx = chain.execution_proof_gossip_verification_context(); - GossipVerifiedExecutionProof::new(proof, &ctx) - }, - "gossip_execution_proof_verification_handle", - ) - .ok_or(BeaconChainError::RuntimeShutdown)? - .await - .map_err(BeaconChainError::TokioJoin)? + let result: Result<_, Error> = async { + self.task_executor + .clone() + .spawn_blocking_handle( + move || { + let ctx = chain.execution_proof_gossip_verification_context(); + GossipVerifiedExecutionProof::new(proof, &ctx) + }, + "gossip_execution_proof_verification_handle", + ) + .ok_or(BeaconChainError::RuntimeShutdown)? + .await + .map_err(BeaconChainError::TokioJoin)? + } + .await; + let (outcome, reason) = match &result { + Ok(_) => ("accepted", "valid"), + Err(error) => (error.outcome(), error.as_str()), + }; + metrics::inc_counter_vec( + &metrics::EXECUTION_PROOF_VERIFICATION_TOTAL, + &[proof_type.into(), outcome, reason], + ); + result } } diff --git a/beacon_node/beacon_chain/src/execution_proof_verification/mod.rs b/beacon_node/beacon_chain/src/execution_proof_verification/mod.rs index f1b05c06f0d..3747aeefd19 100644 --- a/beacon_node/beacon_chain/src/execution_proof_verification/mod.rs +++ b/beacon_node/beacon_chain/src/execution_proof_verification/mod.rs @@ -56,6 +56,46 @@ pub enum Error { BeaconChainError(Box), } +impl Error { + /// A stable classification of this gossip verification error. + pub const fn outcome(&self) -> &'static str { + match self { + Self::ProofAlreadySeen + | Self::ValidProofAlreadyKnown + | Self::DuplicateFromValidator { .. } + | Self::UnknownBlockRoot { .. } + | Self::PastFinalizedSlot { .. } + | Self::PayloadUnavailable { .. } => "ignored", + Self::EmptyProofData + | Self::UnknownValidatorIndex(_) + | Self::ValidatorNotActive { .. } + | Self::InvalidSignature + | Self::InvalidProof => "rejected", + Self::ProofEngineMissing | Self::ProofEngine(_) | Self::BeaconChainError(_) => "error", + } + } + + /// A stable, bounded description of this gossip verification error. + pub const fn as_str(&self) -> &'static str { + match self { + Self::ProofAlreadySeen => "proof_already_seen", + Self::ValidProofAlreadyKnown => "valid_proof_already_known", + Self::DuplicateFromValidator { .. } => "duplicate_from_validator", + Self::UnknownBlockRoot { .. } => "unknown_block_root", + Self::PastFinalizedSlot { .. } => "past_finalized_slot", + Self::PayloadUnavailable { .. } => "payload_unavailable", + Self::EmptyProofData => "empty_proof_data", + Self::UnknownValidatorIndex(_) => "unknown_validator_index", + Self::ValidatorNotActive { .. } => "validator_not_active", + Self::InvalidSignature => "invalid_signature", + Self::InvalidProof => "invalid_proof", + Self::ProofEngineMissing => "proof_engine_missing", + Self::ProofEngine(_) => "proof_engine", + Self::BeaconChainError(_) => "beacon_chain", + } + } +} + impl From for Error { fn from(e: BeaconChainError) -> Self { Error::BeaconChainError(Box::new(e)) @@ -75,3 +115,37 @@ impl From for Error { } } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn error_metric_values_are_stable() { + assert_eq!(Error::ProofAlreadySeen.outcome(), "ignored"); + assert_eq!(Error::InvalidSignature.outcome(), "rejected"); + assert_eq!(Error::ProofEngineMissing.outcome(), "error"); + + assert_eq!(Error::ProofAlreadySeen.as_str(), "proof_already_seen"); + assert_eq!( + Error::PayloadUnavailable { + beacon_block_root: Hash256::default(), + } + .as_str(), + "payload_unavailable" + ); + assert_eq!(Error::InvalidSignature.as_str(), "invalid_signature"); + assert_eq!( + Error::ProofEngine(ProofEngineError::ProofVerifierError { + message: "failed".to_string(), + error_type: "internal", + }) + .as_str(), + "proof_engine" + ); + assert_eq!( + Error::BeaconChainError(Box::new(BeaconChainError::RuntimeShutdown)).as_str(), + "beacon_chain" + ); + } +} diff --git a/beacon_node/beacon_chain/src/metrics.rs b/beacon_node/beacon_chain/src/metrics.rs index d4880549848..23be2d74638 100644 --- a/beacon_node/beacon_chain/src/metrics.rs +++ b/beacon_node/beacon_chain/src/metrics.rs @@ -2110,6 +2110,55 @@ pub static PENDING_PAYLOAD_CACHE_SIZE: LazyLock> = LazyLock::ne "Number of entries in the pending payload availability cache.", ) }); +pub static PENDING_PAYLOAD_CACHE_EXECUTION_PROOFS: LazyLock> = + LazyLock::new(|| { + try_create_int_gauge( + "pending_payload_cache_execution_proofs", + "Number of distinct execution proofs stored in the pending payload cache.", + ) + }); +pub static PENDING_PAYLOAD_CACHE_PAYLOADS_AWAITING_EXECUTION_PROOFS: LazyLock> = + LazyLock::new(|| { + try_create_int_gauge( + "pending_payload_cache_payloads_awaiting_execution_proofs", + "Number of executed payload envelopes waiting for more distinct execution proofs.", + ) + }); +pub static PENDING_PAYLOAD_CACHE_REQUIRED_EXECUTION_PROOFS: LazyLock> = + LazyLock::new(|| { + try_create_int_gauge( + "pending_payload_cache_required_execution_proofs", + "Configured number of distinct execution proofs required before payload import.", + ) + }); + +/* + * Execution proof metrics + */ +pub static EXECUTION_PROOF_RECEIVED_TOTAL: LazyLock> = LazyLock::new(|| { + try_create_int_counter_vec( + "beacon_execution_proof_received_total", + "Count of execution proof envelopes received by source and proof type.", + &["source", "proof_type"], + ) +}); +pub static EXECUTION_PROOF_VERIFICATION_TOTAL: LazyLock> = + LazyLock::new(|| { + try_create_int_counter_vec( + "beacon_execution_proof_verification_total", + "Count of execution proof verification outcomes by proof type, outcome, and reason.", + &["proof_type", "outcome", "reason"], + ) + }); +pub static EXECUTION_PROOF_GOSSIP_PROCESSING_SECONDS: LazyLock> = + LazyLock::new(|| { + try_create_histogram_vec_with_buckets( + "beacon_execution_proof_gossip_processing_seconds", + "Time spent processing execution proofs received over gossip by proof type.", + decimal_buckets(-3, 1), + &["proof_type"], + ) + }); pub static DATA_AVAILABILITY_RECONSTRUCTION_TIME: LazyLock> = LazyLock::new(|| { try_create_histogram( @@ -2221,6 +2270,24 @@ pub fn scrape_for_metrics(beacon_chain: &BeaconChain) { &PENDING_PAYLOAD_CACHE_SIZE, beacon_chain.pending_payload_cache.cache_size(), ); + set_gauge_by_usize( + &PENDING_PAYLOAD_CACHE_EXECUTION_PROOFS, + beacon_chain + .pending_payload_cache + .cached_execution_proof_count(), + ); + set_gauge_by_usize( + &PENDING_PAYLOAD_CACHE_PAYLOADS_AWAITING_EXECUTION_PROOFS, + beacon_chain + .pending_payload_cache + .payloads_awaiting_execution_proofs(), + ); + set_gauge_by_usize( + &PENDING_PAYLOAD_CACHE_REQUIRED_EXECUTION_PROOFS, + beacon_chain + .pending_payload_cache + .required_execution_proofs(), + ); if let Some((size, num_lookups)) = beacon_chain.pre_finalization_block_cache.metrics() { set_gauge_by_usize(&PRE_FINALIZATION_BLOCK_CACHE_SIZE, size); diff --git a/beacon_node/beacon_chain/src/pending_payload_cache/mod.rs b/beacon_node/beacon_chain/src/pending_payload_cache/mod.rs index 0401c93d263..878e095a162 100644 --- a/beacon_node/beacon_chain/src/pending_payload_cache/mod.rs +++ b/beacon_node/beacon_chain/src/pending_payload_cache/mod.rs @@ -579,6 +579,31 @@ impl PendingPayloadCache { self.availability_cache.read().len() } + /// Number of distinct execution proofs held across all pending payloads. + pub fn cached_execution_proof_count(&self) -> usize { + self.availability_cache + .read() + .iter() + .map(|(_, components)| components.execution_proofs.len()) + .sum() + } + + /// Number of executed payload envelopes that remain gated on execution proofs. + pub fn payloads_awaiting_execution_proofs(&self) -> usize { + if self.required_execution_proofs == 0 { + return 0; + } + + self.availability_cache + .read() + .iter() + .filter(|(_, components)| { + components.envelope.is_some() + && components.execution_proofs.len() < self.required_execution_proofs + }) + .count() + } + // ── Internal helpers ── fn check_availability( @@ -1038,7 +1063,10 @@ mod data_availability_checker_tests { #[tokio::test] async fn execution_proof_gates_availability() { let s = setup_gated(NodeCustodyType::Fullnode); + assert_eq!(s.cache.cached_execution_proof_count(), 0); + assert_eq!(s.cache.payloads_awaiting_execution_proofs(), 0); s.put_envelope(); + assert_eq!(s.cache.payloads_awaiting_execution_proofs(), 1); assert_missing(s.put_columns(s.custody.clone())); let assigned = ProofType::all(); @@ -1047,6 +1075,8 @@ mod data_availability_checker_tests { for _ in 0..=REQUIRED_EXECUTION_PROOFS { assert_missing(s.put_proof(assigned[0])); } + assert_eq!(s.cache.cached_execution_proof_count(), 1); + assert_eq!(s.cache.payloads_awaiting_execution_proofs(), 1); // Distinct provers up to the requirement flip it to available. let mut availability = None; @@ -1055,6 +1085,11 @@ mod data_availability_checker_tests { } let envelope = assert_available(availability.expect("gate needs two provers or more")); assert_eq!(envelope.block_root, s.block_root); + assert_eq!( + s.cache.cached_execution_proof_count(), + REQUIRED_EXECUTION_PROOFS + ); + assert_eq!(s.cache.payloads_awaiting_execution_proofs(), 0); assert_missing(s.put_proof(assigned[REQUIRED_EXECUTION_PROOFS])); } diff --git a/beacon_node/http_api/src/beacon/execution_proofs.rs b/beacon_node/http_api/src/beacon/execution_proofs.rs index 25464bd2003..c2f0a19c47a 100644 --- a/beacon_node/http_api/src/beacon/execution_proofs.rs +++ b/beacon_node/http_api/src/beacon/execution_proofs.rs @@ -16,6 +16,7 @@ use crate::utils::{ }; use crate::version::add_ssz_content_type_header; use beacon_chain::execution_proof_verification::Error as ProofError; +use beacon_chain::metrics as beacon_chain_metrics; use beacon_chain::{AvailabilityProcessingStatus, BeaconChain, BeaconChainTypes}; use bytes::Bytes; use eth2::types::{self as api_types, Failure}; @@ -224,6 +225,19 @@ async fn publish_execution_proof( let beacon_block_root = proof.beacon_block_root(); let proof_type = proof.proof_type(); let validator_index = proof.validator_index; + let proof_bytes = proof.message.proof_data.len(); + + beacon_chain_metrics::inc_counter_vec( + &beacon_chain_metrics::EXECUTION_PROOF_RECEIVED_TOTAL, + &["http_api", proof_type.into()], + ); + debug!( + %beacon_block_root, + %proof_type, + validator_index, + proof_bytes, + "Received execution proof from HTTP API" + ); let verified = match chain.verify_execution_proof_for_gossip(proof.clone()).await { Ok(verified) => verified, diff --git a/beacon_node/network/src/network_beacon_processor/gossip_methods.rs b/beacon_node/network/src/network_beacon_processor/gossip_methods.rs index e27043614e1..aae09b9edb9 100644 --- a/beacon_node/network/src/network_beacon_processor/gossip_methods.rs +++ b/beacon_node/network/src/network_beacon_processor/gossip_methods.rs @@ -12,6 +12,7 @@ use beacon_chain::data_column_verification::{ }; use beacon_chain::execution_proof_verification::Error as ExecutionProofError; use beacon_chain::fetch_blobs::PartialHeaderOrBid; +use beacon_chain::metrics as beacon_chain_metrics; use beacon_chain::partial_data_column_assembler::UpdatedPartials; use beacon_chain::payload_bid_verification::PayloadBidError; use beacon_chain::payload_envelope_verification::{ @@ -4167,6 +4168,25 @@ impl NetworkBeaconProcessor { ) { let beacon_block_root = execution_proof.beacon_block_root(); let proof_type = execution_proof.proof_type(); + let _timer = beacon_chain_metrics::start_timer_vec( + &beacon_chain_metrics::EXECUTION_PROOF_GOSSIP_PROCESSING_SECONDS, + &[proof_type.into()], + ); + let validator_index = execution_proof.validator_index; + let proof_bytes = execution_proof.message.proof_data.len(); + + beacon_chain_metrics::inc_counter_vec( + &beacon_chain_metrics::EXECUTION_PROOF_RECEIVED_TOTAL, + &["gossip", proof_type.into()], + ); + debug!( + %peer_id, + %beacon_block_root, + %proof_type, + validator_index, + proof_bytes, + "Received execution proof from gossip" + ); match self .chain diff --git a/beacon_node/proof_engine/Cargo.toml b/beacon_node/proof_engine/Cargo.toml index 0d230ff143a..909dfb5b7d6 100644 --- a/beacon_node/proof_engine/Cargo.toml +++ b/beacon_node/proof_engine/Cargo.toml @@ -13,6 +13,7 @@ test-utils = [] ethereum_serde_utils = { workspace = true } ethereum_ssz = { workspace = true } hex = { workspace = true } +metrics = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } types = { workspace = true } diff --git a/beacon_node/proof_engine/src/config.rs b/beacon_node/proof_engine/src/config.rs index fa2faa62645..b3fd57af361 100644 --- a/beacon_node/proof_engine/src/config.rs +++ b/beacon_node/proof_engine/src/config.rs @@ -123,9 +123,10 @@ impl ProofEngineConfig { #[cfg(not(feature = "ere-verifier"))] { - Err(ProofEngineError::ProofVerifierError( - "Lighthouse was built without `ere-verifier`".to_string(), - )) + Err(ProofEngineError::ProofVerifierError { + message: "Lighthouse was built without `ere-verifier`".to_string(), + error_type: "proof_verifier_error", + }) } } } diff --git a/beacon_node/proof_engine/src/ere/bindings.rs b/beacon_node/proof_engine/src/ere/bindings.rs index 4c876928d26..9401d979bd7 100644 --- a/beacon_node/proof_engine/src/ere/bindings.rs +++ b/beacon_node/proof_engine/src/ere/bindings.rs @@ -23,6 +23,18 @@ pub(super) enum EreVerifierError { } impl EreVerifierError { + pub(super) const fn as_str(&self) -> &'static str { + match self { + Self::NullPointer => "null_pointer", + Self::BadZkvmKind => "bad_zkvm_kind", + Self::DecodeProgramVk => "decode_program_vk", + Self::DecodeProof => "decode_proof", + Self::Verify => "verify", + Self::Internal => "internal", + Self::Unknown(_) => "unknown", + } + } + fn from_code(code: i32) -> Self { match code { 1 => Self::NullPointer, @@ -142,17 +154,19 @@ mod tests { #[test] fn decodes_ere_status_codes() { let statuses = [ - (1, EreVerifierError::NullPointer), - (2, EreVerifierError::BadZkvmKind), - (3, EreVerifierError::DecodeProgramVk), - (4, EreVerifierError::DecodeProof), - (5, EreVerifierError::Verify), - (6, EreVerifierError::Internal), - (99, EreVerifierError::Unknown(99)), + (1, EreVerifierError::NullPointer, "null_pointer"), + (2, EreVerifierError::BadZkvmKind, "bad_zkvm_kind"), + (3, EreVerifierError::DecodeProgramVk, "decode_program_vk"), + (4, EreVerifierError::DecodeProof, "decode_proof"), + (5, EreVerifierError::Verify, "verify"), + (6, EreVerifierError::Internal, "internal"), + (99, EreVerifierError::Unknown(99), "unknown"), ]; - for (code, expected) in statuses { - assert_eq!(EreVerifierError::from_code(code), expected); + for (code, expected, expected_label) in statuses { + let error = EreVerifierError::from_code(code); + assert_eq!(error, expected); + assert_eq!(error.as_str(), expected_label); } } } diff --git a/beacon_node/proof_engine/src/ere/mod.rs b/beacon_node/proof_engine/src/ere/mod.rs index 5b9354b7c8c..9bb97fbfacb 100644 --- a/beacon_node/proof_engine/src/ere/mod.rs +++ b/beacon_node/proof_engine/src/ere/mod.rs @@ -21,10 +21,13 @@ impl EreProofEngine { for config in config.execution_proofs() { let verifier = Verifier::new(config.proof_type.zkvm(), &config.program_vk).map_err(|error| { - ProofEngineError::ProofVerifierError(format!( - "failed to initialize ERE verifier for proof type {:?}: {error:?}", - config.proof_type - )) + ProofEngineError::ProofVerifierError { + message: format!( + "failed to initialize ERE verifier for proof type {:?}: {error:?}", + config.proof_type + ), + error_type: error.as_str(), + } })?; verifiers.insert(config.proof_type, verifier); } @@ -52,10 +55,13 @@ impl ProofEngineT for EreProofEngine { return Ok(ProofVerificationOutcome::Invalid); } Err(error) => { - return Err(ProofEngineError::ProofVerifierError(format!( - "ERE verifier failed for proof type {:?}: {error:?}", - proof.proof_type - ))); + return Err(ProofEngineError::ProofVerifierError { + message: format!( + "ERE verifier failed for proof type {:?}: {error:?}", + proof.proof_type + ), + error_type: error.as_str(), + }); } }; diff --git a/beacon_node/proof_engine/src/lib.rs b/beacon_node/proof_engine/src/lib.rs index 1adfcf0bac5..1f2e6c3a861 100644 --- a/beacon_node/proof_engine/src/lib.rs +++ b/beacon_node/proof_engine/src/lib.rs @@ -3,9 +3,11 @@ mod config; #[cfg(feature = "ere-verifier")] pub mod ere; +mod metrics; pub mod test_utils; use std::sync::Arc; +use std::time::Instant; use types::execution::{ExecutionProof, ProofType}; pub use config::{ExecutionProofConfig, ProofEngineConfig}; @@ -14,11 +16,23 @@ pub use config::{ExecutionProofConfig, ProofEngineConfig}; #[derive(Debug)] pub enum ProofEngineError { /// The configured proof verifier could not initialize or complete verification. - ProofVerifierError(String), + ProofVerifierError { + message: String, + error_type: &'static str, + }, /// No verifier is configured for the proof's EIP-8025 proof type. UnconfiguredProofType(ProofType), } +impl ProofEngineError { + pub const fn as_str(&self) -> &'static str { + match self { + Self::ProofVerifierError { error_type, .. } => error_type, + Self::UnconfiguredProofType(_) => "unconfigured_proof_type", + } + } +} + /// Outcome of proof verification. `Invalid` means the artifact does not verify; it says nothing /// about the validity of the payload it claims to prove. #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -29,6 +43,15 @@ pub enum ProofVerificationOutcome { Invalid, } +impl ProofVerificationOutcome { + pub const fn as_str(&self) -> &'static str { + match self { + Self::Valid => "valid", + Self::Invalid => "invalid", + } + } +} + /// Interface used by the beacon chain to verify reconstructed execution proofs. pub trait ProofEngineT: Send + Sync + 'static { /// Verify a reconstructed execution proof. @@ -63,6 +86,40 @@ impl ProofEngine { &self, proof: &ExecutionProof, ) -> Result { - self.inner.verify_execution_proof(proof) + let started = Instant::now(); + let result = self.inner.verify_execution_proof(proof); + let (outcome, error_type) = match &result { + Ok(outcome) => (outcome.as_str(), "none"), + Err(error) => ("error", error.as_str()), + }; + metrics::observe_timer_vec( + &metrics::EXECUTION_PROOF_ENGINE_VERIFICATION_SECONDS, + &[proof.proof_type.into(), outcome, error_type], + started.elapsed(), + ); + result + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn proof_verification_labels_are_stable() { + assert_eq!(ProofVerificationOutcome::Valid.as_str(), "valid"); + assert_eq!(ProofVerificationOutcome::Invalid.as_str(), "invalid"); + assert_eq!( + ProofEngineError::ProofVerifierError { + message: "failed".to_string(), + error_type: "internal", + } + .as_str(), + "internal" + ); + assert_eq!( + ProofEngineError::UnconfiguredProofType(ProofType::RethSP1).as_str(), + "unconfigured_proof_type" + ); } } diff --git a/beacon_node/proof_engine/src/metrics.rs b/beacon_node/proof_engine/src/metrics.rs new file mode 100644 index 00000000000..768291b0f7b --- /dev/null +++ b/beacon_node/proof_engine/src/metrics.rs @@ -0,0 +1,12 @@ +pub use metrics::*; +use std::sync::LazyLock; + +pub static EXECUTION_PROOF_ENGINE_VERIFICATION_SECONDS: LazyLock> = + LazyLock::new(|| { + try_create_histogram_vec_with_buckets( + "beacon_execution_proof_engine_verification_seconds", + "Time spent verifying execution proofs in the proof engine by proof type, outcome, and error type.", + decimal_buckets(-3, 1), + &["proof_type", "outcome", "error_type"], + ) + }); diff --git a/consensus/types/src/execution/execution_proof/envelope.rs b/consensus/types/src/execution/execution_proof/envelope.rs index 5ad9ec878b6..106a737280e 100644 --- a/consensus/types/src/execution/execution_proof/envelope.rs +++ b/consensus/types/src/execution/execution_proof/envelope.rs @@ -12,6 +12,7 @@ use tree_hash_derive::TreeHash; #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Encode, Decode, TreeHash)] #[context_deserialize(ForkName)] pub struct ExecutionProofEnvelope { + #[serde(with = "ssz_types::serde_utils::hex_var_list")] pub proof_data: ProofData, #[serde(with = "quoted_proof_type")] pub proof_type: ProofType, @@ -67,10 +68,11 @@ mod tests { } #[test] - fn signed_envelope_json_quotes_integers() { + fn signed_envelope_json_uses_beacon_api_encoding() { let envelope = signed_envelope(ProofType::RethSP1); let json = serde_json::to_value(&envelope).expect("serializes"); + assert_eq!(json["message"]["proof_data"], "0x01"); assert_eq!(json["message"]["proof_type"], "5"); assert_eq!(json["validator_index"], "7"); diff --git a/consensus/types/src/execution/execution_proof/proof_type.rs b/consensus/types/src/execution/execution_proof/proof_type.rs index 1795d886e5c..3b28c13d8c6 100644 --- a/consensus/types/src/execution/execution_proof/proof_type.rs +++ b/consensus/types/src/execution/execution_proof/proof_type.rs @@ -1,7 +1,7 @@ use crate::Hash256; use serde::{Deserialize, Serialize}; use ssz::{Decode as SszDecode, DecodeError, Encode as SszEncode}; -use strum::{Display, FromRepr, VariantArray}; +use strum::{Display, FromRepr, IntoStaticStr, VariantArray}; use tree_hash::{PackedEncoding, TreeHash as TreeHashTrait, TreeHashType}; /// Proof system that verifies an execution proof. @@ -35,6 +35,7 @@ pub enum ZkvmKind { Hash, Display, FromRepr, + IntoStaticStr, VariantArray, Serialize, Deserialize, diff --git a/testing/execution_proof_network_tests/src/network.rs b/testing/execution_proof_network_tests/src/network.rs index 85379b181d4..d0b2d34a418 100644 --- a/testing/execution_proof_network_tests/src/network.rs +++ b/testing/execution_proof_network_tests/src/network.rs @@ -166,7 +166,7 @@ impl ProofNetworkConfig { nodes, validator_count: 16, slot_duration_ms: 2000, - genesis_delay_secs: 30, + genesis_delay_secs: 60, gloas_fork_epoch: 0, log_filter: DEFAULT_LOG_FILTER.to_string(), } diff --git a/testing/execution_proof_network_tests/src/proving_execution_layer.rs b/testing/execution_proof_network_tests/src/proving_execution_layer.rs index b9fdbc6ed9e..45c5057d255 100644 --- a/testing/execution_proof_network_tests/src/proving_execution_layer.rs +++ b/testing/execution_proof_network_tests/src/proving_execution_layer.rs @@ -48,6 +48,9 @@ pub struct ProvenPayload { /// How long the prover waits for the beacon node to expose the block carrying a payload. const BLOCK_LOOKUP_TIMEOUT: Duration = Duration::from_secs(10); const BLOCK_LOOKUP_INTERVAL: Duration = Duration::from_millis(250); +/// Approximate mock proof-generation time. Without a delay, proof gossip can reach peers before +/// the block it references and be rejected as unknown. +const PROOF_GENERATION_DELAY: Duration = Duration::from_millis(500); struct Inner { upstream: String, @@ -202,6 +205,7 @@ impl Inner { .ok_or("no beacon node attached to the proving execution layer yet")?; let (block_root, slot) = self.find_block(&target, payload).await?; + tokio::time::sleep(PROOF_GENERATION_DELAY).await; let genesis_validators_root = target .get_beacon_genesis() .await