Merge unstable 20230925 into deneb-free-blobs.
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
name = "beacon_chain"
|
||||
version = "0.2.0"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>", "Age Manning <Age@AgeManning.com>"]
|
||||
edition = "2021"
|
||||
edition = { workspace = true }
|
||||
autotests = false # using a single test binary compiles faster
|
||||
|
||||
[features]
|
||||
@@ -12,66 +12,64 @@ participation_metrics = [] # Exposes validator participation metrics to Prometh
|
||||
fork_from_env = [] # Initialise the harness chain spec from the FORK_NAME env variable
|
||||
|
||||
[dev-dependencies]
|
||||
maplit = "1.0.2"
|
||||
environment = { path = "../../lighthouse/environment" }
|
||||
serde_json = "1.0.58"
|
||||
maplit = { workspace = true }
|
||||
environment = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
serde_json = "1.0.58"
|
||||
eth2_network_config = { path = "../../common/eth2_network_config"}
|
||||
merkle_proof = { path = "../../consensus/merkle_proof" }
|
||||
store = { path = "../store" }
|
||||
parking_lot = "0.12.0"
|
||||
lazy_static = "1.4.0"
|
||||
smallvec = "1.6.1"
|
||||
lighthouse_metrics = { path = "../../common/lighthouse_metrics" }
|
||||
operation_pool = { path = "../operation_pool" }
|
||||
rayon = "1.4.1"
|
||||
serde = "1.0.116"
|
||||
serde_derive = "1.0.116"
|
||||
ethereum_serde_utils = "0.5.0"
|
||||
slog = { version = "2.5.2", features = ["max_level_trace"] }
|
||||
sloggers = { version = "2.1.1", features = ["json"] }
|
||||
slot_clock = { path = "../../common/slot_clock" }
|
||||
ethereum_hashing = "1.0.0-beta.2"
|
||||
ethereum_ssz = "0.5.0"
|
||||
ssz_types = "0.5.4"
|
||||
ethereum_ssz_derive = "0.5.3"
|
||||
state_processing = { path = "../../consensus/state_processing" }
|
||||
tree_hash_derive = "0.5.0"
|
||||
tree_hash = "0.5.2"
|
||||
types = { path = "../../consensus/types" }
|
||||
tokio = "1.14.0"
|
||||
tokio-stream = "0.1.3"
|
||||
eth1 = { path = "../eth1" }
|
||||
futures = "0.3.7"
|
||||
genesis = { path = "../genesis" }
|
||||
int_to_bytes = { path = "../../consensus/int_to_bytes" }
|
||||
rand = "0.8.5"
|
||||
proto_array = { path = "../../consensus/proto_array" }
|
||||
lru = "0.7.1"
|
||||
tempfile = "3.1.0"
|
||||
bitvec = "0.20.4"
|
||||
bls = { path = "../../crypto/bls" }
|
||||
kzg = { path = "../../crypto/kzg" }
|
||||
safe_arith = { path = "../../consensus/safe_arith" }
|
||||
fork_choice = { path = "../../consensus/fork_choice" }
|
||||
task_executor = { path = "../../common/task_executor" }
|
||||
derivative = "2.1.1"
|
||||
itertools = "0.10.0"
|
||||
slasher = { path = "../../slasher" }
|
||||
eth2 = { path = "../../common/eth2" }
|
||||
strum = { version = "0.24.0", features = ["derive"] }
|
||||
logging = { path = "../../common/logging" }
|
||||
execution_layer = { path = "../execution_layer" }
|
||||
sensitive_url = { path = "../../common/sensitive_url" }
|
||||
superstruct = "0.5.0"
|
||||
hex = "0.4.2"
|
||||
exit-future = "0.2.0"
|
||||
unused_port = {path = "../../common/unused_port"}
|
||||
oneshot_broadcast = { path = "../../common/oneshot_broadcast" }
|
||||
slog-term = "2.6.0"
|
||||
slog-async = "2.5.0"
|
||||
serde_json = { workspace = true }
|
||||
eth2_network_config = { workspace = true }
|
||||
merkle_proof = { workspace = true }
|
||||
store = { workspace = true }
|
||||
parking_lot = { workspace = true }
|
||||
lazy_static = { workspace = true }
|
||||
smallvec = { workspace = true }
|
||||
lighthouse_metrics = { workspace = true }
|
||||
operation_pool = { workspace = true }
|
||||
rayon = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
ethereum_serde_utils = { workspace = true }
|
||||
slog = { workspace = true }
|
||||
sloggers = { workspace = true }
|
||||
slot_clock = { workspace = true }
|
||||
ethereum_hashing = { workspace = true }
|
||||
ethereum_ssz = { workspace = true }
|
||||
ssz_types = { workspace = true }
|
||||
ethereum_ssz_derive = { workspace = true }
|
||||
state_processing = { workspace = true }
|
||||
tree_hash_derive = { workspace = true }
|
||||
tree_hash = { workspace = true }
|
||||
types = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
tokio-stream = { workspace = true }
|
||||
eth1 = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
genesis = { workspace = true }
|
||||
int_to_bytes = { workspace = true }
|
||||
rand = { workspace = true }
|
||||
proto_array = { workspace = true }
|
||||
lru = { workspace = true }
|
||||
tempfile = { workspace = true }
|
||||
bitvec = { workspace = true }
|
||||
bls = { workspace = true }
|
||||
kzg = { workspace = true }
|
||||
safe_arith = { workspace = true }
|
||||
fork_choice = { workspace = true }
|
||||
task_executor = { workspace = true }
|
||||
derivative = { workspace = true }
|
||||
itertools = { workspace = true }
|
||||
slasher = { workspace = true }
|
||||
eth2 = { workspace = true }
|
||||
strum = { workspace = true }
|
||||
logging = { workspace = true }
|
||||
execution_layer = { workspace = true }
|
||||
sensitive_url = { workspace = true }
|
||||
superstruct = { workspace = true }
|
||||
hex = { workspace = true }
|
||||
exit-future = { workspace = true }
|
||||
oneshot_broadcast = { path = "../../common/oneshot_broadcast/" }
|
||||
slog-term = { workspace = true }
|
||||
slog-async = { workspace = true }
|
||||
|
||||
[[test]]
|
||||
name = "beacon_chain_tests"
|
||||
|
||||
@@ -874,10 +874,10 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
///
|
||||
/// May return a database error.
|
||||
pub fn state_root_at_slot(&self, request_slot: Slot) -> Result<Option<Hash256>, Error> {
|
||||
if request_slot > self.slot()? {
|
||||
return Ok(None);
|
||||
} else if request_slot == self.spec.genesis_slot {
|
||||
if request_slot == self.spec.genesis_slot {
|
||||
return Ok(Some(self.genesis_state_root));
|
||||
} else if request_slot > self.slot()? {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
// Check limits w.r.t historic state bounds.
|
||||
@@ -954,10 +954,10 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
///
|
||||
/// May return a database error.
|
||||
fn block_root_at_slot_skips_none(&self, request_slot: Slot) -> Result<Option<Hash256>, Error> {
|
||||
if request_slot > self.slot()? {
|
||||
return Ok(None);
|
||||
} else if request_slot == self.spec.genesis_slot {
|
||||
if request_slot == self.spec.genesis_slot {
|
||||
return Ok(Some(self.genesis_block_root));
|
||||
} else if request_slot > self.slot()? {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let prev_slot = request_slot.saturating_sub(1_u64);
|
||||
@@ -1017,10 +1017,10 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
///
|
||||
/// May return a database error.
|
||||
fn block_root_at_slot_skips_prev(&self, request_slot: Slot) -> Result<Option<Hash256>, Error> {
|
||||
if request_slot > self.slot()? {
|
||||
return Ok(None);
|
||||
} else if request_slot == self.spec.genesis_slot {
|
||||
if request_slot == self.spec.genesis_slot {
|
||||
return Ok(Some(self.genesis_block_root));
|
||||
} else if request_slot > self.slot()? {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
// Try an optimized path of reading the root directly from the head state.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use serde_derive::Serialize;
|
||||
use serde::Serialize;
|
||||
use std::sync::Arc;
|
||||
use types::{
|
||||
beacon_state::CloneConfig, AbstractExecPayload, BeaconState, EthSpec, FullPayload, Hash256,
|
||||
|
||||
@@ -811,11 +811,8 @@ impl<T: BeaconChainTypes> GossipVerifiedBlock<T> {
|
||||
// reboot if the `observed_block_producers` cache is empty. In that case, without this
|
||||
// check, we will load the parent and state from disk only to find out later that we
|
||||
// already know this block.
|
||||
if chain
|
||||
.canonical_head
|
||||
.fork_choice_read_lock()
|
||||
.contains_block(&block_root)
|
||||
{
|
||||
let fork_choice_read_lock = chain.canonical_head.fork_choice_read_lock();
|
||||
if fork_choice_read_lock.contains_block(&block_root) {
|
||||
return Err(BlockError::BlockIsAlreadyKnown);
|
||||
}
|
||||
|
||||
@@ -824,9 +821,10 @@ impl<T: BeaconChainTypes> GossipVerifiedBlock<T> {
|
||||
// We check this *before* we load the parent so that we can return a more detailed error.
|
||||
let block = check_block_is_finalized_checkpoint_or_descendant(
|
||||
chain,
|
||||
&chain.canonical_head.fork_choice_read_lock(),
|
||||
&fork_choice_read_lock,
|
||||
block,
|
||||
)?;
|
||||
drop(fork_choice_read_lock);
|
||||
|
||||
let block_epoch = block.slot().epoch(T::EthSpec::slots_per_epoch());
|
||||
let (parent_block, block) = verify_parent_block_is_known(chain, block)?;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
pub use proto_array::{DisallowedReOrgOffsets, ReOrgThreshold};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
use types::{Checkpoint, Epoch, ProgressiveBalancesMode};
|
||||
|
||||
|
||||
@@ -149,6 +149,8 @@ pub enum BeaconChainError {
|
||||
BlockVariantLacksExecutionPayload(Hash256),
|
||||
ExecutionLayerErrorPayloadReconstruction(ExecutionBlockHash, Box<execution_layer::Error>),
|
||||
EngineGetCapabilititesFailed(Box<execution_layer::Error>),
|
||||
ExecutionLayerGetBlockByNumberFailed(Box<execution_layer::Error>),
|
||||
ExecutionLayerGetBlockByHashFailed(Box<execution_layer::Error>),
|
||||
BlockHashMissingFromExecutionLayer(ExecutionBlockHash),
|
||||
InconsistentPayloadReconstructed {
|
||||
slot: Slot,
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
//! Provides tools for checking if a node is ready for the Bellatrix upgrade and following merge
|
||||
//! transition.
|
||||
|
||||
use crate::{BeaconChain, BeaconChainTypes};
|
||||
use crate::{BeaconChain, BeaconChainError as Error, BeaconChainTypes};
|
||||
use execution_layer::BlockByNumberQuery;
|
||||
use serde::{Deserialize, Serialize, Serializer};
|
||||
use slog::debug;
|
||||
use std::fmt;
|
||||
use std::fmt::Write;
|
||||
use types::*;
|
||||
@@ -120,6 +122,25 @@ impl fmt::Display for MergeReadiness {
|
||||
}
|
||||
}
|
||||
|
||||
pub enum GenesisExecutionPayloadStatus {
|
||||
Correct(ExecutionBlockHash),
|
||||
BlockHashMismatch {
|
||||
got: ExecutionBlockHash,
|
||||
expected: ExecutionBlockHash,
|
||||
},
|
||||
TransactionsRootMismatch {
|
||||
got: Hash256,
|
||||
expected: Hash256,
|
||||
},
|
||||
WithdrawalsRootMismatch {
|
||||
got: Hash256,
|
||||
expected: Hash256,
|
||||
},
|
||||
OtherMismatch,
|
||||
Irrelevant,
|
||||
AlreadyHappened,
|
||||
}
|
||||
|
||||
impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
/// Returns `true` if user has an EL configured, or if the Bellatrix fork has occurred or will
|
||||
/// occur within `MERGE_READINESS_PREPARATION_SECONDS`.
|
||||
@@ -144,9 +165,9 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
}
|
||||
|
||||
/// Attempts to connect to the EL and confirm that it is ready for the merge.
|
||||
pub async fn check_merge_readiness(&self) -> MergeReadiness {
|
||||
pub async fn check_merge_readiness(&self, current_slot: Slot) -> MergeReadiness {
|
||||
if let Some(el) = self.execution_layer.as_ref() {
|
||||
if !el.is_synced_for_notifier().await {
|
||||
if !el.is_synced_for_notifier(current_slot).await {
|
||||
// The EL is not synced.
|
||||
return MergeReadiness::NotSynced;
|
||||
}
|
||||
@@ -161,6 +182,91 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
MergeReadiness::NoExecutionEndpoint
|
||||
}
|
||||
}
|
||||
|
||||
/// Check that the execution payload embedded in the genesis state matches the EL's genesis
|
||||
/// block.
|
||||
pub async fn check_genesis_execution_payload_is_correct(
|
||||
&self,
|
||||
) -> Result<GenesisExecutionPayloadStatus, Error> {
|
||||
let head_snapshot = self.head_snapshot();
|
||||
let genesis_state = &head_snapshot.beacon_state;
|
||||
|
||||
if genesis_state.slot() != 0 {
|
||||
return Ok(GenesisExecutionPayloadStatus::AlreadyHappened);
|
||||
}
|
||||
|
||||
let Ok(latest_execution_payload_header) = genesis_state.latest_execution_payload_header()
|
||||
else {
|
||||
return Ok(GenesisExecutionPayloadStatus::Irrelevant);
|
||||
};
|
||||
let fork = self.spec.fork_name_at_epoch(Epoch::new(0));
|
||||
|
||||
let execution_layer = self
|
||||
.execution_layer
|
||||
.as_ref()
|
||||
.ok_or(Error::ExecutionLayerMissing)?;
|
||||
let exec_block_hash = latest_execution_payload_header.block_hash();
|
||||
|
||||
// Use getBlockByNumber(0) to check that the block hash matches.
|
||||
// At present, Geth does not respond to engine_getPayloadBodiesByRange before genesis.
|
||||
let execution_block = execution_layer
|
||||
.get_block_by_number(BlockByNumberQuery::Tag("0x0"))
|
||||
.await
|
||||
.map_err(|e| Error::ExecutionLayerGetBlockByNumberFailed(Box::new(e)))?
|
||||
.ok_or(Error::BlockHashMissingFromExecutionLayer(exec_block_hash))?;
|
||||
|
||||
if execution_block.block_hash != exec_block_hash {
|
||||
return Ok(GenesisExecutionPayloadStatus::BlockHashMismatch {
|
||||
got: execution_block.block_hash,
|
||||
expected: exec_block_hash,
|
||||
});
|
||||
}
|
||||
|
||||
// Double-check the block by reconstructing it.
|
||||
let execution_payload = execution_layer
|
||||
.get_payload_by_hash_legacy(exec_block_hash, fork)
|
||||
.await
|
||||
.map_err(|e| Error::ExecutionLayerGetBlockByHashFailed(Box::new(e)))?
|
||||
.ok_or(Error::BlockHashMissingFromExecutionLayer(exec_block_hash))?;
|
||||
|
||||
// Verify payload integrity.
|
||||
let header_from_payload = ExecutionPayloadHeader::from(execution_payload.to_ref());
|
||||
|
||||
let got_transactions_root = header_from_payload.transactions_root();
|
||||
let expected_transactions_root = latest_execution_payload_header.transactions_root();
|
||||
let got_withdrawals_root = header_from_payload.withdrawals_root().ok();
|
||||
let expected_withdrawals_root = latest_execution_payload_header.withdrawals_root().ok();
|
||||
|
||||
if got_transactions_root != expected_transactions_root {
|
||||
return Ok(GenesisExecutionPayloadStatus::TransactionsRootMismatch {
|
||||
got: got_transactions_root,
|
||||
expected: expected_transactions_root,
|
||||
});
|
||||
}
|
||||
|
||||
if let Some(&expected) = expected_withdrawals_root {
|
||||
if let Some(&got) = got_withdrawals_root {
|
||||
if got != expected {
|
||||
return Ok(GenesisExecutionPayloadStatus::WithdrawalsRootMismatch {
|
||||
got,
|
||||
expected,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if header_from_payload.to_ref() != latest_execution_payload_header {
|
||||
debug!(
|
||||
self.log,
|
||||
"Genesis execution payload reconstruction failure";
|
||||
"consensus_node_header" => ?latest_execution_payload_header,
|
||||
"execution_node_header" => ?header_from_payload
|
||||
);
|
||||
return Ok(GenesisExecutionPayloadStatus::OtherMismatch);
|
||||
}
|
||||
|
||||
Ok(GenesisExecutionPayloadStatus::Correct(exec_block_hash))
|
||||
}
|
||||
}
|
||||
|
||||
/// Utility function to serialize a Uint256 as a decimal string.
|
||||
|
||||
@@ -20,8 +20,8 @@ use execution_layer::test_utils::generate_genesis_header;
|
||||
use execution_layer::{
|
||||
auth::JwtKey,
|
||||
test_utils::{
|
||||
ExecutionBlockGenerator, MockExecutionLayer, TestingBuilder, DEFAULT_JWT_SECRET,
|
||||
DEFAULT_TERMINAL_BLOCK,
|
||||
ExecutionBlockGenerator, MockBuilder, MockBuilderServer, MockExecutionLayer,
|
||||
DEFAULT_JWT_SECRET, DEFAULT_TERMINAL_BLOCK,
|
||||
},
|
||||
ExecutionLayer,
|
||||
};
|
||||
@@ -175,7 +175,6 @@ pub struct Builder<T: BeaconChainTypes> {
|
||||
store_mutator: Option<BoxedMutator<T::EthSpec, T::HotStore, T::ColdStore>>,
|
||||
execution_layer: Option<ExecutionLayer<T::EthSpec>>,
|
||||
mock_execution_layer: Option<MockExecutionLayer<T::EthSpec>>,
|
||||
mock_builder: Option<TestingBuilder<T::EthSpec>>,
|
||||
testing_slot_clock: Option<TestingSlotClock>,
|
||||
runtime: TestRuntime,
|
||||
log: Logger,
|
||||
@@ -311,7 +310,6 @@ where
|
||||
store_mutator: None,
|
||||
execution_layer: None,
|
||||
mock_execution_layer: None,
|
||||
mock_builder: None,
|
||||
testing_slot_clock: None,
|
||||
runtime,
|
||||
log,
|
||||
@@ -451,50 +449,21 @@ where
|
||||
self
|
||||
}
|
||||
|
||||
pub fn mock_execution_layer(mut self) -> Self {
|
||||
pub fn mock_execution_layer(self) -> Self {
|
||||
self.mock_execution_layer_with_config()
|
||||
}
|
||||
|
||||
pub fn mock_execution_layer_with_config(mut self) -> Self {
|
||||
let mock = mock_execution_layer_from_parts::<E>(
|
||||
self.spec.as_ref().expect("cannot build without spec"),
|
||||
self.runtime.task_executor.clone(),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
self.execution_layer = Some(mock.el.clone());
|
||||
self.mock_execution_layer = Some(mock);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn mock_execution_layer_with_builder(
|
||||
mut self,
|
||||
beacon_url: SensitiveUrl,
|
||||
builder_threshold: Option<u128>,
|
||||
) -> Self {
|
||||
// Get a random unused port
|
||||
let port = unused_port::unused_tcp4_port().unwrap();
|
||||
let builder_url = SensitiveUrl::parse(format!("http://127.0.0.1:{port}").as_str()).unwrap();
|
||||
let spec = self.spec.as_ref().expect("cannot build without spec");
|
||||
let mock_el = mock_execution_layer_from_parts::<E>(
|
||||
spec,
|
||||
self.runtime.task_executor.clone(),
|
||||
Some(builder_url.clone()),
|
||||
builder_threshold,
|
||||
)
|
||||
.move_to_terminal_block();
|
||||
|
||||
let mock_el_url = SensitiveUrl::parse(mock_el.server.url().as_str()).unwrap();
|
||||
|
||||
self.mock_builder = Some(TestingBuilder::new(
|
||||
mock_el_url,
|
||||
builder_url,
|
||||
beacon_url,
|
||||
spec.clone(),
|
||||
self.runtime.task_executor.clone(),
|
||||
));
|
||||
self.execution_layer = Some(mock_el.el.clone());
|
||||
self.mock_execution_layer = Some(mock_el);
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
/// Instruct the mock execution engine to always return a "valid" response to any payload it is
|
||||
/// asked to execute.
|
||||
pub fn mock_execution_layer_all_payloads_valid(self) -> Self {
|
||||
@@ -581,7 +550,7 @@ where
|
||||
shutdown_receiver: Arc::new(Mutex::new(shutdown_receiver)),
|
||||
runtime: self.runtime,
|
||||
mock_execution_layer: self.mock_execution_layer,
|
||||
mock_builder: self.mock_builder.map(Arc::new),
|
||||
mock_builder: None,
|
||||
blob_signature_cache: <_>::default(),
|
||||
rng: make_rng(),
|
||||
}
|
||||
@@ -591,7 +560,6 @@ where
|
||||
pub fn mock_execution_layer_from_parts<T: EthSpec>(
|
||||
spec: &ChainSpec,
|
||||
task_executor: TaskExecutor,
|
||||
builder_url: Option<SensitiveUrl>,
|
||||
builder_threshold: Option<u128>,
|
||||
) -> MockExecutionLayer<T> {
|
||||
let shanghai_time = spec.capella_fork_epoch.map(|epoch| {
|
||||
@@ -615,7 +583,6 @@ pub fn mock_execution_layer_from_parts<T: EthSpec>(
|
||||
builder_threshold,
|
||||
Some(JwtKey::from_slice(&DEFAULT_JWT_SECRET).unwrap()),
|
||||
spec.clone(),
|
||||
builder_url,
|
||||
Some(kzg),
|
||||
)
|
||||
}
|
||||
@@ -639,7 +606,7 @@ pub struct BeaconChainHarness<T: BeaconChainTypes> {
|
||||
pub runtime: TestRuntime,
|
||||
|
||||
pub mock_execution_layer: Option<MockExecutionLayer<T::EthSpec>>,
|
||||
pub mock_builder: Option<Arc<TestingBuilder<T::EthSpec>>>,
|
||||
pub mock_builder: Option<Arc<MockBuilder<T::EthSpec>>>,
|
||||
|
||||
/// Cache for blob signature because we don't need them for import, but we do need them
|
||||
/// to test gossip validation. We always make them during block production but drop them
|
||||
@@ -695,6 +662,49 @@ where
|
||||
.execution_block_generator()
|
||||
}
|
||||
|
||||
pub fn set_mock_builder(&mut self, beacon_url: SensitiveUrl) -> MockBuilderServer {
|
||||
let mock_el = self
|
||||
.mock_execution_layer
|
||||
.as_ref()
|
||||
.expect("harness was not built with mock execution layer");
|
||||
|
||||
let mock_el_url = SensitiveUrl::parse(mock_el.server.url().as_str()).unwrap();
|
||||
|
||||
// Create the builder, listening on a free port.
|
||||
let (mock_builder, mock_builder_server) = MockBuilder::new_for_testing(
|
||||
mock_el_url,
|
||||
beacon_url,
|
||||
self.spec.clone(),
|
||||
self.runtime.task_executor.clone(),
|
||||
);
|
||||
|
||||
// Set the builder URL in the execution layer now that its port is known.
|
||||
let builder_listen_addr = mock_builder_server.local_addr();
|
||||
let port = builder_listen_addr.port();
|
||||
mock_el
|
||||
.el
|
||||
.set_builder_url(
|
||||
SensitiveUrl::parse(format!("http://127.0.0.1:{port}").as_str()).unwrap(),
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
self.mock_builder = Some(Arc::new(mock_builder));
|
||||
|
||||
// Sanity check.
|
||||
let el_builder = self
|
||||
.chain
|
||||
.execution_layer
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.builder()
|
||||
.unwrap();
|
||||
let mock_el_builder = mock_el.el.builder().unwrap();
|
||||
assert!(Arc::ptr_eq(&el_builder, &mock_el_builder));
|
||||
|
||||
mock_builder_server
|
||||
}
|
||||
|
||||
pub fn get_head_block(&self) -> RpcBlock<E> {
|
||||
let block = self.chain.head_beacon_block();
|
||||
let block_root = block.canonical_root();
|
||||
|
||||
Reference in New Issue
Block a user