Skip to content

Commit

Permalink
fix: checkpoint sync sequence number check (#221)
Browse files Browse the repository at this point in the history
  • Loading branch information
merklefruit authored Apr 29, 2024
1 parent 89ecc3d commit 412051c
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 58 deletions.
21 changes: 0 additions & 21 deletions src/l1/blob_fetcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,24 +138,3 @@ where
let bytes = hex::decode(s).map_err(serde::de::Error::custom)?;
Ok(bytes)
}

#[cfg(test)]
mod tests {

use super::*;

// TODO: update with a test from mainnet after dencun is active
#[tokio::test]
async fn test_get_blobs() {
let Ok(l1_beacon_url) = std::env::var("L1_GOERLI_BEACON_RPC_URL") else {
println!("L1_GOERLI_BEACON_RPC_URL not set; skipping test");
return;
};

let slot_number = 7576509;
let fetcher = BlobFetcher::new(l1_beacon_url);
let blobs = fetcher.fetch_blob_sidecars(slot_number).await.unwrap();

assert_eq!(blobs.len(), 6);
}
}
16 changes: 9 additions & 7 deletions src/l1/chain_watcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -541,16 +541,17 @@ fn start_watcher(
mod tests {
use std::sync::Arc;

use ethers::providers::{Http, Middleware, Provider};
use ethers::{
providers::{Http, Middleware, Provider},
types::{BlockId, BlockNumber},
};
use tokio::sync::mpsc;

use crate::{
config::{ChainConfig, Config},
l1::chain_watcher::InnerWatcher,
};

// TODO: update with a test from mainnet after dencun is active
// also, this test will be flaky as nodes start to purge old blobs
#[tokio::test]
async fn test_get_batcher_transactions() {
let Ok(l1_beacon_url) = std::env::var("L1_GOERLI_BEACON_RPC_URL") else {
Expand All @@ -568,21 +569,22 @@ mod tests {
..Default::default()
});

let l1_block_number = 10515928;
let l1_provider = Provider::<Http>::try_from(l1_rpc_url).unwrap();
let l1_block = l1_provider
.get_block_with_txs(l1_block_number)
.get_block_with_txs(BlockId::Number(BlockNumber::Latest))
.await
.unwrap()
.unwrap();

let watcher_inner = InnerWatcher::new(config, mpsc::channel(1).0, l1_block_number, 0).await;
let watcher_inner = InnerWatcher::new(config, mpsc::channel(1).0, 0, 0).await;

let batcher_transactions = watcher_inner
.get_batcher_transactions(&l1_block)
.await
.unwrap();

assert_eq!(batcher_transactions.len(), 1);
batcher_transactions.iter().for_each(|tx| {
assert!(!tx.is_empty());
});
}
}
53 changes: 23 additions & 30 deletions src/runner/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use std::{process, time::Duration};

use ethers::{
providers::{Http, Middleware, Provider},
types::{BlockId, BlockNumber, H256},
providers::{Middleware, Provider},
types::{Block, BlockId, BlockNumber, Transaction, H256},
};
use eyre::Result;
use tokio::{
Expand All @@ -11,8 +11,8 @@ use tokio::{
};

use crate::{
config::{Config, SyncMode, SystemAccounts},
driver::Driver,
config::{Config, SyncMode},
driver::{Driver, HeadInfo},
engine::{Engine, EngineApi, ExecutionPayload, ForkchoiceState, Status},
};

Expand Down Expand Up @@ -112,7 +112,12 @@ impl Runner {
.parse()
.expect("invalid checkpoint block hash provided");

match Self::is_epoch_boundary(block_hash, &checkpoint_sync_url).await? {
let l2_block = checkpoint_sync_url
.get_block_with_txs(block_hash)
.await?
.ok_or_else(|| eyre::eyre!("could not find block"))?;

match is_epoch_boundary(l2_block, &self.config)? {
true => checkpoint_sync_url
.get_block_with_txs(block_hash)
.await?
Expand All @@ -127,7 +132,12 @@ impl Runner {
tracing::info!("finding the latest epoch boundary to use as checkpoint");

let mut block_number = checkpoint_sync_url.get_block_number().await?;
while !Self::is_epoch_boundary(block_number, &checkpoint_sync_url).await? {
let l2_block = checkpoint_sync_url
.get_block_with_txs(block_number)
.await?
.ok_or_else(|| eyre::eyre!("could not find block"))?;

while !is_epoch_boundary(l2_block.clone(), &self.config)? {
self.check_shutdown()?;
block_number -= 1.into();
}
Expand Down Expand Up @@ -219,29 +229,12 @@ impl Runner {

Ok(())
}
}

/// Returns `true` if the L2 block is the first in an epoch (sequence number 0)
async fn is_epoch_boundary<T: Into<BlockId> + Send + Sync>(
block: T,
checkpoint_sync_url: &Provider<Http>,
) -> Result<bool> {
let l2_block = checkpoint_sync_url
.get_block_with_txs(block)
.await?
.ok_or_else(|| eyre::eyre!("could not find block"))?;

let sequence_number = &l2_block
.transactions
.iter()
.find(|tx| tx.to.unwrap() == SystemAccounts::default().attributes_predeploy)
.expect("could not find setL1BlockValues tx in the epoch boundary search")
.input
.clone()
.into_iter()
.skip(132)
.take(32)
.collect::<Vec<u8>>();

Ok(sequence_number == &[0; 32])
}
/// Returns `true` if the L2 block is the first in an epoch (sequence number 0)
fn is_epoch_boundary(l2_block: Block<Transaction>, config: &Config) -> Result<bool> {
let head_info = HeadInfo::try_from_l2_block(config, l2_block)?;
let sequence_number = head_info.sequence_number;

Ok(sequence_number == 0)
}

0 comments on commit 412051c

Please sign in to comment.