88 "strings"
99 "time"
1010
11+ "github.com/evstack/ev-node/core/execution"
1112 "github.com/evstack/ev-node/pkg/store"
1213 ds "github.com/ipfs/go-datastore"
1314 "github.com/ipfs/go-datastore/query"
@@ -141,52 +142,52 @@ func (k *KVExecutor) computeStateRoot(ctx context.Context) ([]byte, error) {
141142// InitChain initializes the chain state with genesis parameters.
142143// It checks the database to see if genesis was already performed.
143144// If not, it computes the state root from the current DB state and persists genesis info.
144- func (k * KVExecutor ) InitChain (ctx context.Context , genesisTime time.Time , initialHeight uint64 , chainID string ) ([]byte , uint64 , error ) {
145+ func (k * KVExecutor ) InitChain (ctx context.Context , genesisTime time.Time , initialHeight uint64 , chainID string ) ([]byte , error ) {
145146 select {
146147 case <- ctx .Done ():
147- return nil , 0 , ctx .Err ()
148+ return nil , ctx .Err ()
148149 default :
149150 }
150151
151152 initialized , err := k .db .Has (ctx , genesisInitializedKey )
152153 if err != nil {
153- return nil , 0 , fmt .Errorf ("failed to check genesis initialization status: %w" , err )
154+ return nil , fmt .Errorf ("failed to check genesis initialization status: %w" , err )
154155 }
155156
156157 if initialized {
157158 genesisRoot , err := k .db .Get (ctx , genesisStateRootKey )
158159 if err != nil {
159- return nil , 0 , fmt .Errorf ("genesis initialized but failed to retrieve state root: %w" , err )
160+ return nil , fmt .Errorf ("genesis initialized but failed to retrieve state root: %w" , err )
160161 }
161- return genesisRoot , 1024 , nil // Assuming 1024 is a constant gas value
162+ return genesisRoot , nil
162163 }
163164
164165 // Genesis not initialized. Compute state root from the current DB state.
165166 // Note: The DB might not be empty if restarting, this reflects the state *at genesis time*.
166167 stateRoot , err := k .computeStateRoot (ctx )
167168 if err != nil {
168- return nil , 0 , fmt .Errorf ("failed to compute initial state root for genesis: %w" , err )
169+ return nil , fmt .Errorf ("failed to compute initial state root for genesis: %w" , err )
169170 }
170171
171172 // Persist genesis state root and initialized flag
172173 batch , err := k .db .Batch (ctx )
173174 if err != nil {
174- return nil , 0 , fmt .Errorf ("failed to create batch for genesis persistence: %w" , err )
175+ return nil , fmt .Errorf ("failed to create batch for genesis persistence: %w" , err )
175176 }
176177 err = batch .Put (ctx , genesisStateRootKey , stateRoot )
177178 if err != nil {
178- return nil , 0 , fmt .Errorf ("failed to put genesis state root in batch: %w" , err )
179+ return nil , fmt .Errorf ("failed to put genesis state root in batch: %w" , err )
179180 }
180181 err = batch .Put (ctx , genesisInitializedKey , []byte ("true" )) // Store a marker value
181182 if err != nil {
182- return nil , 0 , fmt .Errorf ("failed to put genesis initialized flag in batch: %w" , err )
183+ return nil , fmt .Errorf ("failed to put genesis initialized flag in batch: %w" , err )
183184 }
184185 err = batch .Commit (ctx )
185186 if err != nil {
186- return nil , 0 , fmt .Errorf ("failed to commit genesis persistence batch: %w" , err )
187+ return nil , fmt .Errorf ("failed to commit genesis persistence batch: %w" , err )
187188 }
188189
189- return stateRoot , 1024 , nil // Assuming 1024 is a constant gas value
190+ return stateRoot , nil
190191}
191192
192193// GetTxs retrieves available transactions from the mempool channel.
@@ -222,16 +223,16 @@ func (k *KVExecutor) GetTxs(ctx context.Context) ([][]byte, error) {
222223// ExecuteTxs processes each transaction assumed to be in the format "key=value".
223224// It updates the database accordingly using a batch and removes the executed transactions from the mempool.
224225// Invalid transactions are filtered out and logged, but execution continues.
225- func (k * KVExecutor ) ExecuteTxs (ctx context.Context , txs [][]byte , blockHeight uint64 , timestamp time.Time , prevStateRoot []byte ) ([]byte , uint64 , error ) {
226+ func (k * KVExecutor ) ExecuteTxs (ctx context.Context , txs [][]byte , blockHeight uint64 , timestamp time.Time , prevStateRoot []byte ) ([]byte , error ) {
226227 select {
227228 case <- ctx .Done ():
228- return nil , 0 , ctx .Err ()
229+ return nil , ctx .Err ()
229230 default :
230231 }
231232
232233 batch , err := k .db .Batch (ctx )
233234 if err != nil {
234- return nil , 0 , fmt .Errorf ("failed to create database batch: %w" , err )
235+ return nil , fmt .Errorf ("failed to create database batch: %w" , err )
235236 }
236237
237238 validTxCount := 0
@@ -274,7 +275,7 @@ func (k *KVExecutor) ExecuteTxs(ctx context.Context, txs [][]byte, blockHeight u
274275 err = batch .Put (ctx , dsKey , []byte (value ))
275276 if err != nil {
276277 // This error is unlikely for Put unless the context is cancelled.
277- return nil , 0 , fmt .Errorf ("failed to stage put operation in batch for key '%s': %w" , key , err )
278+ return nil , fmt .Errorf ("failed to stage put operation in batch for key '%s': %w" , key , err )
278279 }
279280 validTxCount ++
280281 }
@@ -287,18 +288,18 @@ func (k *KVExecutor) ExecuteTxs(ctx context.Context, txs [][]byte, blockHeight u
287288 // Commit the batch to apply all changes atomically
288289 err = batch .Commit (ctx )
289290 if err != nil {
290- return nil , 0 , fmt .Errorf ("failed to commit transaction batch: %w" , err )
291+ return nil , fmt .Errorf ("failed to commit transaction batch: %w" , err )
291292 }
292293
293294 // Compute the new state root *after* successful commit
294295 stateRoot , err := k .computeStateRoot (ctx )
295296 if err != nil {
296297 // This is problematic, state was changed but root calculation failed.
297298 // May need more robust error handling or recovery logic.
298- return nil , 0 , fmt .Errorf ("failed to compute state root after executing transactions: %w" , err )
299+ return nil , fmt .Errorf ("failed to compute state root after executing transactions: %w" , err )
299300 }
300301
301- return stateRoot , 1024 , nil
302+ return stateRoot , nil
302303}
303304
304305// SetFinal marks a block as finalized at the specified height.
@@ -422,3 +423,64 @@ func (k *KVExecutor) Rollback(ctx context.Context, height uint64) error {
422423func getTxKey (height uint64 , txKey string ) ds.Key {
423424 return heightKeyPrefix .Child (ds .NewKey (fmt .Sprintf ("%d/%s" , height , txKey )))
424425}
426+
427+ // GetExecutionInfo returns execution layer parameters.
428+ // For KVExecutor, returns MaxGas=0 indicating no gas-based filtering.
429+ func (k * KVExecutor ) GetExecutionInfo (ctx context.Context ) (execution.ExecutionInfo , error ) {
430+ return execution.ExecutionInfo {MaxGas : 0 }, nil
431+ }
432+
433+ // FilterTxs validates force-included transactions and applies size filtering.
434+ // For KVExecutor, validates key=value format when force-included txs are present.
435+ // KVExecutor doesn't track gas, so maxGas is ignored.
436+ func (k * KVExecutor ) FilterTxs (ctx context.Context , txs [][]byte , maxBytes , maxGas uint64 , hasForceIncludedTransaction bool ) ([]execution.FilterStatus , error ) {
437+ result := make ([]execution.FilterStatus , len (txs ))
438+
439+ var cumulativeBytes uint64
440+ limitReached := false
441+
442+ for i , tx := range txs {
443+ // Skip empty transactions
444+ if len (tx ) == 0 {
445+ result [i ] = execution .FilterRemove
446+ continue
447+ }
448+
449+ txBytes := uint64 (len (tx ))
450+
451+ // Only validate tx format if force-included txs are present
452+ // Mempool txs are already validated
453+ if hasForceIncludedTransaction {
454+ // Basic format validation: must be key=value
455+ parts := strings .SplitN (string (tx ), "=" , 2 )
456+ if len (parts ) != 2 || strings .TrimSpace (parts [0 ]) == "" {
457+ result [i ] = execution .FilterRemove
458+ continue
459+ }
460+ }
461+
462+ // Skip tx that can never make it in a block (too big)
463+ if maxBytes > 0 && txBytes > maxBytes {
464+ result [i ] = execution .FilterRemove
465+ continue
466+ }
467+
468+ // Once limit is reached, postpone remaining txs
469+ if limitReached {
470+ result [i ] = execution .FilterPostpone
471+ continue
472+ }
473+
474+ // Check size limit
475+ if maxBytes > 0 && cumulativeBytes + txBytes > maxBytes {
476+ limitReached = true
477+ result [i ] = execution .FilterPostpone
478+ continue
479+ }
480+
481+ cumulativeBytes += txBytes
482+ result [i ] = execution .FilterOK
483+ }
484+
485+ return result , nil
486+ }
0 commit comments