Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

e2e tests for L1 Pectra activation #14006

Draft
wants to merge 19 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion op-e2e/actions/helpers/l1_miner.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,10 @@ func (s *L1Miner) ActL1StartBlock(timeDelta uint64) Action {
core.ProcessBeaconBlockRoot(*header.ParentBeaconRoot, vmenv)
}

if s.l1Cfg.Config.IsPrague(header.Number, header.Time) {
header.RequestsHash = &types.EmptyRequestsHash
}

s.l1Building = true
s.l1BuildingHeader = header
s.l1BuildingState = statedb
Expand Down Expand Up @@ -254,7 +258,7 @@ func (s *L1Miner) ActL1EndBlock(t Testing) *types.Block {
}
_, err = s.l1Chain.InsertChain(types.Blocks{block})
if err != nil {
t.Fatalf("failed to insert block into l1 chain")
t.Fatalf("failed to insert block into l1 chain: %w", err)
}
return block
}
Expand Down
39 changes: 39 additions & 0 deletions op-e2e/actions/helpers/l2_batcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -527,3 +527,42 @@ func (s *L2Batcher) ActSubmitAllMultiBlobs(t Testing, numBlobs int) {
s.ActL2ChannelClose(t)
s.ActL2BatchSubmitMultiBlob(t, numBlobs)
}

// ActSubmitSetCodeTx submits a SetCodeTx to the batch inbox. This models a malicious
// batcher and is only used to tests the derivation pipeline follows spec and ignores
// the SetCodeTx.
func (s *L2Batcher) ActSubmitSetCodeTx(t Testing) {
chainId := *uint256.MustFromBig(s.rollupCfg.L1ChainID)

nonce, err := s.l1.PendingNonceAt(t.Ctx(), s.BatcherAddr)
require.NoError(t, err, "need batcher nonce")

setCodeAuthorization := types.SetCodeAuthorization{
ChainID: chainId,
Address: common.HexToAddress("0xab"), // arbitrary nonzero address
Nonce: nonce,
}

signedAuth, err := types.SignSetCode(s.l2BatcherCfg.BatcherKey, setCodeAuthorization)
require.NoError(t, err, "SignSetCode failed")

txData := &types.SetCodeTx{
ChainID: &chainId,
Nonce: nonce,
To: s.rollupCfg.BatchInboxAddress, // send to batch inbox
Value: uint256.NewInt(0),
Data: s.ReadNextOutputFrame(t),
AccessList: types.AccessList{},
AuthList: []types.SetCodeAuthorization{signedAuth},
Gas: 1_000_000,
GasFeeCap: uint256.NewInt(1_000_000_000),
}

tx, err := types.SignNewTx(s.l2BatcherCfg.BatcherKey, s.l1Signer, txData)
require.NoError(t, err, "need to sign tx")

t.Log("submitting EIP 7702 Set Code Batcher Transaction...")
err = s.l1.SendTransaction(t.Ctx(), tx)
require.NoError(t, err, "need to send tx")
s.LastSubmitted = tx
}
145 changes: 145 additions & 0 deletions op-e2e/actions/proofs/l1_prague_fork_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
package proofs

import (
"fmt"
"testing"

batcherFlags "github.com/ethereum-optimism/optimism/op-batcher/flags"
"github.com/ethereum-optimism/optimism/op-chain-ops/genesis"
actionsHelpers "github.com/ethereum-optimism/optimism/op-e2e/actions/helpers"
"github.com/ethereum-optimism/optimism/op-e2e/actions/proofs/helpers"
"github.com/ethereum-optimism/optimism/op-program/client/claim"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/stretchr/testify/require"
)

