From 8894cf55ab1b8caedbeb147e2dfb15cf2426c784 Mon Sep 17 00:00:00 2001 From: clabby Date: Wed, 11 Sep 2024 18:57:19 -0400 Subject: [PATCH 1/5] chore: Cleanup proofs actions --- op-e2e/actions/altda_test.go | 2 +- op-e2e/actions/batch_queue_test.go | 2 +- op-e2e/actions/blocktime_test.go | 8 +- op-e2e/actions/dencun_fork_test.go | 28 +-- op-e2e/actions/ecotone_fork_test.go | 8 +- op-e2e/actions/eip4844_test.go | 4 +- op-e2e/actions/fjord_fork_test.go | 4 +- op-e2e/actions/interop_test.go | 4 +- op-e2e/actions/l1_miner.go | 4 +- op-e2e/actions/l1_miner_test.go | 4 +- op-e2e/actions/l1_replica.go | 4 + op-e2e/actions/l1_replica_test.go | 17 +- op-e2e/actions/l2_batcher_test.go | 18 +- op-e2e/actions/l2_engine.go | 4 + op-e2e/actions/l2_engine_test.go | 16 +- op-e2e/actions/l2_proposer_test.go | 4 +- op-e2e/actions/l2_sequencer_test.go | 48 +---- op-e2e/actions/l2_verifier_test.go | 33 +--- op-e2e/actions/proofs/env.go | 181 +++++++++++++++++++ op-e2e/actions/proofs/fixture.go | 119 ++++++++++++ op-e2e/actions/proofs/simple_program_test.go | 109 +++++++++++ op-e2e/actions/reorg_test.go | 14 +- op-e2e/actions/safedb_test.go | 4 +- op-e2e/actions/span_batch_test.go | 14 +- op-e2e/actions/sync_test.go | 56 +++--- op-e2e/actions/system_config_test.go | 12 +- op-e2e/actions/user_test.go | 4 +- op-e2e/actions/utils.go | 79 ++++++++ 28 files changed, 613 insertions(+), 191 deletions(-) create mode 100644 op-e2e/actions/proofs/env.go create mode 100644 op-e2e/actions/proofs/fixture.go create mode 100644 op-e2e/actions/proofs/simple_program_test.go create mode 100644 op-e2e/actions/utils.go diff --git a/op-e2e/actions/altda_test.go b/op-e2e/actions/altda_test.go index ab18ff77e098..ed6068c141ae 100644 --- a/op-e2e/actions/altda_test.go +++ b/op-e2e/actions/altda_test.go @@ -60,7 +60,7 @@ func NewL2AltDA(t Testing, params ...AltDAParam) *L2AltDA { log := testlog.Logger(t, log.LvlDebug) dp := e2eutils.MakeDeployParams(t, p) - sd := e2eutils.Setup(t, dp, defaultAlloc) + sd := e2eutils.Setup(t, dp, DefaultAlloc) require.True(t, sd.RollupCfg.AltDAEnabled()) diff --git a/op-e2e/actions/batch_queue_test.go b/op-e2e/actions/batch_queue_test.go index 69c9957d134b..e5132a85ac94 100644 --- a/op-e2e/actions/batch_queue_test.go +++ b/op-e2e/actions/batch_queue_test.go @@ -30,7 +30,7 @@ func TestDeriveChainFromNearL1Genesis(gt *testing.T) { dp := e2eutils.MakeDeployParams(t, p) // do not activate Delta hardfork for verifier applyDeltaTimeOffset(dp, nil) - sd := e2eutils.Setup(t, dp, defaultAlloc) + sd := e2eutils.Setup(t, dp, DefaultAlloc) logger := testlog.Logger(t, log.LevelInfo) miner, seqEngine, sequencer := setupSequencerTest(t, sd, logger) diff --git a/op-e2e/actions/blocktime_test.go b/op-e2e/actions/blocktime_test.go index 7bf34e103cc7..20f644887697 100644 --- a/op-e2e/actions/blocktime_test.go +++ b/op-e2e/actions/blocktime_test.go @@ -45,12 +45,12 @@ func TestBlockTimeBatchType(t *testing.T) { // This is a regression test against the bug fixed in PR #4566 func BatchInLastPossibleBlocks(gt *testing.T, deltaTimeOffset *hexutil.Uint64) { t := NewDefaultTesting(gt) - dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams) + dp := e2eutils.MakeDeployParams(t, DefaultRollupTestParams) applyDeltaTimeOffset(dp, deltaTimeOffset) dp.DeployConfig.SequencerWindowSize = 4 dp.DeployConfig.L2BlockTime = 2 - sd := e2eutils.Setup(t, dp, defaultAlloc) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LevelDebug) sd, _, miner, sequencer, sequencerEngine, _, _, batcher := setupReorgTestActors(t, dp, sd, log) @@ -156,7 +156,7 @@ func BatchInLastPossibleBlocks(gt *testing.T, deltaTimeOffset *hexutil.Uint64) { // Note: It batches submits when possible. func LargeL1Gaps(gt *testing.T, deltaTimeOffset *hexutil.Uint64) { t := NewDefaultTesting(gt) - dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams) + dp := e2eutils.MakeDeployParams(t, DefaultRollupTestParams) dp.DeployConfig.L1BlockTime = 4 dp.DeployConfig.L2BlockTime = 2 dp.DeployConfig.SequencerWindowSize = 4 @@ -166,7 +166,7 @@ func LargeL1Gaps(gt *testing.T, deltaTimeOffset *hexutil.Uint64) { // TODO(client-pod#831): The Ecotone (and Fjord) activation blocks don't include user txs, // so disabling these forks for now. applyDeltaTimeOffset(dp, deltaTimeOffset) - sd := e2eutils.Setup(t, dp, defaultAlloc) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LevelDebug) sd, _, miner, sequencer, sequencerEngine, verifier, _, batcher := setupReorgTestActors(t, dp, sd, log) diff --git a/op-e2e/actions/dencun_fork_test.go b/op-e2e/actions/dencun_fork_test.go index 9b411e28f1e7..ac0484c800b0 100644 --- a/op-e2e/actions/dencun_fork_test.go +++ b/op-e2e/actions/dencun_fork_test.go @@ -18,10 +18,10 @@ import ( func TestDencunL1ForkAfterGenesis(gt *testing.T) { t := NewDefaultTesting(gt) - dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams) + dp := e2eutils.MakeDeployParams(t, DefaultRollupTestParams) offset := hexutil.Uint64(24) dp.DeployConfig.L1CancunTimeOffset = &offset - sd := e2eutils.Setup(t, dp, defaultAlloc) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LevelDebug) _, _, miner, sequencer, _, verifier, _, batcher := setupReorgTestActors(t, dp, sd, log) @@ -61,9 +61,9 @@ func TestDencunL1ForkAfterGenesis(gt *testing.T) { func TestDencunL1ForkAtGenesis(gt *testing.T) { t := NewDefaultTesting(gt) - dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams) + dp := e2eutils.MakeDeployParams(t, DefaultRollupTestParams) require.Zero(t, *dp.DeployConfig.L1CancunTimeOffset) - sd := e2eutils.Setup(t, dp, defaultAlloc) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LevelDebug) _, _, miner, sequencer, _, verifier, _, batcher := setupReorgTestActors(t, dp, sd, log) @@ -118,7 +118,7 @@ func verifyEcotoneBlock(gt *testing.T, header *types.Header) { func TestDencunL2ForkAfterGenesis(gt *testing.T) { t := NewDefaultTesting(gt) - dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams) + dp := e2eutils.MakeDeployParams(t, DefaultRollupTestParams) require.Zero(t, *dp.DeployConfig.L1CancunTimeOffset) // This test wil fork on the second block offset := hexutil.Uint64(dp.DeployConfig.L2BlockTime * 2) @@ -127,7 +127,7 @@ func TestDencunL2ForkAfterGenesis(gt *testing.T) { dp.DeployConfig.L2GenesisGraniteTimeOffset = nil // New forks have to be added here, after changing the default deploy config! - sd := e2eutils.Setup(t, dp, defaultAlloc) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LevelDebug) _, _, _, sequencer, engine, verifier, _, _ := setupReorgTestActors(t, dp, sd, log) @@ -156,10 +156,10 @@ func TestDencunL2ForkAfterGenesis(gt *testing.T) { func TestDencunL2ForkAtGenesis(gt *testing.T) { t := NewDefaultTesting(gt) - dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams) + dp := e2eutils.MakeDeployParams(t, DefaultRollupTestParams) require.Zero(t, *dp.DeployConfig.L2GenesisEcotoneTimeOffset) - sd := e2eutils.Setup(t, dp, defaultAlloc) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LevelDebug) _, _, _, sequencer, engine, verifier, _, _ := setupReorgTestActors(t, dp, sd, log) @@ -194,9 +194,9 @@ func newEngine(t Testing, sd *e2eutils.SetupData, log log.Logger) *L2Engine { // TestDencunBlobTxRPC tries to send a Blob tx to the L2 engine via RPC, it should not be accepted. func TestDencunBlobTxRPC(gt *testing.T) { t := NewDefaultTesting(gt) - dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams) + dp := e2eutils.MakeDeployParams(t, DefaultRollupTestParams) - sd := e2eutils.Setup(t, dp, defaultAlloc) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LevelDebug) engine := newEngine(t, sd, log) cl := engine.EthClient() @@ -208,9 +208,9 @@ func TestDencunBlobTxRPC(gt *testing.T) { // TestDencunBlobTxInTxPool tries to insert a blob tx directly into the tx pool, it should not be accepted. func TestDencunBlobTxInTxPool(gt *testing.T) { t := NewDefaultTesting(gt) - dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams) + dp := e2eutils.MakeDeployParams(t, DefaultRollupTestParams) - sd := e2eutils.Setup(t, dp, defaultAlloc) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LevelDebug) engine := newEngine(t, sd, log) tx := aliceSimpleBlobTx(t, dp) @@ -221,9 +221,9 @@ func TestDencunBlobTxInTxPool(gt *testing.T) { // TestDencunBlobTxInclusion tries to send a Blob tx to the L2 engine, it should not be accepted. func TestDencunBlobTxInclusion(gt *testing.T) { t := NewDefaultTesting(gt) - dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams) + dp := e2eutils.MakeDeployParams(t, DefaultRollupTestParams) - sd := e2eutils.Setup(t, dp, defaultAlloc) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LevelDebug) _, engine, sequencer := setupSequencerTest(t, sd, log) diff --git a/op-e2e/actions/ecotone_fork_test.go b/op-e2e/actions/ecotone_fork_test.go index 260a7960089a..3237915d6e00 100644 --- a/op-e2e/actions/ecotone_fork_test.go +++ b/op-e2e/actions/ecotone_fork_test.go @@ -41,7 +41,7 @@ func verifyCodeHashMatches(t Testing, client *ethclient.Client, address common.A func TestEcotoneNetworkUpgradeTransactions(gt *testing.T) { t := NewDefaultTesting(gt) - dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams) + dp := e2eutils.MakeDeployParams(t, DefaultRollupTestParams) ecotoneOffset := hexutil.Uint64(4) log := testlog.Logger(t, log.LevelDebug) @@ -54,7 +54,7 @@ func TestEcotoneNetworkUpgradeTransactions(gt *testing.T) { // New forks have to be added here... require.NoError(t, dp.DeployConfig.Check(log), "must have valid config") - sd := e2eutils.Setup(t, dp, defaultAlloc) + sd := e2eutils.Setup(t, dp, DefaultAlloc) _, _, miner, sequencer, engine, verifier, _, _ := setupReorgTestActors(t, dp, sd, log) ethCl := engine.EthClient() @@ -239,7 +239,7 @@ func TestEcotoneNetworkUpgradeTransactions(gt *testing.T) { // TestEcotoneBeforeL1 tests that the L2 Ecotone fork can activate before L1 Dencun does func TestEcotoneBeforeL1(gt *testing.T) { t := NewDefaultTesting(gt) - dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams) + dp := e2eutils.MakeDeployParams(t, DefaultRollupTestParams) offset := hexutil.Uint64(0) farOffset := hexutil.Uint64(10000) dp.DeployConfig.L2GenesisRegolithTimeOffset = &offset @@ -248,7 +248,7 @@ func TestEcotoneBeforeL1(gt *testing.T) { dp.DeployConfig.L2GenesisDeltaTimeOffset = &offset dp.DeployConfig.L2GenesisEcotoneTimeOffset = &offset - sd := e2eutils.Setup(t, dp, defaultAlloc) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LevelDebug) _, _, _, sequencer, engine, verifier, _, _ := setupReorgTestActors(t, dp, sd, log) diff --git a/op-e2e/actions/eip4844_test.go b/op-e2e/actions/eip4844_test.go index ddab21d48b47..8b287250bb0e 100644 --- a/op-e2e/actions/eip4844_test.go +++ b/op-e2e/actions/eip4844_test.go @@ -17,14 +17,14 @@ import ( ) func setupEIP4844Test(t Testing, log log.Logger) (*e2eutils.SetupData, *e2eutils.DeployParams, *L1Miner, *L2Sequencer, *L2Engine, *L2Verifier, *L2Engine) { - dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams) + dp := e2eutils.MakeDeployParams(t, DefaultRollupTestParams) genesisActivation := hexutil.Uint64(0) dp.DeployConfig.L1CancunTimeOffset = &genesisActivation dp.DeployConfig.L2GenesisCanyonTimeOffset = &genesisActivation dp.DeployConfig.L2GenesisDeltaTimeOffset = &genesisActivation dp.DeployConfig.L2GenesisEcotoneTimeOffset = &genesisActivation - sd := e2eutils.Setup(t, dp, defaultAlloc) + sd := e2eutils.Setup(t, dp, DefaultAlloc) miner, seqEngine, sequencer := setupSequencerTest(t, sd, log) miner.ActL1SetFeeRecipient(common.Address{'A'}) sequencer.ActL2PipelineFull(t) diff --git a/op-e2e/actions/fjord_fork_test.go b/op-e2e/actions/fjord_fork_test.go index 517ec5cd2618..d003c69af394 100644 --- a/op-e2e/actions/fjord_fork_test.go +++ b/op-e2e/actions/fjord_fork_test.go @@ -30,7 +30,7 @@ var ( func TestFjordNetworkUpgradeTransactions(gt *testing.T) { t := NewDefaultTesting(gt) - dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams) + dp := e2eutils.MakeDeployParams(t, DefaultRollupTestParams) genesisBlock := hexutil.Uint64(0) fjordOffset := hexutil.Uint64(2) @@ -46,7 +46,7 @@ func TestFjordNetworkUpgradeTransactions(gt *testing.T) { dp.DeployConfig.L2GenesisFjordTimeOffset = &fjordOffset require.NoError(t, dp.DeployConfig.Check(log), "must have valid config") - sd := e2eutils.Setup(t, dp, defaultAlloc) + sd := e2eutils.Setup(t, dp, DefaultAlloc) _, _, _, sequencer, engine, verifier, _, _ := setupReorgTestActors(t, dp, sd, log) ethCl := engine.EthClient() diff --git a/op-e2e/actions/interop_test.go b/op-e2e/actions/interop_test.go index 8890f86a0067..614ab05f65a7 100644 --- a/op-e2e/actions/interop_test.go +++ b/op-e2e/actions/interop_test.go @@ -19,8 +19,8 @@ var _ interop.InteropBackend = (*testutils.MockInteropBackend)(nil) func TestInteropVerifier(gt *testing.T) { t := NewDefaultTesting(gt) - dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams) - sd := e2eutils.Setup(t, dp, defaultAlloc) + dp := e2eutils.MakeDeployParams(t, DefaultRollupTestParams) + sd := e2eutils.Setup(t, dp, DefaultAlloc) // Temporary work-around: interop needs to be active, for cross-safety to not be instant. // The state genesis in this test is pre-interop however. sd.RollupCfg.InteropTime = new(uint64) diff --git a/op-e2e/actions/l1_miner.go b/op-e2e/actions/l1_miner.go index d14eab394131..46c9045961bb 100644 --- a/op-e2e/actions/l1_miner.go +++ b/op-e2e/actions/l1_miner.go @@ -17,7 +17,7 @@ import ( "github.com/ethereum/go-ethereum/trie" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils" - "github.com/ethereum-optimism/optimism/op-node/rollup/derive" + "github.com/ethereum-optimism/optimism/op-program/host/sources" "github.com/ethereum-optimism/optimism/op-service/eth" ) @@ -52,7 +52,7 @@ func NewL1Miner(t Testing, log log.Logger, genesis *core.Genesis) *L1Miner { } } -func (s *L1Miner) BlobStore() derive.L1BlobsFetcher { +func (s *L1Miner) BlobStore() sources.L1BlobSource { return s.blobStore } diff --git a/op-e2e/actions/l1_miner_test.go b/op-e2e/actions/l1_miner_test.go index 10e4c0c5498c..a56fc06c235b 100644 --- a/op-e2e/actions/l1_miner_test.go +++ b/op-e2e/actions/l1_miner_test.go @@ -15,8 +15,8 @@ import ( func TestL1Miner_BuildBlock(gt *testing.T) { t := NewDefaultTesting(gt) - dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams) - sd := e2eutils.Setup(t, dp, defaultAlloc) + dp := e2eutils.MakeDeployParams(t, DefaultRollupTestParams) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LevelDebug) miner := NewL1Miner(t, log, sd.L1Cfg) t.Cleanup(func() { diff --git a/op-e2e/actions/l1_replica.go b/op-e2e/actions/l1_replica.go index fb042757065e..83120203ee7b 100644 --- a/op-e2e/actions/l1_replica.go +++ b/op-e2e/actions/l1_replica.go @@ -192,6 +192,10 @@ func (s *L1Replica) L1Client(t Testing, cfg *rollup.Config) *sources.L1Client { return l1F } +func (s *L1Replica) L1Chain() *core.BlockChain { + return s.l1Chain +} + func (s *L1Replica) UnsafeNum() uint64 { head := s.l1Chain.CurrentBlock() headNum := uint64(0) diff --git a/op-e2e/actions/l1_replica_test.go b/op-e2e/actions/l1_replica_test.go index ab918a619644..1d342a86e81f 100644 --- a/op-e2e/actions/l1_replica_test.go +++ b/op-e2e/actions/l1_replica_test.go @@ -21,20 +21,11 @@ import ( "github.com/ethereum-optimism/optimism/op-service/testlog" ) -var defaultRollupTestParams = &e2eutils.TestParams{ - MaxSequencerDrift: 40, - SequencerWindowSize: 120, - ChannelTimeout: 120, - L1BlockTime: 15, -} - -var defaultAlloc = &e2eutils.AllocParams{PrefundTestUsers: true} - // Test if we can mock an RPC failure func TestL1Replica_ActL1RPCFail(gt *testing.T) { t := NewDefaultTesting(gt) - dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams) - sd := e2eutils.Setup(t, dp, defaultAlloc) + dp := e2eutils.MakeDeployParams(t, DefaultRollupTestParams) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LevelDebug) replica := NewL1Replica(t, log, sd.L1Cfg) t.Cleanup(func() { @@ -55,9 +46,9 @@ func TestL1Replica_ActL1RPCFail(gt *testing.T) { // Test if we can make the replica sync an artificial L1 chain, rewind it, and reorg it func TestL1Replica_ActL1Sync(gt *testing.T) { t := NewDefaultTesting(gt) - dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams) + dp := e2eutils.MakeDeployParams(t, DefaultRollupTestParams) dp.DeployConfig.L1CancunTimeOffset = nil - sd := e2eutils.Setup(t, dp, defaultAlloc) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LevelDebug) genesisBlock := sd.L1Cfg.ToBlock() consensus := beacon.New(ethash.NewFaker()) diff --git a/op-e2e/actions/l2_batcher_test.go b/op-e2e/actions/l2_batcher_test.go index 6235c7482326..88dd393a38df 100644 --- a/op-e2e/actions/l2_batcher_test.go +++ b/op-e2e/actions/l2_batcher_test.go @@ -81,7 +81,7 @@ func NormalBatcher(gt *testing.T, deltaTimeOffset *hexutil.Uint64) { } dp := e2eutils.MakeDeployParams(t, p) applyDeltaTimeOffset(dp, deltaTimeOffset) - sd := e2eutils.Setup(t, dp, defaultAlloc) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LevelDebug) miner, seqEngine, sequencer := setupSequencerTest(t, sd, log) verifEngine, verifier := setupVerifier(t, sd, log, miner.L1Client(t, sd.RollupCfg), miner.BlobStore(), &sync.Config{}) @@ -148,9 +148,9 @@ func NormalBatcher(gt *testing.T, deltaTimeOffset *hexutil.Uint64) { func L2Finalization(gt *testing.T, deltaTimeOffset *hexutil.Uint64) { t := NewDefaultTesting(gt) - dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams) + dp := e2eutils.MakeDeployParams(t, DefaultRollupTestParams) applyDeltaTimeOffset(dp, deltaTimeOffset) - sd := e2eutils.Setup(t, dp, defaultAlloc) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LevelDebug) miner, engine, sequencer := setupSequencerTest(t, sd, log) @@ -245,9 +245,9 @@ func L2Finalization(gt *testing.T, deltaTimeOffset *hexutil.Uint64) { // L2FinalizationWithSparseL1 tests that safe L2 blocks can be finalized even if we do not regularly get a L1 finalization signal func L2FinalizationWithSparseL1(gt *testing.T, deltaTimeOffset *hexutil.Uint64) { t := NewDefaultTesting(gt) - dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams) + dp := e2eutils.MakeDeployParams(t, DefaultRollupTestParams) applyDeltaTimeOffset(dp, deltaTimeOffset) - sd := e2eutils.Setup(t, dp, defaultAlloc) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LevelDebug) miner, engine, sequencer := setupSequencerTest(t, sd, log) @@ -301,11 +301,11 @@ func L2FinalizationWithSparseL1(gt *testing.T, deltaTimeOffset *hexutil.Uint64) // and the safe L2 head should remain unaltered. func GarbageBatch(gt *testing.T, deltaTimeOffset *hexutil.Uint64) { t := NewDefaultTesting(gt) - p := defaultRollupTestParams + p := DefaultRollupTestParams dp := e2eutils.MakeDeployParams(t, p) applyDeltaTimeOffset(dp, deltaTimeOffset) for _, garbageKind := range GarbageKinds { - sd := e2eutils.Setup(t, dp, defaultAlloc) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LevelError) miner, engine, sequencer := setupSequencerTest(t, sd, log) @@ -385,7 +385,7 @@ func ExtendedTimeWithoutL1Batches(gt *testing.T, deltaTimeOffset *hexutil.Uint64 } dp := e2eutils.MakeDeployParams(t, p) applyDeltaTimeOffset(dp, deltaTimeOffset) - sd := e2eutils.Setup(t, dp, defaultAlloc) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LevelError) miner, engine, sequencer := setupSequencerTest(t, sd, log) @@ -441,7 +441,7 @@ func BigL2Txs(gt *testing.T, deltaTimeOffset *hexutil.Uint64) { } dp := e2eutils.MakeDeployParams(t, p) applyDeltaTimeOffset(dp, deltaTimeOffset) - sd := e2eutils.Setup(t, dp, defaultAlloc) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LevelInfo) miner, engine, sequencer := setupSequencerTest(t, sd, log) diff --git a/op-e2e/actions/l2_engine.go b/op-e2e/actions/l2_engine.go index 54267ee9da58..828ede53cade 100644 --- a/op-e2e/actions/l2_engine.go +++ b/op-e2e/actions/l2_engine.go @@ -135,6 +135,10 @@ func (e *engineApiBackend) Genesis() *core.Genesis { return e.genesis } +func (s *L2Engine) L2Chain() *core.BlockChain { + return s.l2Chain +} + func (s *L2Engine) Enode() *enode.Node { return s.node.Server().LocalNode().Node() } diff --git a/op-e2e/actions/l2_engine_test.go b/op-e2e/actions/l2_engine_test.go index 5d7a537b5d03..2ea335ec855e 100644 --- a/op-e2e/actions/l2_engine_test.go +++ b/op-e2e/actions/l2_engine_test.go @@ -31,8 +31,8 @@ import ( func TestL2EngineAPI(gt *testing.T) { t := NewDefaultTesting(gt) jwtPath := e2eutils.WriteDefaultJWT(t) - dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams) - sd := e2eutils.Setup(t, dp, defaultAlloc) + dp := e2eutils.MakeDeployParams(t, DefaultRollupTestParams) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LevelDebug) genesisBlock := sd.L2Cfg.ToBlock() consensus := beacon.New(ethash.NewFaker()) @@ -107,8 +107,8 @@ func TestL2EngineAPI(gt *testing.T) { func TestL2EngineAPIBlockBuilding(gt *testing.T) { t := NewDefaultTesting(gt) jwtPath := e2eutils.WriteDefaultJWT(t) - dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams) - sd := e2eutils.Setup(t, dp, defaultAlloc) + dp := e2eutils.MakeDeployParams(t, DefaultRollupTestParams) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LevelDebug) genesisBlock := sd.L2Cfg.ToBlock() db := rawdb.NewMemoryDatabase() @@ -208,8 +208,8 @@ func TestL2EngineAPIBlockBuilding(gt *testing.T) { func TestL2EngineAPIFail(gt *testing.T) { t := NewDefaultTesting(gt) jwtPath := e2eutils.WriteDefaultJWT(t) - dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams) - sd := e2eutils.Setup(t, dp, defaultAlloc) + dp := e2eutils.MakeDeployParams(t, DefaultRollupTestParams) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LevelDebug) engine := NewL2Engine(t, log, sd.L2Cfg, sd.RollupCfg.Genesis.L1, jwtPath) // mock an RPC failure @@ -228,8 +228,8 @@ func TestL2EngineAPIFail(gt *testing.T) { func TestEngineAPITests(t *testing.T) { test.RunEngineAPITests(t, func(t *testing.T) engineapi.EngineBackend { jwtPath := e2eutils.WriteDefaultJWT(t) - dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams) - sd := e2eutils.Setup(t, dp, defaultAlloc) + dp := e2eutils.MakeDeployParams(t, DefaultRollupTestParams) + sd := e2eutils.Setup(t, dp, DefaultAlloc) n, _, apiBackend := newBackend(t, sd.L2Cfg, jwtPath, nil) err := n.Start() require.NoError(t, err) diff --git a/op-e2e/actions/l2_proposer_test.go b/op-e2e/actions/l2_proposer_test.go index bed138cdb3a7..a8fe25816a0c 100644 --- a/op-e2e/actions/l2_proposer_test.go +++ b/op-e2e/actions/l2_proposer_test.go @@ -45,9 +45,9 @@ func TestProposerBatchType(t *testing.T) { func RunProposerTest(gt *testing.T, deltaTimeOffset *hexutil.Uint64) { t := NewDefaultTesting(gt) - dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams) + dp := e2eutils.MakeDeployParams(t, DefaultRollupTestParams) applyDeltaTimeOffset(dp, deltaTimeOffset) - sd := e2eutils.Setup(t, dp, defaultAlloc) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LevelDebug) miner, seqEngine, sequencer := setupSequencerTest(t, sd, log) diff --git a/op-e2e/actions/l2_sequencer_test.go b/op-e2e/actions/l2_sequencer_test.go index 87cf95eaa425..8872da6481d1 100644 --- a/op-e2e/actions/l2_sequencer_test.go +++ b/op-e2e/actions/l2_sequencer_test.go @@ -5,10 +5,6 @@ import ( "testing" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/eth/ethconfig" - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/common" @@ -21,43 +17,9 @@ import ( "github.com/ethereum-optimism/optimism/op-service/testlog" ) -func EngineWithP2P() EngineOption { - return func(ethCfg *ethconfig.Config, nodeCfg *node.Config) error { - p2pKey, err := crypto.GenerateKey() - if err != nil { - return err - } - nodeCfg.P2P = p2p.Config{ - MaxPeers: 100, - NoDiscovery: true, - ListenAddr: "127.0.0.1:0", - PrivateKey: p2pKey, - } - return nil - } -} - -type sequencerCfg struct { - verifierCfg -} - -func defaultSequencerConfig() *sequencerCfg { - return &sequencerCfg{verifierCfg: *defaultVerifierCfg()} -} - -type SequencerOpt func(opts *sequencerCfg) - -func WithVerifierOpts(opts ...VerifierOpt) SequencerOpt { - return func(cfg *sequencerCfg) { - for _, opt := range opts { - opt(&cfg.verifierCfg) - } - } -} - func setupSequencerTest(t Testing, sd *e2eutils.SetupData, log log.Logger, opts ...SequencerOpt) (*L1Miner, *L2Engine, *L2Sequencer) { jwtPath := e2eutils.WriteDefaultJWT(t) - cfg := defaultSequencerConfig() + cfg := DefaultSequencerConfig() for _, opt := range opts { opt(cfg) } @@ -70,7 +32,7 @@ func setupSequencerTest(t Testing, sd *e2eutils.SetupData, log log.Logger, opts l2Cl, err := sources.NewEngineClient(engine.RPCClient(), log, nil, sources.EngineClientDefaultConfig(sd.RollupCfg)) require.NoError(t, err) - sequencer := NewL2Sequencer(t, log.New("role", "sequencer"), l1F, miner.BlobStore(), altda.Disabled, l2Cl, sd.RollupCfg, 0, cfg.interopBackend) + sequencer := NewL2Sequencer(t, log.New("role", "sequencer"), l1F, miner.BlobStore(), altda.Disabled, l2Cl, sd.RollupCfg, 0, cfg.InteropBackend) return miner, engine, sequencer } @@ -83,7 +45,7 @@ func TestL2Sequencer_SequencerDrift(gt *testing.T) { L1BlockTime: 12, } dp := e2eutils.MakeDeployParams(t, p) - sd := e2eutils.Setup(t, dp, defaultAlloc) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LevelDebug) miner, engine, sequencer := setupSequencerTest(t, sd, log) miner.ActL1SetFeeRecipient(common.Address{'A'}) @@ -150,8 +112,8 @@ func TestL2Sequencer_SequencerDrift(gt *testing.T) { // while the verifier-codepath only ever sees the valid post-reorg L1 chain. func TestL2Sequencer_SequencerOnlyReorg(gt *testing.T) { t := NewDefaultTesting(gt) - dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams) - sd := e2eutils.Setup(t, dp, defaultAlloc) + dp := e2eutils.MakeDeployParams(t, DefaultRollupTestParams) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LevelDebug) miner, _, sequencer := setupSequencerTest(t, sd, log) diff --git a/op-e2e/actions/l2_verifier_test.go b/op-e2e/actions/l2_verifier_test.go index f8f751ca6b7a..75c1efbc176c 100644 --- a/op-e2e/actions/l2_verifier_test.go +++ b/op-e2e/actions/l2_verifier_test.go @@ -9,48 +9,21 @@ import ( altda "github.com/ethereum-optimism/optimism/op-alt-da" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils" - "github.com/ethereum-optimism/optimism/op-node/node/safedb" "github.com/ethereum-optimism/optimism/op-node/rollup/derive" - "github.com/ethereum-optimism/optimism/op-node/rollup/interop" "github.com/ethereum-optimism/optimism/op-node/rollup/sync" "github.com/ethereum-optimism/optimism/op-service/testlog" ) -type verifierCfg struct { - safeHeadListener safeDB - interopBackend interop.InteropBackend -} - -type VerifierOpt func(opts *verifierCfg) - -func WithSafeHeadListener(l safeDB) VerifierOpt { - return func(opts *verifierCfg) { - opts.safeHeadListener = l - } -} - -func WithInteropBackend(b interop.InteropBackend) VerifierOpt { - return func(opts *verifierCfg) { - opts.interopBackend = b - } -} - -func defaultVerifierCfg() *verifierCfg { - return &verifierCfg{ - safeHeadListener: safedb.Disabled, - } -} - func setupVerifier(t Testing, sd *e2eutils.SetupData, log log.Logger, l1F derive.L1Fetcher, blobSrc derive.L1BlobsFetcher, syncCfg *sync.Config, opts ...VerifierOpt) (*L2Engine, *L2Verifier) { - cfg := defaultVerifierCfg() + cfg := DefaultVerifierCfg() for _, opt := range opts { opt(cfg) } jwtPath := e2eutils.WriteDefaultJWT(t) engine := NewL2Engine(t, log.New("role", "verifier-engine"), sd.L2Cfg, sd.RollupCfg.Genesis.L1, 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, cfg.interopBackend) + verifier := NewL2Verifier(t, log.New("role", "verifier"), l1F, blobSrc, altda.Disabled, engCl, sd.RollupCfg, syncCfg, cfg.SafeHeadListener, cfg.InteropBackend) return engine, verifier } @@ -70,7 +43,7 @@ func TestL2Verifier_SequenceWindow(gt *testing.T) { L1BlockTime: 15, } dp := e2eutils.MakeDeployParams(t, p) - sd := e2eutils.Setup(t, dp, defaultAlloc) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LevelDebug) miner, engine, verifier := setupVerifierOnlyTest(t, sd, log) miner.ActL1SetFeeRecipient(common.Address{'A'}) diff --git a/op-e2e/actions/proofs/env.go b/op-e2e/actions/proofs/env.go new file mode 100644 index 000000000000..020e158c684a --- /dev/null +++ b/op-e2e/actions/proofs/env.go @@ -0,0 +1,181 @@ +package proofs + +import ( + "math/rand" + "testing" + + altda "github.com/ethereum-optimism/optimism/op-alt-da" + batcherFlags "github.com/ethereum-optimism/optimism/op-batcher/flags" + "github.com/ethereum-optimism/optimism/op-e2e/actions" + "github.com/ethereum-optimism/optimism/op-e2e/e2eutils" + "github.com/ethereum-optimism/optimism/op-program/host" + "github.com/ethereum-optimism/optimism/op-program/host/config" + "github.com/ethereum-optimism/optimism/op-service/sources" + "github.com/ethereum-optimism/optimism/op-service/testlog" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/log" + "github.com/stretchr/testify/require" +) + +// L2FaultProofEnv is a test harness for a fault provable L2 chain. +type L2FaultProofEnv struct { + log log.Logger + batcher *actions.L2Batcher + sequencer *actions.L2Sequencer + engine *actions.L2Engine + engCl *sources.EngineClient + sd *e2eutils.SetupData + dp *e2eutils.DeployParams + miner *actions.L1Miner + alice *actions.CrossLayerUser +} + +func NewL2FaultProofEnv(t actions.Testing, tp *e2eutils.TestParams, dp *e2eutils.DeployParams, batcherCfg *actions.BatcherCfg) *L2FaultProofEnv { + log := testlog.Logger(t, log.LvlDebug) + sd := e2eutils.Setup(t, dp, actions.DefaultAlloc) + + jwtPath := e2eutils.WriteDefaultJWT(t) + cfg := &actions.SequencerCfg{VerifierCfg: *actions.DefaultVerifierCfg()} + + miner := actions.NewL1Miner(t, log.New("role", "l1-miner"), sd.L1Cfg) + + l1F, err := sources.NewL1Client(miner.RPCClient(), log, nil, sources.L1ClientDefaultConfig(sd.RollupCfg, false, sources.RPCKindStandard)) + require.NoError(t, err) + engine := actions.NewL2Engine(t, log.New("role", "sequencer-engine"), sd.L2Cfg, sd.RollupCfg.Genesis.L1, jwtPath, actions.EngineWithP2P()) + l2Cl, err := sources.NewEngineClient(engine.RPCClient(), log, nil, sources.EngineClientDefaultConfig(sd.RollupCfg)) + require.NoError(t, err) + + sequencer := actions.NewL2Sequencer(t, log.New("role", "sequencer"), l1F, miner.BlobStore(), altda.Disabled, l2Cl, sd.RollupCfg, 0, cfg.InteropBackend) + miner.ActL1SetFeeRecipient(common.Address{0xCA, 0xFE, 0xBA, 0xBE}) + sequencer.ActL2PipelineFull(t) + engCl := engine.EngineClient(t, sd.RollupCfg) + + // Set the batcher key to the secret key of the batcher + batcherCfg.BatcherKey = dp.Secrets.Batcher + batcher := actions.NewL2Batcher(log, sd.RollupCfg, batcherCfg, sequencer.RollupClient(), miner.EthClient(), engine.EthClient(), engCl) + + addresses := e2eutils.CollectAddresses(sd, dp) + cl := engine.EthClient() + l2UserEnv := &actions.BasicUserEnv[*actions.L2Bindings]{ + EthCl: cl, + Signer: types.LatestSigner(sd.L2Cfg.Config), + AddressCorpora: addresses, + Bindings: actions.NewL2Bindings(t, cl, engine.GethClient()), + } + alice := actions.NewCrossLayerUser(log, dp.Secrets.Alice, rand.New(rand.NewSource(0xa57b))) + alice.L2.SetUserEnv(l2UserEnv) + + return &L2FaultProofEnv{ + log: log, + batcher: batcher, + sequencer: sequencer, + engine: engine, + engCl: engCl, + sd: sd, + dp: dp, + miner: miner, + alice: alice, + } +} + +type TestParam func(p *e2eutils.TestParams) + +func NewTestParams(params ...TestParam) *e2eutils.TestParams { + dfault := actions.DefaultRollupTestParams + for _, apply := range params { + apply(dfault) + } + return dfault +} + +type DeployParam func(p *e2eutils.DeployParams) + +func NewDeployParams(t actions.Testing, params ...DeployParam) *e2eutils.DeployParams { + dfault := e2eutils.MakeDeployParams(t, NewTestParams()) + for _, apply := range params { + apply(dfault) + } + return dfault +} + +type BatcherCfgParam func(c *actions.BatcherCfg) + +func NewBatcherCfg(params ...BatcherCfgParam) *actions.BatcherCfg { + dfault := &actions.BatcherCfg{ + MinL1TxSize: 0, + MaxL1TxSize: 128_000, + DataAvailabilityType: batcherFlags.BlobsType, + } + for _, apply := range params { + apply(dfault) + } + return dfault +} + +type OpProgramCfgParam func(p *config.Config) + +func NewOpProgramCfg( + t actions.Testing, + env *L2FaultProofEnv, + fi *FixtureInputs, + params ...OpProgramCfgParam, +) *config.Config { + t.Helper() + + dfault := config.NewConfig(env.sd.RollupCfg, env.sd.L2Cfg.Config, fi.L1Head, fi.L2Head, fi.L2OutputRoot, fi.L2Claim, fi.L2BlockNumber) + + // Set up in-process L1 sources + dfault.L1ProcessSource = env.miner.L1Client(t, env.sd.RollupCfg) + dfault.L1BeaconProcessSource = env.miner.BlobStore() + + // Set up in-process L2 source + l2ClCfg := sources.L2ClientDefaultConfig(env.sd.RollupCfg, true) + l2RPC := env.engine.RPCClient() + l2Client, err := host.NewL2Client(l2RPC, env.log, nil, &host.L2ClientConfig{L2ClientConfig: l2ClCfg, L2Head: fi.L2Head}) + require.NoError(t, err, "failed to create L2 client") + l2DebugCl := &host.L2Source{L2Client: l2Client, DebugClient: sources.NewDebugClient(l2RPC.CallContext)} + dfault.L2ProcessSource = l2DebugCl + + if dumpFixtures { + dfault.DataDir = t.TempDir() + } + + for _, apply := range params { + apply(dfault) + } + return dfault +} + +type FixtureInputParam func(f *FixtureInputs) + +func RunFaultProofProgram(t actions.Testing, gt *testing.T, env *L2FaultProofEnv, l2ClaimBlockNum uint64, fixtureInputParams ...FixtureInputParam) error { + // Fetch the pre and post output roots for the fault proof. + preRoot, err := env.sequencer.RollupClient().OutputAtBlock(t.Ctx(), l2ClaimBlockNum-1) + require.NoError(t, err) + claimRoot, err := env.sequencer.RollupClient().OutputAtBlock(t.Ctx(), l2ClaimBlockNum) + require.NoError(t, err) + l1Head := env.miner.L1Chain().CurrentBlock() + + fixtureInputs := &FixtureInputs{ + L2BlockNumber: l2ClaimBlockNum, + L2Claim: common.Hash(claimRoot.OutputRoot), + L2Head: preRoot.BlockRef.Hash, + L2OutputRoot: common.Hash(preRoot.OutputRoot), + L2ChainID: env.sd.RollupCfg.L2ChainID.Uint64(), + L1Head: l1Head.Hash(), + } + for _, apply := range fixtureInputParams { + apply(fixtureInputs) + } + + // Run the fault proof program from the state transition from L2 block 0 -> 1. + programCfg := NewOpProgramCfg( + t, + env, + fixtureInputs, + ) + err = host.FaultProofProgram(t.Ctx(), env.log, programCfg) + tryDumpTestFixture(gt, err, t.Name(), env, programCfg) + return err +} diff --git a/op-e2e/actions/proofs/fixture.go b/op-e2e/actions/proofs/fixture.go new file mode 100644 index 000000000000..7f988e6a0634 --- /dev/null +++ b/op-e2e/actions/proofs/fixture.go @@ -0,0 +1,119 @@ +package proofs + +import ( + "encoding/json" + "errors" + "io/fs" + "os" + "os/exec" + "path/filepath" + "testing" + + "github.com/ethereum-optimism/optimism/op-program/host/config" + "github.com/ethereum-optimism/optimism/op-program/client/claim" + "github.com/ethereum/go-ethereum/common" + "github.com/naoina/toml" + "github.com/stretchr/testify/require" +) + +var ( + dumpFixtures = false + fixtureDir string +) + +func init() { + if os.Getenv("OP_E2E_DUMP_FIXTURES") == "1" { + dumpFixtures = true + } + fixtureDir = os.Getenv("OP_E2E_FPP_FIXTURE_DIR") +} + +type TestFixture struct { + Name string `toml:"name"` + ExpectedStatus uint8 `toml:"expected-status"` + Inputs FixtureInputs `toml:"inputs"` +} + +type FixtureInputs struct { + L2BlockNumber uint64 `toml:"l2-block-number"` + L2Claim common.Hash `toml:"l2-claim"` + L2Head common.Hash `toml:"l2-head"` + L2OutputRoot common.Hash `toml:"l2-output-root"` + L2ChainID uint64 `toml:"l2-chain-id"` + L1Head common.Hash `toml:"l1-head"` +} + +// Dumps a `fp-tests` test fixture to disk if the `OP_E2E_DUMP_FIXTURES` environment variable is set. +// +// [fp-tests]: https://github.com/ethereum-optimism/fp-tests +func tryDumpTestFixture(t *testing.T, result error, name string, env *L2FaultProofEnv, programCfg *config.Config) { + if !dumpFixtures { + return + } + + rollupCfg := env.sd.RollupCfg + l2Genesis := env.sd.L2Cfg + + var expectedStatus uint8 + if result == nil { + expectedStatus = 0 + } else if errors.Is(result, claim.ErrClaimNotValid) { + expectedStatus = 1 + } else { + expectedStatus = 2 + } + + fixture := TestFixture{ + Name: name, + ExpectedStatus: expectedStatus, + Inputs: FixtureInputs{ + L2BlockNumber: programCfg.L2ClaimBlockNumber, + L2Claim: programCfg.L2Claim, + L2Head: programCfg.L2Head, + L2OutputRoot: programCfg.L2OutputRoot, + L2ChainID: env.sd.RollupCfg.L2ChainID.Uint64(), + L1Head: programCfg.L1Head, + }, + } + + fixturePath := filepath.Join(fixtureDir, name) + + err := os.MkdirAll(filepath.Join(fixturePath), fs.ModePerm) + require.NoError(t, err, "failed to create fixture dir") + + fixtureFilePath := filepath.Join(fixturePath, "fixture.toml") + serFixture, err := toml.Marshal(fixture) + require.NoError(t, err, "failed to serialize fixture") + require.NoError(t, os.WriteFile(fixtureFilePath, serFixture, fs.ModePerm), "failed to write fixture") + + genesisPath := filepath.Join(fixturePath, "genesis.json") + serGenesis, err := l2Genesis.MarshalJSON() + require.NoError(t, err, "failed to serialize genesis") + require.NoError(t, os.WriteFile(genesisPath, serGenesis, fs.ModePerm), "failed to write genesis") + + rollupPath := filepath.Join(fixturePath, "rollup.json") + serRollup, err := json.Marshal(rollupCfg) + require.NoError(t, err, "failed to serialize rollup") + require.NoError(t, os.WriteFile(rollupPath, serRollup, fs.ModePerm), "failed to write rollup") + + // Copy the witness database into the fixture directory. + cmd := exec.Command("cp", "-r", programCfg.DataDir, filepath.Join(fixturePath, "witness-db")) + require.NoError(t, cmd.Run(), "Failed to copy witness DB") + + // Compress the genesis file. + cmd = exec.Command("zstd", genesisPath) + _ = cmd.Run() + require.NoError(t, os.Remove(genesisPath), "Failed to remove uncompressed genesis file") + + // Compress the witness database. + cmd = exec.Command( + "tar", + "--zstd", + "-cf", + filepath.Join(fixturePath, "witness-db.tar.zst"), + filepath.Join(fixturePath, "witness-db"), + ) + cmd.Dir = filepath.Join(fixturePath) + require.NoError(t, cmd.Run(), "Failed to compress witness DB") + require.NoError(t, os.RemoveAll(filepath.Join(fixturePath, "witness-db")), "Failed to remove uncompressed witness DB") +} diff --git a/op-e2e/actions/proofs/simple_program_test.go b/op-e2e/actions/proofs/simple_program_test.go new file mode 100644 index 000000000000..900184bb3af8 --- /dev/null +++ b/op-e2e/actions/proofs/simple_program_test.go @@ -0,0 +1,109 @@ +package proofs + +import ( + "testing" + + "github.com/ethereum-optimism/optimism/op-e2e/actions" + "github.com/ethereum-optimism/optimism/op-e2e/e2eutils" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/stretchr/testify/require" +) + +func Test_ProgramAction_SimpleEmptyChain_HonestClaim_Granite(gt *testing.T) { + t := actions.NewDefaultTesting(gt) + tp := NewTestParams() + dp := NewDeployParams(t, func(dp *e2eutils.DeployParams) { + genesisBlock := hexutil.Uint64(0) + + // Enable Cancun on L1 & Granite on L2 at genesis + dp.DeployConfig.L1CancunTimeOffset = &genesisBlock + dp.DeployConfig.L2GenesisRegolithTimeOffset = &genesisBlock + dp.DeployConfig.L2GenesisCanyonTimeOffset = &genesisBlock + dp.DeployConfig.L2GenesisDeltaTimeOffset = &genesisBlock + dp.DeployConfig.L2GenesisEcotoneTimeOffset = &genesisBlock + dp.DeployConfig.L2GenesisFjordTimeOffset = &genesisBlock + dp.DeployConfig.L2GenesisGraniteTimeOffset = &genesisBlock + }) + bCfg := NewBatcherCfg() + env := NewL2FaultProofEnv(t, tp, dp, bCfg) + + // Build an empty block on L2 + env.sequencer.ActL2StartBlock(t) + env.sequencer.ActL2EndBlock(t) + + // Instruct the batcher to submit the block to L1, and include the transaction. + env.batcher.ActSubmitAll(t) + env.miner.ActL1StartBlock(12)(t) + env.miner.ActL1IncludeTxByHash(env.batcher.LastSubmitted.Hash())(t) + env.miner.ActL1EndBlock(t) + + // Finalize the block with the batch on L1. + env.miner.ActL1SafeNext(t) + env.miner.ActL1FinalizeNext(t) + + // Instruct the sequencer to derive the L2 chain from the data on L1 that the batcher just posted. + env.sequencer.ActL1HeadSignal(t) + env.sequencer.ActL2PipelineFull(t) + + l1Head := env.miner.L1Chain().CurrentBlock() + l2SafeHead := env.engine.L2Chain().CurrentSafeBlock() + + // Ensure there is only 1 block on L1. + require.Equal(t, uint64(1), l1Head.Number.Uint64()) + // Ensure the block is marked as safe before we attempt to fault prove it. + require.Equal(t, uint64(1), l2SafeHead.Number.Uint64()) + + err := RunFaultProofProgram(t, gt, env, l2SafeHead.Number.Uint64()) + require.NoError(t, err, "fault proof program failed") +} + +func Test_ProgramAction_SimpleEmptyChain_JunkClaim_Granite(gt *testing.T) { + t := actions.NewDefaultTesting(gt) + tp := NewTestParams() + dp := NewDeployParams(t, func(dp *e2eutils.DeployParams) { + genesisBlock := hexutil.Uint64(0) + + // Enable Cancun on L1 & Granite on L2 at genesis + dp.DeployConfig.L1CancunTimeOffset = &genesisBlock + dp.DeployConfig.L2GenesisRegolithTimeOffset = &genesisBlock + dp.DeployConfig.L2GenesisCanyonTimeOffset = &genesisBlock + dp.DeployConfig.L2GenesisDeltaTimeOffset = &genesisBlock + dp.DeployConfig.L2GenesisEcotoneTimeOffset = &genesisBlock + dp.DeployConfig.L2GenesisFjordTimeOffset = &genesisBlock + dp.DeployConfig.L2GenesisGraniteTimeOffset = &genesisBlock + }) + bCfg := NewBatcherCfg() + env := NewL2FaultProofEnv(t, tp, dp, bCfg) + + // Build an empty block on L2 + env.sequencer.ActL2StartBlock(t) + env.sequencer.ActL2EndBlock(t) + + // Instruct the batcher to submit the block to L1, and include the transaction. + env.batcher.ActSubmitAll(t) + env.miner.ActL1StartBlock(12)(t) + env.miner.ActL1IncludeTxByHash(env.batcher.LastSubmitted.Hash())(t) + env.miner.ActL1EndBlock(t) + + // Finalize the block with the batch on L1. + env.miner.ActL1SafeNext(t) + env.miner.ActL1FinalizeNext(t) + + // Instruct the sequencer to derive the L2 chain from the data on L1 that the batcher just posted. + env.sequencer.ActL1HeadSignal(t) + env.sequencer.ActL2PipelineFull(t) + + l1Head := env.miner.L1Chain().CurrentBlock() + l2SafeHead := env.engine.L2Chain().CurrentSafeBlock() + + // Ensure there is only 1 block on L1. + require.Equal(t, uint64(1), l1Head.Number.Uint64()) + // Ensure the block is marked as safe before we attempt to fault prove it. + require.Equal(t, uint64(1), l2SafeHead.Number.Uint64()) + + err := RunFaultProofProgram(t, gt, env, l2SafeHead.Number.Uint64(), func(f *FixtureInputs) { + f.L2Claim = common.HexToHash("0xdeadbeef") + }) + require.Error(t, err, "fault proof program should have failed") +} diff --git a/op-e2e/actions/reorg_test.go b/op-e2e/actions/reorg_test.go index 271b69cb1b29..1ffd512d328f 100644 --- a/op-e2e/actions/reorg_test.go +++ b/op-e2e/actions/reorg_test.go @@ -27,7 +27,7 @@ func setupReorgTest(t Testing, config *e2eutils.TestParams, deltaTimeOffset *hex dp := e2eutils.MakeDeployParams(t, config) applyDeltaTimeOffset(dp, deltaTimeOffset) - sd := e2eutils.Setup(t, dp, defaultAlloc) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LevelDebug) return setupReorgTestActors(t, dp, sd, log) @@ -75,7 +75,7 @@ func TestReorgBatchType(t *testing.T) { func ReorgOrphanBlock(gt *testing.T, deltaTimeOffset *hexutil.Uint64) { t := NewDefaultTesting(gt) - sd, _, miner, sequencer, _, verifier, verifierEng, batcher := setupReorgTest(t, defaultRollupTestParams, deltaTimeOffset) + sd, _, miner, sequencer, _, verifier, verifierEng, batcher := setupReorgTest(t, DefaultRollupTestParams, deltaTimeOffset) verifEngClient := verifierEng.EngineClient(t, sd.RollupCfg) sequencer.ActL2PipelineFull(t) @@ -143,7 +143,7 @@ func ReorgOrphanBlock(gt *testing.T, deltaTimeOffset *hexutil.Uint64) { func ReorgFlipFlop(gt *testing.T, deltaTimeOffset *hexutil.Uint64) { t := NewDefaultTesting(gt) - sd, _, miner, sequencer, _, verifier, verifierEng, batcher := setupReorgTest(t, defaultRollupTestParams, deltaTimeOffset) + sd, _, miner, sequencer, _, verifier, verifierEng, batcher := setupReorgTest(t, DefaultRollupTestParams, deltaTimeOffset) minerCl := miner.L1Client(t, sd.RollupCfg) verifEngClient := verifierEng.EngineClient(t, sd.RollupCfg) checkVerifEngine := func() { @@ -599,9 +599,9 @@ func RestartOpGeth(gt *testing.T, deltaTimeOffset *hexutil.Uint64) { nodeCfg.DataDir = dbPath return nil } - dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams) + dp := e2eutils.MakeDeployParams(t, DefaultRollupTestParams) applyDeltaTimeOffset(dp, deltaTimeOffset) - sd := e2eutils.Setup(t, dp, defaultAlloc) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LevelDebug) jwtPath := e2eutils.WriteDefaultJWT(t) // L1 @@ -687,9 +687,9 @@ func RestartOpGeth(gt *testing.T, deltaTimeOffset *hexutil.Uint64) { // the alt block is not synced by the verifier, in unsafe and safe sync modes. func ConflictingL2Blocks(gt *testing.T, deltaTimeOffset *hexutil.Uint64) { t := NewDefaultTesting(gt) - dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams) + dp := e2eutils.MakeDeployParams(t, DefaultRollupTestParams) applyDeltaTimeOffset(dp, deltaTimeOffset) - sd := e2eutils.Setup(t, dp, defaultAlloc) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LevelDebug) sd, _, miner, sequencer, seqEng, verifier, _, batcher := setupReorgTestActors(t, dp, sd, log) diff --git a/op-e2e/actions/safedb_test.go b/op-e2e/actions/safedb_test.go index 9fd570fa79f5..d7baeeb3715c 100644 --- a/op-e2e/actions/safedb_test.go +++ b/op-e2e/actions/safedb_test.go @@ -17,7 +17,7 @@ import ( func TestRecordSafeHeadUpdates(gt *testing.T) { t := NewDefaultTesting(gt) - sd, miner, sequencer, verifier, verifierEng, batcher := setupSafeDBTest(t, defaultRollupTestParams) + sd, miner, sequencer, verifier, verifierEng, batcher := setupSafeDBTest(t, DefaultRollupTestParams) verifEngClient := verifierEng.EngineClient(t, sd.RollupCfg) sequencer.ActL2PipelineFull(t) @@ -116,7 +116,7 @@ func TestRecordSafeHeadUpdates(gt *testing.T) { func setupSafeDBTest(t Testing, config *e2eutils.TestParams) (*e2eutils.SetupData, *L1Miner, *L2Sequencer, *L2Verifier, *L2Engine, *L2Batcher) { dp := e2eutils.MakeDeployParams(t, config) - sd := e2eutils.Setup(t, dp, defaultAlloc) + sd := e2eutils.Setup(t, dp, DefaultAlloc) logger := testlog.Logger(t, log.LevelDebug) return setupSafeDBTestActors(t, dp, sd, logger) diff --git a/op-e2e/actions/span_batch_test.go b/op-e2e/actions/span_batch_test.go index 23f5963fa97a..7eb551c521c7 100644 --- a/op-e2e/actions/span_batch_test.go +++ b/op-e2e/actions/span_batch_test.go @@ -41,7 +41,7 @@ func TestDropSpanBatchBeforeHardfork(gt *testing.T) { dp := e2eutils.MakeDeployParams(t, p) // do not activate Delta hardfork for verifier applyDeltaTimeOffset(dp, nil) - sd := e2eutils.Setup(t, dp, defaultAlloc) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LevelError) miner, seqEngine, sequencer := setupSequencerTest(t, sd, log) verifEngine, verifier := setupVerifier(t, sd, log, miner.L1Client(t, sd.RollupCfg), miner.BlobStore(), &sync.Config{}) @@ -137,7 +137,7 @@ func TestHardforkMiddleOfSpanBatch(gt *testing.T) { dp.DeployConfig.L2GenesisFjordTimeOffset = nil dp.DeployConfig.L2GenesisGraniteTimeOffset = nil - sd := e2eutils.Setup(t, dp, defaultAlloc) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LevelError) miner, seqEngine, sequencer := setupSequencerTest(t, sd, log) verifEngine, verifier := setupVerifier(t, sd, log, miner.L1Client(t, sd.RollupCfg), miner.BlobStore(), &sync.Config{}) @@ -245,7 +245,7 @@ func TestAcceptSingularBatchAfterHardfork(gt *testing.T) { // activate Delta hardfork for verifier. applyDeltaTimeOffset(dp, &minTs) - sd := e2eutils.Setup(t, dp, defaultAlloc) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LevelError) miner, seqEngine, sequencer := setupSequencerTest(t, sd, log) verifEngine, verifier := setupVerifier(t, sd, log, miner.L1Client(t, sd.RollupCfg), miner.BlobStore(), &sync.Config{}) @@ -331,7 +331,7 @@ func TestMixOfBatchesAfterHardfork(gt *testing.T) { // Activate Delta hardfork for verifier. applyDeltaTimeOffset(dp, &minTs) - sd := e2eutils.Setup(t, dp, defaultAlloc) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LevelError) miner, seqEngine, sequencer := setupSequencerTest(t, sd, log) verifEngine, verifier := setupVerifier(t, sd, log, miner.L1Client(t, sd.RollupCfg), miner.BlobStore(), &sync.Config{}) @@ -421,7 +421,7 @@ func TestSpanBatchEmptyChain(gt *testing.T) { minTs := hexutil.Uint64(0) // Activate Delta hardfork applyDeltaTimeOffset(dp, &minTs) - sd := e2eutils.Setup(t, dp, defaultAlloc) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LevelError) miner, seqEngine, sequencer := setupSequencerTest(t, sd, log) _, verifier := setupVerifier(t, sd, log, miner.L1Client(t, sd.RollupCfg), miner.BlobStore(), &sync.Config{}) @@ -484,7 +484,7 @@ func TestSpanBatchLowThroughputChain(gt *testing.T) { minTs := hexutil.Uint64(0) // Activate Delta hardfork applyDeltaTimeOffset(dp, &minTs) - sd := e2eutils.Setup(t, dp, defaultAlloc) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LevelError) miner, seqEngine, sequencer := setupSequencerTest(t, sd, log) _, verifier := setupVerifier(t, sd, log, miner.L1Client(t, sd.RollupCfg), miner.BlobStore(), &sync.Config{}) @@ -598,7 +598,7 @@ func TestBatchEquivalence(gt *testing.T) { dp := e2eutils.MakeDeployParams(t, p) minTs := hexutil.Uint64(0) applyDeltaTimeOffset(dp, &minTs) - sdDeltaActivated := e2eutils.Setup(t, dp, defaultAlloc) + sdDeltaActivated := e2eutils.Setup(t, dp, DefaultAlloc) // Delta deactivated deploy config rcfg := *sdDeltaActivated.RollupCfg diff --git a/op-e2e/actions/sync_test.go b/op-e2e/actions/sync_test.go index 5f78739631cc..d2b34b1f06fa 100644 --- a/op-e2e/actions/sync_test.go +++ b/op-e2e/actions/sync_test.go @@ -65,9 +65,9 @@ func TestSyncBatchType(t *testing.T) { func DerivationWithFlakyL1RPC(gt *testing.T, deltaTimeOffset *hexutil.Uint64) { t := NewDefaultTesting(gt) - dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams) + dp := e2eutils.MakeDeployParams(t, DefaultRollupTestParams) applyDeltaTimeOffset(dp, deltaTimeOffset) - sd := e2eutils.Setup(t, dp, defaultAlloc) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LevelError) // mute all the temporary derivation errors that we forcefully create _, _, miner, sequencer, _, verifier, _, batcher := setupReorgTestActors(t, dp, sd, log) @@ -105,9 +105,9 @@ func DerivationWithFlakyL1RPC(gt *testing.T, deltaTimeOffset *hexutil.Uint64) { func FinalizeWhileSyncing(gt *testing.T, deltaTimeOffset *hexutil.Uint64) { t := NewDefaultTesting(gt) - dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams) + dp := e2eutils.MakeDeployParams(t, DefaultRollupTestParams) applyDeltaTimeOffset(dp, deltaTimeOffset) - sd := e2eutils.Setup(t, dp, defaultAlloc) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LevelError) // mute all the temporary derivation errors that we forcefully create _, _, miner, sequencer, _, verifier, _, batcher := setupReorgTestActors(t, dp, sd, log) @@ -151,8 +151,8 @@ func FinalizeWhileSyncing(gt *testing.T, deltaTimeOffset *hexutil.Uint64) { // TestUnsafeSync tests that a verifier properly imports unsafe blocks via gossip. func TestUnsafeSync(gt *testing.T) { t := NewDefaultTesting(gt) - dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams) - sd := e2eutils.Setup(t, dp, defaultAlloc) + dp := e2eutils.MakeDeployParams(t, DefaultRollupTestParams) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LevelInfo) sd, _, _, sequencer, seqEng, verifier, _, _ := setupReorgTestActors(t, dp, sd, log) @@ -179,12 +179,12 @@ func TestUnsafeSync(gt *testing.T) { func TestBackupUnsafe(gt *testing.T) { t := NewDefaultTesting(gt) - dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams) + dp := e2eutils.MakeDeployParams(t, DefaultRollupTestParams) minTs := hexutil.Uint64(0) // Activate Delta hardfork applyDeltaTimeOffset(dp, &minTs) dp.DeployConfig.L2BlockTime = 2 - sd := e2eutils.Setup(t, dp, defaultAlloc) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LvlInfo) _, dp, miner, sequencer, seqEng, verifier, _, batcher := setupReorgTestActors(t, dp, sd, log) l2Cl := seqEng.EthClient() @@ -340,12 +340,12 @@ func TestBackupUnsafe(gt *testing.T) { func TestBackupUnsafeReorgForkChoiceInputError(gt *testing.T) { t := NewDefaultTesting(gt) - dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams) + dp := e2eutils.MakeDeployParams(t, DefaultRollupTestParams) minTs := hexutil.Uint64(0) // Activate Delta hardfork applyDeltaTimeOffset(dp, &minTs) dp.DeployConfig.L2BlockTime = 2 - sd := e2eutils.Setup(t, dp, defaultAlloc) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LvlInfo) _, dp, miner, sequencer, seqEng, verifier, _, batcher := setupReorgTestActors(t, dp, sd, log) l2Cl := seqEng.EthClient() @@ -473,12 +473,12 @@ func TestBackupUnsafeReorgForkChoiceInputError(gt *testing.T) { func TestBackupUnsafeReorgForkChoiceNotInputError(gt *testing.T) { t := NewDefaultTesting(gt) - dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams) + dp := e2eutils.MakeDeployParams(t, DefaultRollupTestParams) minTs := hexutil.Uint64(0) // Activate Delta hardfork applyDeltaTimeOffset(dp, &minTs) dp.DeployConfig.L2BlockTime = 2 - sd := e2eutils.Setup(t, dp, defaultAlloc) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LvlInfo) _, dp, miner, sequencer, seqEng, verifier, _, batcher := setupReorgTestActors(t, dp, sd, log) l2Cl := seqEng.EthClient() @@ -692,8 +692,8 @@ func BatchSubmitBlock(t Testing, miner *L1Miner, sequencer *L2Sequencer, verifie // when passed a single unsafe block. op-geth can either snap sync or full sync here. func TestELSync(gt *testing.T) { t := NewDefaultTesting(gt) - dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams) - sd := e2eutils.Setup(t, dp, defaultAlloc) + dp := e2eutils.MakeDeployParams(t, DefaultRollupTestParams) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LevelInfo) miner, seqEng, sequencer := setupSequencerTest(t, sd, log) @@ -745,8 +745,8 @@ func PrepareELSyncedNode(t Testing, miner *L1Miner, sequencer *L2Sequencer, seqE // 8. Create 1 more block & batch submit everything & assert that the verifier picked up those blocks func TestELSyncTransitionstoCL(gt *testing.T) { t := NewDefaultTesting(gt) - dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams) - sd := e2eutils.Setup(t, dp, defaultAlloc) + dp := e2eutils.MakeDeployParams(t, DefaultRollupTestParams) + sd := e2eutils.Setup(t, dp, DefaultAlloc) logger := testlog.Logger(t, log.LevelInfo) captureLog, captureLogHandler := testlog.CaptureLogger(t, log.LevelInfo) @@ -802,8 +802,8 @@ func TestELSyncTransitionstoCL(gt *testing.T) { func TestELSyncTransitionsToCLSyncAfterNodeRestart(gt *testing.T) { t := NewDefaultTesting(gt) - dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams) - sd := e2eutils.Setup(t, dp, defaultAlloc) + dp := e2eutils.MakeDeployParams(t, DefaultRollupTestParams) + sd := e2eutils.Setup(t, dp, DefaultAlloc) logger := testlog.Logger(t, log.LevelInfo) captureLog, captureLogHandler := testlog.CaptureLogger(t, log.LevelInfo) @@ -819,7 +819,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 = NewL2Verifier(t, captureLog, miner.L1Client(t, sd.RollupCfg), miner.BlobStore(), altda.Disabled, verifier.eng, sd.RollupCfg, &sync.Config{SyncMode: sync.ELSync}, defaultVerifierCfg().safeHeadListener, nil) + verifier = NewL2Verifier(t, captureLog, miner.L1Client(t, sd.RollupCfg), miner.BlobStore(), altda.Disabled, verifier.eng, sd.RollupCfg, &sync.Config{SyncMode: sync.ELSync}, DefaultVerifierCfg().SafeHeadListener, nil) // Build another 10 L1 blocks on the sequencer for i := 0; i < 10; i++ { @@ -844,8 +844,8 @@ func TestELSyncTransitionsToCLSyncAfterNodeRestart(gt *testing.T) { func TestForcedELSyncCLAfterNodeRestart(gt *testing.T) { t := NewDefaultTesting(gt) - dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams) - sd := e2eutils.Setup(t, dp, defaultAlloc) + dp := e2eutils.MakeDeployParams(t, DefaultRollupTestParams) + sd := e2eutils.Setup(t, dp, DefaultAlloc) logger := testlog.Logger(t, log.LevelInfo) captureLog, captureLogHandler := testlog.CaptureLogger(t, log.LevelInfo) @@ -861,7 +861,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 := NewL2Verifier(t, captureLog, miner.L1Client(t, sd.RollupCfg), miner.BlobStore(), altda.Disabled, verifier.eng, sd.RollupCfg, &sync.Config{SyncMode: sync.ELSync, SupportsPostFinalizationELSync: true}, defaultVerifierCfg().safeHeadListener, nil) + verifier2 := NewL2Verifier(t, captureLog, miner.L1Client(t, sd.RollupCfg), miner.BlobStore(), altda.Disabled, verifier.eng, sd.RollupCfg, &sync.Config{SyncMode: sync.ELSync, SupportsPostFinalizationELSync: true}, DefaultVerifierCfg().SafeHeadListener, nil) // Build another 10 L1 blocks on the sequencer for i := 0; i < 10; i++ { @@ -890,12 +890,12 @@ func TestForcedELSyncCLAfterNodeRestart(gt *testing.T) { func TestInvalidPayloadInSpanBatch(gt *testing.T) { t := NewDefaultTesting(gt) - dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams) + dp := e2eutils.MakeDeployParams(t, DefaultRollupTestParams) minTs := hexutil.Uint64(0) // Activate Delta hardfork applyDeltaTimeOffset(dp, &minTs) dp.DeployConfig.L2BlockTime = 2 - sd := e2eutils.Setup(t, dp, defaultAlloc) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LevelInfo) _, _, miner, sequencer, seqEng, verifier, _, batcher := setupReorgTestActors(t, dp, sd, log) l2Cl := seqEng.EthClient() @@ -995,12 +995,12 @@ func TestInvalidPayloadInSpanBatch(gt *testing.T) { func TestSpanBatchAtomicity_Consolidation(gt *testing.T) { t := NewDefaultTesting(gt) - dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams) + dp := e2eutils.MakeDeployParams(t, DefaultRollupTestParams) minTs := hexutil.Uint64(0) // Activate Delta hardfork applyDeltaTimeOffset(dp, &minTs) dp.DeployConfig.L2BlockTime = 2 - sd := e2eutils.Setup(t, dp, defaultAlloc) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LevelInfo) _, _, miner, sequencer, seqEng, verifier, _, batcher := setupReorgTestActors(t, dp, sd, log) seqEngCl, err := sources.NewEngineClient(seqEng.RPCClient(), log, nil, sources.EngineClientDefaultConfig(sd.RollupCfg)) @@ -1063,12 +1063,12 @@ func TestSpanBatchAtomicity_Consolidation(gt *testing.T) { func TestSpanBatchAtomicity_ForceAdvance(gt *testing.T) { t := NewDefaultTesting(gt) - dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams) + dp := e2eutils.MakeDeployParams(t, DefaultRollupTestParams) minTs := hexutil.Uint64(0) // Activate Delta hardfork applyDeltaTimeOffset(dp, &minTs) dp.DeployConfig.L2BlockTime = 2 - sd := e2eutils.Setup(t, dp, defaultAlloc) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LevelInfo) _, _, miner, sequencer, _, verifier, _, batcher := setupReorgTestActors(t, dp, sd, log) diff --git a/op-e2e/actions/system_config_test.go b/op-e2e/actions/system_config_test.go index 452d5dbc300b..406ca0a16983 100644 --- a/op-e2e/actions/system_config_test.go +++ b/op-e2e/actions/system_config_test.go @@ -51,10 +51,10 @@ func TestSystemConfigBatchType(t *testing.T) { func BatcherKeyRotation(gt *testing.T, deltaTimeOffset *hexutil.Uint64) { t := NewDefaultTesting(gt) - dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams) + dp := e2eutils.MakeDeployParams(t, DefaultRollupTestParams) dp.DeployConfig.L2BlockTime = 2 applyDeltaTimeOffset(dp, deltaTimeOffset) - sd := e2eutils.Setup(t, dp, defaultAlloc) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LevelDebug) miner, seqEngine, sequencer := setupSequencerTest(t, sd, log) miner.ActL1SetFeeRecipient(common.Address{'A'}) @@ -226,7 +226,7 @@ func BatcherKeyRotation(gt *testing.T, deltaTimeOffset *hexutil.Uint64) { // and that the L1 data fees to the L2 transaction are applied correctly before, during and after the GPO update in L2. func GPOParamsChange(gt *testing.T, deltaTimeOffset *hexutil.Uint64) { t := NewDefaultTesting(gt) - dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams) + dp := e2eutils.MakeDeployParams(t, DefaultRollupTestParams) applyDeltaTimeOffset(dp, deltaTimeOffset) // activating Delta only, not Ecotone and further: @@ -236,7 +236,7 @@ func GPOParamsChange(gt *testing.T, deltaTimeOffset *hexutil.Uint64) { dp.DeployConfig.L2GenesisFjordTimeOffset = nil dp.DeployConfig.L2GenesisGraniteTimeOffset = nil - sd := e2eutils.Setup(t, dp, defaultAlloc) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LevelDebug) miner, seqEngine, sequencer := setupSequencerTest(t, sd, log) batcher := NewL2Batcher(log, sd.RollupCfg, DefaultBatcherCfg(dp), @@ -361,9 +361,9 @@ func GPOParamsChange(gt *testing.T, deltaTimeOffset *hexutil.Uint64) { // the gas limit change event. And checks if a verifier node can reproduce the same gas limit change. func GasLimitChange(gt *testing.T, deltaTimeOffset *hexutil.Uint64) { t := NewDefaultTesting(gt) - dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams) + dp := e2eutils.MakeDeployParams(t, DefaultRollupTestParams) applyDeltaTimeOffset(dp, deltaTimeOffset) - sd := e2eutils.Setup(t, dp, defaultAlloc) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LevelDebug) miner, seqEngine, sequencer := setupSequencerTest(t, sd, log) batcher := NewL2Batcher(log, sd.RollupCfg, DefaultBatcherCfg(dp), diff --git a/op-e2e/actions/user_test.go b/op-e2e/actions/user_test.go index 3a0b079cb3e4..8bb1b042c9a3 100644 --- a/op-e2e/actions/user_test.go +++ b/op-e2e/actions/user_test.go @@ -109,7 +109,7 @@ func TestCrossLayerUser(t *testing.T) { func runCrossLayerUserTest(gt *testing.T, test hardforkScheduledTest) { t := NewDefaultTesting(gt) - dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams) + dp := e2eutils.MakeDeployParams(t, DefaultRollupTestParams) // This overwrites all deploy-config settings, // so even when the deploy-config defaults change, we test the right transitions. dp.DeployConfig.L2GenesisRegolithTimeOffset = test.regolithTime @@ -125,7 +125,7 @@ func runCrossLayerUserTest(gt *testing.T, test hardforkScheduledTest) { require.Zero(t, uint64(*test.ecotoneTime)%uint64(dp.DeployConfig.L2BlockTime), "ecotone fork must be aligned") } - sd := e2eutils.Setup(t, dp, defaultAlloc) + sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LevelDebug) require.Equal(t, dp.Secrets.Addresses().Batcher, dp.DeployConfig.BatchSenderAddress) diff --git a/op-e2e/actions/utils.go b/op-e2e/actions/utils.go new file mode 100644 index 000000000000..aa03db3e29b5 --- /dev/null +++ b/op-e2e/actions/utils.go @@ -0,0 +1,79 @@ +package actions + +import ( + "github.com/ethereum-optimism/optimism/op-e2e/e2eutils" + "github.com/ethereum-optimism/optimism/op-node/node/safedb" + "github.com/ethereum-optimism/optimism/op-node/rollup/interop" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth/ethconfig" + "github.com/ethereum/go-ethereum/node" + "github.com/ethereum/go-ethereum/p2p" +) + +var DefaultRollupTestParams = &e2eutils.TestParams{ + MaxSequencerDrift: 40, + SequencerWindowSize: 120, + ChannelTimeout: 120, + L1BlockTime: 15, +} + +var DefaultAlloc = &e2eutils.AllocParams{PrefundTestUsers: true} + +type VerifierCfg struct { + SafeHeadListener safeDB + InteropBackend interop.InteropBackend +} + +type VerifierOpt func(opts *VerifierCfg) + +func WithSafeHeadListener(l safeDB) VerifierOpt { + return func(opts *VerifierCfg) { + opts.SafeHeadListener = l + } +} + +func WithInteropBackend(b interop.InteropBackend) VerifierOpt { + return func(opts *VerifierCfg) { + opts.InteropBackend = b + } +} + +func DefaultVerifierCfg() *VerifierCfg { + return &VerifierCfg{ + SafeHeadListener: safedb.Disabled, + } +} + +func EngineWithP2P() EngineOption { + return func(ethCfg *ethconfig.Config, nodeCfg *node.Config) error { + p2pKey, err := crypto.GenerateKey() + if err != nil { + return err + } + nodeCfg.P2P = p2p.Config{ + MaxPeers: 100, + NoDiscovery: true, + ListenAddr: "127.0.0.1:0", + PrivateKey: p2pKey, + } + return nil + } +} + +type SequencerCfg struct { + VerifierCfg +} + +func DefaultSequencerConfig() *SequencerCfg { + return &SequencerCfg{VerifierCfg: *DefaultVerifierCfg()} +} + +type SequencerOpt func(opts *SequencerCfg) + +func WithVerifierOpts(opts ...VerifierOpt) SequencerOpt { + return func(cfg *SequencerCfg) { + for _, opt := range opts { + opt(&cfg.VerifierCfg) + } + } +} From 763db00da2475b87893d86915a526c7a7b14e600 Mon Sep 17 00:00:00 2001 From: clabby Date: Wed, 11 Sep 2024 19:36:31 -0400 Subject: [PATCH 2/5] tidy --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 5ab245ccf283..e1b4e14530a1 100644 --- a/go.mod +++ b/go.mod @@ -35,6 +35,7 @@ require ( github.com/multiformats/go-base32 v0.1.0 github.com/multiformats/go-multiaddr v0.13.0 github.com/multiformats/go-multiaddr-dns v0.3.1 + github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416 github.com/olekukonko/tablewriter v0.0.5 github.com/onsi/gomega v1.34.1 github.com/pkg/errors v0.9.1 @@ -165,7 +166,6 @@ require ( github.com/multiformats/go-varint v0.0.7 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/naoina/go-stringutil v0.1.0 // indirect - github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416 // indirect github.com/onsi/ginkgo/v2 v2.20.0 // indirect github.com/opencontainers/runtime-spec v1.2.0 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect From 3c1e7fd62196d8a23abb64c2a5520c8b50b5b0a9 Mon Sep 17 00:00:00 2001 From: clabby Date: Wed, 11 Sep 2024 19:39:21 -0400 Subject: [PATCH 3/5] lint --- op-e2e/actions/proofs/fixture.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/op-e2e/actions/proofs/fixture.go b/op-e2e/actions/proofs/fixture.go index 7f988e6a0634..c7eedad5833e 100644 --- a/op-e2e/actions/proofs/fixture.go +++ b/op-e2e/actions/proofs/fixture.go @@ -9,8 +9,8 @@ import ( "path/filepath" "testing" - "github.com/ethereum-optimism/optimism/op-program/host/config" "github.com/ethereum-optimism/optimism/op-program/client/claim" + "github.com/ethereum-optimism/optimism/op-program/host/config" "github.com/ethereum/go-ethereum/common" "github.com/naoina/toml" "github.com/stretchr/testify/require" From 89b7520c4fc27536a587f8375108c834455f3d7c Mon Sep 17 00:00:00 2001 From: clabby Date: Wed, 11 Sep 2024 19:45:38 -0400 Subject: [PATCH 4/5] adrian review --- op-e2e/actions/proofs/env.go | 4 ++-- op-e2e/actions/proofs/fixture.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/op-e2e/actions/proofs/env.go b/op-e2e/actions/proofs/env.go index 020e158c684a..8996c4d32d8a 100644 --- a/op-e2e/actions/proofs/env.go +++ b/op-e2e/actions/proofs/env.go @@ -10,6 +10,7 @@ import ( "github.com/ethereum-optimism/optimism/op-e2e/e2eutils" "github.com/ethereum-optimism/optimism/op-program/host" "github.com/ethereum-optimism/optimism/op-program/host/config" + hostTypes "github.com/ethereum-optimism/optimism/op-program/host/types" "github.com/ethereum-optimism/optimism/op-service/sources" "github.com/ethereum-optimism/optimism/op-service/testlog" "github.com/ethereum/go-ethereum/common" @@ -121,8 +122,6 @@ func NewOpProgramCfg( fi *FixtureInputs, params ...OpProgramCfgParam, ) *config.Config { - t.Helper() - dfault := config.NewConfig(env.sd.RollupCfg, env.sd.L2Cfg.Config, fi.L1Head, fi.L2Head, fi.L2OutputRoot, fi.L2Claim, fi.L2BlockNumber) // Set up in-process L1 sources @@ -139,6 +138,7 @@ func NewOpProgramCfg( if dumpFixtures { dfault.DataDir = t.TempDir() + dfault.DataFormat = hostTypes.DataFormatPebble } for _, apply := range params { diff --git a/op-e2e/actions/proofs/fixture.go b/op-e2e/actions/proofs/fixture.go index c7eedad5833e..8bc4a875a4c3 100644 --- a/op-e2e/actions/proofs/fixture.go +++ b/op-e2e/actions/proofs/fixture.go @@ -22,10 +22,10 @@ var ( ) func init() { - if os.Getenv("OP_E2E_DUMP_FIXTURES") == "1" { + fixtureDir = os.Getenv("OP_E2E_FPP_FIXTURE_DIR") + if fixtureDir != "" { dumpFixtures = true } - fixtureDir = os.Getenv("OP_E2E_FPP_FIXTURE_DIR") } type TestFixture struct { From 6b1c210cba679496c860d9d74d76a4b8c72b342e Mon Sep 17 00:00:00 2001 From: clabby Date: Wed, 11 Sep 2024 20:39:35 -0400 Subject: [PATCH 5/5] move `RunFaultProofProgram` onto the `L2FaultProofEnv` type --- op-e2e/actions/op_program_test.go | 385 ------------------- op-e2e/actions/proofs/env.go | 66 ++-- op-e2e/actions/proofs/simple_program_test.go | 4 +- 3 files changed, 35 insertions(+), 420 deletions(-) delete mode 100644 op-e2e/actions/op_program_test.go diff --git a/op-e2e/actions/op_program_test.go b/op-e2e/actions/op_program_test.go deleted file mode 100644 index e642d447c506..000000000000 --- a/op-e2e/actions/op_program_test.go +++ /dev/null @@ -1,385 +0,0 @@ -package actions - -import ( - "context" - "encoding/json" - "errors" - "io/fs" - "math/rand" - "os" - "os/exec" - "path/filepath" - "testing" - - "github.com/BurntSushi/toml" - batcherFlags "github.com/ethereum-optimism/optimism/op-batcher/flags" - "github.com/ethereum-optimism/optimism/op-e2e/e2eutils" - "github.com/ethereum-optimism/optimism/op-program/client/claim" - "github.com/ethereum-optimism/optimism/op-program/host" - "github.com/ethereum-optimism/optimism/op-program/host/config" - hostTypes "github.com/ethereum-optimism/optimism/op-program/host/types" - "github.com/ethereum-optimism/optimism/op-service/sources" - "github.com/ethereum-optimism/optimism/op-service/testlog" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/log" - "github.com/stretchr/testify/require" -) - -var ( - dumpFixtures = false - fixtureDir string -) - -func init() { - fixtureDir = os.Getenv("OP_E2E_FPP_FIXTURE_DIR") - if fixtureDir != "" { - dumpFixtures = true - } -} - -// L2FaultProofEnv is a test harness for a fault provable L2 chain. -type L2FaultProofEnv struct { - log log.Logger - batcher *L2Batcher - sequencer *L2Sequencer - engine *L2Engine - engCl *sources.EngineClient - sd *e2eutils.SetupData - dp *e2eutils.DeployParams - miner *L1Miner - alice *CrossLayerUser -} - -func NewL2FaultProofEnv(t Testing, tp *e2eutils.TestParams, dp *e2eutils.DeployParams, batcherCfg *BatcherCfg) *L2FaultProofEnv { - log := testlog.Logger(t, log.LvlDebug) - sd := e2eutils.Setup(t, dp, defaultAlloc) - - miner, engine, sequencer := setupSequencerTest(t, sd, log) - miner.ActL1SetFeeRecipient(common.Address{0xCA, 0xFE, 0xBA, 0xBE}) - sequencer.ActL2PipelineFull(t) - engCl := engine.EngineClient(t, sd.RollupCfg) - - // Set the batcher key to the secret key of the batcher - batcherCfg.BatcherKey = dp.Secrets.Batcher - batcher := NewL2Batcher(log, sd.RollupCfg, batcherCfg, sequencer.RollupClient(), miner.EthClient(), engine.EthClient(), engCl) - - addresses := e2eutils.CollectAddresses(sd, dp) - cl := engine.EthClient() - l2UserEnv := &BasicUserEnv[*L2Bindings]{ - EthCl: cl, - Signer: types.LatestSigner(sd.L2Cfg.Config), - AddressCorpora: addresses, - Bindings: NewL2Bindings(t, cl, engine.GethClient()), - } - alice := NewCrossLayerUser(log, dp.Secrets.Alice, rand.New(rand.NewSource(0xa57b))) - alice.L2.SetUserEnv(l2UserEnv) - - return &L2FaultProofEnv{ - log: log, - batcher: batcher, - sequencer: sequencer, - engine: engine, - engCl: engCl, - sd: sd, - dp: dp, - miner: miner, - alice: alice, - } -} - -type TestParam func(p *e2eutils.TestParams) - -func NewTestParams(params ...TestParam) *e2eutils.TestParams { - dfault := defaultRollupTestParams - for _, apply := range params { - apply(dfault) - } - return dfault -} - -type DeployParam func(p *e2eutils.DeployParams) - -func NewDeployParams(t Testing, params ...DeployParam) *e2eutils.DeployParams { - dfault := e2eutils.MakeDeployParams(t, NewTestParams()) - for _, apply := range params { - apply(dfault) - } - return dfault -} - -type BatcherCfgParam func(c *BatcherCfg) - -func NewBatcherCfg(params ...BatcherCfgParam) *BatcherCfg { - dfault := &BatcherCfg{ - MinL1TxSize: 0, - MaxL1TxSize: 128_000, - DataAvailabilityType: batcherFlags.BlobsType, - } - for _, apply := range params { - apply(dfault) - } - return dfault -} - -type OpProgramCfgParam func(p *config.Config) - -func NewOpProgramCfg( - t Testing, - env *L2FaultProofEnv, - l1Head common.Hash, - l2Head common.Hash, - l2OutputRoot common.Hash, - l2Claim common.Hash, - l2ClaimBlockNum uint64, - params ...OpProgramCfgParam, -) *config.Config { - dfault := config.NewConfig(env.sd.RollupCfg, env.sd.L2Cfg.Config, l1Head, l2Head, l2OutputRoot, l2Claim, l2ClaimBlockNum) - - // Set up in-process L1 sources - dfault.L1ProcessSource = env.miner.L1Client(t, env.sd.RollupCfg) - dfault.L1BeaconProcessSource = env.miner.blobStore - - // Set up in-process L2 source - l2ClCfg := sources.L2ClientDefaultConfig(env.sd.RollupCfg, true) - l2RPC := env.engine.RPCClient() - l2Client, err := host.NewL2Client(l2RPC, env.log, nil, &host.L2ClientConfig{L2ClientConfig: l2ClCfg, L2Head: l2Head}) - require.NoError(t, err, "failed to create L2 client") - l2DebugCl := &host.L2Source{L2Client: l2Client, DebugClient: sources.NewDebugClient(l2RPC.CallContext)} - dfault.L2ProcessSource = l2DebugCl - - if dumpFixtures { - dfault.DataDir = t.TempDir() - dfault.DataFormat = hostTypes.DataFormatPebble - } - - for _, apply := range params { - apply(dfault) - } - return dfault -} - -func Test_ProgramAction_SimpleEmptyChain_HonestClaim_Granite(gt *testing.T) { - t := NewDefaultTesting(gt) - tp := NewTestParams() - dp := NewDeployParams(t, func(dp *e2eutils.DeployParams) { - genesisBlock := hexutil.Uint64(0) - - // Enable Cancun on L1 & Granite on L2 at genesis - dp.DeployConfig.L1CancunTimeOffset = &genesisBlock - dp.DeployConfig.L2GenesisRegolithTimeOffset = &genesisBlock - dp.DeployConfig.L2GenesisCanyonTimeOffset = &genesisBlock - dp.DeployConfig.L2GenesisDeltaTimeOffset = &genesisBlock - dp.DeployConfig.L2GenesisEcotoneTimeOffset = &genesisBlock - dp.DeployConfig.L2GenesisFjordTimeOffset = &genesisBlock - dp.DeployConfig.L2GenesisGraniteTimeOffset = &genesisBlock - }) - bCfg := NewBatcherCfg() - env := NewL2FaultProofEnv(t, tp, dp, bCfg) - - // Build an empty block on L2 - env.sequencer.ActL2StartBlock(t) - env.sequencer.ActL2EndBlock(t) - - // Instruct the batcher to submit the block to L1, and include the transaction. - env.batcher.ActSubmitAll(t) - env.miner.ActL1StartBlock(12)(t) - env.miner.ActL1IncludeTxByHash(env.batcher.LastSubmitted.Hash())(t) - env.miner.ActL1EndBlock(t) - - // Finalize the block with the batch on L1. - env.miner.ActL1SafeNext(t) - env.miner.ActL1FinalizeNext(t) - - // Instruct the sequencer to derive the L2 chain from the data on L1 that the batcher just posted. - env.sequencer.ActL1HeadSignal(t) - env.sequencer.ActL2PipelineFull(t) - - l1Head := env.miner.l1Chain.CurrentBlock() - l2SafeHead := env.engine.l2Chain.CurrentSafeBlock() - - // Ensure there is only 1 block on L1. - require.Equal(t, uint64(1), l1Head.Number.Uint64()) - // Ensure the block is marked as safe before we attempt to fault prove it. - require.Equal(t, uint64(1), l2SafeHead.Number.Uint64()) - - // Fetch the pre and post output roots for the fault proof. - preRoot, err := env.sequencer.RollupClient().OutputAtBlock(context.Background(), l2SafeHead.Number.Uint64()-1) - require.NoError(t, err) - claimRoot, err := env.sequencer.RollupClient().OutputAtBlock(context.Background(), l2SafeHead.Number.Uint64()) - require.NoError(t, err) - - // Run the fault proof program from the state transition from L2 block 0 -> 1. - programCfg := NewOpProgramCfg( - t, - env, - l1Head.Hash(), - preRoot.BlockRef.Hash, - common.Hash(preRoot.OutputRoot), - common.Hash(claimRoot.OutputRoot), - l2SafeHead.Number.Uint64(), - ) - err = host.FaultProofProgram(context.Background(), env.log, programCfg) - require.NoError(t, err) - - tryDumpTestFixture(gt, err, "simple-empty-chain-honest-claim-granite", env, programCfg) -} - -func Test_ProgramAction_SimpleEmptyChain_JunkClaim_Granite(gt *testing.T) { - t := NewDefaultTesting(gt) - tp := NewTestParams() - dp := NewDeployParams(t, func(dp *e2eutils.DeployParams) { - genesisBlock := hexutil.Uint64(0) - - // Enable Cancun on L1 & Granite on L2 at genesis - dp.DeployConfig.L1CancunTimeOffset = &genesisBlock - dp.DeployConfig.L2GenesisRegolithTimeOffset = &genesisBlock - dp.DeployConfig.L2GenesisCanyonTimeOffset = &genesisBlock - dp.DeployConfig.L2GenesisDeltaTimeOffset = &genesisBlock - dp.DeployConfig.L2GenesisEcotoneTimeOffset = &genesisBlock - dp.DeployConfig.L2GenesisFjordTimeOffset = &genesisBlock - dp.DeployConfig.L2GenesisGraniteTimeOffset = &genesisBlock - }) - bCfg := NewBatcherCfg() - env := NewL2FaultProofEnv(t, tp, dp, bCfg) - - // Build an empty block on L2 - env.sequencer.ActL2StartBlock(t) - env.sequencer.ActL2EndBlock(t) - - // Instruct the batcher to submit the block to L1, and include the transaction. - env.batcher.ActSubmitAll(t) - env.miner.ActL1StartBlock(12)(t) - env.miner.ActL1IncludeTxByHash(env.batcher.LastSubmitted.Hash())(t) - env.miner.ActL1EndBlock(t) - - // Finalize the block with the batch on L1. - env.miner.ActL1SafeNext(t) - env.miner.ActL1FinalizeNext(t) - - // Instruct the sequencer to derive the L2 chain from the data on L1 that the batcher just posted. - env.sequencer.ActL1HeadSignal(t) - env.sequencer.ActL2PipelineFull(t) - - l1Head := env.miner.l1Chain.CurrentBlock() - l2SafeHead := env.engine.l2Chain.CurrentSafeBlock() - - // Ensure there is only 1 block on L1. - require.Equal(t, uint64(1), l1Head.Number.Uint64()) - // Ensure the block is marked as safe before we attempt to fault prove it. - require.Equal(t, uint64(1), l2SafeHead.Number.Uint64()) - - // Fetch the pre and post output roots for the fault proof. - preRoot, err := env.sequencer.RollupClient().OutputAtBlock(context.Background(), l2SafeHead.Number.Uint64()-1) - require.NoError(t, err) - - // Run the fault proof program from the state transition from L2 block 0 -> 1, with a junk claim. - programCfg := NewOpProgramCfg( - t, - env, - l1Head.Hash(), - preRoot.BlockRef.Hash, - common.Hash(preRoot.OutputRoot), - common.HexToHash("0xdeadbeef"), - l2SafeHead.Number.Uint64(), - ) - err = host.FaultProofProgram(context.Background(), env.log, programCfg) - require.Error(t, err) - - tryDumpTestFixture(gt, err, "simple-empty-chain-junk-claim-granite", env, programCfg) -} - -//////////////////////////////////////////////////////////////// -// Fixture Generation utils // -//////////////////////////////////////////////////////////////// - -type TestFixture struct { - Name string `toml:"name"` - ExpectedStatus uint8 `toml:"expected-status"` - Inputs FixtureInputs `toml:"inputs"` -} - -type FixtureInputs struct { - L2BlockNumber uint64 `toml:"l2-block-number"` - L2Claim common.Hash `toml:"l2-claim"` - L2Head common.Hash `toml:"l2-head"` - L2OutputRoot common.Hash `toml:"l2-output-root"` - L2ChainID uint64 `toml:"l2-chain-id"` - L1Head common.Hash `toml:"l1-head"` -} - -// Dumps a `fp-tests` test fixture to disk if the `OP_E2E_DUMP_FIXTURES` environment variable is set. -// -// [fp-tests]: https://github.com/ethereum-optimism/fp-tests -func tryDumpTestFixture(t *testing.T, result error, name string, env *L2FaultProofEnv, programCfg *config.Config) { - if !dumpFixtures { - return - } - - rollupCfg := env.sequencer.rollupCfg - l2Genesis := env.sd.L2Cfg - - var expectedStatus uint8 - if result == nil { - expectedStatus = 0 - } else if errors.Is(result, claim.ErrClaimNotValid) { - expectedStatus = 1 - } else { - expectedStatus = 2 - } - - fixture := TestFixture{ - Name: name, - ExpectedStatus: expectedStatus, - Inputs: FixtureInputs{ - L2BlockNumber: programCfg.L2ClaimBlockNumber, - L2Claim: programCfg.L2Claim, - L2Head: programCfg.L2Head, - L2OutputRoot: programCfg.L2OutputRoot, - L2ChainID: env.sd.RollupCfg.L2ChainID.Uint64(), - L1Head: programCfg.L1Head, - }, - } - - fixturePath := filepath.Join(fixtureDir, name) - - err := os.MkdirAll(filepath.Join(fixturePath), fs.ModePerm) - require.NoError(t, err, "failed to create fixture dir") - - fixtureFilePath := filepath.Join(fixturePath, "fixture.toml") - serFixture, err := toml.Marshal(fixture) - require.NoError(t, err, "failed to serialize fixture") - require.NoError(t, os.WriteFile(fixtureFilePath, serFixture, fs.ModePerm), "failed to write fixture") - - genesisPath := filepath.Join(fixturePath, "genesis.json") - serGenesis, err := l2Genesis.MarshalJSON() - require.NoError(t, err, "failed to serialize genesis") - require.NoError(t, os.WriteFile(genesisPath, serGenesis, fs.ModePerm), "failed to write genesis") - - rollupPath := filepath.Join(fixturePath, "rollup.json") - serRollup, err := json.Marshal(rollupCfg) - require.NoError(t, err, "failed to serialize rollup") - require.NoError(t, os.WriteFile(rollupPath, serRollup, fs.ModePerm), "failed to write rollup") - - // Copy the witness database into the fixture directory. - cmd := exec.Command("cp", "-r", programCfg.DataDir, filepath.Join(fixturePath, "witness-db")) - require.NoError(t, cmd.Run(), "Failed to copy witness DB") - - // Compress the genesis file. - cmd = exec.Command("zstd", genesisPath) - _ = cmd.Run() - require.NoError(t, os.Remove(genesisPath), "Failed to remove uncompressed genesis file") - - // Compress the witness database. - cmd = exec.Command( - "tar", - "--zstd", - "-cf", - filepath.Join(fixturePath, "witness-db.tar.zst"), - filepath.Join(fixturePath, "witness-db"), - ) - cmd.Dir = filepath.Join(fixturePath) - require.NoError(t, cmd.Run(), "Failed to compress witness DB") - require.NoError(t, os.RemoveAll(filepath.Join(fixturePath, "witness-db")), "Failed to remove uncompressed witness DB") -} diff --git a/op-e2e/actions/proofs/env.go b/op-e2e/actions/proofs/env.go index 8996c4d32d8a..59fc51fdf452 100644 --- a/op-e2e/actions/proofs/env.go +++ b/op-e2e/actions/proofs/env.go @@ -80,6 +80,39 @@ func NewL2FaultProofEnv(t actions.Testing, tp *e2eutils.TestParams, dp *e2eutils } } +type FixtureInputParam func(f *FixtureInputs) + +func (env *L2FaultProofEnv) RunFaultProofProgram(t actions.Testing, gt *testing.T, l2ClaimBlockNum uint64, fixtureInputParams ...FixtureInputParam) error { + // Fetch the pre and post output roots for the fault proof. + preRoot, err := env.sequencer.RollupClient().OutputAtBlock(t.Ctx(), l2ClaimBlockNum-1) + require.NoError(t, err) + claimRoot, err := env.sequencer.RollupClient().OutputAtBlock(t.Ctx(), l2ClaimBlockNum) + require.NoError(t, err) + l1Head := env.miner.L1Chain().CurrentBlock() + + fixtureInputs := &FixtureInputs{ + L2BlockNumber: l2ClaimBlockNum, + L2Claim: common.Hash(claimRoot.OutputRoot), + L2Head: preRoot.BlockRef.Hash, + L2OutputRoot: common.Hash(preRoot.OutputRoot), + L2ChainID: env.sd.RollupCfg.L2ChainID.Uint64(), + L1Head: l1Head.Hash(), + } + for _, apply := range fixtureInputParams { + apply(fixtureInputs) + } + + // Run the fault proof program from the state transition from L2 block 0 -> 1. + programCfg := NewOpProgramCfg( + t, + env, + fixtureInputs, + ) + err = host.FaultProofProgram(t.Ctx(), env.log, programCfg) + tryDumpTestFixture(gt, err, t.Name(), env, programCfg) + return err +} + type TestParam func(p *e2eutils.TestParams) func NewTestParams(params ...TestParam) *e2eutils.TestParams { @@ -146,36 +179,3 @@ func NewOpProgramCfg( } return dfault } - -type FixtureInputParam func(f *FixtureInputs) - -func RunFaultProofProgram(t actions.Testing, gt *testing.T, env *L2FaultProofEnv, l2ClaimBlockNum uint64, fixtureInputParams ...FixtureInputParam) error { - // Fetch the pre and post output roots for the fault proof. - preRoot, err := env.sequencer.RollupClient().OutputAtBlock(t.Ctx(), l2ClaimBlockNum-1) - require.NoError(t, err) - claimRoot, err := env.sequencer.RollupClient().OutputAtBlock(t.Ctx(), l2ClaimBlockNum) - require.NoError(t, err) - l1Head := env.miner.L1Chain().CurrentBlock() - - fixtureInputs := &FixtureInputs{ - L2BlockNumber: l2ClaimBlockNum, - L2Claim: common.Hash(claimRoot.OutputRoot), - L2Head: preRoot.BlockRef.Hash, - L2OutputRoot: common.Hash(preRoot.OutputRoot), - L2ChainID: env.sd.RollupCfg.L2ChainID.Uint64(), - L1Head: l1Head.Hash(), - } - for _, apply := range fixtureInputParams { - apply(fixtureInputs) - } - - // Run the fault proof program from the state transition from L2 block 0 -> 1. - programCfg := NewOpProgramCfg( - t, - env, - fixtureInputs, - ) - err = host.FaultProofProgram(t.Ctx(), env.log, programCfg) - tryDumpTestFixture(gt, err, t.Name(), env, programCfg) - return err -} diff --git a/op-e2e/actions/proofs/simple_program_test.go b/op-e2e/actions/proofs/simple_program_test.go index 900184bb3af8..b160045210d5 100644 --- a/op-e2e/actions/proofs/simple_program_test.go +++ b/op-e2e/actions/proofs/simple_program_test.go @@ -54,7 +54,7 @@ func Test_ProgramAction_SimpleEmptyChain_HonestClaim_Granite(gt *testing.T) { // Ensure the block is marked as safe before we attempt to fault prove it. require.Equal(t, uint64(1), l2SafeHead.Number.Uint64()) - err := RunFaultProofProgram(t, gt, env, l2SafeHead.Number.Uint64()) + err := env.RunFaultProofProgram(t, gt, l2SafeHead.Number.Uint64()) require.NoError(t, err, "fault proof program failed") } @@ -102,7 +102,7 @@ func Test_ProgramAction_SimpleEmptyChain_JunkClaim_Granite(gt *testing.T) { // Ensure the block is marked as safe before we attempt to fault prove it. require.Equal(t, uint64(1), l2SafeHead.Number.Uint64()) - err := RunFaultProofProgram(t, gt, env, l2SafeHead.Number.Uint64(), func(f *FixtureInputs) { + err := env.RunFaultProofProgram(t, gt, l2SafeHead.Number.Uint64(), func(f *FixtureInputs) { f.L2Claim = common.HexToHash("0xdeadbeef") }) require.Error(t, err, "fault proof program should have failed")