Skip to content

Commit 2840b30

Browse files
authored
Block and Chain drivers (#29)
* feat: modify_spec_id * wip: block and chain drivers * feature: block and chain drivers * chore: update ascii diagram * chore: update state diagram * fix: aliases
1 parent d85f775 commit 2840b30

File tree

11 files changed

+519
-163
lines changed

11 files changed

+519
-163
lines changed

Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "trevm"
3-
version = "0.1.1"
3+
version = "0.2.0"
44
rust-version = "1.79.0"
55
edition = "2021"
66
authors = ["init4"]
@@ -30,8 +30,10 @@ redundant-clone = "warn"
3030
alloy-consensus = { version = "0.2", features = ["k256"] }
3131
alloy-eips = "0.2.0"
3232
alloy-primitives = "0.7.6"
33+
alloy-rpc-types-eth = "0.2.0"
3334
alloy-sol-types = "0.7.7"
3435
revm = { version = "12.0.0", default-features = false, features = ["std"] }
36+
thiserror = "1.0.63"
3537
zenith-types = "0.2.2"
3638

3739
[dev-dependencies]

assets/states.png

256 KB
Loading

src/driver/alloy.rs

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
use crate::{driver::RunTxResult, Block, BlockDriver, EvmNeedsTx, Shanghai};
2+
use alloy_consensus::TxEnvelope;
3+
use alloy_primitives::U256;
4+
use revm::{
5+
primitives::{BlobExcessGasAndPrice, BlockEnv, EVMError},
6+
Database, DatabaseCommit,
7+
};
8+
9+
impl<'a> From<&'a alloy_rpc_types_eth::Block<TxEnvelope>> for Shanghai<'a> {
10+
fn from(block: &'a alloy_rpc_types_eth::Block<TxEnvelope>) -> Self {
11+
block.withdrawals.as_ref().map(|s| Shanghai::new(s)).unwrap_or_default()
12+
}
13+
}
14+
15+
impl Block for alloy_rpc_types_eth::Header {
16+
fn fill_block_env(&self, block_env: &mut revm::primitives::BlockEnv) {
17+
let BlockEnv {
18+
number,
19+
coinbase,
20+
timestamp,
21+
gas_limit,
22+
basefee,
23+
difficulty,
24+
prevrandao,
25+
blob_excess_gas_and_price,
26+
} = block_env;
27+
*number = U256::from(self.number.unwrap_or_default());
28+
*coinbase = self.miner;
29+
*timestamp = U256::from(self.timestamp);
30+
*gas_limit = U256::from(self.gas_limit);
31+
*basefee = U256::from(self.base_fee_per_gas.unwrap_or_default());
32+
*difficulty = U256::from(self.difficulty);
33+
*prevrandao = self.mix_hash;
34+
*blob_excess_gas_and_price =
35+
self.blob_gas_used.map(|ebg| BlobExcessGasAndPrice::new(ebg as u64));
36+
}
37+
}
38+
39+
/// Error during Ethereum consensus checks.
40+
#[derive(thiserror::Error)]
41+
pub enum AlloyBlockError<Db: Database> {
42+
/// An error occurred in the EVM.
43+
#[error("EVM error")]
44+
EvmError(revm::primitives::EVMError<Db::Error>),
45+
46+
/// Block contained only tx hashes, without transactions
47+
#[error("Block contained only tx hashes, without transactions")]
48+
MissingTransactions,
49+
}
50+
51+
impl<Db: Database> std::fmt::Debug for AlloyBlockError<Db> {
52+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
53+
match self {
54+
Self::EvmError(_) => f.debug_struct("EvmError").finish_non_exhaustive(),
55+
Self::MissingTransactions => f.write_str("MissingTransactions"),
56+
}
57+
}
58+
}
59+
60+
impl<Db: Database> From<EVMError<Db::Error>> for AlloyBlockError<Db> {
61+
fn from(e: EVMError<Db::Error>) -> Self {
62+
Self::EvmError(e)
63+
}
64+
}
65+
66+
impl<'b> BlockDriver<'b, Shanghai<'b>> for alloy_rpc_types_eth::Block<TxEnvelope> {
67+
type Block = alloy_rpc_types_eth::Header;
68+
69+
// TODO: Implement this
70+
type Error<Db: Database> = AlloyBlockError<Db>;
71+
72+
fn block(&self) -> &Self::Block {
73+
&self.header
74+
}
75+
76+
fn context(&'b self) -> Shanghai<'b> {
77+
self.withdrawals.as_ref().map(|w| Shanghai::new(w.as_slice())).unwrap_or_default()
78+
}
79+
80+
fn run_txns<'a, Ext, Db: Database + DatabaseCommit>(
81+
&self,
82+
mut trevm: EvmNeedsTx<'a, Ext, Db, Shanghai<'b>>,
83+
) -> RunTxResult<'a, 'b, Ext, Db, Shanghai<'b>, Self> {
84+
if !self.transactions.is_full() {
85+
return Err(trevm.errored(AlloyBlockError::MissingTransactions));
86+
}
87+
88+
for transaction in self.transactions.txns() {
89+
trevm = trevm.run_tx(transaction).map_err(|e| e.err_into())?.accept();
90+
}
91+
Ok(trevm)
92+
}
93+
94+
fn post_block_checks<Ext, Db: Database + DatabaseCommit>(
95+
&self,
96+
_trevm: &crate::EvmBlockComplete<'_, Ext, Db, Shanghai<'b>>,
97+
) -> Result<(), Self::Error<Db>> {
98+
// TODO
99+
Ok(())
100+
}
101+
}