func TestPragueForkAfterGenesis(gt *testing.T) {
type testCase struct {
name string
useSetCodeTx bool
}

testCases := []testCase{
{
name: "calldata", useSetCodeTx: false,
},
{
name: "setCode", useSetCodeTx: true,
},
}

runL1PragueTest := func(gt *testing.T, testCfg *helpers.TestCfg[testCase]) {
t := actionsHelpers.NewDefaultTesting(gt)
env := helpers.NewL2FaultProofEnv(t, testCfg, helpers.NewTestParams(),
helpers.NewBatcherCfg(
func(c *actionsHelpers.BatcherCfg) {
c.DataAvailabilityType = batcherFlags.CalldataType
},
),
func(dp *genesis.DeployConfig) {
t := hexutil.Uint64(24) // Activate at second l1 block
dp.L1PragueTimeOffset = &t
},
)

miner, batcher, verifier, sequencer := env.Miner, env.Batcher, env.Sequencer, env.Sequencer

// utils
checkVerifierDerivedToL1Head := func(t actionsHelpers.StatefulTesting) {
l1Head := miner.L1Chain().CurrentBlock()
currentL1 := verifier.SyncStatus().CurrentL1
require.Equal(t, l1Head.Number.Int64(), int64(currentL1.Number), "verifier should derive up to and including the L1 head")
require.Equal(t, l1Head.Hash(), currentL1.Hash, "verifier should derive up to and including the L1 head")
}

buildUnsafeL2AndSubmit := func(useSetCode bool) {
sequencer.ActL2EmptyBlock(t)
miner.ActL1StartBlock(12)(t)
if useSetCode {
batcher.ActBufferAll(t)
batcher.ActL2ChannelClose(t)
batcher.ActSubmitSetCodeTx(t)
} else {
batcher.ActSubmitAll(t)
}
miner.ActL1IncludeTx(batcher.BatcherAddr)(t)
miner.ActL1EndBlock(t)
}

checkPragueStatusOnL1 := func(active bool) {
l1Head := miner.L1Chain().CurrentBlock()
if active {
// require.True(t, sd.L1Cfg.Config.IsPrague(l1Head.Number, l1Head.Time), "Prague should be active")
require.NotNil(t, l1Head.RequestsHash, "Prague header requests hash should be non-nil")
} else {
// require.False(t, sd.L1Cfg.Config.IsPrague(l1Head.Number, l1Head.Time), "Prague should not be active yet")
require.Nil(t, l1Head.RequestsHash, "Prague header requests hash should be nil")
}
}

syncVerifierAndCheck := func(t actionsHelpers.StatefulTesting) {
verifier.ActL1HeadSignal(t)
verifier.ActL2PipelineFull(t)
checkVerifierDerivedToL1Head(t)
}

// Check initially Prague is not activated
checkPragueStatusOnL1(false)

// Start op-nodes
sequencer.ActL2PipelineFull(t)
verifier.ActL2PipelineFull(t)

// Build empty L1 blocks, crossing the fork boundary
miner.ActEmptyBlock(t)
miner.ActEmptyBlock(t) // Prague activates here
miner.ActEmptyBlock(t)

// Check that Prague is active on L1
checkPragueStatusOnL1(true)

// Cache safe head before verifier sync
safeL2Before := verifier.SyncStatus().SafeL2

// Build L2 unsafe chain and batch it to L1 using either calldata or
// EIP-7702 setCode txs
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-7702.md
buildUnsafeL2AndSubmit(testCfg.Custom.useSetCodeTx)
Comment on lines +105 to +108
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This currently fails as upstream geth does not yet support EIP7702 transactions in the txpool. The test passes when run against this patch ethereum-optimism/op-geth#479


// Check verifier derived from Prague L1 blocks
syncVerifierAndCheck(t)

// Check safe head did or did not change,
// depending on tx type used by batcher:
safeL2After := verifier.SyncStatus().SafeL2
if testCfg.Custom.useSetCodeTx {
require.Equal(t, safeL2Before, safeL2After, "safe head should not have changed (set code batcher tx ignored)")
} else {
require.Greater(t, safeL2After.Number, safeL2Before.Number, "safe head should have progressed (calldata batcher tx included)")
}

env.RunFaultProofProgram(t, safeL2After.Number, testCfg.CheckResult, testCfg.InputParams...)
}

matrix := helpers.NewMatrix[testCase]()
defer matrix.Run(gt)

for _, tc := range testCases {
matrix.AddTestCase(
fmt.Sprintf("HonestClaim-%s", tc.name),
tc,
helpers.NewForkMatrix(helpers.LatestFork),
runL1PragueTest,
helpers.ExpectNoError(),
)
matrix.AddTestCase(
fmt.Sprintf("JunkClaim-%s", tc.name),
tc,
helpers.NewForkMatrix(helpers.LatestFork),
runL1PragueTest,
helpers.ExpectError(claim.ErrClaimNotValid),
helpers.WithL2Claim(common.HexToHash("0xdeadbeef")),
)
}
}
2 changes: 1 addition & 1 deletion op-e2e/config/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ func initAllocType(root string, allocType AllocType) {
mtx.Unlock()

// This needs to be updated whenever the latest hardfork is changed.
if mode == genesis.L2AllocsGranite {
if mode == genesis.L2AllocsHolocene {
dc, err := inspect.DeployConfig(st, intent.Chains[0].ID)
if err != nil {
panic(fmt.Errorf("failed to inspect deploy config: %w", err))
Expand Down
1 change: 1 addition & 0 deletions packages/contracts-bedrock/lib/automate
Submodule automate added at 011758