Skip to content

Commit

Permalink
Block and Chain drivers (#29)
Browse files Browse the repository at this point in the history
* feat: modify_spec_id

* wip: block and chain drivers

* feature: block and chain drivers

* chore: update ascii diagram

* chore: update state diagram

* fix: aliases
  • Loading branch information
prestwich authored Aug 1, 2024
1 parent d85f775 commit 2840b30
Show file tree
Hide file tree
Showing 11 changed files with 519 additions and 163 deletions.
4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "trevm"
version = "0.1.1"
version = "0.2.0"
rust-version = "1.79.0"
edition = "2021"
authors = ["init4"]
Expand Down Expand Up @@ -30,8 +30,10 @@ redundant-clone = "warn"
alloy-consensus = { version = "0.2", features = ["k256"] }
alloy-eips = "0.2.0"
alloy-primitives = "0.7.6"
alloy-rpc-types-eth = "0.2.0"
alloy-sol-types = "0.7.7"
revm = { version = "12.0.0", default-features = false, features = ["std"] }
thiserror = "1.0.63"
zenith-types = "0.2.2"

[dev-dependencies]
Expand Down
Binary file modified assets/states.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
101 changes: 101 additions & 0 deletions src/driver/alloy.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
use crate::{driver::RunTxResult, Block, BlockDriver, EvmNeedsTx, Shanghai};
use alloy_consensus::TxEnvelope;
use alloy_primitives::U256;
use revm::{
primitives::{BlobExcessGasAndPrice, BlockEnv, EVMError},
Database, DatabaseCommit,
};

impl<'a> From<&'a alloy_rpc_types_eth::Block<TxEnvelope>> for Shanghai<'a> {
fn from(block: &'a alloy_rpc_types_eth::Block<TxEnvelope>) -> Self {
block.withdrawals.as_ref().map(|s| Shanghai::new(s)).unwrap_or_default()
}
}

impl Block for alloy_rpc_types_eth::Header {
fn fill_block_env(&self, block_env: &mut revm::primitives::BlockEnv) {
let BlockEnv {
number,
coinbase,
timestamp,
gas_limit,
basefee,
difficulty,
prevrandao,
blob_excess_gas_and_price,
} = block_env;
*number = U256::from(self.number.unwrap_or_default());
*coinbase = self.miner;
*timestamp = U256::from(self.timestamp);
*gas_limit = U256::from(self.gas_limit);
*basefee = U256::from(self.base_fee_per_gas.unwrap_or_default());
*difficulty = U256::from(self.difficulty);
*prevrandao = self.mix_hash;
*blob_excess_gas_and_price =
self.blob_gas_used.map(|ebg| BlobExcessGasAndPrice::new(ebg as u64));
}
}

/// Error during Ethereum consensus checks.
#[derive(thiserror::Error)]
pub enum AlloyBlockError<Db: Database> {
/// An error occurred in the EVM.
#[error("EVM error")]
EvmError(revm::primitives::EVMError<Db::Error>),

/// Block contained only tx hashes, without transactions
#[error("Block contained only tx hashes, without transactions")]
MissingTransactions,
}

impl<Db: Database> std::fmt::Debug for AlloyBlockError<Db> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::EvmError(_) => f.debug_struct("EvmError").finish_non_exhaustive(),
Self::MissingTransactions => f.write_str("MissingTransactions"),
}
}
}

impl<Db: Database> From<EVMError<Db::Error>> for AlloyBlockError<Db> {
fn from(e: EVMError<Db::Error>) -> Self {
Self::EvmError(e)
}
}

impl<'b> BlockDriver<'b, Shanghai<'b>> for alloy_rpc_types_eth::Block<TxEnvelope> {
type Block = alloy_rpc_types_eth::Header;

// TODO: Implement this
type Error<Db: Database> = AlloyBlockError<Db>;

fn block(&self) -> &Self::Block {
&self.header
}

fn context(&'b self) -> Shanghai<'b> {
self.withdrawals.as_ref().map(|w| Shanghai::new(w.as_slice())).unwrap_or_default()
}

fn run_txns<'a, Ext, Db: Database + DatabaseCommit>(
&self,
mut trevm: EvmNeedsTx<'a, Ext, Db, Shanghai<'b>>,
) -> RunTxResult<'a, 'b, Ext, Db, Shanghai<'b>, Self> {
if !self.transactions.is_full() {
return Err(trevm.errored(AlloyBlockError::MissingTransactions));
}

