Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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.

4 changes: 3 additions & 1 deletion bin/ethlambda/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -640,7 +640,9 @@ async fn fetch_initial_state(
// overlaps with what `get_forkchoice_store` already wrote, but it's
// idempotent and the only path that also stores `BlockSignatures`.
let anchor_root = signed_block.message.header().hash_tree_root();
let mut store = Store::get_forkchoice_store(backend, state, signed_block.message.clone());
let mut store = Store::get_forkchoice_store(backend, state, signed_block.message.clone())
.inspect_err(|err| error!(%err, "Failed to initialize store from anchor state and block"))
.map_err(|_| checkpoint_sync::CheckpointSyncError::AnchorPairingMismatch)?;
store.insert_signed_block(anchor_root, signed_block);
Ok(store)
}
Expand Down
3 changes: 2 additions & 1 deletion crates/blockchain/tests/forkchoice_spectests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ fn run(path: &Path) -> datatest_stable::Result<()> {
}

let backend = Arc::new(InMemoryBackend::new());
let mut store = Store::get_forkchoice_store(backend, anchor_state, anchor_block);
let mut store = Store::get_forkchoice_store(backend, anchor_state, anchor_block)
.expect("anchor state and block must match");

// Block registry: maps block labels to their roots
let mut block_registry: HashMap<String, H256> = HashMap::new();
Expand Down
3 changes: 2 additions & 1 deletion crates/blockchain/tests/signature_spectests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ fn run(path: &Path) -> datatest_stable::Result<()> {
// Initialize the store with the anchor state and block
let genesis_time = anchor_state.config.genesis_time;
let backend = Arc::new(InMemoryBackend::new());
let mut st = Store::get_forkchoice_store(backend, anchor_state, anchor_block);
let mut st = Store::get_forkchoice_store(backend, anchor_state, anchor_block)
.expect("anchor state and block must match");

// Step 2: Run the state transition function with the block fixture
let signed_block: SignedBlock = test.signed_block.into();
Expand Down
1 change: 1 addition & 0 deletions crates/storage/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ ethlambda-types.workspace = true

tracing.workspace = true
rocksdb.workspace = true
thiserror.workspace = true

libssz.workspace = true
libssz-derive.workspace = true
Expand Down
2 changes: 1 addition & 1 deletion crates/storage/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ pub mod backend;
mod store;

pub use api::{ALL_TABLES, StorageBackend, StorageReadView, StorageWriteBatch, Table};
pub use store::{ForkCheckpoints, Store};
pub use store::{ForkCheckpoints, GetForkchoiceStoreError, Store};
38 changes: 30 additions & 8 deletions crates/storage/src/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,22 @@ use ethlambda_types::{
state::{ChainConfig, State, anchor_pair_is_consistent},
};
use libssz::{SszDecode, SszEncode};
use thiserror::Error;
use tracing::info;

/// Errors returned by [`Store::get_forkchoice_store`].
#[derive(Debug, Error)]
pub enum GetForkchoiceStoreError {
#[error(
"anchor block doesn't match anchor state: \
state header = {anchor_state:?}, block = {anchor_block:?}"
)]
AnchorPairInconsistent {
anchor_state: Box<State>,
anchor_block: Box<Block>,
},
}

/// Checkpoints to update in the forkchoice store.
///
/// Used with `Store::update_checkpoints` to update head and optionally
Expand Down Expand Up @@ -470,20 +484,28 @@ impl Store {
/// The block must match the state's `latest_block_header`.
/// Named to mirror the spec's `get_forkchoice_store` function.
///
/// # Panics
/// # Errors
///
/// Panics if [`anchor_pair_is_consistent`] would reject the pair.
/// Returns [`GetForkchoiceStoreError::AnchorPairInconsistent`] if the block's header
/// doesn't match the state's `latest_block_header` (comparing all fields
/// except `state_root`, which is computed internally).
pub fn get_forkchoice_store(
backend: Arc<dyn StorageBackend>,
mut anchor_state: State,
anchor_block: Block,
) -> Self {
assert!(
anchor_pair_is_consistent(&mut anchor_state, &anchor_block),
"anchor block does not match anchor state"
);
) -> Result<Self, GetForkchoiceStoreError> {
if !anchor_pair_is_consistent(&mut anchor_state, &anchor_block) {
return Err(GetForkchoiceStoreError::AnchorPairInconsistent {
anchor_state: Box::new(anchor_state),
anchor_block: Box::new(anchor_block),
});
}

Self::init_store(backend, anchor_state, Some(anchor_block.body))
Ok(Self::init_store(
backend,
anchor_state,
Some(anchor_block.body),
))
}

/// Internal helper to initialize the store with anchor data.
Expand Down