Skip to content

Commit d8a96da

Browse files
authored
op-e2e: Test that setting op fee pre-Isthmus is ignored (#14910)
* op-e2e: Test that setting op fee pre-Isthmus is ignored * address feedback @mbaxter
1 parent 080b8af commit d8a96da

File tree

2 files changed

+168
-0
lines changed

2 files changed

+168
-0
lines changed

Diff for: op-e2e/actions/helpers/l1_replica.go

+25
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121

2222
"github.com/ethereum-optimism/optimism/op-node/rollup"
2323
"github.com/ethereum-optimism/optimism/op-service/client"
24+
opeth "github.com/ethereum-optimism/optimism/op-service/eth"
2425
"github.com/ethereum-optimism/optimism/op-service/sources"
2526
"github.com/ethereum-optimism/optimism/op-service/testutils"
2627
)
@@ -235,6 +236,30 @@ func (s *L1Replica) FinalizedNum() uint64 {
235236
return finalizedNum
236237
}
237238

239+
func (s *L1Replica) UnsafeID() opeth.BlockID {
240+
h := s.l1Chain.CurrentBlock()
241+
if h == nil {
242+
return opeth.BlockID{}
243+
}
244+
return opeth.HeaderBlockID(h)
245+
}
246+
247+
func (s *L1Replica) SafeID() opeth.BlockID {
248+
h := s.l1Chain.CurrentSafeBlock()
249+
if h == nil {
250+
return opeth.BlockID{}
251+
}
252+
return opeth.HeaderBlockID(h)
253+
}
254+
255+
func (s *L1Replica) FinalizedID() opeth.BlockID {
256+
h := s.l1Chain.CurrentFinalBlock()
257+
if h == nil {
258+
return opeth.BlockID{}
259+
}
260+
return opeth.HeaderBlockID(h)
261+
}
262+
238263
// ActL1Finalize finalizes a later block, which must be marked as safe before doing so (see ActL1SafeNext).
239264
func (s *L1Replica) ActL1Finalize(t Testing, num uint64) {
240265
safeNum := s.SafeNum()

Diff for: op-e2e/actions/proofs/system_config_test.go

+143
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
package proofs_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/Masterminds/semver/v3"
7+
"github.com/ethereum/go-ethereum/accounts/abi/bind"
8+
"github.com/stretchr/testify/require"
9+
10+
"github.com/ethereum-optimism/optimism/op-chain-ops/genesis"
11+
actionsHelpers "github.com/ethereum-optimism/optimism/op-e2e/actions/helpers"
12+
"github.com/ethereum-optimism/optimism/op-e2e/actions/proofs/helpers"
13+
"github.com/ethereum-optimism/optimism/op-e2e/bindings"
14+
"github.com/ethereum-optimism/optimism/op-node/rollup"
15+
"github.com/ethereum-optimism/optimism/op-node/rollup/derive"
16+
"github.com/ethereum-optimism/optimism/op-service/eth"
17+
)
18+
19+
// Test_ProgramAction_SystemConfigEarlyIsthmusUpgrade tests that setting the operator
20+
// fee parameters pre-Isthmus is ignored and doesn't cause problems during derivation.
21+
func Test_ProgramAction_SystemConfigEarlyIsthmusUpgrade(gt *testing.T) {
22+
matrix := helpers.NewMatrix[any]()
23+
matrix.AddDefaultTestCases(
24+
nil,
25+
helpers.NewForkMatrix(helpers.Holocene),
26+
testSystemConfigEarlyIsthmusUpgrade,
27+
)
28+
matrix.Run(gt)
29+
}
30+
31+
func testSystemConfigEarlyIsthmusUpgrade(gt *testing.T, testCfg *helpers.TestCfg[any]) {
32+
const isthmusOffset = 24
33+
34+
testOperatorFeeScalar := uint32(20000)
35+
testOperatorFeeConstant := uint64(500)
36+
37+
t := actionsHelpers.NewDefaultTesting(gt)
38+
testSetup := func(dp *genesis.DeployConfig) {
39+
dp.ActivateForkAtOffset(rollup.Isthmus, isthmusOffset)
40+
}
41+
env := helpers.NewL2FaultProofEnv(t, testCfg, helpers.NewTestParams(), helpers.NewBatcherCfg(), testSetup)
42+
sequencer := env.Sequencer
43+
miner := env.Miner
44+
45+
sysCfg, err := bindings.NewSystemConfig(env.Sd.RollupCfg.L1SystemConfigAddress, env.Miner.EthClient())
46+
require.NoError(t, err)
47+
opts := &bind.CallOpts{}
48+
49+
sysCfgVerStr, err := sysCfg.Version(opts)
50+
require.NoError(t, err)
51+
t.Logf("SystemConfig version: %s", sysCfgVerStr)
52+
ver, err := semver.NewVersion(sysCfgVerStr)
53+
require.NoError(t, err)
54+
require.GreaterOrEqual(t, ver.Major(), uint64(3), "expect Isthmus contracts or later")
55+
56+
opFeeScalarAndConstant := func() (uint32, uint64) {
57+
t.Helper()
58+
scalar, err := sysCfg.OperatorFeeScalar(opts)
59+
require.NoError(t, err)
60+
constant, err := sysCfg.OperatorFeeConstant(opts)
61+
require.NoError(t, err)
62+
return scalar, constant
63+
}
64+
65+
requireL1InfoParams := func(block eth.L2BlockRef, scalar uint32, constant uint64) {
66+
t.Helper()
67+
l1infoTx := env.Engine.L2Chain().GetBlockByHash(block.Hash).Transactions()[0]
68+
l1info, err := derive.L1BlockInfoFromBytes(env.Sd.RollupCfg, block.Time, l1infoTx.Data())
69+
require.NoError(t, err)
70+
require.Equal(t, scalar, l1info.OperatorFeeScalar)
71+
require.Equal(t, constant, l1info.OperatorFeeConstant)
72+
}
73+
74+
scalar0, constant0 := opFeeScalarAndConstant()
75+
require.Zero(t, scalar0)
76+
require.Zero(t, constant0)
77+
78+
owner, err := sysCfg.Owner(opts)
79+
require.NoError(t, err)
80+
require.Equal(t, env.Dp.Addresses.Deployer, owner)
81+
sysCfgOwner, err := bind.NewKeyedTransactorWithChainID(env.Dp.Secrets.Deployer, env.Sd.RollupCfg.L1ChainID)
82+
require.NoError(t, err)
83+
84+
_, err = sysCfg.SetOperatorFeeScalars(sysCfgOwner, testOperatorFeeScalar, testOperatorFeeConstant)
85+
require.NoError(t, err)
86+
miner.ActL1StartBlock(12)(t)
87+
miner.ActL1IncludeTx(env.Dp.Addresses.Deployer)(t)
88+
miner.ActL1EndBlock(t)
89+
scalar1, constant1 := opFeeScalarAndConstant()
90+
require.Equal(t, testOperatorFeeScalar, scalar1)
91+
require.Equal(t, testOperatorFeeConstant, constant1)
92+
93+
sequencer.ActL1HeadSignal(t)
94+
sequencer.ActBuildToL1Head(t)
95+
u1 := miner.UnsafeID()
96+
env.BatchAndMine(t)
97+
sequencer.ActL1HeadSignal(t)
98+
sequencer.ActL2PipelineFull(t)
99+
syncStatus := sequencer.SyncStatus()
100+
require.Equal(t, syncStatus.UnsafeL2, syncStatus.SafeL2)
101+
require.Equal(t, u1, syncStatus.UnsafeL2.L1Origin)
102+
require.False(t, env.Sd.RollupCfg.IsIsthmus(syncStatus.SafeL2.Time))
103+
104+
requireL1InfoParams(syncStatus.SafeL2, 0, 0)
105+
env.RunFaultProofProgram(t, syncStatus.SafeL2.Number, testCfg.CheckResult, testCfg.InputParams...)
106+
107+
sequencer.ActBuildL2ToIsthmus(t)
108+
sequencer.ActL2EmptyBlock(t) // one more to have Isthmus L1 info deposit
109+
u2 := miner.UnsafeID()
110+
env.BatchAndMine(t)
111+
sequencer.ActL1HeadSignal(t)
112+
sequencer.ActL2PipelineFull(t)
113+
syncStatus = sequencer.SyncStatus()
114+
require.Equal(t, syncStatus.UnsafeL2, syncStatus.SafeL2)
115+
require.Equal(t, syncStatus.UnsafeL2.L1Origin, u2)
116+
require.True(t, env.Sd.RollupCfg.IsIsthmus(syncStatus.SafeL2.Time))
117+
118+
// Assert that operator fee params are zero since they were set before Isthmus activated.
119+
requireL1InfoParams(syncStatus.SafeL2, 0, 0)
120+
env.RunFaultProofProgram(t, syncStatus.SafeL2.Number, testCfg.CheckResult, testCfg.InputParams...)
121+
122+
// modify both to ensure we test with different parameters
123+
testOperatorFeeScalar *= 2
124+
testOperatorFeeConstant *= 2
125+
// Now set them again with Isthmus active and see that they are set correctly.
126+
_, err = sysCfg.SetOperatorFeeScalars(sysCfgOwner, testOperatorFeeScalar, testOperatorFeeConstant)
127+
require.NoError(t, err)
128+
miner.ActL1StartBlock(12)(t)
129+
miner.ActL1IncludeTx(env.Dp.Addresses.Deployer)(t)
130+
miner.ActL1EndBlock(t)
131+
sequencer.ActL1HeadSignal(t)
132+
sequencer.ActBuildToL1Head(t)
133+
u3 := miner.UnsafeID()
134+
env.BatchAndMine(t)
135+
sequencer.ActL1HeadSignal(t)
136+
sequencer.ActL2PipelineFull(t)
137+
syncStatus = sequencer.SyncStatus()
138+
require.Equal(t, syncStatus.UnsafeL2, syncStatus.SafeL2)
139+
require.Equal(t, u3, syncStatus.UnsafeL2.L1Origin)
140+
141+
requireL1InfoParams(syncStatus.SafeL2, testOperatorFeeScalar, testOperatorFeeConstant)
142+
env.RunFaultProofProgram(t, syncStatus.SafeL2.Number, testCfg.CheckResult, testCfg.InputParams...)
143+
}

0 commit comments

Comments
 (0)