Skip to content

Commit b945171

Browse files
authored
Merge branch 'feat/testnet-fixes' into round-aware-signatures-tracker
2 parents 9675d4e + 05bbb23 commit b945171

41 files changed

Lines changed: 1410 additions & 232 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

cmd/node/config/config.toml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,29 @@
110110
{ EnableEpoch = 2, NumRoundsToWaitBeforeSignalingChronologyStuck = 100 },
111111
]
112112

113+
ConsensusConfigsByRound = [
114+
{
115+
EnableRound = 0,
116+
SubroundsTiming = [
117+
{ StartTime = 0.0, EndTime = 0.05 }, # start round
118+
{ StartTime = 0.05, EndTime = 0.25 }, # block
119+
{ StartTime = 0.25, EndTime = 0.85 }, # signature
120+
{ StartTime = 0.85, EndTime = 0.95 }, # end round
121+
],
122+
ProcessingThresholdPercent = 85
123+
},
124+
{
125+
EnableRound = 440,
126+
SubroundsTiming = [
127+
{ StartTime = 0.0, EndTime = 0.05 }, # start round
128+
{ StartTime = 0.05, EndTime = 0.35 }, # block
129+
{ StartTime = 0.35, EndTime = 0.55 }, # signature
130+
{ StartTime = 0.55, EndTime = 0.95 }, # end round
131+
],
132+
ProcessingThresholdPercent = 85
133+
}
134+
]
135+
113136
[HardwareRequirements]
114137
CPUFlags = ["SSE4", "SSE42"]
115138

common/configs/commonConfigs.go

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,19 @@ const (
1414
defaultNumRoundsToWaitBeforeSignalingChronologyStuck = 10
1515
)
1616

17+
const expectedSubroundsTimingCount = 4
18+
19+
var defaultConsensusConfigByRound = config.ConsensusConfigByRound{
20+
EnableRound: 0,
21+
SubroundsTiming: []config.SubroundTiming{
22+
{StartTime: 0.0, EndTime: 0.05},
23+
{StartTime: 0.05, EndTime: 0.25},
24+
{StartTime: 0.25, EndTime: 0.85},
25+
{StartTime: 0.85, EndTime: 0.95},
26+
},
27+
ProcessingThresholdPercent: 85,
28+
}
29+
1730
// ErrEmptyCommonConfigsByEpoch signals that an empty common configs by epoch has been provided
1831
var ErrEmptyCommonConfigsByEpoch = errors.New("empty common configs by epoch")
1932

@@ -24,13 +37,15 @@ type commonConfigs struct {
2437
orderedEpochStartConfigByEpoch []config.EpochStartConfigByEpoch
2538
orderedEpochStartConfigByRound []config.EpochStartConfigByRound
2639
orderedConsensusConfigByEpoch []config.ConsensusConfigByEpoch
40+
orderedConsensusConfigByRound []config.ConsensusConfigByRound
2741
}
2842

2943
// NewCommonConfigsHandler creates a new process configs by epoch component
3044
func NewCommonConfigsHandler(
3145
configsByEpoch []config.EpochStartConfigByEpoch,
3246
configsByRound []config.EpochStartConfigByRound,
3347
consensusConfigByEpoch []config.ConsensusConfigByEpoch,
48+
consensusConfigByRound []config.ConsensusConfigByRound,
3449
) (*commonConfigs, error) {
3550
err := checkCommonConfigsByEpoch(configsByEpoch)
3651
if err != nil {
@@ -46,10 +61,16 @@ func NewCommonConfigsHandler(
4661
return nil, err
4762
}
4863

64+
err = checkConsensusConfigsByRound(consensusConfigByRound)
65+
if err != nil {
66+
return nil, err
67+
}
68+
4969
cc := &commonConfigs{
5070
orderedEpochStartConfigByEpoch: make([]config.EpochStartConfigByEpoch, len(configsByEpoch)),
5171
orderedEpochStartConfigByRound: make([]config.EpochStartConfigByRound, len(configsByRound)),
5272
orderedConsensusConfigByEpoch: make([]config.ConsensusConfigByEpoch, len(consensusConfigByEpoch)),
73+
orderedConsensusConfigByRound: make([]config.ConsensusConfigByRound, len(consensusConfigByRound)),
5374
}
5475

5576
// sort the config values in ascending order
@@ -68,6 +89,11 @@ func NewCommonConfigsHandler(
6889
return cc.orderedConsensusConfigByEpoch[i].EnableEpoch < cc.orderedConsensusConfigByEpoch[j].EnableEpoch
6990
})
7091

92+
copy(cc.orderedConsensusConfigByRound, consensusConfigByRound)
93+
sort.SliceStable(cc.orderedConsensusConfigByRound, func(i, j int) bool {
94+
return cc.orderedConsensusConfigByRound[i].EnableRound < cc.orderedConsensusConfigByRound[j].EnableRound
95+
})
96+
7197
return cc, nil
7298
}
7399

