Skip to content

Commit

Permalink
engine fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
refcell committed Dec 4, 2024
1 parent db0fc14 commit ec75976
Show file tree
Hide file tree
Showing 9 changed files with 204 additions and 126 deletions.
55 changes: 29 additions & 26 deletions Cargo.lock

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

10 changes: 5 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ redundant-clone = "warn"
all-features = true
rustdoc-args = ["--cfg", "docsrs"]

[patch.crates-io]
kona-derive = { git = "https://github.com/anton-rs/kona", branch = "rf/fix/executor-trait" }
kona-driver = { git = "https://github.com/anton-rs/kona", branch = "rf/fix/executor-trait" }
# [patch.crates-io]
# kona-derive = { git = "https://github.com/anton-rs/kona", branch = "main" }
# kona-driver = { git = "https://github.com/anton-rs/kona", branch = "main" }

[workspace.dependencies]
# Workspace
Expand All @@ -51,8 +51,8 @@ hilo-providers-local = { version = "0.11.0", path = "crates/providers-local", de
hilo-providers-alloy = { version = "0.11.0", path = "crates/providers-alloy", default-features = false }

# Kona
kona-derive = { version = "0.1.0", default-features = false }
kona-driver = { version = "0.1.0", default-features = false }
kona-derive = { version = "0.2.0", default-features = false }
kona-driver = { version = "0.2.0", default-features = false }

# Alloy
alloy-rlp = { version = "0.3.9", default-features = false }
Expand Down
2 changes: 1 addition & 1 deletion crates/engine/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ alloy-consensus.workspace = true
alloy-network.workspace = true
alloy-rpc-client.workspace = true
alloy-rpc-types-eth.workspace = true
alloy-provider = { workspace = true, features = ["ipc", "reqwest"] }
alloy-provider = { workspace = true, features = ["ipc", "reqwest", "engine-api"] }
alloy-primitives = { workspace = true, features = ["map"] }
alloy-transport-http = { workspace = true, features = ["jwt-auth"] }
alloy-rpc-types-engine = { workspace = true, features = ["jwt", "serde"] }
Expand Down
120 changes: 114 additions & 6 deletions crates/engine/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
use alloy_eips::eip1898::BlockNumberOrTag;
use alloy_network::AnyNetwork;
use alloy_primitives::{Bytes, B256};
use alloy_provider::{ReqwestProvider, RootProvider};
use alloy_provider::{ReqwestProvider, RootProvider /* , ext::EngineApi */};
use alloy_rpc_client::RpcClient;
use alloy_rpc_types_engine::{
ExecutionPayloadEnvelopeV2, ExecutionPayloadInputV2, ExecutionPayloadV2, ExecutionPayloadV3,
ForkchoiceState, ForkchoiceUpdated, JwtSecret, PayloadId, PayloadStatus,
ExecutionPayloadEnvelopeV2, ExecutionPayloadFieldV2, ExecutionPayloadInputV2,
ExecutionPayloadV1, ExecutionPayloadV2, ExecutionPayloadV3, ForkchoiceState, ForkchoiceUpdated,
JwtSecret, PayloadId, PayloadStatus, PayloadStatusEnum,
};
use alloy_transport_http::{
hyper_util::{
Expand All @@ -19,7 +20,7 @@ use alloy_transport_http::{
use async_trait::async_trait;
use http_body_util::Full;
use op_alloy_genesis::RollupConfig;
use op_alloy_protocol::{BatchValidationProvider, L2BlockInfo};
use op_alloy_protocol::{BatchValidationProvider, BlockInfo, L2BlockInfo};
use op_alloy_provider::ext::engine::OpEngineApi;
use op_alloy_rpc_types_engine::{OpExecutionPayloadEnvelopeV3, OpPayloadAttributes};
use std::sync::Arc;
Expand All @@ -40,6 +41,8 @@ pub struct EngineClient {
engine: RootProvider<Http<HyperAuthClient>, AnyNetwork>,
/// The L2 chain provider.
rpc: AlloyL2ChainProvider,
/// The [RollupConfig] for the chain used to timestamp which version of the engine api to use.
cfg: Arc<RollupConfig>,
}

impl EngineClient {
Expand All @@ -56,15 +59,113 @@ impl EngineClient {
let engine = RootProvider::<_, AnyNetwork>::new(rpc_client);

let rpc = ReqwestProvider::new_http(rpc);
let rpc = AlloyL2ChainProvider::new(rpc, cfg);
Self { engine, rpc }
let rpc = AlloyL2ChainProvider::new(rpc, cfg.clone());
Self { engine, rpc, cfg }
}

/// Returns which fork choice version to use based on the timestamp
/// and rollup config.
pub fn fork_choice_version(&self, timestamp: u64) -> u64 {
// TODO: replace this with https://github.com/alloy-rs/op-alloy/pull/321
// once it's merged and updated in kona.
if self.cfg.ecotone_time.is_some_and(|t| timestamp >= t) {
// Cancun
3
} else if self.cfg.canyon_time.is_some_and(|t| timestamp >= t) {
// Shanghai
2
} else {
1
}
}

/// Accepts a given payload.
/// Sends [OpPayloadAttributes] via a `ForkChoiceUpdated` message to the [Engine].
/// If the payload is valid, the engine will create a new block and update the `safe_head`,
/// `safe_epoch`, and `unsafe_head`.
pub async fn accept_payload(
&mut self,
forkchoice: ForkchoiceState,
attributes: OpPayloadAttributes,
) -> Result<BlockInfo, EngineError> {
let timestamp = attributes.payload_attributes.timestamp;
let update = self.forkchoice_update(forkchoice, Some(attributes)).await?;

if !update.payload_status.status.is_valid() {
return Err(EngineError::InvalidForkChoiceAttributes);
}

let id = update.payload_id.ok_or(EngineError::MissingPayloadId)?;

match self.fork_choice_version(timestamp) {
1 => self.accept_v1(id).await,
2 => self.accept_v2(id).await,
3 => self.accept_v3(id).await,
_ => Err(EngineError::InvalidNewPayloadAttributes),
}
}

/// Gets and marks a new payload for the V1 engine api.
pub async fn accept_v1(&mut self, _id: PayloadId) -> Result<BlockInfo, EngineError> {
unimplemented!("v1 not supported by OpEngineApi")
}

/// Gets and marks a new payload for the V2 engine api.
pub async fn accept_v2(&mut self, id: PayloadId) -> Result<BlockInfo, EngineError> {
let payload = self.get_payload_v2(id).await?;

let withdrawals = match &payload.execution_payload {
ExecutionPayloadFieldV2::V2(ExecutionPayloadV2 { withdrawals, .. }) => {
withdrawals.clone()
}
ExecutionPayloadFieldV2::V1(_) => vec![],
};
let payload_inner = payload.into_v1_payload();
let block_info = BlockInfo {
number: payload_inner.block_number,
hash: payload_inner.block_hash,
parent_hash: payload_inner.parent_hash,
timestamp: payload_inner.timestamp,
};
let payload = ExecutionPayloadV2 { payload_inner, withdrawals };
let status = self.new_payload_v2(payload.clone()).await?;
if !status.is_valid() && status.status != PayloadStatusEnum::Accepted {
return Err(EngineError::InvalidNewPayloadAttributes);
}

Ok(block_info)
}

/// Gets and marks a new payload for the V3 engine api.
pub async fn accept_v3(&mut self, id: PayloadId) -> Result<BlockInfo, EngineError> {
let payload = self.get_payload_v3(id).await?;

let block_info = BlockInfo {
number: payload.execution_payload.payload_inner.payload_inner.block_number,
hash: payload.execution_payload.payload_inner.payload_inner.block_hash,
parent_hash: payload.execution_payload.payload_inner.payload_inner.parent_hash,
timestamp: payload.execution_payload.payload_inner.payload_inner.timestamp,
};
let status = self.new_payload_v3(payload.execution_payload, block_info.hash).await?;
if !status.is_valid() && status.status != PayloadStatusEnum::Accepted {
return Err(EngineError::InvalidNewPayloadAttributes);
}

Ok(block_info)
}
}

#[async_trait]
impl Engine for EngineClient {
type Error = EngineError;

async fn get_payload_v1(
&self,
_payload_id: PayloadId,
) -> Result<ExecutionPayloadV1, Self::Error> {
unimplemented!("v1 not supported by OpEngineApi")
}

async fn get_payload_v2(
&self,
payload_id: PayloadId,
Expand All @@ -87,6 +188,13 @@ impl Engine for EngineClient {
self.engine.fork_choice_updated_v2(state, attr).await.map_err(|_| EngineError::PayloadError)
}

async fn new_payload_v1(
&self,
_payload: ExecutionPayloadV1,
) -> Result<PayloadStatus, Self::Error> {
unimplemented!("v1 not supported by OpEngineApi")
}

async fn new_payload_v2(
&self,
payload: ExecutionPayloadV2,
Expand Down
Loading

0 comments on commit ec75976

Please sign in to comment.