Skip to content

Commit

Permalink
feat: scroll alloy provider (#147)
Browse files Browse the repository at this point in the history
Signed-off-by: Gregory Edison <[email protected]>
  • Loading branch information
greged93 authored Jan 29, 2025
1 parent 34fbede commit 6c63414
Show file tree
Hide file tree
Showing 8 changed files with 412 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ jobs:
--exclude reth-e2e-test-utils --exclude reth-ethereum-payload-builder --exclude reth-exex-test-utils \
--exclude reth-node-ethereum --exclude reth-scroll-cli --exclude reth-scroll-evm \
--exclude reth-scroll-node --exclude scroll-reth --exclude reth-scroll-rpc --exclude reth-scroll-trie \
--exclude reth-scroll-engine-primitives
--exclude reth-scroll-engine-primitives --exclude scroll-alloy-provider
book:
name: book
Expand Down
43 changes: 43 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ members = [
"crates/rpc/rpc/",
"crates/scroll/alloy/consensus",
"crates/scroll/alloy/network",
"crates/scroll/alloy/provider",
"crates/scroll/alloy/rpc-types",
"crates/scroll/alloy/rpc-types-engine",
"crates/scroll/bin/scroll-reth",
Expand Down Expand Up @@ -487,6 +488,7 @@ alloy-transport-ws = { version = "0.9.2", default-features = false }

# scroll
scroll-alloy-consensus = { path = "crates/scroll/alloy/consensus" }
scroll-alloy-provider = { path = "crates/scroll/alloy/provider" }
scroll-alloy-rpc-types = { path = "crates/scroll/alloy/rpc-types" }
scroll-alloy-rpc-types-engine = { path = "crates/scroll/alloy/rpc-types-engine" }
scroll-alloy-network = { path = "crates/scroll/alloy/network" }
Expand Down
74 changes: 74 additions & 0 deletions crates/scroll/alloy/provider/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
[package]
name = "scroll-alloy-provider"
version.workspace = true
edition.workspace = true
rust-version.workspace = true
license.workspace = true
homepage.workspace = true
repository.workspace = true
exclude.workspace = true

[lints]
workspace = true

[dependencies]
# alloy
alloy-json-rpc.workspace = true
alloy-provider.workspace = true
alloy-primitives.workspace = true
alloy-rpc-types-engine = { workspace = true, features = ["serde"] }
alloy-rpc-client.workspace = true
alloy-transport.workspace = true
alloy-transport-http = { workspace = true, features = ["jwt-auth"] }

# scroll
scroll-alloy-network.workspace = true
scroll-alloy-rpc-types-engine = { workspace = true, features = ["serde"] }

# misc
async-trait.workspace = true
derive_more.workspace = true
eyre.workspace = true
http-body-util.workspace = true
reqwest.workspace = true
tower.workspace = true

[dev-dependencies]
reth-payload-builder = { workspace = true, features = ["test-utils"] }
reth-engine-primitives.workspace = true
reth-primitives.workspace = true
reth-primitives-traits.workspace = true
reth-provider = { workspace = true, features = ["test-utils"] }
reth-rpc-builder.workspace = true
reth-rpc-engine-api.workspace = true
reth-rpc-types-compat.workspace = true
reth-scroll-engine-primitives.workspace = true
reth-scroll-node.workspace = true
reth-scroll-payload.workspace = true
reth-scroll-chainspec.workspace = true
reth-tasks.workspace = true
reth-tracing.workspace = true
reth-transaction-pool.workspace = true

tokio = { workspace = true, features = ["rt", "rt-multi-thread"] }
futures-util.workspace = true

[features]
default = ["std"]
std = [
"alloy-primitives/std",
"alloy-rpc-types-engine/std",
"scroll-alloy-rpc-types-engine/std",
"derive_more/std",
"reth-primitives/std",
"reth-primitives-traits/std",
]
scroll = [
"reth-scroll-node/scroll",
"reth-scroll-engine-primitives/scroll"
]
optimism = [
"reth-provider/optimism",
"reth-scroll-engine-primitives/optimism",
"reth-scroll-node/optimism"
]
146 changes: 146 additions & 0 deletions crates/scroll/alloy/provider/src/engine/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
mod provider;
pub use provider::ScrollAuthEngineApiProvider;

use alloy_primitives::{BlockHash, U64};
use alloy_provider::{Network, Provider};
use alloy_rpc_types_engine::{
ClientVersionV1, ExecutionPayloadBodiesV1, ExecutionPayloadV1, ForkchoiceState,
ForkchoiceUpdated, PayloadId, PayloadStatus,
};
use alloy_transport::{Transport, TransportResult};
use scroll_alloy_rpc_types_engine::ScrollPayloadAttributes;

/// Engine API trait for Scroll. Only exposes versions of the API that are supported.
/// Note:
/// > The provider should use a JWT authentication layer.
#[async_trait::async_trait]
pub trait ScrollEngineApi<N, T> {
/// See also <https://github.com/ethereum/execution-apis/blob/6709c2a795b707202e93c4f2867fa0bf2640a84f/src/engine/paris.md#engine_newpayloadv1>
/// Caution: This should not accept the `withdrawals` field
async fn new_payload_v1(&self, payload: ExecutionPayloadV1) -> TransportResult<PayloadStatus>;

/// See also <https://github.com/ethereum/execution-apis/blob/6709c2a795b707202e93c4f2867fa0bf2640a84f/src/engine/paris.md#engine_forkchoiceupdatedv1>
/// Caution: This should not accept the `withdrawals` field in the payload attributes.
///
/// Modifications:
/// - Adds the below fields to the `payload_attributes`:
/// - transactions: an optional list of transactions to include at the start of the block.
/// - no_tx_pool: a boolean which signals whether pool transactions need to be included in
/// the payload building task.
async fn fork_choice_updated_v1(
&self,
fork_choice_state: ForkchoiceState,
payload_attributes: Option<ScrollPayloadAttributes>,
) -> TransportResult<ForkchoiceUpdated>;

/// See also <https://github.com/ethereum/execution-apis/blob/6709c2a795b707202e93c4f2867fa0bf2640a84f/src/engine/paris.md#engine_getpayloadv1>
///
/// Returns the most recent version of the payload that is available in the corresponding
/// payload build process at the time of receiving this call.
///
/// Caution: This should not return the `withdrawals` field
///
/// Note:
/// > Provider software MAY stop the corresponding build process after serving this call.
async fn get_payload_v1(&self, payload_id: PayloadId) -> TransportResult<ExecutionPayloadV1>;

/// 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>;

/// See also <https://github.com/ethereum/execution-apis/blob/6452a6b194d7db269bf1dbd087a267251d3cc7f8/src/engine/shanghai.md#engine_getpayloadbodiesbyrangev1>
///
/// 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.
async fn get_payload_bodies_by_range_v1(
&self,
start: U64,
count: U64,
) -> TransportResult<ExecutionPayloadBodiesV1>;

/// This function will return the ClientVersionV1 object.
/// See also:
/// <https://github.com/ethereum/execution-apis/blob/03911ffc053b8b806123f1fc237184b0092a485a/src/engine/identification.md#engine_getclientversionv1>make fmt
///
///
/// - When connected to a single execution client, the consensus client **MUST** receive an
/// array with a single `ClientVersionV1` object.
/// - When connected to multiple execution clients via a multiplexer, the multiplexer **MUST**
/// concatenate the responses from each execution client into a single,
/// flat array before returning the response to the consensus client.
async fn get_client_version_v1(
&self,
client_version: ClientVersionV1,
) -> TransportResult<Vec<ClientVersionV1>>;

/// 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>>;
}

#[async_trait::async_trait]
impl<N, T, P> ScrollEngineApi<N, T> for P
where
N: Network,
T: Transport + Clone,
P: Provider<T, N>,
{
async fn new_payload_v1(&self, payload: ExecutionPayloadV1) -> TransportResult<PayloadStatus> {
self.client().request("engine_newPayloadV1", (payload,)).await
}

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

async fn get_payload_v1(&self, payload_id: PayloadId) -> TransportResult<ExecutionPayloadV1> {
self.client().request("engine_getPayloadV1", (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
}
}
Loading

0 comments on commit 6c63414

Please sign in to comment.