Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
29 changes: 28 additions & 1 deletion cmd/ethrex/initializers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -504,22 +504,44 @@ pub async fn init_l1(
))
}

async fn regenerate_head_state(store: &Store, blockchain: &Arc<Blockchain>) -> eyre::Result<()> {
/// Regenerates the state up to the head block by re-applying blocks from the
/// last known state root.
///
/// Since the path-based feature was added, the database stores the state 128
/// blocks behind the head block while the state of the blocks in between are
/// kept in in-memory-diff-layers.
///
/// After the node is shutdown, those in-memory layers are lost, and the database
/// won't have the state for those blocks. It will have the blocks though.
///
/// When the node is started again, the state needs to be regenerated by
/// re-applying the blocks from the last known state root up to the head block.
///
/// This function performs that regeneration.
pub async fn regenerate_head_state(
store: &Store,
blockchain: &Arc<Blockchain>,
) -> eyre::Result<()> {
let head_block_number = store.get_latest_block_number().await?;

let Some(last_header) = store.get_block_header(head_block_number)? else {
unreachable!("Database is empty, genesis block should be present");
};

let mut current_last_header = last_header;

// Find the last block with a known state root
while !store.has_state_root(current_last_header.state_root)? {
let parent_number = current_last_header.number - 1;

debug!("Need to regenerate state for block {parent_number}");

let Some(parent_header) = store.get_block_header(parent_number)? else {
return Err(eyre::eyre!(
"Parent header for block {parent_number} not found"
));
};

current_last_header = parent_header;
}

Expand All @@ -529,17 +551,22 @@ async fn regenerate_head_state(store: &Store, blockchain: &Arc<Blockchain>) -> e
debug!("State is already up to date");
return Ok(());
}

info!("Regenerating state from block {last_state_number} to {head_block_number}");

// Re-apply blocks from the last known state root to the head block
for i in (last_state_number + 1)..=head_block_number {
debug!("Re-applying block {i} to regenerate state");

let block = store
.get_block_by_number(i)
.await?
.ok_or_else(|| eyre::eyre!("Block {i} not found"))?;

blockchain.add_block(block).await?;
}

info!("Finished regenerating state");

Ok(())
}
4 changes: 3 additions & 1 deletion cmd/ethrex/l2/initializers.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::cli::Options as L1Options;
use crate::initializers::{
self, get_authrpc_socket_addr, get_http_socket_addr, get_local_node_record, get_local_p2p_node,
get_network, get_signer, init_blockchain, init_network, init_store,
get_network, get_signer, init_blockchain, init_network, init_store, regenerate_head_state,
};
use crate::l2::L2Options;
use crate::utils::{
Expand Down Expand Up @@ -169,6 +169,8 @@ pub async fn init_l2(

let blockchain = init_blockchain(store.clone(), blockchain_opts);

regenerate_head_state(&store, &blockchain).await?;

let signer = get_signer(&datadir);

let local_p2p_node = get_local_p2p_node(&opts.node_opts, &signer);
Expand Down
Loading