-
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.
[multi-chain] Implement a generic chain spec (#653)
* feat(wip): Introduce a generic chain spec in the `edr_generic` crate * feat: Allow for missing nonce/mixHash in remote blocks * fixup: Formatting * fix: Make sure to accept rpc blocks with txs being 32-byte hashes * fixup: Maintain symmetry between mod::ConversionErrors used internally * Update crates/edr_generic/src/lib.rs Co-authored-by: Wodann <Wodann@users.noreply.github.com> * Update crates/edr_generic/src/rpc/block.rs Co-authored-by: Wodann <Wodann@users.noreply.github.com> * fixup: Rename SignedWithFallbackToPostEip155 * feat: Implement ProviderSpec for GenericChainSpec * feat: Implement SyncNapiSpec for GenericChainSpec and use in `edr_napi` * fixup: Use the generic chain spec in the local Hardhat patch * fixup: Re-generate patch hash * fixup: Update test/provider.ts * ci: run EDR TS tests * ci: add Alchemy URL * revert: deletion of L1 chain in N-API * ci: cache RPC calls in TS tests * refactor: Prefer const in pattern match over a guard in tx RLP decode This is more consistent with the other uses and increases visibility to the underlying static str value. --------- Co-authored-by: Wodann <Wodann@users.noreply.github.com>
- Loading branch information
Showing
34 changed files
with
1,687 additions
and
106 deletions.
There are no files selected for viewing
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
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 was deleted.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
[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"] } | ||
derive-where = { version = "1.2.7", default-features = false } | ||
edr_eth = { path = "../edr_eth" } | ||
edr_evm = { path = "../edr_evm" } | ||
edr_provider = { path = "../edr_provider" } | ||
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_rpc_client = { path = "../edr_rpc_client" } | ||
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,145 @@ | ||
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, | ||
// TODO: Should we properly decode the transaction type? | ||
TypedEnvelope::Unrecognized(_) => transaction::Type::Unrecognized(0xFF), | ||
} | ||
} | ||
} | ||
|
||
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,18 @@ | ||
//! 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 (treats them as legacy | ||
/// [`Eip155`](edr_eth::transaction::signed::Eip155) transactions) | ||
/// - it allows remote blocks with missing `nonce` and `mix_hash` fields | ||
#[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; |
Oops, something went wrong.