Commit ac443ef0 authored by Adrian Sutton's avatar Adrian Sutton Committed by GitHub

op-e2e: Separate helpers for proofs action tests into a new package (#11920)

* op-e2e: Move action test helpers for proofs to a separate package.

* op-e2e: Use helpers package under proofs rather than a completely separate package tree for helpers.
parent 92ed64e1
......@@ -4,6 +4,7 @@ import (
"testing"
"github.com/ethereum-optimism/optimism/op-e2e/actions"
"github.com/ethereum-optimism/optimism/op-e2e/actions/proofs/helpers"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils"
"github.com/ethereum-optimism/optimism/op-program/client/claim"
"github.com/ethereum/go-ethereum/common"
......@@ -19,58 +20,58 @@ import (
// 4. Submit the channel frame data across 2 transactions.
// 5. Instruct the sequencer to derive the L2 chain.
// 6. Run the FPP on the safe head.
func runChannelTimeoutTest(gt *testing.T, testCfg *TestCfg[any]) {
func runChannelTimeoutTest(gt *testing.T, testCfg *helpers.TestCfg[any]) {
t := actions.NewDefaultTesting(gt)
tp := NewTestParams(func(tp *e2eutils.TestParams) {
tp := helpers.NewTestParams(func(tp *e2eutils.TestParams) {
// Set the channel timeout to 10 blocks, 12x lower than the sequencing window.
tp.ChannelTimeout = 10
})
env := NewL2FaultProofEnv(t, testCfg, tp, NewBatcherCfg())
env := helpers.NewL2FaultProofEnv(t, testCfg, tp, helpers.NewBatcherCfg())
const NumL2Blocks = 10
// Build NumL2Blocks empty blocks on L2
for i := 0; i < NumL2Blocks; i++ {
env.sequencer.ActL2StartBlock(t)
env.sequencer.ActL2EndBlock(t)
env.Sequencer.ActL2StartBlock(t)
env.Sequencer.ActL2EndBlock(t)
}
// Buffer the first half of L2 blocks in the batcher, and submit it.
for i := 0; i < NumL2Blocks/2; i++ {
env.batcher.ActL2BatchBuffer(t)
env.Batcher.ActL2BatchBuffer(t)
}
env.batcher.ActL2BatchSubmit(t)
env.Batcher.ActL2BatchSubmit(t)
// Instruct the batcher to submit the first channel frame to L1, and include the transaction.
env.miner.ActL1StartBlock(12)(t)
env.miner.ActL1IncludeTxByHash(env.batcher.LastSubmitted.Hash())(t)
env.miner.ActL1EndBlock(t)
env.Miner.ActL1StartBlock(12)(t)
env.Miner.ActL1IncludeTxByHash(env.Batcher.LastSubmitted.Hash())(t)
env.Miner.ActL1EndBlock(t)
// Finalize the block with the first channel frame on L1.
env.miner.ActL1SafeNext(t)
env.miner.ActL1FinalizeNext(t)
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)
env.Sequencer.ActL1HeadSignal(t)
env.Sequencer.ActL2PipelineFull(t)
// Ensure that the safe head has not advanced - the channel is incomplete.
l2SafeHead := env.engine.L2Chain().CurrentSafeBlock()
l2SafeHead := env.Engine.L2Chain().CurrentSafeBlock()
require.Equal(t, uint64(0), l2SafeHead.Number.Uint64())
// Time out the channel by mining `ChannelTimeout + 1` empty blocks on L1.
for i := uint64(0); i < tp.ChannelTimeout+1; i++ {
env.miner.ActEmptyBlock(t)
env.miner.ActL1SafeNext(t)
env.miner.ActL1FinalizeNext(t)
env.Miner.ActEmptyBlock(t)
env.Miner.ActL1SafeNext(t)
env.Miner.ActL1FinalizeNext(t)
}
// Instruct the sequencer to derive the L2 chain - the channel should now be timed out.
env.sequencer.ActL1HeadSignal(t)
env.sequencer.ActL2PipelineFull(t)
env.Sequencer.ActL1HeadSignal(t)
env.Sequencer.ActL2PipelineFull(t)
// Ensure the safe head has still not advanced.
l2SafeHead = env.engine.L2Chain().CurrentSafeBlock()
l2SafeHead = env.Engine.L2Chain().CurrentSafeBlock()
require.Equal(t, uint64(0), l2SafeHead.Number.Uint64())
// Instruct the batcher to submit the blocks to L1 in a new channel,
......@@ -78,30 +79,30 @@ func runChannelTimeoutTest(gt *testing.T, testCfg *TestCfg[any]) {
for i := 0; i < 2; i++ {
// Buffer half of the L2 chain's blocks.
for j := 0; j < NumL2Blocks/2; j++ {
env.batcher.ActL2BatchBuffer(t)
env.Batcher.ActL2BatchBuffer(t)
}
// Close the channel on the second iteration.
if i == 1 {
env.batcher.ActL2ChannelClose(t)
env.Batcher.ActL2ChannelClose(t)
}
env.batcher.ActL2BatchSubmit(t)
env.miner.ActL1StartBlock(12)(t)
env.miner.ActL1IncludeTxByHash(env.batcher.LastSubmitted.Hash())(t)
env.miner.ActL1EndBlock(t)
env.Batcher.ActL2BatchSubmit(t)
env.Miner.ActL1StartBlock(12)(t)
env.Miner.ActL1IncludeTxByHash(env.Batcher.LastSubmitted.Hash())(t)
env.Miner.ActL1EndBlock(t)
// Finalize the block with the frame data on L1.
env.miner.ActL1SafeNext(t)
env.miner.ActL1FinalizeNext(t)
env.Miner.ActL1SafeNext(t)
env.Miner.ActL1FinalizeNext(t)
}
// Instruct the sequencer to derive the L2 chain.
env.sequencer.ActL1HeadSignal(t)
env.sequencer.ActL2PipelineFull(t)
env.Sequencer.ActL1HeadSignal(t)
env.Sequencer.ActL2PipelineFull(t)
// Ensure the safe head has still advanced to L2 block # NumL2Blocks.
l2SafeHead = env.engine.L2Chain().CurrentSafeBlock()
l2SafeHead = env.Engine.L2Chain().CurrentSafeBlock()
require.EqualValues(t, NumL2Blocks, l2SafeHead.Number.Uint64())
// Run the FPP on L2 block # NumL2Blocks/2.
......@@ -109,22 +110,22 @@ func runChannelTimeoutTest(gt *testing.T, testCfg *TestCfg[any]) {
}
func Test_ProgramAction_ChannelTimeout(gt *testing.T) {
matrix := NewMatrix[any]()
matrix := helpers.NewMatrix[any]()
defer matrix.Run(gt)
matrix.AddTestCase(
"HonestClaim",
nil,
LatestForkOnly,
helpers.LatestForkOnly,
runChannelTimeoutTest,
ExpectNoError(),
helpers.ExpectNoError(),
)
matrix.AddTestCase(
"JunkClaim",
nil,
LatestForkOnly,
helpers.LatestForkOnly,
runChannelTimeoutTest,
ExpectError(claim.ErrClaimNotValid),
WithL2Claim(common.HexToHash("0xdeadbeef")),
helpers.ExpectError(claim.ErrClaimNotValid),
helpers.WithL2Claim(common.HexToHash("0xdeadbeef")),
)
}
......@@ -5,6 +5,7 @@ import (
"testing"
"github.com/ethereum-optimism/optimism/op-e2e/actions"
"github.com/ethereum-optimism/optimism/op-e2e/actions/proofs/helpers"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils"
"github.com/ethereum-optimism/optimism/op-program/client/claim"
"github.com/ethereum/go-ethereum/common"
......@@ -25,73 +26,73 @@ var garbageKinds = []actions.GarbageKind{
//
// channel format ([]Frame):
// [f[0 - correct] f_x[1 - bad frame] f[1 - correct]]
func runGarbageChannelTest(gt *testing.T, testCfg *TestCfg[actions.GarbageKind]) {
func runGarbageChannelTest(gt *testing.T, testCfg *helpers.TestCfg[actions.GarbageKind]) {
t := actions.NewDefaultTesting(gt)
tp := NewTestParams(func(tp *e2eutils.TestParams) {
tp := helpers.NewTestParams(func(tp *e2eutils.TestParams) {
// Set the channel timeout to 10 blocks, 12x lower than the sequencing window.
tp.ChannelTimeout = 10
})
env := NewL2FaultProofEnv(t, testCfg, tp, NewBatcherCfg())
env := helpers.NewL2FaultProofEnv(t, testCfg, tp, helpers.NewBatcherCfg())
includeBatchTx := func(env *L2FaultProofEnv) {
includeBatchTx := func(env *helpers.L2FaultProofEnv) {
// Instruct the batcher to submit the first channel frame to L1, and include the transaction.
env.miner.ActL1StartBlock(12)(t)
env.miner.ActL1IncludeTxByHash(env.batcher.LastSubmitted.Hash())(t)
env.miner.ActL1EndBlock(t)
env.Miner.ActL1StartBlock(12)(t)
env.Miner.ActL1IncludeTxByHash(env.Batcher.LastSubmitted.Hash())(t)
env.Miner.ActL1EndBlock(t)
// Finalize the block with the first channel frame on L1.
env.miner.ActL1SafeNext(t)
env.miner.ActL1FinalizeNext(t)
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)
env.Sequencer.ActL1HeadSignal(t)
env.Sequencer.ActL2PipelineFull(t)
}
const NumL2Blocks = 10
// Build NumL2Blocks empty blocks on L2
for i := 0; i < NumL2Blocks; i++ {
env.sequencer.ActL2StartBlock(t)
env.sequencer.ActL2EndBlock(t)
env.Sequencer.ActL2StartBlock(t)
env.Sequencer.ActL2EndBlock(t)
}
// Buffer the first half of L2 blocks in the batcher, and submit it.
for i := 0; i < NumL2Blocks/2; i++ {
env.batcher.ActL2BatchBuffer(t)
env.Batcher.ActL2BatchBuffer(t)
}
env.batcher.ActL2BatchSubmit(t)
env.Batcher.ActL2BatchSubmit(t)
// Include the batcher transaction.
includeBatchTx(env)
// Ensure that the safe head has not advanced - the channel is incomplete.
l2SafeHead := env.engine.L2Chain().CurrentSafeBlock()
l2SafeHead := env.Engine.L2Chain().CurrentSafeBlock()
require.Equal(t, uint64(0), l2SafeHead.Number.Uint64())
// Buffer the second half of L2 blocks in the batcher.
for i := 0; i < NumL2Blocks/2; i++ {
env.batcher.ActL2BatchBuffer(t)
env.Batcher.ActL2BatchBuffer(t)
}
env.batcher.ActL2ChannelClose(t)
expectedSecondFrame := env.batcher.ReadNextOutputFrame(t)
env.Batcher.ActL2ChannelClose(t)
expectedSecondFrame := env.Batcher.ReadNextOutputFrame(t)
// Submit a garbage frame, modified from the expected second frame.
env.batcher.ActL2BatchSubmitGarbageRaw(t, expectedSecondFrame, testCfg.Custom)
env.Batcher.ActL2BatchSubmitGarbageRaw(t, expectedSecondFrame, testCfg.Custom)
// Include the garbage second frame tx
includeBatchTx(env)
// Ensure that the safe head has not advanced - the channel is incomplete.
l2SafeHead = env.engine.L2Chain().CurrentSafeBlock()
l2SafeHead = env.Engine.L2Chain().CurrentSafeBlock()
require.Equal(t, uint64(0), l2SafeHead.Number.Uint64())
// Submit the correct second frame.
env.batcher.ActL2BatchSubmitRaw(t, expectedSecondFrame)
env.Batcher.ActL2BatchSubmitRaw(t, expectedSecondFrame)
// Include the corract second frame tx.
includeBatchTx(env)
// Ensure that the safe head has advanced - the channel is complete.
l2SafeHead = env.engine.L2Chain().CurrentSafeBlock()
l2SafeHead = env.Engine.L2Chain().CurrentSafeBlock()
require.Equal(t, uint64(NumL2Blocks), l2SafeHead.Number.Uint64())
// Run the FPP on L2 block # NumL2Blocks.
......@@ -99,24 +100,24 @@ func runGarbageChannelTest(gt *testing.T, testCfg *TestCfg[actions.GarbageKind])
}
func Test_ProgramAction_GarbageChannel(gt *testing.T) {
matrix := NewMatrix[actions.GarbageKind]()
matrix := helpers.NewMatrix[actions.GarbageKind]()
defer matrix.Run(gt)
for _, garbageKind := range garbageKinds {
matrix.AddTestCase(
fmt.Sprintf("HonestClaim-%s", garbageKind.String()),
garbageKind,
LatestForkOnly,
helpers.LatestForkOnly,
runGarbageChannelTest,
ExpectNoError(),
helpers.ExpectNoError(),
)
matrix.AddTestCase(
fmt.Sprintf("JunkClaim-%s", garbageKind.String()),
garbageKind,
LatestForkOnly,
helpers.LatestForkOnly,
runGarbageChannelTest,
ExpectError(claim.ErrClaimNotValid),
WithL2Claim(common.HexToHash("0xdeadbeef")),
helpers.ExpectError(claim.ErrClaimNotValid),
helpers.WithL2Claim(common.HexToHash("0xdeadbeef")),
)
}
}
package proofs
package helpers
import (
"context"
......@@ -25,14 +25,14 @@ import (
// 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
Batcher *actions.L2Batcher
Sequencer *actions.L2Sequencer
Engine *actions.L2Engine
engCl *sources.EngineClient
sd *e2eutils.SetupData
dp *e2eutils.DeployParams
miner *actions.L1Miner
alice *actions.CrossLayerUser
Miner *actions.L1Miner
Alice *actions.CrossLayerUser
}
func NewL2FaultProofEnv[c any](t actions.Testing, testCfg *TestCfg[c], tp *e2eutils.TestParams, batcherCfg *actions.BatcherCfg) *L2FaultProofEnv {
......@@ -102,14 +102,14 @@ func NewL2FaultProofEnv[c any](t actions.Testing, testCfg *TestCfg[c], tp *e2eut
return &L2FaultProofEnv{
log: log,
batcher: batcher,
sequencer: sequencer,
engine: engine,
Batcher: batcher,
Sequencer: sequencer,
Engine: engine,
engCl: engCl,
sd: sd,
dp: dp,
miner: miner,
alice: alice,
Miner: miner,
Alice: alice,
}
}
......@@ -137,11 +137,11 @@ func WithL2Claim(claim common.Hash) FixtureInputParam {
func (env *L2FaultProofEnv) RunFaultProofProgram(t actions.Testing, l2ClaimBlockNum uint64, checkResult CheckResult, fixtureInputParams ...FixtureInputParam) {
// Fetch the pre and post output roots for the fault proof.
preRoot, err := env.sequencer.RollupClient().OutputAtBlock(t.Ctx(), l2ClaimBlockNum-1)
preRoot, err := env.Sequencer.RollupClient().OutputAtBlock(t.Ctx(), l2ClaimBlockNum-1)
require.NoError(t, err)
claimRoot, err := env.sequencer.RollupClient().OutputAtBlock(t.Ctx(), l2ClaimBlockNum)
claimRoot, err := env.Sequencer.RollupClient().OutputAtBlock(t.Ctx(), l2ClaimBlockNum)
require.NoError(t, err)
l1Head := env.miner.L1Chain().CurrentBlock()
l1Head := env.Miner.L1Chain().CurrentBlock()
fixtureInputs := &FixtureInputs{
L2BlockNumber: l2ClaimBlockNum,
......@@ -163,12 +163,12 @@ func (env *L2FaultProofEnv) RunFaultProofProgram(t actions.Testing, l2ClaimBlock
)
withInProcessPrefetcher := host.WithPrefetcher(func(ctx context.Context, logger log.Logger, kv kvstore.KV, cfg *config.Config) (host.Prefetcher, error) {
// Set up in-process L1 sources
l1Cl := env.miner.L1Client(t, env.sd.RollupCfg)
l1BlobFetcher := env.miner.BlobStore()
l1Cl := env.Miner.L1Client(t, env.sd.RollupCfg)
l1BlobFetcher := env.Miner.BlobStore()
// Set up in-process L2 source
l2ClCfg := sources.L2ClientDefaultConfig(env.sd.RollupCfg, true)
l2RPC := env.engine.RPCClient()
l2RPC := env.Engine.RPCClient()
l2Client, err := host.NewL2Client(l2RPC, env.log, nil, &host.L2ClientConfig{L2ClientConfig: l2ClCfg, L2Head: cfg.L2Head})
require.NoError(t, err, "failed to create L2 client")
l2DebugCl := &host.L2Source{L2Client: l2Client, DebugClient: sources.NewDebugClient(l2RPC.CallContext)}
......
......@@ -4,42 +4,43 @@ import (
"testing"
"github.com/ethereum-optimism/optimism/op-e2e/actions"
"github.com/ethereum-optimism/optimism/op-e2e/actions/proofs/helpers"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
)
// Run a test that proves a deposit-only block generated due to sequence window expiry.
func runSequenceWindowExpireTest(gt *testing.T, testCfg *TestCfg[any]) {
func runSequenceWindowExpireTest(gt *testing.T, testCfg *helpers.TestCfg[any]) {
t := actions.NewDefaultTesting(gt)
tp := NewTestParams()
env := NewL2FaultProofEnv(t, testCfg, tp, NewBatcherCfg())
tp := helpers.NewTestParams()
env := helpers.NewL2FaultProofEnv(t, testCfg, tp, helpers.NewBatcherCfg())
// Mine an empty block for gas estimation purposes.
env.miner.ActEmptyBlock(t)
env.Miner.ActEmptyBlock(t)
// Expire the sequence window by building `SequenceWindow + 1` empty blocks on L1.
for i := 0; i < int(tp.SequencerWindowSize)+1; i++ {
env.alice.L1.ActResetTxOpts(t)
env.alice.ActDeposit(t)
env.Alice.L1.ActResetTxOpts(t)
env.Alice.ActDeposit(t)
env.miner.ActL1StartBlock(12)(t)
env.miner.ActL1IncludeTx(env.alice.Address())(t)
env.miner.ActL1EndBlock(t)
env.Miner.ActL1StartBlock(12)(t)
env.Miner.ActL1IncludeTx(env.Alice.Address())(t)
env.Miner.ActL1EndBlock(t)
env.miner.ActL1SafeNext(t)
env.miner.ActL1FinalizeNext(t)
env.Miner.ActL1SafeNext(t)
env.Miner.ActL1FinalizeNext(t)
}
// Ensure the safe head is still 0.
l2SafeHead := env.engine.L2Chain().CurrentSafeBlock()
l2SafeHead := env.Engine.L2Chain().CurrentSafeBlock()
require.EqualValues(t, 0, l2SafeHead.Number.Uint64())
// Ask the sequencer to derive the deposit-only L2 chain.
env.sequencer.ActL1HeadSignal(t)
env.sequencer.ActL2PipelineFull(t)
env.Sequencer.ActL1HeadSignal(t)
env.Sequencer.ActL2PipelineFull(t)
// Ensure the safe head advanced forcefully.
l2SafeHead = env.engine.L2Chain().CurrentSafeBlock()
l2SafeHead = env.Engine.L2Chain().CurrentSafeBlock()
require.Greater(t, l2SafeHead.Number.Uint64(), uint64(0))
// Run the FPP on one of the auto-derived blocks.
......@@ -47,22 +48,22 @@ func runSequenceWindowExpireTest(gt *testing.T, testCfg *TestCfg[any]) {
}
func Test_ProgramAction_SequenceWindowExpired(gt *testing.T) {
matrix := NewMatrix[any]()
matrix := helpers.NewMatrix[any]()
defer matrix.Run(gt)
matrix.AddTestCase(
"HonestClaim",
nil,
LatestForkOnly,
helpers.LatestForkOnly,
runSequenceWindowExpireTest,
ExpectNoError(),
helpers.ExpectNoError(),
)
matrix.AddTestCase(
"JunkClaim",
nil,
LatestForkOnly,
helpers.LatestForkOnly,
runSequenceWindowExpireTest,
ExpectNoError(),
WithL2Claim(common.HexToHash("0xdeadbeef")),
helpers.ExpectNoError(),
helpers.WithL2Claim(common.HexToHash("0xdeadbeef")),
)
}
......@@ -4,35 +4,36 @@ import (
"testing"
"github.com/ethereum-optimism/optimism/op-e2e/actions"
"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/stretchr/testify/require"
)
func runSimpleProgramTest(gt *testing.T, testCfg *TestCfg[any]) {
func runSimpleProgramTest(gt *testing.T, testCfg *helpers.TestCfg[any]) {
t := actions.NewDefaultTesting(gt)
env := NewL2FaultProofEnv(t, testCfg, NewTestParams(), NewBatcherCfg())
env := helpers.NewL2FaultProofEnv(t, testCfg, helpers.NewTestParams(), helpers.NewBatcherCfg())
// Build an empty block on L2
env.sequencer.ActL2StartBlock(t)
env.sequencer.ActL2EndBlock(t)
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)
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)
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)
env.Sequencer.ActL1HeadSignal(t)
env.Sequencer.ActL2PipelineFull(t)
l1Head := env.miner.L1Chain().CurrentBlock()
l2SafeHead := env.engine.L2Chain().CurrentSafeBlock()
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())
......@@ -43,22 +44,22 @@ func runSimpleProgramTest(gt *testing.T, testCfg *TestCfg[any]) {
}
func Test_ProgramAction_SimpleEmptyChain(gt *testing.T) {
matrix := NewMatrix[any]()
matrix := helpers.NewMatrix[any]()
defer matrix.Run(gt)
matrix.AddTestCase(
"HonestClaim",
nil,
LatestForkOnly,
helpers.LatestForkOnly,
runSimpleProgramTest,
ExpectNoError(),
helpers.ExpectNoError(),
)
matrix.AddTestCase(
"JunkClaim",
nil,
LatestForkOnly,
helpers.LatestForkOnly,
runSimpleProgramTest,
ExpectError(claim.ErrClaimNotValid),
WithL2Claim(common.HexToHash("0xdeadbeef")),
helpers.ExpectError(claim.ErrClaimNotValid),
helpers.WithL2Claim(common.HexToHash("0xdeadbeef")),
)
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment