Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(client): Continue derivation on execution failure #545

Merged
merged 1 commit into from
Sep 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 6 additions & 15 deletions bin/client/src/kona.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,12 @@
extern crate alloc;

use alloc::sync::Arc;
use alloy_consensus::Header;
use kona_client::{
l1::{DerivationDriver, OracleBlobProvider, OracleL1ChainProvider},
l2::OracleL2ChainProvider,
BootInfo, CachingOracle,
};
use kona_common_proc::client_entry;
use kona_executor::StatelessL2BlockExecutor;
use op_alloy_rpc_types_engine::OptimismAttributesWithParent;

pub(crate) mod fault;
use fault::{fpvm_handle_register, HINT_WRITER, ORACLE_READER};
Expand Down Expand Up @@ -50,6 +47,7 @@ fn main() -> Result<()> {
// DERIVATION & EXECUTION //
////////////////////////////////////////////////////////////////

// Create a new derivation driver with the given boot information and oracle.
let mut driver = DerivationDriver::new(
boot.as_ref(),
oracle.as_ref(),
Expand All @@ -58,19 +56,12 @@ fn main() -> Result<()> {
l2_provider.clone(),
)
.await?;
let OptimismAttributesWithParent { attributes, .. } =
driver.produce_disputed_payload().await?;

let mut executor = StatelessL2BlockExecutor::builder(
&boot.rollup_config,
l2_provider.clone(),
l2_provider,
)
.with_parent_header(driver.take_l2_safe_head_header())
.with_handle_register(fpvm_handle_register)
.build();
let Header { number, .. } = *executor.execute_payload(attributes)?;
let output_root = executor.compute_output_root()?;
// Run the derivation pipeline until we are able to produce the output root of the claimed
// L2 block.
let (number, output_root) = driver
.produce_output(&boot.rollup_config, &l2_provider, &l2_provider, fpvm_handle_register)
.await?;

////////////////////////////////////////////////////////////////
// EPILOGUE //
Expand Down
61 changes: 54 additions & 7 deletions bin/client/src/l1/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use super::OracleL1ChainProvider;
use crate::{l2::OracleL2ChainProvider, BootInfo, HintType};
use alloc::sync::Arc;
use alloy_consensus::{Header, Sealed};
use alloy_primitives::B256;
use anyhow::{anyhow, Result};
use core::fmt::Debug;
use kona_derive::{
Expand All @@ -19,8 +20,10 @@ use kona_derive::{
},
traits::{BlobProvider, ChainProvider, L2ChainProvider, OriginProvider},
};
use kona_mpt::TrieProvider;
use kona_executor::{KonaHandleRegister, StatelessL2BlockExecutor};
use kona_mpt::{TrieHinter, TrieProvider};
use kona_preimage::{CommsClient, PreimageKey, PreimageKeyType};
use op_alloy_genesis::RollupConfig;
use op_alloy_protocol::{BlockInfo, L2BlockInfo};
use op_alloy_rpc_types_engine::OptimismAttributesWithParent;
use tracing::{info, warn};
Expand Down Expand Up @@ -150,14 +153,58 @@ where
Ok(Self { l2_safe_head, l2_safe_head_header, pipeline })
}

/// Produces the output root of the next L2 block.
///
/// ## Takes
/// - `cfg`: The rollup configuration.
/// - `provider`: The trie provider.
/// - `hinter`: The trie hinter.
/// - `handle_register`: The handle register for the EVM.
///
/// ## Returns
/// - `Ok((number, output_root))` - A tuple containing the number of the produced block and the
/// output root.
/// - `Err(e)` - An error if the block could not be produced.
pub async fn produce_output<P, H>(
&mut self,
cfg: &RollupConfig,
provider: &P,
hinter: &H,
handle_register: KonaHandleRegister<P, H>,
) -> Result<(u64, B256)>
where
P: TrieProvider + Send + Sync + Clone,
H: TrieHinter + Send + Sync + Clone,
{
loop {
let OptimismAttributesWithParent { attributes, .. } = self.produce_payload().await?;

let mut executor =
StatelessL2BlockExecutor::builder(cfg, provider.clone(), hinter.clone())
.with_parent_header(self.l2_safe_head_header().clone())
.with_handle_register(handle_register)
.build();

let number = match executor.execute_payload(attributes) {
Ok(Header { number, .. }) => *number,
Err(e) => {
tracing::error!(target: "client", "Failed to execute L2 block: {}", e);
continue;
}
};
let output_root = executor.compute_output_root()?;

return Ok((number, output_root));
}
}

/// Produces the disputed [OptimismAttributesWithParent] payload, directly after the starting L2
/// output root passed through the [BootInfo].
pub async fn produce_disputed_payload(&mut self) -> Result<OptimismAttributesWithParent> {
async fn produce_payload(&mut self) -> Result<OptimismAttributesWithParent> {
// As we start the safe head at the disputed block's parent, we step the pipeline until the
// first attributes are produced. All batches at and before the safe head will be
// dropped, so the first payload will always be the disputed one.
let mut attributes = None;
while attributes.is_none() {
loop {
match self.pipeline.step(self.l2_safe_head).await {
StepResult::PreparedAttributes => {
info!(target: "client_derivation_driver", "Stepped derivation pipeline")
Expand Down Expand Up @@ -190,10 +237,10 @@ where
}
}

attributes = self.pipeline.next();
if let Some(attrs) = self.pipeline.next() {
return Ok(attrs);
}
}

Ok(attributes.expect("Failed to derive payload attributes"))
}

/// Finds the startup information for the derivation pipeline.
Expand Down