Skip to content

Commit

Permalink
Merge branch 'main' into dependabot-commit-msg
Browse files Browse the repository at this point in the history
  • Loading branch information
gupadhyaya authored Oct 22, 2024
2 parents 4c879d7 + 0f699be commit 82aa188
Show file tree
Hide file tree
Showing 4 changed files with 396 additions and 29 deletions.
12 changes: 5 additions & 7 deletions test/dummy.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import (
"context"
"encoding/hex"
"errors"
"fmt"
"math"
"reflect"
"sync"
"time"

Expand Down Expand Up @@ -105,18 +107,14 @@ func (d *DummySequencer) GetNextBatch(ctx context.Context, req sequencing.GetNex
lastBatchHash := d.lastBatchHash
d.lastBatchHashMutex.RUnlock()

if lastBatchHash == nil && req.LastBatchHash != nil {
return nil, errors.New("lastBatch is supposed to be nil")
} else if lastBatchHash != nil && req.LastBatchHash == nil {
return nil, errors.New("lastBatch is not supposed to be nil")
} else if !bytes.Equal(lastBatchHash, req.LastBatchHash) {
return nil, errors.New("supplied lastBatch does not match with sequencer last batch")
if !reflect.DeepEqual(lastBatchHash, req.LastBatchHash) {
return nil, fmt.Errorf("batch hash mismatch: lastBatchHash = %x, req.LastBatchHash = %x", lastBatchHash, req.LastBatchHash)
}

batch := d.tq.GetNextBatch(req.MaxBytes)
batchRes := &sequencing.GetNextBatchResponse{Batch: batch, Timestamp: now}
// If there are no transactions, return empty batch without updating the last batch hash
if batch.Transactions == nil {
if len(batch.Transactions) == 0 {
return batchRes, nil
}

Expand Down
75 changes: 53 additions & 22 deletions test/dummy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ package test

import (
"context"
"crypto/rand"
"fmt"
"io"
"math"
"testing"
"time"
Expand All @@ -14,7 +17,8 @@ import (
func TestTransactionQueue_AddTransaction(t *testing.T) {
queue := NewTransactionQueue()

tx1 := []byte("transaction_1")
tx1, err := GenerateSecureRandomBytes(32)
assert.NoError(t, err)
queue.AddTransaction(tx1)

// Check that the transaction was added
Expand All @@ -27,8 +31,10 @@ func TestTransactionQueue_GetNextBatch(t *testing.T) {
queue := NewTransactionQueue()

// Add multiple transactions
tx1 := []byte("transaction_1")
tx2 := []byte("transaction_2")
tx1, err := GenerateSecureRandomBytes(32)
assert.NoError(t, err)
tx2, err := GenerateSecureRandomBytes(32)
assert.NoError(t, err)
queue.AddTransaction(tx1)
queue.AddTransaction(tx2)

Expand All @@ -46,7 +52,8 @@ func TestTransactionQueue_GetNextBatch(t *testing.T) {
func TestDummySequencer_SubmitRollupTransaction(t *testing.T) {
// Define a test rollup ID and transaction
rollupId := []byte("test_rollup_id")
tx := []byte("test_transaction")
tx, err := GenerateSecureRandomBytes(32)
assert.NoError(t, err)
sequencer := NewDummySequencer(rollupId)

// Submit a transaction
Expand Down Expand Up @@ -92,9 +99,12 @@ func TestDummySequencer_SubmitEmptyTransaction(t *testing.T) {
func TestDummySequencer_SubmitMultipleTransactions(t *testing.T) {
// Define a test rollup ID and multiple transactions
rollupId := []byte("test_rollup_id")
tx1 := []byte("transaction_1")
tx2 := []byte("transaction_2")
tx3 := []byte("transaction_3")
tx1, err := GenerateSecureRandomBytes(32)
assert.NoError(t, err)
tx2, err := GenerateSecureRandomBytes(32)
assert.NoError(t, err)
tx3, err := GenerateSecureRandomBytes(32)
assert.NoError(t, err)
sequencer := NewDummySequencer(rollupId)

// Submit multiple transactions
Expand All @@ -111,7 +121,7 @@ func TestDummySequencer_SubmitMultipleTransactions(t *testing.T) {
Tx: tx3,
}

_, err := sequencer.SubmitRollupTransaction(context.Background(), req1)
_, err = sequencer.SubmitRollupTransaction(context.Background(), req1)
assert.NoError(t, err)
_, err = sequencer.SubmitRollupTransaction(context.Background(), req2)
assert.NoError(t, err)
Expand All @@ -129,13 +139,14 @@ func TestDummySequencer_SubmitMultipleTransactions(t *testing.T) {
func TestDummySequencer_GetNextBatch(t *testing.T) {
// Add a transaction to the queue
rollupId := []byte("test_rollup_id")
tx := []byte("test_transaction")
tx, err := GenerateSecureRandomBytes(32)
assert.NoError(t, err)
sequencer := NewDummySequencer(rollupId)
req := sequencing.SubmitRollupTransactionRequest{
RollupId: rollupId,
Tx: tx,
}
_, err := sequencer.SubmitRollupTransaction(context.Background(), req)
_, err = sequencer.SubmitRollupTransaction(context.Background(), req)
assert.NoError(t, err)

// Retrieve the next batch
Expand Down Expand Up @@ -178,12 +189,13 @@ func TestDummySequencer_GetNextBatch_LastBatchHashMismatch(t *testing.T) {
// Submit a transaction
rollupId := []byte("test_rollup_id")
sequencer := NewDummySequencer(rollupId)
tx := []byte("test_transaction")
tx, err := GenerateSecureRandomBytes(32)
assert.NoError(t, err)
req := sequencing.SubmitRollupTransactionRequest{
RollupId: rollupId,
Tx: tx,
}
_, err := sequencer.SubmitRollupTransaction(context.Background(), req)
_, err = sequencer.SubmitRollupTransaction(context.Background(), req)
assert.NoError(t, err)

// Retrieve the next batch
Expand All @@ -195,17 +207,20 @@ func TestDummySequencer_GetNextBatch_LastBatchHashMismatch(t *testing.T) {

// Assert that the batch hash mismatch error is returned
assert.Error(t, err)
assert.Equal(t, "lastBatch is supposed to be nil", err.Error())
assert.ErrorContains(t, err, "batch hash mismatch", "unexpected error message")
}

// Test retrieving a batch with maxBytes limit
func TestDummySequencer_GetNextBatch_MaxBytesLimit(t *testing.T) {
// Define a test rollup ID and multiple transactions
rollupId := []byte("test_rollup_id")
sequencer := NewDummySequencer(rollupId)
tx1 := []byte("transaction_1")
tx2 := []byte("transaction_2")
tx3 := []byte("transaction_3")
tx1, err := GenerateSecureRandomBytes(32)
assert.NoError(t, err)
tx2, err := GenerateSecureRandomBytes(32)
assert.NoError(t, err)
tx3, err := GenerateSecureRandomBytes(32)
assert.NoError(t, err)

// Submit multiple transactions
req1 := sequencing.SubmitRollupTransactionRequest{
Expand All @@ -221,7 +236,7 @@ func TestDummySequencer_GetNextBatch_MaxBytesLimit(t *testing.T) {
Tx: tx3,
}

_, err := sequencer.SubmitRollupTransaction(context.Background(), req1)
_, err = sequencer.SubmitRollupTransaction(context.Background(), req1)
assert.NoError(t, err)
_, err = sequencer.SubmitRollupTransaction(context.Background(), req2)
assert.NoError(t, err)
Expand Down Expand Up @@ -267,12 +282,13 @@ func TestDummySequencer_VerifyBatch(t *testing.T) {
// Add and retrieve a batch
rollupId := []byte("test_rollup_id")
sequencer := NewDummySequencer(rollupId)
tx := []byte("test_transaction")
tx, err := GenerateSecureRandomBytes(32)
assert.NoError(t, err)
req := sequencing.SubmitRollupTransactionRequest{
RollupId: rollupId,
Tx: tx,
}
_, err := sequencer.SubmitRollupTransaction(context.Background(), req)
_, err = sequencer.SubmitRollupTransaction(context.Background(), req)
assert.NoError(t, err)

// Get the next batch to generate batch hash
Expand Down Expand Up @@ -320,8 +336,10 @@ func TestDummySequencer_VerifyBatchWithMultipleTransactions(t *testing.T) {
// Define a test rollup ID and multiple transactions
rollupId := []byte("test_rollup_id")
sequencer := NewDummySequencer(rollupId)
tx1 := []byte("transaction_1")
tx2 := []byte("transaction_2")
tx1, err := GenerateSecureRandomBytes(32)
assert.NoError(t, err)
tx2, err := GenerateSecureRandomBytes(32)
assert.NoError(t, err)

// Submit multiple transactions
req1 := sequencing.SubmitRollupTransactionRequest{
Expand All @@ -333,7 +351,7 @@ func TestDummySequencer_VerifyBatchWithMultipleTransactions(t *testing.T) {
Tx: tx2,
}

_, err := sequencer.SubmitRollupTransaction(context.Background(), req1)
_, err = sequencer.SubmitRollupTransaction(context.Background(), req1)
assert.NoError(t, err)
_, err = sequencer.SubmitRollupTransaction(context.Background(), req2)
assert.NoError(t, err)
Expand Down Expand Up @@ -375,3 +393,16 @@ func TestDummySequencer_VerifyBatch_NotFound(t *testing.T) {
assert.NoError(t, err)
assert.False(t, verifyResp.Status)
}

// GenerateSecureRandomBytes generates cryptographically secure random bytes of the given length.
func GenerateSecureRandomBytes(length int) ([]byte, error) {
if length <= 0 {
return nil, fmt.Errorf("invalid length: %d, must be greater than 0", length)
}

buf := make([]byte, length)
if _, err := io.ReadFull(rand.Reader, buf); err != nil {
return nil, fmt.Errorf("failed to generate random bytes: %w", err)
}
return buf, nil
}
126 changes: 126 additions & 0 deletions test/multi_rollup_sequencer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package test

import (
"context"
"encoding/hex"
"fmt"
"reflect"
"sync"
"time"

"github.com/rollkit/go-sequencing"
)

// MultiRollupSequencer is a sequencer for testing that serves multiple rollups
type MultiRollupSequencer struct {
rollups map[string]*RollupData
rollupsMutex sync.RWMutex
}

// RollupData holds the data for a specific rollup, including its transaction queue, last batch hash, and seen batches.
type RollupData struct {
tq *TransactionQueue
lastBatchHash []byte
lastBatchHashMutex sync.RWMutex

seenBatches map[string]struct{}
seenBatchesMutex sync.Mutex
}

// SubmitRollupTransaction implements sequencing.Sequencer.
func (d *MultiRollupSequencer) SubmitRollupTransaction(ctx context.Context, req sequencing.SubmitRollupTransactionRequest) (*sequencing.SubmitRollupTransactionResponse, error) {
rollup, err := d.getOrCreateRollup(req.RollupId)
if err != nil {
return nil, err
}
rollup.tq.AddTransaction(req.Tx)
return &sequencing.SubmitRollupTransactionResponse{}, nil
}

// GetNextBatch implements sequencing.Sequencer.
func (d *MultiRollupSequencer) GetNextBatch(ctx context.Context, req sequencing.GetNextBatchRequest) (*sequencing.GetNextBatchResponse, error) {
rollup, err := d.getOrCreateRollup(req.RollupId)
if err != nil {
return nil, err
}

now := time.Now()
rollup.lastBatchHashMutex.RLock()
lastBatchHash := rollup.lastBatchHash
rollup.lastBatchHashMutex.RUnlock()

if !reflect.DeepEqual(lastBatchHash, req.LastBatchHash) {
return nil, fmt.Errorf("batch hash mismatch: lastBatchHash = %x, req.LastBatchHash = %x", lastBatchHash, req.LastBatchHash)
}

batch := rollup.tq.GetNextBatch(req.MaxBytes)
batchRes := &sequencing.GetNextBatchResponse{Batch: batch, Timestamp: now}
// If there are no transactions, return empty batch without updating the last batch hash
if len(batch.Transactions) == 0 {
return batchRes, nil
}

h, err := batch.Hash()
if err != nil {
return nil, err
}

rollup.lastBatchHashMutex.Lock()
rollup.lastBatchHash = h
rollup.lastBatchHashMutex.Unlock()

rollup.seenBatchesMutex.Lock()
rollup.seenBatches[hex.EncodeToString(h)] = struct{}{}
rollup.seenBatchesMutex.Unlock()
return batchRes, nil
}

// VerifyBatch implements sequencing.Sequencer.
func (d *MultiRollupSequencer) VerifyBatch(ctx context.Context, req sequencing.VerifyBatchRequest) (*sequencing.VerifyBatchResponse, error) {
rollup, err := d.getOrCreateRollup(req.RollupId)
if err != nil {
return nil, err
}

rollup.seenBatchesMutex.Lock()
defer rollup.seenBatchesMutex.Unlock()
key := hex.EncodeToString(req.BatchHash)
if _, exists := rollup.seenBatches[key]; exists {
return &sequencing.VerifyBatchResponse{Status: true}, nil
}
return &sequencing.VerifyBatchResponse{Status: false}, nil
}

// getOrCreateRollup returns the RollupData for a given rollupId, creating it if necessary.
func (d *MultiRollupSequencer) getOrCreateRollup(rollupId []byte) (*RollupData, error) {
rollupKey := hex.EncodeToString(rollupId)

d.rollupsMutex.Lock()
defer d.rollupsMutex.Unlock()
rollup, exists := d.rollups[rollupKey]
if exists {
return rollup, nil
}

// Double-check existence after acquiring write lock
if rollup, exists := d.rollups[rollupKey]; exists {
return rollup, nil
}

// Create a new RollupData if it doesn't exist
rollup = &RollupData{
tq: NewTransactionQueue(),
seenBatches: make(map[string]struct{}, 0),
}
d.rollups[rollupKey] = rollup
return rollup, nil
}

// NewMultiRollupSequencer creates a new MultiRollupSequencer
func NewMultiRollupSequencer() *MultiRollupSequencer {
return &MultiRollupSequencer{
rollups: make(map[string]*RollupData),
}
}

var _ sequencing.Sequencer = &MultiRollupSequencer{}
Loading

0 comments on commit 82aa188

Please sign in to comment.