Skip to content

Commit

Permalink
fix(client): Interop bugfixes (#1006)
Browse files Browse the repository at this point in the history
  • Loading branch information
clabby authored Feb 5, 2025
1 parent eaec362 commit 7c11275
Show file tree
Hide file tree
Showing 7 changed files with 53 additions and 25 deletions.
28 changes: 12 additions & 16 deletions bin/client/src/interop/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use kona_executor::{ExecutorError, KonaHandleRegister};
use kona_preimage::{HintWriterClient, PreimageOracleClient};
use kona_proof::{errors::OracleProviderError, l2::OracleL2ChainProvider, CachingOracle};
use kona_proof_interop::{
BootInfo, ConsolidationError, PreState, INVALID_TRANSITION_HASH, TRANSITION_STATE_MAX_STEPS,
boot::BootstrapError, BootInfo, ConsolidationError, PreState, TRANSITION_STATE_MAX_STEPS,
};
use thiserror::Error;
use tracing::{error, info};
Expand All @@ -31,18 +31,18 @@ pub enum FaultProofProgramError {
/// An error occurred in the driver.
#[error(transparent)]
Driver(#[from] DriverError<ExecutorError>),
/// An error occurred during RLP decoding.
#[error("RLP decoding error: {0}")]
Rlp(alloy_rlp::Error),
/// Consolidation error.
#[error(transparent)]
Consolidation(#[from] ConsolidationError),
/// Bootstrap error
#[error(transparent)]
Bootstrap(#[from] BootstrapError),
/// State transition failed.
#[error("Critical state transition failure")]
StateTransitionFailed,
/// Missing a rollup configuration.
#[error("Missing rollup configuration for chain ID {0}")]
MissingRollupConfig(u64),
/// Consolidation error.
#[error(transparent)]
Consolidation(#[from] ConsolidationError),
}

/// Executes the interop fault proof program with the given [PreimageOracleClient] and
Expand All @@ -68,20 +68,16 @@ where
let oracle = Arc::new(CachingOracle::new(ORACLE_LRU_SIZE, oracle_client, hint_client));
let boot = match BootInfo::load(oracle.as_ref()).await {
Ok(boot) => boot,
Err(BootstrapError::NoOpTransition) => {
info!(target: "client_interop", "No-op transition, short-circuiting.");
return Ok(());
}
Err(e) => {
error!(target: "client_interop", "Failed to load boot info: {:?}", e);
error!(target: "client_interop", "Failed to load boot info: {}", e);
return Err(e.into());
}
};

// If the pre state is invalid, short-circuit and check if the post-state claim is also invalid.
if boot.agreed_pre_state_commitment == INVALID_TRANSITION_HASH &&
boot.claimed_post_state == INVALID_TRANSITION_HASH
{
info!(target: "client_interop", "Invalid pre and post state, short-circuiting.");
return Ok(());
}

// Load in the agreed pre-state from the preimage oracle in order to determine the active
// sub-problem.
match boot.agreed_pre_state {
Expand Down
2 changes: 1 addition & 1 deletion bin/host/src/interop/cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ impl InteropHost {
let preimage = BidirectionalChannel::new()?;

let server_task = self.start_server(hint.host, preimage.host).await?;
let client_task = task::spawn(kona_client::single::run(
let client_task = task::spawn(kona_client::interop::run(
OracleReader::new(preimage.client),
HintWriter::new(hint.client),
None,
Expand Down
2 changes: 1 addition & 1 deletion bin/host/src/interop/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ impl HintHandler for InteropHintHandler {

let block_number = u64::from_be_bytes(hint.data.as_ref()[..8].try_into()?);
let address = Address::from_slice(&hint.data.as_ref()[8..28]);
let slot = B256::from_slice(&hint.data.as_ref()[28..]);
let slot = B256::from_slice(&hint.data.as_ref()[28..60]);
let chain_id = u64::from_be_bytes(hint.data[60..].try_into()?);

let mut proof_response = providers
Expand Down
36 changes: 32 additions & 4 deletions crates/proof-sdk/proof-interop/src/boot.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! This module contains the prologue phase of the client program, pulling in the boot information
//! through the `PreimageOracle` ABI as local keys.
use crate::{HintType, PreState};
use crate::{HintType, PreState, INVALID_TRANSITION, INVALID_TRANSITION_HASH};
use alloc::{string::ToString, vec::Vec};
use alloy_primitives::{Bytes, B256, U256};
use alloy_rlp::Decodable;
Expand All @@ -13,6 +13,7 @@ use kona_proof::errors::OracleProviderError;
use maili_genesis::RollupConfig;
use maili_registry::{HashMap, ROLLUP_CONFIGS};
use serde::{Deserialize, Serialize};
use thiserror::Error;
use tracing::warn;

/// The local key ident for the L1 head hash.
Expand Down Expand Up @@ -56,7 +57,7 @@ impl BootInfo {
/// ## Returns
/// - `Ok(BootInfo)`: The boot information.
/// - `Err(_)`: Failed to load the boot information.
pub async fn load<O>(oracle: &O) -> Result<Self, OracleProviderError>
pub async fn load<O>(oracle: &O) -> Result<Self, BootstrapError>
where
O: PreimageOracleClient + HintWriterClient + Clone + Send,
{
Expand Down Expand Up @@ -88,9 +89,22 @@ impl BootInfo {
.map_err(OracleProviderError::SliceConversion)?,
);

let raw_pre_state = read_raw_pre_state(oracle, l2_pre).await?;
if raw_pre_state == INVALID_TRANSITION {
warn!(
target: "boot-loader",
"Invalid pre-state, short-circuiting to check post-state claim."
);

if l2_post == INVALID_TRANSITION_HASH {
return Err(BootstrapError::NoOpTransition);
} else {
return Err(BootstrapError::InvalidPostState(l2_post));
}
}

let agreed_pre_state =
PreState::decode(&mut read_raw_pre_state(oracle, l2_pre).await?.as_ref())
.map_err(OracleProviderError::Rlp)?;
PreState::decode(&mut raw_pre_state.as_ref()).map_err(OracleProviderError::Rlp)?;

let chain_ids: Vec<_> = match agreed_pre_state {
PreState::SuperRoot(ref super_root) => {
Expand Down Expand Up @@ -135,6 +149,20 @@ impl BootInfo {
}
}

/// An error that occurred during the bootstrapping phase.
#[derive(Debug, Error)]
pub enum BootstrapError {
/// An error occurred while reading from the preimage oracle.
#[error(transparent)]
Oracle(#[from] OracleProviderError),
/// The pre-state is invalid and the post-state claim is not invalid.
#[error("`INVALID` pre-state claim; Post-state {0} unexpected.")]
InvalidPostState(B256),
/// The pre-state is invalid and the post-state claim is also invalid.
#[error("No-op state transition detected; both pre and post states are `INVALID`.")]
NoOpTransition,
}

/// Reads the raw pre-state from the preimage oracle.
pub(crate) async fn read_raw_pre_state<O>(
caching_oracle: &O,
Expand Down
3 changes: 2 additions & 1 deletion crates/proof-sdk/proof-interop/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ extern crate alloc;

mod pre_state;
pub use pre_state::{
OptimisticBlock, PreState, TransitionState, INVALID_TRANSITION_HASH, TRANSITION_STATE_MAX_STEPS,
OptimisticBlock, PreState, TransitionState, INVALID_TRANSITION, INVALID_TRANSITION_HASH,
TRANSITION_STATE_MAX_STEPS,
};

mod hint;
Expand Down
3 changes: 3 additions & 0 deletions crates/proof-sdk/proof-interop/src/pre_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ pub(crate) const TRANSITION_STATE_VERSION: u8 = 255;
/// The maximum number of steps allowed in a [TransitionState].
pub const TRANSITION_STATE_MAX_STEPS: u64 = 2u64.pow(10) - 1;

/// The [Bytes] representation of the string "invalid".
pub const INVALID_TRANSITION: Bytes = Bytes::from_static(b"invalid");

/// `keccak256("invalid")`
pub const INVALID_TRANSITION_HASH: B256 =
b256!("ffd7db0f9d5cdeb49c4c9eba649d4dc6d852d64671e65488e57f58584992ac68");
Expand Down
4 changes: 2 additions & 2 deletions crates/proof-sdk/proof/src/hint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ where
}

let mut hint_data = Vec::with_capacity(self.data.len() + data.as_ref().len());
hint_data[..self.data.len()].copy_from_slice(self.data.as_ref());
hint_data[self.data.len()..].copy_from_slice(data.as_ref());
hint_data.extend_from_slice(self.data.as_ref());
hint_data.extend_from_slice(data.as_ref());

Self { data: hint_data.into(), ..self }
}
Expand Down

0 comments on commit 7c11275

Please sign in to comment.