/
vote_strategy.go
148 lines (130 loc) · 3.25 KB
/
vote_strategy.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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package quorum
import (
"math/rand"
"sync"
"time"
"encoding/json"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog"
)
type BlockMakerStatus int
const (
_ = iota
Active BlockMakerStatus = iota
Paused = iota
)
type BlockMakerStrategy interface {
// Start generating blocks
Start() error
// (temporary) stop generating blocks
Pause() error
// Resume after a pause
Resume() error
// Status returns indication if this implementation
// is generation CreateBlock events.
Status() BlockMakerStatus
}
// randomDeadlineStrategy asks the block voter to generate blocks
// after a deadline is passed without importing a new head. This
// deadline is chosen at random between 2 limits.
type randomDeadlineStrategy struct {
mux *event.TypeMux
min, max int // min and max deadline
activeMu sync.Mutex
active bool
deadlineTimer *time.Timer
}
// NewRandomDeadelineStrategy returns a block maker strategy that
// generated blocks randomly between the given min and max seconds.
func NewRandomDeadelineStrategy(mux *event.TypeMux, min, max uint) *randomDeadlineStrategy {
if min > max {
min, max = max, min
}
if min == 0 {
glog.Info("Set minimum block deadeline interval to 1 second")
min += 1
}
if min == max {
max += 1
}
s := &randomDeadlineStrategy{
mux: mux,
min: int(min),
max: int(max),
active: true,
}
return s
}
func resetBlockMakerTimer(t *time.Timer, min, max int) {
t.Stop()
select {
case <-t.C:
default:
}
t.Reset(time.Duration(min+rand.Intn(max-min)) * time.Second)
}
// Start generating block create request events.
func (s *randomDeadlineStrategy) Start() error {
if glog.V(logger.Debug) {
glog.Infof("Random deadline strategy configured with min=%d, max=%d", s.min, s.max)
}
s.deadlineTimer = time.NewTimer(time.Duration(s.min+rand.Intn(s.max-s.min)) * time.Second)
go func() {
sub := s.mux.Subscribe(core.ChainHeadEvent{})
for {
select {
case <-s.deadlineTimer.C:
s.activeMu.Lock()
if s.active {
s.mux.Post(CreateBlock{})
}
s.activeMu.Unlock()
resetBlockMakerTimer(s.deadlineTimer, s.min, s.max)
case <-sub.Chan():
resetBlockMakerTimer(s.deadlineTimer, s.min, s.max)
}
}
}()
return nil
}
// Pause stops generating block create requests.
// Can be resumed with Resume.
func (s *randomDeadlineStrategy) Pause() error {
s.activeMu.Lock()
s.active = false
s.activeMu.Unlock()
return nil
}
// Resume if paused.
func (s *randomDeadlineStrategy) Resume() error {
s.activeMu.Lock()
s.active = true
s.activeMu.Unlock()
return nil
}
// Status returns an indication if this strategy is currently
// generating block create request.
func (s *randomDeadlineStrategy) Status() BlockMakerStatus {
s.activeMu.Lock()
defer s.activeMu.Unlock()
if s.active {
return Active
}
return Paused
}
func (s *randomDeadlineStrategy) MarshalJSON() ([]byte, error) {
s.activeMu.Lock()
defer s.activeMu.Unlock()
status := "active"
if !s.active {
status = "paused"
}
return json.Marshal(map[string]interface{}{
"type": "deadline",
"minblocktime": s.min,
"maxblocktime": s.max,
"status": status,
})
}