Skip to content

Commit bc86dc0

Browse files
authored
Reduce number of blobs used in tests to speed up CI (#8194)
`beacon-chain-tests` is now regularly taking 1h+ on CI since Fulu fork was added. This PR attemtpts to reduce the test time by bringing down the number of blobs generated in tests - instead of generating 0..max_blobs, the generator now generates 0..1 blobs by default, and this can be modified by setting `harness.execution_block_generator.set_min_blob_count(n)`. Note: The blobs are pre-generated and doesn't require too much CPU to generate however processing a larger number of them on the beacon chain does take a lot of time. This PR also include a few other small improvements - Our slowest test (`chain_segment_varying_chunk_size`) runs 3x faster in Fulu just by reusing chain segments - Avoid re-running fork specific tests on all forks - Fix a bunch of tests that depends on the harness's existing random blob generation, which is fragile beacon chain test time on test machine is **~2x** faster: ### `unstable` ``` Summary [ 751.586s] 291 tests run: 291 passed (13 slow), 0 skipped ``` ### this branch ``` Summary [ 373.792s] 291 tests run: 291 passed (2 slow), 0 skipped ``` The next set of tests to optimise is the ones that use [`get_chain_segment`](https://github.com/sigp/lighthouse/blob/77a9af96de0f693127055e381ece3e98dceea0a8/beacon_node/beacon_chain/tests/block_verification.rs#L45), as it by default build 320 blocks with supernode - an easy optimisation would be to build these blocks with cgc = 8 for tests that only require fullnodes. Co-Authored-By: Jimmy Chen <[email protected]> Co-Authored-By: Jimmy Chen <[email protected]>
1 parent 2c9b670 commit bc86dc0

File tree

17 files changed

+171
-172
lines changed

17 files changed

+171
-172
lines changed

beacon_node/beacon_chain/src/data_availability_checker/overflow_lru_cache.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1279,7 +1279,7 @@ mod pending_components_tests {
12791279
let mut rng = StdRng::seed_from_u64(0xDEADBEEF0BAD5EEDu64);
12801280
let spec = test_spec::<E>();
12811281
let (block, blobs_vec) =
1282-
generate_rand_block_and_blobs::<E>(ForkName::Deneb, NumBlobs::Random, &mut rng, &spec);
1282+
generate_rand_block_and_blobs::<E>(ForkName::Deneb, NumBlobs::Random, &mut rng);
12831283
let max_len = spec.max_blobs_per_block(block.epoch()) as usize;
12841284
let mut blobs: RuntimeFixedVector<Option<Arc<BlobSidecar<E>>>> =
12851285
RuntimeFixedVector::default(max_len);

beacon_node/beacon_chain/src/kzg_utils.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -468,7 +468,7 @@ mod test {
468468

469469
#[track_caller]
470470
fn test_validate_data_columns(kzg: &Kzg, spec: &ChainSpec) {
471-
let num_of_blobs = 6;
471+
let num_of_blobs = 2;
472472
let (signed_block, blobs, proofs) =
473473
create_test_fulu_block_and_blobs::<E>(num_of_blobs, spec);
474474
let blob_refs = blobs.iter().collect::<Vec<_>>();
@@ -494,7 +494,8 @@ mod test {
494494

495495
#[track_caller]
496496
fn test_build_data_columns(kzg: &Kzg, spec: &ChainSpec) {
497-
let num_of_blobs = 6;
497+
// Using at least 2 blobs to make sure we're arranging the data columns correctly.
498+
let num_of_blobs = 2;
498499
let (signed_block, blobs, proofs) =
499500
create_test_fulu_block_and_blobs::<E>(num_of_blobs, spec);
500501

@@ -534,6 +535,7 @@ mod test {
534535

535536
#[track_caller]
536537
fn test_reconstruct_data_columns(kzg: &Kzg, spec: &ChainSpec) {
538+
// Using at least 2 blobs to make sure we're arranging the data columns correctly.
537539
let num_of_blobs = 2;
538540
let (signed_block, blobs, proofs) =
539541
create_test_fulu_block_and_blobs::<E>(num_of_blobs, spec);
@@ -557,6 +559,7 @@ mod test {
557559

558560
#[track_caller]
559561
fn test_reconstruct_data_columns_unordered(kzg: &Kzg, spec: &ChainSpec) {
562+
// Using at least 2 blobs to make sure we're arranging the data columns correctly.
560563
let num_of_blobs = 2;
561564
let (signed_block, blobs, proofs) =
562565
create_test_fulu_block_and_blobs::<E>(num_of_blobs, spec);
@@ -578,7 +581,7 @@ mod test {
578581

579582
#[track_caller]
580583
fn test_reconstruct_blobs_from_data_columns(kzg: &Kzg, spec: &ChainSpec) {
581-
let num_of_blobs = 6;
584+
let num_of_blobs = 3;
582585
let (signed_block, blobs, proofs) =
583586
create_test_fulu_block_and_blobs::<E>(num_of_blobs, spec);
584587
let blob_refs = blobs.iter().collect::<Vec<_>>();
@@ -588,7 +591,8 @@ mod test {
588591

589592
// Now reconstruct
590593
let signed_blinded_block = signed_block.into();
591-
let blob_indices = vec![3, 4, 5];
594+
// Using at least 2 blobs to make sure we're arranging the data columns correctly.
595+
let blob_indices = vec![1, 2];
592596
let reconstructed_blobs = reconstruct_blobs(
593597
kzg,
594598
&column_sidecars.iter().as_slice()[0..column_sidecars.len() / 2],

beacon_node/beacon_chain/src/test_utils.rs

Lines changed: 44 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ pub const TEST_DATA_COLUMN_SIDECARS_SSZ: &[u8] =
8181
// a different value.
8282
pub const DEFAULT_TARGET_AGGREGATORS: u64 = u64::MAX;
8383

84+
// Minimum and maximum number of blobs to generate in each slot when using the `NumBlobs::Random` option (default).
85+
const DEFAULT_MIN_BLOBS: usize = 1;
86+
const DEFAULT_MAX_BLOBS: usize = 2;
87+
8488
static KZG: LazyLock<Arc<Kzg>> = LazyLock::new(|| {
8589
let kzg = Kzg::new_from_trusted_setup(&get_trusted_setup()).expect("should create kzg");
8690
Arc::new(kzg)
@@ -172,23 +176,28 @@ fn make_rng() -> Mutex<StdRng> {
172176
Mutex::new(StdRng::seed_from_u64(0x0DDB1A5E5BAD5EEDu64))
173177
}
174178

175-
/// Return a `ChainSpec` suitable for test usage.
176-
///
177-
/// If the `fork_from_env` feature is enabled, read the fork to use from the FORK_NAME environment
178-
/// variable. Otherwise use the default spec.
179-
pub fn test_spec<E: EthSpec>() -> ChainSpec {
180-
let mut spec = if cfg!(feature = "fork_from_env") {
179+
pub fn fork_name_from_env() -> Option<ForkName> {
180+
if cfg!(feature = "fork_from_env") {
181181
let fork_name = std::env::var(FORK_NAME_ENV_VAR).unwrap_or_else(|e| {
182182
panic!(
183183
"{} env var must be defined when using fork_from_env: {:?}",
184184
FORK_NAME_ENV_VAR, e
185185
)
186186
});
187-
let fork = ForkName::from_str(fork_name.as_str()).unwrap();
188-
fork.make_genesis_spec(E::default_spec())
187+
Some(ForkName::from_str(fork_name.as_str()).unwrap())
189188
} else {
190-
E::default_spec()
191-
};
189+
None
190+
}
191+
}
192+
193+
/// Return a `ChainSpec` suitable for test usage.
194+
///
195+
/// If the `fork_from_env` feature is enabled, read the fork to use from the FORK_NAME environment
196+
/// variable. Otherwise use the default spec.
197+
pub fn test_spec<E: EthSpec>() -> ChainSpec {
198+
let mut spec = fork_name_from_env()
199+
.map(|fork| fork.make_genesis_spec(E::default_spec()))
200+
.unwrap_or_else(|| E::default_spec());
192201

193202
// Set target aggregators to a high value by default.
194203
spec.target_aggregators_per_committee = DEFAULT_TARGET_AGGREGATORS;
@@ -3245,96 +3254,49 @@ pub enum NumBlobs {
32453254
None,
32463255
}
32473256

3257+
macro_rules! add_blob_transactions {
3258+
($message:expr, $payload_type:ty, $num_blobs:expr, $rng:expr, $fork_name:expr) => {{
3259+
let num_blobs = match $num_blobs {
3260+
NumBlobs::Random => $rng.random_range(DEFAULT_MIN_BLOBS..=DEFAULT_MAX_BLOBS),
3261+
NumBlobs::Number(n) => n,
3262+
NumBlobs::None => 0,
3263+
};
3264+
let (bundle, transactions) =
3265+
execution_layer::test_utils::generate_blobs::<E>(num_blobs, $fork_name).unwrap();
3266+
3267+
let payload: &mut $payload_type = &mut $message.body.execution_payload;
3268+
payload.execution_payload.transactions = <_>::default();
3269+
for tx in Vec::from(transactions) {
3270+
payload.execution_payload.transactions.push(tx).unwrap();
3271+
}
3272+
$message.body.blob_kzg_commitments = bundle.commitments.clone();
3273+
bundle
3274+
}};
3275+
}
3276+
32483277
pub fn generate_rand_block_and_blobs<E: EthSpec>(
32493278
fork_name: ForkName,
32503279
num_blobs: NumBlobs,
32513280
rng: &mut impl Rng,
3252-
spec: &ChainSpec,
32533281
) -> (SignedBeaconBlock<E, FullPayload<E>>, Vec<BlobSidecar<E>>) {
32543282
let inner = map_fork_name!(fork_name, BeaconBlock, <_>::random_for_test(rng));
32553283

32563284
let mut block = SignedBeaconBlock::from_block(inner, types::Signature::random_for_test(rng));
3257-
let max_blobs = spec.max_blobs_per_block(block.epoch()) as usize;
32583285
let mut blob_sidecars = vec![];
32593286

32603287
let bundle = match block {
32613288
SignedBeaconBlock::Deneb(SignedBeaconBlockDeneb {
32623289
ref mut message, ..
3263-
}) => {
3264-
// Get either zero blobs or a random number of blobs between 1 and Max Blobs.
3265-
let payload: &mut FullPayloadDeneb<E> = &mut message.body.execution_payload;
3266-
let num_blobs = match num_blobs {
3267-
NumBlobs::Random => rng.random_range(1..=max_blobs),
3268-
NumBlobs::Number(n) => n,
3269-
NumBlobs::None => 0,
3270-
};
3271-
let (bundle, transactions) =
3272-
execution_layer::test_utils::generate_blobs::<E>(num_blobs, fork_name).unwrap();
3273-
3274-
payload.execution_payload.transactions = <_>::default();
3275-
for tx in Vec::from(transactions) {
3276-
payload.execution_payload.transactions.push(tx).unwrap();
3277-
}
3278-
message.body.blob_kzg_commitments = bundle.commitments.clone();
3279-
bundle
3280-
}
3290+
}) => add_blob_transactions!(message, FullPayloadDeneb<E>, num_blobs, rng, fork_name),
32813291
SignedBeaconBlock::Electra(SignedBeaconBlockElectra {
32823292
ref mut message, ..
3283-
}) => {
3284-
// Get either zero blobs or a random number of blobs between 1 and Max Blobs.
3285-
let payload: &mut FullPayloadElectra<E> = &mut message.body.execution_payload;
3286-
let num_blobs = match num_blobs {
3287-
NumBlobs::Random => rng.random_range(1..=max_blobs),
3288-
NumBlobs::Number(n) => n,
3289-
NumBlobs::None => 0,
3290-
};
3291-
let (bundle, transactions) =
3292-
execution_layer::test_utils::generate_blobs::<E>(num_blobs, fork_name).unwrap();
3293-
payload.execution_payload.transactions = <_>::default();
3294-
for tx in Vec::from(transactions) {
3295-
payload.execution_payload.transactions.push(tx).unwrap();
3296-
}
3297-
message.body.blob_kzg_commitments = bundle.commitments.clone();
3298-
bundle
3299-
}
3293+
}) => add_blob_transactions!(message, FullPayloadElectra<E>, num_blobs, rng, fork_name),
33003294
SignedBeaconBlock::Fulu(SignedBeaconBlockFulu {
33013295
ref mut message, ..
3302-
}) => {
3303-
// Get either zero blobs or a random number of blobs between 1 and Max Blobs.
3304-
let payload: &mut FullPayloadFulu<E> = &mut message.body.execution_payload;
3305-
let num_blobs = match num_blobs {
3306-
NumBlobs::Random => rng.random_range(1..=max_blobs),
3307-
NumBlobs::Number(n) => n,
3308-
NumBlobs::None => 0,
3309-
};
3310-
let (bundle, transactions) =
3311-
execution_layer::test_utils::generate_blobs::<E>(num_blobs, fork_name).unwrap();
3312-
payload.execution_payload.transactions = <_>::default();
3313-
for tx in Vec::from(transactions) {
3314-
payload.execution_payload.transactions.push(tx).unwrap();
3315-
}
3316-
message.body.blob_kzg_commitments = bundle.commitments.clone();
3317-
bundle
3318-
}
3296+
}) => add_blob_transactions!(message, FullPayloadFulu<E>, num_blobs, rng, fork_name),
33193297
SignedBeaconBlock::Gloas(SignedBeaconBlockGloas {
33203298
ref mut message, ..
3321-
}) => {
3322-
// Get either zero blobs or a random number of blobs between 1 and Max Blobs.
3323-
let payload: &mut FullPayloadGloas<E> = &mut message.body.execution_payload;
3324-
let num_blobs = match num_blobs {
3325-
NumBlobs::Random => rng.random_range(1..=max_blobs),
3326-
NumBlobs::Number(n) => n,
3327-
NumBlobs::None => 0,
3328-
};
3329-
let (bundle, transactions) =
3330-
execution_layer::test_utils::generate_blobs::<E>(num_blobs, fork_name).unwrap();
3331-
payload.execution_payload.transactions = <_>::default();
3332-
for tx in Vec::from(transactions) {
3333-
payload.execution_payload.transactions.push(tx).unwrap();
3334-
}
3335-
message.body.blob_kzg_commitments = bundle.commitments.clone();
3336-
bundle
3337-
}
3299+
}) => add_blob_transactions!(message, FullPayloadGloas<E>, num_blobs, rng, fork_name),
33383300
_ => return (block, blob_sidecars),
33393301
};
33403302

@@ -3375,7 +3337,7 @@ pub fn generate_rand_block_and_data_columns<E: EthSpec>(
33753337
SignedBeaconBlock<E, FullPayload<E>>,
33763338
DataColumnSidecarList<E>,
33773339
) {
3378-
let (block, _blobs) = generate_rand_block_and_blobs(fork_name, num_blobs, rng, spec);
3340+
let (block, _blobs) = generate_rand_block_and_blobs(fork_name, num_blobs, rng);
33793341
let data_columns = generate_data_column_sidecars_from_block(&block, spec);
33803342
(block, data_columns)
33813343
}

beacon_node/beacon_chain/tests/block_verification.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -297,19 +297,20 @@ async fn chain_segment_full_segment() {
297297

298298
#[tokio::test]
299299
async fn chain_segment_varying_chunk_size() {
300-
for chunk_size in &[1, 2, 3, 5, 31, 32, 33, 42] {
300+
let (chain_segment, chain_segment_blobs) = get_chain_segment().await;
301+
let blocks: Vec<RpcBlock<E>> = chain_segment_blocks(&chain_segment, &chain_segment_blobs)
302+
.into_iter()
303+
.collect();
304+
305+
for chunk_size in &[1, 2, 31, 32, 33] {
301306
let harness = get_harness(VALIDATOR_COUNT, NodeCustodyType::Fullnode);
302-
let (chain_segment, chain_segment_blobs) = get_chain_segment().await;
303-
let blocks: Vec<RpcBlock<E>> = chain_segment_blocks(&chain_segment, &chain_segment_blobs)
304-
.into_iter()
305-
.collect();
306307

307308
harness
308309
.chain
309310
.slot_clock
310311
.set_slot(blocks.last().unwrap().slot().as_u64());
311312

312-
for chunk in blocks.chunks(*chunk_size) {
313+
for chunk in blocks.clone().chunks(*chunk_size) {
313314
harness
314315
.chain
315316
.process_chain_segment(chunk.to_vec(), NotifyExecutionLayer::Yes)

beacon_node/beacon_chain/tests/events.rs

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,26 @@
11
use beacon_chain::blob_verification::GossipVerifiedBlob;
22
use beacon_chain::data_column_verification::GossipVerifiedDataColumn;
3-
use beacon_chain::test_utils::{BeaconChainHarness, generate_data_column_sidecars_from_block};
3+
use beacon_chain::test_utils::{
4+
BeaconChainHarness, fork_name_from_env, generate_data_column_sidecars_from_block, test_spec,
5+
};
46
use eth2::types::{EventKind, SseBlobSidecar, SseDataColumnSidecar};
57
use rand::SeedableRng;
68
use rand::rngs::StdRng;
79
use std::sync::Arc;
810
use types::blob_sidecar::FixedBlobSidecarList;
911
use types::test_utils::TestRandom;
10-
use types::{BlobSidecar, DataColumnSidecar, EthSpec, ForkName, MinimalEthSpec, Slot};
12+
use types::{BlobSidecar, DataColumnSidecar, EthSpec, MinimalEthSpec, Slot};
1113

1214
type E = MinimalEthSpec;
1315

1416
/// Verifies that a blob event is emitted when a gossip verified blob is received via gossip or the publish block API.
1517
#[tokio::test]
1618
async fn blob_sidecar_event_on_process_gossip_blob() {
17-
let spec = Arc::new(ForkName::Deneb.make_genesis_spec(E::default_spec()));
19+
if fork_name_from_env().is_some_and(|f| !f.deneb_enabled() || f.fulu_enabled()) {
20+
return;
21+
};
22+
23+
let spec = Arc::new(test_spec::<E>());
1824
let harness = BeaconChainHarness::builder(E::default())
1925
.spec(spec)
2026
.deterministic_keypairs(8)
@@ -48,7 +54,11 @@ async fn blob_sidecar_event_on_process_gossip_blob() {
4854
/// Verifies that a data column event is emitted when a gossip verified data column is received via gossip or the publish block API.
4955
#[tokio::test]
5056
async fn data_column_sidecar_event_on_process_gossip_data_column() {
51-
let spec = Arc::new(ForkName::Fulu.make_genesis_spec(E::default_spec()));
57+
if fork_name_from_env().is_some_and(|f| !f.fulu_enabled()) {
58+
return;
59+
};
60+
61+
let spec = Arc::new(test_spec::<E>());
5262
let harness = BeaconChainHarness::builder(E::default())
5363
.spec(spec)
5464
.deterministic_keypairs(8)
@@ -93,7 +103,11 @@ async fn data_column_sidecar_event_on_process_gossip_data_column() {
93103
/// Verifies that a blob event is emitted when blobs are received via RPC.
94104
#[tokio::test]
95105
async fn blob_sidecar_event_on_process_rpc_blobs() {
96-
let spec = Arc::new(ForkName::Deneb.make_genesis_spec(E::default_spec()));
106+
if fork_name_from_env().is_some_and(|f| !f.deneb_enabled() || f.fulu_enabled()) {
107+
return;
108+
};
109+
110+
let spec = Arc::new(test_spec::<E>());
97111
let harness = BeaconChainHarness::builder(E::default())
98112
.spec(spec)
99113
.deterministic_keypairs(8)
@@ -112,7 +126,7 @@ async fn blob_sidecar_event_on_process_rpc_blobs() {
112126
let slot = head_state.slot() + 1;
113127
let ((signed_block, opt_blobs), _) = harness.make_block(head_state, slot).await;
114128
let (kzg_proofs, blobs) = opt_blobs.unwrap();
115-
assert!(blobs.len() > 2);
129+
assert_eq!(blobs.len(), 2);
116130

117131
let blob_1 =
118132
Arc::new(BlobSidecar::new(0, blobs[0].clone(), &signed_block, kzg_proofs[0]).unwrap());
@@ -144,7 +158,11 @@ async fn blob_sidecar_event_on_process_rpc_blobs() {
144158

145159
#[tokio::test]
146160
async fn data_column_sidecar_event_on_process_rpc_columns() {
147-
let spec = Arc::new(ForkName::Fulu.make_genesis_spec(E::default_spec()));
161+
if fork_name_from_env().is_some_and(|f| !f.fulu_enabled()) {
162+
return;
163+
};
164+
165+
let spec = Arc::new(test_spec::<E>());
148166
let harness = BeaconChainHarness::builder(E::default())
149167
.spec(spec.clone())
150168
.deterministic_keypairs(8)

0 commit comments

Comments
 (0)