Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
7dd0a79
contracts-bedrock: add Espresso BatchAuthenticator and supporting infra
QuentinI May 7, 2026
5e47299
Update packages/contracts-bedrock/src/L1/BatchAuthenticator.sol
QuentinI May 13, 2026
e88cbe8
Remove stray path
QuentinI May 13, 2026
2704403
Remove hardcoded Sepolia URL
QuentinI May 13, 2026
b99bcb9
Use OZ v5 in mock verifier
QuentinI May 13, 2026
dcff468
Fix Codex's suggestion
QuentinI May 20, 2026
c102ced
Lower pragma
QuentinI May 20, 2026
011c7a7
Remove unrelated foundry.toml changes
QuentinI May 20, 2026
d769ea2
scripts/checks: clean up exclude lists per PR review
QuentinI May 20, 2026
5651e2a
Fix re-initialization
QuentinI May 21, 2026
ab161a1
Add batcher address history
QuentinI May 25, 2026
400f1f5
contracts-bedrock: drop OZ TUP from espresso deploy
palango May 20, 2026
e898f5c
Remove pause from BatchAuthenticator
QuentinI May 25, 2026
0f4d001
Add a defensive check
QuentinI May 25, 2026
ea1f014
test: add end-to-end dual-batcher switch test
QuentinI May 25, 2026
c993c2a
Fix tests
QuentinI May 28, 2026
09533af
switchBatcher from toggle to a setter
QuentinI May 29, 2026
2d634fd
Use OZ Checkpoints for batcher history
QuentinI May 29, 2026
e6d65e0
contracts-bedrock: deploy espresso impls via vm.getCode, drop suppres…
QuentinI Jun 1, 2026
a99e175
Check batcher in Espresso mode
shenkeyao May 28, 2026
483e8e4
regenerate snapshots for UnauthorizedEspressoBatcher error
QuentinI Jun 2, 2026
2e5cc7d
contracts-bedrock: wire espresso proxies to shared OP Stack ProxyAdmin
QuentinI Jun 4, 2026
59f5d38
add caller to BatchInfoAuthenticated event
QuentinI Jun 4, 2026
5461fba
forge fmt
piersy Jun 9, 2026
96dfd24
Remove unused imports
piersy Jun 10, 2026
f132cbf
Rename tests to fit test name convention
piersy Jun 10, 2026
2354b89
op-chain-ops/script: resolve directory-qualified getCode artifact names
QuentinI Jun 11, 2026
70291e3
contracts-bedrock: fix semgrep checks-fast findings
QuentinI Jun 11, 2026
14210d4
contracts-bedrock: prevent same-block espressoBatcher history corruption
QuentinI Jun 15, 2026
68784e3
Fix formatting
piersy Jun 17, 2026
27f75a7
Fix recompile tests
QuentinI Jun 17, 2026
c87f184
op-node: add event-based batch authentication
QuentinI May 25, 2026
d797a1b
op-node: rename EspressoEnforcementTime to EspressoTime
QuentinI May 25, 2026
1f3150f
op-node: require BatchAuthenticatorAddress when Espresso is enabled
QuentinI Jun 2, 2026
9638afd
op-node: fix EspressoTime fork-activation doc comments
QuentinI Jun 2, 2026
dd772e3
op-node: bind authenticated batches to the authenticating caller
QuentinI Jun 8, 2026
7a4a401
op-node: replace global batch auth caches with dependency-injected in…
piersy Jun 2, 2026
9b14f40
Use rollup.Config in DataSourceConfig
piersy Jun 3, 2026
3a76b2d
op-node: fix up batch-auth cache DI and rollupCfg cherry-picks
QuentinI Jun 8, 2026
182d84e
Hardcode BatchAuthLookbackWindow
QuentinI Jun 8, 2026
5aff9d1
Tighten assertions for batch auth tests
piersy Jun 11, 2026
7979391
op-node: test Espresso fork boundary and per-commitment batch auth
piersy Jun 11, 2026
8917fef
op-node: isolate Espresso derivation tests into espresso_-prefixed files
piersy Jun 11, 2026
05cb149
Update op-node/rollup/derive/espresso_blob_data_source_test.go
piersy Jun 15, 2026
25b8fa9
Update op-node/rollup/derive/espresso_blob_data_source_test.go
piersy Jun 15, 2026
2782976
Expand LRU size comment
QuentinI Jun 18, 2026
866cae8
Merge branch 'celo-rebase-18' into espresso/derivation-pipeline
piersy Jun 18, 2026
b7785e7
op-node: reset (not retry) when a batch-auth lookback block is NotFou…
piersy Jun 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 140 additions & 6 deletions op-node/rollup/derive/altda_data_source_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package derive

