Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
redo proto
  • Loading branch information
tac0turtle committed Apr 28, 2026
commit 58a300240547db88e3d43c6697578ecda909ff6a
2 changes: 1 addition & 1 deletion execution/grpc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ The gRPC service is defined in `proto/evnode/v1/execution.proto` and provides th
- Support for Unix domain socket connections with `unix:///path/to/socket`
- gRPC reflection for debugging and service discovery
- Compression for efficient data transfer
- Contiguous transaction batch encoding to reduce per-transaction protobuf overhead
- Additive contiguous transaction batch encoding to reduce per-transaction protobuf overhead while keeping legacy `txs` fields in the protobuf API
- Comprehensive error handling and validation

## Testing
Expand Down
2 changes: 1 addition & 1 deletion execution/grpc/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ func (c *Client) GetTxs(ctx context.Context) ([][]byte, error) {
return nil, fmt.Errorf("grpc client: failed to get txs: %w", err)
}

txs, err := decodeTxBatch(resp.Msg.TxBatch)
txs, err := decodeTxBatchOrTxs(resp.Msg.TxBatch, resp.Msg.Txs)
if err != nil {
return nil, fmt.Errorf("grpc client: invalid get txs response: %w", err)
}
Expand Down
4 changes: 2 additions & 2 deletions execution/grpc/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ func (s *Server) ExecuteTxs(
return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("prev_state_root is required"))
}

txs, err := decodeTxBatch(req.Msg.TxBatch)
txs, err := decodeTxBatchOrTxs(req.Msg.TxBatch, req.Msg.Txs)
if err != nil {
return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("invalid tx_batch: %w", err))
}
Expand Down Expand Up @@ -172,7 +172,7 @@ func (s *Server) FilterTxs(
ctx context.Context,
req *connect.Request[pb.FilterTxsRequest],
) (*connect.Response[pb.FilterTxsResponse], error) {
txs, err := decodeTxBatch(req.Msg.TxBatch)
txs, err := decodeTxBatchOrTxs(req.Msg.TxBatch, req.Msg.Txs)
if err != nil {
return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("invalid tx_batch: %w", err))
}
Expand Down
31 changes: 31 additions & 0 deletions execution/grpc/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,22 @@ func TestServer_ExecuteTxs(t *testing.T) {
},
wantErr: false,
},
{
name: "legacy txs fallback",
req: &pb.ExecuteTxsRequest{
Txs: txs,
BlockHeight: blockHeight,
Timestamp: timestamppb.New(timestamp),
PrevStateRoot: prevStateRoot,
},
mockFunc: func(ctx context.Context, txsIn [][]byte, bh uint64, ts time.Time, psr []byte) ([]byte, error) {
if len(txsIn) != len(txs) {
t.Fatalf("expected %d txs, got %d", len(txs), len(txsIn))
}
return expectedStateRoot, nil
},
wantErr: false,
},
{
name: "missing block height",
req: &pb.ExecuteTxsRequest{
Expand Down Expand Up @@ -416,6 +432,21 @@ func TestServer_FilterTxs(t *testing.T) {
},
wantErr: false,
},
{
name: "legacy txs fallback",
req: &pb.FilterTxsRequest{
Txs: txs,
MaxBytes: 100,
MaxGas: 200,
},
mockFunc: func(ctx context.Context, txsIn [][]byte, maxBytes, maxGas uint64, forced bool) ([]execution.FilterStatus, error) {
if len(txsIn) != len(txs) {
t.Fatalf("expected %d txs, got %d", len(txs), len(txsIn))
}
return expectedStatuses, nil
},
wantErr: false,
},
{
name: "invalid tx batch",
req: &pb.FilterTxsRequest{
Expand Down
11 changes: 11 additions & 0 deletions execution/grpc/tx_batch.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,14 @@ func decodeTxBatch(batch *pb.TxBatch) ([][]byte, error) {
}
return txs, nil
}

func decodeTxBatchOrTxs(batch *pb.TxBatch, txs [][]byte) ([][]byte, error) {
if hasTxBatchData(batch) {
return decodeTxBatch(batch)
}
return txs, nil
}

func hasTxBatchData(batch *pb.TxBatch) bool {
return batch != nil && (len(batch.Data) != 0 || len(batch.TxSizes) != 0)
}
33 changes: 33 additions & 0 deletions execution/grpc/tx_batch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,36 @@ func TestDecodeTxBatchRejectsMalformedInput(t *testing.T) {
})
}
}

func TestDecodeTxBatchOrTxsFallsBackToLegacyTxs(t *testing.T) {
legacyTxs := [][]byte{[]byte("legacy1"), []byte("legacy2")}

txs, err := decodeTxBatchOrTxs(nil, legacyTxs)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if len(txs) != len(legacyTxs) {
t.Fatalf("expected %d txs, got %d", len(legacyTxs), len(txs))
}
for i := range txs {
if !bytes.Equal(txs[i], legacyTxs[i]) {
t.Fatalf("tx %d: expected %q, got %q", i, legacyTxs[i], txs[i])
}
}
}

func TestDecodeTxBatchOrTxsPrefersTxBatch(t *testing.T) {
batchTxs := [][]byte{[]byte("batch")}
legacyTxs := [][]byte{[]byte("legacy")}

txs, err := decodeTxBatchOrTxs(mustEncodeTxBatch(t, batchTxs), legacyTxs)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if len(txs) != len(batchTxs) {
t.Fatalf("expected %d txs, got %d", len(batchTxs), len(txs))
}
if !bytes.Equal(txs[0], batchTxs[0]) {
t.Fatalf("expected tx_batch %q, got %q", batchTxs[0], txs[0])
}
}
15 changes: 12 additions & 3 deletions proto/evnode/v1/execution.proto
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,16 @@ message TxBatch {
// GetTxsResponse contains the available transactions
message GetTxsResponse {
// Valid transactions from mempool.
TxBatch tx_batch = 1;
repeated bytes txs = 1;

// Valid transactions from mempool in contiguous batch form.
TxBatch tx_batch = 2;
}

// ExecuteTxsRequest contains transactions and block context for execution
message ExecuteTxsRequest {
// Ordered transactions to execute.
TxBatch tx_batch = 1;
repeated bytes txs = 1;

// Height of block being created (must be > 0)
uint64 block_height = 2;
Expand All @@ -77,6 +80,9 @@ message ExecuteTxsRequest {

// Previous block's state root hash
bytes prev_state_root = 4;

// Ordered transactions to execute in contiguous batch form.
TxBatch tx_batch = 5;
}

// ExecuteTxsResponse contains the result of transaction execution
Expand Down Expand Up @@ -122,7 +128,7 @@ enum FilterStatus {
// FilterTxsRequest contains transactions to validate and filter
message FilterTxsRequest {
// All transactions (force-included + mempool).
TxBatch tx_batch = 1;
repeated bytes txs = 1;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's kill the ones we don't use.


// Maximum cumulative size allowed (0 means no size limit)
uint64 max_bytes = 2;
Expand All @@ -132,6 +138,9 @@ message FilterTxsRequest {

// Whether force-included transactions are present
bool has_force_included_transaction = 4;

// All transactions (force-included + mempool) in contiguous batch form.
TxBatch tx_batch = 5;
}

// FilterTxsResponse contains the filter status for each transaction
Expand Down
72 changes: 51 additions & 21 deletions types/pb/evnode/v1/execution.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading