-
Notifications
You must be signed in to change notification settings - Fork 199
/
arithmeticEpochProvider.go
115 lines (95 loc) · 3.87 KB
/
arithmeticEpochProvider.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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package epochproviders
import (
"fmt"
"sync"
"time"
logger "github.com/ElrondNetwork/elrond-go-logger"
)
// deltaEpochActive represents how many epochs behind the current computed epoch are to be considered "active" and
//cause the requests to be sent to all peers regardless of being full observers or not. Usually, a node will have
// [config.toml].[StoragePruning].NumActivePersisters opened persisters but to the fact that a shorter epoch can happen,
// that value is lowered at a maximum 1.
const deltaEpochActive = uint32(1)
const millisecondsInOneSecond = uint64(1000)
var log = logger.GetOrCreate("resolvers/epochproviders")
// ArgArithmeticEpochProvider is the argument structure for the arithmetic epoch provider
type ArgArithmeticEpochProvider struct {
RoundsPerEpoch uint32
RoundTimeInMilliseconds uint64
StartTime int64
}
type arithmeticEpochProvider struct {
sync.RWMutex
currentComputedEpoch uint32
headerEpoch uint32
headerTimestampForNewEpoch uint64
roundsPerEpoch uint32
roundTimeInMilliseconds uint64
startTime int64
getUnixHandler func() int64
}
// NewArithmeticEpochProvider returns a new arithmetic epoch provider able to mathematically compute the current network epoch
// based on the last block saved, considering the block's timestamp and epoch in respect with the current time
func NewArithmeticEpochProvider(arg ArgArithmeticEpochProvider) (*arithmeticEpochProvider, error) {
if arg.RoundsPerEpoch == 0 {
return nil, fmt.Errorf("%w in NewArithmeticEpochProvider", ErrInvalidRoundsPerEpoch)
}
if arg.RoundTimeInMilliseconds == 0 {
return nil, fmt.Errorf("%w in NewArithmeticEpochProvider", ErrInvalidRoundTimeInMilliseconds)
}
if arg.StartTime < 0 {
return nil, fmt.Errorf("%w in NewArithmeticEpochProvider", ErrInvalidStartTime)
}
aep := &arithmeticEpochProvider{
headerEpoch: 0,
headerTimestampForNewEpoch: uint64(arg.StartTime),
roundsPerEpoch: arg.RoundsPerEpoch,
roundTimeInMilliseconds: arg.RoundTimeInMilliseconds,
startTime: arg.StartTime,
}
aep.getUnixHandler = func() int64 {
return time.Now().Unix()
}
aep.computeCurrentEpoch() //based on the genesis provided data
return aep, nil
}
// EpochIsActiveInNetwork returns true if the persister for the given epoch is active in the network
func (aep *arithmeticEpochProvider) EpochIsActiveInNetwork(epoch uint32) bool {
aep.RLock()
defer aep.RUnlock()
subtractWillOverflow := aep.currentComputedEpoch < epoch
if subtractWillOverflow {
return true
}
return aep.currentComputedEpoch-epoch <= deltaEpochActive
}
// EpochConfirmed is called whenever the epoch was changed and will cause the re-computation of the network's current epoch
func (aep *arithmeticEpochProvider) EpochConfirmed(newEpoch uint32, newTimestamp uint64) {
isTimestampInvalid := newTimestamp == 0
if isTimestampInvalid {
return
}
aep.Lock()
aep.headerEpoch = newEpoch
aep.headerTimestampForNewEpoch = newTimestamp
aep.computeCurrentEpoch()
aep.Unlock()
}
func (aep *arithmeticEpochProvider) computeCurrentEpoch() {
currentTimeStamp := uint64(aep.getUnixHandler())
if currentTimeStamp < aep.headerTimestampForNewEpoch {
aep.currentComputedEpoch = aep.headerEpoch
return
}
diffTimeStampInSeconds := currentTimeStamp - aep.headerTimestampForNewEpoch
diffTimeStampInMilliseconds := diffTimeStampInSeconds * millisecondsInOneSecond
diffRounds := diffTimeStampInMilliseconds / aep.roundTimeInMilliseconds
diffEpochs := diffRounds / uint64(aep.roundsPerEpoch+1)
aep.currentComputedEpoch = aep.headerEpoch + uint32(diffEpochs)
log.Debug("arithmeticEpochProvider.computeCurrentEpoch",
"computed network epoch", aep.currentComputedEpoch)
}
// IsInterfaceNil returns true if there is no value under the interface
func (aep *arithmeticEpochProvider) IsInterfaceNil() bool {
return aep == nil
}