@@ -25,6 +25,8 @@ import (
2525 "github.com/evstack/ev-node/types"
2626)
2727
28+ var _ BlockProducer = (* Executor )(nil )
29+
2830// Executor handles block production, transaction processing, and state management
2931type Executor struct {
3032 // Core components
@@ -60,6 +62,10 @@ type Executor struct {
6062 ctx context.Context
6163 cancel context.CancelFunc
6264 wg sync.WaitGroup
65+
66+ // blockProducer is the interface used for block production operations.
67+ // defaults to self, but can be wrapped with tracing.
68+ blockProducer BlockProducer
6369}
6470
6571// NewExecutor creates a new block executor.
@@ -101,7 +107,7 @@ func NewExecutor(
101107 }
102108 }
103109
104- return & Executor {
110+ e := & Executor {
105111 store : store ,
106112 exec : exec ,
107113 sequencer : sequencer ,
@@ -117,7 +123,15 @@ func NewExecutor(
117123 txNotifyCh : make (chan struct {}, 1 ),
118124 errorCh : errorCh ,
119125 logger : logger .With ().Str ("component" , "executor" ).Logger (),
120- }, nil
126+ }
127+ e .blockProducer = e
128+ return e , nil
129+ }
130+
131+ // SetBlockProducer sets the block producer interface, allowing injection of
132+ // a tracing wrapper or other decorator.
133+ func (e * Executor ) SetBlockProducer (bp BlockProducer ) {
134+ e .blockProducer = bp
121135}
122136
123137// Start begins the execution component
@@ -279,7 +293,7 @@ func (e *Executor) executionLoop() {
279293 continue
280294 }
281295
282- if err := e .produceBlock ( ); err != nil {
296+ if err := e .blockProducer . ProduceBlock ( e . ctx ); err != nil {
283297 e .logger .Error ().Err (err ).Msg ("failed to produce block" )
284298 }
285299 txsAvailable = false
@@ -288,7 +302,7 @@ func (e *Executor) executionLoop() {
288302
289303 case <- lazyTimerCh :
290304 e .logger .Debug ().Msg ("Lazy timer triggered block production" )
291- if err := e .produceBlock ( ); err != nil {
305+ if err := e .blockProducer . ProduceBlock ( e . ctx ); err != nil {
292306 e .logger .Error ().Err (err ).Msg ("failed to produce block from lazy timer" )
293307 }
294308 // Reset lazy timer
@@ -300,8 +314,8 @@ func (e *Executor) executionLoop() {
300314 }
301315}
302316
303- // produceBlock creates, validates, and stores a new block
304- func (e * Executor ) produceBlock ( ) error {
317+ // ProduceBlock creates, validates, and stores a new block.
318+ func (e * Executor ) ProduceBlock ( ctx context. Context ) error {
305319 start := time .Now ()
306320 defer func () {
307321 if e .metrics .OperationDuration ["block_production" ] != nil {
@@ -338,7 +352,7 @@ func (e *Executor) produceBlock() error {
338352
339353 // Check if there's an already stored block at the newHeight
340354 // If there is use that instead of creating a new block
341- pendingHeader , pendingData , err := e .store .GetBlockData (e . ctx , newHeight )
355+ pendingHeader , pendingData , err := e .store .GetBlockData (ctx , newHeight )
342356 if err == nil {
343357 e .logger .Info ().Uint64 ("height" , newHeight ).Msg ("using pending block" )
344358 header = pendingHeader
@@ -347,7 +361,7 @@ func (e *Executor) produceBlock() error {
347361 return fmt .Errorf ("failed to get block data: %w" , err )
348362 } else {
349363 // get batch from sequencer
350- batchData , err = e .retrieveBatch ( e . ctx )
364+ batchData , err = e .blockProducer . RetrieveBatch ( ctx )
351365 if errors .Is (err , common .ErrNoBatch ) {
352366 e .logger .Debug ().Msg ("no batch available" )
353367 return nil
@@ -357,13 +371,13 @@ func (e *Executor) produceBlock() error {
357371 return fmt .Errorf ("failed to retrieve batch: %w" , err )
358372 }
359373
360- header , data , err = e .createBlock ( e . ctx , newHeight , batchData )
374+ header , data , err = e .blockProducer . CreateBlock ( ctx , newHeight , batchData )
361375 if err != nil {
362376 return fmt .Errorf ("failed to create block: %w" , err )
363377 }
364378
365379 // saved early for crash recovery, will be overwritten later with the final signature
366- batch , err := e .store .NewBatch (e . ctx )
380+ batch , err := e .store .NewBatch (ctx )
367381 if err != nil {
368382 return fmt .Errorf ("failed to create batch for early save: %w" , err )
369383 }
@@ -378,12 +392,12 @@ func (e *Executor) produceBlock() error {
378392 // Pass force-included mask through context for execution optimization
379393 // Force-included txs (from DA) MUST be validated as they're from untrusted sources
380394 // Mempool txs can skip validation as they were validated when added to mempool
381- ctx := e . ctx
395+ applyCtx := ctx
382396 if batchData != nil && batchData .Batch != nil && batchData .ForceIncludedMask != nil {
383- ctx = coreexecutor .WithForceIncludedMask (ctx , batchData .ForceIncludedMask )
397+ applyCtx = coreexecutor .WithForceIncludedMask (applyCtx , batchData .ForceIncludedMask )
384398 }
385399
386- newState , err := e .applyBlock ( ctx , header .Header , data )
400+ newState , err := e .blockProducer . ApplyBlock ( applyCtx , header .Header , data )
387401 if err != nil {
388402 return fmt .Errorf ("failed to apply block: %w" , err )
389403 }
@@ -400,13 +414,13 @@ func (e *Executor) produceBlock() error {
400414 }
401415 header .Signature = signature
402416
403- if err := e .validateBlock ( currentState , header , data ); err != nil {
417+ if err := e .blockProducer . ValidateBlock ( ctx , currentState , header , data ); err != nil {
404418 e .sendCriticalError (fmt .Errorf ("failed to validate block: %w" , err ))
405419 e .logger .Error ().Err (err ).Msg ("CRITICAL: Permanent block validation error - halting block production" )
406420 return fmt .Errorf ("failed to validate block: %w" , err )
407421 }
408422
409- batch , err := e .store .NewBatch (e . ctx )
423+ batch , err := e .store .NewBatch (ctx )
410424 if err != nil {
411425 return fmt .Errorf ("failed to create batch: %w" , err )
412426 }
@@ -431,9 +445,9 @@ func (e *Executor) produceBlock() error {
431445 e .setLastState (newState )
432446
433447 // broadcast header and data to P2P network
434- g , ctx := errgroup .WithContext (e . ctx )
435- g .Go (func () error { return e .headerBroadcaster .WriteToStoreAndBroadcast (ctx , header ) })
436- g .Go (func () error { return e .dataBroadcaster .WriteToStoreAndBroadcast (ctx , data ) })
448+ g , broadcastCtx := errgroup .WithContext (ctx )
449+ g .Go (func () error { return e .headerBroadcaster .WriteToStoreAndBroadcast (broadcastCtx , header ) })
450+ g .Go (func () error { return e .dataBroadcaster .WriteToStoreAndBroadcast (broadcastCtx , data ) })
437451 if err := g .Wait (); err != nil {
438452 e .logger .Error ().Err (err ).Msg ("failed to broadcast header and/data" )
439453 // don't fail block production on broadcast error
@@ -449,8 +463,8 @@ func (e *Executor) produceBlock() error {
449463 return nil
450464}
451465
452- // retrieveBatch gets the next batch of transactions from the sequencer
453- func (e * Executor ) retrieveBatch (ctx context.Context ) (* BatchData , error ) {
466+ // RetrieveBatch gets the next batch of transactions from the sequencer.
467+ func (e * Executor ) RetrieveBatch (ctx context.Context ) (* BatchData , error ) {
454468 req := coresequencer.GetNextBatchRequest {
455469 Id : []byte (e .genesis .ChainID ),
456470 MaxBytes : common .DefaultMaxBlobSize ,
@@ -481,8 +495,8 @@ func (e *Executor) retrieveBatch(ctx context.Context) (*BatchData, error) {
481495 }, nil
482496}
483497
484- // createBlock creates a new block from the given batch
485- func (e * Executor ) createBlock (ctx context.Context , height uint64 , batchData * BatchData ) (* types.SignedHeader , * types.Data , error ) {
498+ // CreateBlock creates a new block from the given batch.
499+ func (e * Executor ) CreateBlock (ctx context.Context , height uint64 , batchData * BatchData ) (* types.SignedHeader , * types.Data , error ) {
486500 currentState := e .getLastState ()
487501 headerTime := uint64 (e .genesis .StartTime .UnixNano ())
488502
@@ -581,8 +595,8 @@ func (e *Executor) createBlock(ctx context.Context, height uint64, batchData *Ba
581595 return header , data , nil
582596}
583597
584- // applyBlock applies the block to get the new state
585- func (e * Executor ) applyBlock (ctx context.Context , header types.Header , data * types.Data ) (types.State , error ) {
598+ // ApplyBlock applies the block to get the new state.
599+ func (e * Executor ) ApplyBlock (ctx context.Context , header types.Header , data * types.Data ) (types.State , error ) {
586600 currentState := e .getLastState ()
587601
588602 // Prepare transactions
@@ -654,8 +668,8 @@ func (e *Executor) executeTxsWithRetry(ctx context.Context, rawTxs [][]byte, hea
654668 return nil , nil
655669}
656670
657- // validateBlock validates the created block
658- func (e * Executor ) validateBlock ( lastState types.State , header * types.SignedHeader , data * types.Data ) error {
671+ // ValidateBlock validates the created block.
672+ func (e * Executor ) ValidateBlock ( _ context. Context , lastState types.State , header * types.SignedHeader , data * types.Data ) error {
659673 // Set custom verifier for aggregator node signature
660674 header .SetCustomVerifierForAggregator (e .options .AggregatorNodeSignatureBytesProvider )
661675
0 commit comments