import (
"context"
"errors"
"io"
"math/big"
"math/rand"
Expand Down Expand Up @@ -118,12 +119,11 @@ func TestAltDADataSource(t *testing.T) {
}
l1Refs = append(l1Refs, ref)
logger.Info("new l1 block", "ref", ref)
// called for each l1 block to sync challenges
l1F.ExpectFetchReceipts(ref.Hash, nil, types.Receipts{}, nil)

// pick a random number of commitments to include in the l1 block
c := rng.Intn(4)
var txs []*types.Transaction
var receipts types.Receipts

for j := 0; j < c; j++ {
// mock input commitments in l1 transactions
Expand All @@ -147,9 +147,17 @@ func TestAltDADataSource(t *testing.T) {
})
require.NoError(t, err)

receipt := types.Receipt{
TxHash: tx.Hash(),
Status: types.ReceiptStatusSuccessful,
}

txs = append(txs, tx)
receipts = append(receipts, &receipt)

}
l1F.SetFetchReceipts(ref.Hash, testutils.RandomBlockInfo(rng), receipts, nil)

logger.Info("included commitments", "count", c)
l1F.ExpectInfoAndTxsByHash(ref.Hash, testutils.RandomBlockInfo(rng), txs, nil)
// called once per derivation
Expand Down Expand Up @@ -221,12 +229,11 @@ func TestAltDADataSource(t *testing.T) {
}
l1Refs = append(l1Refs, ref)
logger.Info("new l1 block", "ref", ref)
// called for each l1 block to sync challenges
l1F.ExpectFetchReceipts(ref.Hash, nil, types.Receipts{}, nil)

// pick a random number of commitments to include in the l1 block
c := rng.Intn(4)
var txs []*types.Transaction
var receipts []*types.Receipt

for j := 0; j < c; j++ {
// mock input commitments in l1 transactions
Expand All @@ -249,11 +256,18 @@ func TestAltDADataSource(t *testing.T) {
})
require.NoError(t, err)

receipt := &types.Receipt{
TxHash: tx.Hash(),
Status: types.ReceiptStatusSuccessful,
}

txs = append(txs, tx)
receipts = append(receipts, receipt)

}
logger.Info("included commitments", "count", c)
l1F.ExpectInfoAndTxsByHash(ref.Hash, testutils.RandomBlockInfo(rng), txs, nil)
l1F.SetFetchReceipts(ref.Hash, testutils.RandomBlockInfo(rng), receipts, nil)
}

