github.com/MetalBlockchain/metalgo@v1.11.9/vms/platformvm/state/chain_time_helpers.go (about)

     1  // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package state
     5  
     6  import (
     7  	"fmt"
     8  	"time"
     9  
    10  	"github.com/MetalBlockchain/metalgo/database"
    11  	"github.com/MetalBlockchain/metalgo/utils/timer/mockable"
    12  )
    13  
    14  func NextBlockTime(state Chain, clk *mockable.Clock) (time.Time, bool, error) {
    15  	var (
    16  		timestamp  = clk.Time()
    17  		parentTime = state.GetTimestamp()
    18  	)
    19  	if parentTime.After(timestamp) {
    20  		timestamp = parentTime
    21  	}
    22  	// [timestamp] = max(now, parentTime)
    23  
    24  	nextStakerChangeTime, err := GetNextStakerChangeTime(state)
    25  	if err != nil {
    26  		return time.Time{}, false, fmt.Errorf("failed getting next staker change time: %w", err)
    27  	}
    28  
    29  	// timeWasCapped means that [timestamp] was reduced to [nextStakerChangeTime]
    30  	timeWasCapped := !timestamp.Before(nextStakerChangeTime)
    31  	if timeWasCapped {
    32  		timestamp = nextStakerChangeTime
    33  	}
    34  	// [timestamp] = min(max(now, parentTime), nextStakerChangeTime)
    35  	return timestamp, timeWasCapped, nil
    36  }
    37  
    38  // GetNextStakerChangeTime returns the next time a staker will be either added
    39  // or removed to/from the current validator set.
    40  func GetNextStakerChangeTime(state Chain) (time.Time, error) {
    41  	currentStakerIterator, err := state.GetCurrentStakerIterator()
    42  	if err != nil {
    43  		return time.Time{}, err
    44  	}
    45  	defer currentStakerIterator.Release()
    46  
    47  	pendingStakerIterator, err := state.GetPendingStakerIterator()
    48  	if err != nil {
    49  		return time.Time{}, err
    50  	}
    51  	defer pendingStakerIterator.Release()
    52  
    53  	hasCurrentStaker := currentStakerIterator.Next()
    54  	hasPendingStaker := pendingStakerIterator.Next()
    55  	switch {
    56  	case hasCurrentStaker && hasPendingStaker:
    57  		nextCurrentTime := currentStakerIterator.Value().NextTime
    58  		nextPendingTime := pendingStakerIterator.Value().NextTime
    59  		if nextCurrentTime.Before(nextPendingTime) {
    60  			return nextCurrentTime, nil
    61  		}
    62  		return nextPendingTime, nil
    63  	case hasCurrentStaker:
    64  		return currentStakerIterator.Value().NextTime, nil
    65  	case hasPendingStaker:
    66  		return pendingStakerIterator.Value().NextTime, nil
    67  	default:
    68  		return time.Time{}, database.ErrNotFound
    69  	}
    70  }