-
Notifications
You must be signed in to change notification settings - Fork 3.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(op-e2e): Recover from bad transactions in batch test (#12039)
* feat(op-e2e): Recover from bad transactions in batch test * fix * clean * naming nit
- Loading branch information
Showing
3 changed files
with
199 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
package proofs | ||
|
||
import ( | ||
"testing" | ||
|
||
actionsHelpers "github.com/ethereum-optimism/optimism/op-e2e/actions/helpers" | ||
"github.com/ethereum-optimism/optimism/op-e2e/actions/proofs/helpers" | ||
"github.com/ethereum-optimism/optimism/op-program/client/claim" | ||
"github.com/ethereum/go-ethereum/common" | ||
"github.com/ethereum/go-ethereum/core/types" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func runBadTxInBatchTest(gt *testing.T, testCfg *helpers.TestCfg[any]) { | ||
t := actionsHelpers.NewDefaultTesting(gt) | ||
env := helpers.NewL2FaultProofEnv(t, testCfg, helpers.NewTestParams(), helpers.NewBatcherCfg()) | ||
|
||
// Build a block on L2 with 1 tx. | ||
env.Alice.L2.ActResetTxOpts(t) | ||
env.Alice.L2.ActSetTxToAddr(&env.Dp.Addresses.Bob) | ||
env.Alice.L2.ActMakeTx(t) | ||
|
||
env.Sequencer.ActL2StartBlock(t) | ||
env.Engine.ActL2IncludeTx(env.Alice.Address())(t) | ||
env.Sequencer.ActL2EndBlock(t) | ||
env.Alice.L2.ActCheckReceiptStatusOfLastTx(true)(t) | ||
|
||
// Instruct the batcher to submit a faulty channel, with an invalid tx. | ||
err := env.Batcher.BufferWithOpts(t, func(block *types.Block) { | ||
// Replace the tx with one that has a bad signature. | ||
txs := block.Transactions() | ||
newTx, err := txs[1].WithSignature(env.Alice.L2.Signer(), make([]byte, 65)) | ||
txs[1] = newTx | ||
require.NoError(t, err) | ||
}) | ||
require.NoError(t, err) | ||
env.Batcher.ActL2ChannelClose(t) | ||
env.Batcher.ActL2BatchSubmit(t) | ||
|
||
// Include the batcher transaction. | ||
env.Miner.ActL1StartBlock(12)(t) | ||
env.Miner.ActL1IncludeTxByHash(env.Batcher.LastSubmitted.Hash())(t) | ||
env.Miner.ActL1EndBlock(t) | ||
env.Miner.ActL1SafeNext(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 has not advanced - the batch is invalid. | ||
l2SafeHead := env.Engine.L2Chain().CurrentSafeBlock() | ||
require.Equal(t, uint64(0), l2SafeHead.Number.Uint64()) | ||
|
||
// Reset the batcher and submit a valid batch. | ||
env.Batcher.Reset() | ||
env.Batcher.ActSubmitAll(t) | ||
env.Miner.ActL1StartBlock(12)(t) | ||
env.Miner.ActL1IncludeTxByHash(env.Batcher.LastSubmitted.Hash())(t) | ||
env.Miner.ActL1EndBlock(t) | ||
env.Miner.ActL1SafeNext(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 has advanced. | ||
l1Head := env.Miner.L1Chain().CurrentBlock() | ||
l2SafeHead = env.Engine.L2Chain().CurrentSafeBlock() | ||
require.Equal(t, uint64(2), l1Head.Number.Uint64()) | ||
require.Equal(t, uint64(1), l2SafeHead.Number.Uint64()) | ||
|
||
env.RunFaultProofProgram(t, l2SafeHead.Number.Uint64(), testCfg.CheckResult, testCfg.InputParams...) | ||
} | ||
|
||
func runBadTxInBatch_ResubmitBadFirstFrame_Test(gt *testing.T, testCfg *helpers.TestCfg[any]) { | ||
t := actionsHelpers.NewDefaultTesting(gt) | ||
env := helpers.NewL2FaultProofEnv(t, testCfg, helpers.NewTestParams(), helpers.NewBatcherCfg()) | ||
|
||
// Build 2 blocks on L2 with 1 tx each. | ||
for i := 0; i < 2; i++ { | ||
env.Alice.L2.ActResetTxOpts(t) | ||
env.Alice.L2.ActSetTxToAddr(&env.Dp.Addresses.Bob) | ||
env.Alice.L2.ActMakeTx(t) | ||
|
||
env.Sequencer.ActL2StartBlock(t) | ||
env.Engine.ActL2IncludeTx(env.Alice.Address())(t) | ||
env.Sequencer.ActL2EndBlock(t) | ||
env.Alice.L2.ActCheckReceiptStatusOfLastTx(true)(t) | ||
} | ||
|
||
// Instruct the batcher to submit a faulty channel, with an invalid tx in the second block | ||
// within the span batch. | ||
env.Batcher.ActL2BatchBuffer(t) | ||
err := env.Batcher.BufferWithOpts(t, func(block *types.Block) { | ||
// Replace the tx with one that has a bad signature. | ||
txs := block.Transactions() | ||
newTx, err := txs[1].WithSignature(env.Alice.L2.Signer(), make([]byte, 65)) | ||
txs[1] = newTx | ||
require.NoError(t, err) | ||
}) | ||
require.NoError(t, err) | ||
env.Batcher.ActL2ChannelClose(t) | ||
env.Batcher.ActL2BatchSubmit(t) | ||
|
||
// Include the batcher transaction. | ||
env.Miner.ActL1StartBlock(12)(t) | ||
env.Miner.ActL1IncludeTxByHash(env.Batcher.LastSubmitted.Hash())(t) | ||
env.Miner.ActL1EndBlock(t) | ||
env.Miner.ActL1SafeNext(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 has not advanced - the batch is invalid. | ||
l2SafeHead := env.Engine.L2Chain().CurrentSafeBlock() | ||
require.Equal(t, uint64(0), l2SafeHead.Number.Uint64()) | ||
|
||
// Reset the batcher and submit a valid batch. | ||
env.Batcher.Reset() | ||
env.Batcher.ActSubmitAll(t) | ||
env.Miner.ActL1StartBlock(12)(t) | ||
env.Miner.ActL1IncludeTxByHash(env.Batcher.LastSubmitted.Hash())(t) | ||
env.Miner.ActL1EndBlock(t) | ||
env.Miner.ActL1SafeNext(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 has advanced. | ||
l1Head := env.Miner.L1Chain().CurrentBlock() | ||
l2SafeHead = env.Engine.L2Chain().CurrentSafeBlock() | ||
require.Equal(t, uint64(2), l1Head.Number.Uint64()) | ||
require.Equal(t, uint64(2), l2SafeHead.Number.Uint64()) | ||
|
||
env.RunFaultProofProgram(t, l2SafeHead.Number.Uint64()-1, testCfg.CheckResult, testCfg.InputParams...) | ||
} | ||
|
||
func Test_ProgramAction_BadTxInBatch(gt *testing.T) { | ||
matrix := helpers.NewMatrix[any]() | ||
defer matrix.Run(gt) | ||
|
||
matrix.AddTestCase( | ||
"HonestClaim", | ||
nil, | ||
helpers.LatestForkOnly, | ||
runBadTxInBatchTest, | ||
helpers.ExpectNoError(), | ||
) | ||
matrix.AddTestCase( | ||
"JunkClaim", | ||
nil, | ||
helpers.LatestForkOnly, | ||
runBadTxInBatchTest, | ||
helpers.ExpectError(claim.ErrClaimNotValid), | ||
helpers.WithL2Claim(common.HexToHash("0xdeadbeef")), | ||
) | ||
matrix.AddTestCase( | ||
"ResubmitBadFirstFrame-HonestClaim", | ||
nil, | ||
helpers.LatestForkOnly, | ||
runBadTxInBatch_ResubmitBadFirstFrame_Test, | ||
helpers.ExpectNoError(), | ||
) | ||
matrix.AddTestCase( | ||
"ResubmitBadFirstFrame-JunkClaim", | ||
nil, | ||
helpers.LatestForkOnly, | ||
runBadTxInBatch_ResubmitBadFirstFrame_Test, | ||
helpers.ExpectError(claim.ErrClaimNotValid), | ||
helpers.WithL2Claim(common.HexToHash("0xdeadbeef")), | ||
) | ||
} |