@@ -118,11 +118,11 @@ func (e *Executor) Start(ctx context.Context) error {
118118 return fmt .Errorf ("failed to initialize state: %w" , err )
119119 }
120120
121- // Start execution loop
121+ // Start block production
122122 e .wg .Add (1 )
123123 go func () {
124124 defer e .wg .Done ()
125- e .executionLoop ()
125+ e .startBlockProduction ()
126126 }()
127127
128128 e .logger .Info ().Msg ("executor started" )
@@ -255,76 +255,123 @@ func (e *Executor) createGenesisBlock(ctx context.Context, stateRoot []byte) err
255255 return e .store .SaveBlockData (ctx , genesisHeader , data , & signature )
256256}
257257
258- // executionLoop handles block production and aggregation
259- func (e * Executor ) executionLoop () {
260- e .logger .Info ().Msg ("starting execution loop " )
261- defer e .logger .Info ().Msg ("execution loop stopped" )
258+ // startBlockProduction manages the block production lifecycle
259+ func (e * Executor ) startBlockProduction () {
260+ e .logger .Info ().Msg ("starting block production " )
261+ defer e .logger .Info ().Msg ("block production stopped" )
262262
263- var delay time.Duration
263+ // Wait until it's time to start producing blocks
264+ if ! e .waitUntilProductionTime () {
265+ return // context cancelled
266+ }
267+
268+ // Run the main production loop
269+ e .blockProductionLoop ()
270+ }
271+
272+ // waitUntilProductionTime waits until it's time to produce the first block
273+ func (e * Executor ) waitUntilProductionTime () bool {
274+ state := e .GetLastState ()
264275 initialHeight := e .genesis .InitialHeight
265- currentState := e .GetLastState ()
266276
267- if currentState .LastBlockHeight < initialHeight {
268- delay = time .Until (e .genesis .StartTime .Add (e .config .Node .BlockTime .Duration ))
277+ var waitUntil time.Time
278+ if state .LastBlockHeight < initialHeight {
279+ // New chain: wait until genesis time + block time
280+ waitUntil = e .genesis .StartTime .Add (e .config .Node .BlockTime .Duration )
269281 } else {
270- delay = time .Until (currentState .LastBlockTime .Add (e .config .Node .BlockTime .Duration ))
282+ // Existing chain: wait until last block time + block time
283+ waitUntil = state .LastBlockTime .Add (e .config .Node .BlockTime .Duration )
271284 }
272285
286+ delay := time .Until (waitUntil )
273287 if delay > 0 {
274- e .logger .Info ().Dur ("delay" , delay ).Msg ("waiting to start block production" )
288+ e .logger .Info ().
289+ Dur ("delay" , delay ).
290+ Time ("wait_until" , waitUntil ).
291+ Uint64 ("current_height" , state .LastBlockHeight ).
292+ Msg ("waiting to start block production" )
293+
275294 select {
276295 case <- e .ctx .Done ():
277- return
296+ return false
278297 case <- time .After (delay ):
298+ return true
279299 }
280300 }
281301
302+ return true
303+ }
304+
305+ // blockProductionLoop is the main block production loop
306+ func (e * Executor ) blockProductionLoop () {
307+ // Setup block timer
282308 blockTimer := time .NewTimer (e .config .Node .BlockTime .Duration )
283309 defer blockTimer .Stop ()
284310
311+ // Setup lazy timer if needed
285312 var lazyTimer * time.Timer
286313 var lazyTimerCh <- chan time.Time
314+
287315 if e .config .Node .LazyMode {
288- // lazyTimer triggers block publication even during inactivity
289316 lazyTimer = time .NewTimer (e .config .Node .LazyBlockInterval .Duration )
290317 defer lazyTimer .Stop ()
291318 lazyTimerCh = lazyTimer .C
319+ e .logger .Info ().
320+ Bool ("lazy_mode" , true ).
321+ Dur ("lazy_interval" , e .config .Node .LazyBlockInterval .Duration ).
322+ Msg ("lazy mode enabled" )
292323 }
324+
293325 txsAvailable := false
294326
327+ // Main production loop
295328 for {
296329 select {
297330 case <- e .ctx .Done ():
298331 return
299332
300333 case <- blockTimer .C :
301- if e .config .Node .LazyMode && ! txsAvailable {
302- // In lazy mode without transactions, just continue ticking
303- blockTimer .Reset (e .config .Node .BlockTime .Duration )
304- continue
305- }
306-
307- if err := e .produceBlock (); err != nil {
308- e .logger .Error ().Err (err ).Msg ("failed to produce block" )
309- }
310- txsAvailable = false
311- // Always reset block timer to keep ticking
312- blockTimer .Reset (e .config .Node .BlockTime .Duration )
334+ e .handleBlockTimer (& txsAvailable , blockTimer )
313335
314336 case <- lazyTimerCh :
315- e .logger .Debug ().Msg ("Lazy timer triggered block production" )
316- if err := e .produceBlock (); err != nil {
317- e .logger .Error ().Err (err ).Msg ("failed to produce block from lazy timer" )
318- }
319- // Reset lazy timer
320- lazyTimer .Reset (e .config .Node .LazyBlockInterval .Duration )
337+ e .handleLazyTimer (lazyTimer )
321338
322339 case <- e .txNotifyCh :
323340 txsAvailable = true
341+ e .logger .Debug ().Msg ("new transactions available" )
324342 }
325343 }
326344}
327345
346+ // handleBlockTimer processes regular block production timer
347+ func (e * Executor ) handleBlockTimer (txsAvailable * bool , timer * time.Timer ) {
348+ // In lazy mode, skip block production if no transactions available
349+ if e .config .Node .LazyMode && ! * txsAvailable {
350+ timer .Reset (e .config .Node .BlockTime .Duration )
351+ return
352+ }
353+
354+ // Produce block
355+ if err := e .produceBlock (); err != nil {
356+ e .logger .Error ().Err (err ).Msg ("failed to produce block" )
357+ }
358+
359+ // Reset state and timer
360+ * txsAvailable = false
361+ timer .Reset (e .config .Node .BlockTime .Duration )
362+ }
363+
364+ // handleLazyTimer processes lazy mode timer for forced block production
365+ func (e * Executor ) handleLazyTimer (timer * time.Timer ) {
366+ e .logger .Debug ().Msg ("lazy timer triggered block production" )
367+
368+ if err := e .produceBlock (); err != nil {
369+ e .logger .Error ().Err (err ).Msg ("failed to produce block from lazy timer" )
370+ }
371+
372+ timer .Reset (e .config .Node .LazyBlockInterval .Duration )
373+ }
374+
328375// produceBlock creates, validates, and stores a new block
329376func (e * Executor ) produceBlock () error {
330377 start := time .Now ()
0 commit comments