Commit bd97c322 authored by clabby's avatar clabby Committed by GitHub

feat(op-e2e): Open channel closed after sequence window expiry test (#11993)

* feat(op-e2e): Open channel closed after sequence window expiry test

Adds a test to the proof actions that proves a block at the safe head
after the batcher has opened a channel, allowed the sequence window to
expire, and then attempted to close their open channel after the fact.

* buffer frame

* include extra tx
parent eba495d2
......@@ -30,8 +30,8 @@ type L2FaultProofEnv struct {
Sequencer *helpers.L2Sequencer
Engine *helpers.L2Engine
engCl *sources.EngineClient
sd *e2eutils.SetupData
dp *e2eutils.DeployParams
Sd *e2eutils.SetupData
Dp *e2eutils.DeployParams
Miner *helpers.L1Miner
Alice *helpers.CrossLayerUser
}
......@@ -107,8 +107,8 @@ func NewL2FaultProofEnv[c any](t helpers.Testing, testCfg *TestCfg[c], tp *e2eut
Sequencer: sequencer,
Engine: engine,
engCl: engCl,
sd: sd,
dp: dp,
Sd: sd,
Dp: dp,
Miner: miner,
Alice: alice,
}
......@@ -149,7 +149,7 @@ func (env *L2FaultProofEnv) RunFaultProofProgram(t helpers.Testing, l2ClaimBlock
L2Claim: common.Hash(claimRoot.OutputRoot),
L2Head: preRoot.BlockRef.Hash,
L2OutputRoot: common.Hash(preRoot.OutputRoot),
L2ChainID: env.sd.RollupCfg.L2ChainID.Uint64(),
L2ChainID: env.Sd.RollupCfg.L2ChainID.Uint64(),
L1Head: l1Head.Hash(),
}
for _, apply := range fixtureInputParams {
......@@ -162,7 +162,7 @@ func (env *L2FaultProofEnv) RunFaultProofProgram(t helpers.Testing, l2ClaimBlock
fakeBeacon := fakebeacon.NewBeacon(
env.log,
env.Miner.BlobStore(),
env.sd.L1Cfg.Timestamp,
env.Sd.L1Cfg.Timestamp,
12,
)
require.NoError(t, fakeBeacon.Start("127.0.0.1:0"))
......@@ -178,11 +178,11 @@ func (env *L2FaultProofEnv) RunFaultProofProgram(t helpers.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)
l1Cl := env.Miner.L1Client(t, env.Sd.RollupCfg)
l1BlobFetcher := env.Miner.BlobSource()
// Set up in-process L2 source
l2ClCfg := sources.L2ClientDefaultConfig(env.sd.RollupCfg, true)
l2ClCfg := sources.L2ClientDefaultConfig(env.Sd.RollupCfg, true)
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")
......@@ -238,7 +238,7 @@ func NewOpProgramCfg(
fi *FixtureInputs,
params ...OpProgramCfgParam,
) *config.Config {
dfault := config.NewConfig(env.sd.RollupCfg, env.sd.L2Cfg.Config, fi.L1Head, fi.L2Head, fi.L2OutputRoot, fi.L2Claim, fi.L2BlockNumber)
dfault := config.NewConfig(env.Sd.RollupCfg, env.Sd.L2Cfg.Config, fi.L1Head, fi.L2Head, fi.L2OutputRoot, fi.L2Claim, fi.L2BlockNumber)
if dumpFixtures {
dfault.DataDir = t.TempDir()
......
......@@ -60,8 +60,8 @@ func tryDumpTestFixture(
}
name = convertToKebabCase(name)
rollupCfg := env.sd.RollupCfg
l2Genesis := env.sd.L2Cfg
rollupCfg := env.Sd.RollupCfg
l2Genesis := env.Sd.L2Cfg
var expectedStatus uint8
if result == nil {
......
......@@ -38,7 +38,7 @@ func RunKonaNative(
) error {
// Write rollup config to tempdir.
rollupConfigPath := filepath.Join(workDir, "rollup.json")
ser, err := json.Marshal(env.sd.RollupCfg)
ser, err := json.Marshal(env.Sd.RollupCfg)
require.NoError(t, err)
require.NoError(t, os.WriteFile(rollupConfigPath, ser, fs.ModePerm))
......
......@@ -48,6 +48,86 @@ func runSequenceWindowExpireTest(gt *testing.T, testCfg *helpers.TestCfg[any]) {
env.RunFaultProofProgram(t, l2SafeHead.Number.Uint64()/2, testCfg.CheckResult, testCfg.InputParams...)
}
// Runs a that proves a block in a chain where the batcher opens a channel, the sequence window expires, and then the
// batcher attempts to close the channel afterwards.
func runSequenceWindowExpire_ChannelCloseAfterWindowExpiry_Test(gt *testing.T, testCfg *helpers.TestCfg[any]) {
t := actionsHelpers.NewDefaultTesting(gt)
tp := helpers.NewTestParams()
env := helpers.NewL2FaultProofEnv(t, testCfg, tp, helpers.NewBatcherCfg())
// Mine 2 empty blocks on L2.
for i := 0; i < 2; i++ {
env.Sequencer.ActL2StartBlock(t)
env.Alice.L2.ActResetTxOpts(t)
env.Alice.L2.ActSetTxToAddr(&env.Dp.Addresses.Bob)
env.Alice.L2.ActMakeTx(t)
env.Engine.ActL2IncludeTx(env.Alice.Address())(t)
env.Sequencer.ActL2EndBlock(t)
}
// Open the channel on L1.
env.Batcher.ActL2BatchBuffer(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 first channel frame 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)
// Ensure the safe head is still 0.
l2SafeHead := env.Engine.L2Chain().CurrentSafeBlock()
require.EqualValues(t, 0, l2SafeHead.Number.Uint64())
// Cache the next frame data before expiring the sequence window, but don't submit it yet.
env.Batcher.ActL2BatchBuffer(t)
env.Batcher.ActL2ChannelClose(t)
finalFrame := env.Batcher.ReadNextOutputFrame(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.Miner.ActL1StartBlock(12)(t)
env.Miner.ActL1IncludeTx(env.Alice.Address())(t)
env.Miner.ActL1EndBlock(t)
env.Miner.ActL1SafeNext(t)
env.Miner.ActL1FinalizeNext(t)
}
// Instruct the batcher to closethe channel on L1, after the sequence window + channel timeout has elapsed.
env.Batcher.ActL2BatchSubmitRaw(t, finalFrame)
env.Miner.ActL1StartBlock(12)(t)
env.Miner.ActL1IncludeTxByHash(env.Batcher.LastSubmitted.Hash())(t)
env.Miner.ActL1EndBlock(t)
// Finalize the block with the second channel frame on L1.
env.Miner.ActL1SafeNext(t)
env.Miner.ActL1FinalizeNext(t)
// Ensure the safe head is still 0.
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)
// Ensure the safe head advanced forcefully.
l2SafeHead = env.Engine.L2Chain().CurrentSafeBlock()
require.Greater(t, l2SafeHead.Number.Uint64(), uint64(0))
// Run the FPP on one of the auto-derived blocks.
env.RunFaultProofProgram(t, l2SafeHead.Number.Uint64()/2, testCfg.CheckResult, testCfg.InputParams...)
}
func Test_ProgramAction_SequenceWindowExpired(gt *testing.T) {
matrix := helpers.NewMatrix[any]()
defer matrix.Run(gt)
......@@ -67,4 +147,19 @@ func Test_ProgramAction_SequenceWindowExpired(gt *testing.T) {
helpers.ExpectError(claim.ErrClaimNotValid),
helpers.WithL2Claim(common.HexToHash("0xdeadbeef")),
)
matrix.AddTestCase(
"ChannelCloseAfterWindowExpiry-HonestClaim",
nil,
helpers.LatestForkOnly,
runSequenceWindowExpire_ChannelCloseAfterWindowExpiry_Test,
helpers.ExpectNoError(),
)
matrix.AddTestCase(
"ChannelCloseAfterWindowExpiry-JunkClaim",
nil,
helpers.LatestForkOnly,
runSequenceWindowExpire_ChannelCloseAfterWindowExpiry_Test,
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