Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
ratankaliani committed Jan 29, 2025
2 parents b734851 + 71a02cc commit 5ba17e6
Show file tree
Hide file tree
Showing 136 changed files with 1,039 additions and 10,405 deletions.
337 changes: 227 additions & 110 deletions Cargo.lock

Large diffs are not rendered by default.

19 changes: 10 additions & 9 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,13 @@ kona-preimage = { path = "crates/proof-sdk/preimage", version = "0.2.1", default
kona-std-fpvm-proc = { path = "crates/proof-sdk/std-fpvm-proc", version = "0.1.2", default-features = false }

# Maili
maili-consensus = { version = "0.1.6", default-features = false }
maili-protocol = { version = "0.1.6", default-features = false }
maili-registry = { version = "0.1.6", default-features = false }
maili-genesis = { version = "0.1.6", default-features = false }
maili-rpc = { version = "0.1.9", default-features = false }
maili-protocol = { version = "0.1.9", default-features = false }
maili-registry = { version = "0.1.9", default-features = false }
maili-genesis = { version = "0.1.9", default-features = false }

# Alloy
alloy-rlp = { version = "0.3.10", default-features = false }
alloy-rlp = { version = "0.3.11", default-features = false }
alloy-trie = { version = "0.7.8", default-features = false }
alloy-eips = { version = "0.9.2", default-features = false }
alloy-serde = { version = "0.9.2", default-features = false }
Expand All @@ -94,16 +94,16 @@ alloy-consensus = { version = "0.9.2", default-features = false }
alloy-transport = { version = "0.9.2", default-features = false }
alloy-rpc-types = { version = "0.9.2", default-features = false }
alloy-rpc-client = { version = "0.9.2", default-features = false }
alloy-primitives = { version = "0.8.14", default-features = false }
alloy-primitives = { version = "0.8.19", default-features = false }
alloy-node-bindings = { version = "0.9.2", default-features = false }
alloy-transport-http = { version = "0.9.2", default-features = false }
alloy-rpc-types-engine = { version = "0.9.2", default-features = false }
alloy-rpc-types-beacon = { version = "0.9.2", default-features = false }
alloy-sol-types = { version = "0.8.18", default-features = false }
alloy-sol-types = { version = "0.8.19", default-features = false }

# OP Alloy
op-alloy-consensus = { version = "0.9.5", default-features = false }
op-alloy-rpc-types-engine = { version = "0.9.5", default-features = false }
op-alloy-consensus = { version = "0.9.6", default-features = false }
op-alloy-rpc-types-engine = { version = "0.9.6", default-features = false }

# General
lru = "0.12.5"
Expand All @@ -117,6 +117,7 @@ reqwest = "0.12.12"
async-trait = "0.1.85"
linked_list_allocator = "0.10.5"
rstest = "0.24.0"
tempfile = "3.15.0"

# General
sha2 = { version = "0.10.8", default-features = false }
Expand Down
72 changes: 39 additions & 33 deletions bin/client/src/interop/transition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::interop::util::fetch_l2_safe_head_hash;
use alloc::sync::Arc;
use alloy_consensus::Sealed;
use alloy_primitives::B256;
use core::fmt::Debug;
use core::{cmp::Ordering, fmt::Debug};
use kona_derive::errors::{PipelineError, PipelineErrorKind};
use kona_driver::{Driver, DriverError};
use kona_executor::{KonaHandleRegister, TrieDBProvider};
Expand Down Expand Up @@ -45,7 +45,7 @@ where
"No derivation/execution required, transition state is already saturated."
);

return transition_and_check(pre, None, boot.claimed_post_state);
return transition_and_check(pre, None, boot.claimed_post_state, None);
}
}

Expand All @@ -70,30 +70,27 @@ where

