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