Skip to content

Commit

Permalink
Revert pull #365
Browse files Browse the repository at this point in the history
  • Loading branch information
emhane committed Jan 13, 2025
1 parent 835c340 commit 1996adc
Show file tree
Hide file tree
Showing 8 changed files with 357 additions and 0 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ rustdoc-args = ["--cfg", "docsrs"]
op-alloy-genesis = { version = "0.9.2", path = "crates/genesis", default-features = false }
op-alloy-consensus = { version = "0.9.2", path = "crates/consensus", default-features = false }
op-alloy-network = { version = "0.9.2", path = "crates/network", default-features = false }
op-alloy-provider = { version = "0.9.2", path = "crates/provider", default-features = false }
op-alloy-rpc-types = { version = "0.9.2", path = "crates/rpc-types", default-features = false }
op-alloy-rpc-types-engine = { version = "0.9.2", path = "crates/rpc-types-engine", default-features = false }

Expand Down
1 change: 1 addition & 0 deletions book/src/links.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
[op-alloy-consensus]: https://crates.io/crates/op-alloy-consensus
[op-alloy-genesis]: https://crates.io/crates/op-alloy-genesis
[op-alloy-network]: https://crates.io/crates/op-alloy-network
[op-alloy-provider]: https://crates.io/crates/op-alloy-provider
[op-alloy-protocol]: https://crates.io/crates/op-alloy-protocol
[op-alloy-rpc-types-engine]: https://crates.io/crates/op-alloy-rpc-types-engine
[op-alloy-rpc-types]: https://crates.io/crates/op-alloy-rpc-types
Expand Down
1 change: 1 addition & 0 deletions book/src/starting.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ so `op-alloy-consensus` types can be used from `op-alloy` through `op_alloy::con
- [`op-alloy-network`][op-alloy-network]
- [`op-alloy-genesis`][op-alloy-genesis] (supports `no_std`)
- [`op-alloy-protocol`][op-alloy-protocol] (supports `no_std`)
- [`op-alloy-provider`][op-alloy-protocol]
- [`op-alloy-consensus`][op-alloy-consensus] (supports `no_std`)
- [`op-alloy-rpc-types`][op-alloy-rpc-types] (supports `no_std`)
- [`op-alloy-rpc-types-engine`][op-alloy-rpc-types-engine] (supports `no_std`)
Expand Down
32 changes: 32 additions & 0 deletions crates/provider/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
[package]
name = "op-alloy-provider"
description = "Interface with an OP Stack blockchain"

version.workspace = true
edition.workspace = true
rust-version.workspace = true
license.workspace = true
homepage.workspace = true
authors.workspace = true
repository.workspace = true
exclude.workspace = true

[lints]
workspace = true

[dependencies]
# Workspace
op-alloy-rpc-types-engine = { workspace = true, features = ["serde"] }

# Alloy
alloy-network.workspace = true
alloy-provider.workspace = true
alloy-transport.workspace = true
alloy-primitives = { workspace = true, features = ["rlp", "serde"] }
alloy-rpc-types-engine = { workspace = true, features = ["serde"] }

# Maili
maili-provider.workspace = true

# misc
async-trait.workspace = true
12 changes: 12 additions & 0 deletions crates/provider/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
## `op-alloy-provider`

<a href="https://github.com/alloy-rs/op-alloy/actions/workflows/ci.yml"><img src="https://github.com/alloy-rs/op-alloy/actions/workflows/ci.yml/badge.svg?label=ci" alt="CI"></a>
<a href="https://crates.io/crates/op-alloy-provider"><img src="https://img.shields.io/crates/v/op-alloy-provider.svg" alt="op-alloy-provider crate"></a>
<a href="https://github.com/alloy-rs/op-alloy/blob/main/LICENSE-MIT"><img src="https://img.shields.io/badge/License-MIT-d1d1f6.svg?label=license&labelColor=2a2f35" alt="MIT License"></a>
<a href="https://github.com/alloy-rs/op-alloy/blob/main/LICENSE-APACHE"><img src="https://img.shields.io/badge/License-APACHE-d1d1f6.svg?label=license&labelColor=2a2f35" alt="Apache License"></a>
<a href="https://alloy-rs.github.io/op-alloy"><img src="https://img.shields.io/badge/Book-854a15?logo=mdBook&labelColor=2a2f35" alt="Book"></a>


Optimism providers to interface with the engine API, adopted from L1, and [OP-unique engine API][op-api].

[op-api]: https://github.com/op-rs/maili/blob/main/crates/provider/README.md
297 changes: 297 additions & 0 deletions crates/provider/src/ext/engine.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,297 @@
use alloy_network::Network;
use alloy_primitives::{BlockHash, Bytes, B256};
use alloy_provider::Provider;
use alloy_rpc_types_engine::{
ClientVersionV1, ExecutionPayloadBodiesV1, ExecutionPayloadEnvelopeV2, ExecutionPayloadInputV2,
ExecutionPayloadV3, ForkchoiceState, ForkchoiceUpdated, PayloadId, PayloadStatus,
};
use alloy_transport::{Transport, TransportResult};
use maili_provider::EngineExtApi;
use op_alloy_rpc_types_engine::{
OpExecutionPayloadEnvelopeV3, OpExecutionPayloadEnvelopeV4, OpPayloadAttributes,
};

/// Extension trait that gives access to Optimism engine API RPC methods.
///
/// Note:
/// > The provider should use a JWT authentication layer.
///
/// This follows the Optimism specs that can be found at:
/// <https://specs.optimism.io/protocol/exec-engine.html#engine-api>
#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
pub trait OpEngineApi<N, T>: EngineExtApi<N, T> {
/// Sends the given payload to the execution layer client, as specified for the Shanghai fork.
///
/// See also <https://github.com/ethereum/execution-apis/blob/584905270d8ad665718058060267061ecfd79ca5/src/engine/shanghai.md#engine_newpayloadv2>
///
/// No modifications needed for OP compatibility.
async fn new_payload_v2(
&self,
payload: ExecutionPayloadInputV2,
) -> TransportResult<PayloadStatus>;

/// Sends the given payload to the execution layer client, as specified for the Cancun fork.
///
/// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/cancun.md#engine_newpayloadv3>
///
/// OP modifications:
/// - expected versioned hashes MUST be an empty array: therefore the `versioned_hashes`
/// parameter is removed.
/// - parent beacon block root MUST be the parent beacon block root from the L1 origin block of
/// the L2 block.
async fn new_payload_v3(
&self,
payload: ExecutionPayloadV3,
parent_beacon_block_root: B256,
) -> TransportResult<PayloadStatus>;

/// Sends the given payload to the execution layer client, as specified for the Prague fork.
///
/// See also <https://github.com/ethereum/execution-apis/blob/03911ffc053b8b806123f1fc237184b0092a485a/src/engine/prague.md#engine_newpayloadv4>
///
/// OP modifications: TODO
async fn new_payload_v4(
&self,
payload: ExecutionPayloadV3,
parent_beacon_block_root: B256,
execution_requests: Vec<Bytes>,
) -> TransportResult<PayloadStatus>;

/// Updates the execution layer client with the given fork choice, as specified for the Shanghai
/// fork.
///
/// Caution: This should not accept the `parentBeaconBlockRoot` field in the payload attributes.
///
/// See also <https://github.com/ethereum/execution-apis/blob/6709c2a795b707202e93c4f2867fa0bf2640a84f/src/engine/shanghai.md#engine_forkchoiceupdatedv2>
///
/// OP modifications:
/// - The `payload_attributes` parameter is extended with the [`OpPayloadAttributes`] type
/// as described in <https://specs.optimism.io/protocol/exec-engine.html#extended-payloadattributesv2>
async fn fork_choice_updated_v2(
&self,
fork_choice_state: ForkchoiceState,
payload_attributes: Option<OpPayloadAttributes>,
) -> TransportResult<ForkchoiceUpdated>;

/// Updates the execution layer client with the given fork choice, as specified for the Cancun
/// fork.
///
/// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/cancun.md#engine_forkchoiceupdatedv3>
///
/// OP modifications:
/// - Must be called with an Ecotone payload
/// - Attributes must contain the parent beacon block root field
/// - The `payload_attributes` parameter is extended with the [`OpPayloadAttributes`] type
/// as described in <https://specs.optimism.io/protocol/exec-engine.html#extended-payloadattributesv2>
async fn fork_choice_updated_v3(
&self,
fork_choice_state: ForkchoiceState,
payload_attributes: Option<OpPayloadAttributes>,
) -> TransportResult<ForkchoiceUpdated>;

/// Retrieves an execution payload from a previously started build process, as specified for the
/// Shanghai fork.
///
/// See also <https://github.com/ethereum/execution-apis/blob/6709c2a795b707202e93c4f2867fa0bf2640a84f/src/engine/shanghai.md#engine_getpayloadv2>
///
/// Note:
/// > Provider software MAY stop the corresponding build process after serving this call.
///
/// No modifications needed for OP compatibility.
async fn get_payload_v2(
&self,
payload_id: PayloadId,
) -> TransportResult<ExecutionPayloadEnvelopeV2>;

/// Retrieves an execution payload from a previously started build process, as specified for the
/// Cancun fork.
///
/// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/cancun.md#engine_getpayloadv3>
///
/// Note:
/// > Provider software MAY stop the corresponding build process after serving this call.
///
/// OP modifications:
/// - the response type is extended to [`OpExecutionPayloadEnvelopeV3`].
async fn get_payload_v3(
&self,
payload_id: PayloadId,
) -> TransportResult<OpExecutionPayloadEnvelopeV3>;

/// Returns the most recent version of the payload that is available in the corresponding
/// payload build process at the time of receiving this call.
///
/// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/prague.md#engine_getpayloadv4>
///
/// Note:
/// > Provider software MAY stop the corresponding build process after serving this call.
///
/// OP modifications:
/// - the response type is extended to [`OpExecutionPayloadEnvelopeV4`].
async fn get_payload_v4(
&self,
payload_id: PayloadId,
) -> TransportResult<OpExecutionPayloadEnvelopeV4>;

/// Returns the execution payload bodies by the given hash.
///
/// See also <https://github.com/ethereum/execution-apis/blob/6452a6b194d7db269bf1dbd087a267251d3cc7f8/src/engine/shanghai.md#engine_getpayloadbodiesbyhashv1>
async fn get_payload_bodies_by_hash_v1(
&self,
block_hashes: Vec<BlockHash>,
) -> TransportResult<ExecutionPayloadBodiesV1>;

/// Returns the execution payload bodies by the range starting at `start`, containing `count`
/// blocks.
///
/// WARNING: This method is associated with the BeaconBlocksByRange message in the consensus
/// layer p2p specification, meaning the input should be treated as untrusted or potentially
/// adversarial.
///
/// Implementers should take care when acting on the input to this method, specifically
/// ensuring that the range is limited properly, and that the range boundaries are computed
/// correctly and without panics.
///
/// See also <https://github.com/ethereum/execution-apis/blob/6452a6b194d7db269bf1dbd087a267251d3cc7f8/src/engine/shanghai.md#engine_getpayloadbodiesbyrangev1>
async fn get_payload_bodies_by_range_v1(
&self,
start: u64,
count: u64,
) -> TransportResult<ExecutionPayloadBodiesV1>;

/// Returns the execution client version information.
///
/// Note:
/// > The `client_version` parameter identifies the consensus client.
///
/// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/identification.md#engine_getclientversionv1>
async fn get_client_version_v1(
&self,
client_version: ClientVersionV1,
) -> TransportResult<Vec<ClientVersionV1>>;

/// Returns the list of Engine API methods supported by the execution layer client software.
///
/// See also <https://github.com/ethereum/execution-apis/blob/6452a6b194d7db269bf1dbd087a267251d3cc7f8/src/engine/common.md#capabilities>
async fn exchange_capabilities(
&self,
capabilities: Vec<String>,
) -> TransportResult<Vec<String>>;
}

#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
impl<N, T, P> OpEngineApi<N, T> for P
where
N: Network,
T: Transport + Clone,
P: Provider<T, N>,
{
async fn new_payload_v2(
&self,
payload: ExecutionPayloadInputV2,
) -> TransportResult<PayloadStatus> {
self.client().request("engine_newPayloadV2", (payload,)).await
}

async fn new_payload_v3(
&self,
payload: ExecutionPayloadV3,
parent_beacon_block_root: B256,
) -> TransportResult<PayloadStatus> {
// Note: The `versioned_hashes` parameter is always an empty array for OP chains.
let versioned_hashes: Vec<B256> = vec![];

self.client()
.request("engine_newPayloadV3", (payload, versioned_hashes, parent_beacon_block_root))
.await
}

async fn new_payload_v4(
&self,
payload: ExecutionPayloadV3,
parent_beacon_block_root: B256,
execution_requests: Vec<Bytes>,
) -> TransportResult<PayloadStatus> {
// Note: The `versioned_hashes` parameter is always an empty array for OP chains.
let versioned_hashes: Vec<B256> = vec![];

self.client()
.request(
"engine_newPayloadV4",
(payload, versioned_hashes, parent_beacon_block_root, execution_requests),
)
.await
}

async fn fork_choice_updated_v2(
&self,
fork_choice_state: ForkchoiceState,
payload_attributes: Option<OpPayloadAttributes>,
) -> TransportResult<ForkchoiceUpdated> {
self.client()
.request("engine_forkchoiceUpdatedV2", (fork_choice_state, payload_attributes))
.await
}

async fn fork_choice_updated_v3(
&self,
fork_choice_state: ForkchoiceState,
payload_attributes: Option<OpPayloadAttributes>,
) -> TransportResult<ForkchoiceUpdated> {
self.client()
.request("engine_forkchoiceUpdatedV3", (fork_choice_state, payload_attributes))
.await
}

async fn get_payload_v2(
&self,
payload_id: PayloadId,
) -> TransportResult<ExecutionPayloadEnvelopeV2> {
self.client().request("engine_getPayloadV2", (payload_id,)).await
}

async fn get_payload_v3(
&self,
payload_id: PayloadId,
) -> TransportResult<OpExecutionPayloadEnvelopeV3> {
self.client().request("engine_getPayloadV3", (payload_id,)).await
}

async fn get_payload_v4(
&self,
payload_id: PayloadId,
) -> TransportResult<OpExecutionPayloadEnvelopeV4> {
self.client().request("engine_getPayloadV4", (payload_id,)).await
}

async fn get_payload_bodies_by_hash_v1(
&self,
block_hashes: Vec<BlockHash>,
) -> TransportResult<ExecutionPayloadBodiesV1> {
self.client().request("engine_getPayloadBodiesByHashV1", (block_hashes,)).await
}

async fn get_payload_bodies_by_range_v1(
&self,
start: u64,
count: u64,
) -> TransportResult<ExecutionPayloadBodiesV1> {
self.client().request("engine_getPayloadBodiesByRangeV1", (start, count)).await
}

async fn get_client_version_v1(
&self,
client_version: ClientVersionV1,
) -> TransportResult<Vec<ClientVersionV1>> {
self.client().request("engine_getClientVersionV1", (client_version,)).await
}

async fn exchange_capabilities(
&self,
capabilities: Vec<String>,
) -> TransportResult<Vec<String>> {
self.client().request("engine_exchangeCapabilities", (capabilities,)).await
}
}
4 changes: 4 additions & 0 deletions crates/provider/src/ext/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
//! Extended APIs for the OP provider module.
/// Engine API extension.
pub mod engine;
9 changes: 9 additions & 0 deletions crates/provider/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#![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"
)]
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]

pub mod ext;

0 comments on commit 1996adc

Please sign in to comment.