From 50fe9a6f9498326ef7276f125dbae16d1b544b00 Mon Sep 17 00:00:00 2001 From: gupadhyaya Date: Tue, 1 Oct 2024 17:17:37 +0400 Subject: [PATCH 01/13] extend api to include rollup id, add Hash function to Batch, add maxBytes --- go.mod | 4 + go.sum | 10 ++ proto/sequencing/sequencing.proto | 10 +- proxy/grpc/client.go | 29 ++-- proxy/grpc/server.go | 12 +- sequencing.go | 40 +++++- serialization.go | 11 ++ test/dummy.go | 49 +++---- test/dummy_test.go | 130 +++++++++++++++++ types/pb/sequencing/sequencing.pb.go | 206 +++++++++++++++++++++++---- 10 files changed, 419 insertions(+), 82 deletions(-) create mode 100644 test/dummy_test.go diff --git a/go.mod b/go.mod index aaa9a34..c0fc44a 100644 --- a/go.mod +++ b/go.mod @@ -4,14 +4,18 @@ go 1.21.0 require ( github.com/cosmos/gogoproto v1.7.0 + github.com/stretchr/testify v1.8.4 google.golang.org/grpc v1.67.0 ) require ( + github.com/davecgh/go-spew v1.1.1 // indirect github.com/google/go-cmp v0.6.0 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect golang.org/x/net v0.28.0 // indirect golang.org/x/sys v0.24.0 // indirect golang.org/x/text v0.17.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed // indirect google.golang.org/protobuf v1.34.2 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 3c7c2b1..196891a 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,15 @@ github.com/cosmos/gogoproto v1.7.0 h1:79USr0oyXAbxg3rspGh/m4SWNyoz/GLaAh0QlCe2fro= github.com/cosmos/gogoproto v1.7.0/go.mod h1:yWChEv5IUEYURQasfyBW5ffkMHR/90hiHgbNgrtp4j0= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= @@ -16,3 +22,7 @@ google.golang.org/grpc v1.67.0 h1:IdH9y6PF5MPSdAntIcpjQ+tXO41pcQsfZV2RxtQgVcw= google.golang.org/grpc v1.67.0/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/proto/sequencing/sequencing.proto b/proto/sequencing/sequencing.proto index 135763b..e488230 100644 --- a/proto/sequencing/sequencing.proto +++ b/proto/sequencing/sequencing.proto @@ -29,8 +29,12 @@ service SequencerOutput { // GetNextBatchRequest ... message GetNextBatchRequest { + // the unhashed rollup id + bytes rollup_id = 1; // Merkle tree hash of the last batch - bytes last_batch_hash = 1; + bytes last_batch_hash = 2; + // maximum bytes that execution client can support per block + uint64 max_bytes = 3; } // GetNextBatchResponse ... @@ -52,8 +56,10 @@ service BatchVerifier { // VerifyBatchRequest ... message VerifyBatchRequest { + // the unhashed rollup id + bytes rollup_id = 1; // Merkle tree hash of the batch - bytes batch_hash = 1; + bytes batch_hash = 2; } // VerifyBatchResponse diff --git a/proxy/grpc/client.go b/proxy/grpc/client.go index 1a15626..f030004 100644 --- a/proxy/grpc/client.go +++ b/proxy/grpc/client.go @@ -2,7 +2,6 @@ package grpc import ( "context" - "time" "google.golang.org/grpc" @@ -46,34 +45,36 @@ func (c *Client) Stop() error { } // SubmitRollupTransaction submits a transaction from rollup to sequencer. -func (c *Client) SubmitRollupTransaction(ctx context.Context, rollupId []byte, tx []byte) error { +func (c *Client) SubmitRollupTransaction(ctx context.Context, req sequencing.SubmitRollupTransactionRequest) (*sequencing.SubmitRollupTransactionResponse, error) { _, err := c.SequencerInputClient.SubmitRollupTransaction(ctx, &pbseq.SubmitRollupTransactionRequest{ - RollupId: rollupId, - Data: tx, + RollupId: req.RollupId, + Data: req.RollupId, }) - return err + return nil, err } // GetNextBatch returns the next batch of transactions from sequencer to rollup. -func (c *Client) GetNextBatch(ctx context.Context, lastBatchHash []byte) (*sequencing.Batch, time.Time, error) { - resp, err := c.SequencerOutputClient.GetNextBatch(ctx, &pbseq.GetNextBatchRequest{LastBatchHash: lastBatchHash[:]}) +func (c *Client) GetNextBatch(ctx context.Context, req sequencing.GetNextBatchRequest) (*sequencing.GetNextBatchResponse, error) { + resp, err := c.SequencerOutputClient.GetNextBatch(ctx, &pbseq.GetNextBatchRequest{RollupId: req.RollupId, LastBatchHash: req.LastBatchHash[:]}) if err != nil { - return nil, time.Now(), err + return nil, err } b := &sequencing.Batch{} b.FromProto(resp.Batch) t, err := types.TimestampFromProto(resp.Timestamp) if err != nil { - return nil, time.Now(), err + return nil, err } - return b, t, nil + return &sequencing.GetNextBatchResponse{Batch: b, Timestamp: t}, nil } // VerifyBatch verifies a batch of transactions received from the sequencer. -func (c *Client) VerifyBatch(ctx context.Context, batchHash []byte) (bool, error) { - resp, err := c.BatchVerifierClient.VerifyBatch(ctx, &pbseq.VerifyBatchRequest{BatchHash: batchHash[:]}) +func (c *Client) VerifyBatch(ctx context.Context, req sequencing.VerifyBatchRequest) (*sequencing.VerifyBatchResponse, error) { + resp, err := c.BatchVerifierClient.VerifyBatch(ctx, &pbseq.VerifyBatchRequest{RollupId: req.RollupId, BatchHash: req.BatchHash[:]}) if err != nil { - return false, err + return nil, err } - return resp.Status, nil + return &sequencing.VerifyBatchResponse{Status: resp.Status}, nil } + +var _ sequencing.Sequencer = &Client{} diff --git a/proxy/grpc/server.go b/proxy/grpc/server.go index 307bcff..fd01526 100644 --- a/proxy/grpc/server.go +++ b/proxy/grpc/server.go @@ -46,7 +46,7 @@ type proxyVerificationSrv struct { // SubmitRollupTransaction submits a transaction from rollup to sequencer. func (s *proxyInputSrv) SubmitRollupTransaction(ctx context.Context, req *pbseq.SubmitRollupTransactionRequest) (*pbseq.SubmitRollupTransactionResponse, error) { - err := s.SequencerInput.SubmitRollupTransaction(ctx, req.RollupId, req.Data) + _, err := s.SequencerInput.SubmitRollupTransaction(ctx, sequencing.SubmitRollupTransactionRequest{RollupId: req.RollupId, Tx: req.Data}) if err != nil { return nil, err } @@ -55,22 +55,22 @@ func (s *proxyInputSrv) SubmitRollupTransaction(ctx context.Context, req *pbseq. // GetNextBatch returns the next batch of transactions from sequencer to rollup. func (s *proxyOutputSrv) GetNextBatch(ctx context.Context, req *pbseq.GetNextBatchRequest) (*pbseq.GetNextBatchResponse, error) { - batch, timestamp, err := s.SequencerOutput.GetNextBatch(ctx, req.LastBatchHash[:]) + resp, err := s.SequencerOutput.GetNextBatch(ctx, sequencing.GetNextBatchRequest{RollupId: req.RollupId, LastBatchHash: req.LastBatchHash[:]}) if err != nil { return nil, err } - ts, err := types.TimestampProto(timestamp) + ts, err := types.TimestampProto(resp.Timestamp) if err != nil { return nil, err } - return &pbseq.GetNextBatchResponse{Batch: batch.ToProto(), Timestamp: ts}, nil + return &pbseq.GetNextBatchResponse{Batch: resp.Batch.ToProto(), Timestamp: ts}, nil } // VerifyBatch verifies a batch of transactions received from the sequencer. func (s *proxyVerificationSrv) VerifyBatch(ctx context.Context, req *pbseq.VerifyBatchRequest) (*pbseq.VerifyBatchResponse, error) { - ok, err := s.BatchVerifier.VerifyBatch(ctx, req.BatchHash[:]) + resp, err := s.BatchVerifier.VerifyBatch(ctx, sequencing.VerifyBatchRequest{BatchHash: req.BatchHash}) if err != nil { return nil, err } - return &pbseq.VerifyBatchResponse{Status: ok}, nil + return &pbseq.VerifyBatchResponse{Status: resp.Status}, nil } diff --git a/sequencing.go b/sequencing.go index 461de14..407a130 100644 --- a/sequencing.go +++ b/sequencing.go @@ -15,7 +15,7 @@ type Sequencer interface { // SequencerInput provides a method for submitting a transaction from rollup to sequencer type SequencerInput interface { // SubmitRollupTransaction submits a transaction from rollup to sequencer - SubmitRollupTransaction(ctx context.Context, rollupId RollupId, tx Tx) error + SubmitRollupTransaction(ctx context.Context, req SubmitRollupTransactionRequest) (*SubmitRollupTransactionResponse, error) } // SequencerOutput provides a method for getting the next batch of transactions from sequencer to rollup @@ -23,13 +23,13 @@ type SequencerOutput interface { // GetNextBatch returns the next batch of transactions from sequencer to rollup // lastBatch is the last batch of transactions received from the sequencer // returns the next batch of transactions and an error if any from the sequencer - GetNextBatch(ctx context.Context, lastBatchHash Hash) (*Batch, time.Time, error) + GetNextBatch(ctx context.Context, req GetNextBatchRequest) (*GetNextBatchResponse, error) } // BatchVerifier provides a method for verifying a batch of transactions received from the sequencer type BatchVerifier interface { // VerifyBatch verifies a batch of transactions received from the sequencer - VerifyBatch(ctx context.Context, batchHash Hash) (bool, error) + VerifyBatch(ctx context.Context, req VerifyBatchRequest) (*VerifyBatchResponse, error) } // RollupId is a unique identifier for a rollup chain @@ -45,3 +45,37 @@ type Hash = []byte type Batch struct { Transactions []Tx } + +// SubmitRollupTransactionRequest is a request to submit a transaction from rollup to sequencer +type SubmitRollupTransactionRequest struct { + RollupId RollupId + Tx Tx +} + +// SubmitRollupTransactionResponse is a response to submitting a transaction from rollup to sequencer +type SubmitRollupTransactionResponse struct { +} + +// GetNextBatchRequest is a request to get the next batch of transactions from sequencer to rollup +type GetNextBatchRequest struct { + RollupId RollupId + LastBatchHash Hash + MaxBytes uint64 +} + +// GetNextBatchResponse is a response to getting the next batch of transactions from sequencer to rollup +type GetNextBatchResponse struct { + Batch *Batch + Timestamp time.Time +} + +// VerifyBatchRequest is a request to verify a batch of transactions received from the sequencer +type VerifyBatchRequest struct { + RollupId RollupId + BatchHash Hash +} + +// VerifyBatchResponse is a response to verifying a batch of transactions received from the sequencer +type VerifyBatchResponse struct { + Status bool +} diff --git a/serialization.go b/serialization.go index 0b65a65..71bc036 100644 --- a/serialization.go +++ b/serialization.go @@ -1,6 +1,8 @@ package sequencing import ( + "crypto/sha256" + pbseq "github.com/rollkit/go-sequencing/types/pb/sequencing" ) @@ -46,3 +48,12 @@ func (batch *Batch) Unmarshal(data []byte) error { batch.FromProto(&pb) return nil } + +func (batch *Batch) Hash() ([]byte, error) { + batchBytes, err := batch.Marshal() + if err != nil { + return nil, err + } + hash := sha256.Sum256(batchBytes) + return hash[:], nil +} diff --git a/test/dummy.go b/test/dummy.go index 4936b82..4a17bdc 100644 --- a/test/dummy.go +++ b/test/dummy.go @@ -3,7 +3,6 @@ package test import ( "bytes" "context" - "crypto/sha256" "errors" "sync" "time" @@ -59,53 +58,54 @@ type DummySequencer struct { } // SubmitRollupTransaction implements sequencing.Sequencer. -func (d *DummySequencer) SubmitRollupTransaction(ctx context.Context, rollupId []byte, tx []byte) error { +func (d *DummySequencer) SubmitRollupTransaction(ctx context.Context, req sequencing.SubmitRollupTransactionRequest) (*sequencing.SubmitRollupTransactionResponse, error) { if d.RollupId == nil { - d.RollupId = rollupId + d.RollupId = req.RollupId } else { - if !bytes.Equal(d.RollupId, rollupId) { - return ErrorRollupIdMismatch + if !bytes.Equal(d.RollupId, req.RollupId) { + return nil, ErrorRollupIdMismatch } } - d.tq.AddTransaction(tx) - return nil + d.tq.AddTransaction(req.Tx) + return nil, nil } // GetNextBatch implements sequencing.Sequencer. -func (d *DummySequencer) GetNextBatch(ctx context.Context, lastBatchHash []byte) (*sequencing.Batch, time.Time, error) { +func (d *DummySequencer) GetNextBatch(ctx context.Context, req sequencing.GetNextBatchRequest) (*sequencing.GetNextBatchResponse, error) { now := time.Now() if d.lastBatchHash == nil { - if lastBatchHash != nil { - return nil, now, errors.New("lastBatch is supposed to be nil") + if req.LastBatchHash != nil { + return nil, errors.New("lastBatch is supposed to be nil") } - } else if lastBatchHash == nil { - return nil, now, errors.New("lastBatch is not supposed to be nil") + } else if req.LastBatchHash == nil { + return nil, errors.New("lastBatch is not supposed to be nil") } else { - if !bytes.Equal(d.lastBatchHash, lastBatchHash) { - return nil, now, errors.New("supplied lastBatch does not match with sequencer last batch") + if !bytes.Equal(d.lastBatchHash, req.LastBatchHash) { + return nil, errors.New("supplied lastBatch does not match with sequencer last batch") } } batch := d.tq.GetNextBatch() + 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 { - return batch, now, nil + return batchRes, nil } - batchBytes, err := batch.Marshal() + h, err := batch.Hash() if err != nil { - return nil, now, err + return nil, err } - d.lastBatchHash = hashSHA256(batchBytes) + d.lastBatchHash = h d.seenBatches[string(d.lastBatchHash)] = struct{}{} - return batch, now, nil + return batchRes, nil } // VerifyBatch implements sequencing.Sequencer. -func (d *DummySequencer) VerifyBatch(ctx context.Context, batchHash []byte) (bool, error) { - _, ok := d.seenBatches[string(batchHash)] - return ok, nil +func (d *DummySequencer) VerifyBatch(ctx context.Context, req sequencing.VerifyBatchRequest) (*sequencing.VerifyBatchResponse, error) { + _, ok := d.seenBatches[string(req.BatchHash)] + return &sequencing.VerifyBatchResponse{Status: ok}, nil } // NewDummySequencer creates a new DummySequencer @@ -116,9 +116,4 @@ func NewDummySequencer() *DummySequencer { } } -func hashSHA256(data []byte) []byte { - hash := sha256.Sum256(data) - return hash[:] -} - var _ sequencing.Sequencer = &DummySequencer{} diff --git a/test/dummy_test.go b/test/dummy_test.go new file mode 100644 index 0000000..8993d36 --- /dev/null +++ b/test/dummy_test.go @@ -0,0 +1,130 @@ +package test + +import ( + "context" + "testing" + "time" + + "github.com/rollkit/go-sequencing" + "github.com/stretchr/testify/assert" +) + +func TestSubmitRollupTransaction(t *testing.T) { + sequencer := NewDummySequencer() + + // Define a test rollup ID and transaction + rollupId := []byte("test_rollup_id") + tx := []byte("test_transaction") + + // Submit a transaction + req := sequencing.SubmitRollupTransactionRequest{ + RollupId: rollupId, + Tx: tx, + } + resp, err := sequencer.SubmitRollupTransaction(context.Background(), req) + + // Assert no error + assert.NoError(t, err) + // Assert the transaction was successfully added to the queue + assert.Nil(t, resp) + assert.Equal(t, rollupId, sequencer.RollupId) +} + +func TestSubmitRollupTransaction_RollupIdMismatch(t *testing.T) { + sequencer := NewDummySequencer() + + // Submit a transaction with one rollup ID + rollupId1 := []byte("test_rollup_id1") + tx1 := []byte("test_transaction_1") + req1 := sequencing.SubmitRollupTransactionRequest{ + RollupId: rollupId1, + Tx: tx1, + } + sequencer.SubmitRollupTransaction(context.Background(), req1) + + // Submit a transaction with a different rollup ID (should cause an error) + rollupId2 := []byte("test_rollup_id2") + tx2 := []byte("test_transaction_2") + req2 := sequencing.SubmitRollupTransactionRequest{ + RollupId: rollupId2, + Tx: tx2, + } + _, err := sequencer.SubmitRollupTransaction(context.Background(), req2) + + // Assert that the error is ErrorRollupIdMismatch + assert.Error(t, err) + assert.Equal(t, err, ErrorRollupIdMismatch) +} + +func TestGetNextBatch(t *testing.T) { + sequencer := NewDummySequencer() + + // Define a test rollup ID and transaction + rollupId := []byte("test_rollup_id") + tx := []byte("test_transaction") + + // Submit a transaction + req := sequencing.SubmitRollupTransactionRequest{ + RollupId: rollupId, + Tx: tx, + } + sequencer.SubmitRollupTransaction(context.Background(), req) + + // Get the next batch + getBatchReq := sequencing.GetNextBatchRequest{ + RollupId: rollupId, + LastBatchHash: nil, + MaxBytes: 1024, + } + batchRes, err := sequencer.GetNextBatch(context.Background(), getBatchReq) + + // Assert no error + assert.NoError(t, err) + + // Assert that the returned batch contains the correct transaction + assert.NotNil(t, batchRes.Batch) + assert.Equal(t, 1, len(batchRes.Batch.Transactions)) + assert.Equal(t, tx, batchRes.Batch.Transactions[0]) + + // Assert timestamp is recent + assert.WithinDuration(t, time.Now(), batchRes.Timestamp, time.Second) +} + +func TestVerifyBatch(t *testing.T) { + sequencer := NewDummySequencer() + + // Define a test rollup ID and transaction + rollupId := []byte("test_rollup_id") + tx := []byte("test_transaction") + + // Submit a transaction + req := sequencing.SubmitRollupTransactionRequest{ + RollupId: rollupId, + Tx: tx, + } + sequencer.SubmitRollupTransaction(context.Background(), req) + + // Get the next batch to generate batch hash + getBatchReq := sequencing.GetNextBatchRequest{ + RollupId: rollupId, + LastBatchHash: nil, + MaxBytes: 1024, + } + batchRes, err := sequencer.GetNextBatch(context.Background(), getBatchReq) + assert.NoError(t, err) + + batchHash, err := batchRes.Batch.Hash() + assert.NoError(t, err) + // Verify the batch + verifyReq := sequencing.VerifyBatchRequest{ + RollupId: rollupId, + BatchHash: batchHash, // hash of the submitted transaction + } + verifyRes, err := sequencer.VerifyBatch(context.Background(), verifyReq) + + // Assert no error + assert.NoError(t, err) + + // Assert that the batch was verified successfully + assert.True(t, verifyRes.Status) +} diff --git a/types/pb/sequencing/sequencing.pb.go b/types/pb/sequencing/sequencing.pb.go index 706d0ae..0582234 100644 --- a/types/pb/sequencing/sequencing.pb.go +++ b/types/pb/sequencing/sequencing.pb.go @@ -122,8 +122,12 @@ var xxx_messageInfo_SubmitRollupTransactionResponse proto.InternalMessageInfo // GetNextBatchRequest ... type GetNextBatchRequest struct { + // the unhashed rollup id + RollupId []byte `protobuf:"bytes,1,opt,name=rollup_id,json=rollupId,proto3" json:"rollup_id,omitempty"` // Merkle tree hash of the last batch - LastBatchHash []byte `protobuf:"bytes,1,opt,name=last_batch_hash,json=lastBatchHash,proto3" json:"last_batch_hash,omitempty"` + LastBatchHash []byte `protobuf:"bytes,2,opt,name=last_batch_hash,json=lastBatchHash,proto3" json:"last_batch_hash,omitempty"` + // maximum bytes that execution client can support per block + MaxBytes uint64 `protobuf:"varint,3,opt,name=max_bytes,json=maxBytes,proto3" json:"max_bytes,omitempty"` } func (m *GetNextBatchRequest) Reset() { *m = GetNextBatchRequest{} } @@ -159,6 +163,13 @@ func (m *GetNextBatchRequest) XXX_DiscardUnknown() { var xxx_messageInfo_GetNextBatchRequest proto.InternalMessageInfo +func (m *GetNextBatchRequest) GetRollupId() []byte { + if m != nil { + return m.RollupId + } + return nil +} + func (m *GetNextBatchRequest) GetLastBatchHash() []byte { if m != nil { return m.LastBatchHash @@ -166,6 +177,13 @@ func (m *GetNextBatchRequest) GetLastBatchHash() []byte { return nil } +func (m *GetNextBatchRequest) GetMaxBytes() uint64 { + if m != nil { + return m.MaxBytes + } + return 0 +} + // GetNextBatchResponse ... type GetNextBatchResponse struct { Batch *Batch `protobuf:"bytes,1,opt,name=batch,proto3" json:"batch,omitempty"` @@ -266,8 +284,10 @@ func (m *Batch) GetTransactions() [][]byte { // VerifyBatchRequest ... type VerifyBatchRequest struct { + // the unhashed rollup id + RollupId []byte `protobuf:"bytes,1,opt,name=rollup_id,json=rollupId,proto3" json:"rollup_id,omitempty"` // Merkle tree hash of the batch - BatchHash []byte `protobuf:"bytes,1,opt,name=batch_hash,json=batchHash,proto3" json:"batch_hash,omitempty"` + BatchHash []byte `protobuf:"bytes,2,opt,name=batch_hash,json=batchHash,proto3" json:"batch_hash,omitempty"` } func (m *VerifyBatchRequest) Reset() { *m = VerifyBatchRequest{} } @@ -303,6 +323,13 @@ func (m *VerifyBatchRequest) XXX_DiscardUnknown() { var xxx_messageInfo_VerifyBatchRequest proto.InternalMessageInfo +func (m *VerifyBatchRequest) GetRollupId() []byte { + if m != nil { + return m.RollupId + } + return nil +} + func (m *VerifyBatchRequest) GetBatchHash() []byte { if m != nil { return m.BatchHash @@ -369,34 +396,36 @@ func init() { func init() { proto.RegisterFile("sequencing/sequencing.proto", fileDescriptor_b389fdbc59f03c95) } var fileDescriptor_b389fdbc59f03c95 = []byte{ - // 430 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x52, 0x3d, 0x8f, 0xd3, 0x40, - 0x10, 0xb5, 0x81, 0x3b, 0x5d, 0x26, 0x3e, 0x4e, 0xec, 0x21, 0xb0, 0x7c, 0x62, 0x1d, 0x5c, 0xc0, - 0x89, 0x13, 0x8e, 0xe4, 0x6b, 0x68, 0x68, 0xae, 0x81, 0x34, 0x7c, 0x38, 0x11, 0x6d, 0xb4, 0x4e, - 0x36, 0xb1, 0x25, 0xc7, 0x36, 0xde, 0xb1, 0x44, 0xfe, 0x00, 0x35, 0x3f, 0x8b, 0x32, 0x25, 0x25, - 0x4a, 0xfe, 0x08, 0xf2, 0xfa, 0x5b, 0xc1, 0x88, 0xce, 0x7e, 0xf3, 0xe6, 0xcd, 0xbc, 0x37, 0x0b, - 0x57, 0x82, 0x7f, 0xcd, 0x78, 0xb4, 0x08, 0xa2, 0xf5, 0xb8, 0xf9, 0xb4, 0x93, 0x34, 0xc6, 0x98, - 0x40, 0x83, 0x18, 0xe6, 0x3a, 0x8e, 0xd7, 0x21, 0x1f, 0xcb, 0x8a, 0x97, 0xad, 0xc6, 0x18, 0x6c, - 0xb8, 0x40, 0xb6, 0x49, 0x0a, 0xb2, 0xf5, 0x19, 0xe8, 0x34, 0xf3, 0x36, 0x01, 0xba, 0x71, 0x18, - 0x66, 0xc9, 0x2c, 0x65, 0x91, 0x60, 0x0b, 0x0c, 0xe2, 0xc8, 0xcd, 0x55, 0x04, 0x92, 0x2b, 0x18, - 0xa4, 0xb2, 0x36, 0x0f, 0x96, 0xba, 0x3a, 0x52, 0xaf, 0x35, 0xf7, 0xac, 0x00, 0x26, 0x4b, 0x42, - 0xe0, 0xc1, 0x92, 0x21, 0xd3, 0xef, 0x49, 0x5c, 0x7e, 0x5b, 0xcf, 0xc1, 0xec, 0x95, 0x14, 0x49, - 0x1c, 0x09, 0x6e, 0xbd, 0x85, 0xcb, 0x77, 0x1c, 0x3f, 0xf0, 0x6f, 0x78, 0xc7, 0x70, 0xe1, 0x57, - 0xa3, 0x5e, 0xc0, 0x45, 0xc8, 0x04, 0xce, 0xbd, 0x1c, 0x9c, 0xfb, 0x4c, 0xf8, 0xe5, 0xc0, 0xf3, - 0x1c, 0x96, 0xd4, 0xf7, 0x4c, 0xf8, 0xd6, 0x16, 0x1e, 0x77, 0xdb, 0x0b, 0x59, 0xf2, 0x12, 0x4e, - 0x64, 0xab, 0xec, 0x1a, 0x3a, 0x8f, 0xec, 0x56, 0x36, 0x05, 0xb3, 0xa8, 0x93, 0x37, 0x30, 0xa8, - 0x83, 0x90, 0xbb, 0x0f, 0x1d, 0xc3, 0x2e, 0xa2, 0xb2, 0xab, 0xa8, 0xec, 0x59, 0xc5, 0x70, 0x1b, - 0xb2, 0x75, 0x03, 0x27, 0x52, 0x89, 0x58, 0xa0, 0x61, 0xe3, 0x4c, 0xe8, 0xea, 0xe8, 0xfe, 0xb5, - 0xe6, 0x76, 0x30, 0xeb, 0x16, 0xc8, 0x17, 0x9e, 0x06, 0xab, 0x6d, 0xc7, 0xe5, 0x33, 0x80, 0x23, - 0x83, 0x03, 0xaf, 0x36, 0xf7, 0x1a, 0x2e, 0x3b, 0x4d, 0xa5, 0xb7, 0x27, 0x70, 0x2a, 0x90, 0x61, - 0x26, 0x64, 0xc7, 0x99, 0x5b, 0xfe, 0x39, 0xdf, 0x55, 0x78, 0x38, 0x2d, 0x6c, 0xf2, 0x74, 0x12, - 0x25, 0x19, 0x12, 0x84, 0xa7, 0x3d, 0x07, 0x20, 0xaf, 0xda, 0x91, 0xfc, 0xfb, 0xf0, 0xc6, 0xcd, - 0x7f, 0x71, 0xcb, 0x8b, 0x2a, 0xce, 0x0a, 0x2e, 0xea, 0x3d, 0x3e, 0x66, 0x98, 0x2f, 0x32, 0x05, - 0xad, 0x7d, 0x27, 0x62, 0xb6, 0x15, 0xff, 0xf2, 0x00, 0x8c, 0x51, 0x3f, 0xa1, 0x9e, 0xc3, 0xe0, - 0x5c, 0x42, 0x32, 0xa4, 0x80, 0xa7, 0xe4, 0x13, 0x0c, 0x5b, 0x81, 0x11, 0xda, 0xd6, 0x38, 0x8e, - 0xdf, 0x30, 0x7b, 0xeb, 0xd5, 0x88, 0x3b, 0xfd, 0xe7, 0x9e, 0xaa, 0xbb, 0x3d, 0x55, 0x7f, 0xef, - 0xa9, 0xfa, 0xe3, 0x40, 0x95, 0xdd, 0x81, 0x2a, 0xbf, 0x0e, 0x54, 0xf1, 0x4e, 0xe5, 0xeb, 0xb8, - 0xfd, 0x13, 0x00, 0x00, 0xff, 0xff, 0xa0, 0xc1, 0x62, 0x61, 0x81, 0x03, 0x00, 0x00, + // 453 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0xcf, 0x8f, 0xd2, 0x40, + 0x14, 0xc7, 0x19, 0xf7, 0x47, 0xe0, 0xc1, 0xba, 0x71, 0xd6, 0x68, 0xd3, 0x8d, 0x03, 0xce, 0x41, + 0x89, 0x1b, 0x4b, 0x82, 0x17, 0xcf, 0x5c, 0x74, 0x2f, 0xba, 0x96, 0x8d, 0x57, 0x32, 0x85, 0x01, + 0x9a, 0xf4, 0x97, 0x9d, 0xd7, 0x08, 0xff, 0x80, 0x67, 0xff, 0x2c, 0x8f, 0x7b, 0xf4, 0x68, 0xe0, + 0x1f, 0x31, 0x9d, 0xb6, 0xb4, 0x04, 0x6b, 0xb8, 0xcd, 0xbc, 0xf7, 0xed, 0xf7, 0x3b, 0xfd, 0xbc, + 0x07, 0xd7, 0x4a, 0x7e, 0x4b, 0x64, 0x30, 0x75, 0x83, 0xc5, 0xa0, 0x3c, 0x5a, 0x51, 0x1c, 0x62, + 0x48, 0xa1, 0xac, 0x98, 0xdd, 0x45, 0x18, 0x2e, 0x3c, 0x39, 0xd0, 0x1d, 0x27, 0x99, 0x0f, 0xd0, + 0xf5, 0xa5, 0x42, 0xe1, 0x47, 0x99, 0x98, 0x7f, 0x01, 0x36, 0x4e, 0x1c, 0xdf, 0x45, 0x3b, 0xf4, + 0xbc, 0x24, 0xba, 0x8f, 0x45, 0xa0, 0xc4, 0x14, 0xdd, 0x30, 0xb0, 0x53, 0x17, 0x85, 0xf4, 0x1a, + 0x5a, 0xb1, 0xee, 0x4d, 0xdc, 0x99, 0x41, 0x7a, 0xa4, 0xdf, 0xb1, 0x9b, 0x59, 0xe1, 0x76, 0x46, + 0x29, 0x9c, 0xce, 0x04, 0x0a, 0xe3, 0x91, 0xae, 0xeb, 0x33, 0x7f, 0x09, 0xdd, 0x5a, 0x4b, 0x15, + 0x85, 0x81, 0x92, 0xfc, 0x3b, 0x5c, 0x7d, 0x90, 0xf8, 0x49, 0xae, 0x70, 0x24, 0x70, 0xba, 0x3c, + 0x2a, 0xea, 0x15, 0x5c, 0x7a, 0x42, 0xe1, 0xc4, 0x49, 0xbf, 0x98, 0x2c, 0x85, 0x5a, 0xe6, 0xa9, + 0x17, 0x69, 0x59, 0xfb, 0x7c, 0x14, 0x6a, 0x99, 0x9a, 0xf8, 0x62, 0x35, 0x71, 0xd6, 0x28, 0x95, + 0x71, 0xd2, 0x23, 0xfd, 0x53, 0xbb, 0xe9, 0x8b, 0xd5, 0x28, 0xbd, 0xf3, 0x35, 0x3c, 0xdd, 0x0f, + 0xce, 0x1e, 0x44, 0x5f, 0xc3, 0x99, 0xf6, 0xd5, 0xa9, 0xed, 0xe1, 0x13, 0xab, 0x42, 0x35, 0x53, + 0x66, 0x7d, 0xfa, 0x1e, 0x5a, 0x3b, 0x84, 0x3a, 0xbf, 0x3d, 0x34, 0xad, 0x0c, 0xb2, 0x55, 0x40, + 0xb6, 0xee, 0x0b, 0x85, 0x5d, 0x8a, 0xf9, 0x0d, 0x9c, 0x69, 0x27, 0xca, 0xa1, 0x83, 0x25, 0x13, + 0x65, 0x90, 0xde, 0x49, 0xbf, 0x63, 0xef, 0xd5, 0xf8, 0x1d, 0xd0, 0xaf, 0x32, 0x76, 0xe7, 0xeb, + 0xe3, 0xf9, 0xbc, 0x00, 0x38, 0x40, 0xd3, 0x72, 0x0a, 0x2c, 0xfc, 0x2d, 0x5c, 0xed, 0x39, 0xe6, + 0x3f, 0xfe, 0x0c, 0xce, 0x15, 0x0a, 0x4c, 0x94, 0xf6, 0x6b, 0xda, 0xf9, 0x6d, 0xf8, 0x83, 0xc0, + 0xe3, 0x71, 0xc6, 0x40, 0xc6, 0xb7, 0x41, 0x94, 0x20, 0x45, 0x78, 0x5e, 0x33, 0x57, 0xfa, 0xa6, + 0xca, 0xeb, 0xff, 0xfb, 0x64, 0xde, 0x1c, 0xa5, 0xcd, 0x17, 0xa5, 0x31, 0x9c, 0xc3, 0xe5, 0xee, + 0x1d, 0x9f, 0x13, 0x4c, 0x1f, 0x32, 0x86, 0x4e, 0x75, 0x88, 0xb4, 0x5b, 0x75, 0xfc, 0xc7, 0x5e, + 0x99, 0xbd, 0x7a, 0xc1, 0x2e, 0x47, 0xc0, 0x85, 0x2e, 0x69, 0x48, 0xae, 0x8c, 0xe9, 0x1d, 0xb4, + 0x2b, 0xc0, 0x28, 0xab, 0x7a, 0x1c, 0xce, 0xc6, 0xec, 0xd6, 0xf6, 0x8b, 0x88, 0x91, 0xf1, 0x6b, + 0xc3, 0xc8, 0xc3, 0x86, 0x91, 0x3f, 0x1b, 0x46, 0x7e, 0x6e, 0x59, 0xe3, 0x61, 0xcb, 0x1a, 0xbf, + 0xb7, 0xac, 0xe1, 0x9c, 0xeb, 0xd5, 0x79, 0xf7, 0x37, 0x00, 0x00, 0xff, 0xff, 0x1b, 0xd3, 0x53, + 0x7b, 0xd8, 0x03, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -712,11 +741,23 @@ func (m *GetNextBatchRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.MaxBytes != 0 { + i = encodeVarintSequencing(dAtA, i, uint64(m.MaxBytes)) + i-- + dAtA[i] = 0x18 + } if len(m.LastBatchHash) > 0 { i -= len(m.LastBatchHash) copy(dAtA[i:], m.LastBatchHash) i = encodeVarintSequencing(dAtA, i, uint64(len(m.LastBatchHash))) i-- + dAtA[i] = 0x12 + } + if len(m.RollupId) > 0 { + i -= len(m.RollupId) + copy(dAtA[i:], m.RollupId) + i = encodeVarintSequencing(dAtA, i, uint64(len(m.RollupId))) + i-- dAtA[i] = 0xa } return len(dAtA) - i, nil @@ -826,6 +867,13 @@ func (m *VerifyBatchRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { copy(dAtA[i:], m.BatchHash) i = encodeVarintSequencing(dAtA, i, uint64(len(m.BatchHash))) i-- + dAtA[i] = 0x12 + } + if len(m.RollupId) > 0 { + i -= len(m.RollupId) + copy(dAtA[i:], m.RollupId) + i = encodeVarintSequencing(dAtA, i, uint64(len(m.RollupId))) + i-- dAtA[i] = 0xa } return len(dAtA) - i, nil @@ -907,10 +955,17 @@ func (m *GetNextBatchRequest) Size() (n int) { } var l int _ = l + l = len(m.RollupId) + if l > 0 { + n += 1 + l + sovSequencing(uint64(l)) + } l = len(m.LastBatchHash) if l > 0 { n += 1 + l + sovSequencing(uint64(l)) } + if m.MaxBytes != 0 { + n += 1 + sovSequencing(uint64(m.MaxBytes)) + } return n } @@ -952,6 +1007,10 @@ func (m *VerifyBatchRequest) Size() (n int) { } var l int _ = l + l = len(m.RollupId) + if l > 0 { + n += 1 + l + sovSequencing(uint64(l)) + } l = len(m.BatchHash) if l > 0 { n += 1 + l + sovSequencing(uint64(l)) @@ -1175,6 +1234,40 @@ func (m *GetNextBatchRequest) Unmarshal(dAtA []byte) error { } switch fieldNum { case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RollupId", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSequencing + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthSequencing + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthSequencing + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RollupId = append(m.RollupId[:0], dAtA[iNdEx:postIndex]...) + if m.RollupId == nil { + m.RollupId = []byte{} + } + iNdEx = postIndex + case 2: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field LastBatchHash", wireType) } @@ -1208,6 +1301,25 @@ func (m *GetNextBatchRequest) Unmarshal(dAtA []byte) error { m.LastBatchHash = []byte{} } iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxBytes", wireType) + } + m.MaxBytes = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSequencing + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MaxBytes |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipSequencing(dAtA[iNdEx:]) @@ -1463,6 +1575,40 @@ func (m *VerifyBatchRequest) Unmarshal(dAtA []byte) error { } switch fieldNum { case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RollupId", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSequencing + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthSequencing + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthSequencing + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RollupId = append(m.RollupId[:0], dAtA[iNdEx:postIndex]...) + if m.RollupId == nil { + m.RollupId = []byte{} + } + iNdEx = postIndex + case 2: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field BatchHash", wireType) } From 245e653d29c9fe85c87ddb31f715766ed5135575 Mon Sep 17 00:00:00 2001 From: gupadhyaya Date: Tue, 1 Oct 2024 17:29:59 +0400 Subject: [PATCH 02/13] minor fixes --- serialization.go | 1 + test/dummy_test.go | 14 +++++++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/serialization.go b/serialization.go index 71bc036..936bf65 100644 --- a/serialization.go +++ b/serialization.go @@ -49,6 +49,7 @@ func (batch *Batch) Unmarshal(data []byte) error { return nil } +// Hash returns the hash of a batch. func (batch *Batch) Hash() ([]byte, error) { batchBytes, err := batch.Marshal() if err != nil { diff --git a/test/dummy_test.go b/test/dummy_test.go index 8993d36..da2b645 100644 --- a/test/dummy_test.go +++ b/test/dummy_test.go @@ -5,8 +5,9 @@ import ( "testing" "time" - "github.com/rollkit/go-sequencing" "github.com/stretchr/testify/assert" + + "github.com/rollkit/go-sequencing" ) func TestSubmitRollupTransaction(t *testing.T) { @@ -40,7 +41,8 @@ func TestSubmitRollupTransaction_RollupIdMismatch(t *testing.T) { RollupId: rollupId1, Tx: tx1, } - sequencer.SubmitRollupTransaction(context.Background(), req1) + _, err := sequencer.SubmitRollupTransaction(context.Background(), req1) + assert.NoError(t, err) // Submit a transaction with a different rollup ID (should cause an error) rollupId2 := []byte("test_rollup_id2") @@ -49,7 +51,7 @@ func TestSubmitRollupTransaction_RollupIdMismatch(t *testing.T) { RollupId: rollupId2, Tx: tx2, } - _, err := sequencer.SubmitRollupTransaction(context.Background(), req2) + _, err = sequencer.SubmitRollupTransaction(context.Background(), req2) // Assert that the error is ErrorRollupIdMismatch assert.Error(t, err) @@ -68,7 +70,8 @@ func TestGetNextBatch(t *testing.T) { RollupId: rollupId, Tx: tx, } - sequencer.SubmitRollupTransaction(context.Background(), req) + _, err := sequencer.SubmitRollupTransaction(context.Background(), req) + assert.NoError(t, err) // Get the next batch getBatchReq := sequencing.GetNextBatchRequest{ @@ -102,7 +105,8 @@ func TestVerifyBatch(t *testing.T) { RollupId: rollupId, Tx: tx, } - sequencer.SubmitRollupTransaction(context.Background(), req) + _, err := sequencer.SubmitRollupTransaction(context.Background(), req) + assert.NoError(t, err) // Get the next batch to generate batch hash getBatchReq := sequencing.GetNextBatchRequest{ From 79a6630f172f0d6ffc778c2440747b136ec05d11 Mon Sep 17 00:00:00 2001 From: gupadhyaya Date: Tue, 1 Oct 2024 17:34:07 +0400 Subject: [PATCH 03/13] fix issues --- proxy/grpc/client.go | 4 ++-- proxy/grpc/server.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/proxy/grpc/client.go b/proxy/grpc/client.go index f030004..4f163dc 100644 --- a/proxy/grpc/client.go +++ b/proxy/grpc/client.go @@ -55,7 +55,7 @@ func (c *Client) SubmitRollupTransaction(ctx context.Context, req sequencing.Sub // GetNextBatch returns the next batch of transactions from sequencer to rollup. func (c *Client) GetNextBatch(ctx context.Context, req sequencing.GetNextBatchRequest) (*sequencing.GetNextBatchResponse, error) { - resp, err := c.SequencerOutputClient.GetNextBatch(ctx, &pbseq.GetNextBatchRequest{RollupId: req.RollupId, LastBatchHash: req.LastBatchHash[:]}) + resp, err := c.SequencerOutputClient.GetNextBatch(ctx, &pbseq.GetNextBatchRequest{RollupId: req.RollupId, LastBatchHash: req.LastBatchHash}) if err != nil { return nil, err } @@ -70,7 +70,7 @@ func (c *Client) GetNextBatch(ctx context.Context, req sequencing.GetNextBatchRe // VerifyBatch verifies a batch of transactions received from the sequencer. func (c *Client) VerifyBatch(ctx context.Context, req sequencing.VerifyBatchRequest) (*sequencing.VerifyBatchResponse, error) { - resp, err := c.BatchVerifierClient.VerifyBatch(ctx, &pbseq.VerifyBatchRequest{RollupId: req.RollupId, BatchHash: req.BatchHash[:]}) + resp, err := c.BatchVerifierClient.VerifyBatch(ctx, &pbseq.VerifyBatchRequest{RollupId: req.RollupId, BatchHash: req.BatchHash}) if err != nil { return nil, err } diff --git a/proxy/grpc/server.go b/proxy/grpc/server.go index fd01526..3fbbd09 100644 --- a/proxy/grpc/server.go +++ b/proxy/grpc/server.go @@ -55,7 +55,7 @@ func (s *proxyInputSrv) SubmitRollupTransaction(ctx context.Context, req *pbseq. // GetNextBatch returns the next batch of transactions from sequencer to rollup. func (s *proxyOutputSrv) GetNextBatch(ctx context.Context, req *pbseq.GetNextBatchRequest) (*pbseq.GetNextBatchResponse, error) { - resp, err := s.SequencerOutput.GetNextBatch(ctx, sequencing.GetNextBatchRequest{RollupId: req.RollupId, LastBatchHash: req.LastBatchHash[:]}) + resp, err := s.SequencerOutput.GetNextBatch(ctx, sequencing.GetNextBatchRequest{RollupId: req.RollupId, LastBatchHash: req.LastBatchHash}) if err != nil { return nil, err } From 67ff8ae4072c74773b0b971bc28097db3d1dff95 Mon Sep 17 00:00:00 2001 From: gupadhyaya Date: Tue, 1 Oct 2024 17:42:52 +0400 Subject: [PATCH 04/13] fix test and comments --- sequencing.go | 10 +++++++++- test/dummy.go | 2 +- test/dummy_test.go | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/sequencing.go b/sequencing.go index 407a130..44c0567 100644 --- a/sequencing.go +++ b/sequencing.go @@ -15,13 +15,18 @@ type Sequencer interface { // SequencerInput provides a method for submitting a transaction from rollup to sequencer type SequencerInput interface { // SubmitRollupTransaction submits a transaction from rollup to sequencer + // RollupId is the unique identifier for the rollup chain + // Tx is the transaction to submit + // returns an error if any from the sequencer SubmitRollupTransaction(ctx context.Context, req SubmitRollupTransactionRequest) (*SubmitRollupTransactionResponse, error) } // SequencerOutput provides a method for getting the next batch of transactions from sequencer to rollup type SequencerOutput interface { // GetNextBatch returns the next batch of transactions from sequencer to rollup - // lastBatch is the last batch of transactions received from the sequencer + // RollupId is the unique identifier for the rollup chain + // LastBatchHash is the cryptographic hash of the last batch received by the rollup + // MaxBytes is the maximum number of bytes to return in the batch // returns the next batch of transactions and an error if any from the sequencer GetNextBatch(ctx context.Context, req GetNextBatchRequest) (*GetNextBatchResponse, error) } @@ -29,6 +34,9 @@ type SequencerOutput interface { // BatchVerifier provides a method for verifying a batch of transactions received from the sequencer type BatchVerifier interface { // VerifyBatch verifies a batch of transactions received from the sequencer + // RollupId is the unique identifier for the rollup chain + // BatchHash is the cryptographic hash of the batch to verify + // returns a boolean indicating if the batch is valid and an error if any from the sequencer VerifyBatch(ctx context.Context, req VerifyBatchRequest) (*VerifyBatchResponse, error) } diff --git a/test/dummy.go b/test/dummy.go index 4a17bdc..2ee90f0 100644 --- a/test/dummy.go +++ b/test/dummy.go @@ -67,7 +67,7 @@ func (d *DummySequencer) SubmitRollupTransaction(ctx context.Context, req sequen } } d.tq.AddTransaction(req.Tx) - return nil, nil + return &sequencing.SubmitRollupTransactionResponse{}, nil } // GetNextBatch implements sequencing.Sequencer. diff --git a/test/dummy_test.go b/test/dummy_test.go index da2b645..8574c10 100644 --- a/test/dummy_test.go +++ b/test/dummy_test.go @@ -27,7 +27,7 @@ func TestSubmitRollupTransaction(t *testing.T) { // Assert no error assert.NoError(t, err) // Assert the transaction was successfully added to the queue - assert.Nil(t, resp) + assert.NotNil(t, resp) assert.Equal(t, rollupId, sequencer.RollupId) } From 6f55326d410a7bac8984ce9ca745378fdab5cbe0 Mon Sep 17 00:00:00 2001 From: gupadhyaya Date: Tue, 1 Oct 2024 17:58:47 +0400 Subject: [PATCH 05/13] concurrency safe --- test/dummy.go | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/test/dummy.go b/test/dummy.go index 2ee90f0..5848db3 100644 --- a/test/dummy.go +++ b/test/dummy.go @@ -51,10 +51,12 @@ func (tq *TransactionQueue) GetNextBatch() *sequencing.Batch { type DummySequencer struct { sequencing.RollupId - tq *TransactionQueue - lastBatchHash []byte + tq *TransactionQueue + lastBatchHash []byte + lastBatchHashMutex sync.RWMutex - seenBatches map[string]struct{} + seenBatches map[string]struct{} + seenBatchesMutex sync.Mutex } // SubmitRollupTransaction implements sequencing.Sequencer. @@ -73,14 +75,17 @@ func (d *DummySequencer) SubmitRollupTransaction(ctx context.Context, req sequen // GetNextBatch implements sequencing.Sequencer. func (d *DummySequencer) GetNextBatch(ctx context.Context, req sequencing.GetNextBatchRequest) (*sequencing.GetNextBatchResponse, error) { now := time.Now() - if d.lastBatchHash == nil { + d.lastBatchHashMutex.RLock() + lastBatchHash := d.lastBatchHash + d.lastBatchHashMutex.RUnlock() + if lastBatchHash == nil { if req.LastBatchHash != nil { return nil, errors.New("lastBatch is supposed to be nil") } } else if req.LastBatchHash == nil { return nil, errors.New("lastBatch is not supposed to be nil") } else { - if !bytes.Equal(d.lastBatchHash, req.LastBatchHash) { + if !bytes.Equal(lastBatchHash, req.LastBatchHash) { return nil, errors.New("supplied lastBatch does not match with sequencer last batch") } } @@ -97,14 +102,21 @@ func (d *DummySequencer) GetNextBatch(ctx context.Context, req sequencing.GetNex return nil, err } + d.lastBatchHashMutex.Lock() d.lastBatchHash = h - d.seenBatches[string(d.lastBatchHash)] = struct{}{} + d.lastBatchHashMutex.Unlock() + + d.seenBatchesMutex.Lock() + d.seenBatches[string(h)] = struct{}{} + d.seenBatchesMutex.Unlock() return batchRes, nil } // VerifyBatch implements sequencing.Sequencer. func (d *DummySequencer) VerifyBatch(ctx context.Context, req sequencing.VerifyBatchRequest) (*sequencing.VerifyBatchResponse, error) { + d.seenBatchesMutex.Lock() _, ok := d.seenBatches[string(req.BatchHash)] + d.seenBatchesMutex.Unlock() return &sequencing.VerifyBatchResponse{Status: ok}, nil } From 22349c4084983954b86055af00bfc6e58246607e Mon Sep 17 00:00:00 2001 From: gupadhyaya Date: Tue, 1 Oct 2024 18:00:41 +0400 Subject: [PATCH 06/13] fix verify batch --- test/dummy.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/test/dummy.go b/test/dummy.go index 5848db3..4f0ac06 100644 --- a/test/dummy.go +++ b/test/dummy.go @@ -115,9 +115,13 @@ func (d *DummySequencer) GetNextBatch(ctx context.Context, req sequencing.GetNex // VerifyBatch implements sequencing.Sequencer. func (d *DummySequencer) VerifyBatch(ctx context.Context, req sequencing.VerifyBatchRequest) (*sequencing.VerifyBatchResponse, error) { d.seenBatchesMutex.Lock() - _, ok := d.seenBatches[string(req.BatchHash)] - d.seenBatchesMutex.Unlock() - return &sequencing.VerifyBatchResponse{Status: ok}, nil + defer d.seenBatchesMutex.Unlock() + for batchHash := range d.seenBatches { + if bytes.Equal([]byte(batchHash), req.BatchHash) { + return &sequencing.VerifyBatchResponse{Status: true}, nil + } + } + return &sequencing.VerifyBatchResponse{Status: false}, nil } // NewDummySequencer creates a new DummySequencer From b7c2c518adb0380e58b5ad513292a6c0c03f459b Mon Sep 17 00:00:00 2001 From: gupadhyaya Date: Tue, 1 Oct 2024 19:59:20 +0400 Subject: [PATCH 07/13] remove rollup id storage --- test/dummy.go | 12 ---- test/dummy_test.go | 155 +++++++++++++++++++++++++++------------------ 2 files changed, 94 insertions(+), 73 deletions(-) diff --git a/test/dummy.go b/test/dummy.go index 4f0ac06..633d551 100644 --- a/test/dummy.go +++ b/test/dummy.go @@ -10,9 +10,6 @@ import ( "github.com/rollkit/go-sequencing" ) -// ErrorRollupIdMismatch is returned when the rollup id does not match -var ErrorRollupIdMismatch = errors.New("rollup id mismatch") - // TransactionQueue is a queue of transactions type TransactionQueue struct { queue []sequencing.Tx @@ -49,8 +46,6 @@ func (tq *TransactionQueue) GetNextBatch() *sequencing.Batch { // DummySequencer is a dummy sequencer for testing that serves a single rollup type DummySequencer struct { - sequencing.RollupId - tq *TransactionQueue lastBatchHash []byte lastBatchHashMutex sync.RWMutex @@ -61,13 +56,6 @@ type DummySequencer struct { // SubmitRollupTransaction implements sequencing.Sequencer. func (d *DummySequencer) SubmitRollupTransaction(ctx context.Context, req sequencing.SubmitRollupTransactionRequest) (*sequencing.SubmitRollupTransactionResponse, error) { - if d.RollupId == nil { - d.RollupId = req.RollupId - } else { - if !bytes.Equal(d.RollupId, req.RollupId) { - return nil, ErrorRollupIdMismatch - } - } d.tq.AddTransaction(req.Tx) return &sequencing.SubmitRollupTransactionResponse{}, nil } diff --git a/test/dummy_test.go b/test/dummy_test.go index 8574c10..7d45170 100644 --- a/test/dummy_test.go +++ b/test/dummy_test.go @@ -5,12 +5,43 @@ import ( "testing" "time" - "github.com/stretchr/testify/assert" - "github.com/rollkit/go-sequencing" + "github.com/stretchr/testify/assert" ) -func TestSubmitRollupTransaction(t *testing.T) { +func TestTransactionQueue_AddTransaction(t *testing.T) { + queue := NewTransactionQueue() + + tx1 := []byte("transaction_1") + queue.AddTransaction(tx1) + + // Check that the transaction was added + batch := queue.GetNextBatch() + assert.Equal(t, 1, len(batch.Transactions)) + assert.Equal(t, tx1, batch.Transactions[0]) +} + +func TestTransactionQueue_GetNextBatch(t *testing.T) { + queue := NewTransactionQueue() + + // Add multiple transactions + tx1 := []byte("transaction_1") + tx2 := []byte("transaction_2") + queue.AddTransaction(tx1) + queue.AddTransaction(tx2) + + // Get next batch and check if all transactions are retrieved + batch := queue.GetNextBatch() + assert.Equal(t, 2, len(batch.Transactions)) + assert.Equal(t, tx1, batch.Transactions[0]) + assert.Equal(t, tx2, batch.Transactions[1]) + + // Ensure the queue is empty after retrieving the batch + emptyBatch := queue.GetNextBatch() + assert.Equal(t, 0, len(emptyBatch.Transactions)) +} + +func TestDummySequencer_SubmitRollupTransaction(t *testing.T) { sequencer := NewDummySequencer() // Define a test rollup ID and transaction @@ -24,111 +55,113 @@ func TestSubmitRollupTransaction(t *testing.T) { } resp, err := sequencer.SubmitRollupTransaction(context.Background(), req) - // Assert no error + // Assert no error and check if transaction was added assert.NoError(t, err) - // Assert the transaction was successfully added to the queue assert.NotNil(t, resp) - assert.Equal(t, rollupId, sequencer.RollupId) + + // Check that the transaction is in the queue + batch := sequencer.tq.GetNextBatch() + assert.Equal(t, 1, len(batch.Transactions)) + assert.Equal(t, tx, batch.Transactions[0]) } -func TestSubmitRollupTransaction_RollupIdMismatch(t *testing.T) { +func TestDummySequencer_GetNextBatch(t *testing.T) { sequencer := NewDummySequencer() - // Submit a transaction with one rollup ID - rollupId1 := []byte("test_rollup_id1") - tx1 := []byte("test_transaction_1") - req1 := sequencing.SubmitRollupTransactionRequest{ - RollupId: rollupId1, - Tx: tx1, + // Add a transaction to the queue + rollupId := []byte("test_rollup_id") + tx := []byte("test_transaction") + req := sequencing.SubmitRollupTransactionRequest{ + RollupId: rollupId, + Tx: tx, } - _, err := sequencer.SubmitRollupTransaction(context.Background(), req1) - assert.NoError(t, err) + sequencer.SubmitRollupTransaction(context.Background(), req) - // Submit a transaction with a different rollup ID (should cause an error) - rollupId2 := []byte("test_rollup_id2") - tx2 := []byte("test_transaction_2") - req2 := sequencing.SubmitRollupTransactionRequest{ - RollupId: rollupId2, - Tx: tx2, + // Retrieve the next batch + getBatchReq := sequencing.GetNextBatchRequest{ + RollupId: rollupId, + LastBatchHash: nil, } - _, err = sequencer.SubmitRollupTransaction(context.Background(), req2) + batchResp, err := sequencer.GetNextBatch(context.Background(), getBatchReq) - // Assert that the error is ErrorRollupIdMismatch - assert.Error(t, err) - assert.Equal(t, err, ErrorRollupIdMismatch) + // Assert no error + assert.NoError(t, err) + // Ensure the batch contains the transaction + assert.NotNil(t, batchResp) + assert.Equal(t, 1, len(batchResp.Batch.Transactions)) + assert.Equal(t, tx, batchResp.Batch.Transactions[0]) + + // Assert timestamp is recent + assert.WithinDuration(t, time.Now(), batchResp.Timestamp, time.Second) } -func TestGetNextBatch(t *testing.T) { +func TestDummySequencer_GetNextBatch_LastBatchHashMismatch(t *testing.T) { sequencer := NewDummySequencer() - // Define a test rollup ID and transaction + // Submit a transaction rollupId := []byte("test_rollup_id") tx := []byte("test_transaction") - - // Submit a transaction req := sequencing.SubmitRollupTransactionRequest{ RollupId: rollupId, Tx: tx, } - _, err := sequencer.SubmitRollupTransaction(context.Background(), req) - assert.NoError(t, err) + sequencer.SubmitRollupTransaction(context.Background(), req) - // Get the next batch + // Retrieve the next batch getBatchReq := sequencing.GetNextBatchRequest{ RollupId: rollupId, - LastBatchHash: nil, - MaxBytes: 1024, + LastBatchHash: []byte("invalid_hash"), } - batchRes, err := sequencer.GetNextBatch(context.Background(), getBatchReq) - - // Assert no error - assert.NoError(t, err) - - // Assert that the returned batch contains the correct transaction - assert.NotNil(t, batchRes.Batch) - assert.Equal(t, 1, len(batchRes.Batch.Transactions)) - assert.Equal(t, tx, batchRes.Batch.Transactions[0]) + _, err := sequencer.GetNextBatch(context.Background(), getBatchReq) - // Assert timestamp is recent - assert.WithinDuration(t, time.Now(), batchRes.Timestamp, time.Second) + // Assert that the batch hash mismatch error is returned + assert.Error(t, err) + assert.Equal(t, "lastBatch is supposed to be nil", err.Error()) } -func TestVerifyBatch(t *testing.T) { +func TestDummySequencer_VerifyBatch(t *testing.T) { sequencer := NewDummySequencer() - // Define a test rollup ID and transaction + // Add and retrieve a batch rollupId := []byte("test_rollup_id") tx := []byte("test_transaction") - - // Submit a transaction req := sequencing.SubmitRollupTransactionRequest{ RollupId: rollupId, Tx: tx, } - _, err := sequencer.SubmitRollupTransaction(context.Background(), req) - assert.NoError(t, err) + sequencer.SubmitRollupTransaction(context.Background(), req) // Get the next batch to generate batch hash getBatchReq := sequencing.GetNextBatchRequest{ RollupId: rollupId, LastBatchHash: nil, - MaxBytes: 1024, } - batchRes, err := sequencer.GetNextBatch(context.Background(), getBatchReq) + batchResp, err := sequencer.GetNextBatch(context.Background(), getBatchReq) assert.NoError(t, err) - batchHash, err := batchRes.Batch.Hash() + batchHash, err := batchResp.Batch.Hash() assert.NoError(t, err) - // Verify the batch + // Verify the batch using the batch hash verifyReq := sequencing.VerifyBatchRequest{ - RollupId: rollupId, - BatchHash: batchHash, // hash of the submitted transaction + BatchHash: batchHash, } - verifyRes, err := sequencer.VerifyBatch(context.Background(), verifyReq) + verifyResp, err := sequencer.VerifyBatch(context.Background(), verifyReq) - // Assert no error + // Assert no error and that the batch is verified successfully assert.NoError(t, err) + assert.True(t, verifyResp.Status) +} - // Assert that the batch was verified successfully - assert.True(t, verifyRes.Status) +func TestDummySequencer_VerifyBatch_NotFound(t *testing.T) { + sequencer := NewDummySequencer() + + // Try verifying a batch with an invalid hash + verifyReq := sequencing.VerifyBatchRequest{ + BatchHash: []byte("invalid_hash"), + } + verifyResp, err := sequencer.VerifyBatch(context.Background(), verifyReq) + + // Assert no error and that the batch is not found + assert.NoError(t, err) + assert.False(t, verifyResp.Status) } From fef56010979592fa5fe57ee7c58b2072bb9925a4 Mon Sep 17 00:00:00 2001 From: gupadhyaya Date: Tue, 1 Oct 2024 20:27:59 +0400 Subject: [PATCH 08/13] minor fixes to test --- test/dummy_test.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/test/dummy_test.go b/test/dummy_test.go index 7d45170..0a899ec 100644 --- a/test/dummy_test.go +++ b/test/dummy_test.go @@ -5,8 +5,9 @@ import ( "testing" "time" - "github.com/rollkit/go-sequencing" "github.com/stretchr/testify/assert" + + "github.com/rollkit/go-sequencing" ) func TestTransactionQueue_AddTransaction(t *testing.T) { @@ -75,7 +76,8 @@ func TestDummySequencer_GetNextBatch(t *testing.T) { RollupId: rollupId, Tx: tx, } - sequencer.SubmitRollupTransaction(context.Background(), req) + _, err := sequencer.SubmitRollupTransaction(context.Background(), req) + assert.NoError(t, err) // Retrieve the next batch getBatchReq := sequencing.GetNextBatchRequest{ @@ -105,14 +107,15 @@ func TestDummySequencer_GetNextBatch_LastBatchHashMismatch(t *testing.T) { RollupId: rollupId, Tx: tx, } - sequencer.SubmitRollupTransaction(context.Background(), req) + _, err := sequencer.SubmitRollupTransaction(context.Background(), req) + assert.NoError(t, err) // Retrieve the next batch getBatchReq := sequencing.GetNextBatchRequest{ RollupId: rollupId, LastBatchHash: []byte("invalid_hash"), } - _, err := sequencer.GetNextBatch(context.Background(), getBatchReq) + _, err = sequencer.GetNextBatch(context.Background(), getBatchReq) // Assert that the batch hash mismatch error is returned assert.Error(t, err) @@ -129,7 +132,8 @@ func TestDummySequencer_VerifyBatch(t *testing.T) { RollupId: rollupId, Tx: tx, } - sequencer.SubmitRollupTransaction(context.Background(), req) + _, err := sequencer.SubmitRollupTransaction(context.Background(), req) + assert.NoError(t, err) // Get the next batch to generate batch hash getBatchReq := sequencing.GetNextBatchRequest{ From a98e57cdbc4d92f908dc270254de3f57b929ac26 Mon Sep 17 00:00:00 2001 From: gupadhyaya Date: Tue, 1 Oct 2024 21:36:25 +0400 Subject: [PATCH 09/13] fix GetNextBatch for max bytes and add additional tests --- test/dummy.go | 35 ++++++-- test/dummy_test.go | 216 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 241 insertions(+), 10 deletions(-) diff --git a/test/dummy.go b/test/dummy.go index 633d551..405decc 100644 --- a/test/dummy.go +++ b/test/dummy.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "errors" + "math" "sync" "time" @@ -30,17 +31,39 @@ func (tq *TransactionQueue) AddTransaction(tx sequencing.Tx) { tq.queue = append(tq.queue, tx) } +func totalBytes(data [][]byte) int { + total := 0 + for _, sub := range data { + total += len(sub) + } + return total +} + // GetNextBatch extracts a batch of transactions from the queue -func (tq *TransactionQueue) GetNextBatch() *sequencing.Batch { +func (tq *TransactionQueue) GetNextBatch(maxBytes uint64) *sequencing.Batch { tq.mu.Lock() defer tq.mu.Unlock() - size := len(tq.queue) - if size == 0 { + var batch [][]byte + batchSize := uint64(len(tq.queue)) + if batchSize == 0 { return &sequencing.Batch{Transactions: nil} } - batch := tq.queue[:size] - tq.queue = tq.queue[size:] + + if maxBytes == 0 { + maxBytes = math.MaxUint64 + } + + for { + batch = tq.queue[:batchSize] + blobSize := totalBytes(batch) + if uint64(blobSize) <= maxBytes { + break + } + batchSize = batchSize - 1 + } + + tq.queue = tq.queue[batchSize:] return &sequencing.Batch{Transactions: batch} } @@ -78,7 +101,7 @@ func (d *DummySequencer) GetNextBatch(ctx context.Context, req sequencing.GetNex } } - batch := d.tq.GetNextBatch() + 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 { diff --git a/test/dummy_test.go b/test/dummy_test.go index 0a899ec..c890029 100644 --- a/test/dummy_test.go +++ b/test/dummy_test.go @@ -2,6 +2,7 @@ package test import ( "context" + "math" "testing" "time" @@ -17,7 +18,7 @@ func TestTransactionQueue_AddTransaction(t *testing.T) { queue.AddTransaction(tx1) // Check that the transaction was added - batch := queue.GetNextBatch() + batch := queue.GetNextBatch(math.MaxUint64) assert.Equal(t, 1, len(batch.Transactions)) assert.Equal(t, tx1, batch.Transactions[0]) } @@ -32,13 +33,13 @@ func TestTransactionQueue_GetNextBatch(t *testing.T) { queue.AddTransaction(tx2) // Get next batch and check if all transactions are retrieved - batch := queue.GetNextBatch() + batch := queue.GetNextBatch(math.MaxUint64) assert.Equal(t, 2, len(batch.Transactions)) assert.Equal(t, tx1, batch.Transactions[0]) assert.Equal(t, tx2, batch.Transactions[1]) // Ensure the queue is empty after retrieving the batch - emptyBatch := queue.GetNextBatch() + emptyBatch := queue.GetNextBatch(math.MaxUint64) assert.Equal(t, 0, len(emptyBatch.Transactions)) } @@ -61,11 +62,73 @@ func TestDummySequencer_SubmitRollupTransaction(t *testing.T) { assert.NotNil(t, resp) // Check that the transaction is in the queue - batch := sequencer.tq.GetNextBatch() + batch := sequencer.tq.GetNextBatch(math.MaxUint64) assert.Equal(t, 1, len(batch.Transactions)) assert.Equal(t, tx, batch.Transactions[0]) } +func TestDummySequencer_SubmitEmptyTransaction(t *testing.T) { + sequencer := NewDummySequencer() + + // Define a test rollup ID and an empty transaction + rollupId := []byte("test_rollup_id") + tx := []byte("") + + // Submit an empty transaction + req := sequencing.SubmitRollupTransactionRequest{ + RollupId: rollupId, + Tx: tx, + } + resp, err := sequencer.SubmitRollupTransaction(context.Background(), req) + + // Assert no error (since the sequencer may accept empty transactions) and ensure the transaction was added + assert.NoError(t, err) + assert.NotNil(t, resp) + + // Check that the transaction is in the queue (even if empty) + batch := sequencer.tq.GetNextBatch(math.MaxUint64) + assert.Equal(t, 1, len(batch.Transactions)) + assert.Equal(t, tx, batch.Transactions[0]) +} + +func TestDummySequencer_SubmitMultipleTransactions(t *testing.T) { + sequencer := NewDummySequencer() + + // 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") + + // Submit multiple transactions + req1 := sequencing.SubmitRollupTransactionRequest{ + RollupId: rollupId, + Tx: tx1, + } + req2 := sequencing.SubmitRollupTransactionRequest{ + RollupId: rollupId, + Tx: tx2, + } + req3 := sequencing.SubmitRollupTransactionRequest{ + RollupId: rollupId, + Tx: tx3, + } + + _, err := sequencer.SubmitRollupTransaction(context.Background(), req1) + assert.NoError(t, err) + _, err = sequencer.SubmitRollupTransaction(context.Background(), req2) + assert.NoError(t, err) + _, err = sequencer.SubmitRollupTransaction(context.Background(), req3) + assert.NoError(t, err) + + // Check that all transactions are added to the queue + batch := sequencer.tq.GetNextBatch(math.MaxUint64) + assert.Equal(t, 3, len(batch.Transactions)) + assert.Equal(t, tx1, batch.Transactions[0]) + assert.Equal(t, tx2, batch.Transactions[1]) + assert.Equal(t, tx3, batch.Transactions[2]) +} + func TestDummySequencer_GetNextBatch(t *testing.T) { sequencer := NewDummySequencer() @@ -97,6 +160,24 @@ func TestDummySequencer_GetNextBatch(t *testing.T) { assert.WithinDuration(t, time.Now(), batchResp.Timestamp, time.Second) } +// Test retrieving a batch with no transactions +func TestDummySequencer_GetNextBatch_NoTransactions(t *testing.T) { + sequencer := NewDummySequencer() + + // Attempt to retrieve a batch with no transactions in the queue + getBatchReq := sequencing.GetNextBatchRequest{ + RollupId: []byte("test_rollup_id"), + LastBatchHash: nil, + } + batchResp, err := sequencer.GetNextBatch(context.Background(), getBatchReq) + + // Assert no error + assert.NoError(t, err) + // Assert that the batch is empty + assert.NotNil(t, batchResp) + assert.Equal(t, 0, len(batchResp.Batch.Transactions)) +} + func TestDummySequencer_GetNextBatch_LastBatchHashMismatch(t *testing.T) { sequencer := NewDummySequencer() @@ -122,6 +203,72 @@ func TestDummySequencer_GetNextBatch_LastBatchHashMismatch(t *testing.T) { assert.Equal(t, "lastBatch is supposed to be nil", err.Error()) } +// Test retrieving a batch with maxBytes limit +func TestDummySequencer_GetNextBatch_MaxBytesLimit(t *testing.T) { + sequencer := NewDummySequencer() + + // 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") + + // Submit multiple transactions + req1 := sequencing.SubmitRollupTransactionRequest{ + RollupId: rollupId, + Tx: tx1, + } + req2 := sequencing.SubmitRollupTransactionRequest{ + RollupId: rollupId, + Tx: tx2, + } + req3 := sequencing.SubmitRollupTransactionRequest{ + RollupId: rollupId, + Tx: tx3, + } + + _, err := sequencer.SubmitRollupTransaction(context.Background(), req1) + assert.NoError(t, err) + _, err = sequencer.SubmitRollupTransaction(context.Background(), req2) + assert.NoError(t, err) + _, err = sequencer.SubmitRollupTransaction(context.Background(), req3) + assert.NoError(t, err) + + // Retrieve the next batch with maxBytes limit (assuming maxBytes limits the size of transactions returned) + maxBytes := uint64(len(tx1) + len(tx2)) // Set maxBytes to the size of tx1 + tx2 + + getBatchReq := sequencing.GetNextBatchRequest{ + RollupId: rollupId, + LastBatchHash: nil, + MaxBytes: maxBytes, + } + batchResp, err := sequencer.GetNextBatch(context.Background(), getBatchReq) + + // Assert no error + assert.NoError(t, err) + // Assert that only two transactions (tx1 and tx2) are retrieved due to the maxBytes limit + assert.NotNil(t, batchResp) + assert.Equal(t, 2, len(batchResp.Batch.Transactions)) + assert.Equal(t, tx1, batchResp.Batch.Transactions[0]) + assert.Equal(t, tx2, batchResp.Batch.Transactions[1]) + + lastBatchHash, err := batchResp.Batch.Hash() + assert.NoError(t, err) + // Retrieve the remaining transaction (tx3) with another call + getBatchReq2 := sequencing.GetNextBatchRequest{ + RollupId: rollupId, + LastBatchHash: lastBatchHash, + MaxBytes: maxBytes, // This can be set higher to retrieve all remaining transactions + } + batchResp2, err2 := sequencer.GetNextBatch(context.Background(), getBatchReq2) + + // Assert no error and tx3 is retrieved + assert.NoError(t, err2) + assert.NotNil(t, batchResp2) + assert.Equal(t, 1, len(batchResp2.Batch.Transactions)) + assert.Equal(t, tx3, batchResp2.Batch.Transactions[0]) +} + func TestDummySequencer_VerifyBatch(t *testing.T) { sequencer := NewDummySequencer() @@ -156,6 +303,67 @@ func TestDummySequencer_VerifyBatch(t *testing.T) { assert.True(t, verifyResp.Status) } +func TestDummySequencer_VerifyEmptyBatch(t *testing.T) { + sequencer := NewDummySequencer() + + // Create a request with an empty batch hash + emptyBatchHash := []byte{} + verifyReq := sequencing.VerifyBatchRequest{ + BatchHash: emptyBatchHash, + } + + // Attempt to verify the empty batch + verifyResp, err := sequencer.VerifyBatch(context.Background(), verifyReq) + + // Assert that the batch is not verified (as it's empty) + assert.NoError(t, err) + assert.False(t, verifyResp.Status) +} + +func TestDummySequencer_VerifyBatchWithMultipleTransactions(t *testing.T) { + sequencer := NewDummySequencer() + + // Define a test rollup ID and multiple transactions + rollupId := []byte("test_rollup_id") + tx1 := []byte("transaction_1") + tx2 := []byte("transaction_2") + + // Submit multiple transactions + req1 := sequencing.SubmitRollupTransactionRequest{ + RollupId: rollupId, + Tx: tx1, + } + req2 := sequencing.SubmitRollupTransactionRequest{ + RollupId: rollupId, + Tx: tx2, + } + + _, err := sequencer.SubmitRollupTransaction(context.Background(), req1) + assert.NoError(t, err) + _, err = sequencer.SubmitRollupTransaction(context.Background(), req2) + assert.NoError(t, err) + + // Get the next batch to generate the batch hash + getBatchReq := sequencing.GetNextBatchRequest{ + RollupId: rollupId, + LastBatchHash: nil, + } + batchResp, err := sequencer.GetNextBatch(context.Background(), getBatchReq) + assert.NoError(t, err) + + batchHash, err := batchResp.Batch.Hash() + assert.NoError(t, err) + // Verify the batch using the batch hash + verifyReq := sequencing.VerifyBatchRequest{ + BatchHash: batchHash, + } + verifyResp, err := sequencer.VerifyBatch(context.Background(), verifyReq) + + // Assert that the batch with multiple transactions is verified successfully + assert.NoError(t, err) + assert.True(t, verifyResp.Status) +} + func TestDummySequencer_VerifyBatch_NotFound(t *testing.T) { sequencer := NewDummySequencer() From b30eec5235e78eb15a206ae8c5e3eb2b9400a91f Mon Sep 17 00:00:00 2001 From: gupadhyaya Date: Tue, 1 Oct 2024 22:30:01 +0400 Subject: [PATCH 10/13] reintroduce rollupId, but as a config in the constructor --- test/dummy.go | 50 +++++++++++++++++++++++++++++++--------------- test/dummy_test.go | 40 ++++++++++++++++++------------------- 2 files changed, 53 insertions(+), 37 deletions(-) diff --git a/test/dummy.go b/test/dummy.go index 405decc..77972b8 100644 --- a/test/dummy.go +++ b/test/dummy.go @@ -3,6 +3,7 @@ package test import ( "bytes" "context" + "encoding/hex" "errors" "math" "sync" @@ -11,6 +12,8 @@ import ( "github.com/rollkit/go-sequencing" ) +var ErrInvalidRollupId = errors.New("invalid rollup id") + // TransactionQueue is a queue of transactions type TransactionQueue struct { queue []sequencing.Tx @@ -54,7 +57,7 @@ func (tq *TransactionQueue) GetNextBatch(maxBytes uint64) *sequencing.Batch { maxBytes = math.MaxUint64 } - for { + for batchSize > 0 { batch = tq.queue[:batchSize] blobSize := totalBytes(batch) if uint64(blobSize) <= maxBytes { @@ -62,6 +65,10 @@ func (tq *TransactionQueue) GetNextBatch(maxBytes uint64) *sequencing.Batch { } batchSize = batchSize - 1 } + if batchSize == 0 { + // No transactions can fit within maxBytes + return &sequencing.Batch{Transactions: nil} + } tq.queue = tq.queue[batchSize:] return &sequencing.Batch{Transactions: batch} @@ -69,6 +76,7 @@ func (tq *TransactionQueue) GetNextBatch(maxBytes uint64) *sequencing.Batch { // DummySequencer is a dummy sequencer for testing that serves a single rollup type DummySequencer struct { + rollupId []byte tq *TransactionQueue lastBatchHash []byte lastBatchHashMutex sync.RWMutex @@ -79,26 +87,29 @@ type DummySequencer struct { // SubmitRollupTransaction implements sequencing.Sequencer. func (d *DummySequencer) SubmitRollupTransaction(ctx context.Context, req sequencing.SubmitRollupTransactionRequest) (*sequencing.SubmitRollupTransactionResponse, error) { + if !d.isValid(req.RollupId) { + return nil, ErrInvalidRollupId + } d.tq.AddTransaction(req.Tx) return &sequencing.SubmitRollupTransactionResponse{}, nil } // GetNextBatch implements sequencing.Sequencer. func (d *DummySequencer) GetNextBatch(ctx context.Context, req sequencing.GetNextBatchRequest) (*sequencing.GetNextBatchResponse, error) { + if !d.isValid(req.RollupId) { + return nil, ErrInvalidRollupId + } now := time.Now() d.lastBatchHashMutex.RLock() lastBatchHash := d.lastBatchHash d.lastBatchHashMutex.RUnlock() - if lastBatchHash == nil { - if req.LastBatchHash != nil { - return nil, errors.New("lastBatch is supposed to be nil") - } - } else if req.LastBatchHash == nil { + + 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") - } + } else if !bytes.Equal(lastBatchHash, req.LastBatchHash) { + return nil, errors.New("supplied lastBatch does not match with sequencer last batch") } batch := d.tq.GetNextBatch(req.MaxBytes) @@ -118,26 +129,33 @@ func (d *DummySequencer) GetNextBatch(ctx context.Context, req sequencing.GetNex d.lastBatchHashMutex.Unlock() d.seenBatchesMutex.Lock() - d.seenBatches[string(h)] = struct{}{} + d.seenBatches[hex.EncodeToString(h)] = struct{}{} d.seenBatchesMutex.Unlock() return batchRes, nil } // VerifyBatch implements sequencing.Sequencer. func (d *DummySequencer) VerifyBatch(ctx context.Context, req sequencing.VerifyBatchRequest) (*sequencing.VerifyBatchResponse, error) { + if !d.isValid(req.RollupId) { + return nil, ErrInvalidRollupId + } d.seenBatchesMutex.Lock() defer d.seenBatchesMutex.Unlock() - for batchHash := range d.seenBatches { - if bytes.Equal([]byte(batchHash), req.BatchHash) { - return &sequencing.VerifyBatchResponse{Status: true}, nil - } + key := hex.EncodeToString(req.BatchHash) + if _, exists := d.seenBatches[key]; exists { + return &sequencing.VerifyBatchResponse{Status: true}, nil } return &sequencing.VerifyBatchResponse{Status: false}, nil } +func (d *DummySequencer) isValid(rollupId []byte) bool { + return bytes.Equal(d.rollupId, rollupId) +} + // NewDummySequencer creates a new DummySequencer -func NewDummySequencer() *DummySequencer { +func NewDummySequencer(rollupId []byte) *DummySequencer { return &DummySequencer{ + rollupId: rollupId, tq: NewTransactionQueue(), seenBatches: make(map[string]struct{}, 0), } diff --git a/test/dummy_test.go b/test/dummy_test.go index c890029..7ef7175 100644 --- a/test/dummy_test.go +++ b/test/dummy_test.go @@ -44,11 +44,10 @@ func TestTransactionQueue_GetNextBatch(t *testing.T) { } func TestDummySequencer_SubmitRollupTransaction(t *testing.T) { - sequencer := NewDummySequencer() - // Define a test rollup ID and transaction rollupId := []byte("test_rollup_id") tx := []byte("test_transaction") + sequencer := NewDummySequencer(rollupId) // Submit a transaction req := sequencing.SubmitRollupTransactionRequest{ @@ -68,11 +67,10 @@ func TestDummySequencer_SubmitRollupTransaction(t *testing.T) { } func TestDummySequencer_SubmitEmptyTransaction(t *testing.T) { - sequencer := NewDummySequencer() - // Define a test rollup ID and an empty transaction rollupId := []byte("test_rollup_id") tx := []byte("") + sequencer := NewDummySequencer(rollupId) // Submit an empty transaction req := sequencing.SubmitRollupTransactionRequest{ @@ -92,13 +90,12 @@ func TestDummySequencer_SubmitEmptyTransaction(t *testing.T) { } func TestDummySequencer_SubmitMultipleTransactions(t *testing.T) { - sequencer := NewDummySequencer() - // 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") + sequencer := NewDummySequencer(rollupId) // Submit multiple transactions req1 := sequencing.SubmitRollupTransactionRequest{ @@ -130,11 +127,10 @@ func TestDummySequencer_SubmitMultipleTransactions(t *testing.T) { } func TestDummySequencer_GetNextBatch(t *testing.T) { - sequencer := NewDummySequencer() - // Add a transaction to the queue rollupId := []byte("test_rollup_id") tx := []byte("test_transaction") + sequencer := NewDummySequencer(rollupId) req := sequencing.SubmitRollupTransactionRequest{ RollupId: rollupId, Tx: tx, @@ -162,11 +158,11 @@ func TestDummySequencer_GetNextBatch(t *testing.T) { // Test retrieving a batch with no transactions func TestDummySequencer_GetNextBatch_NoTransactions(t *testing.T) { - sequencer := NewDummySequencer() - + rollupId := []byte("test_rollup_id") + sequencer := NewDummySequencer(rollupId) // Attempt to retrieve a batch with no transactions in the queue getBatchReq := sequencing.GetNextBatchRequest{ - RollupId: []byte("test_rollup_id"), + RollupId: rollupId, LastBatchHash: nil, } batchResp, err := sequencer.GetNextBatch(context.Background(), getBatchReq) @@ -179,10 +175,9 @@ func TestDummySequencer_GetNextBatch_NoTransactions(t *testing.T) { } func TestDummySequencer_GetNextBatch_LastBatchHashMismatch(t *testing.T) { - sequencer := NewDummySequencer() - // Submit a transaction rollupId := []byte("test_rollup_id") + sequencer := NewDummySequencer(rollupId) tx := []byte("test_transaction") req := sequencing.SubmitRollupTransactionRequest{ RollupId: rollupId, @@ -205,10 +200,9 @@ func TestDummySequencer_GetNextBatch_LastBatchHashMismatch(t *testing.T) { // Test retrieving a batch with maxBytes limit func TestDummySequencer_GetNextBatch_MaxBytesLimit(t *testing.T) { - sequencer := NewDummySequencer() - // 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") @@ -270,10 +264,9 @@ func TestDummySequencer_GetNextBatch_MaxBytesLimit(t *testing.T) { } func TestDummySequencer_VerifyBatch(t *testing.T) { - sequencer := NewDummySequencer() - // Add and retrieve a batch rollupId := []byte("test_rollup_id") + sequencer := NewDummySequencer(rollupId) tx := []byte("test_transaction") req := sequencing.SubmitRollupTransactionRequest{ RollupId: rollupId, @@ -294,6 +287,7 @@ func TestDummySequencer_VerifyBatch(t *testing.T) { assert.NoError(t, err) // Verify the batch using the batch hash verifyReq := sequencing.VerifyBatchRequest{ + RollupId: rollupId, BatchHash: batchHash, } verifyResp, err := sequencer.VerifyBatch(context.Background(), verifyReq) @@ -304,11 +298,13 @@ func TestDummySequencer_VerifyBatch(t *testing.T) { } func TestDummySequencer_VerifyEmptyBatch(t *testing.T) { - sequencer := NewDummySequencer() + rollupId := []byte("test_rollup_id") + sequencer := NewDummySequencer(rollupId) // Create a request with an empty batch hash emptyBatchHash := []byte{} verifyReq := sequencing.VerifyBatchRequest{ + RollupId: rollupId, BatchHash: emptyBatchHash, } @@ -321,10 +317,9 @@ func TestDummySequencer_VerifyEmptyBatch(t *testing.T) { } func TestDummySequencer_VerifyBatchWithMultipleTransactions(t *testing.T) { - sequencer := NewDummySequencer() - // Define a test rollup ID and multiple transactions rollupId := []byte("test_rollup_id") + sequencer := NewDummySequencer(rollupId) tx1 := []byte("transaction_1") tx2 := []byte("transaction_2") @@ -355,6 +350,7 @@ func TestDummySequencer_VerifyBatchWithMultipleTransactions(t *testing.T) { assert.NoError(t, err) // Verify the batch using the batch hash verifyReq := sequencing.VerifyBatchRequest{ + RollupId: rollupId, BatchHash: batchHash, } verifyResp, err := sequencer.VerifyBatch(context.Background(), verifyReq) @@ -365,10 +361,12 @@ func TestDummySequencer_VerifyBatchWithMultipleTransactions(t *testing.T) { } func TestDummySequencer_VerifyBatch_NotFound(t *testing.T) { - sequencer := NewDummySequencer() + rollupId := []byte("test_rollup_id") + sequencer := NewDummySequencer(rollupId) // Try verifying a batch with an invalid hash verifyReq := sequencing.VerifyBatchRequest{ + RollupId: rollupId, BatchHash: []byte("invalid_hash"), } verifyResp, err := sequencer.VerifyBatch(context.Background(), verifyReq) From ad1c339630f3314d9c025e4dc218f7f9108b6e17 Mon Sep 17 00:00:00 2001 From: gupadhyaya Date: Tue, 1 Oct 2024 22:51:10 +0400 Subject: [PATCH 11/13] minor --- test/dummy.go | 1 + 1 file changed, 1 insertion(+) diff --git a/test/dummy.go b/test/dummy.go index 77972b8..83adbbf 100644 --- a/test/dummy.go +++ b/test/dummy.go @@ -12,6 +12,7 @@ import ( "github.com/rollkit/go-sequencing" ) +// ErrInvalidRollupId is returned when the rollup id is invalid var ErrInvalidRollupId = errors.New("invalid rollup id") // TransactionQueue is a queue of transactions From 2923ec88c7eee52904a790a8de1d98091411663d Mon Sep 17 00:00:00 2001 From: gupadhyaya Date: Wed, 2 Oct 2024 07:52:20 +0400 Subject: [PATCH 12/13] fix --- proxy/grpc/client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxy/grpc/client.go b/proxy/grpc/client.go index 4f163dc..596f635 100644 --- a/proxy/grpc/client.go +++ b/proxy/grpc/client.go @@ -48,7 +48,7 @@ func (c *Client) Stop() error { func (c *Client) SubmitRollupTransaction(ctx context.Context, req sequencing.SubmitRollupTransactionRequest) (*sequencing.SubmitRollupTransactionResponse, error) { _, err := c.SequencerInputClient.SubmitRollupTransaction(ctx, &pbseq.SubmitRollupTransactionRequest{ RollupId: req.RollupId, - Data: req.RollupId, + Data: req.Tx, }) return nil, err } From a13a9434b26c679ed560a517ab75b18a91443699 Mon Sep 17 00:00:00 2001 From: gupadhyaya Date: Wed, 2 Oct 2024 08:09:10 +0400 Subject: [PATCH 13/13] minor fixes to submit tx in client --- proxy/grpc/client.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/proxy/grpc/client.go b/proxy/grpc/client.go index 596f635..af39fee 100644 --- a/proxy/grpc/client.go +++ b/proxy/grpc/client.go @@ -50,7 +50,10 @@ func (c *Client) SubmitRollupTransaction(ctx context.Context, req sequencing.Sub RollupId: req.RollupId, Data: req.Tx, }) - return nil, err + if err != nil { + return nil, err + } + return &sequencing.SubmitRollupTransactionResponse{}, nil } // GetNextBatch returns the next batch of transactions from sequencer to rollup.