Skip to content

Commit 157cefb

Browse files
feat(chainspec): activate Unzen from genesis + drop special zk-gas schedule for Masaya (#205)
* feat(chainspec): reset Masaya to activate Unzen at genesis Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * refactor(evm): drop Masaya-specific zk-gas schedule Masaya is being reset to fork into Unzen from genesis, so the frozen pre-recalibration schedule that preserved consensus on its old finalized blocks is no longer needed. Collapse every chain onto UNZEN_ZK_GAS_SCHEDULE and drop the now-unused chain_id parameter from schedule_for. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent ec1650b commit 157cefb

10 files changed

Lines changed: 71 additions & 499 deletions

File tree

crates/block/src/executor.rs

Lines changed: 5 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -397,8 +397,8 @@ where
397397
// Charge the per-transaction intrinsic zk gas before EVM execution begins, as required
398398
// by the Unzen zk gas spec (taikoxyz/taiko-mono#21669). The intrinsic sits in the
399399
// in-flight tx total so it is committed alongside opcode/precompile usage on success
400-
// and discarded on revert/failure. A schedule with a zero intrinsic (Masaya) makes this
401-
// a no-op. If the intrinsic alone would exceed the remaining block budget, mirror the
400+
// and discarded on revert/failure. A schedule with a zero intrinsic makes this a no-op.
401+
// If the intrinsic alone would exceed the remaining block budget, mirror the
402402
// mid-tx exhaustion path used by the inspector.
403403
if let Err(ZkGasOutcome::LimitExceeded) = self.evm.charge_tx_intrinsic_zk_gas() {
404404
self.zk_gas_exhausted = true;
@@ -558,19 +558,17 @@ mod test {
558558
state::AccountInfo,
559559
};
560560

561-
use alethia_reth_chainspec::TAIKO_MASAYA_CHAIN_ID;
562561
use alethia_reth_evm::{
563-
alloy::decode_anchor_system_call_data,
564-
factory::TaikoEvmFactory,
565-
zk_gas::unzen::{MASAYA_TX_INTRINSIC_ZK_GAS, TX_INTRINSIC_ZK_GAS},
562+
alloy::decode_anchor_system_call_data, factory::TaikoEvmFactory,
563+
zk_gas::unzen::TX_INTRINSIC_ZK_GAS,
566564
};
567565

568566
use super::*;
569567
use crate::{
570568
config::{TaikoEvmConfig, TaikoNextBlockEnvAttributes},
571569
testutil::{
572570
BENCH_LIMIT_TARGET, BENCH_SUCCESS_TARGET, db_with_contracts, recovered_tx,
573-
recovered_tx_with_chain_id, unzen_chain_spec, unzen_evm_env, unzen_execution_ctx,
571+
unzen_chain_spec, unzen_evm_env, unzen_execution_ctx,
574572
},
575573
};
576574
use alethia_reth_chainspec::spec::TaikoChainSpec;
@@ -665,39 +663,6 @@ mod test {
665663
);
666664
}
667665

668-
#[test]
669-
fn executor_does_not_charge_tx_intrinsic_on_masaya_schedule() {
670-
let chain_spec = Arc::new(unzen_chain_spec());
671-
let mut state = State::builder()
672-
.with_database(db_with_contracts(&[(BENCH_CALLER, 0)]))
673-
.with_bundle_update()
674-
.build();
675-
let mut env = unzen_evm_env();
676-
env.cfg_env.chain_id = TAIKO_MASAYA_CHAIN_ID;
677-
let evm = TaikoEvmFactory.create_evm(&mut state, env);
678-
let ctx = unzen_execution_ctx();
679-
let mut executor =
680-
TaikoBlockExecutor::new(evm, ctx.clone(), chain_spec, RethReceiptBuilder::default());
681-
682-
executor
683-
.execute_transaction(recovered_tx_with_chain_id(
684-
BENCH_CALLER,
685-
BENCH_SUCCESS_TARGET,
686-
0,
687-
1,
688-
TAIKO_MASAYA_CHAIN_ID,
689-
))
690-
.expect("successful tx should commit on Masaya");
691-
692-
let finalized = ctx.finalized_block_zk_gas();
693-
assert_eq!(MASAYA_TX_INTRINSIC_ZK_GAS, 0);
694-
assert!(
695-
finalized < TX_INTRINSIC_ZK_GAS,
696-
"Masaya finalized block zk gas ({finalized}) must not include any per-tx intrinsic charge"
697-
);
698-
assert!(finalized > 0, "successful tx must still record opcode-driven zk gas (got 0)");
699-
}
700-
701666
#[cfg(feature = "prover")]
702667
#[test]
703668
fn execute_block_stops_after_non_anchor_zk_gas_exhaustion() {

crates/block/src/testutil.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ pub fn recovered_tx(
7575
}
7676

7777
/// Builds a recovered legacy transaction targeting `to` from `caller` with an explicit chain id,
78-
/// so tests can submit transactions against the Masaya chain id (`167_011`) and others.
78+
/// so tests can submit transactions against chain ids other than the default.
7979
pub fn recovered_tx_with_chain_id(
8080
caller: Address,
8181
to: Address,

crates/chainspec/src/hardfork.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ pub static TAIKO_MASAYA_HARDFORKS: LazyLock<ChainHardforks> = LazyLock::new(|| {
102102
(TaikoHardfork::Ontake.boxed(), ForkCondition::Block(0)),
103103
(TaikoHardfork::Pacaya.boxed(), ForkCondition::Block(0)),
104104
(TaikoHardfork::Shasta.boxed(), ForkCondition::Timestamp(0)),
105-
(TaikoHardfork::Unzen.boxed(), ForkCondition::Timestamp(1_778_158_800)),
105+
(TaikoHardfork::Unzen.boxed(), ForkCondition::Timestamp(0)),
106106
]))
107107
});
108108

