Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Block and Chain drivers #29

Merged
merged 6 commits into from
Aug 1, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
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