-
Notifications
You must be signed in to change notification settings - Fork 256
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add initial EIP-7547 engine types (#287)
* feat: add initial EIP-7547 engine types * move to eip7547 crate * update all definitions to match the spec * fix readme * fix package name * fix: use QUANTITY for nonce, proposer index, slot * fix: use u64_hex
- Loading branch information
Showing
6 changed files
with
254 additions
and
0 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
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,23 @@ | ||
[package] | ||
name = "alloy-eip7547" | ||
description = "EIP-7547: Inclusion Lists types" | ||
|
||
version.workspace = true | ||
edition.workspace = true | ||
rust-version.workspace = true | ||
authors.workspace = true | ||
license.workspace = true | ||
homepage.workspace = true | ||
repository.workspace = true | ||
exclude.workspace = true | ||
|
||
[dependencies] | ||
alloy-primitives = { workspace = true, features = ["rlp", "serde"] } | ||
alloy-rpc-engine-types = { workspace = true } | ||
alloy-serde = { workspace = true } | ||
|
||
# serde | ||
serde = { workspace = true } | ||
|
||
[dev-dependencies] | ||
serde_json = { 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,5 @@ | ||
# alloy-eip7547 | ||
|
||
Includes the EIP-7547 engine types. | ||
|
||
Currently based on the [EIP-7547 engine API spec](https://github.com/michaelneuder/execution-apis/pull/1). |
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,15 @@ | ||
//! Constants related to EIP-7547. | ||
/// The maximum gas allowed for the inclusion list. | ||
/// | ||
/// Based on the following part of the spec: | ||
/// | ||
/// ## Constants | ||
/// | ||
/// | Name | Value | | ||
/// | - | - | | ||
/// | `INCLUSION_LIST_MAX_GAS` | `uint64(4194304) = 2**22` | | ||
pub const INCLUSION_LIST_MAX_GAS: u64 = 4194304; | ||
|
||
/// The capabilities for inclusion list engine API endpoints. | ||
pub const CAPABILITIES: [&str; 2] = ["engine_newInclusionListV1", "engine_getInclusionListV1"]; |
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,20 @@ | ||
#![doc = include_str!("../README.md")] | ||
#![doc( | ||
html_logo_url = "https://raw.githubusercontent.com/alloy-rs/core/main/assets/alloy.jpg", | ||
html_favicon_url = "https://raw.githubusercontent.com/alloy-rs/core/main/assets/favicon.ico" | ||
)] | ||
#![warn( | ||
missing_copy_implementations, | ||
missing_debug_implementations, | ||
missing_docs, | ||
unreachable_pub, | ||
clippy::missing_const_for_fn, | ||
rustdoc::all | ||
)] | ||
#![cfg_attr(not(test), warn(unused_crate_dependencies))] | ||
#![deny(unused_must_use, rust_2018_idioms)] | ||
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] | ||
|
||
pub mod constants; | ||
|
||
pub mod summary; |
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,190 @@ | ||
//! Contains types related to the Inclusion lists that will be used by in the engine API RPC | ||
//! definitions. | ||
use alloy_primitives::{Address, B256}; | ||
use alloy_rpc_engine_types::PayloadStatusEnum; | ||
use alloy_serde::u64_hex; | ||
use serde::{ser::SerializeMap, Deserialize, Serialize, Serializer}; | ||
use std::fmt; | ||
|
||
/// This structure contains the result of processing an `engine_newInclusionListV1` RPC call. | ||
/// | ||
/// From the spec: | ||
/// | ||
/// ### InclusionListStatusV1 | ||
/// | ||
/// This structure contains the result of processing an inclusion list. The fields are encoded as | ||
/// follows: | ||
/// - `status`: `enum` - `"VALID" | "INVALID" | "SYNCING" | "ACCEPTED"` | ||
/// - `validationError`: `String|null` - a message providing additional details on the validation | ||
/// error if the payload is classified as `INVALID`. | ||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize)] | ||
#[serde(rename_all = "camelCase")] | ||
pub struct InclusionListStatusV1 { | ||
/// The status of the payload. | ||
#[serde(flatten)] | ||
pub status: PayloadStatusEnum, | ||
} | ||
|
||
impl InclusionListStatusV1 { | ||
/// Initializes a new inclusion list status. | ||
pub const fn new(status: PayloadStatusEnum) -> Self { | ||
Self { status } | ||
} | ||
|
||
/// Returns true if the payload status is syncing. | ||
pub const fn is_syncing(&self) -> bool { | ||
self.status.is_syncing() | ||
} | ||
|
||
/// Returns true if the payload status is valid. | ||
pub const fn is_valid(&self) -> bool { | ||
self.status.is_valid() | ||
} | ||
|
||
/// Returns true if the payload status is invalid. | ||
pub const fn is_invalid(&self) -> bool { | ||
self.status.is_invalid() | ||
} | ||
} | ||
|
||
impl fmt::Display for InclusionListStatusV1 { | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
write!(f, "InclusionListStatusV1 {{ status: {} }}", self.status) | ||
} | ||
} | ||
|
||
impl Serialize for InclusionListStatusV1 { | ||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> | ||
where | ||
S: Serializer, | ||
{ | ||
let mut map = serializer.serialize_map(Some(3))?; | ||
map.serialize_entry("status", self.status.as_str())?; | ||
map.serialize_entry("validationError", &self.status.validation_error())?; | ||
map.end() | ||
} | ||
} | ||
|
||
/// This is an individual entry in the inclusion list summary, representing a transaction that | ||
/// should be included in this block or the next block. | ||
/// | ||
/// From the spec: | ||
/// | ||
/// ### InclusionListSummaryEntryV1 | ||
/// | ||
/// This structure contains the details of each inclusion list entry. | ||
/// | ||
/// - `address` : `DATA`, 20 Bytes | ||
/// - `nonce` : `QUANTITY`, 64 Bits | ||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] | ||
#[serde(rename_all = "camelCase")] | ||
pub struct InclusionListSummaryEntryV1 { | ||
/// The address of the inclusion list entry. | ||
pub address: Address, | ||
/// The nonce of the inclusion list entry. | ||
#[serde(with = "u64_hex")] | ||
pub nonce: u64, | ||
} | ||
|
||
impl fmt::Display for InclusionListSummaryEntryV1 { | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
write!(f, "InclusionListEntryV1 {{ address: {}, nonce: {} }}", self.address, self.nonce) | ||
} | ||
} | ||
|
||
/// This structure contains the inclusion list summary input to the `engine_newInclusionListV1` RPC | ||
/// call. | ||
/// | ||
/// ### InclusionListSummaryV1 | ||
/// | ||
/// This structure contains the inclusion list summary. | ||
/// | ||
/// - `slot` : `QUANTITY`, 64 Bits | ||
/// - `proposer_index`: `QUANTITY`, 64 Bits | ||
/// - `parent_hash`: `DATA`, 32 Bytes | ||
/// - `summary`: `Array of InclusionListSummaryEntryV1`, Array of entries that must be satisfied. | ||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] | ||
#[serde(rename_all = "camelCase")] | ||
pub struct InclusionListSummaryV1 { | ||
/// The slot of the inclusion list summary. | ||
#[serde(with = "u64_hex")] | ||
pub slot: u64, | ||
/// The proposer index of the inclusion list summary. | ||
#[serde(with = "u64_hex")] | ||
pub proposer_index: u64, | ||
/// The parent hash of the inclusion list summary. | ||
pub parent_hash: B256, | ||
/// The summary of the inclusion list summary. | ||
pub summary: Vec<InclusionListSummaryEntryV1>, | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
use alloy_primitives::hex::FromHex; | ||
use serde_json::json; | ||
|
||
#[test] | ||
fn inclusion_list_status_v1_serialization() { | ||
let status = InclusionListStatusV1::new(PayloadStatusEnum::Valid); | ||
let json = json!({ | ||
"status": "VALID", | ||
"validationError": null, | ||
}); | ||
assert_eq!(serde_json::to_value(status).unwrap(), json); | ||
} | ||
|
||
#[test] | ||
fn inclusion_list_entry_v1_serialization() { | ||
let entry = InclusionListSummaryEntryV1 { | ||
address: Address::from_hex("0x0000000000000000000000000000000000000042").unwrap(), | ||
nonce: 42, | ||
}; | ||
let json = json!({ | ||
"address": "0x0000000000000000000000000000000000000042", | ||
"nonce": "0x2a", | ||
}); | ||
assert_eq!(serde_json::to_value(entry).unwrap(), json); | ||
} | ||
|
||
#[test] | ||
fn inclusion_list_summary_v1_serialization() { | ||
let summary = InclusionListSummaryV1 { | ||
slot: 42, | ||
proposer_index: 42, | ||
parent_hash: B256::from_hex( | ||
"0x2222222222222222222222222222222222222222222222222222222222222222", | ||
) | ||
.unwrap(), | ||
summary: vec![ | ||
InclusionListSummaryEntryV1 { | ||
address: Address::from_hex("0x0000000000000000000000000000000000000042") | ||
.unwrap(), | ||
nonce: 42, | ||
}, | ||
InclusionListSummaryEntryV1 { | ||
address: Address::from_hex("0x0000000000000000000000000000000000000043") | ||
.unwrap(), | ||
nonce: 43, | ||
}, | ||
], | ||
}; | ||
let json = json!({ | ||
"slot": "0x2a", | ||
"proposerIndex": "0x2a", | ||
"parentHash": "0x2222222222222222222222222222222222222222222222222222222222222222", | ||
"summary": [ | ||
{ | ||
"address": "0x0000000000000000000000000000000000000042", | ||
"nonce": "0x2a", | ||
}, | ||
{ | ||
"address": "0x0000000000000000000000000000000000000043", | ||
"nonce": "0x2b", | ||
}, | ||
], | ||
}); | ||
assert_eq!(serde_json::to_value(summary).unwrap(), json); | ||
} | ||
} |