github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/state/protocol/blocktimer/blocktimer.go (about) 1 package blocktimer 2 3 import ( 4 "fmt" 5 "time" 6 7 "github.com/onflow/flow-go/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 }