@@ -140,6 +166,71 @@ func checkConsensusConfigsByEpoch(configsByEpoch []config.ConsensusConfigByEpoch
140166
return nil
141167
}
142168

169+
func checkConsensusConfigsByRound(configsByRound []config.ConsensusConfigByRound) error {
170+
if len(configsByRound) == 0 {
171+
return ErrEmptyConsensusConfigsByRound
172+
}
173+
174+
// check for duplicated rounds
175+
seen := make(map[uint64]struct{})
176+
for _, cfg := range configsByRound {
177+
_, exists := seen[cfg.EnableRound]
178+
if exists {
179+
return ErrDuplicatedRoundConfig
180+
}
181+
seen[cfg.EnableRound] = struct{}{}
182+
183+
if err := checkSubroundsTiming(cfg); err != nil {
184+
return err
185+
}
186+
}
187+
188+
_, exists := seen[0]
189+
if !exists {
190+
return ErrMissingRoundZeroConfig
191+
}
192+
193+
return nil
194+
}
195+
196+
func checkSubroundsTiming(cfg config.ConsensusConfigByRound) error {
197+
// the slice must contain exactly one entry per subround
198+
if len(cfg.SubroundsTiming) != expectedSubroundsTimingCount {
199+
return ErrInvalidSubroundsTimingCount
200+
}
201+
202+
// all values must be non-negative and each subround must have start < end
203+
for _, t := range cfg.SubroundsTiming {
204+
if t.StartTime < 0 || t.EndTime < 0 {
205+
return ErrNegativeSubroundTiming
206+
}
207+
if t.StartTime >= t.EndTime {
208+
return ErrInvalidSubroundTimingRange
209+
}
210+
}
211+
212+
// subrounds must be ordered, contiguous (no gaps), and non-overlapping
213+
for i := 1; i < len(cfg.SubroundsTiming); i++ {
214+
if cfg.SubroundsTiming[i].StartTime != cfg.SubroundsTiming[i-1].EndTime {
215+
return ErrOverlappingSubroundTiming
216+
}
217+
}
218+
219+
// all boundary values must be < 1.0
220+
for _, t := range cfg.SubroundsTiming {
221+
if t.StartTime >= 1.0 || t.EndTime >= 1.0 {
222+
return ErrSubroundTimingExceedsRound
223+
}
224+
}
225+
226+
// ProcessingThresholdPercent must be in (0, 100]
227+
if cfg.ProcessingThresholdPercent == 0 || cfg.ProcessingThresholdPercent > 100 {
228+
return ErrInvalidProcessingThreshold
229+
}
230+
231+
return nil
232+
}
233+
143234
// GetGracePeriodRoundsByEpoch returns the grace period rounds by epoch
144235
func (cc *commonConfigs) GetGracePeriodRoundsByEpoch(epoch uint32) uint32 {
145236
for i := len(cc.orderedEpochStartConfigByEpoch) - 1; i >= 0; i-- {
@@ -184,6 +275,28 @@ func (cc *commonConfigs) GetNumRoundsToWaitBeforeSignalingChronologyStuck(epoch
184275
return defaultNumRoundsToWaitBeforeSignalingChronologyStuck // this should not happen
185276
}
186277

278+
// GetSubroundsTimingByRound returns the subrounds timing configuration active for the given round
279+
func (cc *commonConfigs) GetSubroundsTimingByRound(round uint64) config.ConsensusConfigByRound {
280+
for i := len(cc.orderedConsensusConfigByRound) - 1; i >= 0; i-- {
281+
if cc.orderedConsensusConfigByRound[i].EnableRound <= round {
282+
return cc.orderedConsensusConfigByRound[i]
283+
}
284+
}
285+
286+
return defaultConsensusConfigByRound // this should not happen
287+
}
288+
289+
// GetActiveTimingBoundaryRound returns the EnableRound of the ConsensusConfigByRound entry that is active for the given round
290+
func (cc *commonConfigs) GetActiveTimingBoundaryRound(round uint64) uint64 {
291+
for i := len(cc.orderedConsensusConfigByRound) - 1; i >= 0; i-- {
292+
if cc.orderedConsensusConfigByRound[i].EnableRound <= round {
293+
return cc.orderedConsensusConfigByRound[i].EnableRound
294+
}
295+
}
296+
297+
return 0
298+
}
299+
187300
// IsInterfaceNil checks if the instance is nil
188301
func (cc *commonConfigs) IsInterfaceNil() bool {
189302
return cc == nil

0 commit comments

Comments
 (0)