@@ -224,4 +224,14 @@ mod test {
224224
assert!(shasta.is_timestamp(), "shasta activation should be timestamp-based");
225225
assert_eq!(shasta, ForkCondition::Timestamp(0));
226226
}
227+
228+
#[test]
229+
fn test_masaya_unzen_activates_at_genesis() {
230+
let unzen = TAIKO_MASAYA_HARDFORKS.fork(TaikoHardfork::Unzen);
231+
assert_eq!(
232+
unzen,
233+
ForkCondition::Timestamp(0),
234+
"post-reset Masaya forks into Unzen at genesis"
235+
);
236+
}
227237
}

crates/chainspec/src/lib.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,10 @@ pub const TAIKO_HOODI_GENESIS_HASH: B256 =
3939
pub const TAIKO_MAINNET_GENESIS_HASH: B256 =
4040
b256!("0x90bc60466882de9637e269e87abab53c9108cf9113188bc4f80bcfcb10e489b9");
4141

42-
/// Genesis hash for the Taiko Masaya network.
42+
/// Genesis hash for the Taiko Masaya network. After the reset, Masaya activates Unzen at genesis
43+
/// (`Timestamp(0)`), which makes the genesis header an Osaka-era block.
4344
pub const TAIKO_MASAYA_GENESIS_HASH: B256 =
44-
b256!("0xeef96dc254e1ac4a0044b116e38b16dface1a153d9299c056552898a43f8513e");
45+
b256!("0xd3597fd63c823352526ce2a4cfafe0837d878e3c9ac8558129bc04ce900402ae");
4546

4647
/// EVM chain id for the Taiko Devnet network.
4748
pub const TAIKO_DEVNET_CHAIN_ID: u64 = 167_001;

