-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathslot_selector.go
More file actions
120 lines (99 loc) · 4.22 KB
/
slot_selector.go
File metadata and controls
120 lines (99 loc) · 4.22 KB
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
116
117
118
119
120
package dasmon
import (
"fmt"
"math"
"math/rand"
)
// SlotSelectionStrategy defines how slots are selected for custody probing
type SlotSelectionStrategy string
const (
// SlotSelectionUniform uses uniform random distribution across the custody window
SlotSelectionUniform SlotSelectionStrategy = "uniform"
// SlotSelectionRecent biases selection toward recent slots (closer to chain head)
// Uses exponential decay distribution
SlotSelectionRecent SlotSelectionStrategy = "recent"
// SlotSelectionHistorical biases selection toward older slots (further from chain head)
// Uses inverted exponential distribution
SlotSelectionHistorical SlotSelectionStrategy = "historical"
// SlotSelectionHeavilyRecent strongly biases selection toward very recent slots
// Uses more aggressive exponential decay than "recent"
SlotSelectionHeavilyRecent SlotSelectionStrategy = "heavily_recent"
// SlotSelectionHeavilyHistorical strongly biases selection toward older slots
// Uses more aggressive distribution than "historical"
SlotSelectionHeavilyHistorical SlotSelectionStrategy = "heavily_historical"
)
// SlotSelector is an interface for selecting slots based on different strategies.
type SlotSelector interface {
// SelectSlot selects a slot from the range [earliest, latest) based on the configured strategy.
// Returns earliest if the range is empty (latest <= earliest).
SelectSlot(within Range[uint64]) uint64
}
// ParseSlotSelector creates a SlotSelector implementation based on the given strategy.
// Returns an error if the strategy is unknown.
func ParseSlotSelector(strategy SlotSelectionStrategy) (SlotSelector, error) {
switch strategy {
case SlotSelectionUniform:
return &uniformSelector{}, nil
case SlotSelectionRecent:
return &recentSelector{decayFactor: 1.5}, nil
case SlotSelectionHistorical:
return &historicalSelector{decayFactor: 1.5}, nil
case SlotSelectionHeavilyRecent:
return &recentSelector{decayFactor: 3.0}, nil
case SlotSelectionHeavilyHistorical:
return &historicalSelector{decayFactor: 3.0}, nil
default:
return nil, fmt.Errorf("unknown slot selection strategy: %s", strategy)
}
}
// uniformSelector selects slots using uniform random distribution.
type uniformSelector struct{}
func (s *uniformSelector) SelectSlot(within Range[uint64]) uint64 {
slotDelta := within.Length()
if slotDelta == 0 {
return within.Start
}
return within.Start + uint64(rand.Uint64()%slotDelta)
}
// recentSelector selects slots with bias toward recent slots (closer to chain head).
// Uses exponential decay distribution where recent slots have higher probability.
type recentSelector struct {
// decayFactor controls the strength of the bias.
// Higher values create stronger concentration toward recent slots.
decayFactor float64
}
func (s *recentSelector) SelectSlot(within Range[uint64]) uint64 {
slotDelta := within.Length()
if slotDelta == 0 {
return within.Start
}
// Use exponential distribution transformed to [0, 1) naturally
// 1 - exp(-x/k) maps exponential to [0, 1) with bias toward 0
expValue := rand.ExpFloat64()
normalizedValue := 1.0 - math.Exp(-expValue/s.decayFactor)
// Map to slot range: invert so 0 maps to latest-1 (most recent)
offset := uint64(normalizedValue * float64(slotDelta-1))
// Invert: subtract from latest-1 to bias toward recent while staying < latest
return within.End - 1 - uint64(offset)
}
// historicalSelector selects slots with bias toward older slots (further from chain head).
// Uses inverted exponential distribution.
type historicalSelector struct {
// decayFactor controls the strength of the bias.
// Higher values create stronger concentration toward historical slots.
decayFactor float64
}
func (s *historicalSelector) SelectSlot(within Range[uint64]) uint64 {
slotDelta := within.Length()
if slotDelta == 0 {
return within.Start
}
// Use exponential distribution transformed to [0, 1) naturally
// 1 - exp(-x/k) maps exponential to [0, 1) with bias toward 0
expValue := rand.ExpFloat64()
normalizedValue := 1.0 - math.Exp(-expValue/s.decayFactor)
// Map to slot range: 0 maps to earliest (most historical)
offset := uint64(normalizedValue * float64(slotDelta-1))
// Add to earliest to bias toward historical slots while staying < latest
return within.Start + uint64(offset)
}