github.com/koko1123/flow-go-1@v0.29.6/state/protocol/blocktimer/blocktimer.go (about)

     1  package blocktimer
     2  
     3  import (
     4  	"fmt"
     5  	"time"
     6  
     7  	"github.com/koko1123/flow-go-1/state/protocol"
     8  )
     9  
    10  // Is a functor that generates a current timestamp, usually it's just time.Now().
    11  // Used to make testing easier
    12  type timestampGenerator = func() time.Time
    13  
    14  // BlockTimestamp is a helper structure that performs building and validation of valid
    15  // timestamp for blocks that are generated by block builder and checked by hotstuff event loop.
    16  // Let τ be the time stamp of the parent block and t be the current clock time of the proposer that is building the child block
    17  // An honest proposer sets the Timestamp of its proposal according to the following rule:
    18  // if t is within the interval [τ + minInterval, τ + maxInterval], then the proposer sets Timestamp := t
    19  // otherwise, the proposer chooses the time stamp from the interval that is closest to its current time t, i.e.
    20  // if t < τ + minInterval, the proposer sets Timestamp := τ + minInterval
    21  // if τ + maxInterval < t, the proposer sets Timestamp := τ + maxInterval
    22  type BlockTimestamp struct {
    23  	minInterval time.Duration
    24  	maxInterval time.Duration
    25  	generator   timestampGenerator
    26  }
    27  
    28  var DefaultBlockTimer = NewNoopBlockTimer()
    29  
    30  // NewBlockTimer creates new block timer with specific intervals and time.Now as generator
    31  func NewBlockTimer(minInterval, maxInterval time.Duration) (*BlockTimestamp, error) {
    32  	if minInterval >= maxInterval {
    33  		return nil, fmt.Errorf("invariant minInterval < maxInterval is not satisfied, %d >= %d", minInterval, maxInterval)
    34  	}
    35  	if minInterval <= 0 {
    36  		return nil, fmt.Errorf("invariant minInterval > 0 it not satisifed")
    37  	}
    38  
    39  	return &BlockTimestamp{
    40  		minInterval: minInterval,
    41  		maxInterval: maxInterval,
    42  		generator:   func() time.Time { return time.Now().UTC() },
    43  	}, nil
    44  }
    45  
    46  // Build generates a timestamp based on definition of valid timestamp.
    47  func (b BlockTimestamp) Build(parentTimestamp time.Time) time.Time {
    48  	// calculate the timestamp and cutoffs
    49  	timestamp := b.generator()
    50  	from := parentTimestamp.Add(b.minInterval)
    51  	to := parentTimestamp.Add(b.maxInterval)
    52  
    53  	// adjust timestamp if outside of cutoffs
    54  	if timestamp.Before(from) {
    55  		timestamp = from
    56  	}
    57  	if timestamp.After(to) {
    58  		timestamp = to
    59  	}
    60  
    61  	return timestamp
    62  }
    63  
    64  // Validate accepts parent and current timestamps and checks if current timestamp satisfies
    65  // definition of valid timestamp.
    66  // Timestamp is valid if: Timestamp ∈ [τ + minInterval, τ + maxInterval]
    67  // Returns:
    68  //   - model.ErrInvalidBlockTimestamp - timestamp is invalid
    69  //   - nil - success
    70  func (b BlockTimestamp) Validate(parentTimestamp, currentTimestamp time.Time) error {
    71  	from := parentTimestamp.Add(b.minInterval)
    72  	to := parentTimestamp.Add(b.maxInterval)
    73  	if currentTimestamp.Before(from) || currentTimestamp.After(to) {
    74  		return protocol.NewInvalidBlockTimestamp("timestamp %v is not within interval [%v; %v]", currentTimestamp, from, to)
    75  	}
    76  	return nil
    77  }