Context
Two PrecompileProvider impls live in crates/mega-evm/src/evm/precompiles.rs:
-
impl<CTX> PrecompileProvider<CTX> for MegaPrecompiles where CTX: ContextTr<Cfg: Cfg<Spec = MegaSpecId>> at lines 105-135. set_spec rebuilds the provider via MegaPrecompiles::new_with_spec(spec), branching on MegaSpecId to install the correct precompile table.
-
impl<DB, ExtEnvs> PrecompileProvider<MegaContext<DB, ExtEnvs>> for PrecompilesMap at lines 143-182. set_spec(OpSpecId) delegates to PrecompileProvider::<OpContext<DB>>::set_spec, which would rebuild the table from a vanilla OpSpecId.
MegaContext declares its Cfg as CfgEnv<OpSpecId> (crates/mega-evm/src/evm/context.rs:606), so Cfg::Spec = OpSpecId. The trait bound on impl (1) requires Cfg::Spec = MegaSpecId — unsatisfiable for MegaContext. Impl (1) is therefore unselectable through MegaContext.
In addition, the EVM construction path at crates/mega-evm/src/evm/mod.rs:153 builds the runtime provider as:
PrecompilesMap::from_static(MegaPrecompiles::new_with_spec(spec).precompiles())
This extracts the &'static Precompiles table and discards the MegaPrecompiles struct, so the struct's set_spec and Default impls cannot be invoked at runtime. Mega's customizations (OSAKA modexp + 100k-gas KZG) take effect today only because the static table baked at construction already contains them.
Potential issue to flag
revm currently does not call precompile_provider.set_spec(cfg.spec) on the warm transaction-execution path, so impl (2)'s op-revm delegation is never exercised and the baked-in overrides survive.
If a future revm version adds such a call, impl (2) would receive an OpSpecId and op-revm would rebuild a vanilla table, replacing:
- 100k-gas KZG point evaluation override → vanilla 50k-gas pricing
- OSAKA modexp → ISTHMUS modexp (different gas curve)
The MegaSpecId → OpSpecId mapping is many-to-one (all Mega specs currently map to ISTHMUS), so OpSpecId alone cannot reconstruct the correct Mega-specific table. Two clients running different revm minor versions could end up computing different gas usage on any block invoking these precompiles.
Filing this so the dead-code path and the warm-path delegation are visible before the next revm dependency bump.
Context
Two
PrecompileProviderimpls live incrates/mega-evm/src/evm/precompiles.rs:impl<CTX> PrecompileProvider<CTX> for MegaPrecompiles where CTX: ContextTr<Cfg: Cfg<Spec = MegaSpecId>>at lines 105-135.set_specrebuilds the provider viaMegaPrecompiles::new_with_spec(spec), branching onMegaSpecIdto install the correct precompile table.impl<DB, ExtEnvs> PrecompileProvider<MegaContext<DB, ExtEnvs>> for PrecompilesMapat lines 143-182.set_spec(OpSpecId)delegates toPrecompileProvider::<OpContext<DB>>::set_spec, which would rebuild the table from a vanillaOpSpecId.MegaContextdeclares itsCfgasCfgEnv<OpSpecId>(crates/mega-evm/src/evm/context.rs:606), soCfg::Spec = OpSpecId. The trait bound on impl (1) requiresCfg::Spec = MegaSpecId— unsatisfiable forMegaContext. Impl (1) is therefore unselectable throughMegaContext.In addition, the EVM construction path at
crates/mega-evm/src/evm/mod.rs:153builds the runtime provider as:This extracts the
&'static Precompilestable and discards theMegaPrecompilesstruct, so the struct'sset_specandDefaultimpls cannot be invoked at runtime. Mega's customizations (OSAKA modexp + 100k-gas KZG) take effect today only because the static table baked at construction already contains them.Potential issue to flag
revm currently does not call
precompile_provider.set_spec(cfg.spec)on the warm transaction-execution path, so impl (2)'s op-revm delegation is never exercised and the baked-in overrides survive.If a future revm version adds such a call, impl (2) would receive an
OpSpecIdand op-revm would rebuild a vanilla table, replacing:The
MegaSpecId → OpSpecIdmapping is many-to-one (all Mega specs currently map toISTHMUS), soOpSpecIdalone cannot reconstruct the correct Mega-specific table. Two clients running different revm minor versions could end up computing different gas usage on any block invoking these precompiles.Filing this so the dead-code path and the warm-path delegation are visible before the next revm dependency bump.