Skip to content
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
fc465f7
WIP Add more sync tests
dapplion Dec 3, 2025
88a86ff
Add more sync tests
dapplion Dec 4, 2025
6b08ca3
Add blobs and columns
dapplion Dec 5, 2025
0fe9c68
Disable crypto programatically
dapplion Dec 7, 2025
89cab8f
Fix more tests
dapplion Dec 9, 2025
9822b73
Fix bug with mock execution engine
dapplion Dec 12, 2025
3b4ddc6
Fix tests
dapplion Dec 12, 2025
c5b9457
Fix remaining tests
dapplion Dec 13, 2025
fc294a5
Add more fulu tests
dapplion Dec 13, 2025
10aa052
Merge remote-tracking branch 'sigp/unstable' into more-sync-tests
dapplion Dec 13, 2025
013476d
Lint full
dapplion Dec 13, 2025
bee1abd
Enable ignored test
dapplion Dec 13, 2025
d39253a
Allow to reorder event order
dapplion Dec 13, 2025
51a55e4
Tests passing
dapplion Dec 15, 2025
1755dfd
Lint
dapplion Dec 16, 2025
2288a3a
Run phase0 only for network tests
dapplion Dec 16, 2025
d48dcf2
Reduce diff
dapplion Dec 16, 2025
38bdf2d
Reduce diff
dapplion Dec 16, 2025
b6fc8a9
Merge remote-tracking branch 'sigp/unstable' into more-sync-tests
dapplion Dec 16, 2025
73099eb
Use FIFO
dapplion Dec 17, 2025
8234cab
Apply PR review
dapplion Jan 9, 2026
91ade9a
Address PR review comments
dapplion Jan 14, 2026
ff83f43
Use features to disable crypto
dapplion Jan 14, 2026
d2eaf15
Reduce diff
dapplion Jan 14, 2026
fc2b226
Reduce diff
dapplion Jan 14, 2026
24569a3
Fix fake crypto usage
dapplion Jan 15, 2026
9354fa0
Add crypto on test
dapplion Jan 15, 2026
a7a36e3
Fix crypto
dapplion Jan 15, 2026
de20c3e
fmt
dapplion Jan 15, 2026
a12e855
Lint crypto_on
dapplion Jan 15, 2026
768bc07
Complete crypto_on tests
dapplion Jan 15, 2026
6504995
Merge branch 'unstable' into more-sync-tests
dapplion Jan 15, 2026
e141084
lint
dapplion Jan 15, 2026
13277f1
Lint with fake_crypto feature
dapplion Jan 15, 2026
f425f31
Merge remote-tracking branch 'sigp/unstable' into more-sync-tests
dapplion Jan 19, 2026
71bf593
rename CompleteStrategy to SimulateConfig
dapplion Feb 4, 2026
efd2ad2
Merge remote-tracking branch 'sigp/unstable' into more-sync-tests
dapplion Feb 4, 2026
09a6283
adapt tests to new RpcBlock enum API after merge
dapplion Feb 4, 2026
5754769
Merge remote-tracking branch 'sigp/unstable' into more-sync-tests
dapplion Feb 4, 2026
1437165
remove random queue processing from simulate()
dapplion Feb 5, 2026
e4b9b51
remove stale test_same_chain_race_condition
dapplion Feb 5, 2026
c5ed04f
remove unused import
dapplion Feb 5, 2026
6646dc2
remove unused block_imported_while_processing
dapplion Feb 5, 2026
1cf9640
add test for same chain race condition
dapplion Feb 5, 2026
57506c8
fix formatting
dapplion Feb 5, 2026
8d29e73
address review feedback: rename builder method and fix test docs
dapplion Feb 5, 2026
787932d
Merge branch 'unstable' into more-sync-tests
dapplion Feb 10, 2026
765dcae
Merge remote-tracking branch 'sigp/unstable' into more-sync-tests
dapplion Feb 12, 2026
854d6cf
address pr review: rename expect_ to assert_, revert VerifySignatures…
dapplion Feb 12, 2026
415e89e
fix flaky reconstruction_at_deadline test
dapplion Feb 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.

8 changes: 6 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,12 @@ TEST_FEATURES ?=
PROFILE ?= release

# List of all recent hard forks. This list is used to set env variables for http_api tests
# Include phase0 to test the code paths in sync that are pre blobs
RECENT_FORKS=electra fulu gloas

# For network tests include phase0 to cover genesis syncing (blocks without blobs or columns)
TEST_NETWORK_FORKS=phase0 $(RECENT_FORKS)

# Extra flags for Cargo
CARGO_INSTALL_EXTRA_FLAGS?=

Expand Down Expand Up @@ -219,10 +223,10 @@ test-op-pool-%:
-p operation_pool

