Skip to content

Commit

Permalink
Arbitrum Bold Verifier (#371)
Browse files Browse the repository at this point in the history
  • Loading branch information
Wizdave97 authored Feb 1, 2025
1 parent 2600695 commit 74859b3
Show file tree
Hide file tree
Showing 10 changed files with 442 additions and 42 deletions.
5 changes: 5 additions & 0 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion modules/hyperclient/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@polytope-labs/hyperclient",
"description": "The hyperclient is a library for managing (in-flight) ISMP requests",
"version": "1.0.1",
"version": "1.0.2",
"author": "Polytope Labs (hello@polytope.technology)",
"license": "Apache-2.0",
"bugs": {
Expand Down
10 changes: 9 additions & 1 deletion modules/ismp/clients/arbitrum/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,21 @@ evm-state-machine = { workspace = true }
alloy-rlp = { workspace = true }
alloy-rlp-derive = { workspace = true }
alloy-primitives = { workspace = true }
alloy-sol-macro = { workspace = true }
alloy-sol-types = { workspace = true }
hex = { workspace = true, default-features = false }
hex-literal = { workspace = true }
codec = { workspace = true, default-features = false }
ethabi = { workspace = true }
sp-io = { workspace = true }
anyhow = { workspace = true }

[dev-dependencies]
ethers = { workspace = true, features = ["default"] }
tokio = { workspace = true, features = ["full"] }
ismp-testsuite = { path = "../../testsuite" }
sp-core = { workspace = true }
dotenv = "0.15.0"

[features]
default = ["std"]
Expand All @@ -40,5 +45,8 @@ std = [
"ethabi/std",
"hex/std",
"geth-primitives/std",
"evm-state-machine/std"
"evm-state-machine/std",
"sp-io/std",
"anyhow/std",
"alloy-sol-types/std"
]
167 changes: 162 additions & 5 deletions modules/ismp/clients/arbitrum/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ mod tests;

use alloc::format;
use alloy_rlp::Decodable;
use alloy_sol_types::SolValue;
use anyhow::anyhow;
use ethabi::ethereum_types::{H160, H256, U256};
use evm_state_machine::{derive_map_key, get_contract_account, get_value_from_proof, prelude::*};
use geth_primitives::{CodecHeader, Header};
Expand All @@ -36,8 +38,10 @@ use ismp::{

/// Storage layout slot for the nodes map in the Rollup Contract
pub const NODES_SLOT: u64 = 118;
/// Storage layout slot for the _assertions map in the Rollup Contract
pub const ASSERTIONS_SLOT: u64 = 117;

#[derive(codec::Encode, codec::Decode, Debug)]
#[derive(codec::Encode, codec::Decode, Debug, Clone)]
pub struct GlobalState {
pub block_hash: H256,
pub send_root: H256,
Expand All @@ -59,12 +63,11 @@ impl GlobalState {
}
}

#[derive(codec::Encode, codec::Decode, Debug)]
#[derive(codec::Encode, codec::Decode, Debug, Clone)]
pub enum MachineStatus {
Running = 0,
Finished = 1,
Errored = 2,
TooFar = 3,
}

impl TryFrom<u8> for MachineStatus {
Expand All @@ -77,8 +80,6 @@ impl TryFrom<u8> for MachineStatus {
Ok(MachineStatus::Finished)
} else if status == 2 {
Ok(MachineStatus::Errored)
} else if status == 3 {
Ok(MachineStatus::TooFar)
} else {
Err("Invalid machine status received")
}
Expand Down Expand Up @@ -188,3 +189,159 @@ pub fn verify_arbitrum_payload<H: Keccak256 + Send + Sync>(
commitment: StateCommitment { timestamp, overlay_root: None, state_root },
})
}

#[derive(codec::Encode, codec::Decode, Debug)]
pub struct ArbitrumBoldProof {
/// Arbitrum header that corresponds to the node being created
pub arbitrum_header: CodecHeader,
/// After State as recorded in the AssertionCreated event that was emitted for this node
pub after_state: AssertionState,
/// Previous assertion hash
pub previous_assertion_hash: H256,
/// Sequencer batch acc as recorded in the AssertionCreated event that was emitted for this
/// node
pub sequencer_batch_acc: H256,
/// Proof for the assertion hash field in the _assertions map in the
/// RollupCore
pub storage_proof: Vec<Vec<u8>>,
/// RollupCore contract proof in the ethereum world trie
pub contract_proof: Vec<Vec<u8>>,
}

// https://github.com/OffchainLabs/nitro-contracts/blob/780366a0c40caf694ed544a6a1d52c0de56573ba/src/rollup/AssertionState.sol#L11
#[derive(codec::Encode, codec::Decode, Debug, Clone)]
pub struct AssertionState {
pub global_state: GlobalState,
pub machine_status: MachineStatus,
pub end_history_root: H256,
}

alloy_sol_macro::sol! {
#![sol(all_derives)]

enum MachineStatusSol {
RUNNING,
FINISHED,
ERRORED
}

struct GlobalStateSol {
bytes32[2] bytes32Vals;
uint64[2] u64Vals;
}

struct AssertionStateSol {
GlobalStateSol globalState;
MachineStatusSol machineStatus;
bytes32 endHistoryRoot;
}

}

impl From<MachineStatus> for MachineStatusSol {
fn from(value: MachineStatus) -> Self {
match value {
MachineStatus::Running => MachineStatusSol::RUNNING,
MachineStatus::Finished => MachineStatusSol::FINISHED,
MachineStatus::Errored => MachineStatusSol::ERRORED,
}
}
}

impl From<GlobalState> for GlobalStateSol {
fn from(value: GlobalState) -> Self {
GlobalStateSol {
bytes32Vals: [value.block_hash.0.into(), value.send_root.0.into()],
u64Vals: [value.inbox_position, value.position_in_message],
}
}
}

impl From<AssertionState> for AssertionStateSol {
fn from(value: AssertionState) -> Self {
AssertionStateSol {
globalState: value.global_state.into(),
machineStatus: value.machine_status.into(),
endHistoryRoot: value.end_history_root.0.into(),
}
}
}

impl AssertionState {
fn hash(&self) -> H256 {
sp_io::hashing::keccak_256(&self.abi_encode()).into()
}

fn abi_encode(&self) -> Vec<u8> {
let assertion_state_sol: AssertionStateSol = self.clone().into();
assertion_state_sol.abi_encode()
}
}

// https://github.com/OffchainLabs/nitro-contracts/blob/109a8a36cd4c6a2a0d2b5003b01adee60d83e2a1/src/rollup/RollupLib.sol#L33
fn compute_assertion_hash(
previous_assertion_hash: H256,
after_state_hash: H256,
sequencer_batch_acc: H256,
) -> H256 {
let mut buf = Vec::new();
buf.extend_from_slice(&previous_assertion_hash[..]);
buf.extend_from_slice(&after_state_hash[..]);
buf.extend_from_slice(&sequencer_batch_acc[..]);
sp_io::hashing::keccak_256(&buf).into()
}

pub fn verify_arbitrum_bold<H: Keccak256 + Send + Sync>(
payload: ArbitrumBoldProof,
root: H256,
rollup_core_address: H160,
consensus_state_id: ConsensusStateId,
) -> Result<IntermediateState, anyhow::Error> {
let storage_root =
get_contract_account::<H>(payload.contract_proof, &rollup_core_address.0, root)?
.storage_root
.0
.into();

let header: Header = payload.arbitrum_header.as_ref().into();
if &payload.after_state.global_state.send_root[..] != &payload.arbitrum_header.extra_data {
Err(anyhow!("Arbitrum header extra data does not match send root in global state",))?
}

let block_number = payload.arbitrum_header.number.low_u64();
let timestamp = payload.arbitrum_header.timestamp;
let state_root = payload.arbitrum_header.state_root.0.into();

let header_hash = header.hash::<H>();
if payload.after_state.global_state.block_hash != header_hash {
Err(anyhow!("Arbitrum header hash does not match block hash in global state",))?
}

let assertion_hash = compute_assertion_hash(
payload.previous_assertion_hash,
payload.after_state.hash(),
payload.sequencer_batch_acc,
);

let assertion_hash_key = derive_map_key::<H>(assertion_hash.0.to_vec(), ASSERTIONS_SLOT);

// Only valid assertions nodes are inserted in the rollup storage
// A Some() value from the proof asserts that this assertion is valid and exists in storage
// https://github.com/OffchainLabs/nitro-contracts/blob/94999b3e2d3b4b7f8e771cc458b9eb229620dd8f/src/rollup/RollupCore.sol#L542

get_value_from_proof::<H>(assertion_hash_key.0.to_vec(), storage_root, payload.storage_proof)?
.ok_or_else(|| anyhow!("Assertion provided is invalid"))?;

Ok(IntermediateState {
height: StateMachineHeight {
id: StateMachineId {
// note: This default state machine id should not be used to store the state
// commitment
state_id: StateMachine::Evm(Default::default()),
consensus_state_id,
},
height: block_number,
},
commitment: StateCommitment { timestamp, overlay_root: None, state_root },
})
}
Loading

0 comments on commit 74859b3

Please sign in to comment.