Skip to content

Commit

Permalink
feat(client): Invalidate impossibly old claims (#852)
Browse files Browse the repository at this point in the history
  • Loading branch information
clabby authored Nov 27, 2024
1 parent 39ad652 commit 344d851
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 61 deletions.
100 changes: 63 additions & 37 deletions bin/client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,21 @@
extern crate alloc;

use alloc::sync::Arc;
use alloy_consensus::{Header, Sealed};
use alloy_primitives::B256;
use core::fmt::Debug;
use kona_driver::{Driver, DriverError};
use kona_executor::ExecutorError;
use kona_preimage::{HintWriterClient, PreimageOracleClient};
use kona_executor::{ExecutorError, TrieDBProvider};
use kona_preimage::{
CommsClient, HintWriterClient, PreimageKey, PreimageKeyType, PreimageOracleClient,
};
use kona_proof::{
errors::OracleProviderError,
executor::KonaExecutor,
l1::{OracleBlobProvider, OracleL1ChainProvider, OraclePipeline},
l2::OracleL2ChainProvider,
sync::new_pipeline_cursor,
BootInfo, CachingOracle,
BootInfo, CachingOracle, HintType,
};
use thiserror::Error;
use tracing::{error, info, warn};
Expand Down Expand Up @@ -64,49 +67,42 @@ where
return Err(e.into());
}
};
let l1_provider = OracleL1ChainProvider::new(boot.clone(), oracle.clone());
let l2_provider = OracleL2ChainProvider::new(boot.clone(), oracle.clone());
let mut l1_provider = OracleL1ChainProvider::new(boot.clone(), oracle.clone());
let mut l2_provider = OracleL2ChainProvider::new(boot.clone(), oracle.clone());
let beacon = OracleBlobProvider::new(oracle.clone());

