Skip to content

Commit

Permalink
apply comments
Browse files Browse the repository at this point in the history
  • Loading branch information
fakedev9999 committed Feb 5, 2025
1 parent 2c816dd commit f1d8817
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 4 deletions.
2 changes: 1 addition & 1 deletion fault_proof/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ op-alloy-rpc-types = { version = "0.9", default-features = false }
# general
anyhow.workspace = true
async-trait.workspace = true
clap.workspace = true
clap = { workspace = true, features = ["derive"] }
dotenv.workspace = true
log.workspace = true
tokio.workspace = true
Expand Down
16 changes: 14 additions & 2 deletions fault_proof/bin/proposer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,19 +244,29 @@ where
.number;
tracing::debug!("Safe L2 head block number: {:?}", safe_l2_head_block_number);

// Get the latest valid proposal
let latest_valid_proposal = self
.factory
.get_latest_valid_proposal(self.l1_provider.clone(), self.l2_provider.clone())
.await?;

// Determine the next L2 block number and parent game index for the new proposal
//
// Two cases based on the result of `get_latest_valid_proposal`:
// 1. With existing valid proposal:
// - Block number = latest valid proposal's block + proposal interval
// - Parent = latest valid game's index
//
// 2. Without valid proposal (first game or all existing games being faulty):
// - Block number = genesis block + proposal interval
// - Parent = u32::MAX (special value indicating no parent)
let (next_l2_block_number_for_proposal, parent_game_index) =
match latest_valid_proposal {
Some((latest_block, latest_game_idx)) => (
latest_block + U256::from(self.config.proposal_interval_in_blocks),
latest_game_idx.to::<u32>(),
),
None => {
// For first game, start from genesis L2 block number + proposal interval
let genesis_l2_block_number = self
.factory
.get_genesis_l2_block_number(
Expand All @@ -271,11 +281,13 @@ where
self.config.proposal_interval_in_blocks,
))
.unwrap(),
u32::MAX, // Use max value for first game's parent index
u32::MAX,
)
}
};

// There's always a new game to propose, as the chain is always moving forward from the genesis block set for the game type
// Only create a new game if the safe L2 head block number is greater than the next L2 block number for proposal
if U256::from(safe_l2_head_block_number) > next_l2_block_number_for_proposal {
self.create_game(next_l2_block_number_for_proposal, parent_game_index)
.await?;
Expand Down
30 changes: 29 additions & 1 deletion fault_proof/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ use crate::contract::{

pub type L1Provider = RootProvider<Http<Client>, Ethereum>;
pub type L2Provider = RootProvider<Http<Client>, Optimism>;
pub type L2NodeProvider = RootProvider<Http<Client>, Optimism>;
pub type L1ProviderWithWallet<F, P, T> = FillProvider<F, P, T, Ethereum>;

#[async_trait]
Expand All @@ -51,6 +52,7 @@ pub trait L2ProviderTrait {

#[async_trait]
impl L2ProviderTrait for L2Provider {
/// Get the L2 block by number
async fn get_l2_block_by_number(
&self,
block_number: BlockNumberOrTag,
Expand All @@ -65,6 +67,7 @@ impl L2ProviderTrait for L2Provider {
}
}

/// Get the L2 storage root for an address at a given block number
async fn get_l2_storage_root(
&self,
address: Address,
Expand All @@ -78,6 +81,12 @@ impl L2ProviderTrait for L2Provider {
Ok(storage_root)
}

/// Compute the output root at a given L2 block number
///
/// Local implementation is used because the RPC method `optimism_outputAtBlock` can fail for older
/// blocks if the L2 node isn't fully synced or has pruned historical state data.
///
/// Common error: "missing trie node ... state is not available"
async fn compute_output_root_at_block(&self, l2_block_number: U256) -> Result<FixedBytes<32>> {
let l2_block = self
.get_l2_block_by_number(BlockNumberOrTag::Number(l2_block_number.to::<u64>()))
Expand Down Expand Up @@ -160,11 +169,15 @@ where
Ok(Some(latest_game_index))
}

/// Fetches the game address by index
async fn fetch_game_address_by_index(&self, game_index: U256) -> Result<Address> {
let game = self.gameAtIndex(game_index).call().await?;
Ok(game.proxy)
}

/// Get the latest valid proposal
///
/// This function checks from the latest game to the earliest game, returning the latest valid proposal.
async fn get_latest_valid_proposal(
&self,
l1_provider: L1Provider,
Expand All @@ -178,36 +191,48 @@ where

let mut block_number;

// Loop through games in reverse order (latest to earliest) to find the most recent valid game
loop {
// Get the game contract for the current index
let game_address = self.fetch_game_address_by_index(game_index).await?;
let game = OPSuccinctFaultDisputeGame::new(game_address, l1_provider.clone());

// Get the L2 block number the game is proposing output for
block_number = game.l2BlockNumber().call().await?.l2BlockNumber_;
tracing::debug!(
"Checking if game {:?} at block {:?} is valid",
game_address,
block_number
);

// Get the output root the game is proposing
let game_claim = game.rootClaim().call().await?.rootClaim_;

// Compute the actual output root at the L2 block number
let output_root = l2_provider
.compute_output_root_at_block(block_number)
.await?;

// If the output root matches the game claim, we've found the latest valid proposal
if output_root == game_claim {
break;
}

// If the output root doesn't match the game claim, we need to find earlier games
tracing::info!(
"Output root {:?} is not same as game claim {:?}",
output_root,
game_claim
);

// If we've reached index 0 and still haven't found a valid proposal
// If we've reached index 0 (the earliest game) and still haven't found a valid proposal
// Return None as no valid proposals were found
if game_index == U256::ZERO {
tracing::info!("No valid proposals found after checking all games");
return Ok(None);
}

// Decrement the game index to check the previous game
game_index -= U256::from(1);
}

Expand All @@ -220,6 +245,9 @@ where
Ok(Some((block_number, game_index)))
}

/// Get the genesis L2 block number
///
/// This function returns the L2 block number of the genesis block for a given game type.
async fn get_genesis_l2_block_number(
&self,
game_type: u32,
Expand Down

0 comments on commit f1d8817

Please sign in to comment.