Commit 22ef8dbc authored by protolambda's avatar protolambda Committed by GitHub

op-e2e: 4844 DA support action-tests (#9104)

* op-e2e: 4844 DA support action-tests

* op-service: MakeSidecar unit-test

* op-e2e: implement fixes for reviews

* op-e2e: action test default batcher config update
parent 1a94b1dc
package actions
import (
"testing"
"github.com/stretchr/testify/require"
"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"
batcherFlags "github.com/ethereum-optimism/optimism/op-batcher/flags"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils"
"github.com/ethereum-optimism/optimism/op-node/rollup/sync"
"github.com/ethereum-optimism/optimism/op-service/testlog"
)
func setupEIP4844Test(t Testing, log log.Logger) (*e2eutils.SetupData, *e2eutils.DeployParams, *L1Miner, *L2Sequencer, *L2Engine, *L2Verifier, *L2Engine) {
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)
miner, seqEngine, sequencer := setupSequencerTest(t, sd, log)
miner.ActL1SetFeeRecipient(common.Address{'A'})
sequencer.ActL2PipelineFull(t)
verifEngine, verifier := setupVerifier(t, sd, log, miner.L1Client(t, sd.RollupCfg), miner.BlobStore(), &sync.Config{})
return sd, dp, miner, sequencer, seqEngine, verifier, verifEngine
}
func setupBatcher(t Testing, log log.Logger, sd *e2eutils.SetupData, dp *e2eutils.DeployParams, miner *L1Miner,
sequencer *L2Sequencer, engine *L2Engine, daType batcherFlags.DataAvailabilityType) *L2Batcher {
return NewL2Batcher(log, sd.RollupCfg, &BatcherCfg{
MinL1TxSize: 0,
MaxL1TxSize: 128_000,
BatcherKey: dp.Secrets.Batcher,
DataAvailabilityType: daType,
}, sequencer.RollupClient(), miner.EthClient(), engine.EthClient(), engine.EngineClient(t, sd.RollupCfg))
}
func TestEIP4844DataAvailability(gt *testing.T) {
t := NewDefaultTesting(gt)
log := testlog.Logger(t, log.LvlDebug)
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.ActSubmitAll(t)
batchTx := batcher.LastSubmitted
// new L1 block with L2 batch
miner.ActL1StartBlock(12)(t)
miner.ActL1IncludeTxByHash(batchTx.Hash())(t)
miner.ActL1EndBlock(t)
require.Equal(t, uint8(types.BlobTxType), batchTx.Type(), "batch tx must be blob-tx")
// 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 TestEIP4844DataAvailabilitySwitch(gt *testing.T) {
t := NewDefaultTesting(gt)
log := testlog.Logger(t, log.LvlDebug)
sd, dp, miner, sequencer, seqEngine, verifier, _ := setupEIP4844Test(t, log)
oldBatcher := setupBatcher(t, log, sd, dp, miner, sequencer, seqEngine, batcherFlags.CalldataType)
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, with legacy calldata DA
oldBatcher.ActSubmitAll(t)
batchTx := oldBatcher.LastSubmitted
// new L1 block with L2 batch
miner.ActL1StartBlock(12)(t)
miner.ActL1IncludeTxByHash(batchTx.Hash())(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.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")
newBatcher := setupBatcher(t, log, sd, dp, miner, sequencer, seqEngine, batcherFlags.BlobsType)
// build empty L1 block
miner.ActEmptyBlock(t)
// Create L2 blocks, and reference the L1 head as origin
sequencer.ActL1HeadSignal(t)
sequencer.ActBuildToL1Head(t)
// submit all new L2 blocks, now with Blobs DA!
newBatcher.ActSubmitAll(t)
batchTx = newBatcher.LastSubmitted
// new L1 block with L2 batch
miner.ActL1StartBlock(12)(t)
miner.ActL1IncludeTxByHash(batchTx.Hash())(t)
miner.ActL1EndBlock(t)
require.Equal(t, uint8(types.BlobTxType), batchTx.Type(), "batch tx must be blob-tx")
// 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")
}
......@@ -3,20 +3,28 @@ package actions
import (
"math/big"
"github.com/stretchr/testify/require"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus/misc/eip1559"
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/trie"
"github.com/stretchr/testify/require"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils"
"github.com/ethereum-optimism/optimism/op-node/rollup/derive"
"github.com/ethereum-optimism/optimism/op-service/eth"
)
// L1Miner wraps a L1Replica with instrumented block building ability.
type L1Miner struct {
L1Replica
blobStore *e2eutils.BlobsStore
// L1 block building preferences
prefCoinbase common.Address
......@@ -29,6 +37,8 @@ type L1Miner struct {
l1Receipts []*types.Receipt // collect receipts of ongoing building
l1Building bool
l1TxFailed []*types.Transaction // log of failed transactions which could not be included
// sidecars that come with the transactions
l1BuildingBlobSidecars []*types.BlobTxSidecar
}
// NewL1Miner creates a new L1Replica that can also build blocks.
......@@ -36,9 +46,14 @@ func NewL1Miner(t Testing, log log.Logger, genesis *core.Genesis) *L1Miner {
rep := NewL1Replica(t, log, genesis)
return &L1Miner{
L1Replica: *rep,
blobStore: e2eutils.NewBlobStore(),
}
}
func (s *L1Miner) BlobStore() derive.L1BlobsFetcher {
return s.blobStore
}
// ActL1StartBlock returns an action to build a new L1 block on top of the head block,
// with timeDelta added to the head block time.
func (s *L1Miner) ActL1StartBlock(timeDelta uint64) Action {
......@@ -77,11 +92,9 @@ func (s *L1Miner) ActL1StartBlock(timeDelta uint64) Action {
header.WithdrawalsHash = &types.EmptyWithdrawalsHash
}
if s.l1Cfg.Config.IsCancun(header.Number, header.Time) {
var root common.Hash
var zero uint64
header.BlobGasUsed = &zero
header.ExcessBlobGas = &zero
header.ParentBeaconRoot = &root
header.BlobGasUsed = new(uint64)
header.ExcessBlobGas = new(uint64)
header.ParentBeaconRoot = new(common.Hash)
}
s.l1Building = true
......@@ -90,6 +103,7 @@ func (s *L1Miner) ActL1StartBlock(timeDelta uint64) Action {
s.l1Receipts = make([]*types.Receipt, 0)
s.l1Transactions = make([]*types.Transaction, 0)
s.pendingIndices = make(map[common.Address]uint64)
s.l1BuildingBlobSidecars = make([]*types.BlobTxSidecar, 0)
s.l1GasPool = new(core.GasPool).AddGas(header.GasLimit)
}
......@@ -111,6 +125,22 @@ func (s *L1Miner) ActL1IncludeTx(from common.Address) Action {
}
}
// ActL1IncludeTxByHash tries to include a tx by tx-hash.
func (s *L1Miner) ActL1IncludeTxByHash(txHash common.Hash) Action {
return func(t Testing) {
if !s.l1Building {
t.InvalidAction("no tx inclusion when not building l1 block")
return
}
tx := s.eth.TxPool().Get(txHash)
require.NotNil(t, tx, "cannot find tx %s", txHash)
s.IncludeTx(t, tx)
from, err := s.l1Signer.Sender(tx)
require.NoError(t, err)
s.pendingIndices[from] = s.pendingIndices[from] + 1 // won't retry the tx
}
}
func (s *L1Miner) IncludeTx(t Testing, tx *types.Transaction) {
from, err := s.l1Signer.Sender(tx)
require.NoError(t, err)
......@@ -124,13 +154,21 @@ func (s *L1Miner) IncludeTx(t Testing, tx *types.Transaction) {
}
s.l1BuildingState.SetTxContext(tx.Hash(), len(s.l1Transactions))
receipt, err := core.ApplyTransaction(s.l1Cfg.Config, s.l1Chain, &s.l1BuildingHeader.Coinbase,
s.l1GasPool, s.l1BuildingState, s.l1BuildingHeader, tx, &s.l1BuildingHeader.GasUsed, *s.l1Chain.GetVMConfig())
s.l1GasPool, s.l1BuildingState, s.l1BuildingHeader, tx.WithoutBlobTxSidecar(), &s.l1BuildingHeader.GasUsed, *s.l1Chain.GetVMConfig())
if err != nil {
s.l1TxFailed = append(s.l1TxFailed, tx)
t.Fatalf("failed to apply transaction to L1 block (tx %d): %v", len(s.l1Transactions), err)
}
s.l1Receipts = append(s.l1Receipts, receipt)
s.l1Transactions = append(s.l1Transactions, tx)
s.l1Transactions = append(s.l1Transactions, tx.WithoutBlobTxSidecar())
if tx.Type() == types.BlobTxType {
require.True(t, s.l1Cfg.Config.IsCancun(s.l1BuildingHeader.Number, s.l1BuildingHeader.Time), "L1 must be cancun to process blob tx")
sidecar := tx.BlobTxSidecar()
if sidecar != nil {
s.l1BuildingBlobSidecars = append(s.l1BuildingBlobSidecars, sidecar)
}
*s.l1BuildingHeader.BlobGasUsed += receipt.BlobGasUsed
}
}
func (s *L1Miner) ActL1SetFeeRecipient(coinbase common.Address) {
......@@ -154,6 +192,19 @@ func (s *L1Miner) ActL1EndBlock(t Testing) {
if s.l1Cfg.Config.IsShanghai(s.l1BuildingHeader.Number, s.l1BuildingHeader.Time) {
block = block.WithWithdrawals(make([]*types.Withdrawal, 0))
}
if s.l1Cfg.Config.IsCancun(s.l1BuildingHeader.Number, s.l1BuildingHeader.Time) {
parent := s.l1Chain.GetHeaderByHash(s.l1BuildingHeader.ParentHash)
var (
parentExcessBlobGas uint64
parentBlobGasUsed uint64
)
if parent.ExcessBlobGas != nil {
parentExcessBlobGas = *parent.ExcessBlobGas
parentBlobGasUsed = *parent.BlobGasUsed
}
excessBlobGas := eip4844.CalcExcessBlobGas(parentExcessBlobGas, parentBlobGasUsed)
s.l1BuildingHeader.ExcessBlobGas = &excessBlobGas
}
// Write state changes to db
root, err := s.l1BuildingState.Commit(s.l1BuildingHeader.Number.Uint64(), s.l1Cfg.Config.IsEIP158(s.l1BuildingHeader.Number))
......@@ -163,7 +214,13 @@ func (s *L1Miner) ActL1EndBlock(t Testing) {
if err := s.l1BuildingState.Database().TrieDB().Commit(root, false); err != nil {
t.Fatalf("l1 trie write error: %v", err)
}
// now that the blob txs are in a canonical block, flush them to the blob store
for _, sidecar := range s.l1BuildingBlobSidecars {
for i, h := range sidecar.BlobHashes() {
blob := (*eth.Blob)(&sidecar.Blobs[i])
s.blobStore.StoreBlob(block.Hash(), h, blob)
}
}
_, err = s.l1Chain.InsertChain(types.Blocks{block})
if err != nil {
t.Fatalf("failed to insert block into l1 chain")
......
......@@ -8,18 +8,24 @@ import (
"io"
"math/big"
"github.com/holiman/uint256"
"github.com/stretchr/testify/require"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"github.com/stretchr/testify/require"
"github.com/ethereum-optimism/optimism/op-batcher/compressor"
batcherFlags "github.com/ethereum-optimism/optimism/op-batcher/flags"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils"
"github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum-optimism/optimism/op-node/rollup/derive"
"github.com/ethereum-optimism/optimism/op-service/eth"
"github.com/ethereum-optimism/optimism/op-service/txmgr"
)
type SyncStatusAPI interface {
......@@ -47,6 +53,17 @@ type BatcherCfg struct {
ForceSubmitSingularBatch bool
ForceSubmitSpanBatch bool
DataAvailabilityType batcherFlags.DataAvailabilityType
}
func DefaultBatcherCfg(dp *e2eutils.DeployParams) *BatcherCfg {
return &BatcherCfg{
MinL1TxSize: 0,
MaxL1TxSize: 128_000,
BatcherKey: dp.Secrets.Batcher,
DataAvailabilityType: batcherFlags.CalldataType,
}
}
type L2BlockRefs interface {
......@@ -76,6 +93,8 @@ type L2Batcher struct {
l2SubmittedBlock eth.L2BlockRef
l2BatcherCfg *BatcherCfg
batcherAddr common.Address
LastSubmitted *types.Transaction
}
func NewL2Batcher(log log.Logger, rollupCfg *rollup.Config, batcherCfg *BatcherCfg, api SyncStatusAPI, l1 L1TxAPI, l2 BlocksAPI, engCl L2BlockRefs) *L2Batcher {
......@@ -220,26 +239,58 @@ func (s *L2Batcher) ActL2BatchSubmit(t Testing, txOpts ...func(tx *types.Dynamic
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)))
rawTx := &types.DynamicFeeTx{
ChainID: s.rollupCfg.L1ChainID,
Nonce: nonce,
To: &s.rollupCfg.BatchInboxAddress,
GasTipCap: gasTipCap,
GasFeeCap: gasFeeCap,
Data: data.Bytes(),
}
for _, opt := range txOpts {
opt(rawTx)
var txData types.TxData
if s.l2BatcherCfg.DataAvailabilityType == batcherFlags.CalldataType {
rawTx := &types.DynamicFeeTx{
ChainID: s.rollupCfg.L1ChainID,
Nonce: nonce,
To: &s.rollupCfg.BatchInboxAddress,
GasTipCap: gasTipCap,
GasFeeCap: gasFeeCap,
Data: data.Bytes(),
}
for _, opt := range txOpts {
opt(rawTx)
}
gas, err := core.IntrinsicGas(rawTx.Data, nil, false, true, true, false)
require.NoError(t, err, "need to compute intrinsic gas")
rawTx.Gas = gas
txData = rawTx
} else if s.l2BatcherCfg.DataAvailabilityType == batcherFlags.BlobsType {
var b eth.Blob
require.NoError(t, b.FromData(data.Bytes()), "must turn data into blob")
sidecar, blobHashes, err := txmgr.MakeSidecar([]*eth.Blob{&b})
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,
}
} else {
t.Fatalf("unrecognized DA type: %q", string(s.l2BatcherCfg.DataAvailabilityType))
}
gas, err := core.IntrinsicGas(rawTx.Data, nil, false, true, true, false)
require.NoError(t, err, "need to compute intrinsic gas")
rawTx.Gas = gas
tx, err := types.SignNewTx(s.l2BatcherCfg.BatcherKey, s.l1Signer, rawTx)
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
......
......@@ -14,6 +14,7 @@ import (
"github.com/ethereum/go-ethereum/params"
"github.com/stretchr/testify/require"
batcherFlags "github.com/ethereum-optimism/optimism/op-batcher/flags"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils"
"github.com/ethereum-optimism/optimism/op-node/rollup/derive"
"github.com/ethereum-optimism/optimism/op-node/rollup/sync"
......@@ -84,14 +85,11 @@ func NormalBatcher(gt *testing.T, deltaTimeOffset *hexutil.Uint64) {
sd := e2eutils.Setup(t, dp, defaultAlloc)
log := testlog.Logger(t, log.LvlDebug)
miner, seqEngine, sequencer := setupSequencerTest(t, sd, log)
verifEngine, verifier := setupVerifier(t, sd, log, miner.L1Client(t, sd.RollupCfg), &sync.Config{})
verifEngine, verifier := setupVerifier(t, sd, log, miner.L1Client(t, sd.RollupCfg), miner.BlobStore(), &sync.Config{})
rollupSeqCl := sequencer.RollupClient()
batcher := NewL2Batcher(log, sd.RollupCfg, &BatcherCfg{
MinL1TxSize: 0,
MaxL1TxSize: 128_000,
BatcherKey: dp.Secrets.Batcher,
}, rollupSeqCl, miner.EthClient(), seqEngine.EthClient(), seqEngine.EngineClient(t, sd.RollupCfg))
batcher := NewL2Batcher(log, sd.RollupCfg, DefaultBatcherCfg(dp),
rollupSeqCl, miner.EthClient(), seqEngine.EthClient(), seqEngine.EngineClient(t, sd.RollupCfg))
// Alice makes a L2 tx
cl := seqEngine.EthClient()
......@@ -186,11 +184,8 @@ func L2Finalization(gt *testing.T, deltaTimeOffset *hexutil.Uint64) {
require.Equal(t, uint64(1), sequencer.SyncStatus().FinalizedL1.Number)
require.Equal(t, uint64(0), sequencer.SyncStatus().FinalizedL2.Number, "L2 block has to be included on L1 before it can be finalized")
batcher := NewL2Batcher(log, sd.RollupCfg, &BatcherCfg{
MinL1TxSize: 0,
MaxL1TxSize: 128_000,
BatcherKey: dp.Secrets.Batcher,
}, sequencer.RollupClient(), miner.EthClient(), engine.EthClient(), engine.EngineClient(t, sd.RollupCfg))
batcher := NewL2Batcher(log, sd.RollupCfg, DefaultBatcherCfg(dp),
sequencer.RollupClient(), miner.EthClient(), engine.EthClient(), engine.EngineClient(t, sd.RollupCfg))
heightToSubmit := sequencer.SyncStatus().UnsafeL2.Number
......@@ -273,11 +268,8 @@ func L2FinalizationWithSparseL1(gt *testing.T, deltaTimeOffset *hexutil.Uint64)
startStatus := sequencer.SyncStatus()
require.Less(t, startStatus.SafeL2.Number, startStatus.UnsafeL2.Number, "sequencer has unsafe L2 block")
batcher := NewL2Batcher(log, sd.RollupCfg, &BatcherCfg{
MinL1TxSize: 0,
MaxL1TxSize: 128_000,
BatcherKey: dp.Secrets.Batcher,
}, sequencer.RollupClient(), miner.EthClient(), engine.EthClient(), engine.EngineClient(t, sd.RollupCfg))
batcher := NewL2Batcher(log, sd.RollupCfg, DefaultBatcherCfg(dp),
sequencer.RollupClient(), miner.EthClient(), engine.EthClient(), engine.EngineClient(t, sd.RollupCfg))
batcher.ActSubmitAll(t)
// include in L1
......@@ -325,13 +317,9 @@ func GarbageBatch(gt *testing.T, deltaTimeOffset *hexutil.Uint64) {
log := testlog.Logger(t, log.LvlError)
miner, engine, sequencer := setupSequencerTest(t, sd, log)
_, verifier := setupVerifier(t, sd, log, miner.L1Client(t, sd.RollupCfg), &sync.Config{})
_, verifier := setupVerifier(t, sd, log, miner.L1Client(t, sd.RollupCfg), miner.BlobStore(), &sync.Config{})
batcherCfg := &BatcherCfg{
MinL1TxSize: 0,
MaxL1TxSize: 128_000,
BatcherKey: dp.Secrets.Batcher,
}
batcherCfg := DefaultBatcherCfg(dp)
if garbageKind == MALFORM_RLP || garbageKind == INVALID_COMPRESSION {
// If the garbage kind is `INVALID_COMPRESSION` or `MALFORM_RLP`, use the `actions` packages
......@@ -409,13 +397,10 @@ func ExtendedTimeWithoutL1Batches(gt *testing.T, deltaTimeOffset *hexutil.Uint64
log := testlog.Logger(t, log.LvlError)
miner, engine, sequencer := setupSequencerTest(t, sd, log)
_, verifier := setupVerifier(t, sd, log, miner.L1Client(t, sd.RollupCfg), &sync.Config{})
_, verifier := setupVerifier(t, sd, log, miner.L1Client(t, sd.RollupCfg), miner.BlobStore(), &sync.Config{})
batcher := NewL2Batcher(log, sd.RollupCfg, &BatcherCfg{
MinL1TxSize: 0,
MaxL1TxSize: 128_000,
BatcherKey: dp.Secrets.Batcher,
}, sequencer.RollupClient(), miner.EthClient(), engine.EthClient(), engine.EngineClient(t, sd.RollupCfg))
batcher := NewL2Batcher(log, sd.RollupCfg, DefaultBatcherCfg(dp),
sequencer.RollupClient(), miner.EthClient(), engine.EthClient(), engine.EngineClient(t, sd.RollupCfg))
sequencer.ActL2PipelineFull(t)
verifier.ActL2PipelineFull(t)
......@@ -468,12 +453,13 @@ func BigL2Txs(gt *testing.T, deltaTimeOffset *hexutil.Uint64) {
log := testlog.Logger(t, log.LvlInfo)
miner, engine, sequencer := setupSequencerTest(t, sd, log)
_, verifier := setupVerifier(t, sd, log, miner.L1Client(t, sd.RollupCfg), &sync.Config{})
_, verifier := setupVerifier(t, sd, log, miner.L1Client(t, sd.RollupCfg), miner.BlobStore(), &sync.Config{})
batcher := NewL2Batcher(log, sd.RollupCfg, &BatcherCfg{
MinL1TxSize: 0,
MaxL1TxSize: 40_000, // try a small batch size, to force the data to be split between more frames
BatcherKey: dp.Secrets.Batcher,
MinL1TxSize: 0,
MaxL1TxSize: 40_000, // try a small batch size, to force the data to be split between more frames
BatcherKey: dp.Secrets.Batcher,
DataAvailabilityType: batcherFlags.CalldataType,
}, sequencer.RollupClient(), miner.EthClient(), engine.EthClient(), engine.EngineClient(t, sd.RollupCfg))
sequencer.ActL2PipelineFull(t)
......
......@@ -48,11 +48,8 @@ func RunProposerTest(gt *testing.T, deltaTimeOffset *hexutil.Uint64) {
miner, seqEngine, sequencer := setupSequencerTest(t, sd, log)
rollupSeqCl := sequencer.RollupClient()
batcher := NewL2Batcher(log, sd.RollupCfg, &BatcherCfg{
MinL1TxSize: 0,
MaxL1TxSize: 128_000,
BatcherKey: dp.Secrets.Batcher,
}, rollupSeqCl, miner.EthClient(), seqEngine.EthClient(), seqEngine.EngineClient(t, sd.RollupCfg))
batcher := NewL2Batcher(log, sd.RollupCfg, DefaultBatcherCfg(dp),
rollupSeqCl, miner.EthClient(), seqEngine.EthClient(), seqEngine.EngineClient(t, sd.RollupCfg))
proposer := NewL2Proposer(t, log, &ProposerCfg{
OutputOracleAddr: &sd.DeploymentsL1.L2OutputOracleProxy,
......
......@@ -30,18 +30,6 @@ func (m *MockL1OriginSelector) FindL1Origin(ctx context.Context, l2Head eth.L2Bl
return m.actual.FindL1Origin(ctx, l2Head)
}
// emptyL1BlobsFetcher is a no-op blobs provider. The actions test batcher currently only supports using calldata.
type emptyL1BlobsFetcher struct {
t Testing
}
var _ derive.L1BlobsFetcher = &emptyL1BlobsFetcher{}
func (e *emptyL1BlobsFetcher) GetBlobs(ctx context.Context, ref eth.L1BlockRef, hashes []eth.IndexedBlobHash) ([]*eth.Blob, error) {
e.t.Fatal("actions test do not support blobs")
return nil, nil
}
// L2Sequencer is an actor that functions like a rollup node,
// without the full P2P/API/Node stack, but just the derivation state, and simplified driver with sequencing ability.
type L2Sequencer struct {
......@@ -54,9 +42,9 @@ type L2Sequencer struct {
mockL1OriginSelector *MockL1OriginSelector
}
func NewL2Sequencer(t Testing, log log.Logger, l1 derive.L1Fetcher, eng L2API, cfg *rollup.Config, seqConfDepth uint64) *L2Sequencer {
mockBlobFetcher := &emptyL1BlobsFetcher{t: t}
ver := NewL2Verifier(t, log, l1, mockBlobFetcher, eng, cfg, &sync.Config{})
func NewL2Sequencer(t Testing, log log.Logger, l1 derive.L1Fetcher, blobSrc derive.L1BlobsFetcher,
eng L2API, cfg *rollup.Config, seqConfDepth uint64) *L2Sequencer {
ver := NewL2Verifier(t, log, l1, blobSrc, eng, cfg, &sync.Config{})
attrBuilder := derive.NewFetchingAttributesBuilder(cfg, l1, eng)
seqConfDepthL1 := driver.NewConfDepth(seqConfDepth, ver.l1State.L1Head, l1)
l1OriginSelector := &MockL1OriginSelector{
......
......@@ -47,7 +47,7 @@ func setupSequencerTest(t Testing, sd *e2eutils.SetupData, log log.Logger) (*L1M
l2Cl, err := sources.NewEngineClient(engine.RPCClient(), log, nil, sources.EngineClientDefaultConfig(sd.RollupCfg))
require.NoError(t, err)
sequencer := NewL2Sequencer(t, log, l1F, l2Cl, sd.RollupCfg, 0)
sequencer := NewL2Sequencer(t, log, l1F, miner.BlobStore(), l2Cl, sd.RollupCfg, 0)
return miner, engine, sequencer
}
......
......@@ -13,19 +13,18 @@ import (
"github.com/ethereum-optimism/optimism/op-service/testlog"
)
func setupVerifier(t Testing, sd *e2eutils.SetupData, log log.Logger, l1F derive.L1Fetcher, syncCfg *sync.Config) (*L2Engine, *L2Verifier) {
func setupVerifier(t Testing, sd *e2eutils.SetupData, log log.Logger, l1F derive.L1Fetcher, blobSrc derive.L1BlobsFetcher, syncCfg *sync.Config) (*L2Engine, *L2Verifier) {
jwtPath := e2eutils.WriteDefaultJWT(t)
engine := NewL2Engine(t, log, sd.L2Cfg, sd.RollupCfg.Genesis.L1, jwtPath, EngineWithP2P())
engCl := engine.EngineClient(t, sd.RollupCfg)
mockBlobFetcher := &emptyL1BlobsFetcher{t: t}
verifier := NewL2Verifier(t, log, l1F, mockBlobFetcher, engCl, sd.RollupCfg, syncCfg)
verifier := NewL2Verifier(t, log, l1F, blobSrc, engCl, sd.RollupCfg, syncCfg)
return engine, verifier
}
func setupVerifierOnlyTest(t Testing, sd *e2eutils.SetupData, log log.Logger) (*L1Miner, *L2Engine, *L2Verifier) {
miner := NewL1Miner(t, log, sd.L1Cfg)
l1Cl := miner.L1Client(t, sd.RollupCfg)
engine, verifier := setupVerifier(t, sd, log, l1Cl, &sync.Config{})
engine, verifier := setupVerifier(t, sd, log, l1Cl, miner.BlobStore(), &sync.Config{})
return miner, engine, verifier
}
......
......@@ -36,13 +36,10 @@ func setupReorgTestActors(t Testing, dp *e2eutils.DeployParams, sd *e2eutils.Set
miner, seqEngine, sequencer := setupSequencerTest(t, sd, log)
miner.ActL1SetFeeRecipient(common.Address{'A'})
sequencer.ActL2PipelineFull(t)
verifEngine, verifier := setupVerifier(t, sd, log, miner.L1Client(t, sd.RollupCfg), &sync.Config{})
verifEngine, verifier := setupVerifier(t, sd, log, miner.L1Client(t, sd.RollupCfg), miner.BlobStore(), &sync.Config{})
rollupSeqCl := sequencer.RollupClient()
batcher := NewL2Batcher(log, sd.RollupCfg, &BatcherCfg{
MinL1TxSize: 0,
MaxL1TxSize: 128_000,
BatcherKey: dp.Secrets.Batcher,
}, rollupSeqCl, miner.EthClient(), seqEngine.EthClient(), seqEngine.EngineClient(t, sd.RollupCfg))
batcher := NewL2Batcher(log, sd.RollupCfg, DefaultBatcherCfg(dp),
rollupSeqCl, miner.EthClient(), seqEngine.EthClient(), seqEngine.EngineClient(t, sd.RollupCfg))
return sd, dp, miner, sequencer, seqEngine, verifier, verifEngine, batcher
}
......@@ -620,13 +617,10 @@ func RestartOpGeth(gt *testing.T, deltaTimeOffset *hexutil.Uint64) {
engRpc := &rpcWrapper{seqEng.RPCClient()}
l2Cl, err := sources.NewEngineClient(engRpc, log, nil, sources.EngineClientDefaultConfig(sd.RollupCfg))
require.NoError(t, err)
sequencer := NewL2Sequencer(t, log, l1F, l2Cl, sd.RollupCfg, 0)
sequencer := NewL2Sequencer(t, log, l1F, miner.BlobStore(), l2Cl, sd.RollupCfg, 0)
batcher := NewL2Batcher(log, sd.RollupCfg, &BatcherCfg{
MinL1TxSize: 0,
MaxL1TxSize: 128_000,
BatcherKey: dp.Secrets.Batcher,
}, sequencer.RollupClient(), miner.EthClient(), seqEng.EthClient(), seqEng.EngineClient(t, sd.RollupCfg))
batcher := NewL2Batcher(log, sd.RollupCfg, DefaultBatcherCfg(dp),
sequencer.RollupClient(), miner.EthClient(), seqEng.EthClient(), seqEng.EngineClient(t, sd.RollupCfg))
// start
sequencer.ActL2PipelineFull(t)
......@@ -711,12 +705,9 @@ func ConflictingL2Blocks(gt *testing.T, deltaTimeOffset *hexutil.Uint64) {
require.NoError(t, err)
l1F, err := sources.NewL1Client(miner.RPCClient(), log, nil, sources.L1ClientDefaultConfig(sd.RollupCfg, false, sources.RPCKindStandard))
require.NoError(t, err)
altSequencer := NewL2Sequencer(t, log, l1F, altSeqEngCl, sd.RollupCfg, 0)
altBatcher := NewL2Batcher(log, sd.RollupCfg, &BatcherCfg{
MinL1TxSize: 0,
MaxL1TxSize: 128_000,
BatcherKey: dp.Secrets.Batcher,
}, altSequencer.RollupClient(), miner.EthClient(), altSeqEng.EthClient(), altSeqEng.EngineClient(t, sd.RollupCfg))
altSequencer := NewL2Sequencer(t, log, l1F, miner.BlobStore(), altSeqEngCl, sd.RollupCfg, 0)
altBatcher := NewL2Batcher(log, sd.RollupCfg, DefaultBatcherCfg(dp),
altSequencer.RollupClient(), miner.EthClient(), altSeqEng.EthClient(), altSeqEng.EngineClient(t, sd.RollupCfg))
// And set up user Alice, using the alternative sequencer endpoint
l2Cl := altSeqEng.EthClient()
......
......@@ -8,9 +8,8 @@ import (
"math/rand"
"testing"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils"
"github.com/ethereum-optimism/optimism/op-node/rollup/sync"
"github.com/ethereum-optimism/optimism/op-service/testlog"
"github.com/stretchr/testify/require"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
......@@ -20,7 +19,11 @@ import (
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"github.com/stretchr/testify/require"
batcherFlags "github.com/ethereum-optimism/optimism/op-batcher/flags"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils"
"github.com/ethereum-optimism/optimism/op-node/rollup/sync"
"github.com/ethereum-optimism/optimism/op-service/testlog"
)
// TestDropSpanBatchBeforeHardfork tests behavior of op-node before Delta hardfork.
......@@ -39,7 +42,7 @@ func TestDropSpanBatchBeforeHardfork(gt *testing.T) {
sd := e2eutils.Setup(t, dp, defaultAlloc)
log := testlog.Logger(t, log.LvlError)
miner, seqEngine, sequencer := setupSequencerTest(t, sd, log)
verifEngine, verifier := setupVerifier(t, sd, log, miner.L1Client(t, sd.RollupCfg), &sync.Config{})
verifEngine, verifier := setupVerifier(t, sd, log, miner.L1Client(t, sd.RollupCfg), miner.BlobStore(), &sync.Config{})
rollupSeqCl := sequencer.RollupClient()
// Force batcher to submit SpanBatches to L1.
......@@ -48,6 +51,7 @@ func TestDropSpanBatchBeforeHardfork(gt *testing.T) {
MaxL1TxSize: 128_000,
BatcherKey: dp.Secrets.Batcher,
ForceSubmitSpanBatch: true,
DataAvailabilityType: batcherFlags.CalldataType,
}, rollupSeqCl, miner.EthClient(), seqEngine.EthClient(), seqEngine.EngineClient(t, sd.RollupCfg))
// Alice makes a L2 tx
......@@ -129,7 +133,7 @@ func TestHardforkMiddleOfSpanBatch(gt *testing.T) {
sd := e2eutils.Setup(t, dp, defaultAlloc)
log := testlog.Logger(t, log.LvlError)
miner, seqEngine, sequencer := setupSequencerTest(t, sd, log)
verifEngine, verifier := setupVerifier(t, sd, log, miner.L1Client(t, sd.RollupCfg), &sync.Config{})
verifEngine, verifier := setupVerifier(t, sd, log, miner.L1Client(t, sd.RollupCfg), miner.BlobStore(), &sync.Config{})
minerCl := miner.EthClient()
rollupSeqCl := sequencer.RollupClient()
......@@ -139,6 +143,7 @@ func TestHardforkMiddleOfSpanBatch(gt *testing.T) {
MaxL1TxSize: 128_000,
BatcherKey: dp.Secrets.Batcher,
ForceSubmitSpanBatch: true,
DataAvailabilityType: batcherFlags.CalldataType,
}, rollupSeqCl, miner.EthClient(), seqEngine.EthClient(), seqEngine.EngineClient(t, sd.RollupCfg))
// Alice makes a L2 tx
......@@ -236,7 +241,7 @@ func TestAcceptSingularBatchAfterHardfork(gt *testing.T) {
sd := e2eutils.Setup(t, dp, defaultAlloc)
log := testlog.Logger(t, log.LvlError)
miner, seqEngine, sequencer := setupSequencerTest(t, sd, log)
verifEngine, verifier := setupVerifier(t, sd, log, miner.L1Client(t, sd.RollupCfg), &sync.Config{})
verifEngine, verifier := setupVerifier(t, sd, log, miner.L1Client(t, sd.RollupCfg), miner.BlobStore(), &sync.Config{})
rollupSeqCl := sequencer.RollupClient()
// Force batcher to submit SingularBatches to L1.
......@@ -245,6 +250,7 @@ func TestAcceptSingularBatchAfterHardfork(gt *testing.T) {
MaxL1TxSize: 128_000,
BatcherKey: dp.Secrets.Batcher,
ForceSubmitSingularBatch: true,
DataAvailabilityType: batcherFlags.CalldataType,
}, rollupSeqCl, miner.EthClient(), seqEngine.EthClient(), seqEngine.EngineClient(t, sd.RollupCfg))
// Alice makes a L2 tx
......@@ -321,7 +327,7 @@ func TestMixOfBatchesAfterHardfork(gt *testing.T) {
sd := e2eutils.Setup(t, dp, defaultAlloc)
log := testlog.Logger(t, log.LvlError)
miner, seqEngine, sequencer := setupSequencerTest(t, sd, log)
verifEngine, verifier := setupVerifier(t, sd, log, miner.L1Client(t, sd.RollupCfg), &sync.Config{})
verifEngine, verifier := setupVerifier(t, sd, log, miner.L1Client(t, sd.RollupCfg), miner.BlobStore(), &sync.Config{})
rollupSeqCl := sequencer.RollupClient()
seqEngCl := seqEngine.EthClient()
......@@ -361,6 +367,7 @@ func TestMixOfBatchesAfterHardfork(gt *testing.T) {
BatcherKey: dp.Secrets.Batcher,
ForceSubmitSpanBatch: i%2 == 0, // Submit SpanBatch for odd numbered batches
ForceSubmitSingularBatch: i%2 == 1, // Submit SingularBatch for even numbered batches
DataAvailabilityType: batcherFlags.CalldataType,
}
batcher := NewL2Batcher(log, sd.RollupCfg, &batcherCfg, rollupSeqCl, miner.EthClient(), seqEngine.EthClient(), seqEngine.EngineClient(t, sd.RollupCfg))
// Submit all new blocks
......@@ -410,14 +417,11 @@ func TestSpanBatchEmptyChain(gt *testing.T) {
sd := e2eutils.Setup(t, dp, defaultAlloc)
log := testlog.Logger(t, log.LvlError)
miner, seqEngine, sequencer := setupSequencerTest(t, sd, log)
_, verifier := setupVerifier(t, sd, log, miner.L1Client(t, sd.RollupCfg), &sync.Config{})
_, verifier := setupVerifier(t, sd, log, miner.L1Client(t, sd.RollupCfg), miner.BlobStore(), &sync.Config{})
rollupSeqCl := sequencer.RollupClient()
batcher := NewL2Batcher(log, sd.RollupCfg, &BatcherCfg{
MinL1TxSize: 0,
MaxL1TxSize: 128_000,
BatcherKey: dp.Secrets.Batcher,
}, rollupSeqCl, miner.EthClient(), seqEngine.EthClient(), seqEngine.EngineClient(t, sd.RollupCfg))
batcher := NewL2Batcher(log, sd.RollupCfg, DefaultBatcherCfg(dp),
rollupSeqCl, miner.EthClient(), seqEngine.EthClient(), seqEngine.EngineClient(t, sd.RollupCfg))
sequencer.ActL2PipelineFull(t)
verifier.ActL2PipelineFull(t)
......@@ -476,14 +480,11 @@ func TestSpanBatchLowThroughputChain(gt *testing.T) {
sd := e2eutils.Setup(t, dp, defaultAlloc)
log := testlog.Logger(t, log.LvlError)
miner, seqEngine, sequencer := setupSequencerTest(t, sd, log)
_, verifier := setupVerifier(t, sd, log, miner.L1Client(t, sd.RollupCfg), &sync.Config{})
_, verifier := setupVerifier(t, sd, log, miner.L1Client(t, sd.RollupCfg), miner.BlobStore(), &sync.Config{})
rollupSeqCl := sequencer.RollupClient()
batcher := NewL2Batcher(log, sd.RollupCfg, &BatcherCfg{
MinL1TxSize: 0,
MaxL1TxSize: 128_000,
BatcherKey: dp.Secrets.Batcher,
}, rollupSeqCl, miner.EthClient(), seqEngine.EthClient(), seqEngine.EngineClient(t, sd.RollupCfg))
batcher := NewL2Batcher(log, sd.RollupCfg, DefaultBatcherCfg(dp),
rollupSeqCl, miner.EthClient(), seqEngine.EthClient(), seqEngine.EngineClient(t, sd.RollupCfg))
cl := seqEngine.EthClient()
const numTestUsers = 5
......@@ -604,10 +605,10 @@ func TestBatchEquivalence(gt *testing.T) {
seqEngCl := seqEngine.EthClient()
// Setup Delta activated spanVerifier
_, spanVerifier := setupVerifier(t, sdDeltaActivated, log, miner.L1Client(t, sdDeltaActivated.RollupCfg), &sync.Config{})
_, spanVerifier := setupVerifier(t, sdDeltaActivated, log, miner.L1Client(t, sdDeltaActivated.RollupCfg), miner.BlobStore(), &sync.Config{})
// Setup Delta deactivated spanVerifier
_, singularVerifier := setupVerifier(t, sdDeltaDeactivated, log, miner.L1Client(t, sdDeltaDeactivated.RollupCfg), &sync.Config{})
_, singularVerifier := setupVerifier(t, sdDeltaDeactivated, log, miner.L1Client(t, sdDeltaDeactivated.RollupCfg), miner.BlobStore(), &sync.Config{})
// Setup SpanBatcher
spanBatcher := NewL2Batcher(log, sdDeltaActivated.RollupCfg, &BatcherCfg{
......@@ -615,6 +616,7 @@ func TestBatchEquivalence(gt *testing.T) {
MaxL1TxSize: 128_000,
BatcherKey: dp.Secrets.Batcher,
ForceSubmitSpanBatch: true,
DataAvailabilityType: batcherFlags.CalldataType,
}, rollupSeqCl, miner.EthClient(), seqEngine.EthClient(), seqEngine.EngineClient(t, sdDeltaActivated.RollupCfg))
// Setup SingularBatcher
......@@ -623,6 +625,7 @@ func TestBatchEquivalence(gt *testing.T) {
MaxL1TxSize: 128_000,
BatcherKey: dp.Secrets.Batcher,
ForceSubmitSingularBatch: true,
DataAvailabilityType: batcherFlags.CalldataType,
}, rollupSeqCl, miner.EthClient(), seqEngine.EthClient(), seqEngine.EngineClient(t, sdDeltaDeactivated.RollupCfg))
const numTestUsers = 5
......
......@@ -172,7 +172,7 @@ func TestELSync(gt *testing.T) {
miner, seqEng, sequencer := setupSequencerTest(t, sd, log)
// Enable engine P2P sync
verEng, verifier := setupVerifier(t, sd, log, miner.L1Client(t, sd.RollupCfg), &sync.Config{SyncMode: sync.ELSync})
verEng, verifier := setupVerifier(t, sd, log, miner.L1Client(t, sd.RollupCfg), miner.BlobStore(), &sync.Config{SyncMode: sync.ELSync})
seqEng.AddPeers(verEng.Enode())
verEng.AddPeers(seqEng.Enode())
......
......@@ -59,22 +59,18 @@ func BatcherKeyRotation(gt *testing.T, deltaTimeOffset *hexutil.Uint64) {
miner, seqEngine, sequencer := setupSequencerTest(t, sd, log)
miner.ActL1SetFeeRecipient(common.Address{'A'})
sequencer.ActL2PipelineFull(t)
_, verifier := setupVerifier(t, sd, log, miner.L1Client(t, sd.RollupCfg), &sync.Config{})
_, verifier := setupVerifier(t, sd, log, miner.L1Client(t, sd.RollupCfg), miner.BlobStore(), &sync.Config{})
rollupSeqCl := sequencer.RollupClient()
// the default batcher
batcherA := NewL2Batcher(log, sd.RollupCfg, &BatcherCfg{
MinL1TxSize: 0,
MaxL1TxSize: 128_000,
BatcherKey: dp.Secrets.Batcher,
}, rollupSeqCl, miner.EthClient(), seqEngine.EthClient(), seqEngine.EngineClient(t, sd.RollupCfg))
batcherA := NewL2Batcher(log, sd.RollupCfg, DefaultBatcherCfg(dp),
rollupSeqCl, miner.EthClient(), seqEngine.EthClient(), seqEngine.EngineClient(t, sd.RollupCfg))
// a batcher with a new key
batcherB := NewL2Batcher(log, sd.RollupCfg, &BatcherCfg{
MinL1TxSize: 0,
MaxL1TxSize: 128_000,
BatcherKey: dp.Secrets.Bob,
}, rollupSeqCl, miner.EthClient(), seqEngine.EthClient(), seqEngine.EngineClient(t, sd.RollupCfg))
altCfg := *DefaultBatcherCfg(dp)
altCfg.BatcherKey = dp.Secrets.Bob
batcherB := NewL2Batcher(log, sd.RollupCfg, &altCfg,
rollupSeqCl, miner.EthClient(), seqEngine.EthClient(), seqEngine.EngineClient(t, sd.RollupCfg))
sequencer.ActL2PipelineFull(t)
verifier.ActL2PipelineFull(t)
......@@ -235,11 +231,8 @@ func GPOParamsChange(gt *testing.T, deltaTimeOffset *hexutil.Uint64) {
sd := e2eutils.Setup(t, dp, defaultAlloc)
log := testlog.Logger(t, log.LvlDebug)
miner, seqEngine, sequencer := setupSequencerTest(t, sd, log)
batcher := NewL2Batcher(log, sd.RollupCfg, &BatcherCfg{
MinL1TxSize: 0,
MaxL1TxSize: 128_000,
BatcherKey: dp.Secrets.Batcher,
}, sequencer.RollupClient(), miner.EthClient(), seqEngine.EthClient(), seqEngine.EngineClient(t, sd.RollupCfg))
batcher := NewL2Batcher(log, sd.RollupCfg, DefaultBatcherCfg(dp),
sequencer.RollupClient(), miner.EthClient(), seqEngine.EthClient(), seqEngine.EngineClient(t, sd.RollupCfg))
alice := NewBasicUser[any](log, dp.Secrets.Alice, rand.New(rand.NewSource(1234)))
alice.SetUserEnv(&BasicUserEnv[any]{
......@@ -365,11 +358,8 @@ func GasLimitChange(gt *testing.T, deltaTimeOffset *hexutil.Uint64) {
sd := e2eutils.Setup(t, dp, defaultAlloc)
log := testlog.Logger(t, log.LvlDebug)
miner, seqEngine, sequencer := setupSequencerTest(t, sd, log)
batcher := NewL2Batcher(log, sd.RollupCfg, &BatcherCfg{
MinL1TxSize: 0,
MaxL1TxSize: 128_000,
BatcherKey: dp.Secrets.Batcher,
}, sequencer.RollupClient(), miner.EthClient(), seqEngine.EthClient(), seqEngine.EngineClient(t, sd.RollupCfg))
batcher := NewL2Batcher(log, sd.RollupCfg, DefaultBatcherCfg(dp),
sequencer.RollupClient(), miner.EthClient(), seqEngine.EthClient(), seqEngine.EngineClient(t, sd.RollupCfg))
sequencer.ActL2PipelineFull(t)
miner.ActEmptyBlock(t)
......@@ -412,7 +402,7 @@ func GasLimitChange(gt *testing.T, deltaTimeOffset *hexutil.Uint64) {
miner.ActL1IncludeTx(dp.Addresses.Batcher)(t)
miner.ActL1EndBlock(t)
_, verifier := setupVerifier(t, sd, log, miner.L1Client(t, sd.RollupCfg), &sync.Config{})
_, verifier := setupVerifier(t, sd, log, miner.L1Client(t, sd.RollupCfg), miner.BlobStore(), &sync.Config{})
verifier.ActL2PipelineFull(t)
require.Equal(t, sequencer.L2Unsafe(), verifier.L2Safe(), "verifier stays in sync, even with gaslimit changes")
......
......@@ -129,11 +129,8 @@ func runCrossLayerUserTest(gt *testing.T, test hardforkScheduledTest) {
require.Equal(t, dp.Secrets.Addresses().Proposer, dp.DeployConfig.L2OutputOracleProposer)
miner, seqEngine, seq := setupSequencerTest(t, sd, log)
batcher := NewL2Batcher(log, sd.RollupCfg, &BatcherCfg{
MinL1TxSize: 0,
MaxL1TxSize: 128_000,
BatcherKey: dp.Secrets.Batcher,
}, seq.RollupClient(), miner.EthClient(), seqEngine.EthClient(), seqEngine.EngineClient(t, sd.RollupCfg))
batcher := NewL2Batcher(log, sd.RollupCfg, DefaultBatcherCfg(dp),
seq.RollupClient(), miner.EthClient(), seqEngine.EthClient(), seqEngine.EngineClient(t, sd.RollupCfg))
proposer := NewL2Proposer(t, log, &ProposerCfg{
OutputOracleAddr: &sd.DeploymentsL1.L2OutputOracleProxy,
ProposerKey: dp.Secrets.Proposer,
......
package e2eutils
import (
"context"
"fmt"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum-optimism/optimism/op-node/rollup/derive"
"github.com/ethereum-optimism/optimism/op-service/eth"
)
// BlobsStore is a simple in-memory store of blobs, for testing purposes
type BlobsStore struct {
// blockhash -> blob versioned hash -> blob
blobs map[common.Hash]map[common.Hash]*eth.Blob
}
func NewBlobStore() *BlobsStore {
return &BlobsStore{blobs: make(map[common.Hash]map[common.Hash]*eth.Blob)}
}
func (store *BlobsStore) StoreBlob(blockHash common.Hash, versionedHash common.Hash, blob *eth.Blob) {
m, ok := store.blobs[blockHash]
if !ok {
m = make(map[common.Hash]*eth.Blob)
store.blobs[blockHash] = m
}
m[versionedHash] = blob
}
func (store *BlobsStore) GetBlobs(ctx context.Context, ref eth.L1BlockRef, hashes []eth.IndexedBlobHash) ([]*eth.Blob, error) {
out := make([]*eth.Blob, 0, len(hashes))
m, ok := store.blobs[ref.Hash]
if !ok {
return nil, fmt.Errorf("no blobs known with given time: %w", ethereum.NotFound)
}
for _, h := range hashes {
b, ok := m[h.Hash]
if !ok {
return nil, fmt.Errorf("blob %d %s is not in store: %w", h.Index, h.Hash, ethereum.NotFound)
}
out = append(out, b)
}
return out, nil
}
var _ derive.L1BlobsFetcher = (*BlobsStore)(nil)
......@@ -277,7 +277,7 @@ func (m *SimpleTxManager) craftTx(ctx context.Context, candidate TxCandidate) (*
if candidate.To == nil {
return nil, errors.New("blob txs cannot deploy contracts")
}
if sidecar, blobHashes, err = makeSidecar(candidate.Blobs); err != nil {
if sidecar, blobHashes, err = MakeSidecar(candidate.Blobs); err != nil {
return nil, fmt.Errorf("failed to make sidecar: %w", err)
}
}
......@@ -314,9 +314,9 @@ func (m *SimpleTxManager) craftTx(ctx context.Context, candidate TxCandidate) (*
}
// makeSidecar builds & returns the BlobTxSidecar and corresponding blob hashes from the raw blob
// MakeSidecar builds & returns the BlobTxSidecar and corresponding blob hashes from the raw blob
// data.
func makeSidecar(blobs []*eth.Blob) (*types.BlobTxSidecar, []common.Hash, error) {
func MakeSidecar(blobs []*eth.Blob) (*types.BlobTxSidecar, []common.Hash, error) {
sidecar := &types.BlobTxSidecar{}
blobHashes := []common.Hash{}
for i, blob := range blobs {
......
......@@ -2,6 +2,7 @@ package txmgr
import (
"context"
"crypto/rand"
"errors"
"fmt"
"math/big"
......@@ -1403,3 +1404,24 @@ func TestCloseWaitingForConfirmation(t *testing.T) {
require.True(t, h.mgr.closed.Load())
require.NoError(t, err)
}
func TestMakeSidecar(t *testing.T) {
var blob eth.Blob
_, err := rand.Read(blob[:])
require.NoError(t, err)
// get the field-elements into a valid range
for i := 0; i < 4096; i++ {
blob[32*i] &= 0b0011_1111
}
sidecar, hashes, err := MakeSidecar([]*eth.Blob{&blob})
require.NoError(t, err)
require.Equal(t, len(hashes), 1)
require.Equal(t, len(sidecar.Blobs), len(hashes))
require.Equal(t, len(sidecar.Proofs), len(hashes))
require.Equal(t, len(sidecar.Commitments), len(hashes))
for i, commit := range sidecar.Commitments {
require.NoError(t, eth.VerifyBlobProof((*eth.Blob)(&sidecar.Blobs[i]), commit, sidecar.Proofs[i]), "proof must be valid")
require.Equal(t, hashes[i], eth.KZGToVersionedHash(commit))
}
}
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