-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(wip): Introduce a generic chain spec in the
edr_generic
crate
- Loading branch information
Showing
17 changed files
with
876 additions
and
3 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
[package] | ||
name = "edr_generic" | ||
version = "0.3.5" | ||
edition = "2021" | ||
description = "A generic chain specification for Ethereum Layer 1 chains." | ||
|
||
[dependencies] | ||
alloy-rlp = { version = "0.3", default-features = false, features = ["derive"] } | ||
edr_eth = { path = "../edr_eth" } | ||
edr_evm = { path = "../edr_evm" } | ||
edr_rpc_eth = { path = "../edr_rpc_eth" } | ||
log = { version = "0.4.17", default-features = false } | ||
revm = { git = "https://github.com/Wodann/revm", rev = "a500675", version = "12.1", default-features = false, features = ["c-kzg", "dev", "serde"] } | ||
revm-primitives = { git = "https://github.com/Wodann/revm", rev = "a500675", version = "7.1", default-features = false, features = ["c-kzg", "hashbrown"] } | ||
serde = { version = "1.0.209", default-features = false, features = ["derive"] } | ||
thiserror = { version = "1.0.37", default-features = false } | ||
|
||
[dev-dependencies] | ||
anyhow = "1.0.75" | ||
edr_defaults = { path = "../edr_defaults" } | ||
edr_evm = { path = "../edr_evm", features = ["test-utils"] } | ||
edr_rpc_eth = { path = "../edr_rpc_eth", features = ["test-utils"] } | ||
edr_test_utils = { path = "../edr_test_utils" } | ||
parking_lot = { version = "0.12.1", default-features = false } | ||
paste = { version = "1.0.14", default-features = false } | ||
serde_json = { version = "1.0.127" } | ||
serial_test = "2.0.0" | ||
tokio = { version = "1.21.2", default-features = false, features = ["macros", "rt-multi-thread", "sync"] } | ||
|
||
[features] | ||
test-remote = [] | ||
|
||
[lints] | ||
workspace = true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
use alloy_rlp::Buf as _; | ||
use edr_eth::{ | ||
receipt::{MapReceiptLogs, Receipt, RootOrStatus}, | ||
transaction::TransactionType, | ||
Bloom, | ||
}; | ||
|
||
use crate::transaction; | ||
|
||
/// An compile-time typed EIP-2718 envelope for L1 Ethereum. | ||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] | ||
pub enum TypedEnvelope<DataT> { | ||
/// Legacy transaction. | ||
Legacy(DataT), | ||
/// EIP-2930 transaction. | ||
Eip2930(DataT), | ||
/// EIP-1559 transaction. | ||
Eip1559(DataT), | ||
/// EIP-4844 transaction. | ||
Eip4844(DataT), | ||
/// Unrecognized transaction type. | ||
Unrecognized(DataT), | ||
} | ||
|
||
impl<DataT> TypedEnvelope<DataT> { | ||
/// Constructs a typed envelope around the given data. | ||
pub fn new(data: DataT, transaction_type: transaction::Type) -> Self { | ||
match transaction_type { | ||
transaction::Type::Legacy => Self::Legacy(data), | ||
transaction::Type::Eip2930 => Self::Eip2930(data), | ||
transaction::Type::Eip1559 => Self::Eip1559(data), | ||
transaction::Type::Eip4844 => Self::Eip4844(data), | ||
transaction::Type::Unrecognized(_) => Self::Unrecognized(data), | ||
} | ||
} | ||
|
||
/// Returns a reference to the data inside the envelope. | ||
pub fn data(&self) -> &DataT { | ||
match self { | ||
TypedEnvelope::Legacy(data) | ||
| TypedEnvelope::Eip2930(data) | ||
| TypedEnvelope::Eip1559(data) | ||
| TypedEnvelope::Eip4844(data) | ||
| TypedEnvelope::Unrecognized(data) => data, | ||
} | ||
} | ||
|
||
/// Maps the data inside the envelope to a new type. | ||
pub fn map<NewDataT, F>(self, f: F) -> TypedEnvelope<NewDataT> | ||
where | ||
F: FnOnce(DataT) -> NewDataT, | ||
{ | ||
match self { | ||
TypedEnvelope::Legacy(data) => TypedEnvelope::Legacy(f(data)), | ||
TypedEnvelope::Eip2930(data) => TypedEnvelope::Eip2930(f(data)), | ||
TypedEnvelope::Eip1559(data) => TypedEnvelope::Eip1559(f(data)), | ||
TypedEnvelope::Eip4844(data) => TypedEnvelope::Eip4844(f(data)), | ||
TypedEnvelope::Unrecognized(data) => TypedEnvelope::Unrecognized(f(data)), | ||
} | ||
} | ||
} | ||
|
||
impl<DataT> TransactionType for TypedEnvelope<DataT> { | ||
type Type = transaction::Type; | ||
|
||
fn transaction_type(&self) -> Self::Type { | ||
match self { | ||
TypedEnvelope::Legacy(_) => transaction::Type::Legacy, | ||
TypedEnvelope::Eip2930(_) => transaction::Type::Eip2930, | ||
TypedEnvelope::Eip1559(_) => transaction::Type::Eip1559, | ||
TypedEnvelope::Eip4844(_) => transaction::Type::Eip4844, | ||
TypedEnvelope::Unrecognized(_) => todo!(), | ||
} | ||
} | ||
} | ||
|
||
impl<DataT> alloy_rlp::Decodable for TypedEnvelope<DataT> | ||
where | ||
DataT: alloy_rlp::Decodable, | ||
{ | ||
fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> { | ||
fn is_list(byte: u8) -> bool { | ||
byte >= 0xc0 | ||
} | ||
|
||
let first = *buf.first().ok_or(alloy_rlp::Error::InputTooShort)?; | ||
let transaction_type = if is_list(first) { | ||
transaction::Type::Legacy | ||
} else { | ||
// Consume the first byte | ||
buf.advance(1); | ||
|
||
crate::transaction::Type::from(first) | ||
}; | ||
|
||
let data = DataT::decode(buf)?; | ||
Ok(TypedEnvelope::new(data, transaction_type)) | ||
} | ||
} | ||
|
||
impl<DataT> alloy_rlp::Encodable for TypedEnvelope<DataT> | ||
where | ||
DataT: alloy_rlp::Encodable, | ||
{ | ||
fn encode(&self, out: &mut dyn alloy_rlp::BufMut) { | ||
let transaction_type: u8 = self.transaction_type().into(); | ||
if transaction_type > 0 { | ||
out.put_u8(transaction_type); | ||
} | ||
|
||
self.data().encode(out); | ||
} | ||
|
||
fn length(&self) -> usize { | ||
let type_length = usize::from(u8::from(self.transaction_type()) > 0u8); | ||
type_length + self.data().length() | ||
} | ||
} | ||
|
||
impl<DataT: Receipt<LogT>, LogT> Receipt<LogT> for TypedEnvelope<DataT> { | ||
fn cumulative_gas_used(&self) -> u64 { | ||
self.data().cumulative_gas_used() | ||
} | ||
|
||
fn logs_bloom(&self) -> &Bloom { | ||
self.data().logs_bloom() | ||
} | ||
|
||
fn transaction_logs(&self) -> &[LogT] { | ||
self.data().transaction_logs() | ||
} | ||
|
||
fn root_or_status(&self) -> RootOrStatus<'_> { | ||
self.data().root_or_status() | ||
} | ||
} | ||
|
||
impl<OldDataT: MapReceiptLogs<OldLogT, NewLogT, NewDataT>, OldLogT, NewLogT, NewDataT> | ||
MapReceiptLogs<OldLogT, NewLogT, TypedEnvelope<NewDataT>> for TypedEnvelope<OldDataT> | ||
{ | ||
fn map_logs(self, map_fn: impl FnMut(OldLogT) -> NewLogT) -> TypedEnvelope<NewDataT> { | ||
self.map(|data| data.map_logs(map_fn)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
//! A slightly more flexible chain specification for Ethereum Layer 1 chain. | ||
mod eip2718; | ||
mod receipt; | ||
mod rpc; | ||
mod spec; | ||
mod transaction; | ||
|
||
/// The chain specification for Ethereum Layer 1 that is a bit more lenient | ||
/// and allows for more flexibility in contrast to | ||
/// [`L1ChainSpec`](edr_eth::chain_spec::L1ChainSpec). | ||
/// | ||
/// Specifically: | ||
/// - it allows unknown transaction types (treates them as legacy | ||
/// [`Eip155`](edr_eth::transaction::signed::Eip155) transactions) | ||
/// - it allows remote blocks with missing `nonce` and `mix_hash` fields (**Not | ||
/// implemented yet**) | ||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, alloy_rlp::RlpEncodable)] | ||
pub struct GenericChainSpec; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
pub use edr_eth::receipt::BlockReceipt; | ||
|
||
pub mod execution; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
use revm_primitives::{EvmWiring, SpecId}; | ||
|
||
use edr_eth::{ | ||
log::ExecutionLog, | ||
receipt::{ | ||
execution::{Eip658, Legacy}, | ||
Execution, ExecutionReceiptBuilder, | ||
}, | ||
transaction::TransactionType, | ||
}; | ||
|
||
use crate::eip2718::TypedEnvelope; | ||
use crate::GenericChainSpec; | ||
|
||
pub struct Builder; | ||
|
||
impl ExecutionReceiptBuilder<GenericChainSpec> for Builder { | ||
type Receipt = TypedEnvelope<Execution<ExecutionLog>>; | ||
|
||
fn new_receipt_builder<StateT: revm::db::StateRef>( | ||
_pre_execution_state: StateT, | ||
_transaction: &<GenericChainSpec as EvmWiring>::Transaction, | ||
) -> Result<Self, StateT::Error> { | ||
Ok(Self) | ||
} | ||
|
||
fn build_receipt( | ||
self, | ||
header: &edr_eth::block::PartialHeader, | ||
transaction: &crate::transaction::SignedFallbackToPostEip155, | ||
result: &revm_primitives::ExecutionResult<GenericChainSpec>, | ||
hardfork: SpecId, | ||
) -> Self::Receipt { | ||
let logs = result.logs().to_vec(); | ||
let logs_bloom = edr_eth::log::logs_to_bloom(&logs); | ||
|
||
let receipt = if hardfork >= SpecId::BYZANTIUM { | ||
Execution::Eip658(Eip658 { | ||
status: result.is_success(), | ||
cumulative_gas_used: header.gas_used, | ||
logs_bloom, | ||
logs, | ||
}) | ||
} else { | ||
Execution::Legacy(Legacy { | ||
root: header.state_root, | ||
cumulative_gas_used: header.gas_used, | ||
logs_bloom, | ||
logs, | ||
}) | ||
}; | ||
|
||
TypedEnvelope::new(receipt, transaction.transaction_type()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
use edr_rpc_eth::RpcSpec; | ||
use serde::{de::DeserializeOwned, Serialize}; | ||
|
||
use crate::eip2718::TypedEnvelope; | ||
use crate::GenericChainSpec; | ||
|
||
pub mod receipt; | ||
pub mod transaction; | ||
|
||
impl RpcSpec for GenericChainSpec { | ||
type ExecutionReceipt<Log> = TypedEnvelope<edr_eth::receipt::Execution<Log>>; | ||
type RpcBlock<Data> = edr_rpc_eth::Block<Data> where Data: Default + DeserializeOwned + Serialize; | ||
type RpcCallRequest = edr_rpc_eth::CallRequest; | ||
type RpcReceipt = self::receipt::BlockReceipt; | ||
type RpcTransaction = self::transaction::TransactionWithSignature; | ||
type RpcTransactionRequest = edr_rpc_eth::TransactionRequest; | ||
} |
Oops, something went wrong.