# Run the tests in the `network` crate for recent forks.
test-network: $(patsubst %,test-network-%,$(RECENT_FORKS))
test-network: $(patsubst %,test-network-%,$(TEST_NETWORK_FORKS))

test-network-%:
env FORK_NAME=$* cargo nextest run --release \
env FORK_NAME=$* cargo nextest run --no-fail-fast --release \
--features "fork_from_env,$(TEST_FEATURES)" \
-p network

Expand Down
1 change: 0 additions & 1 deletion beacon_node/beacon_chain/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

[package]
name = "beacon_chain"
version = "0.2.0"
Expand Down
15 changes: 0 additions & 15 deletions beacon_node/beacon_chain/src/block_verification_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -340,21 +340,6 @@ pub struct BlockImportData<E: EthSpec> {
pub consensus_context: ConsensusContext<E>,
}

impl<E: EthSpec> BlockImportData<E> {
pub fn __new_for_test(
block_root: Hash256,
state: BeaconState<E>,
parent_block: SignedBeaconBlock<E, BlindedPayload<E>>,
) -> Self {
Self {
block_root,
state,
parent_block,
consensus_context: ConsensusContext::new(Slot::new(0)),
}
}
}

/// Trait for common block operations.
pub trait AsBlock<E: EthSpec> {
fn slot(&self) -> Slot;
Expand Down
3 changes: 2 additions & 1 deletion beacon_node/beacon_chain/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -977,7 +977,7 @@ where

let beacon_chain = BeaconChain {
spec: self.spec.clone(),
config: self.chain_config,
config: self.chain_config.clone(),
store: store.clone(),
task_executor: self
.task_executor
Expand Down Expand Up @@ -1051,6 +1051,7 @@ where
self.kzg.clone(),
store,
Arc::new(custody_context),
&self.chain_config.test_config,
self.spec,
)
.map_err(|e| format!("Error initializing DataAvailabilityChecker: {:?}", e))?,
Expand Down
14 changes: 14 additions & 0 deletions beacon_node/beacon_chain/src/chain_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,16 @@ pub struct ChainConfig {
pub disable_get_blobs: bool,
/// The node's custody type, determining how many data columns to custody and sample.
pub node_custody_type: NodeCustodyType,
/// TESTING ONLY: Disable certain functionality to speed up tests
pub test_config: TestConfig,
}

#[derive(Debug, Default, PartialEq, Eq, Clone, Deserialize, Serialize)]
pub struct TestConfig {
/// FOR TESTING ONLY: Disable crypto verification to speed up tests
pub disable_crypto: bool,
/// FOR TESTING ONLY: Disable fetch_blobs optimization
pub disable_fetch_blobs: bool,
}

impl Default for ChainConfig {
Expand Down Expand Up @@ -162,6 +172,10 @@ impl Default for ChainConfig {
invalid_block_roots: HashSet::new(),
disable_get_blobs: false,
node_custody_type: NodeCustodyType::Fullnode,
test_config: TestConfig {
disable_crypto: false,
disable_fetch_blobs: false,
},
}
}
}
Expand Down
27 changes: 18 additions & 9 deletions beacon_node/beacon_chain/src/data_availability_checker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ mod error;
mod overflow_lru_cache;
mod state_lru_cache;

