github.com/iotexproject/iotex-core@v1.14.1-rc1/pkg/util/blockutil/block_time_calculator.go (about)

     1  package blockutil
     2  
     3  import (
     4  	"errors"
     5  	"math"
     6  	"time"
     7  )
     8  
     9  type (
    10  	// BlockTimeCalculator calculates block time of a given height.
    11  	BlockTimeCalculator struct {
    12  		getBlockInterval    getBlockIntervalFn
    13  		getTipHeight        getTipHeightFn
    14  		getHistoryBlockTime getHistoryblockTimeFn
    15  	}
    16  
    17  	getBlockIntervalFn    func(uint64) time.Duration
    18  	getTipHeightFn        func() uint64
    19  	getHistoryblockTimeFn func(uint64) (time.Time, error)
    20  )
    21  
    22  // NewBlockTimeCalculator creates a new BlockTimeCalculator.
    23  func NewBlockTimeCalculator(getBlockInterval getBlockIntervalFn, getTipHeight getTipHeightFn, getHistoryBlockTime getHistoryblockTimeFn) (*BlockTimeCalculator, error) {
    24  	if getBlockInterval == nil {
    25  		return nil, errors.New("nil getBlockInterval")
    26  	}
    27  	if getTipHeight == nil {
    28  		return nil, errors.New("nil getTipHeight")
    29  	}
    30  	if getHistoryBlockTime == nil {
    31  		return nil, errors.New("nil getHistoryBlockTime")
    32  	}
    33  	return &BlockTimeCalculator{
    34  		getBlockInterval:    getBlockInterval,
    35  		getTipHeight:        getTipHeight,
    36  		getHistoryBlockTime: getHistoryBlockTime,
    37  	}, nil
    38  }
    39  
    40  // CalculateBlockTime returns the block time of the given height.
    41  // If the height is in the future, it will predict the block time according to the tip block time and interval.
    42  // If the height is in the past, it will get the block time from indexer.
    43  func (btc *BlockTimeCalculator) CalculateBlockTime(height uint64) (time.Time, error) {
    44  	// get block time from indexer if height is in the past
    45  	tipHeight := btc.getTipHeight()
    46  	if height <= tipHeight {
    47  		return btc.getHistoryBlockTime(height)
    48  	}
    49  
    50  	// predict block time according to tip block time and interval
    51  	blockInterval := btc.getBlockInterval(tipHeight)
    52  	blockNumer := time.Duration(height - tipHeight)
    53  	if blockNumer > math.MaxInt64/blockInterval {
    54  		return time.Time{}, errors.New("height overflow")
    55  	}
    56  	tipBlockTime, err := btc.getHistoryBlockTime(tipHeight)
    57  	if err != nil {
    58  		return time.Time{}, err
    59  	}
    60  	return tipBlockTime.Add(blockNumer * blockInterval), nil
    61  }