Some test fixes

This commit is contained in:
Eitan Seri- Levi
2026-01-29 11:02:55 -08:00
parent 534e3c7976
commit 6ea966846c
7 changed files with 91 additions and 132 deletions

View File

@@ -397,7 +397,7 @@ impl<T: BeaconChainTypes> DataColumnCache<T> for DataAvailabilityChecker<T> {
self.availability_cache self.availability_cache
.peek_pending_components(block_root, |components| { .peek_pending_components(block_root, |components| {
components.is_some_and(|components| { components.is_some_and(|components| {
let cached_column_opt = components.get_cached_data_column(data_column.index()); let cached_column_opt = components.get_cached_data_column(*data_column.index());
cached_column_opt.is_some_and(|cached| *cached == *data_column) cached_column_opt.is_some_and(|cached| *cached == *data_column)
}) })
}) })

View File

@@ -147,7 +147,7 @@ impl<T: BeaconChainTypes> DataColumnCache<T> for DataAvailabilityChecker<T> {
self.availability_cache self.availability_cache
.peek_pending_components(block_root, |components| { .peek_pending_components(block_root, |components| {
components.is_some_and(|components| { components.is_some_and(|components| {
let cached_column_opt = components.get_cached_data_column(data_column.index()); let cached_column_opt = components.get_cached_data_column(*data_column.index());
cached_column_opt.is_some_and(|cached| *cached == *data_column) cached_column_opt.is_some_and(|cached| *cached == *data_column)
}) })
}) })

View File

@@ -644,7 +644,7 @@ mod test {
use crate::test_utils::generate_data_column_indices_rand_order; use crate::test_utils::generate_data_column_indices_rand_order;
use crate::{ use crate::{
block_verification::PayloadVerificationOutcome, block_verification::PayloadVerificationOutcome,
block_verification_types::{AsBlock, BlockImportData}, block_verification_types::AsBlock,
custody_context::NodeCustodyType, custody_context::NodeCustodyType,
data_availability_checker_v2::STATE_LRU_CAPACITY_NON_ZERO, data_availability_checker_v2::STATE_LRU_CAPACITY_NON_ZERO,
test_utils::{BaseHarnessType, BeaconChainHarness, DiskHarnessType}, test_utils::{BaseHarnessType, BeaconChainHarness, DiskHarnessType},
@@ -657,7 +657,7 @@ mod test {
use tempfile::{TempDir, tempdir}; use tempfile::{TempDir, tempdir};
use tracing::{debug_span, info}; use tracing::{debug_span, info};
use types::new_non_zero_usize; use types::new_non_zero_usize;
use types::{ExecPayload, MinimalEthSpec}; use types::MinimalEthSpec;
const LOW_VALIDATOR_COUNT: usize = 32; const LOW_VALIDATOR_COUNT: usize = 32;
const STATE_LRU_CAPACITY: usize = STATE_LRU_CAPACITY_NON_ZERO.get(); const STATE_LRU_CAPACITY: usize = STATE_LRU_CAPACITY_NON_ZERO.get();
@@ -719,11 +719,7 @@ mod test {
assert!(gloas_head.as_gloas().is_ok()); assert!(gloas_head.as_gloas().is_ok());
assert_eq!(gloas_head.slot(), gloas_fork_slot); assert_eq!(gloas_head.slot(), gloas_fork_slot);
assert!( assert!(
gloas_head gloas_head.message().body().execution_payload().is_err(),
.message()
.body()
.execution_payload()
.is_err(),
"Gloas block has no payload" "Gloas block has no payload"
); );
harness harness
@@ -740,77 +736,7 @@ mod test {
Hot: ItemStore<E>, Hot: ItemStore<E>,
Cold: ItemStore<E>, Cold: ItemStore<E>,
{ {
let chain = &harness.chain; todo!()
let head = chain.head_snapshot();
let parent_state = head.beacon_state.clone();
let target_slot = chain.slot().expect("should get slot") + 1;
let parent_root = head.beacon_block_root;
let parent_block = chain
.get_payload(&parent_root)
.expect("should get block")
.expect("should have block");
let (signed_beacon_block_hash, (block, maybe_blobs), state) = harness
.add_block_at_slot(target_slot, parent_state)
.await
.expect("should add block");
let block_root = signed_beacon_block_hash.into();
assert_eq!(
block_root,
block.canonical_root(),
"block root should match"
);
// log kzg commitments
info!("printing kzg commitments");
for comm in Vec::from(
block
.message()
.body()
.blob_kzg_commitments()
.expect("should be deneb fork")
.clone(),
) {
info!(commitment = ?comm, "kzg commitment");
}
info!("done printing kzg commitments");
let gossip_verified_columns = if let Some((kzg_proofs, blobs)) = maybe_blobs {
let sidecars =
DataColumnSidecar::build_sidecars(blobs, &block, &chain.kzg, &chain.spec).unwrap();
Vec::from(sidecars)
.into_iter()
.map(|sidecar| {
let subnet = *sidecar.index();
GossipVerifiedDataColumn::new(sidecar, subnet.into(), &harness.chain)
.expect("should validate column")
})
.collect()
} else {
vec![]
};
let slot = block.slot();
let consensus_context: ConsensusContext<E> = ConsensusContext::<E>::new(slot);
let import_data: PayloadImportData<E> = PayloadImportData {
state,
consensus_context,
};
let payload_verification_outcome = PayloadVerificationOutcome {
payload_verification_status: PayloadVerificationStatus::Verified,
is_valid_merge_transition_block: false,
};
let availability_pending_block = AvailabilityPendingExecutedPayload {
payload,
import_data,
payload_verification_outcome,
};
(availability_pending_block, gossip_verified_columns)
} }
async fn setup_harness_and_cache<E, T>( async fn setup_harness_and_cache<E, T>(
@@ -861,7 +787,13 @@ mod test {
let (pending_payload, columns) = availability_pending_payload(&harness).await; let (pending_payload, columns) = availability_pending_payload(&harness).await;
let root = pending_payload.as_payload().beacon_block_root(); let root = pending_payload.as_payload().beacon_block_root();
let expected_column_indices = harness.chain.data_availability_checker.custody_context().custody_columns_for_epoch(None, &harness.chain.spec).iter().collect::<HashSet<_>>(); let expected_column_indices = harness
.chain
.data_availability_checker
.custody_context()
.custody_columns_for_epoch(None, &harness.chain.spec)
.iter()
.collect::<HashSet<_>>();
let columns_expected = pending_payload.num_blobs_expected(); let columns_expected = pending_payload.num_blobs_expected();
assert_eq!( assert_eq!(
@@ -918,7 +850,13 @@ mod test {
} }
let (pending_payload, columns) = availability_pending_payload(&harness).await; let (pending_payload, columns) = availability_pending_payload(&harness).await;
let expected_column_indices = harness.chain.data_availability_checker.custody_context().custody_columns_for_epoch(None, &harness.chain.spec).iter().collect::<HashSet<_>>(); let expected_column_indices = harness
.chain
.data_availability_checker
.custody_context()
.custody_columns_for_epoch(None, &harness.chain.spec)
.iter()
.collect::<HashSet<_>>();
let columns_expected = pending_payload.num_blobs_expected(); let columns_expected = pending_payload.num_blobs_expected();
assert_eq!( assert_eq!(
columns.len(), columns.len(),
@@ -966,28 +904,28 @@ mod test {
let capacity = STATE_LRU_CAPACITY * 2; let capacity = STATE_LRU_CAPACITY * 2;
let (harness, cache, _path) = setup_harness_and_cache::<E, T>(capacity).await; let (harness, cache, _path) = setup_harness_and_cache::<E, T>(capacity).await;
let mut pending_blocks = VecDeque::new(); let mut pending_payloads = VecDeque::new();
let mut states = Vec::new(); let mut states = Vec::new();
let mut state_roots = Vec::new(); let mut state_roots = Vec::new();
// Get enough blocks to fill the cache to capacity, ensuring all blocks have blobs // Get enough blocks to fill the cache to capacity, ensuring all blocks have blobs
while pending_blocks.len() < capacity { while pending_payloads.len() < capacity {
let (mut pending_block, _) = availability_pending_block(&harness).await; let (mut pending_payload, _) = availability_pending_payload(&harness).await;
if pending_block.num_blobs_expected() == 0 { if pending_payload.num_blobs_expected() == 0 {
// we need blocks with blobs // we need blocks with blobs
continue; continue;
} }
let state_root = pending_block.import_data.state.canonical_root().unwrap(); let state_root = pending_payload.import_data.state.canonical_root().unwrap();
states.push(pending_block.import_data.state.clone()); states.push(pending_payload.import_data.state.clone());
pending_blocks.push_back(pending_block); pending_payloads.push_back(pending_payload);
state_roots.push(state_root); state_roots.push(state_root);
} }
let state_cache = cache.state_lru_cache().lru_cache(); let state_cache = cache.state_lru_cache().lru_cache();
let mut pushed_diet_blocks = VecDeque::new(); let mut pushed_diet_payloads = VecDeque::new();
for i in 0..capacity { for i in 0..capacity {
let pending_block = pending_blocks.pop_front().expect("should have block"); let pending_payload = pending_payloads.pop_front().expect("should have payload");
let block_root = pending_block.as_block().canonical_root(); let block_root = pending_payload.as_payload().beacon_block_root();
assert_eq!( assert_eq!(
state_cache.read().len(), state_cache.read().len(),
@@ -1000,23 +938,23 @@ mod test {
assert_eq!( assert_eq!(
state_cache.read().peek_lru().map(|(root, _)| root), state_cache.read().peek_lru().map(|(root, _)| root),
Some(&lru_root), Some(&lru_root),
"lru block should be in cache" "lru payload should be in cache"
); );
} }
// put the block in the cache // put the block in the cache
let availability = cache let availability = cache
.put_executed_block(pending_block) .put_executed_payload(pending_payload)
.expect("should put block"); .expect("should put payload");
// grab the diet block from the cache for later testing // grab the diet block from the cache for later testing
let diet_block = cache let diet_payload = cache
.critical .critical
.read() .read()
.peek(&block_root) .peek(&block_root)
.and_then(|pending_components| pending_components.get_diet_block().cloned()) .and_then(|pending_components| pending_components.get_diet_payload().cloned())
.expect("should exist"); .expect("should exist");
pushed_diet_blocks.push_back(diet_block); pushed_diet_payloads.push_back(diet_payload);
// should be unavailable since we made sure all blocks had blobs // should be unavailable since we made sure all blocks had blobs
assert!( assert!(
@@ -1032,41 +970,41 @@ mod test {
"lru root should be evicted" "lru root should be evicted"
); );
// get the diet block via direct conversion (testing only) // get the diet block via direct conversion (testing only)
let diet_block = pushed_diet_blocks.pop_front().expect("should have block"); let diet_payload = pushed_diet_payloads.pop_front().expect("should have payload");
// reconstruct the pending block by replaying the block on the parent state // reconstruct the pending block by replaying the block on the parent state
let recovered_pending_block = cache let recovered_pending_payload = cache
.state_lru_cache() .state_lru_cache()
.recover_pending_executed_block(diet_block, &debug_span!("test")) .recover_pending_executed_payload(diet_payload, &debug_span!("test"))
.expect("should reconstruct pending block"); .expect("should reconstruct pending block");
// assert the recovered state is the same as the original // assert the recovered state is the same as the original
assert_eq!( assert_eq!(
recovered_pending_block.import_data.state, states[evicted_index], recovered_pending_payload.import_data.state, states[evicted_index],
"recovered state should be the same as the original" "recovered state should be the same as the original"
); );
} }
} }
// now check the last block // now check the last payload
let last_block = pushed_diet_blocks.pop_back().expect("should exist").clone(); let last_payload = pushed_diet_payloads.pop_back().expect("should exist").clone();
// the state should still be in the cache // the state should still be in the cache
assert!( assert!(
state_cache state_cache
.read() .read()
.peek(&last_block.as_block().state_root()) .peek(&last_payload.as_payload().message.state_root)
.is_some(), .is_some(),
"last block state should still be in cache" "last payload state should still be in cache"
); );
// get the diet block via direct conversion (testing only) // get the diet payload via direct conversion (testing only)
let diet_block = last_block.clone(); let diet_payload = last_payload.clone();
// recover the pending block from the cache // recover the pending payload from the cache
let recovered_pending_block = cache let recovered_pending_payload = cache
.state_lru_cache() .state_lru_cache()
.recover_pending_executed_block(diet_block, &debug_span!("test")) .recover_pending_executed_payload(diet_payload, &debug_span!("test"))
.expect("should reconstruct pending block"); .expect("should reconstruct pending payload");
// assert the recovered state is the same as the original // assert the recovered state is the same as the original
assert_eq!( assert_eq!(
Some(&recovered_pending_block.import_data.state), Some(&recovered_pending_payload.import_data.state),
states.last(), states.last(),
"recovered state should be the same as the original" "recovered state should be the same as the original"
); );
@@ -1084,6 +1022,7 @@ mod pending_components_tests {
use kzg::KzgCommitment; use kzg::KzgCommitment;
use rand::SeedableRng; use rand::SeedableRng;
use rand::rngs::StdRng; use rand::rngs::StdRng;
use ssz_types::RuntimeFixedVector;
use state_processing::ConsensusContext; use state_processing::ConsensusContext;
use types::test_utils::TestRandom; use types::test_utils::TestRandom;
use types::{BeaconState, ForkName, MainnetEthSpec, SignedBeaconBlock, Slot}; use types::{BeaconState, ForkName, MainnetEthSpec, SignedBeaconBlock, Slot};

View File

@@ -1,4 +1,4 @@
#![allow(dead_code)] #![allow(dead_code)]
use crate::payload_verification_types::{AvailabilityPendingExecutedPayload, PayloadImportData}; use crate::payload_verification_types::{AvailabilityPendingExecutedPayload, PayloadImportData};
use crate::{ use crate::{
BeaconChainTypes, BeaconStore, PayloadVerificationOutcome, BeaconChainTypes, BeaconStore, PayloadVerificationOutcome,

View File

@@ -2690,6 +2690,22 @@ where
self.chain.slot_clock.set_slot(slot.into()); self.chain.slot_clock.set_slot(slot.into());
} }
pub async fn add_payload_envelope_at_slot(
&self,
slot: Slot,
state: BeaconState<E>,
) -> Result<
(
SignedBeaconBlockHash,
SignedExecutionPayloaContentsTuple<E>,
BeaconState<E>,
),
BlockError,
> {
self.set_current_slot(slot);
let (block_contents, new_state) = self.make_block(state, slot).await;
}
pub async fn add_block_at_slot( pub async fn add_block_at_slot(
&self, &self,
slot: Slot, slot: Slot,

View File

@@ -1852,6 +1852,11 @@ pub type SignedBlockContentsTuple<E> = (
Option<(KzgProofs<E>, BlobsList<E>)>, Option<(KzgProofs<E>, BlobsList<E>)>,
); );
pub type SignedPayloadEnvelopeContentsTuple<E> = (
Arc<SignedExecutionPayloadEnvelope<E>>,
Option<(KzgProofs<E>, BlobsList<E>)>,
);
fn parse_required_header<T>( fn parse_required_header<T>(
headers: &HeaderMap, headers: &HeaderMap,
header_name: &str, header_name: &str,

View File

@@ -3,7 +3,7 @@ use std::sync::Arc;
use bls::Signature; use bls::Signature;
use context_deserialize::context_deserialize; use context_deserialize::context_deserialize;
use educe::Educe; use educe::Educe;
use kzg::{CellsAndKzgProofs, Kzg, KzgCommitment, KzgProof, BYTES_PER_BLOB}; use kzg::{BYTES_PER_BLOB, CellsAndKzgProofs, Kzg, KzgCommitment, KzgProof};
use merkle_proof::verify_merkle_proof; use merkle_proof::verify_merkle_proof;
use safe_arith::ArithError; use safe_arith::ArithError;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@@ -17,7 +17,9 @@ use tree_hash::TreeHash;
use tree_hash_derive::TreeHash; use tree_hash_derive::TreeHash;
use crate::{ use crate::{
block::{BLOB_KZG_COMMITMENTS_INDEX, BeaconBlockHeader, SignedBeaconBlock, SignedBeaconBlockHeader}, block::{
BLOB_KZG_COMMITMENTS_INDEX, BeaconBlockHeader, SignedBeaconBlock, SignedBeaconBlockHeader,
},
core::{ChainSpec, Epoch, EthSpec, Hash256, Slot}, core::{ChainSpec, Epoch, EthSpec, Hash256, Slot},
data::BlobsList, data::BlobsList,
fork::ForkName, fork::ForkName,
@@ -162,16 +164,13 @@ impl<E: EthSpec> DataColumnSidecar<E> {
let blob_cells_and_proofs: Vec<CellsAndKzgProofs> = blobs let blob_cells_and_proofs: Vec<CellsAndKzgProofs> = blobs
.iter() .iter()
.map(|blob| { .map(|blob| {
let blob_bytes: &[u8; BYTES_PER_BLOB] = let blob_bytes: &[u8; BYTES_PER_BLOB] = blob.as_ref().try_into().map_err(|_| {
blob.as_ref().try_into().map_err(|_| { DataColumnSidecarError::KzgError(KzgError::InconsistentArrayLength(format!(
DataColumnSidecarError::KzgError(KzgError::InconsistentArrayLength( "blob should have size {}, got {}",
format!( BYTES_PER_BLOB,
"blob should have size {}, got {}", blob.len()
BYTES_PER_BLOB, )))
blob.len() })?;
),
))
})?;
kzg.compute_cells_and_proofs(blob_bytes) kzg.compute_cells_and_proofs(blob_bytes)
.map_err(DataColumnSidecarError::KzgError) .map_err(DataColumnSidecarError::KzgError)
}) })
@@ -190,15 +189,15 @@ impl<E: EthSpec> DataColumnSidecar<E> {
// Arrange cells and proofs into columns // Arrange cells and proofs into columns
for (blob_cells, blob_cell_proofs) in &blob_cells_and_proofs { for (blob_cells, blob_cell_proofs) in &blob_cells_and_proofs {
for col_idx in 0..number_of_columns { for col_idx in 0..number_of_columns {
let cell = blob_cells.get(col_idx).ok_or_else(|| { let cell = blob_cells
DataColumnSidecarError::DataColumnIndexOutOfBounds .get(col_idx)
})?; .ok_or_else(|| DataColumnSidecarError::DataColumnIndexOutOfBounds)?;
let cell_vec: Vec<u8> = cell.to_vec(); let cell_vec: Vec<u8> = cell.to_vec();
let cell = Cell::<E>::try_from(cell_vec)?; let cell = Cell::<E>::try_from(cell_vec)?;
let proof = blob_cell_proofs.get(col_idx).ok_or_else(|| { let proof = blob_cell_proofs
DataColumnSidecarError::DataColumnIndexOutOfBounds .get(col_idx)
})?; .ok_or_else(|| DataColumnSidecarError::DataColumnIndexOutOfBounds)?;
columns columns
.get_mut(col_idx) .get_mut(col_idx)