github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/core/helpers/slot_epoch.go (about) 1 package helpers 2 3 import ( 4 "fmt" 5 "math" 6 "time" 7 8 "github.com/pkg/errors" 9 types "github.com/prysmaticlabs/eth2-types" 10 iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface" 11 "github.com/prysmaticlabs/prysm/shared/params" 12 "github.com/prysmaticlabs/prysm/shared/timeutils" 13 ) 14 15 // MaxSlotBuffer specifies the max buffer given to slots from 16 // incoming objects. (24 mins with mainnet spec) 17 const MaxSlotBuffer = uint64(1 << 7) 18 19 // SlotToEpoch returns the epoch number of the input slot. 20 // 21 // Spec pseudocode definition: 22 // def compute_epoch_at_slot(slot: Slot) -> Epoch: 23 // """ 24 // Return the epoch number at ``slot``. 25 // """ 26 // return Epoch(slot // SLOTS_PER_EPOCH) 27 func SlotToEpoch(slot types.Slot) types.Epoch { 28 return types.Epoch(slot.DivSlot(params.BeaconConfig().SlotsPerEpoch)) 29 } 30 31 // CurrentEpoch returns the current epoch number calculated from 32 // the slot number stored in beacon state. 33 // 34 // Spec pseudocode definition: 35 // def get_current_epoch(state: BeaconState) -> Epoch: 36 // """ 37 // Return the current epoch. 38 // """ 39 // return compute_epoch_at_slot(state.slot) 40 func CurrentEpoch(state iface.ReadOnlyBeaconState) types.Epoch { 41 return SlotToEpoch(state.Slot()) 42 } 43 44 // PrevEpoch returns the previous epoch number calculated from 45 // the slot number stored in beacon state. It also checks for 46 // underflow condition. 47 // 48 // Spec pseudocode definition: 49 // def get_previous_epoch(state: BeaconState) -> Epoch: 50 // """` 51 // Return the previous epoch (unless the current epoch is ``GENESIS_EPOCH``). 52 // """ 53 // current_epoch = get_current_epoch(state) 54 // return GENESIS_EPOCH if current_epoch == GENESIS_EPOCH else Epoch(current_epoch - 1) 55 func PrevEpoch(state iface.ReadOnlyBeaconState) types.Epoch { 56 currentEpoch := CurrentEpoch(state) 57 if currentEpoch == 0 { 58 return 0 59 } 60 return currentEpoch - 1 61 } 62 63 // NextEpoch returns the next epoch number calculated from 64 // the slot number stored in beacon state. 65 func NextEpoch(state iface.ReadOnlyBeaconState) types.Epoch { 66 return SlotToEpoch(state.Slot()) + 1 67 } 68 69 // StartSlot returns the first slot number of the 70 // current epoch. 71 // 72 // Spec pseudocode definition: 73 // def compute_start_slot_at_epoch(epoch: Epoch) -> Slot: 74 // """ 75 // Return the start slot of ``epoch``. 76 // """ 77 // return Slot(epoch * SLOTS_PER_EPOCH) 78 func StartSlot(epoch types.Epoch) (types.Slot, error) { 79 slot, err := params.BeaconConfig().SlotsPerEpoch.SafeMul(uint64(epoch)) 80 if err != nil { 81 return slot, errors.Errorf("start slot calculation overflows: %v", err) 82 } 83 return slot, nil 84 } 85 86 // EndSlot returns the last slot number of the 87 // current epoch. 88 func EndSlot(epoch types.Epoch) (types.Slot, error) { 89 if epoch == math.MaxUint64 { 90 return 0, errors.New("start slot calculation overflows") 91 } 92 slot, err := StartSlot(epoch + 1) 93 if err != nil { 94 return 0, err 95 } 96 return slot - 1, nil 97 } 98 99 // IsEpochStart returns true if the given slot number is an epoch starting slot 100 // number. 101 func IsEpochStart(slot types.Slot) bool { 102 return slot%params.BeaconConfig().SlotsPerEpoch == 0 103 } 104 105 // IsEpochEnd returns true if the given slot number is an epoch ending slot 106 // number. 107 func IsEpochEnd(slot types.Slot) bool { 108 return IsEpochStart(slot + 1) 109 } 110 111 // SlotsSinceEpochStarts returns number of slots since the start of the epoch. 112 func SlotsSinceEpochStarts(slot types.Slot) types.Slot { 113 return slot % params.BeaconConfig().SlotsPerEpoch 114 } 115 116 // VerifySlotTime validates the input slot is not from the future. 117 func VerifySlotTime(genesisTime uint64, slot types.Slot, timeTolerance time.Duration) error { 118 slotTime, err := SlotToTime(genesisTime, slot) 119 if err != nil { 120 return err 121 } 122 123 // Defensive check to ensure unreasonable slots are rejected 124 // straight away. 125 if err := ValidateSlotClock(slot, genesisTime); err != nil { 126 return err 127 } 128 129 currentTime := timeutils.Now() 130 diff := slotTime.Sub(currentTime) 131 132 if diff > timeTolerance { 133 return fmt.Errorf("could not process slot from the future, slot time %s > current time %s", slotTime, currentTime) 134 } 135 return nil 136 } 137 138 // SlotToTime takes the given slot and genesis time to determine the start time of the slot. 139 func SlotToTime(genesisTimeSec uint64, slot types.Slot) (time.Time, error) { 140 timeSinceGenesis, err := slot.SafeMul(params.BeaconConfig().SecondsPerSlot) 141 if err != nil { 142 return time.Unix(0, 0), fmt.Errorf("slot (%d) is in the far distant future: %w", slot, err) 143 } 144 sTime, err := timeSinceGenesis.SafeAdd(genesisTimeSec) 145 if err != nil { 146 return time.Unix(0, 0), fmt.Errorf("slot (%d) is in the far distant future: %w", slot, err) 147 } 148 return time.Unix(int64(sTime), 0), nil 149 } 150 151 // SlotsSince computes the number of time slots that have occurred since the given timestamp. 152 func SlotsSince(time time.Time) types.Slot { 153 return CurrentSlot(uint64(time.Unix())) 154 } 155 156 // CurrentSlot returns the current slot as determined by the local clock and 157 // provided genesis time. 158 func CurrentSlot(genesisTimeSec uint64) types.Slot { 159 now := timeutils.Now().Unix() 160 genesis := int64(genesisTimeSec) 161 if now < genesis { 162 return 0 163 } 164 return types.Slot(uint64(now-genesis) / params.BeaconConfig().SecondsPerSlot) 165 } 166 167 // ValidateSlotClock validates a provided slot against the local 168 // clock to ensure slots that are unreasonable are returned with 169 // an error. 170 func ValidateSlotClock(slot types.Slot, genesisTimeSec uint64) error { 171 maxPossibleSlot := CurrentSlot(genesisTimeSec).Add(MaxSlotBuffer) 172 // Defensive check to ensure that we only process slots up to a hard limit 173 // from our local clock. 174 if slot > maxPossibleSlot { 175 return fmt.Errorf("slot %d > %d which exceeds max allowed value relative to the local clock", slot, maxPossibleSlot) 176 } 177 return nil 178 } 179 180 // RoundUpToNearestEpoch rounds up the provided slot value to the nearest epoch. 181 func RoundUpToNearestEpoch(slot types.Slot) types.Slot { 182 if slot%params.BeaconConfig().SlotsPerEpoch != 0 { 183 slot -= slot % params.BeaconConfig().SlotsPerEpoch 184 slot += params.BeaconConfig().SlotsPerEpoch 185 } 186 return slot 187 } 188 189 // VotingPeriodStartTime returns the current voting period's start time 190 // depending on the provided genesis and current slot. 191 func VotingPeriodStartTime(genesis uint64, slot types.Slot) uint64 { 192 slots := params.BeaconConfig().SlotsPerEpoch.Mul(uint64(params.BeaconConfig().EpochsPerEth1VotingPeriod)) 193 startTime := uint64((slot - slot.ModSlot(slots)).Mul(params.BeaconConfig().SecondsPerSlot)) 194 return genesis + startTime 195 } 196 197 // PrevSlot returns previous slot, with an exception in slot 0 to prevent underflow. 198 func PrevSlot(slot types.Slot) types.Slot { 199 if slot > 0 { 200 return slot.Sub(1) 201 } 202 return 0 203 }