mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-01-08 23:08:19 -05:00
feat: add stateless crate to expose stateless validation (#15591)
Co-authored-by: Roman Krasiuk <rokrassyuk@gmail.com> Co-authored-by: Alexey Shekhirin <5773434+shekhirin@users.noreply.github.com>
This commit is contained in:
@@ -13,10 +13,7 @@ workspace = true
|
||||
|
||||
[features]
|
||||
ef-tests = []
|
||||
asm-keccak = [
|
||||
"alloy-primitives/asm-keccak",
|
||||
"revm/asm-keccak",
|
||||
]
|
||||
asm-keccak = ["alloy-primitives/asm-keccak", "revm/asm-keccak"]
|
||||
|
||||
[dependencies]
|
||||
reth-chainspec.workspace = true
|
||||
@@ -30,7 +27,9 @@ reth-provider = { workspace = true, features = ["test-utils"] }
|
||||
reth-evm.workspace = true
|
||||
reth-evm-ethereum.workspace = true
|
||||
reth-ethereum-consensus.workspace = true
|
||||
reth-revm = { workspace = true, features = ["std"] }
|
||||
reth-revm = { workspace = true, features = ["std", "witness"] }
|
||||
reth-stateless = { workspace = true }
|
||||
reth-tracing.workspace = true
|
||||
reth-trie.workspace = true
|
||||
reth-trie-db.workspace = true
|
||||
revm = { workspace = true, features = ["secp256k1", "blst", "c-kzg"] }
|
||||
@@ -46,6 +45,7 @@ serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
thiserror.workspace = true
|
||||
rayon.workspace = true
|
||||
tracing.workspace = true
|
||||
# TODO: When we build for a windows target on an ubuntu runner, crunchy tries to
|
||||
# get the wrong path, update this when the workflow has been updated
|
||||
#
|
||||
|
||||
@@ -4,7 +4,7 @@ use crate::{
|
||||
models::{BlockchainTest, ForkSpec},
|
||||
Case, Error, Suite,
|
||||
};
|
||||
use alloy_rlp::Decodable;
|
||||
use alloy_rlp::{Decodable, Encodable};
|
||||
use rayon::iter::{ParallelBridge, ParallelIterator};
|
||||
use reth_chainspec::ChainSpec;
|
||||
use reth_consensus::{Consensus, HeaderValidator};
|
||||
@@ -16,9 +16,11 @@ use reth_evm_ethereum::execute::EthExecutorProvider;
|
||||
use reth_primitives_traits::{RecoveredBlock, SealedBlock};
|
||||
use reth_provider::{
|
||||
test_utils::create_test_provider_factory_with_chain_spec, BlockWriter, DatabaseProviderFactory,
|
||||
ExecutionOutcome, HistoryWriter, OriginalValuesKnown, StateWriter, StorageLocation,
|
||||
ExecutionOutcome, HeaderProvider, HistoryWriter, OriginalValuesKnown, StateProofProvider,
|
||||
StateWriter, StorageLocation,
|
||||
};
|
||||
use reth_revm::database::StateProviderDatabase;
|
||||
use reth_revm::{database::StateProviderDatabase, witness::ExecutionWitnessRecord, State};
|
||||
use reth_stateless::{validation::stateless_validation, ExecutionWitness};
|
||||
use reth_trie::{HashedPostState, KeccakKeyHasher, StateRoot};
|
||||
use reth_trie_db::DatabaseStateRoot;
|
||||
use std::{collections::BTreeMap, fs, path::Path, sync::Arc};
|
||||
@@ -212,6 +214,7 @@ fn run_case(case: &BlockchainTest) -> Result<(), Error> {
|
||||
|
||||
let executor_provider = EthExecutorProvider::ethereum(chain_spec.clone());
|
||||
let mut parent = genesis_block;
|
||||
let mut program_inputs = Vec::new();
|
||||
|
||||
for (block_index, block) in blocks.iter().enumerate() {
|
||||
// Note: same as the comment on `decode_blocks` as to why we cannot use block.number
|
||||
@@ -226,16 +229,50 @@ fn run_case(case: &BlockchainTest) -> Result<(), Error> {
|
||||
pre_execution_checks(chain_spec.clone(), &parent, block)
|
||||
.map_err(|_| Error::BlockProcessingFailed { block_number })?;
|
||||
|
||||
let mut witness_record = ExecutionWitnessRecord::default();
|
||||
|
||||
// Execute the block
|
||||
let state_db = StateProviderDatabase(provider.latest());
|
||||
let state_provider = provider.latest();
|
||||
let state_db = StateProviderDatabase(&state_provider);
|
||||
let executor = executor_provider.batch_executor(state_db);
|
||||
let output =
|
||||
executor.execute(block).map_err(|_| Error::BlockProcessingFailed { block_number })?;
|
||||
|
||||
let output = executor
|
||||
.execute_with_state_closure(&(*block).clone(), |statedb: &State<_>| {
|
||||
witness_record.record_executed_state(statedb);
|
||||
})
|
||||
.map_err(|_| Error::BlockProcessingFailed { block_number })?;
|
||||
|
||||
// Consensus checks after block execution
|
||||
validate_block_post_execution(block, &chain_spec, &output.receipts, &output.requests)
|
||||
.map_err(|_| Error::BlockProcessingFailed { block_number })?;
|
||||
|
||||
// Generate the stateless witness
|
||||
// TODO: Most of this code is copy-pasted from debug_executionWitness
|
||||
let ExecutionWitnessRecord { hashed_state, codes, keys, lowest_block_number } =
|
||||
witness_record;
|
||||
let state = state_provider.witness(Default::default(), hashed_state)?;
|
||||
let mut exec_witness = ExecutionWitness { state, codes, keys, headers: Default::default() };
|
||||
|
||||
let smallest = lowest_block_number.unwrap_or_else(|| {
|
||||
// Return only the parent header, if there were no calls to the
|
||||
// BLOCKHASH opcode.
|
||||
block_number.saturating_sub(1)
|
||||
});
|
||||
|
||||
let range = smallest..block_number;
|
||||
|
||||
exec_witness.headers = provider
|
||||
.headers_range(range)?
|
||||
.into_iter()
|
||||
.map(|header| {
|
||||
let mut serialized_header = Vec::new();
|
||||
header.encode(&mut serialized_header);
|
||||
serialized_header.into()
|
||||
})
|
||||
.collect();
|
||||
|
||||
program_inputs.push((block.clone(), exec_witness));
|
||||
|
||||
// Compute and check the post state root
|
||||
let hashed_state =
|
||||
HashedPostState::from_bundle_state::<KeccakKeyHasher>(output.state.state());
|
||||
@@ -280,6 +317,12 @@ fn run_case(case: &BlockchainTest) -> Result<(), Error> {
|
||||
account.assert_db(address, provider.tx_ref())?;
|
||||
}
|
||||
|
||||
// Now validate using the stateless client if everything else passes
|
||||
for (block, execution_witness) in program_inputs {
|
||||
stateless_validation(block, execution_witness, chain_spec.clone())
|
||||
.expect("stateless validation failed");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ macro_rules! general_state_test {
|
||||
($test_name:ident, $dir:ident) => {
|
||||
#[test]
|
||||
fn $test_name() {
|
||||
reth_tracing::init_test_tracing();
|
||||
BlockchainTests::new(format!("GeneralStateTests/{}", stringify!($dir))).run();
|
||||
}
|
||||
};
|
||||
@@ -81,6 +82,7 @@ macro_rules! blockchain_test {
|
||||
($test_name:ident, $dir:ident) => {
|
||||
#[test]
|
||||
fn $test_name() {
|
||||
reth_tracing::init_test_tracing();
|
||||
BlockchainTests::new(format!("{}", stringify!($dir))).run();
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user