// create a new data source for each block
Expand Down Expand Up @@ -352,7 +366,6 @@ func TestAltDADataSourceStall(t *testing.T) {
ParentHash: parent.Hash,
Time: parent.Time + l1Time,
}
l1F.ExpectFetchReceipts(ref.Hash, nil, types.Receipts{}, nil)
// mock input commitments in l1 transactions
input := testutils.RandomData(rng, 2000)
comm, _ := storage.SetInput(ctx, input)
Expand All @@ -370,7 +383,9 @@ func TestAltDADataSourceStall(t *testing.T) {
require.NoError(t, err)

txs := []*types.Transaction{tx}
receipts := types.Receipts{&types.Receipt{TxHash: tx.Hash(), Status: types.ReceiptStatusSuccessful}}

l1F.SetFetchReceipts(ref.Hash, nil, receipts, nil)
l1F.ExpectInfoAndTxsByHash(ref.Hash, testutils.RandomBlockInfo(rng), txs, nil)

// delete the input from the DA provider so it returns not found
Expand Down Expand Up @@ -475,7 +490,6 @@ func TestAltDADataSourceInvalidData(t *testing.T) {
ParentHash: parent.Hash,
Time: parent.Time + l1Time,
}
l1F.ExpectFetchReceipts(ref.Hash, nil, types.Receipts{}, nil)
// mock input commitments in l1 transactions with an oversized input
input := testutils.RandomData(rng, altda.MaxInputSize+1)
comm, _ := storage.SetInput(ctx, input)
Expand Down Expand Up @@ -522,7 +536,12 @@ func TestAltDADataSourceInvalidData(t *testing.T) {
require.NoError(t, err)

txs := []*types.Transaction{tx1, tx2, tx3}
receipts := types.Receipts{
&types.Receipt{TxHash: tx1.Hash(), Status: types.ReceiptStatusSuccessful},
&types.Receipt{TxHash: tx2.Hash(), Status: types.ReceiptStatusSuccessful},
&types.Receipt{TxHash: tx3.Hash(), Status: types.ReceiptStatusSuccessful}}

l1F.SetFetchReceipts(ref.Hash, nil, receipts, nil)
l1F.ExpectInfoAndTxsByHash(ref.Hash, testutils.RandomBlockInfo(rng), txs, nil)

src, err := factory.OpenData(ctx, ref, batcherAddr)
Expand All @@ -543,3 +562,118 @@ func TestAltDADataSourceInvalidData(t *testing.T) {

l1F.AssertExpectations(t)
}

// TestAltDADataSourceL1FetcherErrors tests that the pipeline handles intermittent errors in
// L1Source correctly.
func TestAltDADataSourceL1FetcherErrors(t *testing.T) {
logger := testlog.Logger(t, log.LevelDebug)
ctx := context.Background()

rng := rand.New(rand.NewSource(1234))

l1F := &testutils.MockL1Source{}

storage := altda.NewMockDAClient(logger)

pcfg := altda.Config{
ChallengeWindow: 90, ResolveWindow: 90,
}

da := altda.NewAltDAWithStorage(logger, pcfg, storage, &altda.NoopMetrics{})

// Create rollup genesis and config
l1Time := uint64(2)
refA := testutils.RandomBlockRef(rng)
refA.Number = 1
l1Refs := []eth.L1BlockRef{refA}
refA0 := eth.L2BlockRef{
Hash: testutils.RandomHash(rng),
Number: 0,
ParentHash: common.Hash{},
Time: refA.Time,
L1Origin: refA.ID(),
SequenceNumber: 0,
}
batcherPriv := testutils.RandomKey()
batcherAddr := crypto.PubkeyToAddress(batcherPriv.PublicKey)
batcherInbox := common.Address{42}
cfg := &rollup.Config{
Genesis: rollup.Genesis{
L1: refA.ID(),
L2: refA0.ID(),
L2Time: refA0.Time,
},
L1ChainID: big.NewInt(1),
BlockTime: 1,
SeqWindowSize: 20,
BatchInboxAddress: batcherInbox,
AltDAConfig: &rollup.AltDAConfig{
DAChallengeWindow: pcfg.ChallengeWindow,
DAResolveWindow: pcfg.ResolveWindow,
CommitmentType: altda.KeccakCommitmentString,
},
}

signer := cfg.L1Signer()

factory := NewDataSourceFactory(logger, cfg, l1F, nil, da)

parent := l1Refs[0]
// create a new mock l1 ref
ref := eth.L1BlockRef{
Hash: testutils.RandomHash(rng),
Number: parent.Number + 1,
ParentHash: parent.Hash,
Time: parent.Time + l1Time,
}
// mock input to include in l1 transaction
input := testutils.RandomData(rng, 200)
comm, _ := storage.SetInput(ctx, input)

tx, err := types.SignNewTx(batcherPriv, signer, &types.DynamicFeeTx{
ChainID: signer.ChainID(),
Nonce: 0,
GasTipCap: big.NewInt(2 * params.GWei),
GasFeeCap: big.NewInt(30 * params.GWei),
Gas: 100_000,
To: &batcherInbox,
Value: big.NewInt(int64(0)),
Data: comm.TxData(),
})
require.NoError(t, err)

txs := []*types.Transaction{tx}

// First attempt: InfoAndTxsByHash fails, so CalldataSource opens in closed state.
// Note: the mock panics on nil interface type-assert, so we pass a dummy BlockInfo even for error cases.
l1F.ExpectInfoAndTxsByHash(ref.Hash, testutils.RandomBlockInfo(rng), nil, errors.New("Intermittent error"))

src, err := factory.OpenData(ctx, ref, batcherAddr)
// Data source should still be opened correctly (error is deferred)
require.NoError(t, err)

// On Next(), AltDA calls AdvanceL1Origin which fetches receipts for challenge events,
// then the inner CalldataSource retries InfoAndTxsByHash.

// Second attempt: AdvanceL1Origin needs receipts, then InfoAndTxsByHash fails again.
l1F.ExpectFetchReceipts(ref.Hash, nil, types.Receipts{}, nil)
l1F.ExpectInfoAndTxsByHash(ref.Hash, testutils.RandomBlockInfo(rng), nil, errors.New("Intermittent error"))

// Should fail because InfoAndTxsByHash still returns error
_, err = src.Next(ctx)
require.Error(t, err)

// Third attempt: InfoAndTxsByHash succeeds, data is returned.
// AltDA AdvanceL1Origin is a no-op since the origin was already advanced.
l1F.ExpectInfoAndTxsByHash(ref.Hash, testutils.RandomBlockInfo(rng), txs, nil)

// regular input is passed through
data, err := src.Next(ctx)
require.NoError(t, err)
require.Equal(t, hexutil.Bytes(input), data)

_, err = src.Next(ctx)
require.ErrorIs(t, err, io.EOF)

l1F.AssertExpectations(t)
}
Loading
Loading