Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
39 changes: 39 additions & 0 deletions espresso/batch_buffer.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package espresso

import (
"bytes"
"cmp"
"encoding/binary"
"slices"

"github.com/ethereum-optimism/optimism/op-service/eth"
Expand Down Expand Up @@ -88,3 +90,40 @@ func (b *BatchBuffer[B]) Pop() *B {

return &batch
}

type DummyBatch struct {
number uint64
l1Origin eth.BlockID
}

func (b DummyBatch) Number() uint64 {
return b.number
}

func (b DummyBatch) L1Origin() eth.BlockID {
return b.l1Origin
}

func (b DummyBatch) Hash() common.Hash {
return common.Hash{}
}

func (b DummyBatch) Header() *types.Header {
return nil
}

var b = NewBatchBuffer[DummyBatch]()

func Fuzz(data []byte) int {
var num uint64
err := binary.Read(bytes.NewBuffer(data), binary.LittleEndian, &num)

if err != nil {
b.Insert(DummyBatch{number: num, l1Origin: eth.BlockID{Number: num}}, 0)
} else {
b.Peek()
b.Pop()
}

return 0
}
163 changes: 163 additions & 0 deletions espresso/batch_buffer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
package espresso_test

import (
"bytes"
"encoding/binary"
"testing"

"github.com/ethereum-optimism/optimism/espresso"
"github.com/ethereum-optimism/optimism/op-service/eth"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
)

// DummyBatch is a test implementation of the Batch interface
type DummyBatch struct {
number uint64
l1Origin eth.BlockID
}

func (b DummyBatch) Number() uint64 {
return b.number
}

func (b DummyBatch) L1Origin() eth.BlockID {
return b.l1Origin
}

func (b DummyBatch) Hash() common.Hash {
return common.Hash{}
}

func (b DummyBatch) Header() *types.Header {
return nil
}

// Basic batch buffer test
func FuzzBatchBufferBasic(f *testing.F) {
// Generate corpus for batch buffer
f.Add([]byte{0})
f.Add([]byte{1})
f.Add([]byte{0, 0, 0, 0, 0, 0, 0, 0})
f.Add([]byte{1, 0, 0, 0, 0, 0, 0, 0})

f.Fuzz(func(t *testing.T, data []byte) {
b := espresso.NewBatchBuffer[DummyBatch]()
var num uint64
err := binary.Read(bytes.NewBuffer(data), binary.LittleEndian, &num)

if err != nil {
b.Insert(DummyBatch{number: num, l1Origin: eth.BlockID{Number: num}}, 0)
} else {
b.Peek()
b.Pop()
}
})
}

// FuzzBatchBuffer tests the BatchBuffer implementation using Go's built-in fuzzer
func FuzzBatchBufferSimple(f *testing.F) {
// Add some seed corpus
f.Add(uint64(0))
f.Add(uint64(1))
f.Add(uint64(100))
f.Add(uint64(1000))

// Fuzz test
f.Fuzz(func(t *testing.T, num uint64) {
b := espresso.NewBatchBuffer[DummyBatch]()

// Test insertion
b.Insert(DummyBatch{number: num, l1Origin: eth.BlockID{Number: num}}, 0)
if b.Len() != 1 {
t.Errorf("Expected buffer length 1, got %d", b.Len())
}

// Test peek
batch := b.Peek()
if batch == nil {
t.Fatal("Expected non-nil batch from Peek")
}
if batch.Number() != num {
t.Errorf("Expected batch number %d, got %d", num, batch.Number())
}

// Test pop
batch = b.Pop()
if batch == nil {
t.Fatal("Expected non-nil batch from Pop")
}
if batch.Number() != num {
t.Errorf("Expected batch number %d, got %d", num, batch.Number())
}
if b.Len() != 0 {
t.Errorf("Expected empty buffer after Pop, got length %d", b.Len())
}
})
}

// FuzzBatchBufferInsertMultiple tests inserting multiple batches into the buffer
func FuzzBatchBufferInsertMultiple(f *testing.F) {
// Add some seed corpus
f.Add(uint64(1), uint64(2), uint64(3))
f.Add(uint64(10), uint64(5), uint64(15))

// Fuzz test with multiple insertions
f.Fuzz(func(t *testing.T, num1, num2, num3 uint64) {
b := espresso.NewBatchBuffer[DummyBatch]()

// Insert batches
b.Insert(DummyBatch{number: num1, l1Origin: eth.BlockID{Number: num1}}, 0)
b.Insert(DummyBatch{number: num2, l1Origin: eth.BlockID{Number: num2}}, 0)
b.Insert(DummyBatch{number: num3, l1Origin: eth.BlockID{Number: num3}}, 0)

// Test length
if b.Len() != 3 {
t.Errorf("Expected buffer length 3, got %d", b.Len())
}

// Test clear
b.Clear()
if b.Len() != 0 {
t.Errorf("Expected empty buffer after Clear, got length %d", b.Len())
}
})
}

// FuzzBatchBufferTryInsert tests the TryInsert method
func FuzzBatchBufferTryInsert(f *testing.F) {
f.Add(uint64(1), uint64(2))
f.Add(uint64(100), uint64(100))

f.Fuzz(func(t *testing.T, num1, num2 uint64) {
b := espresso.NewBatchBuffer[DummyBatch]()

// Insert first batch
batch1 := DummyBatch{number: num1, l1Origin: eth.BlockID{Number: num1}}
pos, _ := b.TryInsert(batch1)
b.Insert(batch1, pos)

// Try inserting second batch
batch2 := DummyBatch{number: num2, l1Origin: eth.BlockID{Number: num2}}
pos, exists := b.TryInsert(batch2)

// If numbers are the same, it should detect as already existing
if num1 == num2 && !exists {
t.Errorf("Expected duplicate batch to be detected")
}

// If not duplicate, insert it
if !exists {
b.Insert(batch2, pos)

// Get the batch at position
gotBatch := b.Get(pos)
if gotBatch == nil {
t.Fatal("Expected non-nil batch from Get")
}
if gotBatch.Number() != num2 {
t.Errorf("Expected batch number %d, got %d", num2, gotBatch.Number())
}
}
})
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ require (
github.com/dop251/goja v0.0.0-20230806174421-c933cf95e127 // indirect
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/dvyukov/go-fuzz v0.0.0-20240924070022-e577bee5275c // indirect
github.com/elastic/gosigar v0.14.3 // indirect
github.com/ethereum/c-kzg-4844 v1.0.0 // indirect
github.com/ethereum/go-verkle v0.2.2 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,8 @@ github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdf
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/dvyukov/go-fuzz v0.0.0-20240924070022-e577bee5275c h1:oLpHpHwNuAPvw3bBviEZNrJbigNNi5dRadfZnagGgZI=
github.com/dvyukov/go-fuzz v0.0.0-20240924070022-e577bee5275c/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw=
github.com/elastic/gosigar v0.12.0/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs=
github.com/elastic/gosigar v0.14.3 h1:xwkKwPia+hSfg9GqrCUKYdId102m9qTJIIr7egmK/uo=
github.com/elastic/gosigar v0.14.3/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs=
Expand Down
6 changes: 6 additions & 0 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,9 @@ shellcheck:
# Generates a table of contents for the README.md file.
toc:
md_toc -p github README.md

fuzz-batch-buffer:
go test -fuzz=FuzzBatchBufferSimple -fuzztime=1m -v ./espresso
go test -fuzz=FuzzBatchBufferInsertMultiple -fuzztime=1m -v ./espresso
go test -fuzz=FuzzBatchBufferTryInsert -fuzztime=1m -v ./espresso
go test -fuzz=FuzzBatchBufferBasic -fuzztime=1m -v ./espresso
Loading