Skip to content

Commit 5242ad2

Browse files
Eooustuxcanfly
andauthored
feat: implement getRemainingSleep(start) (#1779)
## Overview Implemented `getRemainingSleep(start)` and test case for new timer logic. Removed `defaultSleep` in `AggregationLoop` and `TestGetRemainingSleep`. Related #1644 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Introduced a `LazyAggregator` configuration for more flexible block production strategies. - Added new test functions for comprehensive coverage of aggregation behaviors. - **Improvements** - Simplified the `AggregationLoop` method by removing unnecessary parameters, enhancing clarity and maintainability. - Refined handling of sleep durations during aggregation for better efficiency. - Improved structure of aggregation methods to clearly define lazy and normal aggregation processes. - Enhanced testing strategy for `getRemainingSleep`, allowing for broader scenario coverage. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: 0xEclair <38656355+0xEclair@users.noreply.github.com> Co-authored-by: Javed Khan <tuxcanfly@gmail.com>
1 parent 448d086 commit 5242ad2

6 files changed

Lines changed: 282 additions & 115 deletions

File tree

block/manager.go

Lines changed: 88 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ import (
3535
"github.com/rollkit/rollkit/types"
3636
)
3737

38+
// defaultLazyBufferTime is the additional time to wait to accumulate transactions
39+
// in lazy mode
40+
const defaultLazyBufferTime = 1 * time.Second
41+
3842
// defaultDABlockTime is used only if DABlockTime is not configured for manager
3943
const defaultDABlockTime = 15 * time.Second
4044

@@ -198,6 +202,11 @@ func NewManager(
198202
conf.LazyBlockTime = defaultLazyBlockTime
199203
}
200204

205+
if conf.LazyBufferTime == 0 {
206+
logger.Info("Using default lazy buffer time", "LazyBufferTime", defaultLazyBufferTime)
207+
conf.LazyBufferTime = defaultLazyBufferTime
208+
}
209+
201210
if conf.DAMempoolTTL == 0 {
202211
logger.Info("Using default mempool ttl", "MempoolTTL", defaultMempoolTTL)
203212
conf.DAMempoolTTL = defaultMempoolTTL
@@ -347,8 +356,33 @@ func (m *Manager) IsDAIncluded(hash types.Hash) bool {
347356
return m.blockCache.isDAIncluded(hash.String())
348357
}
349358

359+
// getRemainingSleep calculates the remaining sleep time based on config and a start time.
360+
func (m *Manager) getRemainingSleep(start time.Time) time.Duration {
361+
elapsed := time.Since(start)
362+
interval := m.conf.BlockTime
363+
364+
if m.conf.LazyAggregator {
365+
if m.buildingBlock && elapsed >= interval {
366+
// LazyBufferTime is used to give time for transactions to
367+
// accumulate if we are coming out of a period of inactivity. If we
368+
// had recently produced a block (i.e. within the block time) then
369+
// we will sleep for the remaining time within the block time
370+
// interval.
371+
return m.conf.LazyBufferTime
372+
} else if !m.buildingBlock {
373+
interval = m.conf.LazyBlockTime
374+
}
375+
}
376+
377+
if elapsed < interval {
378+
return interval - elapsed
379+
}
380+
381+
return 0
382+
}
383+
350384
// AggregationLoop is responsible for aggregating transactions into rollup-blocks.
351-
func (m *Manager) AggregationLoop(ctx context.Context, lazy bool) {
385+
func (m *Manager) AggregationLoop(ctx context.Context) {
352386
initialHeight := uint64(m.genesis.InitialHeight)
353387
height := m.store.Height()
354388
var delay time.Duration
@@ -375,76 +409,70 @@ func (m *Manager) AggregationLoop(ctx context.Context, lazy bool) {
375409
// Lazy Aggregator mode.
376410
// In Lazy Aggregator mode, blocks are built only when there are
377411
// transactions or every LazyBlockTime.
378-
if lazy {
379-
// start is used to track the start time of the block production period
380-
var start time.Time
381-
382-
// defaultSleep is used when coming out of a period of inactivity,
383-
// to try and pull in more transactions in the first block
384-
defaultSleep := time.Second
385-
386-
// lazyTimer is used to signal when a block should be built in
387-
// lazy mode to signal that the chain is still live during long
388-
// periods of inactivity.
389-
lazyTimer := time.NewTimer(0)
390-
defer lazyTimer.Stop()
391-
for {
392-
select {
393-
case <-ctx.Done():
394-
return
395-
// the txsAvailable channel is signalled when Txns become available
396-
// in the mempool, or after transactions remain in the mempool after
397-
// building a block.
398-
case _, ok := <-m.txsAvailable:
399-
if ok && !m.buildingBlock {
400-
// set the buildingBlock flag to prevent multiple calls to reset the timer
401-
m.buildingBlock = true
402-
// Reset the block timer based on the block time and the default sleep.
403-
// The default sleep is used to give time for transactions to accumulate
404-
// if we are coming out of a period of inactivity. If we had recently
405-
// produced a block (i.e. within the block time) then we will sleep for
406-
// the remaining time within the block time interval.
407-
blockTimer.Reset(getRemainingSleep(start, m.conf.BlockTime, defaultSleep))
412+
if m.conf.LazyAggregator {
413+
m.lazyAggregationLoop(ctx, blockTimer)
414+
return
415+
}
408416

409-
}
410-
continue
411-
case <-lazyTimer.C:
412-
case <-blockTimer.C:
413-
}
414-
// Define the start time for the block production period
415-
start = time.Now()
416-
err := m.publishBlock(ctx)
417-
if err != nil && ctx.Err() == nil {
418-
m.logger.Error("error while publishing block", "error", err)
417+
m.normalAggregationLoop(ctx, blockTimer)
418+
}
419+
420+
func (m *Manager) lazyAggregationLoop(ctx context.Context, blockTimer *time.Timer) {
421+
// start is used to track the start time of the block production period
422+
start := time.Now()
423+
// lazyTimer is used to signal when a block should be built in
424+
// lazy mode to signal that the chain is still live during long
425+
// periods of inactivity.
426+
lazyTimer := time.NewTimer(0)
427+
defer lazyTimer.Stop()
428+
429+
for {
430+
select {
431+
case <-ctx.Done():
432+
return
433+
// the txsAvailable channel is signalled when Txns become available
434+
// in the mempool, or after transactions remain in the mempool after
435+
// building a block.
436+
case _, ok := <-m.txsAvailable:
437+
if ok && !m.buildingBlock {
438+
// set the buildingBlock flag to prevent multiple calls to reset the time
439+
m.buildingBlock = true
440+
// Reset the block timer based on the block time.
441+
blockTimer.Reset(m.getRemainingSleep(start))
419442
}
420-
// unset the buildingBlocks flag
421-
m.buildingBlock = false
422-
// Reset the lazyTimer to produce a block even if there
423-
// are no transactions as a way to signal that the chain
424-
// is still live. Default sleep is set to 0 because care
425-
// about producing blocks on time vs giving time for
426-
// transactions to accumulate.
427-
lazyTimer.Reset(getRemainingSleep(start, m.conf.LazyBlockTime, 0))
443+
continue
444+
case <-lazyTimer.C:
445+
case <-blockTimer.C:
446+
}
447+
// Define the start time for the block production period
448+
start = time.Now()
449+
if err := m.publishBlock(ctx); err != nil && ctx.Err() == nil {
450+
m.logger.Error("error while publishing block", "error", err)
428451
}
452+
// unset the buildingBlocks flag
453+
m.buildingBlock = false
454+
// Reset the lazyTimer to produce a block even if there
455+
// are no transactions as a way to signal that the chain
456+
// is still live.
457+
lazyTimer.Reset(m.getRemainingSleep(start))
429458
}
459+
}
430460

431-
// Normal Aggregator mode
461+
func (m *Manager) normalAggregationLoop(ctx context.Context, blockTimer *time.Timer) {
432462
for {
433463
select {
434464
case <-ctx.Done():
435465
return
436466
case <-blockTimer.C:
467+
// Define the start time for the block production period
468+
start := time.Now()
469+
if err := m.publishBlock(ctx); err != nil && ctx.Err() == nil {
470+
m.logger.Error("error while publishing block", "error", err)
471+
}
472+
// Reset the blockTimer to signal the next block production
473+
// period based on the block time.
474+
blockTimer.Reset(m.getRemainingSleep(start))
437475
}
438-
start := time.Now()
439-
err := m.publishBlock(ctx)
440-
if err != nil && ctx.Err() == nil {
441-
m.logger.Error("error while publishing block", "error", err)
442-
}
443-
// Reset the blockTimer to signal the next block production
444-
// period based on the block time. Default sleep is set to 0
445-
// because care about producing blocks on time vs giving time
446-
// for transactions to accumulate.
447-
blockTimer.Reset(getRemainingSleep(start, m.conf.BlockTime, 0))
448476
}
449477
}
450478

@@ -763,22 +791,6 @@ func (m *Manager) fetchBlock(ctx context.Context, daHeight uint64) (da.ResultRet
763791
return blockRes, err
764792
}
765793

766-
// getRemainingSleep calculates the remaining sleep time based on an interval
767-
// and a start time.
768-
func getRemainingSleep(start time.Time, interval, defaultSleep time.Duration) time.Duration {
769-
// Initialize the sleep duration to the default sleep duration to cover
770-
// the case where more time has past than the interval duration.
771-
sleepDuration := defaultSleep
772-
// Calculate the time elapsed since the start time.
773-
elapse := time.Since(start)
774-
// If less time has elapsed than the interval duration, calculate the
775-
// remaining time to sleep.
776-
if elapse < interval {
777-
sleepDuration = interval - elapse
778-
}
779-
return sleepDuration
780-
}
781-
782794
func (m *Manager) getSignature(header types.Header) (*types.Signature, error) {
783795
// note: for compatibility with tendermint light client
784796
consensusVote := header.MakeCometBFTVote()

0 commit comments

Comments
 (0)