Commit e57787ea authored by Sebastian Stammler's avatar Sebastian Stammler Committed by GitHub

op-e2e: Add multi-blob action test (#9774)

parent 8ed039b4
...@@ -33,7 +33,8 @@ func setupEIP4844Test(t Testing, log log.Logger) (*e2eutils.SetupData, *e2eutils ...@@ -33,7 +33,8 @@ func setupEIP4844Test(t Testing, log log.Logger) (*e2eutils.SetupData, *e2eutils
} }
func setupBatcher(t Testing, log log.Logger, sd *e2eutils.SetupData, dp *e2eutils.DeployParams, miner *L1Miner, func setupBatcher(t Testing, log log.Logger, sd *e2eutils.SetupData, dp *e2eutils.DeployParams, miner *L1Miner,
sequencer *L2Sequencer, engine *L2Engine, daType batcherFlags.DataAvailabilityType) *L2Batcher { sequencer *L2Sequencer, engine *L2Engine, daType batcherFlags.DataAvailabilityType,
) *L2Batcher {
return NewL2Batcher(log, sd.RollupCfg, &BatcherCfg{ return NewL2Batcher(log, sd.RollupCfg, &BatcherCfg{
MinL1TxSize: 0, MinL1TxSize: 0,
MaxL1TxSize: 128_000, MaxL1TxSize: 128_000,
...@@ -66,13 +67,51 @@ func TestEIP4844DataAvailability(gt *testing.T) { ...@@ -66,13 +67,51 @@ func TestEIP4844DataAvailability(gt *testing.T) {
// submit all new L2 blocks // submit all new L2 blocks
batcher.ActSubmitAll(t) batcher.ActSubmitAll(t)
batchTx := batcher.LastSubmitted batchTx := batcher.LastSubmitted
require.Equal(t, uint8(types.BlobTxType), batchTx.Type(), "batch tx must be blob-tx")
// new L1 block with L2 batch // new L1 block with L2 batch
miner.ActL1StartBlock(12)(t) miner.ActL1StartBlock(12)(t)
miner.ActL1IncludeTxByHash(batchTx.Hash())(t) miner.ActL1IncludeTxByHash(batchTx.Hash())(t)
miner.ActL1EndBlock(t) miner.ActL1EndBlock(t)
// verifier picks up the L2 chain that was submitted
verifier.ActL1HeadSignal(t)
verifier.ActL2PipelineFull(t)
require.Equal(t, verifier.L2Safe(), sequencer.L2Unsafe(), "verifier syncs from sequencer via L1")
require.NotEqual(t, sequencer.L2Safe(), sequencer.L2Unsafe(), "sequencer has not processed L1 yet")
}
func TestEIP4844MultiBlobs(gt *testing.T) {
t := NewDefaultTesting(gt)
log := testlog.Logger(t, log.LevelDebug)
sd, dp, miner, sequencer, seqEngine, verifier, _ := setupEIP4844Test(t, log)
batcher := setupBatcher(t, log, sd, dp, miner, sequencer, seqEngine, batcherFlags.BlobsType)
sequencer.ActL2PipelineFull(t)
verifier.ActL2PipelineFull(t)
// build empty L1 block
miner.ActEmptyBlock(t)
// finalize it, so the L1 geth blob pool doesn't log errors about missing finality
miner.ActL1SafeNext(t)
miner.ActL1FinalizeNext(t)
// Create L2 blocks, and reference the L1 head as origin
sequencer.ActL1HeadSignal(t)
sequencer.ActBuildToL1Head(t)
// submit all new L2 blocks
batcher.ActSubmitAllMultiBlobs(t, 6)
batchTx := batcher.LastSubmitted
require.Equal(t, uint8(types.BlobTxType), batchTx.Type(), "batch tx must be blob-tx") require.Equal(t, uint8(types.BlobTxType), batchTx.Type(), "batch tx must be blob-tx")
require.Len(t, batchTx.BlobTxSidecar().Blobs, 6)
// new L1 block with L2 batch
miner.ActL1StartBlock(12)(t)
miner.ActL1IncludeTxByHash(batchTx.Hash())(t)
miner.ActL1EndBlock(t)
// verifier picks up the L2 chain that was submitted // verifier picks up the L2 chain that was submitted
verifier.ActL1HeadSignal(t) verifier.ActL1HeadSignal(t)
...@@ -105,14 +144,13 @@ func TestEIP4844DataAvailabilitySwitch(gt *testing.T) { ...@@ -105,14 +144,13 @@ func TestEIP4844DataAvailabilitySwitch(gt *testing.T) {
// submit all new L2 blocks, with legacy calldata DA // submit all new L2 blocks, with legacy calldata DA
oldBatcher.ActSubmitAll(t) oldBatcher.ActSubmitAll(t)
batchTx := oldBatcher.LastSubmitted batchTx := oldBatcher.LastSubmitted
require.Equal(t, uint8(types.DynamicFeeTxType), batchTx.Type(), "batch tx must be eip1559 tx")
// new L1 block with L2 batch // new L1 block with L2 batch
miner.ActL1StartBlock(12)(t) miner.ActL1StartBlock(12)(t)
miner.ActL1IncludeTxByHash(batchTx.Hash())(t) miner.ActL1IncludeTxByHash(batchTx.Hash())(t)
miner.ActL1EndBlock(t) miner.ActL1EndBlock(t)
require.Equal(t, uint8(types.DynamicFeeTxType), batchTx.Type(), "batch tx must be eip1559 tx")
// verifier picks up the L2 chain that was submitted // verifier picks up the L2 chain that was submitted
verifier.ActL1HeadSignal(t) verifier.ActL1HeadSignal(t)
verifier.ActL2PipelineFull(t) verifier.ActL2PipelineFull(t)
......
...@@ -318,6 +318,85 @@ func (s *L2Batcher) ActL2BatchSubmit(t Testing, txOpts ...func(tx *types.Dynamic ...@@ -318,6 +318,85 @@ func (s *L2Batcher) ActL2BatchSubmit(t Testing, txOpts ...func(tx *types.Dynamic
s.LastSubmitted = tx s.LastSubmitted = tx
} }
func (s *L2Batcher) ActL2BatchSubmitMultiBlob(t Testing, numBlobs int) {
if s.l2BatcherCfg.DataAvailabilityType != batcherFlags.BlobsType {
t.InvalidAction("ActL2BatchSubmitMultiBlob only available for Blobs DA type")
return
} else if numBlobs > 6 || numBlobs < 1 {
t.InvalidAction("invalid number of blobs %d, must be within [1,6]", numBlobs)
}
// Don't run this action if there's no data to submit
if s.l2ChannelOut == nil {
t.InvalidAction("need to buffer data first, cannot batch submit with empty buffer")
return
}
// Collect the output frames into blobs
blobs := make([]*eth.Blob, numBlobs)
for i := 0; i < numBlobs; i++ {
data := new(bytes.Buffer)
data.WriteByte(derive.DerivationVersion0)
// write only a few bytes to all but the last blob
l := uint64(derive.FrameV0OverHeadSize + 4) // 4 bytes content
if i == numBlobs-1 {
// write remaining channel to last frame
// subtract one, to account for the version byte
l = s.l2BatcherCfg.MaxL1TxSize - 1
}
if _, err := s.l2ChannelOut.OutputFrame(data, l); err == io.EOF {
s.l2Submitting = false
if i < numBlobs-1 {
t.Fatalf("failed to fill up %d blobs, only filled %d", numBlobs, i+1)
}
s.l2ChannelOut = nil
} else if err != nil {
s.l2Submitting = false
t.Fatalf("failed to output channel data to frame: %v", err)
}
blobs[i] = new(eth.Blob)
require.NoError(t, blobs[i].FromData(data.Bytes()), "must turn data into blob")
}
nonce, err := s.l1.PendingNonceAt(t.Ctx(), s.batcherAddr)
require.NoError(t, err, "need batcher nonce")
gasTipCap := big.NewInt(2 * params.GWei)
pendingHeader, err := s.l1.HeaderByNumber(t.Ctx(), big.NewInt(-1))
require.NoError(t, err, "need l1 pending header for gas price estimation")
gasFeeCap := new(big.Int).Add(gasTipCap, new(big.Int).Mul(pendingHeader.BaseFee, big.NewInt(2)))
sidecar, blobHashes, err := txmgr.MakeSidecar(blobs)
require.NoError(t, err)
require.NotNil(t, pendingHeader.ExcessBlobGas, "need L1 header with 4844 properties")
blobBaseFee := eip4844.CalcBlobFee(*pendingHeader.ExcessBlobGas)
blobFeeCap := new(uint256.Int).Mul(uint256.NewInt(2), uint256.MustFromBig(blobBaseFee))
if blobFeeCap.Lt(uint256.NewInt(params.GWei)) { // ensure we meet 1 gwei geth tx-pool minimum
blobFeeCap = uint256.NewInt(params.GWei)
}
txData := &types.BlobTx{
To: s.rollupCfg.BatchInboxAddress,
Data: nil,
Gas: params.TxGas, // intrinsic gas only
BlobHashes: blobHashes,
Sidecar: sidecar,
ChainID: uint256.MustFromBig(s.rollupCfg.L1ChainID),
GasTipCap: uint256.MustFromBig(gasTipCap),
GasFeeCap: uint256.MustFromBig(gasFeeCap),
BlobFeeCap: blobFeeCap,
Value: uint256.NewInt(0),
Nonce: nonce,
}
tx, err := types.SignNewTx(s.l2BatcherCfg.BatcherKey, s.l1Signer, txData)
require.NoError(t, err, "need to sign tx")
err = s.l1.SendTransaction(t.Ctx(), tx)
require.NoError(t, err, "need to send tx")
s.LastSubmitted = tx
}
// ActL2BatchSubmitGarbage constructs a malformed channel frame and submits it to the // ActL2BatchSubmitGarbage constructs a malformed channel frame and submits it to the
// batch inbox. This *should* cause the batch inbox to reject the blocks // batch inbox. This *should* cause the batch inbox to reject the blocks
// encoded within the frame, even if the blocks themselves are valid. // encoded within the frame, even if the blocks themselves are valid.
...@@ -414,3 +493,9 @@ func (s *L2Batcher) ActSubmitAll(t Testing) { ...@@ -414,3 +493,9 @@ func (s *L2Batcher) ActSubmitAll(t Testing) {
s.ActL2ChannelClose(t) s.ActL2ChannelClose(t)
s.ActL2BatchSubmit(t) s.ActL2BatchSubmit(t)
} }
func (s *L2Batcher) ActSubmitAllMultiBlobs(t Testing, numBlobs int) {
s.ActBufferAll(t)
s.ActL2ChannelClose(t)
s.ActL2BatchSubmitMultiBlob(t, numBlobs)
}
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