src/driver/block.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
use crate::{Block, BlockContext, EvmBlockComplete, EvmBlockDriverErrored, EvmNeedsTx};
2+
use revm::{primitives::EVMError, Database, DatabaseCommit};
3+
4+
/// The result of running transactions for a block driver.
5+
pub type RunTxResult<'a, 'b, Ext, Db, C, T> =
6+
Result<EvmNeedsTx<'a, Ext, Db, C>, EvmBlockDriverErrored<'a, 'b, Ext, Db, C, T>>;
7+
8+
/// The result of driving a block to completion.
9+
pub type DriveBlockResult<'a, 'b, Ext, Db, C, T> =
10+
Result<EvmBlockComplete<'a, Ext, Db, C>, EvmBlockDriverErrored<'a, 'b, Ext, Db, C, T>>;
11+
12+
/// Driver for a single trevm block. This trait allows a type to specify the
13+
/// entire lifecycle of a trevm block, from opening the block to driving the
14+
/// trevm to completion.
15+
pub trait BlockDriver<'b, C: BlockContext>
16+
where
17+
Self: 'b,
18+
{
19+
/// The [`Block`] filler for this driver.
20+
type Block: Block;
21+
22+
/// An error type for this driver.
23+
type Error<Db: Database>: std::error::Error
24+
+ From<EVMError<Db::Error>>
25+
+ From<<C as BlockContext>::Error<Db>>;
26+
27+
/// Get a reference to the block filler for this driver.
28+
fn block(&self) -> &Self::Block;
29+
30+
/// Get the context for this block.
31+
fn context(&'b self) -> C;
32+
33+
/// Run the transactions for the block.
34+
fn run_txns<'a, Ext, Db: Database + DatabaseCommit>(
35+
&self,
36+
trevm: EvmNeedsTx<'a, Ext, Db, C>,
37+
) -> RunTxResult<'a, 'b, Ext, Db, C, Self>;
38+
39+
/// Run post
40+
fn post_block_checks<Ext, Db: Database + DatabaseCommit>(
41+
&self,
42+
trevm: &EvmBlockComplete<'_, Ext, Db, C>,
43+
) -> Result<(), Self::Error<Db>>;
44+
}

src/driver/chain.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
use crate::{BlockContext, BlockDriver, EvmBlockComplete, EvmChainDriverErrored, EvmNeedsBlock};
2+
use revm::{
3+
primitives::{EVMError, SpecId},
4+
Database, DatabaseCommit,
5+
};
6+
7+
/// The result of driving a chain to completion.
8+
pub type DriveChainResult<'a, 'b, Ext, Db, C, D> =
9+
Result<(Vec<C>, EvmNeedsBlock<'a, Ext, Db>), EvmChainDriverErrored<'a, 'b, Ext, Db, C, D>>;
10+
11+
/// Driver for a chain of blocks.
12+
pub trait ChainDriver<'b, C: BlockContext> {
13+
/// The block driver for this chain.
14+
type BlockDriver: BlockDriver<'b, C>;
15+
16+
/// An error type for this driver.
17+
type Error<Db: Database>: std::error::Error
18+
+ From<EVMError<Db::Error>>
19+
+ From<<C as BlockContext>::Error<Db>>
20+
+ From<<Self::BlockDriver as BlockDriver<'b, C>>::Error<Db>>;
21+
22+
/// Get the spec id for a block.
23+
fn spec_id_for(&self, block: &<Self::BlockDriver as BlockDriver<'b, C>>::Block) -> SpecId;
24+
25+
/// Get the blocks in this chain. The blocks should be in order, and this
26+
/// function MUST NOT return an empty slice.
27+
fn blocks(&self) -> &[Self::BlockDriver];
28+
29+
/// Checks that run between blocks, e.g. 1559 base fee calculation,
30+
/// or parent-child relationships.
31+
///
32+
/// The `idx` parameter is the index of the block in the chain.
33+
fn check_interblock<Ext, Db: Database + DatabaseCommit>(
34+
&self,
35+
trevm: &EvmBlockComplete<'_, Ext, Db, C>,
36+
idx: usize,
37+
) -> Result<(), Self::Error<Db>>;
38+
}

src/driver/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
mod alloy;
2+
pub use alloy::AlloyBlockError;
3+
4+
mod block;
5+
pub use block::{BlockDriver, DriveBlockResult, RunTxResult};
6+
7+
mod chain;
8+
pub use chain::{ChainDriver, DriveChainResult};

0 commit comments

Comments
 (0)