for transaction in self.transactions.txns() {
trevm = trevm.run_tx(transaction).map_err(|e| e.err_into())?.accept();
}
Ok(trevm)
}

fn post_block_checks<Ext, Db: Database + DatabaseCommit>(
&self,
_trevm: &crate::EvmBlockComplete<'_, Ext, Db, Shanghai<'b>>,
) -> Result<(), Self::Error<Db>> {
// TODO
Ok(())
}
}
44 changes: 44 additions & 0 deletions src/driver/block.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use crate::{Block, BlockContext, EvmBlockComplete, EvmBlockDriverErrored, EvmNeedsTx};
use revm::{primitives::EVMError, Database, DatabaseCommit};

/// The result of running transactions for a block driver.
pub type RunTxResult<'a, 'b, Ext, Db, C, T> =
Result<EvmNeedsTx<'a, Ext, Db, C>, EvmBlockDriverErrored<'a, 'b, Ext, Db, C, T>>;

/// The result of driving a block to completion.
pub type DriveBlockResult<'a, 'b, Ext, Db, C, T> =
Result<EvmBlockComplete<'a, Ext, Db, C>, EvmBlockDriverErrored<'a, 'b, Ext, Db, C, T>>;

/// Driver for a single trevm block. This trait allows a type to specify the
/// entire lifecycle of a trevm block, from opening the block to driving the
/// trevm to completion.
pub trait BlockDriver<'b, C: BlockContext>
where
Self: 'b,
{
/// The [`Block`] filler for this driver.
type Block: Block;

/// An error type for this driver.
type Error<Db: Database>: std::error::Error
+ From<EVMError<Db::Error>>
+ From<<C as BlockContext>::Error<Db>>;

/// Get a reference to the block filler for this driver.
fn block(&self) -> &Self::Block;

/// Get the context for this block.
fn context(&'b self) -> C;

/// Run the transactions for the block.
fn run_txns<'a, Ext, Db: Database + DatabaseCommit>(
&self,
trevm: EvmNeedsTx<'a, Ext, Db, C>,
) -> RunTxResult<'a, 'b, Ext, Db, C, Self>;

/// Run post
fn post_block_checks<Ext, Db: Database + DatabaseCommit>(
&self,
trevm: &EvmBlockComplete<'_, Ext, Db, C>,
) -> Result<(), Self::Error<Db>>;
}
38 changes: 38 additions & 0 deletions src/driver/chain.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
use crate::{BlockContext, BlockDriver, EvmBlockComplete, EvmChainDriverErrored, EvmNeedsBlock};
use revm::{
primitives::{EVMError, SpecId},
Database, DatabaseCommit,
};

/// The result of driving a chain to completion.
pub type DriveChainResult<'a, 'b, Ext, Db, C, D> =
Result<(Vec<C>, EvmNeedsBlock<'a, Ext, Db>), EvmChainDriverErrored<'a, 'b, Ext, Db, C, D>>;

/// Driver for a chain of blocks.
pub trait ChainDriver<'b, C: BlockContext> {
/// The block driver for this chain.
type BlockDriver: BlockDriver<'b, C>;

/// An error type for this driver.
type Error<Db: Database>: std::error::Error
+ From<EVMError<Db::Error>>
+ From<<C as BlockContext>::Error<Db>>
+ From<<Self::BlockDriver as BlockDriver<'b, C>>::Error<Db>>;

/// Get the spec id for a block.
fn spec_id_for(&self, block: &<Self::BlockDriver as BlockDriver<'b, C>>::Block) -> SpecId;

/// Get the blocks in this chain. The blocks should be in order, and this
/// function MUST NOT return an empty slice.
fn blocks(&self) -> &[Self::BlockDriver];

/// Checks that run between blocks, e.g. 1559 base fee calculation,
/// or parent-child relationships.
///
/// The `idx` parameter is the index of the block in the chain.
fn check_interblock<Ext, Db: Database + DatabaseCommit>(
&self,
trevm: &EvmBlockComplete<'_, Ext, Db, C>,
idx: usize,
) -> Result<(), Self::Error<Db>>;
}
8 changes: 8 additions & 0 deletions src/driver/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
mod alloy;
pub use alloy::AlloyBlockError;

mod block;
pub use block::{BlockDriver, DriveBlockResult, RunTxResult};

mod chain;
pub use chain::{ChainDriver, DriveChainResult};
Loading

0 comments on commit 2840b30

Please sign in to comment.