mirror of
https://github.com/sigp/lighthouse.git
synced 2026-06-10 09:37:38 +00:00
Optimise slow block verification tests (#9274)
Reduce CI time for `block_verification` tests that exceed 120s on Fulu/Gloas forks. - Cache the chain segment across tests using `LazyLock<OnceCell>` (was rebuilt 10+ times independently) - Reduce chain length from 320 to 192 slots (10 epochs to 6 epochs) - Reduce `BLOCK_INDICES` from 7 to 3 - Reduce `chain_segment_varying_chunk_size` from 5 to 3 AI assisted, self reviewed. Before vs After comparison (1 sample only): * **Before**: 19 tests exceeded the 120s slow threshold. * **After**: zero exceed it. Overall: 1,890s down to 797s (-58%). ``` | Test | Before | After | Change | |------------------------------------------------------|---------|---------|---------| | chain_segment_varying_chunk_size | 239s | 98s | -59% | | invalid_signature_attester_slashing | 175s | 64s | -64% | | invalid_signature_exit | 173s | 62s | -64% | | invalid_signature_deposit | 170s | 60s | -65% | | invalid_signature_attestation | 165s | 62s | -63% | | invalid_signature_proposer_slashing | 161s | 56s | -66% | | block_gossip_verification | 154s | 91s | -41% | | invalid_signature_block_proposal | 151s | 58s | -61% | | invalid_signature_randao_reveal | 149s | 54s | -64% | | invalid_signature_gossip_block | 135s | 46s | -66% | |------------------------------------------------------|---------|---------|---------| | TOTAL | 1890s | 797s | -58% | ``` Co-Authored-By: Jimmy Chen <jchen.tc@gmail.com> Co-Authored-By: Michael Sproul <michaelsproul@users.noreply.github.com>
This commit is contained in:
@@ -35,20 +35,30 @@ type E = MainnetEthSpec;
|
||||
|
||||
// Gloas requires >= 1 validator per slot for PTC committee computation, so >= 32 for MainnetEthSpec.
|
||||
const VALIDATOR_COUNT: usize = 32;
|
||||
const CHAIN_SEGMENT_LENGTH: usize = 64 * 5;
|
||||
const BLOCK_INDICES: &[usize] = &[0, 1, 32, 64, 68 + 1, 129, CHAIN_SEGMENT_LENGTH - 1];
|
||||
const CHAIN_SEGMENT_LENGTH: usize = 32 * 6;
|
||||
const BLOCK_INDICES: &[usize] = &[1, 32, 64];
|
||||
|
||||
/// A cached set of keys.
|
||||
static KEYPAIRS: LazyLock<Vec<Keypair>> =
|
||||
LazyLock::new(|| types::test_utils::generate_deterministic_keypairs(VALIDATOR_COUNT));
|
||||
|
||||
// TODO(#8633): Delete this unnecessary enum and refactor this file to use `AvailableBlockData` instead.
|
||||
#[derive(Clone)]
|
||||
enum DataSidecars<E: EthSpec> {
|
||||
Blobs(BlobSidecarList<E>),
|
||||
DataColumns(Vec<CustodyDataColumn<E>>),
|
||||
}
|
||||
|
||||
async fn get_chain_segment() -> (Vec<BeaconSnapshot<E>>, Vec<Option<DataSidecars<E>>>) {
|
||||
type ChainSegmentData = (Vec<BeaconSnapshot<E>>, Vec<Option<DataSidecars<E>>>);
|
||||
|
||||
static CHAIN_SEGMENT: LazyLock<tokio::sync::OnceCell<ChainSegmentData>> =
|
||||
LazyLock::new(tokio::sync::OnceCell::new);
|
||||
|
||||
async fn get_chain_segment() -> &'static ChainSegmentData {
|
||||
CHAIN_SEGMENT.get_or_init(build_chain_segment).await
|
||||
}
|
||||
|
||||
async fn build_chain_segment() -> ChainSegmentData {
|
||||
// The assumption that you can re-import a block based on what you have in your DB
|
||||
// is no longer true, as fullnodes stores less than what they sample.
|
||||
// We use a supernode here to build a chain segment.
|
||||
@@ -365,9 +375,9 @@ async fn chain_segment_full_segment() {
|
||||
}
|
||||
let harness = get_harness(VALIDATOR_COUNT, NodeCustodyType::Fullnode);
|
||||
let (chain_segment, chain_segment_blobs) = get_chain_segment().await;
|
||||
store_envelopes_for_chain_segment(&chain_segment, &harness);
|
||||
store_envelopes_for_chain_segment(chain_segment, &harness);
|
||||
let blocks: Vec<RangeSyncBlock<E>> =
|
||||
chain_segment_blocks(&chain_segment, &chain_segment_blobs, harness.chain.clone())
|
||||
chain_segment_blocks(chain_segment, chain_segment_blobs, harness.chain.clone())
|
||||
.into_iter()
|
||||
.collect();
|
||||
|
||||
@@ -391,7 +401,7 @@ async fn chain_segment_full_segment() {
|
||||
.into_block_error()
|
||||
.expect("should import chain segment");
|
||||
|
||||
update_fork_choice_with_envelopes(&chain_segment, &harness);
|
||||
update_fork_choice_with_envelopes(chain_segment, &harness);
|
||||
harness.chain.recompute_head_at_current_slot().await;
|
||||
|
||||
assert_eq!(
|
||||
@@ -410,13 +420,13 @@ async fn chain_segment_varying_chunk_size() {
|
||||
let (chain_segment, chain_segment_blobs) = get_chain_segment().await;
|
||||
let harness = get_harness(VALIDATOR_COUNT, NodeCustodyType::Fullnode);
|
||||
let blocks: Vec<RangeSyncBlock<E>> =
|
||||
chain_segment_blocks(&chain_segment, &chain_segment_blobs, harness.chain.clone())
|
||||
chain_segment_blocks(chain_segment, chain_segment_blobs, harness.chain.clone())
|
||||
.into_iter()
|
||||
.collect();
|
||||
|
||||
for chunk_size in &[1, 2, 31, 32, 33] {
|
||||
for chunk_size in &[1, 32, 33] {
|
||||
let harness = get_harness(VALIDATOR_COUNT, NodeCustodyType::Fullnode);
|
||||
store_envelopes_for_chain_segment(&chain_segment, &harness);
|
||||
store_envelopes_for_chain_segment(chain_segment, &harness);
|
||||
|
||||
harness
|
||||
.chain
|
||||
@@ -432,7 +442,7 @@ async fn chain_segment_varying_chunk_size() {
|
||||
.unwrap_or_else(|_| panic!("should import chain segment of len {}", chunk_size));
|
||||
}
|
||||
|
||||
update_fork_choice_with_envelopes(&chain_segment, &harness);
|
||||
update_fork_choice_with_envelopes(chain_segment, &harness);
|
||||
harness.chain.recompute_head_at_current_slot().await;
|
||||
|
||||
assert_eq!(
|
||||
@@ -457,7 +467,7 @@ async fn chain_segment_non_linear_parent_roots() {
|
||||
* Test with a block removed.
|
||||
*/
|
||||
let mut blocks: Vec<RangeSyncBlock<E>> =
|
||||
chain_segment_blocks(&chain_segment, &chain_segment_blobs, harness.chain.clone())
|
||||
chain_segment_blocks(chain_segment, chain_segment_blobs, harness.chain.clone())
|
||||
.into_iter()
|
||||
.collect();
|
||||
blocks.remove(2);
|
||||
@@ -478,7 +488,7 @@ async fn chain_segment_non_linear_parent_roots() {
|
||||
* Test with a modified parent root.
|
||||
*/
|
||||
let mut blocks: Vec<RangeSyncBlock<E>> =
|
||||
chain_segment_blocks(&chain_segment, &chain_segment_blobs, harness.chain.clone())
|
||||
chain_segment_blocks(chain_segment, chain_segment_blobs, harness.chain.clone())
|
||||
.into_iter()
|
||||
.collect();
|
||||
|
||||
@@ -520,7 +530,7 @@ async fn chain_segment_non_linear_slots() {
|
||||
*/
|
||||
|
||||
let mut blocks: Vec<RangeSyncBlock<E>> =
|
||||
chain_segment_blocks(&chain_segment, &chain_segment_blobs, harness.chain.clone())
|
||||
chain_segment_blocks(chain_segment, chain_segment_blobs, harness.chain.clone())
|
||||
.into_iter()
|
||||
.collect();
|
||||
let (mut block, signature) = blocks[3].as_block().clone().deconstruct();
|
||||
@@ -550,7 +560,7 @@ async fn chain_segment_non_linear_slots() {
|
||||
*/
|
||||
|
||||
let mut blocks: Vec<RangeSyncBlock<E>> =
|
||||
chain_segment_blocks(&chain_segment, &chain_segment_blobs, harness.chain.clone())
|
||||
chain_segment_blocks(chain_segment, chain_segment_blobs, harness.chain.clone())
|
||||
.into_iter()
|
||||
.collect();
|
||||
let (mut block, signature) = blocks[3].as_block().clone().deconstruct();
|
||||
@@ -694,7 +704,7 @@ async fn invalid_signature_gossip_block() {
|
||||
let (chain_segment, chain_segment_blobs) = get_chain_segment().await;
|
||||
for &block_index in BLOCK_INDICES {
|
||||
// Ensure the block will be rejected if imported on its own (without gossip checking).
|
||||
let harness = get_invalid_sigs_harness(&chain_segment).await;
|
||||
let harness = get_invalid_sigs_harness(chain_segment).await;
|
||||
let mut snapshots = chain_segment.clone();
|
||||
let (block, _) = snapshots[block_index]
|
||||
.beacon_block
|
||||
@@ -753,7 +763,7 @@ async fn invalid_signature_block_proposal() {
|
||||
}
|
||||
let (chain_segment, chain_segment_blobs) = get_chain_segment().await;
|
||||
for &block_index in BLOCK_INDICES {
|
||||
let harness = get_invalid_sigs_harness(&chain_segment).await;
|
||||
let harness = get_invalid_sigs_harness(chain_segment).await;
|
||||
let mut snapshots = chain_segment.clone();
|
||||
let (block, _) = snapshots[block_index]
|
||||
.beacon_block
|
||||
@@ -794,9 +804,10 @@ async fn invalid_signature_randao_reveal() {
|
||||
if fork_name_from_env().is_some_and(|f| f.gloas_enabled()) {
|
||||
return;
|
||||
}
|
||||
let (chain_segment, mut chain_segment_blobs) = get_chain_segment().await;
|
||||
let (chain_segment, ref_blobs) = get_chain_segment().await;
|
||||
let mut chain_segment_blobs = ref_blobs.clone();
|
||||
for &block_index in BLOCK_INDICES {
|
||||
let harness = get_invalid_sigs_harness(&chain_segment).await;
|
||||
let harness = get_invalid_sigs_harness(chain_segment).await;
|
||||
let mut snapshots = chain_segment.clone();
|
||||
let (mut block, signature) = snapshots[block_index]
|
||||
.beacon_block
|
||||
@@ -809,7 +820,7 @@ async fn invalid_signature_randao_reveal() {
|
||||
update_parent_roots(&mut snapshots, &mut chain_segment_blobs);
|
||||
update_proposal_signatures(&mut snapshots, &harness);
|
||||
assert_invalid_signature(
|
||||
&chain_segment,
|
||||
chain_segment,
|
||||
&chain_segment_blobs,
|
||||
&harness,
|
||||
block_index,
|
||||
@@ -826,9 +837,10 @@ async fn invalid_signature_proposer_slashing() {
|
||||
if fork_name_from_env().is_some_and(|f| f.gloas_enabled()) {
|
||||
return;
|
||||
}
|
||||
let (chain_segment, mut chain_segment_blobs) = get_chain_segment().await;
|
||||
let (chain_segment, ref_blobs) = get_chain_segment().await;
|
||||
let mut chain_segment_blobs = ref_blobs.clone();
|
||||
for &block_index in BLOCK_INDICES {
|
||||
let harness = get_invalid_sigs_harness(&chain_segment).await;
|
||||
let harness = get_invalid_sigs_harness(chain_segment).await;
|
||||
let mut snapshots = chain_segment.clone();
|
||||
let (mut block, signature) = snapshots[block_index]
|
||||
.beacon_block
|
||||
@@ -855,7 +867,7 @@ async fn invalid_signature_proposer_slashing() {
|
||||
update_parent_roots(&mut snapshots, &mut chain_segment_blobs);
|
||||
update_proposal_signatures(&mut snapshots, &harness);
|
||||
assert_invalid_signature(
|
||||
&chain_segment,
|
||||
chain_segment,
|
||||
&chain_segment_blobs,
|
||||
&harness,
|
||||
block_index,
|
||||
@@ -872,9 +884,10 @@ async fn invalid_signature_attester_slashing() {
|
||||
if fork_name_from_env().is_some_and(|f| f.gloas_enabled()) {
|
||||
return;
|
||||
}
|
||||
let (chain_segment, mut chain_segment_blobs) = get_chain_segment().await;
|
||||
let (chain_segment, ref_blobs) = get_chain_segment().await;
|
||||
let mut chain_segment_blobs = ref_blobs.clone();
|
||||
for &block_index in BLOCK_INDICES {
|
||||
let harness = get_invalid_sigs_harness(&chain_segment).await;
|
||||
let harness = get_invalid_sigs_harness(chain_segment).await;
|
||||
let mut snapshots = chain_segment.clone();
|
||||
let fork_name = harness.chain.spec.fork_name_at_slot::<E>(Slot::new(0));
|
||||
|
||||
@@ -980,7 +993,7 @@ async fn invalid_signature_attester_slashing() {
|
||||
update_parent_roots(&mut snapshots, &mut chain_segment_blobs);
|
||||
update_proposal_signatures(&mut snapshots, &harness);
|
||||
assert_invalid_signature(
|
||||
&chain_segment,
|
||||
chain_segment,
|
||||
&chain_segment_blobs,
|
||||
&harness,
|
||||
block_index,
|
||||
@@ -997,11 +1010,12 @@ async fn invalid_signature_attestation() {
|
||||
if fork_name_from_env().is_some_and(|f| f.gloas_enabled()) {
|
||||
return;
|
||||
}
|
||||
let (chain_segment, mut chain_segment_blobs) = get_chain_segment().await;
|
||||
let (chain_segment, ref_blobs) = get_chain_segment().await;
|
||||
let mut chain_segment_blobs = ref_blobs.clone();
|
||||
let mut checked_attestation = false;
|
||||
|
||||
for &block_index in BLOCK_INDICES {
|
||||
let harness = get_invalid_sigs_harness(&chain_segment).await;
|
||||
let harness = get_invalid_sigs_harness(chain_segment).await;
|
||||
let mut snapshots = chain_segment.clone();
|
||||
let (mut block, signature) = snapshots[block_index]
|
||||
.beacon_block
|
||||
@@ -1049,7 +1063,7 @@ async fn invalid_signature_attestation() {
|
||||
update_parent_roots(&mut snapshots, &mut chain_segment_blobs);
|
||||
update_proposal_signatures(&mut snapshots, &harness);
|
||||
assert_invalid_signature(
|
||||
&chain_segment,
|
||||
chain_segment,
|
||||
&chain_segment_blobs,
|
||||
&harness,
|
||||
block_index,
|
||||
@@ -1069,10 +1083,11 @@ async fn invalid_signature_attestation() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn invalid_signature_deposit() {
|
||||
let (chain_segment, mut chain_segment_blobs) = get_chain_segment().await;
|
||||
let (chain_segment, ref_blobs) = get_chain_segment().await;
|
||||
let mut chain_segment_blobs = ref_blobs.clone();
|
||||
for &block_index in BLOCK_INDICES {
|
||||
// Note: an invalid deposit signature is permitted!
|
||||
let harness = get_invalid_sigs_harness(&chain_segment).await;
|
||||
let harness = get_invalid_sigs_harness(chain_segment).await;
|
||||
let mut snapshots = chain_segment.clone();
|
||||
let deposit = Deposit {
|
||||
proof: vec![Hash256::zero(); DEPOSIT_TREE_DEPTH + 1]
|
||||
@@ -1126,9 +1141,10 @@ async fn invalid_signature_exit() {
|
||||
if fork_name_from_env().is_some_and(|f| f.gloas_enabled()) {
|
||||
return;
|
||||
}
|
||||
let (chain_segment, mut chain_segment_blobs) = get_chain_segment().await;
|
||||
let (chain_segment, ref_blobs) = get_chain_segment().await;
|
||||
let mut chain_segment_blobs = ref_blobs.clone();
|
||||
for &block_index in BLOCK_INDICES {
|
||||
let harness = get_invalid_sigs_harness(&chain_segment).await;
|
||||
let harness = get_invalid_sigs_harness(chain_segment).await;
|
||||
let mut snapshots = chain_segment.clone();
|
||||
let epoch = snapshots[block_index].beacon_state.current_epoch();
|
||||
let (mut block, signature) = snapshots[block_index]
|
||||
@@ -1152,7 +1168,7 @@ async fn invalid_signature_exit() {
|
||||
update_parent_roots(&mut snapshots, &mut chain_segment_blobs);
|
||||
update_proposal_signatures(&mut snapshots, &harness);
|
||||
assert_invalid_signature(
|
||||
&chain_segment,
|
||||
chain_segment,
|
||||
&chain_segment_blobs,
|
||||
&harness,
|
||||
block_index,
|
||||
@@ -1173,7 +1189,8 @@ fn unwrap_err<T, U>(result: Result<T, U>) -> U {
|
||||
#[tokio::test]
|
||||
async fn block_gossip_verification() {
|
||||
let harness = get_harness(VALIDATOR_COUNT, NodeCustodyType::Fullnode);
|
||||
let (chain_segment, chain_segment_blobs) = get_chain_segment().await;
|
||||
let (chain_segment, ref_blobs) = get_chain_segment().await;
|
||||
let chain_segment_blobs = ref_blobs.clone();
|
||||
|
||||
let block_index = CHAIN_SEGMENT_LENGTH - 2;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user