Resolve merge conflicts

This commit is contained in:
Eitan Seri- Levi
2026-02-26 13:19:00 -08:00
92 changed files with 2146 additions and 3426 deletions

View File

@@ -22,7 +22,6 @@ use eth2::types::{ForkVersionedResponse, builder::SignedBuilderBid};
use fixed_bytes::UintExtended;
use fork_choice::ForkchoiceUpdateParameters;
use logging::crit;
use lru::LruCache;
pub use payload_status::PayloadStatus;
use payload_status::process_payload_status;
use sensitive_url::SensitiveUrl;
@@ -32,7 +31,6 @@ use std::collections::{HashMap, hash_map::Entry};
use std::fmt;
use std::future::Future;
use std::io::Write;
use std::num::NonZeroUsize;
use std::path::PathBuf;
use std::sync::Arc;
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
@@ -45,6 +43,7 @@ use tokio::{
use tokio_stream::wrappers::WatchStream;
use tracing::{Instrument, debug, debug_span, error, info, instrument, warn};
use tree_hash::TreeHash;
use types::ExecutionPayloadGloas;
use types::builder::BuilderBid;
use types::execution::BlockProductionVersion;
use types::kzg_ext::KzgCommitments;
@@ -57,7 +56,6 @@ use types::{
ExecutionPayloadCapella, ExecutionPayloadElectra, ExecutionPayloadFulu, FullPayload,
ProposerPreparationData, Slot,
};
use types::{ExecutionPayloadGloas, new_non_zero_usize};
mod block_hash;
mod engine_api;
@@ -75,10 +73,6 @@ pub const DEFAULT_EXECUTION_ENDPOINT: &str = "http://localhost:8551/";
/// Name for the default file used for the jwt secret.
pub const DEFAULT_JWT_FILE: &str = "jwt.hex";
/// Each time the `ExecutionLayer` retrieves a block from an execution node, it stores that block
/// in an LRU cache to avoid redundant lookups. This is the size of that cache.
const EXECUTION_BLOCKS_LRU_CACHE_SIZE: NonZeroUsize = new_non_zero_usize(128);
/// A fee recipient address for use during block production. Only used as a very last resort if
/// there is no address provided by the user.
///
@@ -452,7 +446,6 @@ struct Inner<E: EthSpec> {
execution_engine_forkchoice_lock: Mutex<()>,
suggested_fee_recipient: Option<Address>,
proposer_preparation_data: Mutex<HashMap<u64, ProposerPreparationDataEntry>>,
execution_blocks: Mutex<LruCache<ExecutionBlockHash, ExecutionBlock>>,
proposers: RwLock<HashMap<ProposerKey, Proposer>>,
executor: TaskExecutor,
payload_cache: PayloadCache<E>,
@@ -563,7 +556,6 @@ impl<E: EthSpec> ExecutionLayer<E> {
suggested_fee_recipient,
proposer_preparation_data: Mutex::new(HashMap::new()),
proposers: RwLock::new(HashMap::new()),
execution_blocks: Mutex::new(LruCache::new(EXECUTION_BLOCKS_LRU_CACHE_SIZE)),
executor,
payload_cache: PayloadCache::default(),
last_new_payload_errored: RwLock::new(false),
@@ -655,12 +647,6 @@ impl<E: EthSpec> ExecutionLayer<E> {
.ok_or(ApiError::ExecutionHeadBlockNotFound)?;
Ok(block.total_difficulty)
}
/// Note: this function returns a mutex guard, be careful to avoid deadlocks.
async fn execution_blocks(
&self,
) -> MutexGuard<'_, LruCache<ExecutionBlockHash, ExecutionBlock>> {
self.inner.execution_blocks.lock().await
}
/// Gives access to a channel containing if the last engine state is online or not.
///
@@ -1641,208 +1627,6 @@ impl<E: EthSpec> ExecutionLayer<E> {
Ok(versions)
}
/// Used during block production to determine if the merge has been triggered.
///
/// ## Specification
///
/// `get_terminal_pow_block_hash`
///
/// https://github.com/ethereum/consensus-specs/blob/v1.1.5/specs/merge/validator.md
pub async fn get_terminal_pow_block_hash(
&self,
spec: &ChainSpec,
timestamp: u64,
) -> Result<Option<ExecutionBlockHash>, Error> {
let _timer = metrics::start_timer_vec(
&metrics::EXECUTION_LAYER_REQUEST_TIMES,
&[metrics::GET_TERMINAL_POW_BLOCK_HASH],
);
let hash_opt = self
.engine()
.request(|engine| async move {
let terminal_block_hash = spec.terminal_block_hash;
if terminal_block_hash != ExecutionBlockHash::zero() {
if self
.get_pow_block(engine, terminal_block_hash)
.await?
.is_some()
{
return Ok(Some(terminal_block_hash));
} else {
return Ok(None);
}
}
let block = self.get_pow_block_at_total_difficulty(engine, spec).await?;
if let Some(pow_block) = block {
// If `terminal_block.timestamp == transition_block.timestamp`,
// we violate the invariant that a block's timestamp must be
// strictly greater than its parent's timestamp.
// The execution layer will reject a fcu call with such payload
// attributes leading to a missed block.
// Hence, we return `None` in such a case.
if pow_block.timestamp >= timestamp {
return Ok(None);
}
}
Ok(block.map(|b| b.block_hash))
})
.await
.map_err(Box::new)
.map_err(Error::EngineError)?;
if let Some(hash) = &hash_opt {
info!(
terminal_block_hash_override = ?spec.terminal_block_hash,
terminal_total_difficulty = ?spec.terminal_total_difficulty,
block_hash = ?hash,
"Found terminal block hash"
);
}
Ok(hash_opt)
}
/// This function should remain internal. External users should use
/// `self.get_terminal_pow_block` instead, since it checks against the terminal block hash
/// override.
///
/// ## Specification
///
/// `get_pow_block_at_terminal_total_difficulty`
///
/// https://github.com/ethereum/consensus-specs/blob/v1.1.5/specs/merge/validator.md
async fn get_pow_block_at_total_difficulty(
&self,
engine: &Engine,
spec: &ChainSpec,
) -> Result<Option<ExecutionBlock>, ApiError> {
let mut block = engine
.api
.get_block_by_number(BlockByNumberQuery::Tag(LATEST_TAG))
.await?
.ok_or(ApiError::ExecutionHeadBlockNotFound)?;
self.execution_blocks().await.put(block.block_hash, block);
loop {
let block_reached_ttd =
block.terminal_total_difficulty_reached(spec.terminal_total_difficulty);
if block_reached_ttd {
if block.parent_hash == ExecutionBlockHash::zero() {
return Ok(Some(block));
}
let parent = self
.get_pow_block(engine, block.parent_hash)
.await?
.ok_or(ApiError::ExecutionBlockNotFound(block.parent_hash))?;
let parent_reached_ttd =
parent.terminal_total_difficulty_reached(spec.terminal_total_difficulty);
if block_reached_ttd && !parent_reached_ttd {
return Ok(Some(block));
} else {
block = parent;
}
} else {
return Ok(None);
}
}
}
/// Used during block verification to check that a block correctly triggers the merge.
///
/// ## Returns
///
/// - `Some(true)` if the given `block_hash` is the terminal proof-of-work block.
/// - `Some(false)` if the given `block_hash` is certainly *not* the terminal proof-of-work
/// block.
/// - `None` if the `block_hash` or its parent were not present on the execution engine.
/// - `Err(_)` if there was an error connecting to the execution engine.
///
/// ## Fallback Behaviour
///
/// The request will be broadcast to all nodes, simultaneously. It will await a response (or
/// failure) from all nodes and then return based on the first of these conditions which
/// returns true:
///
/// - Terminal, if any node indicates it is terminal.
/// - Not terminal, if any node indicates it is non-terminal.
/// - Block not found, if any node cannot find the block.
/// - An error, if all nodes return an error.
///
/// ## Specification
///
/// `is_valid_terminal_pow_block`
///
/// https://github.com/ethereum/consensus-specs/blob/v1.1.0/specs/merge/fork-choice.md
pub async fn is_valid_terminal_pow_block_hash(
&self,
block_hash: ExecutionBlockHash,
spec: &ChainSpec,
) -> Result<Option<bool>, Error> {
let _timer = metrics::start_timer_vec(
&metrics::EXECUTION_LAYER_REQUEST_TIMES,
&[metrics::IS_VALID_TERMINAL_POW_BLOCK_HASH],
);
self.engine()
.request(|engine| async move {
if let Some(pow_block) = self.get_pow_block(engine, block_hash).await?
&& let Some(pow_parent) =
self.get_pow_block(engine, pow_block.parent_hash).await?
{
return Ok(Some(
self.is_valid_terminal_pow_block(pow_block, pow_parent, spec),
));
}
Ok(None)
})
.await
.map_err(Box::new)
.map_err(Error::EngineError)
}
/// This function should remain internal.
///
/// External users should use `self.is_valid_terminal_pow_block_hash`.
fn is_valid_terminal_pow_block(
&self,
block: ExecutionBlock,
parent: ExecutionBlock,
spec: &ChainSpec,
) -> bool {
let is_total_difficulty_reached =
block.terminal_total_difficulty_reached(spec.terminal_total_difficulty);
let is_parent_total_difficulty_valid = parent
.total_difficulty
.is_some_and(|td| td < spec.terminal_total_difficulty);
is_total_difficulty_reached && is_parent_total_difficulty_valid
}
/// Maps to the `eth_getBlockByHash` JSON-RPC call.
async fn get_pow_block(
&self,
engine: &Engine,
hash: ExecutionBlockHash,
) -> Result<Option<ExecutionBlock>, ApiError> {
if let Some(cached) = self.execution_blocks().await.get(&hash).copied() {
// The block was in the cache, no need to request it from the execution
// engine.
return Ok(Some(cached));
}
// The block was *not* in the cache, request it from the execution
// engine and cache it for future reference.
if let Some(block) = engine.api.get_block_by_hash(hash).await? {
self.execution_blocks().await.put(hash, block);
Ok(Some(block))
} else {
Ok(None)
}
}
pub async fn get_payload_bodies_by_hash(
&self,
hashes: Vec<ExecutionBlockHash>,
@@ -2330,15 +2114,6 @@ async fn timed_future<F: Future<Output = T>, T>(metric: &str, future: F) -> (T,
(result, duration)
}
#[cfg(test)]
/// Returns the duration since the unix epoch.
fn timestamp_now() -> u64 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_else(|_| Duration::from_secs(0))
.as_secs()
}
fn noop<E: EthSpec>(
_: &ExecutionLayer<E>,
_: PayloadContentsRefTuple<E>,
@@ -2359,7 +2134,6 @@ mod test {
async fn produce_three_valid_pos_execution_blocks() {
let runtime = TestRuntime::default();
MockExecutionLayer::default_params(runtime.task_executor.clone())
.move_to_terminal_block()
.produce_valid_execution_payload_on_head()
.await
.produce_valid_execution_payload_on_head()
@@ -2388,129 +2162,4 @@ mod test {
Some(30_029_266)
);
}
#[tokio::test]
async fn test_forked_terminal_block() {
let runtime = TestRuntime::default();
let (mock, block_hash) = MockExecutionLayer::default_params(runtime.task_executor.clone())
.move_to_terminal_block()
.produce_forked_pow_block();
assert!(
mock.el
.is_valid_terminal_pow_block_hash(block_hash, &mock.spec)
.await
.unwrap()
.unwrap()
);
}
#[tokio::test]
async fn finds_valid_terminal_block_hash() {
let runtime = TestRuntime::default();
MockExecutionLayer::default_params(runtime.task_executor.clone())
.move_to_block_prior_to_terminal_block()
.with_terminal_block(|spec, el, _| async move {
el.engine().upcheck().await;
assert_eq!(
el.get_terminal_pow_block_hash(&spec, timestamp_now())
.await
.unwrap(),
None
)
})
.await
.move_to_terminal_block()
.with_terminal_block(|spec, el, terminal_block| async move {
assert_eq!(
el.get_terminal_pow_block_hash(&spec, timestamp_now())
.await
.unwrap(),
Some(terminal_block.unwrap().block_hash)
)
})
.await;
}
#[tokio::test]
async fn rejects_terminal_block_with_equal_timestamp() {
let runtime = TestRuntime::default();
MockExecutionLayer::default_params(runtime.task_executor.clone())
.move_to_block_prior_to_terminal_block()
.with_terminal_block(|spec, el, _| async move {
el.engine().upcheck().await;
assert_eq!(
el.get_terminal_pow_block_hash(&spec, timestamp_now())
.await
.unwrap(),
None
)
})
.await
.move_to_terminal_block()
.with_terminal_block(|spec, el, terminal_block| async move {
let timestamp = terminal_block.as_ref().map(|b| b.timestamp).unwrap();
assert_eq!(
el.get_terminal_pow_block_hash(&spec, timestamp)
.await
.unwrap(),
None
)
})
.await;
}
#[tokio::test]
async fn verifies_valid_terminal_block_hash() {
let runtime = TestRuntime::default();
MockExecutionLayer::default_params(runtime.task_executor.clone())
.move_to_terminal_block()
.with_terminal_block(|spec, el, terminal_block| async move {
el.engine().upcheck().await;
assert_eq!(
el.is_valid_terminal_pow_block_hash(terminal_block.unwrap().block_hash, &spec)
.await
.unwrap(),
Some(true)
)
})
.await;
}
#[tokio::test]
async fn rejects_invalid_terminal_block_hash() {
let runtime = TestRuntime::default();
MockExecutionLayer::default_params(runtime.task_executor.clone())
.move_to_terminal_block()
.with_terminal_block(|spec, el, terminal_block| async move {
el.engine().upcheck().await;
let invalid_terminal_block = terminal_block.unwrap().parent_hash;
assert_eq!(
el.is_valid_terminal_pow_block_hash(invalid_terminal_block, &spec)
.await
.unwrap(),
Some(false)
)
})
.await;
}
#[tokio::test]
async fn rejects_unknown_terminal_block_hash() {
let runtime = TestRuntime::default();
MockExecutionLayer::default_params(runtime.task_executor.clone())
.move_to_terminal_block()
.with_terminal_block(|spec, el, _| async move {
el.engine().upcheck().await;
let missing_terminal_block = ExecutionBlockHash::repeat_byte(42);
assert_eq!(
el.is_valid_terminal_pow_block_hash(missing_terminal_block, &spec)
.await
.unwrap(),
None
)
})
.await;
}
}

View File

@@ -10,8 +10,6 @@ pub const GET_BLINDED_PAYLOAD_BUILDER: &str = "get_blinded_payload_builder";
pub const POST_BLINDED_PAYLOAD_BUILDER: &str = "post_blinded_payload_builder";
pub const NEW_PAYLOAD: &str = "new_payload";
pub const FORKCHOICE_UPDATED: &str = "forkchoice_updated";
pub const GET_TERMINAL_POW_BLOCK_HASH: &str = "get_terminal_pow_block_hash";
pub const IS_VALID_TERMINAL_POW_BLOCK_HASH: &str = "is_valid_terminal_pow_block_hash";
pub const LOCAL: &str = "local";
pub const BUILDER: &str = "builder";
pub const SUCCESS: &str = "success";

View File

@@ -1,7 +1,8 @@
use crate::engine_api::{
ExecutionBlock, PayloadAttributes, PayloadId, PayloadStatusV1, PayloadStatusV1Status,
json_structures::{
JsonForkchoiceUpdatedV1Response, JsonPayloadStatusV1, JsonPayloadStatusV1Status,
BlobAndProof, BlobAndProofV1, BlobAndProofV2, JsonForkchoiceUpdatedV1Response,
JsonPayloadStatusV1, JsonPayloadStatusV1Status,
},
};
use crate::engines::ForkchoiceState;
@@ -15,6 +16,7 @@ use rand::{Rng, SeedableRng, rngs::StdRng};
use serde::{Deserialize, Serialize};
use ssz::Decode;
use ssz_types::VariableList;
use state_processing::per_block_processing::deneb::kzg_commitment_to_versioned_hash;
use std::cmp::max;
use std::collections::HashMap;
use std::sync::Arc;
@@ -28,8 +30,6 @@ use types::{
Transactions, Uint256,
};
use super::DEFAULT_TERMINAL_BLOCK;
const TEST_BLOB_BUNDLE: &[u8] = include_bytes!("fixtures/mainnet/test_blobs_bundle.ssz");
const TEST_BLOB_BUNDLE_V2: &[u8] = include_bytes!("fixtures/mainnet/test_blobs_bundle_v2.ssz");
@@ -172,9 +172,6 @@ fn make_rng() -> Arc<Mutex<StdRng>> {
impl<E: EthSpec> ExecutionBlockGenerator<E> {
#[allow(clippy::too_many_arguments)]
pub fn new(
terminal_total_difficulty: Uint256,
terminal_block_number: u64,
terminal_block_hash: ExecutionBlockHash,
shanghai_time: Option<u64>,
cancun_time: Option<u64>,
prague_time: Option<u64>,
@@ -187,9 +184,9 @@ impl<E: EthSpec> ExecutionBlockGenerator<E> {
finalized_block_hash: <_>::default(),
blocks: <_>::default(),
block_hashes: <_>::default(),
terminal_total_difficulty,
terminal_block_number,
terminal_block_hash,
terminal_total_difficulty: Default::default(),
terminal_block_number: 0,
terminal_block_hash: Default::default(),
pending_payloads: <_>::default(),
next_payload_id: 0,
payload_ids: <_>::default(),
@@ -293,25 +290,6 @@ impl<E: EthSpec> ExecutionBlockGenerator<E> {
.and_then(|block| block.as_execution_payload())
}
pub fn move_to_block_prior_to_terminal_block(&mut self) -> Result<(), String> {
let target_block = self
.terminal_block_number
.checked_sub(1)
.ok_or("terminal pow block is 0")?;
self.move_to_pow_block(target_block)
}
pub fn move_to_terminal_block(&mut self) -> Result<(), String> {
self.move_to_pow_block(self.terminal_block_number)
}
pub fn move_to_pow_block(&mut self, target_block: u64) -> Result<(), String> {
let next_block = self.latest_block().unwrap().block_number() + 1;
assert!(target_block >= next_block);
self.insert_pow_blocks(next_block..=target_block)
}
pub fn drop_all_blocks(&mut self) {
self.blocks = <_>::default();
self.block_hashes = <_>::default();
@@ -480,6 +458,40 @@ impl<E: EthSpec> ExecutionBlockGenerator<E> {
self.blobs_bundles.get(id).cloned()
}
/// Look up a blob and proof by versioned hash across all stored bundles.
pub fn get_blob_and_proof(&self, versioned_hash: &Hash256) -> Option<BlobAndProof<E>> {
self.blobs_bundles
.iter()
.find_map(|(payload_id, blobs_bundle)| {
let (blob_idx, _) =
blobs_bundle
.commitments
.iter()
.enumerate()
.find(|(_, commitment)| {
&kzg_commitment_to_versioned_hash(commitment) == versioned_hash
})?;
let is_fulu = self.payload_ids.get(payload_id)?.fork_name().fulu_enabled();
let blob = blobs_bundle.blobs.get(blob_idx)?.clone();
if is_fulu {
let start = blob_idx * E::cells_per_ext_blob();
let end = start + E::cells_per_ext_blob();
let proofs = blobs_bundle
.proofs
.get(start..end)?
.to_vec()
.try_into()
.ok()?;
Some(BlobAndProof::V2(BlobAndProofV2 { blob, proofs }))
} else {
Some(BlobAndProof::V1(BlobAndProofV1 {
blob,
proof: *blobs_bundle.proofs.get(blob_idx)?,
}))
}
})
}
pub fn new_payload(&mut self, payload: ExecutionPayload<E>) -> PayloadStatusV1 {
let Some(parent) = self.blocks.get(&payload.parent_hash()) else {
return PayloadStatusV1 {
@@ -879,27 +891,22 @@ fn payload_id_from_u64(n: u64) -> PayloadId {
n.to_le_bytes()
}
pub fn generate_genesis_header<E: EthSpec>(
spec: &ChainSpec,
post_transition_merge: bool,
) -> Option<ExecutionPayloadHeader<E>> {
pub fn generate_genesis_header<E: EthSpec>(spec: &ChainSpec) -> Option<ExecutionPayloadHeader<E>> {
let genesis_fork = spec.fork_name_at_slot::<E>(spec.genesis_slot);
let genesis_block_hash =
generate_genesis_block(spec.terminal_total_difficulty, DEFAULT_TERMINAL_BLOCK)
.ok()
.map(|block| block.block_hash);
let genesis_block_hash = generate_genesis_block(Default::default(), 0)
.ok()
.map(|block| block.block_hash);
let empty_transactions_root = Transactions::<E>::empty().tree_hash_root();
match genesis_fork {
ForkName::Base | ForkName::Altair => None,
ForkName::Base | ForkName::Altair => {
// Pre-Bellatrix forks have no execution payload
None
}
ForkName::Bellatrix => {
if post_transition_merge {
let mut header = ExecutionPayloadHeader::Bellatrix(<_>::default());
*header.block_hash_mut() = genesis_block_hash.unwrap_or_default();
*header.transactions_root_mut() = empty_transactions_root;
Some(header)
} else {
Some(ExecutionPayloadHeader::<E>::Bellatrix(<_>::default()))
}
let mut header = ExecutionPayloadHeader::Bellatrix(<_>::default());
*header.block_hash_mut() = genesis_block_hash.unwrap_or_default();
*header.transactions_root_mut() = empty_transactions_root;
Some(header)
}
ForkName::Capella => {
let mut header = ExecutionPayloadHeader::Capella(<_>::default());
@@ -985,70 +992,6 @@ mod test {
use kzg::{Bytes48, CellRef, KzgBlobRef, trusted_setup::get_trusted_setup};
use types::{MainnetEthSpec, MinimalEthSpec};
#[test]
fn pow_chain_only() {
const TERMINAL_DIFFICULTY: u64 = 10;
const TERMINAL_BLOCK: u64 = 10;
const DIFFICULTY_INCREMENT: u64 = 1;
let mut generator: ExecutionBlockGenerator<MainnetEthSpec> = ExecutionBlockGenerator::new(
Uint256::from(TERMINAL_DIFFICULTY),
TERMINAL_BLOCK,
ExecutionBlockHash::zero(),
None,
None,
None,
None,
None,
None,
);
for i in 0..=TERMINAL_BLOCK {
if i > 0 {
generator.insert_pow_block(i).unwrap();
}
/*
* Generate a block, inspect it.
*/
let block = generator.latest_block().unwrap();
assert_eq!(block.block_number(), i);
let expected_parent = i
.checked_sub(1)
.map(|i| generator.block_by_number(i).unwrap().block_hash())
.unwrap_or_else(ExecutionBlockHash::zero);
assert_eq!(block.parent_hash(), expected_parent);
assert_eq!(
block.total_difficulty().unwrap(),
Uint256::from(i * DIFFICULTY_INCREMENT)
);
assert_eq!(generator.block_by_hash(block.block_hash()).unwrap(), block);
assert_eq!(generator.block_by_number(i).unwrap(), block);
/*
* Check the parent is accessible.
*/
if let Some(prev_i) = i.checked_sub(1) {
assert_eq!(
generator.block_by_number(prev_i).unwrap(),
generator.block_by_hash(block.parent_hash()).unwrap()
);
}
/*
* Check the next block is inaccessible.
*/
let next_i = i + 1;
assert!(generator.block_by_number(next_i).is_none());
}
}
#[test]
fn valid_test_blobs_bundle_v1() {
assert!(

View File

@@ -476,6 +476,35 @@ pub async fn handle_rpc<E: EthSpec>(
_ => unreachable!(),
}
}
ENGINE_GET_BLOBS_V1 => {
let versioned_hashes =
get_param::<Vec<Hash256>>(params, 0).map_err(|s| (s, BAD_PARAMS_ERROR_CODE))?;
let generator = ctx.execution_block_generator.read();
// V1: per-element nullable array, positionally matching the request.
let response: Vec<Option<BlobAndProofV1<E>>> = versioned_hashes
.iter()
.map(|hash| match generator.get_blob_and_proof(hash) {
Some(BlobAndProof::V1(v1)) => Some(v1),
_ => None,
})
.collect();
Ok(serde_json::to_value(response).unwrap())
}
ENGINE_GET_BLOBS_V2 => {
let versioned_hashes =
get_param::<Vec<Hash256>>(params, 0).map_err(|s| (s, BAD_PARAMS_ERROR_CODE))?;
let generator = ctx.execution_block_generator.read();
// V2: all-or-nothing — null if any blob is missing.
let results: Vec<Option<BlobAndProofV2<E>>> = versioned_hashes
.iter()
.map(|hash| match generator.get_blob_and_proof(hash) {
Some(BlobAndProof::V2(v2)) => Some(v2),
_ => None,
})
.collect();
let response: Option<Vec<BlobAndProofV2<E>>> = results.into_iter().collect();
Ok(serde_json::to_value(response).unwrap())
}
ENGINE_FORKCHOICE_UPDATED_V1
| ENGINE_FORKCHOICE_UPDATED_V2
| ENGINE_FORKCHOICE_UPDATED_V3 => {

View File

@@ -1,9 +1,4 @@
use crate::{
test_utils::{
DEFAULT_JWT_SECRET, DEFAULT_TERMINAL_BLOCK, DEFAULT_TERMINAL_DIFFICULTY, MockServer,
},
*,
};
use crate::{test_utils::DEFAULT_JWT_SECRET, test_utils::MockServer, *};
use alloy_primitives::B256 as H256;
use fixed_bytes::FixedBytesExtended;
use kzg::Kzg;
@@ -20,12 +15,10 @@ pub struct MockExecutionLayer<E: EthSpec> {
impl<E: EthSpec> MockExecutionLayer<E> {
pub fn default_params(executor: TaskExecutor) -> Self {
let mut spec = MainnetEthSpec::default_spec();
spec.terminal_total_difficulty = Uint256::from(DEFAULT_TERMINAL_DIFFICULTY);
spec.terminal_block_hash = ExecutionBlockHash::zero();
spec.terminal_block_hash_activation_epoch = Epoch::new(0);
Self::new(
executor,
DEFAULT_TERMINAL_BLOCK,
None,
None,
None,
@@ -40,7 +33,6 @@ impl<E: EthSpec> MockExecutionLayer<E> {
#[allow(clippy::too_many_arguments)]
pub fn new(
executor: TaskExecutor,
terminal_block: u64,
shanghai_time: Option<u64>,
cancun_time: Option<u64>,
prague_time: Option<u64>,
@@ -56,9 +48,6 @@ impl<E: EthSpec> MockExecutionLayer<E> {
let server = MockServer::new(
&handle,
jwt_key,
spec.terminal_total_difficulty,
terminal_block,
spec.terminal_block_hash,
shanghai_time,
cancun_time,
prague_time,
@@ -293,53 +282,4 @@ impl<E: EthSpec> MockExecutionLayer<E> {
assert_eq!(head_execution_block.block_hash(), block_hash);
assert_eq!(head_execution_block.parent_hash(), parent_hash);
}
pub fn move_to_block_prior_to_terminal_block(self) -> Self {
self.server
.execution_block_generator()
.move_to_block_prior_to_terminal_block()
.unwrap();
self
}
pub fn move_to_terminal_block(self) -> Self {
self.server
.execution_block_generator()
.move_to_terminal_block()
.unwrap();
self
}
pub fn produce_forked_pow_block(self) -> (Self, ExecutionBlockHash) {
let head_block = self
.server
.execution_block_generator()
.latest_block()
.unwrap();
let block_hash = self
.server
.execution_block_generator()
.insert_pow_block_by_hash(head_block.parent_hash(), 1)
.unwrap();
(self, block_hash)
}
pub async fn with_terminal_block<U, V>(self, func: U) -> Self
where
U: Fn(Arc<ChainSpec>, ExecutionLayer<E>, Option<ExecutionBlock>) -> V,
V: Future<Output = ()>,
{
let terminal_block_number = self
.server
.execution_block_generator()
.terminal_block_number;
let terminal_block = self
.server
.execution_block_generator()
.execution_block_by_number(terminal_block_number);
func(self.spec.clone(), self.el.clone(), terminal_block).await;
self
}
}

View File

@@ -35,8 +35,6 @@ pub use hook::Hook;
pub use mock_builder::{MockBuilder, Operation, mock_builder_extra_data};
pub use mock_execution_layer::MockExecutionLayer;
pub const DEFAULT_TERMINAL_DIFFICULTY: u64 = 6400;
pub const DEFAULT_TERMINAL_BLOCK: u64 = 64;
pub const DEFAULT_JWT_SECRET: [u8; 32] = [42; 32];
pub const DEFAULT_MOCK_EL_PAYLOAD_VALUE_WEI: u128 = 10_000_000_000_000_000;
pub const DEFAULT_BUILDER_PAYLOAD_VALUE_WEI: u128 = 20_000_000_000_000_000;
@@ -80,9 +78,6 @@ mod mock_execution_layer;
pub struct MockExecutionConfig {
pub server_config: Config,
pub jwt_key: JwtKey,
pub terminal_difficulty: Uint256,
pub terminal_block: u64,
pub terminal_block_hash: ExecutionBlockHash,
pub shanghai_time: Option<u64>,
pub cancun_time: Option<u64>,
pub prague_time: Option<u64>,
@@ -94,9 +89,6 @@ impl Default for MockExecutionConfig {
fn default() -> Self {
Self {
jwt_key: JwtKey::random(),
terminal_difficulty: Uint256::from(DEFAULT_TERMINAL_DIFFICULTY),
terminal_block: DEFAULT_TERMINAL_BLOCK,
terminal_block_hash: ExecutionBlockHash::zero(),
server_config: Config::default(),
shanghai_time: None,
cancun_time: None,
@@ -119,9 +111,6 @@ impl<E: EthSpec> MockServer<E> {
Self::new(
&runtime::Handle::current(),
JwtKey::from_slice(&DEFAULT_JWT_SECRET).unwrap(),
Uint256::from(DEFAULT_TERMINAL_DIFFICULTY),
DEFAULT_TERMINAL_BLOCK,
ExecutionBlockHash::zero(),
None, // FIXME(capella): should this be the default?
None, // FIXME(deneb): should this be the default?
None, // FIXME(electra): should this be the default?
@@ -139,9 +128,6 @@ impl<E: EthSpec> MockServer<E> {
create_test_tracing_subscriber();
let MockExecutionConfig {
jwt_key,
terminal_difficulty,
terminal_block,
terminal_block_hash,
server_config,
shanghai_time,
cancun_time,
@@ -152,9 +138,6 @@ impl<E: EthSpec> MockServer<E> {
let last_echo_request = Arc::new(RwLock::new(None));
let preloaded_responses = Arc::new(Mutex::new(vec![]));
let execution_block_generator = ExecutionBlockGenerator::new(
terminal_difficulty,
terminal_block,
terminal_block_hash,
shanghai_time,
cancun_time,
prague_time,
@@ -216,9 +199,6 @@ impl<E: EthSpec> MockServer<E> {
pub fn new(
handle: &runtime::Handle,
jwt_key: JwtKey,
terminal_difficulty: Uint256,
terminal_block: u64,
terminal_block_hash: ExecutionBlockHash,
shanghai_time: Option<u64>,
cancun_time: Option<u64>,
prague_time: Option<u64>,
@@ -231,9 +211,6 @@ impl<E: EthSpec> MockServer<E> {
MockExecutionConfig {
server_config: Config::default(),
jwt_key,
terminal_difficulty,
terminal_block,
terminal_block_hash,
shanghai_time,
cancun_time,
prague_time,