crates/evm/src/factory.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ impl EvmFactory for TaikoEvmFactory {
4848
input: EvmEnv<Self::Spec, Self::BlockEnv>,
4949
) -> Self::Evm<DB, NoOpInspector> {
5050
let spec_id = input.cfg_env.spec;
51-
let schedule = schedule_for(spec_id, input.cfg_env.chain_id);
51+
let schedule = schedule_for(spec_id);
5252
let evm = Context::mainnet()
5353
.with_cfg(input.cfg_env)
5454
.with_block(input.block_env)
@@ -69,7 +69,7 @@ impl EvmFactory for TaikoEvmFactory {
6969
inspector: I,
7070
) -> Self::Evm<DB, I> {
7171
let spec_id = input.cfg_env.spec;
72-
let schedule = schedule_for(spec_id, input.cfg_env.chain_id);
72+
let schedule = schedule_for(spec_id);
7373
let evm = Context::mainnet()
7474
.with_cfg(input.cfg_env)
7575
.with_block(input.block_env)

crates/evm/src/zk_gas/adapter.rs

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -62,16 +62,14 @@ impl<I> ZkGasInspector<I> {
6262

6363
/// Returns a reference to the active zk gas meter, if metering is enabled.
6464
///
65-
/// Returns `None` when the active spec/chain combination has no zk gas schedule
66-
/// (pre-Unzen specs).
65+
/// Returns `None` when the active spec has no zk gas schedule (pre-Unzen specs).
6766
pub(crate) fn meter(&self) -> Option<&ZkGasMeter<'static>> {
6867
self.metering.as_ref().map(|state| &state.meter)
6968
}
7069

7170
/// Returns a mutable reference to the active zk gas meter, if metering is enabled.
7271
///
73-
/// Returns `None` when the active spec/chain combination has no zk gas schedule
74-
/// (pre-Unzen specs).
72+
/// Returns `None` when the active spec has no zk gas schedule (pre-Unzen specs).
7573
pub(crate) fn meter_mut(&mut self) -> Option<&mut ZkGasMeter<'static>> {
7674
self.metering.as_mut().map(|state| &mut state.meter)
7775
}
@@ -413,17 +411,14 @@ fn parent_step_depth(depth: usize) -> usize {
413411
mod tests {
414412
use crate::{
415413
spec::TaikoSpecId,
416-
zk_gas::{
417-
schedule::schedule_for,
418-
unzen::{MASAYA_UNZEN_ZK_GAS_SCHEDULE, UNZEN_ZK_GAS_SCHEDULE},
419-
},
414+
zk_gas::{schedule::schedule_for, unzen::UNZEN_ZK_GAS_SCHEDULE},
420415
};
421416

422417
use super::{FinishedStep, ZkGasMeteringState};
423418

424419
#[test]
425420
fn flush_deferred_steps_returns_immediately_when_empty() {
426-
let schedule = schedule_for(TaikoSpecId::UNZEN, 167).expect("Unzen schedule");
421+
let schedule = schedule_for(TaikoSpecId::UNZEN).expect("Unzen schedule");
427422
let mut metering = ZkGasMeteringState::new(schedule);
428423

429424
metering.flush_deferred_steps().expect("empty flush should succeed");
@@ -434,7 +429,7 @@ mod tests {
434429

435430
#[test]
436431
fn flush_deferred_steps_clears_flag_after_charging_deferred_step() {
437-
let schedule = schedule_for(TaikoSpecId::UNZEN, 167).expect("Unzen schedule");
432+
let schedule = schedule_for(TaikoSpecId::UNZEN).expect("Unzen schedule");
438433
let mut metering = ZkGasMeteringState::new(schedule);
439434

440435
metering.defer_step(0, FinishedStep { opcode: 0x01, step_gas: 3, spawned: false });
@@ -449,13 +444,13 @@ mod tests {
449444

450445
#[test]
451446
fn flush_deferred_steps_preserves_flag_when_later_deferred_step_remains_after_error() {
452-
let mut metering = ZkGasMeteringState::new(&MASAYA_UNZEN_ZK_GAS_SCHEDULE);
447+
let mut metering = ZkGasMeteringState::new(&UNZEN_ZK_GAS_SCHEDULE);
453448

454449
metering.defer_step(
455450
0,
456451
FinishedStep {
457452
opcode: 0xf0,
458-
step_gas: MASAYA_UNZEN_ZK_GAS_SCHEDULE.block_limit + 1,
453+
step_gas: UNZEN_ZK_GAS_SCHEDULE.block_limit + 1,
459454
spawned: false,
460455
},
461456
);

crates/evm/src/zk_gas/meter.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ impl<'a> ZkGasMeter<'a> {
9999
///
100100
/// Mirrors `TX_INTRINSIC_ZK_GAS` from the Unzen zk gas spec: the charge accumulates into the
101101
/// in-flight transaction total and is only promoted into the block total when the transaction
102-
/// commits. A schedule value of `0` (Masaya) makes this a no-op.
102+
/// commits. A schedule value of `0` makes this a no-op.
103103
pub fn charge_tx_intrinsic(&mut self) -> Result<(), ZkGasOutcome> {
104104
self.charge_amount(self.schedule.tx_intrinsic_zk_gas)
105105
}

crates/evm/src/zk_gas/schedule.rs

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@ use alloy_primitives::Address;
44

55
use crate::spec::TaikoSpecId;
66

7-
use super::unzen::{MASAYA_UNZEN_ZK_GAS_SCHEDULE, UNZEN_ZK_GAS_SCHEDULE};
8-
9-
pub use alethia_reth_chainspec::TAIKO_MASAYA_CHAIN_ID;
7+
use super::unzen::UNZEN_ZK_GAS_SCHEDULE;
108

119
/// Fail-safe multiplier applied to any precompile absent from a schedule's table.
1210
pub const FAILSAFE_MULTIPLIER: u16 = u16::MAX;
@@ -34,8 +32,7 @@ pub struct ZkGasSchedule {
3432
/// Maximum zk gas permitted across a single block.
3533
pub block_limit: u64,
3634
/// Fixed zk gas charged once per block transaction before opcode or precompile
37-
/// metering begins. Set to `0` on chains whose Unzen activation predates this
38-
/// field, to preserve historical block consensus.
35+
/// metering begins.
3936
pub tx_intrinsic_zk_gas: u64,
4037
/// Per-opcode proving-cost multipliers indexed by opcode byte.
4138
pub opcode_multipliers: [u16; 256],
@@ -57,16 +54,11 @@ impl ZkGasSchedule {
5754
}
5855
}
5956

60-
/// Returns the consensus zk gas schedule for the active Taiko fork on the given chain, when
61-
/// defined. Masaya runs Unzen with a 10× higher block budget than Devnet/Hoodi/Mainnet; all
62-
/// other chains share the default Unzen schedule.
63-
pub const fn schedule_for(spec: TaikoSpecId, chain_id: u64) -> Option<&'static ZkGasSchedule> {
57+
/// Returns the consensus zk gas schedule for the active Taiko fork, when defined. Only Unzen
58+
/// defines a schedule; every chain shares the single [`UNZEN_ZK_GAS_SCHEDULE`].
59+
pub const fn schedule_for(spec: TaikoSpecId) -> Option<&'static ZkGasSchedule> {
6460
match spec {
65-
TaikoSpecId::UNZEN => Some(if chain_id == TAIKO_MASAYA_CHAIN_ID {
66-
&MASAYA_UNZEN_ZK_GAS_SCHEDULE
67-
} else {
68-
&UNZEN_ZK_GAS_SCHEDULE
69-
}),
61+
TaikoSpecId::UNZEN => Some(&UNZEN_ZK_GAS_SCHEDULE),
7062
_ => None,
7163
}
7264
}

0 commit comments

Comments
 (0)