diff --git a/op-e2e/actions/altda/altda_test.go b/op-e2e/actions/altda/altda_test.go index e5171d9241f18..dd61f677a174a 100644 --- a/op-e2e/actions/altda/altda_test.go +++ b/op-e2e/actions/altda/altda_test.go @@ -143,7 +143,7 @@ func (a *L2AltDA) NewVerifier(t helpers.Testing) *helpers.L2Verifier { daMgr := altda.NewAltDAWithStorage(a.log, a.altDACfg, a.storage, &altda.NoopMetrics{}) - verifier := helpers.NewL2Verifier(t, a.log, l1F, a.miner.BlobStore(), daMgr, engCl, a.sd.RollupCfg, &sync.Config{}, safedb.Disabled) + verifier := helpers.NewL2Verifier(t, a.log, l1F, a.miner.BlobStore(), daMgr, engCl, a.sd.RollupCfg, &sync.Config{}, safedb.Disabled, nil) return verifier } diff --git a/op-e2e/actions/derivation/batch_queue_test.go b/op-e2e/actions/derivation/batch_queue_test.go index 1346299b80082..9685cc58b3acc 100644 --- a/op-e2e/actions/derivation/batch_queue_test.go +++ b/op-e2e/actions/derivation/batch_queue_test.go @@ -95,7 +95,7 @@ func TestDeriveChainFromNearL1Genesis(gt *testing.T) { l2Cl, err := sources.NewEngineClient(seqEngine.RPCClient(), logger, nil, sources.EngineClientDefaultConfig(sd.RollupCfg)) require.NoError(gt, err) verifier := helpers.NewL2Verifier(t, logger, miner.L1Client(t, sd.RollupCfg), miner.BlobStore(), altda.Disabled, - l2Cl, sequencer.RollupCfg, &sync.Config{}, safedb.Disabled) + l2Cl, sequencer.RollupCfg, &sync.Config{}, safedb.Disabled, nil) verifier.ActL2PipelineFull(t) // Should not get stuck in a reset loop forever require.EqualValues(gt, l2BlockNum, seqEngine.L2Chain().CurrentSafeBlock().Number.Uint64()) require.EqualValues(gt, l2BlockNum, seqEngine.L2Chain().CurrentFinalBlock().Number.Uint64()) diff --git a/op-e2e/actions/helpers/l2_sequencer.go b/op-e2e/actions/helpers/l2_sequencer.go index 37d93210f7e70..7afa829e6f31c 100644 --- a/op-e2e/actions/helpers/l2_sequencer.go +++ b/op-e2e/actions/helpers/l2_sequencer.go @@ -53,7 +53,7 @@ type L2Sequencer struct { func NewL2Sequencer(t Testing, log log.Logger, l1 derive.L1Fetcher, blobSrc derive.L1BlobsFetcher, altDASrc driver.AltDAIface, eng L2API, cfg *rollup.Config, seqConfDepth uint64, ) *L2Sequencer { - ver := NewL2Verifier(t, log, l1, blobSrc, altDASrc, eng, cfg, &sync.Config{}, safedb.Disabled) + ver := NewL2Verifier(t, log, l1, blobSrc, altDASrc, eng, cfg, &sync.Config{}, safedb.Disabled, nil) attrBuilder := derive.NewFetchingAttributesBuilder(cfg, l1, eng) seqConfDepthL1 := confdepth.NewConfDepth(seqConfDepth, ver.syncStatus.L1Head, l1) originSelector := sequencing.NewL1OriginSelector(t.Ctx(), log, cfg, seqConfDepthL1) diff --git a/op-e2e/actions/helpers/l2_verifier.go b/op-e2e/actions/helpers/l2_verifier.go index dd1724250f7b2..759de45b7d484 100644 --- a/op-e2e/actions/helpers/l2_verifier.go +++ b/op-e2e/actions/helpers/l2_verifier.go @@ -108,6 +108,7 @@ type safeDB interface { func NewL2Verifier(t Testing, log log.Logger, l1 derive.L1Fetcher, blobsSrc derive.L1BlobsFetcher, altDASrc driver.AltDAIface, eng L2API, cfg *rollup.Config, syncCfg *sync.Config, safeHeadListener safeDB, + derivationPipelineCfg *rollup.Config, ) *L2Verifier { ctx, cancel := context.WithCancel(context.Background()) t.Cleanup(cancel) @@ -160,7 +161,12 @@ func NewL2Verifier(t Testing, log log.Logger, l1 derive.L1Fetcher, attributes.NewAttributesHandler(log, cfg, ctx, eng), opts) managedMode := interopSys != nil - pipeline := derive.NewDerivationPipeline(log, cfg, l1, blobsSrc, altDASrc, eng, metrics, managedMode) + + // set derivation pipeline cfg separately if needed + if derivationPipelineCfg == nil { + derivationPipelineCfg = cfg + } + pipeline := derive.NewDerivationPipeline(log, derivationPipelineCfg, l1, blobsSrc, altDASrc, eng, metrics, managedMode) sys.Register("pipeline", derive.NewPipelineDeriver(ctx, pipeline), opts) testActionEmitter := sys.Register("test-action", nil, opts) diff --git a/op-e2e/actions/helpers/setups.go b/op-e2e/actions/helpers/setups.go index b5057c30239d3..394d6c37b364b 100644 --- a/op-e2e/actions/helpers/setups.go +++ b/op-e2e/actions/helpers/setups.go @@ -42,7 +42,7 @@ func SetupVerifier(t Testing, sd *e2eutils.SetupData, log log.Logger, jwtPath := e2eutils.WriteDefaultJWT(t) engine := NewL2Engine(t, log.New("role", "verifier-engine"), sd.L2Cfg, jwtPath, EngineWithP2P()) engCl := engine.EngineClient(t, sd.RollupCfg) - verifier := NewL2Verifier(t, log.New("role", "verifier"), l1F, blobSrc, altda.Disabled, engCl, sd.RollupCfg, syncCfg, cfg.SafeHeadListener) + verifier := NewL2Verifier(t, log.New("role", "verifier"), l1F, blobSrc, altda.Disabled, engCl, sd.RollupCfg, syncCfg, cfg.SafeHeadListener, nil) return engine, verifier } diff --git a/op-e2e/actions/proofs/block_data_hint_test.go b/op-e2e/actions/proofs/block_data_hint_test.go index 3a08a54d191f8..4f7ac7e9f4575 100644 --- a/op-e2e/actions/proofs/block_data_hint_test.go +++ b/op-e2e/actions/proofs/block_data_hint_test.go @@ -154,5 +154,6 @@ func createVerifier(t actionsHelpers.Testing, env *helpers.L2FaultProofEnv) (*ac env.Sd.RollupCfg, &sync.Config{}, safedb.Disabled, + nil, ), engine } diff --git a/op-e2e/actions/proofs/isthmus_setcode_tx_test.go b/op-e2e/actions/proofs/isthmus_setcode_tx_test.go index eac5191ce0fca..5bc9987d2dceb 100644 --- a/op-e2e/actions/proofs/isthmus_setcode_tx_test.go +++ b/op-e2e/actions/proofs/isthmus_setcode_tx_test.go @@ -1,76 +1,37 @@ package proofs_test import ( - "bytes" "testing" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/core/vm/program" "github.com/holiman/uint256" "github.com/stretchr/testify/require" actionsHelpers "github.com/ethereum-optimism/optimism/op-e2e/actions/helpers" "github.com/ethereum-optimism/optimism/op-e2e/actions/proofs/helpers" -) - -var ( - aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa") - bb = common.HexToAddress("0x000000000000000000000000000000000000bbbb") + "github.com/ethereum-optimism/optimism/op-program/client/claim" ) func runSetCodeTxTypeTest(gt *testing.T, testCfg *helpers.TestCfg[any]) { t := actionsHelpers.NewDefaultTesting(gt) + env := helpers.NewL2FaultProofEnv(t, testCfg, helpers.NewTestParams(), helpers.NewBatcherCfg()) - // hardcoded because it's not available until after we need it - bobAddr := common.HexToAddress("0x14dC79964da2C08b23698B3D3cc7Ca32193d9955") - - // Create 2 contracts, (1) writes 42 to slot 42, (2) calls (1) - store42Program := program.New().Sstore(0x42, 0x42) - callBobProgram := program.New().Call(nil, bobAddr, 1, 0, 0, 0, 0) - - alloc := *actionsHelpers.DefaultAlloc - alloc.L2Alloc = make(map[common.Address]types.Account) - alloc.L2Alloc[aa] = types.Account{ - Code: store42Program.Bytes(), - } - alloc.L2Alloc[bb] = types.Account{ - Code: callBobProgram.Bytes(), - } - - testCfg.Allocs = &alloc + cl := env.Engine.EthClient() + sequencer := env.Sequencer + miner := env.Miner - tp := helpers.NewTestParams() - env := helpers.NewL2FaultProofEnv(t, testCfg, tp, helpers.NewBatcherCfg()) + miner.ActEmptyBlock(t) + sequencer.ActL1HeadSignal(t) - cl := env.Engine.EthClient() + sequencer.ActL2EmptyBlock(t) - env.Sequencer.ActL2PipelineFull(t) - env.Miner.ActEmptyBlock(t) - env.Sequencer.ActL2StartBlock(t) + batcher := env.Batcher aliceSecret := env.Alice.L2.Secret() - bobSecret := env.Bob.L2.Secret() chainID := env.Sequencer.RollupCfg.L2ChainID - // Sign authorization tuples. - // The way the auths are combined, it becomes - // 1. tx -> addr1 which is delegated to 0xaaaa - // 2. addr1:0xaaaa calls into addr2:0xbbbb - // 3. addr2:0xbbbb writes to storage - auth1, err := types.SignSetCode(aliceSecret, types.SetCodeAuthorization{ - ChainID: *uint256.MustFromBig(chainID), - Address: bb, - Nonce: 1, - }) - require.NoError(gt, err, "failed to sign auth1") - auth2, err := types.SignSetCode(bobSecret, types.SetCodeAuthorization{ - Address: aa, - Nonce: 0, - }) - require.NoError(gt, err, "failed to sign auth2") - txdata := &types.SetCodeTx{ ChainID: uint256.MustFromBig(chainID), Nonce: 0, @@ -78,44 +39,25 @@ func runSetCodeTxTypeTest(gt *testing.T, testCfg *helpers.TestCfg[any]) { Gas: 500000, GasFeeCap: uint256.NewInt(5000000000), GasTipCap: uint256.NewInt(2), - AuthList: []types.SetCodeAuthorization{auth1, auth2}, + AuthList: []types.SetCodeAuthorization{}, } signer := types.NewIsthmusSigner(chainID) tx := types.MustSignNewTx(aliceSecret, signer, txdata) - err = cl.SendTransaction(t.Ctx(), tx) - require.NoError(gt, err, "failed to send set code tx") - - _, err = env.Engine.EngineApi.IncludeTx(tx, env.Alice.Address()) - require.NoError(t, err, "failed to include set code tx") - - env.Sequencer.ActL2EndBlock(t) - - // Verify delegation designations were deployed. - bobCode, err := cl.PendingCodeAt(t.Ctx(), env.Bob.Address()) - require.NoError(gt, err, "failed to get bob code") - want := types.AddressToDelegation(auth2.Address) - if !bytes.Equal(bobCode, want) { - t.Fatalf("addr1 code incorrect: got %s, want %s", common.Bytes2Hex(bobCode), common.Bytes2Hex(want)) - } - aliceCode, err := cl.PendingCodeAt(t.Ctx(), env.Alice.Address()) - require.NoError(gt, err, "failed to get alice code") - want = types.AddressToDelegation(auth1.Address) - if !bytes.Equal(aliceCode, want) { - t.Fatalf("addr2 code incorrect: got %s, want %s", common.Bytes2Hex(aliceCode), common.Bytes2Hex(want)) - } + batcher.ActL2BatchBuffer(t, func(block *types.Block) *types.Block { + // inject user tx into upgrade batch + return block.WithBody(types.Body{Transactions: append(block.Transactions(), tx)}) + }) - // Verify delegation executed the correct code. - fortyTwo := common.BytesToHash([]byte{0x42}) - actual, err := cl.PendingStorageAt(t.Ctx(), env.Bob.Address(), fortyTwo) - require.NoError(gt, err, "failed to get addr1 storage") + batcher.ActL2ChannelClose(t) + batcher.ActL2BatchSubmit(t) - if !bytes.Equal(actual, fortyTwo[:]) { - t.Fatalf("addr2 storage wrong: expected %d, got %d", fortyTwo, actual) - } + env.Miner.ActL1StartBlock(12)(t) + env.Miner.ActL1IncludeTxByHash(env.Batcher.LastSubmitted.Hash())(t) + env.Miner.ActL1EndBlock(t) - // batch submit to L1. batcher should submit span batches. - env.BatchAndMine(t) + env.Sequencer.ActL1HeadSignal(t) + env.Sequencer.ActL2PipelineFull(t) env.Sequencer.ActL1HeadSignal(t) env.Sequencer.ActL2PipelineFull(t) @@ -130,9 +72,41 @@ func TestSetCodeTx(gt *testing.T) { matrix := helpers.NewMatrix[any]() defer matrix.Run(gt) - matrix.AddDefaultTestCases( - nil, - helpers.LatestForkOnly, - runSetCodeTxTypeTest, - ) + cases := []struct { + name string + expectSuccess bool + hardfork helpers.Hardfork + }{ + { + name: "PreIsthmus", + expectSuccess: false, + hardfork: *helpers.Holocene, + }, + { + name: "Isthmus", + expectSuccess: true, + hardfork: *helpers.Isthmus, + }, + } + + for _, c := range cases { + matrix.AddTestCase( + "HonestClaim-"+c.name+"-Failure", + nil, + helpers.NewForkMatrix(&c.hardfork), + runSetCodeTxTypeTest, + helpers.ExpectError(claim.ErrClaimNotValid), + ) + + if c.expectSuccess { + matrix.AddTestCase( + "JunkClaim-"+c.name, + nil, + helpers.NewForkMatrix(&c.hardfork), + runSetCodeTxTypeTest, + helpers.ExpectError(claim.ErrClaimNotValid), + helpers.WithL2Claim(common.HexToHash("0xdeadbeef")), + ) + } + } } diff --git a/op-e2e/actions/sync/sync_test.go b/op-e2e/actions/sync/sync_test.go index 8531e2ef52722..15f682fe8fbe3 100644 --- a/op-e2e/actions/sync/sync_test.go +++ b/op-e2e/actions/sync/sync_test.go @@ -821,7 +821,7 @@ func TestELSyncTransitionsToCLSyncAfterNodeRestart(gt *testing.T) { PrepareELSyncedNode(t, miner, sequencer, seqEng, verifier, verEng, seqEngCl, batcher, dp) // Create a new verifier which is essentially a new op-node with the sync mode of ELSync and default geth engine kind. - verifier = actionsHelpers.NewL2Verifier(t, captureLog, miner.L1Client(t, sd.RollupCfg), miner.BlobStore(), altda.Disabled, verifier.Eng, sd.RollupCfg, &sync.Config{SyncMode: sync.ELSync}, actionsHelpers.DefaultVerifierCfg().SafeHeadListener) + verifier = actionsHelpers.NewL2Verifier(t, captureLog, miner.L1Client(t, sd.RollupCfg), miner.BlobStore(), altda.Disabled, verifier.Eng, sd.RollupCfg, &sync.Config{SyncMode: sync.ELSync}, actionsHelpers.DefaultVerifierCfg().SafeHeadListener, nil) // Build another 10 L1 blocks on the sequencer for i := 0; i < 10; i++ { @@ -863,7 +863,7 @@ func TestForcedELSyncCLAfterNodeRestart(gt *testing.T) { PrepareELSyncedNode(t, miner, sequencer, seqEng, verifier, verEng, seqEngCl, batcher, dp) // Create a new verifier which is essentially a new op-node with the sync mode of ELSync and erigon engine kind. - verifier2 := actionsHelpers.NewL2Verifier(t, captureLog, miner.L1Client(t, sd.RollupCfg), miner.BlobStore(), altda.Disabled, verifier.Eng, sd.RollupCfg, &sync.Config{SyncMode: sync.ELSync, SupportsPostFinalizationELSync: true}, actionsHelpers.DefaultVerifierCfg().SafeHeadListener) + verifier2 := actionsHelpers.NewL2Verifier(t, captureLog, miner.L1Client(t, sd.RollupCfg), miner.BlobStore(), altda.Disabled, verifier.Eng, sd.RollupCfg, &sync.Config{SyncMode: sync.ELSync, SupportsPostFinalizationELSync: true}, actionsHelpers.DefaultVerifierCfg().SafeHeadListener, nil) // Build another 10 L1 blocks on the sequencer for i := 0; i < 10; i++ { diff --git a/op-node/rollup/derive/batches.go b/op-node/rollup/derive/batches.go index 4e3e20d1e50fc..102145f97a4e2 100644 --- a/op-node/rollup/derive/batches.go +++ b/op-node/rollup/derive/batches.go @@ -161,6 +161,8 @@ func checkSingularBatch(cfg *rollup.Config, log log.Logger, l1Blocks []eth.L1Blo } } + isIsthmus := cfg.IsIsthmus(batch.Timestamp) + // We can do this check earlier, but it's a more intensive one, so we do this last. for i, txBytes := range batch.Transactions { if len(txBytes) == 0 { @@ -171,6 +173,10 @@ func checkSingularBatch(cfg *rollup.Config, log log.Logger, l1Blocks []eth.L1Blo log.Warn("sequencers may not embed any deposits into batch data, but found tx that has one", "tx_index", i) return BatchDrop } + if !isIsthmus && txBytes[0] == types.SetCodeTxType { + log.Warn("sequencers may not embed any SetCode transactions before Isthmus", "tx_index", i) + return BatchDrop + } } return BatchAccept