Skip to content

Commit 987beb0

Browse files
committed
wip
1 parent 77bc171 commit 987beb0

File tree

11 files changed

+86
-145
lines changed

11 files changed

+86
-145
lines changed

core/execution/execution.go

Lines changed: 24 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -104,27 +104,6 @@ type Executor interface {
104104
// - info: Current execution parameters
105105
// - error: Any errors during retrieval
106106
GetExecutionInfo(ctx context.Context, height uint64) (ExecutionInfo, error)
107-
108-
// FilterDATransactions validates and filters force-included transactions from DA.
109-
// It performs execution-layer specific validation (e.g., EVM tx parsing, gas checks)
110-
// and returns transactions that are valid and fit within the gas limit.
111-
//
112-
// The function filters out:
113-
// - Invalid/unparseable transactions (gibberish)
114-
// - Transactions that would exceed the cumulative gas limit
115-
//
116-
// For non-gas-based execution layers, return all valid transactions with nil remainingTxs.
117-
//
118-
// Parameters:
119-
// - ctx: Context for timeout/cancellation control
120-
// - txs: Raw transactions from DA to validate
121-
// - maxGas: Maximum cumulative gas allowed for these transactions
122-
//
123-
// Returns:
124-
// - validTxs: Transactions that passed validation and fit within maxGas
125-
// - remainingTxs: Valid transactions that didn't fit due to gas limit (for re-queuing)
126-
// - err: Any errors during filtering (not validation errors, which result in filtering)
127-
FilterDATransactions(ctx context.Context, txs [][]byte, maxGas uint64) (validTxs [][]byte, remainingTxs [][]byte, err error)
128107
}
129108

130109
// HeightProvider is an optional interface that execution clients can implement
@@ -143,18 +122,31 @@ type HeightProvider interface {
143122
GetLatestHeight(ctx context.Context) (uint64, error)
144123
}
145124

146-
// ExecutionInfoProvider is an interface for components that can provide execution layer parameters.
147-
// This is useful for type assertions when an Executor implementation supports gas-based filtering.
148-
type ExecutionInfoProvider interface {
149-
// GetExecutionInfo returns current execution layer parameters.
150-
// See Executor.GetExecutionInfo for full documentation.
151-
GetExecutionInfo(ctx context.Context, height uint64) (ExecutionInfo, error)
152-
}
153-
154-
// DATransactionFilter is an interface for components that can filter DA transactions.
155-
// This is useful for type assertions when an Executor implementation supports gas-based filtering.
125+
// DATransactionFilter is an optional interface that execution clients can implement
126+
// to support gas-based filtering of force-included transactions from DA.
127+
//
128+
// When implemented, the sequencer will use this to filter DA transactions by gas limit
129+
// before including them in blocks. If not implemented, all DA transactions are included
130+
// without gas-based filtering.
156131
type DATransactionFilter interface {
157132
// FilterDATransactions validates and filters force-included transactions from DA.
158-
// See Executor.FilterDATransactions for full documentation.
133+
// It performs execution-layer specific validation (e.g., EVM tx parsing, gas checks)
134+
// and returns transactions that are valid and fit within the gas limit.
135+
//
136+
// The function filters out:
137+
// - Invalid/unparseable transactions (gibberish)
138+
// - Transactions that would exceed the cumulative gas limit
139+
//
140+
// For non-gas-based execution layers, return all valid transactions with nil remainingTxs.
141+
//
142+
// Parameters:
143+
// - ctx: Context for timeout/cancellation control
144+
// - txs: Raw transactions from DA to validate
145+
// - maxGas: Maximum cumulative gas allowed for these transactions
146+
//
147+
// Returns:
148+
// - validTxs: Transactions that passed validation and fit within maxGas
149+
// - remainingTxs: Valid transactions that didn't fit due to gas limit (for re-queuing)
150+
// - err: Any errors during filtering (not validation errors, which result in filtering)
159151
FilterDATransactions(ctx context.Context, txs [][]byte, maxGas uint64) (validTxs [][]byte, remainingTxs [][]byte, err error)
160152
}

