Skip to content

Commit

Permalink
feat: skip state root validation during unwinding (#135)
Browse files Browse the repository at this point in the history
Signed-off-by: Gregory Edison <[email protected]>
  • Loading branch information
greged93 authored Jan 15, 2025
1 parent 0a89b0a commit 0e01a23
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 11 deletions.
3 changes: 2 additions & 1 deletion crates/scroll/bin/scroll-reth/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ scroll = [
]
skip-state-root-validation = [
"reth-node-builder/skip-state-root-validation",
"reth-scroll-node/skip-state-root-validation"
"reth-scroll-node/skip-state-root-validation",
"reth-provider/skip-state-root-validation"
]
optimism = [
"reth-provider/optimism",
Expand Down
27 changes: 17 additions & 10 deletions crates/stages/stages/src/stages/merkle.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,27 @@
use alloy_consensus::BlockHeader;
use alloy_primitives::{BlockNumber, B256};
use reth_codecs::Compact;
use reth_consensus::ConsensusError;
use reth_db::tables;
use reth_db_api::transaction::{DbTx, DbTxMut};
use reth_primitives::{GotExpected, SealedHeader};
use reth_provider::{
DBProvider, HeaderProvider, LatestStateProviderRef, ProviderError, StageCheckpointReader,
StageCheckpointWriter, StateCommitmentProvider, StateRootProviderExt, StatsReader, TrieWriter,
};
use reth_stages_api::{
BlockErrorKind, EntitiesCheckpoint, ExecInput, ExecOutput, MerkleCheckpoint, Stage,
StageCheckpoint, StageError, StageId, UnwindInput, UnwindOutput,
EntitiesCheckpoint, ExecInput, ExecOutput, MerkleCheckpoint, Stage, StageCheckpoint,
StageError, StageId, UnwindInput, UnwindOutput,
};
use reth_trie::{IntermediateStateRootState, StateRootProgress, StoredSubNode};
use std::fmt::Debug;
use tracing::*;

#[cfg(not(feature = "skip-state-root-validation"))]
use {
alloy_primitives::{BlockNumber, B256},
reth_consensus::ConsensusError,
reth_primitives::{GotExpected, SealedHeader},
reth_stages_api::BlockErrorKind,
};

// TODO: automate the process outlined below so the user can just send in a debugging package
/// The error message that we include in invalid state root errors to tell users what information
/// they should include in a bug report, since true state root errors can be impossible to debug
Expand Down Expand Up @@ -276,9 +281,7 @@ where
self.save_execution_checkpoint(provider, None)?;

#[cfg(feature = "skip-state-root-validation")]
{
debug!(target: "sync::stages::merkle::exec", ?trie_root, block_number = target_block.number());
}
debug!(target: "sync::stages::merkle::exec", ?trie_root, block_number = target_block.number());
#[cfg(not(feature = "skip-state-root-validation"))]
validate_state_root(trie_root, SealedHeader::seal(target_block), to_block)?;

Expand Down Expand Up @@ -334,6 +337,9 @@ where
.header_by_number(input.unwind_to)?
.ok_or_else(|| ProviderError::HeaderNotFound(input.unwind_to.into()))?;

#[cfg(feature = "skip-state-root-validation")]
debug!(target: "sync::stages::merkle::unwind", ?block_root, block_number = target.number());
#[cfg(not(feature = "skip-state-root-validation"))]
validate_state_root(block_root, SealedHeader::seal(target), input.unwind_to)?;

// Validation passed, apply unwind changes to the database.
Expand All @@ -348,6 +354,7 @@ where

/// Check that the computed state root matches the root in the expected header.
#[inline]
#[cfg(not(feature = "skip-state-root-validation"))]
fn validate_state_root<H: BlockHeader + Debug>(
got: B256,
expected: SealedHeader<H>,
Expand All @@ -373,10 +380,10 @@ mod tests {
stage_test_suite_ext, ExecuteStageTestRunner, StageTestRunner, StorageKind,
TestRunnerError, TestStageDB, UnwindStageTestRunner,
};
use alloy_primitives::{keccak256, U256};
use alloy_primitives::{keccak256, B256, U256};
use assert_matches::assert_matches;
use reth_db_api::cursor::{DbCursorRO, DbCursorRW, DbDupCursorRO};
use reth_primitives::{SealedBlock, StaticFileSegment, StorageEntry};
use reth_primitives::{SealedBlock, SealedHeader, StaticFileSegment, StorageEntry};
use reth_provider::{providers::StaticFileWriter, StaticFileProviderFactory};
use reth_stages_api::StageUnitCheckpoint;
use reth_testing_utils::generators::{
Expand Down
1 change: 1 addition & 0 deletions crates/storage/provider/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -145,3 +145,4 @@ scroll = [
"reth-execution-types/scroll",
"reth-evm/scroll",
]
skip-state-root-validation = []
7 changes: 7 additions & 0 deletions crates/storage/provider/src/providers/database/provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -321,8 +321,15 @@ impl<TX: DbTx + DbTxMut + 'static, N: NodeTypesForProvider> DatabaseProvider<TX,
.ok_or_else(|| ProviderError::HeaderNotFound(parent_number.into()))?
.state_root();

#[cfg(feature = "skip-state-root-validation")]
{
let _ = parent_state_root;
debug!(target: "provider::db::unwind", ?new_state_root, block_number = parent_number);
}

// state root should be always correct as we are reverting state.
// but for sake of double verification we will check it again.
#[cfg(not(feature = "skip-state-root-validation"))]
if new_state_root != parent_state_root {
let parent_hash = self
.block_hash(parent_number)?
Expand Down

0 comments on commit 0e01a23

Please sign in to comment.