// If the genesis block is claimed, we can exit early.
// The agreed upon prestate is consented to by all parties, and there is no state
// transition, so the claim is valid if the claimed output root matches the agreed
// upon output root.
if boot.claimed_l2_block_number == 0 {
warn!("Genesis block claimed. Exiting early.");
if boot.agreed_l2_output_root == boot.claimed_l2_output_root {
info!(
target: "client",
"Successfully validated genesis block with output root {output_root}",
output_root = boot.agreed_l2_output_root
);
return Ok(());
} else {
error!(
target: "client",
"Failed to validate genesis block. Expected {genesis_root}, actual {claimed_root}",
genesis_root = boot.agreed_l2_output_root,
claimed_root = boot.claimed_l2_output_root
);
return Err(FaultProofProgramError::InvalidClaim(
boot.agreed_l2_output_root,
boot.claimed_l2_output_root,
));
};
// If the claimed L2 block number is less than the safe head of the L2 chain, the claim is
// invalid.
let safe_head = fetch_safe_head(oracle.as_ref(), boot.as_ref(), &mut l2_provider).await?;
if boot.claimed_l2_block_number < safe_head.number {
error!(
target: "client",
"Claimed L2 block number {claimed} is less than the safe head {safe}",
claimed = boot.claimed_l2_block_number,
safe = safe_head.number
);
return Err(FaultProofProgramError::InvalidClaim(
boot.agreed_l2_output_root,
boot.claimed_l2_output_root,
));
}

// In the case where the agreed upon L2 output root is the same as the claimed L2 output root,
// trace extension is detected and we can skip the derivation and execution steps.
if boot.agreed_l2_output_root == boot.claimed_l2_output_root {
info!(
target: "client",
"Trace extension detected. State transition is already agreed upon.",
);
return Ok(());
}

////////////////////////////////////////////////////////////////
// DERIVATION & EXECUTION //
////////////////////////////////////////////////////////////////

// Create a new derivation driver with the given boot information and oracle.
let cursor = new_pipeline_cursor(
oracle.clone(),
&boot,
&mut l1_provider.clone(),
&mut l2_provider.clone(),
)
.await?;
let cursor = new_pipeline_cursor(&boot, safe_head, &mut l1_provider, &mut l2_provider).await?;
let cfg = Arc::new(boot.rollup_config.clone());
let pipeline = OraclePipeline::new(
cfg.clone(),
Expand Down Expand Up @@ -147,3 +143,33 @@ where

Ok(())
}

/// Fetches the safe head of the L2 chain based on the agreed upon L2 output root in the
/// [BootInfo].
async fn fetch_safe_head<O>(
caching_oracle: &O,
boot_info: &BootInfo,
l2_chain_provider: &mut OracleL2ChainProvider<O>,
) -> Result<Sealed<Header>, OracleProviderError>
where
O: CommsClient,
{
caching_oracle
.write(&HintType::StartingL2Output.encode_with(&[boot_info.agreed_l2_output_root.as_ref()]))
.await
.map_err(OracleProviderError::Preimage)?;
let mut output_preimage = [0u8; 128];
caching_oracle
.get_exact(
PreimageKey::new(*boot_info.agreed_l2_output_root, PreimageKeyType::Keccak256),
&mut output_preimage,
)
.await
.map_err(OracleProviderError::Preimage)?;

let safe_hash =
output_preimage[96..128].try_into().map_err(OracleProviderError::SliceConversion)?;
l2_chain_provider
.header_by_hash(safe_hash)
.map(|header| Sealed::new_unchecked(header, safe_hash))
}
28 changes: 4 additions & 24 deletions crates/proof-sdk/proof/src/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,44 +2,25 @@
use crate::{
errors::OracleProviderError, l1::OracleL1ChainProvider, l2::OracleL2ChainProvider, BootInfo,
FlushableCache, HintType,
FlushableCache,
};
use alloc::sync::Arc;
use alloy_consensus::Sealed;
use alloy_consensus::{Header, Sealed};
use core::fmt::Debug;
use kona_derive::traits::ChainProvider;
use kona_driver::{PipelineCursor, TipCursor};
use kona_executor::TrieDBProvider;
use kona_preimage::{CommsClient, PreimageKey, PreimageKeyType};
use kona_preimage::CommsClient;
use op_alloy_protocol::BatchValidationProvider;

/// Constructs a [`PipelineCursor`] from the caching oracle, boot info, and providers.
pub async fn new_pipeline_cursor<O>(
caching_oracle: Arc<O>,
boot_info: &BootInfo,
safe_header: Sealed<Header>,
chain_provider: &mut OracleL1ChainProvider<O>,
l2_chain_provider: &mut OracleL2ChainProvider<O>,
) -> Result<PipelineCursor, OracleProviderError>
where
O: CommsClient + FlushableCache + FlushableCache + Send + Sync + Debug,
{
// Find the initial safe head, based off of the starting L2 block number in the boot info.
caching_oracle
.write(&HintType::StartingL2Output.encode_with(&[boot_info.agreed_l2_output_root.as_ref()]))
.await
.map_err(OracleProviderError::Preimage)?;
let mut output_preimage = [0u8; 128];
caching_oracle
.get_exact(
PreimageKey::new(*boot_info.agreed_l2_output_root, PreimageKeyType::Keccak256),
&mut output_preimage,
)
.await
.map_err(OracleProviderError::Preimage)?;

let safe_hash =
output_preimage[96..128].try_into().map_err(OracleProviderError::SliceConversion)?;
let safe_header = l2_chain_provider.header_by_hash(safe_hash)?;
let safe_head_info = l2_chain_provider.l2_block_info_by_number(safe_header.number).await?;
let l1_origin = chain_provider.block_info_by_number(safe_head_info.l1_origin.number).await?;

Expand All @@ -54,7 +35,6 @@ where
let origin = chain_provider.block_info_by_number(l1_origin_number).await?;

// Construct the cursor.
let safe_header = Sealed::new_unchecked(safe_header, safe_hash);
let mut cursor = PipelineCursor::new(channel_timeout, origin);
let tip = TipCursor::new(safe_head_info, safe_header, boot_info.agreed_l2_output_root);
cursor.advance(origin, tip);
Expand Down

0 comments on commit 344d851

Please sign in to comment.