execution/grpc/client.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ import (
1717
// Ensure Client implements the execution.Executor interface
1818
var _ execution.Executor = (*Client)(nil)
1919

20+
// Ensure Client implements the optional DATransactionFilter interface
21+
var _ execution.DATransactionFilter = (*Client)(nil)
22+
2023
// Client is a gRPC client that implements the execution.Executor interface.
2124
// It communicates with a remote execution service via gRPC using Connect-RPC.
2225
type Client struct {

execution/grpc/client_test.go

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,17 @@ import (
55
"net/http/httptest"
66
"testing"
77
"time"
8+
9+
"github.com/evstack/ev-node/core/execution"
810
)
911

1012
// mockExecutor is a mock implementation of execution.Executor for testing
1113
type mockExecutor struct {
12-
initChainFunc func(ctx context.Context, genesisTime time.Time, initialHeight uint64, chainID string) ([]byte, error)
13-
getTxsFunc func(ctx context.Context) ([][]byte, error)
14-
executeTxsFunc func(ctx context.Context, txs [][]byte, blockHeight uint64, timestamp time.Time, prevStateRoot []byte) ([]byte, error)
15-
setFinalFunc func(ctx context.Context, blockHeight uint64) error
14+
initChainFunc func(ctx context.Context, genesisTime time.Time, initialHeight uint64, chainID string) ([]byte, error)
15+
getTxsFunc func(ctx context.Context) ([][]byte, error)
16+
executeTxsFunc func(ctx context.Context, txs [][]byte, blockHeight uint64, timestamp time.Time, prevStateRoot []byte) ([]byte, error)
17+
setFinalFunc func(ctx context.Context, blockHeight uint64) error
18+
getExecutionInfoFunc func(ctx context.Context, height uint64) (execution.ExecutionInfo, error)
1619
}
1720

1821
func (m *mockExecutor) InitChain(ctx context.Context, genesisTime time.Time, initialHeight uint64, chainID string) ([]byte, error) {
@@ -43,6 +46,13 @@ func (m *mockExecutor) SetFinal(ctx context.Context, blockHeight uint64) error {
4346
return nil
4447
}
4548

49+
func (m *mockExecutor) GetExecutionInfo(ctx context.Context, height uint64) (execution.ExecutionInfo, error) {
50+
if m.getExecutionInfoFunc != nil {
51+
return m.getExecutionInfoFunc(ctx, height)
52+
}
53+
return execution.ExecutionInfo{MaxGas: 0}, nil
54+
}
55+
4656
func TestClient_InitChain(t *testing.T) {
4757
ctx := context.Background()
4858
expectedStateRoot := []byte("test_state_root")

execution/grpc/go.mod

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@ require (
77
connectrpc.com/grpcreflect v1.3.0
88
github.com/evstack/ev-node v1.0.0-beta.11
99
github.com/evstack/ev-node/core v1.0.0-beta.5
10-
golang.org/x/net v0.47.0
11-
google.golang.org/protobuf v1.36.10
10+
golang.org/x/net v0.49.0
11+
google.golang.org/protobuf v1.36.11
1212
)
1313

14-
require golang.org/x/text v0.31.0 // indirect
14+
require golang.org/x/text v0.33.0 // indirect
1515

1616
replace github.com/evstack/ev-node/core => ../../core
17+
18+
replace github.com/evstack/ev-node => ../..

execution/grpc/go.sum

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,11 @@ connectrpc.com/connect v1.19.1 h1:R5M57z05+90EfEvCY1b7hBxDVOUl45PrtXtAV2fOC14=
22
connectrpc.com/connect v1.19.1/go.mod h1:tN20fjdGlewnSFeZxLKb0xwIZ6ozc3OQs2hTXy4du9w=
33
connectrpc.com/grpcreflect v1.3.0 h1:Y4V+ACf8/vOb1XOc251Qun7jMB75gCUNw6llvB9csXc=
44
connectrpc.com/grpcreflect v1.3.0/go.mod h1:nfloOtCS8VUQOQ1+GTdFzVg2CJo4ZGaat8JIovCtDYs=
5-
github.com/evstack/ev-node v1.0.0-beta.11 h1:3g4Ja2mP3HVGt3Q6rOvLExAlU24r+mEcpq0tUiKPPmw=
6-
github.com/evstack/ev-node v1.0.0-beta.11/go.mod h1:BNQb29H/34/PgOB25Tn3+SuVhjdfZs3GsQz++bo8iHQ=
7-
github.com/evstack/ev-node/core v1.0.0-beta.5 h1:lgxE8XiF3U9pcFgh7xuKMgsOGvLBGRyd9kc9MR4WL0o=
8-
github.com/evstack/ev-node/core v1.0.0-beta.5/go.mod h1:n2w/LhYQTPsi48m6lMj16YiIqsaQw6gxwjyJvR+B3sY=
95
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
106
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
11-
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
12-
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
13-
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
14-
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
15-
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
16-
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
7+
golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=
8+
golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=
9+
golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE=
10+
golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8=
11+
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
12+
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=

execution/grpc/server.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,11 +158,17 @@ func (s *Server) GetExecutionInfo(
158158
//
159159
// It validates and filters force-included transactions from DA, returning
160160
// transactions that are valid and fit within the gas limit.
161+
// Returns an error if the executor does not implement DATransactionFilter.
161162
func (s *Server) FilterDATransactions(
162163
ctx context.Context,
163164
req *connect.Request[pb.FilterDATransactionsRequest],
164165
) (*connect.Response[pb.FilterDATransactionsResponse], error) {
165-
validTxs, remainingTxs, err := s.executor.FilterDATransactions(ctx, req.Msg.Txs, req.Msg.MaxGas)
166+
filter, ok := s.executor.(execution.DATransactionFilter)
167+
if !ok {
168+
return nil, connect.NewError(connect.CodeUnimplemented, fmt.Errorf("executor does not support DA transaction filtering"))
169+
}
170+
171+
validTxs, remainingTxs, err := filter.FilterDATransactions(ctx, req.Msg.Txs, req.Msg.MaxGas)
166172
if err != nil {
167173
return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("failed to filter DA transactions: %w", err))
168174
}

pkg/sequencers/single/sequencer.go

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,11 @@ type Sequencer struct {
5353
cachedForcedInclusionTxs [][]byte
5454

5555
// Executor for DA transaction filtering (optional)
56-
// When set, forced inclusion transactions are filtered by gas limit
57-
// using the executor's GetExecutionInfo and FilterDATransactions methods
56+
// When set, forced inclusion transactions are filtered by gas limit.
57+
// GetExecutionInfo is called directly on the executor.
58+
// FilterDATransactions is called via type assertion to DATransactionFilter.
5859
executor execution.Executor
60+
txFilter execution.DATransactionFilter // cached type assertion result
5961
}
6062

6163
// NewSequencer creates a new Single Sequencer
@@ -127,7 +129,13 @@ func NewSequencer(
127129
// This should be called after NewSequencer and before Start if filtering is desired.
128130
func (c *Sequencer) SetExecutor(executor execution.Executor) {
129131
c.executor = executor
130-
c.logger.Info().Msg("Executor configured for DA transaction gas-based filtering")
132+
// Check if executor implements the optional DATransactionFilter interface
133+
if filter, ok := executor.(execution.DATransactionFilter); ok {
134+
c.txFilter = filter
135+
c.logger.Info().Msg("Executor configured for DA transaction gas-based filtering")
136+
} else {
137+
c.logger.Info().Msg("Executor configured (no DA transaction filtering support)")
138+
}
131139
}
132140

133141
// getInitialDAStartHeight retrieves the DA height of the first included chain height from store.
@@ -215,18 +223,18 @@ func (c *Sequencer) GetNextBatch(ctx context.Context, req coresequencer.GetNextB
215223
// Process forced inclusion transactions from checkpoint position
216224
forcedTxs := c.processForcedInclusionTxsFromCheckpoint(req.MaxBytes)
217225

218-
// Apply gas-based filtering if executor is configured
226+
// Apply gas-based filtering if executor and filter are configured
219227
var filteredForcedTxs [][]byte
220228
var remainingGasFilteredTxs [][]byte
221-
if c.executor != nil && len(forcedTxs) > 0 {
229+
if c.executor != nil && c.txFilter != nil && len(forcedTxs) > 0 {
222230
// Get current gas limit from execution layer
223231
info, err := c.executor.GetExecutionInfo(ctx, 0) // 0 = latest/next block
224232
if err != nil {
225233
c.logger.Warn().Err(err).Msg("failed to get execution info for gas filtering, proceeding without gas filter")
226234
filteredForcedTxs = forcedTxs
227235
} else if info.MaxGas > 0 {
228-
// Filter by gas limit
229-
filteredForcedTxs, remainingGasFilteredTxs, err = c.executor.FilterDATransactions(ctx, forcedTxs, info.MaxGas)
236+
// Filter by gas limit using the DATransactionFilter interface
237+
filteredForcedTxs, remainingGasFilteredTxs, err = c.txFilter.FilterDATransactions(ctx, forcedTxs, info.MaxGas)
230238
if err != nil {
231239
c.logger.Warn().Err(err).Msg("failed to filter DA transactions by gas, proceeding without gas filter")
232240
filteredForcedTxs = forcedTxs

pkg/sequencers/single/sequencer_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1010,7 +1010,8 @@ func TestSequencer_GetNextBatch_EmptyDABatch_IncreasesDAHeight(t *testing.T) {
10101010
assert.Equal(t, uint64(0), seq.checkpoint.TxIndex)
10111011
}
10121012

1013-
// mockExecutor is a mock implementation of execution.Executor for testing gas filtering
1013+
// mockExecutor is a mock implementation of execution.Executor and the optional
1014+
// execution.DATransactionFilter interface for testing gas filtering
10141015
type mockExecutor struct {
10151016
maxGas uint64
10161017
getInfoErr error

pkg/telemetry/executor_tracing.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,13 @@ func (t *tracedExecutor) GetExecutionInfo(ctx context.Context, height uint64) (c
123123
return info, err
124124
}
125125

126-
// FilterDATransactions forwards to the inner executor with tracing.
126+
// FilterDATransactions forwards to the inner executor with tracing if it implements DATransactionFilter.
127127
func (t *tracedExecutor) FilterDATransactions(ctx context.Context, txs [][]byte, maxGas uint64) ([][]byte, [][]byte, error) {
128+
filter, ok := t.inner.(coreexec.DATransactionFilter)
129+
if !ok {
130+
// If not implemented, return all transactions as valid (no filtering)
131+
return txs, nil, nil
132+
}
128133
ctx, span := t.tracer.Start(ctx, "Executor.FilterDATransactions",
129134
trace.WithAttributes(
130135
attribute.Int("input_tx_count", len(txs)),
@@ -133,7 +138,7 @@ func (t *tracedExecutor) FilterDATransactions(ctx context.Context, txs [][]byte,
133138
)
134139
defer span.End()
135140

136-
validTxs, remainingTxs, err := t.inner.FilterDATransactions(ctx, txs, maxGas)
141+
validTxs, remainingTxs, err := filter.FilterDATransactions(ctx, txs, maxGas)
137142
if err != nil {
138143
span.RecordError(err)
139144
span.SetStatus(codes.Error, err.Error())

test/mocks/execution.go

Lines changed: 0 additions & 82 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)