github.com/ava-labs/avalanchego@v1.11.11/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/ava-labs/avalanchego/database" 11 "github.com/ava-labs/avalanchego/utils/timer/mockable" 12 "github.com/ava-labs/avalanchego/vms/components/gas" 13 "github.com/ava-labs/avalanchego/vms/platformvm/config" 14 "github.com/ava-labs/avalanchego/vms/platformvm/txs/fee" 15 ) 16 17 func NextBlockTime(state Chain, clk *mockable.Clock) (time.Time, bool, error) { 18 var ( 19 timestamp = clk.Time() 20 parentTime = state.GetTimestamp() 21 ) 22 if parentTime.After(timestamp) { 23 timestamp = parentTime 24 } 25 // [timestamp] = max(now, parentTime) 26 27 nextStakerChangeTime, err := GetNextStakerChangeTime(state) 28 if err != nil { 29 return time.Time{}, false, fmt.Errorf("failed getting next staker change time: %w", err) 30 } 31 32 // timeWasCapped means that [timestamp] was reduced to [nextStakerChangeTime] 33 timeWasCapped := !timestamp.Before(nextStakerChangeTime) 34 if timeWasCapped { 35 timestamp = nextStakerChangeTime 36 } 37 // [timestamp] = min(max(now, parentTime), nextStakerChangeTime) 38 return timestamp, timeWasCapped, nil 39 } 40 41 // GetNextStakerChangeTime returns the next time a staker will be either added 42 // or removed to/from the current validator set. 43 func GetNextStakerChangeTime(state Chain) (time.Time, error) { 44 currentStakerIterator, err := state.GetCurrentStakerIterator() 45 if err != nil { 46 return time.Time{}, err 47 } 48 defer currentStakerIterator.Release() 49 50 pendingStakerIterator, err := state.GetPendingStakerIterator() 51 if err != nil { 52 return time.Time{}, err 53 } 54 defer pendingStakerIterator.Release() 55 56 hasCurrentStaker := currentStakerIterator.Next() 57 hasPendingStaker := pendingStakerIterator.Next() 58 switch { 59 case hasCurrentStaker && hasPendingStaker: 60 nextCurrentTime := currentStakerIterator.Value().NextTime 61 nextPendingTime := pendingStakerIterator.Value().NextTime 62 if nextCurrentTime.Before(nextPendingTime) { 63 return nextCurrentTime, nil 64 } 65 return nextPendingTime, nil 66 case hasCurrentStaker: 67 return currentStakerIterator.Value().NextTime, nil 68 case hasPendingStaker: 69 return pendingStakerIterator.Value().NextTime, nil 70 default: 71 return time.Time{}, database.ErrNotFound 72 } 73 } 74 75 // PickFeeCalculator creates either a static or a dynamic fee calculator, 76 // depending on the active upgrade. 77 // 78 // PickFeeCalculator does not modify [state]. 79 func PickFeeCalculator(cfg *config.Config, state Chain) fee.Calculator { 80 timestamp := state.GetTimestamp() 81 if !cfg.UpgradeConfig.IsEtnaActivated(timestamp) { 82 return NewStaticFeeCalculator(cfg, timestamp) 83 } 84 85 feeState := state.GetFeeState() 86 gasPrice := gas.CalculatePrice( 87 cfg.DynamicFeeConfig.MinPrice, 88 feeState.Excess, 89 cfg.DynamicFeeConfig.ExcessConversionConstant, 90 ) 91 return fee.NewDynamicCalculator( 92 cfg.DynamicFeeConfig.Weights, 93 gasPrice, 94 ) 95 } 96 97 // NewStaticFeeCalculator creates a static fee calculator, with the config set 98 // to either the pre-AP3 or post-AP3 config. 99 func NewStaticFeeCalculator(cfg *config.Config, timestamp time.Time) fee.Calculator { 100 config := cfg.StaticFeeConfig 101 if !cfg.UpgradeConfig.IsApricotPhase3Activated(timestamp) { 102 config.CreateSubnetTxFee = cfg.CreateAssetTxFee 103 config.CreateBlockchainTxFee = cfg.CreateAssetTxFee 104 } 105 return fee.NewStaticCalculator(config) 106 }