use crate::chain_config::TestConfig;
use crate::data_availability_checker::error::Error;
use crate::data_column_verification::{
CustodyDataColumn, GossipVerifiedDataColumn, KzgVerifiedCustodyDataColumn,
Expand Down Expand Up @@ -86,6 +87,7 @@ pub struct DataAvailabilityChecker<T: BeaconChainTypes> {
kzg: Arc<Kzg>,
custody_context: Arc<CustodyContext<T::EthSpec>>,
spec: Arc<ChainSpec>,
disable_crypto: bool,
}

pub type AvailabilityAndReconstructedColumns<E> = (Availability<E>, DataColumnSidecarList<E>);
Expand Down Expand Up @@ -124,6 +126,7 @@ impl<T: BeaconChainTypes> DataAvailabilityChecker<T> {
kzg: Arc<Kzg>,
store: BeaconStore<T>,
custody_context: Arc<CustodyContext<T::EthSpec>>,
test_config: &TestConfig,
spec: Arc<ChainSpec>,
) -> Result<Self, AvailabilityCheckError> {
let inner = DataAvailabilityCheckerInner::new(
Expand All @@ -139,6 +142,7 @@ impl<T: BeaconChainTypes> DataAvailabilityChecker<T> {
kzg,
custody_context,
spec,
disable_crypto: test_config.disable_crypto,
})
}

Expand Down Expand Up @@ -378,8 +382,10 @@ impl<T: BeaconChainTypes> DataAvailabilityChecker<T> {
let (block_root, block, blobs, data_columns) = block.deconstruct();
if self.blobs_required_for_block(&block) {
return if let Some(blob_list) = blobs {
verify_kzg_for_blob_list(blob_list.iter(), &self.kzg)
.map_err(AvailabilityCheckError::InvalidBlobs)?;
if !self.disable_crypto {
verify_kzg_for_blob_list(blob_list.iter(), &self.kzg)
.map_err(AvailabilityCheckError::InvalidBlobs)?;
}
Ok(MaybeAvailableBlock::Available(AvailableBlock {
block_root,
block,
Expand All @@ -393,13 +399,15 @@ impl<T: BeaconChainTypes> DataAvailabilityChecker<T> {
}
if self.data_columns_required_for_block(&block) {
return if let Some(data_column_list) = data_columns.as_ref() {
verify_kzg_for_data_column_list(
data_column_list
.iter()
.map(|custody_column| custody_column.as_data_column()),
&self.kzg,
)
.map_err(AvailabilityCheckError::InvalidColumn)?;
if !self.disable_crypto {
verify_kzg_for_data_column_list(
data_column_list
.iter()
.map(|custody_column| custody_column.as_data_column()),
&self.kzg,
)
.map_err(AvailabilityCheckError::InvalidColumn)?;
}
Ok(MaybeAvailableBlock::Available(AvailableBlock {
block_root,
block,
Expand Down Expand Up @@ -1195,6 +1203,7 @@ mod test {
kzg,
store,
custody_context,
&TestConfig::default(),
spec,
)
.expect("should initialise data availability checker")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -727,6 +727,8 @@ impl<T: BeaconChainTypes> DataAvailabilityCheckerInner<T> {
pub fn remove_pre_execution_block(&self, block_root: &Hash256) {
// The read lock is immediately dropped so we can safely remove the block from the cache.
if let Some(BlockProcessStatus::NotValidated(_, _)) = self.get_cached_block(block_root) {
// If the block is execution invalid, this status is permanent and idempotent to this
// block_root. We drop its components (e.g. columns) because they will never be useful.
self.critical.write().pop(block_root);
}
}
Expand Down
8 changes: 7 additions & 1 deletion beacon_node/beacon_chain/src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -782,7 +782,13 @@ where
}

pub fn get_full_block(&self, block_root: &Hash256) -> RpcBlock<E> {
let block = self.chain.get_blinded_block(block_root).unwrap().unwrap();
let block = self
.chain
.get_blinded_block(block_root)
.unwrap()
.unwrap_or_else(|| {
panic!("block root does not exist in external harness {block_root:?}")
});
let full_block = self.chain.store.make_full_block(block_root, block).unwrap();
self.build_rpc_block_from_store_blobs(Some(*block_root), Arc::new(full_block))
}
Expand Down
15 changes: 11 additions & 4 deletions beacon_node/beacon_processor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -446,12 +446,15 @@ impl<E: EthSpec> From<ReadyWork> for WorkEvent<E> {
},
},
ReadyWork::RpcBlock(QueuedRpcBlock {
beacon_block_root: _,
beacon_block_root,
process_fn,
ignore_fn: _,
}) => Self {
drop_during_sync: false,
work: Work::RpcBlock { process_fn },
work: Work::RpcBlock {
process_fn,
beacon_block_root,
},
},
ReadyWork::IgnoredRpcBlock(IgnoredRpcBlock { process_fn }) => Self {
drop_during_sync: false,
Expand Down Expand Up @@ -592,6 +595,7 @@ pub enum Work<E: EthSpec> {
GossipLightClientFinalityUpdate(BlockingFn),
GossipLightClientOptimisticUpdate(BlockingFn),
RpcBlock {
beacon_block_root: Hash256,
process_fn: AsyncFn,
},
RpcBlobs {
Expand Down Expand Up @@ -674,7 +678,7 @@ pub enum WorkType {
}

impl<E: EthSpec> Work<E> {
fn str_id(&self) -> &'static str {
pub fn str_id(&self) -> &'static str {
self.to_type().into()
}

Expand Down Expand Up @@ -1592,7 +1596,10 @@ impl<E: EthSpec> BeaconProcessor<E> {
beacon_block_root: _,
process_fn,
} => task_spawner.spawn_async(process_fn),
Work::RpcBlock { process_fn }
Work::RpcBlock {
process_fn,
beacon_block_root: _,
}
| Work::RpcBlobs { process_fn }
| Work::RpcCustodyColumn(process_fn)
| Work::ColumnReconstruction(process_fn) => task_spawner.spawn_async(process_fn),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use ssz_types::VariableList;
use std::cmp::max;
use std::collections::HashMap;
use std::sync::Arc;
use tracing::warn;
use tree_hash::TreeHash;
use tree_hash_derive::TreeHash;
use types::{
Expand Down Expand Up @@ -537,6 +538,21 @@ impl<E: EthSpec> ExecutionBlockGenerator<E> {
.contains_key(&forkchoice_state.finalized_block_hash);

if unknown_head_block_hash || unknown_safe_block_hash || unknown_finalized_block_hash {
if unknown_head_block_hash {
warn!(?head_block_hash, "Received unknown head block hash");
}
if unknown_safe_block_hash {
warn!(
safe_block_hash = ?forkchoice_state.safe_block_hash,
"Received unknown safe block hash"
);
}
if unknown_finalized_block_hash {
warn!(
finalized_block_hash = ?forkchoice_state.finalized_block_hash,
"Received unknown finalized block hash"
)
}
return Ok(JsonForkchoiceUpdatedV1Response {
payload_status: JsonPayloadStatusV1 {
status: JsonPayloadStatusV1Status::Syncing,
Expand Down
11 changes: 11 additions & 0 deletions beacon_node/execution_layer/src/test_utils/handle_rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::test_utils::{DEFAULT_CLIENT_VERSION, DEFAULT_MOCK_EL_PAYLOAD_VALUE_WE
use serde::{Deserialize, de::DeserializeOwned};
use serde_json::Value as JsonValue;
use std::sync::Arc;
use tracing::debug;

pub const GENERIC_ERROR_CODE: i64 = -1234;
pub const BAD_PARAMS_ERROR_CODE: i64 = -32602;
Expand All @@ -28,6 +29,8 @@ pub async fn handle_rpc<E: EthSpec>(
.ok_or_else(|| "missing/invalid params field".to_string())
.map_err(|s| (s, GENERIC_ERROR_CODE))?;

debug!(method, "Mock execution engine");

match method {
ETH_SYNCING => ctx
.syncing_response
Expand Down Expand Up @@ -517,6 +520,12 @@ pub async fn handle_rpc<E: EthSpec>(
_ => unreachable!(),
};

debug!(
?payload_attributes,
?forkchoice_state,
"ENGINE_FORKCHOICE_UPDATED"
);

// validate method called correctly according to fork time
if let Some(pa) = payload_attributes.as_ref() {
match ctx
Expand Down Expand Up @@ -584,13 +593,15 @@ pub async fn handle_rpc<E: EthSpec>(
.lock()
.on_forkchoice_updated(forkchoice_state.clone(), payload_attributes.clone())
{
debug!("Returning hook response");
return Ok(serde_json::to_value(hook_response).unwrap());
}

let head_block_hash = forkchoice_state.head_block_hash;

// Canned responses set by block hash take priority.
if let Some(status) = ctx.get_fcu_payload_status(&head_block_hash) {
debug!(?head_block_hash, "Canned response set by block hash");
return status
.map(|status| {
let response = JsonForkchoiceUpdatedV1Response {
Expand Down
2 changes: 1 addition & 1 deletion beacon_node/lighthouse_network/src/rpc/protocol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -715,7 +715,7 @@ where
}
}

#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone, PartialEq, IntoStaticStr)]
pub enum RequestType<E: EthSpec> {
Status(StatusMessage),
Goodbye(GoodbyeReason),
Expand Down
2 changes: 1 addition & 1 deletion beacon_node/lighthouse_network/src/service/api_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ pub struct CustodyId {
pub struct CustodyRequester(pub SingleLookupReqId);

/// Application level requests sent to the network.
#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum AppRequestId {
Sync(SyncRequestId),
Router,
Expand Down
1 change: 1 addition & 0 deletions beacon_node/network/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ gossipsub = { workspace = true }
k256 = "0.13.4"
kzg = { workspace = true }
matches = "0.1.8"
paste = "1.0.15"
rand_08 = { package = "rand", version = "0.8.5" }
rand_chacha = "0.9.0"
rand_chacha_03 = { package = "rand_chacha", version = "0.3.1" }
Expand Down
5 changes: 4 additions & 1 deletion beacon_node/network/src/network_beacon_processor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,10 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
);
self.try_send(BeaconWorkEvent {
drop_during_sync: false,
work: Work::RpcBlock { process_fn },
work: Work::RpcBlock {
process_fn,
beacon_block_root: block_root,
},
})
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,8 +224,14 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
// derived from kzg commitments from the block, without having to wait for all blobs
// to be sent from the peers if we already have them.
let publish_blobs = false;
self.fetch_engine_blobs_and_publish(signed_beacon_block, block_root, publish_blobs)
.await
if !self.chain.config.test_config.disable_fetch_blobs {
self.fetch_engine_blobs_and_publish(
signed_beacon_block,
block_root,
publish_blobs,
)
.await;
}
}
_ => {}
}
Expand Down
Loading
Loading