Skip to content

Commit

Permalink
EXP-133 engine api Extensions (#250)
Browse files Browse the repository at this point in the history
* Add custom payload builder for engine v2 payloads

* add precompile for bridge out

* use context precompile
emit logs to transmit withdrawal info

* add web3 dep, funcational test for bridge precompile

* add withdrawal intents to l2 block

* fix: path must be shorter than SUN_LEN

* remove unused import

* lint: fix formatting

* remove todo

* fix functional test

* remove duplicate code, update comments
  • Loading branch information
sapinb authored Aug 30, 2024
1 parent 4e3d0b0 commit 245a812
Show file tree
Hide file tree
Showing 33 changed files with 2,729 additions and 70 deletions.
32 changes: 27 additions & 5 deletions Cargo.lock

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

19 changes: 18 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ members = [
"crates/prover/zkvm",
"crates/reth/db",
"crates/reth/exex",
"crates/reth/node",
"crates/reth/rpc",
"crates/rpc/api",
"crates/rpc/types",
Expand Down Expand Up @@ -58,6 +59,7 @@ bitcoin-blockspace = { path = "crates/prover/bitcoin-blockspace" }
express-chaintsn = { path = "crates/chaintsn" }
express-reth-db = { path = "crates/reth/db" }
express-reth-exex = { path = "crates/reth/exex" }
express-reth-node = { path = "crates/reth/node" }
express-reth-rpc = { path = "crates/reth/rpc" }
express-rpc-utils = { path = "crates/rpc/utils" }
express-storage = { path = "crates/storage" }
Expand All @@ -66,9 +68,10 @@ express-zkvm = { path = "crates/prover/zkvm" } # FIXME make
zkvm = { path = "crates/prover/zkvm" }
zkvm-primitives = { path = "crates/prover/primitives" }

# IMPORTANT: ensure alloy-* types are of the same version as inside reth dependency
# IMPORTANT: ensure alloy-* and revm packages are of the same version as inside reth dependency
alloy-genesis = { version = "0.2", default-features = false }
alloy-rpc-types = { version = "0.2", default-features = false }
alloy-sol-types = "0.7.2"
anyhow = "1.0.86"
arbitrary = { version = "1.3.2", features = ["derive"] }
argh = "0.1"
Expand Down Expand Up @@ -97,14 +100,20 @@ paste = "1.0"
rand = "0.8.5"
reqwest = { version = "0.12.4", features = ["json"] }
reth = { git = "https://github.com/alpenlabs/reth.git", rev = "dde184f56591d0af" }
reth-basic-payload-builder = { git = "https://github.com/alpenlabs/reth.git", rev = "dde184f56591d0af" }
reth-chainspec = { git = "https://github.com/alpenlabs/reth.git", rev = "dde184f56591d0af" }
reth-cli-commands = { git = "https://github.com/alpenlabs/reth.git", rev = "dde184f56591d0af" }
reth-cli-util = { git = "https://github.com/alpenlabs/reth.git", rev = "dde184f56591d0af" }
reth-db = { git = "https://github.com/alpenlabs/reth.git", rev = "dde184f56591d0af" }
reth-errors = { git = "https://github.com/alpenlabs/reth.git", rev = "dde184f56591d0af" }
reth-ethereum-payload-builder = { git = "https://github.com/alpenlabs/reth.git", rev = "dde184f56591d0af" }
reth-evm = { git = "https://github.com/alpenlabs/reth.git", rev = "dde184f56591d0af" }
reth-evm-ethereum = { git = "https://github.com/alpenlabs/reth.git", rev = "dde184f56591d0af" }
reth-exex = { git = "https://github.com/alpenlabs/reth.git", rev = "dde184f56591d0af" }
reth-ipc = { git = "https://github.com/alpenlabs/reth.git", rev = "dde184f56591d0af" }
reth-node-api = { git = "https://github.com/alpenlabs/reth.git", rev = "dde184f56591d0af" }
reth-node-ethereum = { git = "https://github.com/alpenlabs/reth.git", rev = "dde184f56591d0af" }
reth-payload-builder = { git = "https://github.com/alpenlabs/reth.git", rev = "dde184f56591d0af" }
reth-primitives = { git = "https://github.com/alpenlabs/reth.git", rev = "dde184f56591d0af", default-features = false, features = [
"std",
] }
Expand All @@ -116,6 +125,14 @@ reth-rpc-layer = { git = "https://github.com/alpenlabs/reth.git", rev = "dde184f
reth-rpc-types = { git = "https://github.com/alpenlabs/reth.git", rev = "dde184f56591d0af" }
reth-rpc-types-compat = { git = "https://github.com/alpenlabs/reth.git", rev = "dde184f56591d0af" }
reth-trie-common = { git = "https://github.com/alpenlabs/reth.git", rev = "dde184f56591d0af" }
revm = { version = "12.1.0", features = [
"std",
"secp256k1",
"blst",
], default-features = false }
revm-primitives = { version = "7.1.0", features = [
"std",
], default-features = false }
rockbound = { git = "https://github.com/alpenlabs/rockbound", rev = "3b10aaabef6652f0" }
secp256k1 = "0.29.0"
serde = { version = "1.0", features = ["derive"] }
Expand Down
3 changes: 1 addition & 2 deletions crates/consensus-logic/src/duty/block_assembly.rs
Original file line number Diff line number Diff line change
Expand Up @@ -298,8 +298,7 @@ fn prepare_exec_data<E: ExecEngineCtl>(
trace!("finished EL payload job");

// Reassemble it into an exec update.
let eui = payload_data.update_input().clone();
let exec_update = ExecUpdate::new(eui, UpdateOutput::new_from_state(Buf32::zero()));
let exec_update = payload_data.exec_update().clone();
let exec_seg = ExecSegment::new(exec_update);

// And the accessory.
Expand Down
15 changes: 7 additions & 8 deletions crates/eectl/src/messages.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use alpen_express_primitives::prelude::*;
use alpen_express_state::{block::L2BlockBundle, exec_update::UpdateInput, id::L2BlockId};
use alpen_express_state::{block::L2BlockBundle, exec_update::ExecUpdate, id::L2BlockId};

/// Succinct commitment to relevant EL block data.
// This ended up being the same as the EL payload types in the state crate,
Expand All @@ -9,8 +9,7 @@ pub struct ExecPayloadData {
/// Encoded EL payload, minus any operations we push to it.
///
/// This is the "explicit" input from the CL block.
// TODO replace this with the `UpdateInput` from the exec update, maybe some other stuff
update_input: UpdateInput,
exec_update: ExecUpdate,

accessory_data: Vec<u8>,

Expand All @@ -23,25 +22,25 @@ pub struct ExecPayloadData {
}

impl ExecPayloadData {
pub fn new(update_input: UpdateInput, accessory_data: Vec<u8>, ops: Vec<Op>) -> Self {
pub fn new(exec_update: ExecUpdate, accessory_data: Vec<u8>, ops: Vec<Op>) -> Self {
Self {
update_input,
exec_update,
accessory_data,
ops,
}
}

pub fn from_l2_block_bundle(l2block: &L2BlockBundle) -> Self {
Self {
update_input: l2block.block().exec_segment().update().input().clone(),
exec_update: l2block.block().exec_segment().update().clone(),
accessory_data: l2block.accessory().exec_payload().to_vec(),
// TODO: extract ops from block
ops: vec![],
}
}

pub fn update_input(&self) -> &UpdateInput {
&self.update_input
pub fn exec_update(&self) -> &ExecUpdate {
&self.exec_update
}

pub fn accessory_data(&self) -> &[u8] {
Expand Down
10 changes: 8 additions & 2 deletions crates/eectl/src/stub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@
use std::{collections::*, sync::Mutex, time};

use alpen_express_primitives::buf::Buf32;
use alpen_express_state::{exec_update::UpdateInput, prelude::*};
use alpen_express_state::{
exec_update::{ExecUpdate, UpdateInput, UpdateOutput},
prelude::*,
};

use crate::{engine::*, errors::*, messages::*};

Expand Down Expand Up @@ -67,7 +70,10 @@ impl ExecEngineCtl for StubController {
} else {
// TODO make up a more plausible payload
let exec = ExecPayloadData::new(
UpdateInput::new(0, Buf32::zero(), Vec::new()),
ExecUpdate::new(
UpdateInput::new(0, Buf32::zero(), Vec::new()),
UpdateOutput::new_from_state(Buf32::zero()),
),
Vec::new(),
Vec::new(),
);
Expand Down
1 change: 1 addition & 0 deletions crates/evmexec/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ alpen-express-db = { workspace = true }
alpen-express-eectl = { workspace = true }
alpen-express-primitives = { workspace = true }
alpen-express-state = { workspace = true }
express-reth-node = { workspace = true }
express-storage = { workspace = true }

anyhow = { workspace = true }
Expand Down
73 changes: 57 additions & 16 deletions crates/evmexec/src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,14 @@ use alpen_express_eectl::{
errors::{EngineError, EngineResult},
messages::{ELDepositData, ExecPayloadData, Op, PayloadEnv},
};
use alpen_express_state::{block::L2BlockBundle, exec_update::UpdateInput, id::L2BlockId};
use alpen_express_primitives::buf::Buf64;
use alpen_express_state::{
block::L2BlockBundle,
bridge_ops,
exec_update::{ExecUpdate, UpdateInput, UpdateOutput},
id::L2BlockId,
};
use express_reth_node::{ExpressExecutionPayloadEnvelopeV2, ExpressPayloadAttributes};
use express_storage::L2BlockManager;
use futures::future::TryFutureExt;
use reth_primitives::{Address, B256};
Expand Down Expand Up @@ -94,14 +101,14 @@ impl<T: EngineRpc> RpcExecEngineInner<T> {
})
.collect();

let payload_attributes = PayloadAttributes {
let payload_attributes = ExpressPayloadAttributes::new_from_eth(PayloadAttributes {
// evm expects timestamp in seconds
timestamp: payload_env.timestamp() / 1000,
prev_randao: B256::ZERO,
withdrawals: Some(withdrawals),
parent_beacon_block_root: None,
suggested_fee_recipient: Address::ZERO,
};
});

let mut fcs = *self.fork_choice_state.lock().await;
fcs.head_block_hash = prev_block.block_hash();
Expand Down Expand Up @@ -131,14 +138,16 @@ impl<T: EngineRpc> RpcExecEngineInner<T> {
.map_err(|_| EngineError::UnknownPayloadId(payload_id))
.await?;

let execution_payload_data = match payload.execution_payload {
let ExpressExecutionPayloadEnvelopeV2 {
inner: execution_payload_v2,
withdrawal_intents: rpc_withdrawal_intents,
} = payload;

let (el_payload, ops) = match execution_payload_v2.execution_payload {
ExecutionPayloadFieldV2::V1(payload) => {
let el_payload: ElPayload = payload.into();
let accessory_data = borsh::to_vec(&el_payload).unwrap();
let update_input = UpdateInput::try_from(el_payload)
.map_err(|err| EngineError::Other(err.to_string()))?;

ExecPayloadData::new(update_input, accessory_data, vec![])
(el_payload, vec![])
}
ExecutionPayloadFieldV2::V2(payload) => {
let ops = payload
Expand All @@ -153,21 +162,38 @@ impl<T: EngineRpc> RpcExecEngineInner<T> {
.collect();

let el_payload: ElPayload = payload.payload_inner.into();
let accessory_data = borsh::to_vec(&el_payload).unwrap();
let update_input = UpdateInput::try_from(el_payload)
.map_err(|err| EngineError::Other(err.to_string()))?;

ExecPayloadData::new(update_input, accessory_data, ops)
(el_payload, ops)
}
};

let el_state_root = el_payload.state_root;
let accessory_data = borsh::to_vec(&el_payload).unwrap();
let update_input =
UpdateInput::try_from(el_payload).map_err(|err| EngineError::Other(err.to_string()))?;

let withdrawal_intents = rpc_withdrawal_intents
.into_iter()
.map(to_bridge_withdrawal_intents)
.collect();

let update_output =
UpdateOutput::new_from_state(el_state_root).with_withdrawals(withdrawal_intents);

let execution_payload_data = ExecPayloadData::new(
ExecUpdate::new(update_input, update_output),
accessory_data,
ops,
);

Ok(PayloadStatus::Ready(execution_payload_data))
}

async fn submit_new_payload(&self, payload: ExecPayloadData) -> EngineResult<BlockStatus> {
let el_payload = borsh::from_slice::<ElPayload>(payload.accessory_data())
.map_err(|_| EngineError::Other("Invalid payload".to_string()))?;

// actually bridge-in deposits
let withdrawals: Vec<Withdrawal> = payload
.ops()
.iter()
Expand Down Expand Up @@ -324,6 +350,13 @@ struct ForkchoiceStatePartial {
pub finalized_block_hash: Option<B256>,
}

fn to_bridge_withdrawal_intents(
rpc_withdrawal_intent: express_reth_node::WithdrawalIntent,
) -> bridge_ops::WithdrawalIntent {
let express_reth_node::WithdrawalIntent { amt, dest_pk } = rpc_withdrawal_intent;
bridge_ops::WithdrawalIntent::new(amt, Buf64(dest_pk))
}

#[cfg(test)]
mod tests {
use alpen_express_eectl::{errors::EngineResult, messages::PayloadEnv};
Expand Down Expand Up @@ -478,9 +511,12 @@ mod tests {
let fcs = ForkchoiceState::default();

mock_client.expect_get_payload_v2().returning(move |_| {
Ok(ExecutionPayloadEnvelopeV2 {
execution_payload: ExecutionPayloadFieldV2::V1(random_execution_payload_v1()),
block_value: U256::from(100),
Ok(ExpressExecutionPayloadEnvelopeV2 {
inner: ExecutionPayloadEnvelopeV2 {
execution_payload: ExecutionPayloadFieldV2::V1(random_execution_payload_v1()),
block_value: U256::from(100),
},
withdrawal_intents: vec![],
})
});

Expand Down Expand Up @@ -514,8 +550,13 @@ mod tests {
};
let accessory_data = borsh::to_vec(&el_payload).unwrap();
let update_input = UpdateInput::try_from(el_payload).unwrap();
let update_output = UpdateOutput::new_from_state(Buf32::zero());

let payload_data = ExecPayloadData::new(update_input, accessory_data, vec![]);
let payload_data = ExecPayloadData::new(
ExecUpdate::new(update_input, update_output),
accessory_data,
vec![],
);

mock_client.expect_new_payload_v2().returning(move |_| {
Ok(reth_rpc_types::engine::PayloadStatus {
Expand Down
Loading

0 comments on commit 245a812

Please sign in to comment.