Skip to content

Commit f330e11

Browse files
committed
Merge remote-tracking branch 'origin/release/v4.6.0' into fakedev9999/debug-cycle-count-old-hang
# Conflicts: # .github/workflows/cycle-count-diff.yml
2 parents ecac949 + d9d117f commit f330e11

4 files changed

Lines changed: 71 additions & 10 deletions

File tree

bindings/build.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@ fn main() -> anyhow::Result<()> {
2727
return Ok(());
2828
}
2929

30+
// Generate full artifacts because the bindings expose contract bytecode.
31+
let status =
32+
Command::new("forge").arg("build").current_dir(&contracts_package_path).status()?;
33+
34+
if !status.success() {
35+
anyhow::bail!("Forge build failed with exit code: {}", status);
36+
}
37+
3038
// Use 'forge bind' to generate bindings for only the contracts we need for E2E tests
3139
let mut forge_command = Command::new("forge");
3240
forge_command.args([
@@ -35,6 +43,7 @@ fn main() -> anyhow::Result<()> {
3543
bindings_codegen_path.as_str(),
3644
"--module",
3745
"--overwrite",
46+
"--skip-build",
3847
"--skip-extra-derives",
3948
]);
4049

book/advanced/cost-estimation-tools.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,19 @@ cargo run --bin cost-estimator -- \
4646

4747
For best estimation, use a range bigger than the batcher interval with batch size equal to the range.
4848

49+
To run against a historical range without depending on op-node SafeDB, pass both `--no-safe-head-split` and an explicit `--l1-head`:
50+
51+
```bash
52+
cargo run --bin cost-estimator -- \
53+
--start 2000000 \
54+
--end 2001800 \
55+
--batch-size 300 \
56+
--no-safe-head-split \
57+
--l1-head <L1_HEAD_BLOCK_HASH>
58+
```
59+
60+
`--no-safe-head-split` uses fixed-size batches instead of SafeDB-aligned safe head boundaries. `--l1-head` uses the supplied L1 head hash instead of looking it up through SafeDB, and ignores `L1_BLOCK_TAG` / `L1_CONFIRMATIONS` for the estimator run.
61+
4962
### Output
5063

5164
Execution report saved to `execution-reports/{chain_id}/{start}-{end}-report.csv` with metrics:

scripts/utils/bin/cost_estimator.rs

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use alloy_primitives::B256;
12
use anyhow::Result;
23
use clap::Parser;
34
use futures::StreamExt;
@@ -18,8 +19,8 @@ use op_succinct_proof_utils::{get_range_elf_embedded, initialize_host};
1819
use op_succinct_scripts::HostExecutorArgs;
1920

2021
// Cost-estimator-specific CLI args. Wraps `HostExecutorArgs` and adds the estimator-only
21-
// `--no-safe-head-split` flag so unrelated host binaries (e.g. `multi`,
22-
// `gen-sp1-test-artifacts`) don't advertise a flag they ignore.
22+
// `--no-safe-head-split` and `--l1-head` flags so unrelated host binaries (e.g. `multi`,
23+
// `gen-sp1-test-artifacts`) don't advertise flags they ignore.
2324
#[derive(Debug, Clone, Parser)]
2425
#[command(about = "Estimate OP Succinct execution costs over an L2 block range")]
2526
struct CostEstimatorArgs {
@@ -31,6 +32,12 @@ struct CostEstimatorArgs {
3132
/// `RANGE_SPLIT_COUNT` segment) rather than per span batch.
3233
#[arg(long)]
3334
no_safe_head_split: bool,
35+
/// L1 head block hash to derive the L2 range from. When set, it is used directly instead of
36+
/// looking it up via the op-node safeDB, so a caller that already knows the L1 head can skip
37+
/// the safeDB binary search (and the `--safe-db-fallback` timestamp estimation). This matches
38+
/// the fault-proof proposer, which anchors each range to the L1 head committed on-chain.
39+
#[arg(long)]
40+
l1_head: Option<B256>,
3441
}
3542
use rayon::iter::{IntoParallelIterator, ParallelIterator};
3643
use sp1_sdk::{
@@ -45,6 +52,14 @@ use std::{
4552
sync::Arc,
4653
};
4754

55+
fn cost_estimator_l1_selection(has_explicit_l1_head: bool) -> Result<L1BlockSelectionConfig> {
56+
if has_explicit_l1_head {
57+
Ok(L1BlockSelectionConfig::default())
58+
} else {
59+
L1BlockSelectionConfig::from_env()
60+
}
61+
}
62+
4863
/// Run the zkVM execution process for each split range in parallel. Writes the execution stats for
4964
/// each block range to a CSV file after each execution completes (not guaranteed to be in order).
5065
async fn execute_blocks_and_write_stats_csv<H>(
@@ -245,12 +260,13 @@ fn aggregate_execution_stats(
245260
async fn main() -> Result<()> {
246261
let args = CostEstimatorArgs::parse();
247262
let no_safe_head_split = args.no_safe_head_split;
263+
let l1_head = args.l1_head;
248264
let args = args.host;
249265

250266
dotenv::from_path(&args.env_file).ok();
251267
utils::setup_logger();
252268

253-
let l1_selection = L1BlockSelectionConfig::from_env()?;
269+
let l1_selection = cost_estimator_l1_selection(l1_head.is_some())?;
254270
let data_fetcher =
255271
OPSuccinctDataFetcher::new_with_rollup_config_and_l1_selection(l1_selection).await?;
256272
let l2_chain_id = data_fetcher.get_l2_chain_id().await?;
@@ -275,11 +291,14 @@ async fn main() -> Result<()> {
275291
.await?
276292
};
277293

278-
// Check if the safeDB is activated on the L2 node. If it is, we use the safeHead based range
279-
// splitting algorithm. Otherwise, we use the simple range splitting algorithm.
280-
let safe_db_activated = data_fetcher.is_safe_db_activated().await?;
281-
282-
let split_ranges = if safe_db_activated && !no_safe_head_split {
294+
// Pick the splitter. With --no-safe-head-split the caller wants the basic fixed-size splitter
295+
// regardless, so skip the is_safe_db_activated() probe entirely: that probe queries the op-node
296+
// safeDB (optimism_safeHeadAtL1Block), which may be disabled or unreachable, and there is no
297+
// reason to touch it on a path that will not use safeHead-aligned splitting. Otherwise probe,
298+
// and use the basic splitter when the safeDB is not active.
299+
let split_ranges = if no_safe_head_split {
300+
split_range_basic(l2_start_block, l2_end_block, args.effective_batch_size())
301+
} else if data_fetcher.is_safe_db_activated().await? {
283302
split_range_based_on_safe_heads(
284303
&data_fetcher,
285304
l2_start_block,
@@ -295,7 +314,7 @@ async fn main() -> Result<()> {
295314

296315
let host_args = futures::stream::iter(split_ranges.iter())
297316
.map(|range| async {
298-
host.fetch(range.start, range.end, None, args.safe_db_fallback)
317+
host.fetch(range.start, range.end, l1_head, args.safe_db_fallback)
299318
.await
300319
.expect("Failed to get host CLI args")
301320
})
@@ -340,3 +359,20 @@ async fn main() -> Result<()> {
340359

341360
Ok(())
342361
}
362+
363+
#[cfg(test)]
364+
mod tests {
365+
use super::*;
366+
use op_succinct_host_utils::l1_selection::{L1_BLOCK_TAG_ENV, L1_CONFIRMATIONS_ENV};
367+
368+
#[test]
369+
fn explicit_l1_head_ignores_non_default_l1_selection_env() {
370+
std::env::set_var(L1_BLOCK_TAG_ENV, "safe");
371+
std::env::set_var(L1_CONFIRMATIONS_ENV, "4");
372+
let l1_selection = cost_estimator_l1_selection(true).unwrap();
373+
std::env::remove_var(L1_BLOCK_TAG_ENV);
374+
std::env::remove_var(L1_CONFIRMATIONS_ENV);
375+
376+
assert_eq!(l1_selection, L1BlockSelectionConfig::default());
377+
}
378+
}

utils/altda/host/src/cfg.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,10 @@ impl AltDAChainHost {
106106
} else {
107107
let providers = self.create_providers().await?;
108108
let backend =
109-
OnlineHostBackend::new(self.clone(), kv_store.clone(), providers, AltDAHintHandler);
109+
OnlineHostBackend::new(self.clone(), kv_store.clone(), providers, AltDAHintHandler)
110+
.with_high_level_hint(AltDAExtendedHintType::Standard(
111+
HintType::L2PayloadWitness,
112+
));
110113

111114
task::spawn(async {
112115
PreimageServer::new(

0 commit comments

Comments
 (0)