mirror of
https://github.com/sigp/lighthouse.git
synced 2026-07-01 20:04:41 +00:00
Run Gloas sync tests instead of skipping them (#9446)
Co-Authored-By: dapplion <35266934+dapplion@users.noreply.github.com> Co-Authored-By: Pawan Dhananjay <pawandhananjay@gmail.com>
This commit is contained in:
@@ -45,6 +45,17 @@ use types::{
|
||||
|
||||
const D: Duration = Duration::new(0, 0);
|
||||
|
||||
/// Extract the Gloas payload envelope (if any) carried by a stored `RangeSyncBlock`.
|
||||
fn envelope_of(block: &RangeSyncBlock<E>) -> Option<Arc<SignedExecutionPayloadEnvelope<E>>> {
|
||||
match block {
|
||||
RangeSyncBlock::Gloas {
|
||||
envelope: Some(envelope),
|
||||
..
|
||||
} => Some(envelope.envelope().clone()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Gloas genesis needs enough validators to populate `proposer_lookahead`.
|
||||
const TEST_RIG_VALIDATOR_COUNT: usize = 8;
|
||||
|
||||
@@ -331,7 +342,6 @@ impl TestRig {
|
||||
fork_name,
|
||||
network_blocks_by_root: <_>::default(),
|
||||
network_blocks_by_slot: <_>::default(),
|
||||
network_envelopes_by_root: <_>::default(),
|
||||
penalties: <_>::default(),
|
||||
seen_lookups: <_>::default(),
|
||||
requests: <_>::default(),
|
||||
@@ -669,7 +679,10 @@ impl TestRig {
|
||||
if self.complete_strategy.hold_envelope_for_block == Some(block_root) {
|
||||
return;
|
||||
}
|
||||
let envelope = self.network_envelopes_by_root.get(&block_root).cloned();
|
||||
let envelope = self
|
||||
.network_blocks_by_root
|
||||
.get(&block_root)
|
||||
.and_then(envelope_of);
|
||||
self.send_rpc_envelope_response(req_id, peer_id, envelope);
|
||||
}
|
||||
|
||||
@@ -843,7 +856,7 @@ impl TestRig {
|
||||
if self.complete_strategy.hold_envelope_for_block == Some(block_root) {
|
||||
return None;
|
||||
}
|
||||
self.network_envelopes_by_root.get(&block_root).cloned()
|
||||
envelope_of(block)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
self.send_rpc_envelopes_response(req_id, peer_id, &envelopes);
|
||||
@@ -1057,13 +1070,7 @@ impl TestRig {
|
||||
.await;
|
||||
let block = external_harness.get_full_block(&block_root);
|
||||
let block_slot = block.slot();
|
||||
self.insert_external_block(
|
||||
block,
|
||||
external_harness
|
||||
.chain
|
||||
.get_payload_envelope(&block_root)
|
||||
.unwrap(),
|
||||
);
|
||||
self.insert_external_block(block);
|
||||
blocks.push((block_slot, block_root));
|
||||
}
|
||||
|
||||
@@ -1171,8 +1178,7 @@ impl TestRig {
|
||||
// Cache every block through the single `get_full_block` + `insert_external_block2` path.
|
||||
for root in [g_root, a_root, c_root, b_root] {
|
||||
let block = external_harness.get_full_block(&root);
|
||||
let envelope = external_harness.chain.get_payload_envelope(&root).unwrap();
|
||||
self.insert_external_block(block, envelope);
|
||||
self.insert_external_block(block);
|
||||
}
|
||||
|
||||
self.harness.set_current_slot(child_slot);
|
||||
@@ -1200,21 +1206,12 @@ impl TestRig {
|
||||
Some((r, fork))
|
||||
}
|
||||
|
||||
fn insert_external_block(
|
||||
&mut self,
|
||||
block: RangeSyncBlock<E>,
|
||||
envelope: Option<SignedExecutionPayloadEnvelope<E>>,
|
||||
) {
|
||||
fn insert_external_block(&mut self, block: RangeSyncBlock<E>) {
|
||||
let block_root = block.canonical_root();
|
||||
let block_slot = block.slot();
|
||||
self.network_blocks_by_root
|
||||
.insert(block_root, block.clone());
|
||||
self.network_blocks_by_slot.insert(block_slot, block);
|
||||
// Cache Gloas envelopes for lookup RPCs.
|
||||
if let Some(envelope) = envelope {
|
||||
self.network_envelopes_by_root
|
||||
.insert(block_root, envelope.into());
|
||||
}
|
||||
self.log(&format!(
|
||||
"Produced block {block_root:?} slot {block_slot} in external harness",
|
||||
));
|
||||
@@ -1300,9 +1297,9 @@ impl TestRig {
|
||||
let range_sync_block = if block.fork_name_unchecked().gloas_enabled() {
|
||||
// Gloas carries data columns in the payload envelope, not in `block_data`.
|
||||
let envelope = self
|
||||
.network_envelopes_by_root
|
||||
.network_blocks_by_root
|
||||
.get(&block_root)
|
||||
.cloned()
|
||||
.and_then(envelope_of)
|
||||
.map(|envelope| AvailableEnvelope::new(envelope, columns.unwrap_or_default()));
|
||||
RangeSyncBlock::new_gloas(block, envelope).unwrap()
|
||||
} else {
|
||||
@@ -1370,6 +1367,8 @@ impl TestRig {
|
||||
.unwrap_or_else(|| panic!("No block at slot {slot}"))
|
||||
.clone();
|
||||
let block_root = rpc_block.canonical_root();
|
||||
let block_state_root = rpc_block.as_block().state_root();
|
||||
let envelope = envelope_of(&rpc_block);
|
||||
self.harness
|
||||
.chain
|
||||
.process_block(
|
||||
@@ -1381,6 +1380,18 @@ impl TestRig {
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
// Gloas: import the payload envelope so the block counts as full for its children.
|
||||
if let Some(envelope) = envelope {
|
||||
let state = self
|
||||
.harness
|
||||
.chain
|
||||
.get_state(&block_state_root, Some(Slot::new(slot)), false)
|
||||
.expect("should load state")
|
||||
.expect("state should exist");
|
||||
self.harness
|
||||
.process_envelope(block_root, (*envelope).clone(), &state, block_state_root)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
self.harness.chain.recompute_head_at_current_slot().await;
|
||||
}
|
||||
@@ -1495,6 +1506,17 @@ impl TestRig {
|
||||
panic!("Some downscore events: {:?}", self.penalties);
|
||||
}
|
||||
}
|
||||
|
||||
fn assert_no_block_requests(&self) {
|
||||
assert_eq!(
|
||||
self.requests
|
||||
.iter()
|
||||
.filter(|(request, _)| matches!(request, RequestType::BlocksByRoot(_)))
|
||||
.collect::<Vec<_>>(),
|
||||
Vec::<&(RequestType<E>, AppRequestId)>::new(),
|
||||
"There should be no block requests"
|
||||
);
|
||||
}
|
||||
fn assert_failed_lookup_sync(&mut self) {
|
||||
assert!(self.created_lookups() > 0, "no created lookups");
|
||||
assert_eq!(self.completed_lookups(), 0, "some completed lookups");
|
||||
@@ -1623,6 +1645,10 @@ impl TestRig {
|
||||
genesis_fork().fulu_enabled().then(Self::default)
|
||||
}
|
||||
|
||||
fn new_after_gloas() -> Option<Self> {
|
||||
genesis_fork().gloas_enabled().then(Self::default)
|
||||
}
|
||||
|
||||
pub fn new_fulu_peer_test(fulu_test_type: FuluTestType) -> Option<Self> {
|
||||
genesis_fork().fulu_enabled().then(|| {
|
||||
Self::new(TestRigConfig {
|
||||
@@ -2129,7 +2155,8 @@ async fn happy_path_unknown_data_parent(depth: usize) {
|
||||
let Some(mut r) = TestRig::new_after_fulu() else {
|
||||
return;
|
||||
};
|
||||
// No unknown-parent data-column trigger post-Gloas.
|
||||
// Fulu-only: the `UnknownDataColumnParent` trigger doesn't exist post-Gloas (columns ride in
|
||||
// the payload envelope, not as standalone data columns).
|
||||
if r.is_after_gloas() {
|
||||
return;
|
||||
}
|
||||
@@ -2359,10 +2386,6 @@ async fn test_single_block_lookup_ignored_response() {
|
||||
/// Assert that if the beacon processor returns DuplicateFullyImported, the lookup completes successfully
|
||||
async fn test_single_block_lookup_duplicate_response() {
|
||||
let mut r = TestRig::default();
|
||||
// The mock only covers block processing; Gloas also needs real envelope/column results.
|
||||
if r.is_after_gloas() {
|
||||
return;
|
||||
}
|
||||
r.build_chain_and_trigger_last_block(1).await;
|
||||
// Send a DuplicateFullyImported response, the lookup should complete successfully
|
||||
r.simulate(
|
||||
@@ -2427,10 +2450,6 @@ async fn lookups_form_chain() {
|
||||
/// Assert that if a lookup chain (by appending ancestors) is too long we drop it
|
||||
async fn test_parent_lookup_too_deep_grow_ancestor_one() {
|
||||
let mut r = TestRig::default();
|
||||
// TODO(gloas): range sync does not fetch payload envelopes yet.
|
||||
if r.is_after_gloas() {
|
||||
return;
|
||||
}
|
||||
r.build_chain(PARENT_DEPTH_TOLERANCE + 1).await;
|
||||
r.trigger_with_last_block();
|
||||
r.simulate(SimulateConfig::happy_path()).await;
|
||||
@@ -2575,13 +2594,13 @@ async fn test_same_chain_race_condition() {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
/// Assert that if the lookup's block is in the da_checker we don't download it again
|
||||
async fn block_in_da_checker_skips_download() {
|
||||
// Only post-Fulu, as the block needs custody columns to remain in the da_checker
|
||||
/// Assert that if the lookup's block is in the da_checker we don't download it again (pre-Gloas).
|
||||
async fn block_in_da_checker_skips_download_fulu() {
|
||||
// Only post-Fulu, as the block needs custody columns to remain in the da_checker.
|
||||
let Some(mut r) = TestRig::new_after_fulu() else {
|
||||
return;
|
||||
};
|
||||
// TODO(gloas): the helper does not populate the envelope missing-component path yet.
|
||||
// Pre-Gloas only; the Gloas equivalent is `block_in_da_checker_skips_download_gloas`.
|
||||
if r.is_after_gloas() {
|
||||
return;
|
||||
}
|
||||
@@ -2594,14 +2613,28 @@ async fn block_in_da_checker_skips_download() {
|
||||
r.trigger_with_block_at_slot(1);
|
||||
r.simulate(SimulateConfig::happy_path()).await;
|
||||
r.assert_successful_lookup_sync();
|
||||
assert_eq!(
|
||||
r.requests
|
||||
.iter()
|
||||
.filter(|(request, _)| matches!(request, RequestType::BlocksByRoot(_)))
|
||||
.collect::<Vec<_>>(),
|
||||
Vec::<&(RequestType<E>, AppRequestId)>::new(),
|
||||
"There should be no block requests"
|
||||
);
|
||||
r.assert_no_block_requests();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
/// Assert that if the lookup's block is in the da_checker we don't download it again (Gloas).
|
||||
async fn block_in_da_checker_skips_download_gloas() {
|
||||
let Some(mut r) = TestRig::new_after_gloas() else {
|
||||
return;
|
||||
};
|
||||
// A Gloas block carries no inline DA, so a lone block never sits in the da_checker awaiting
|
||||
// components: only a FULL *child* proves the block published a payload and supplies the peers
|
||||
// that serve its columns/envelope. Build a parent + FULL child, insert the PARENT into the
|
||||
// da_checker, then trigger via the child (which is provided by the trigger, not downloaded).
|
||||
// The parent lookup must then skip the parent's block download.
|
||||
r.build_chain(2).await;
|
||||
let parent = r.block_at_slot(1);
|
||||
let child = r.block_at_slot(2);
|
||||
r.import_block_to_da_checker(parent).await;
|
||||
r.trigger_unknown_parent_blocks_from_all_peers(&[child]);
|
||||
r.simulate(SimulateConfig::happy_path()).await;
|
||||
r.assert_successful_lookup_sync();
|
||||
r.assert_no_block_requests();
|
||||
}
|
||||
|
||||
macro_rules! fulu_peer_matrix_tests {
|
||||
|
||||
Reference in New Issue
Block a user