// If the claimed L2 block number is less than the safe head of the L2 chain, the claim is
// invalid.
if claimed_l2_block_number < safe_head.number {
error!(
target: "interop_client",
"Claimed L2 block number {claimed} is less than the safe head {safe}",
claimed = claimed_l2_block_number,
safe = safe_head.number
);
return Err(FaultProofProgramError::InvalidClaim(
boot.agreed_pre_state,
boot.claimed_post_state,
));
}

// In the case where the agreed upon L2 pre-state is the same as the claimed L2 post-state,
// the state transition is invalid as it does not extend the chain.
if boot.agreed_pre_state == boot.claimed_post_state {
info!(
target: "interop_client",
"No-op state transition is invalid; Pre == post.",
);
return Err(FaultProofProgramError::InvalidClaim(
boot.agreed_pre_state,
boot.claimed_post_state,
));
match claimed_l2_block_number.cmp(&safe_head.number) {
Ordering::Less => {
error!(
target: "interop_client",
"Claimed L2 block number {claimed} is less than the safe head {safe}",
claimed = claimed_l2_block_number,
safe = safe_head.number
);
return Err(FaultProofProgramError::InvalidClaim(
boot.agreed_pre_state,
boot.claimed_post_state,
));
}
Ordering::Equal => {
info!(
target: "interop_client",
"Claimed L2 block is already safe."
);
return Ok(());
}
_ => { /* Continue */ }
}

// Create a new derivation driver with the given boot information and oracle.
Expand All @@ -117,9 +114,14 @@ where
// Run the derivation pipeline until we are able to produce the output root of the claimed
// L2 block.
match driver.advance_to_target(&boot.rollup_config, Some(claimed_l2_block_number)).await {
Ok((_, block_hash, output_root)) => {
let optimistic_block = OptimisticBlock::new(block_hash, output_root);
transition_and_check(pre, Some(optimistic_block), boot.claimed_post_state)?;
Ok((safe_head, output_root)) => {
let optimistic_block = OptimisticBlock::new(safe_head.block_info.hash, output_root);
transition_and_check(
pre,
Some(optimistic_block),
boot.claimed_post_state,
Some((boot.claimed_l2_timestamp, safe_head.block_info.timestamp)),
)?;

info!(
target: "interop_client",
Expand Down Expand Up @@ -160,7 +162,8 @@ where
fn transition_and_check(
pre_state: PreState,
optimistic_block: Option<OptimisticBlock>,
expected: B256,
expected_post_state: B256,
timestamps: Option<(u64, u64)>,
) -> Result<(), FaultProofProgramError> {
let did_append = optimistic_block.is_some();
let post_state = pre_state
Expand All @@ -175,15 +178,18 @@ fn transition_and_check(
);
}

if post_state_commitment != expected {
if post_state_commitment != expected_post_state || timestamps.is_some_and(|(a, b)| a != b) {
error!(
target: "interop_client",
"Failed to validate progressed transition state. Expected post-state commitment: {expected}, actual: {actual}",
expected = expected,
expected = expected_post_state,
actual = post_state_commitment
);

return Err(FaultProofProgramError::InvalidClaim(expected, post_state_commitment));
return Err(FaultProofProgramError::InvalidClaim(
expected_post_state,
post_state_commitment,
));
}

info!(
Expand Down
140 changes: 140 additions & 0 deletions bin/client/src/precompiles/bls12.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
//! Contains the accelerated precompile for the BLS12-381 curve.
//!
//! BLS12-381 is introduced in [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537).
//!
//! For constants and logic, see the [revm implementation].
//!
//! [revm implementation]: https://github.com/bluealloy/revm/blob/main/crates/precompile/src/bls12_381/pairing.rs
use crate::{HINT_WRITER, ORACLE_READER};
use alloc::{string::ToString, vec::Vec};
use alloy_primitives::{address, keccak256, Address, Bytes};
use kona_preimage::{
errors::PreimageOracleError, HintWriterClient, PreimageKey, PreimageKeyType,
PreimageOracleClient,
};
use kona_proof::{errors::OracleProviderError, HintType};
use revm::{
precompile::{Error as PrecompileError, Precompile, PrecompileResult, PrecompileWithAddress},
primitives::PrecompileOutput,
};

/// The max pairing size for BLS12-381 input given a 20M gas limit.
const BLS12_MAX_PAIRING_SIZE_ISTHMUS: usize = 235_008;

/// The address of the BLS12-381 pairing check precompile.
const BLS12_PAIRING_CHECK: Address = address!("0x000000000000000000000000000000000000000f");

/// Input length of pairing operation.
const INPUT_LENGTH: usize = 384;

/// Multiplier gas fee for BLS12-381 pairing operation.
const PAIRING_MULTIPLIER_BASE: u64 = 32600;

/// Offset gas fee for BLS12-381 pairing operation.
const PAIRING_OFFSET_BASE: u64 = 37700;

/// The address of the BLS12-381 pairing precompile.
pub(crate) const FPVM_BLS12_PAIRING_ISTHMUS: PrecompileWithAddress =
PrecompileWithAddress(BLS12_PAIRING_CHECK, Precompile::Standard(fpvm_bls12_pairing_isthmus));

/// Performs an FPVM-accelerated BLS12-381 pairing check.
fn fpvm_bls12_pairing(input: &Bytes, gas_limit: u64) -> PrecompileResult {
let input_len = input.len();
if input_len % INPUT_LENGTH != 0 {
return Err(PrecompileError::Other(alloc::format!(
"Pairing input length should be multiple of {INPUT_LENGTH}, was {input_len}"
))
.into());
}

let k = input_len / INPUT_LENGTH;
let required_gas: u64 = PAIRING_MULTIPLIER_BASE * k as u64 + PAIRING_OFFSET_BASE;
if required_gas > gas_limit {
return Err(PrecompileError::OutOfGas.into());
}

let result_data = kona_proof::block_on(async move {
// Write the hint for the ecrecover precompile run.
let hint_data = &[BLS12_PAIRING_CHECK.as_ref(), input.as_ref()];
HINT_WRITER
.write(&HintType::L1Precompile.encode_with(hint_data))
.await
.map_err(OracleProviderError::Preimage)?;

// Construct the key hash for the ecrecover precompile run.
let raw_key_data = hint_data.iter().copied().flatten().copied().collect::<Vec<u8>>();
let key_hash = keccak256(&raw_key_data);

// Fetch the result of the ecrecover precompile run from the host.
let result_data = ORACLE_READER
.get(PreimageKey::new(*key_hash, PreimageKeyType::Precompile))
.await
.map_err(OracleProviderError::Preimage)?;

// Ensure we've received valid result data.
if result_data.is_empty() {
return Err(OracleProviderError::Preimage(PreimageOracleError::Other(
"Invalid result data".to_string(),
)));
}

// Ensure we've not received an error from the host.
if result_data[0] == 0 {
return Err(OracleProviderError::Preimage(PreimageOracleError::Other(
"Error executing ecrecover precompile in host".to_string(),
)));
}

// Return the result data.
Ok(result_data[1..].to_vec())
})
.map_err(|e| PrecompileError::Other(e.to_string()))?;

Ok(PrecompileOutput::new(required_gas, result_data.into()))
}

/// Performs an FPVM-accelerated `bls12` pairing check precompile call
/// after the Isthmus Hardfork.
fn fpvm_bls12_pairing_isthmus(input: &Bytes, gas_limit: u64) -> PrecompileResult {
if input.len() > BLS12_MAX_PAIRING_SIZE_ISTHMUS {
return Err(PrecompileError::Other(alloc::format!(
"Pairing input length must be at most {}",
BLS12_MAX_PAIRING_SIZE_ISTHMUS
))
.into());
}

fpvm_bls12_pairing(input, gas_limit)
}

#[cfg(test)]
mod tests {
use super::*;
use alloc::vec;

#[test]
fn test_fpvm_bls12_pairing_isthmus_max_bytes() {
let input = Bytes::from(vec![0u8; BLS12_MAX_PAIRING_SIZE_ISTHMUS + 1]);
let gas_limit = PAIRING_MULTIPLIER_BASE;
let err = PrecompileError::Other("Pairing input length must be at most 235008".to_string());
assert_eq!(fpvm_bls12_pairing_isthmus(&input, gas_limit), Err(err.into()));
}

#[test]
fn test_fpvm_bls12_offset() {
let input = Bytes::from(vec![0u8; INPUT_LENGTH + 1]);
let gas_limit = PAIRING_OFFSET_BASE;
let err = PrecompileError::Other(
"Pairing input length should be multiple of 384, was 385".to_string(),
);
assert_eq!(fpvm_bls12_pairing(&input, gas_limit), Err(err.into()));
}

#[test]
fn test_fpvm_bls12_out_of_gas() {
let input = Bytes::from(vec![0u8; INPUT_LENGTH * 2]);
let gas_limit = PAIRING_MULTIPLIER_BASE - 1;
assert_eq!(fpvm_bls12_pairing(&input, gas_limit), Err(PrecompileError::OutOfGas.into()));
}
}
5 changes: 5 additions & 0 deletions bin/client/src/precompiles/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use revm::{
State,
};

mod bls12;
mod bn128_pair;
mod ecrecover;
mod kzg_point_eval;
Expand Down Expand Up @@ -43,6 +44,10 @@ pub(crate) fn fpvm_handle_register<F, H>(
ctx_precompiles.extend([bn128_pair::FPVM_ECPAIRING_GRANITE]);
}

if spec_id.is_enabled_in(SpecId::ISTHMUS) {
ctx_precompiles.extend([bls12::FPVM_BLS12_PAIRING_ISTHMUS]);
}

ctx_precompiles
});
}
6 changes: 3 additions & 3 deletions bin/client/src/single.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ where

// Run the derivation pipeline until we are able to produce the output root of the claimed
// L2 block.
let (number, _, output_root) =
let (safe_head, output_root) =
driver.advance_to_target(&boot.rollup_config, Some(boot.claimed_l2_block_number)).await?;

////////////////////////////////////////////////////////////////
Expand All @@ -134,7 +134,7 @@ where
error!(
target: "client",
"Failed to validate L2 block #{number} with output root {output_root}",
number = number,
number = safe_head.block_info.number,
output_root = output_root
);
return Err(FaultProofProgramError::InvalidClaim(output_root, boot.claimed_l2_output_root));
Expand All @@ -143,7 +143,7 @@ where
info!(
target: "client",
"Successfully validated L2 block #{number} with output root {output_root}",
number = number,
number = safe_head.block_info.number,
output_root = output_root
);

Expand Down
3 changes: 2 additions & 1 deletion bin/host/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ kona-client.workspace = true
kona-providers-alloy.workspace = true

# Maili
maili-protocol = { workspace = true, features = ["std", "serde"] }
maili-rpc.workspace = true
maili-registry.workspace = true
maili-protocol = { workspace = true, features = ["std", "serde"] }
maili-genesis = { workspace = true, features = ["std", "serde"] }

# Alloy
Expand Down
1 change: 1 addition & 0 deletions bin/host/src/eth/precompiles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use revm::{
pub(crate) const ACCELERATED_PRECOMPILES: &[PrecompileWithAddress] = &[
precompile::secp256k1::ECRECOVER, // ecRecover
precompile::bn128::pair::ISTANBUL, // ecPairing
precompile::bls12_381::pairing::PRECOMPILE, // BLS12-381 pairing
precompile::kzg_point_evaluation::POINT_EVALUATION, // KZG point evaluation
];

Expand Down
Loading

0 comments on commit 5ba17e6

Please sign in to comment.