-
Notifications
You must be signed in to change notification settings - Fork 0
/
state.go
132 lines (105 loc) · 3.39 KB
/
state.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
package qbft
import (
"time"
)
type state struct {
// validators represent the current validator set
validators ValidatorSet
round uint64
quorum uint64
// timeoutCh is closed when the timeout for the round has expired
// timeoutTimer *time.Timer
timer Timer
latestPC []SignedContainer
acceptedPB *Block
commitSent bool
latestPreparedProposedBlock *Block
finalisedBlockSent bool
// list of messages received and processed
preparedMessages messageSetByRound[PrepareMessage]
proposalMessages messageSetByRound[ProposalMessage]
commitMessages messageSetByRound[CommitMessage]
roundChangeMessages messageSetByRound[RoundChangeMessage]
}
type defaultTimer struct {
timer *time.Timer
}
func (d *defaultTimer) TimeCh() <-chan time.Time {
return d.timer.C
}
func (d *defaultTimer) SetTimeout(duration time.Duration) {
d.timer.Reset(duration)
}
func newDefaultTimer() Timer {
timer := time.NewTimer(0)
timer.Stop()
return &defaultTimer{timer: timer}
}
func newState(timer Timer) *state {
return &state{
timer: timer,
}
}
func (s *state) setTimeout(timeout time.Duration) {
s.timer.SetTimeout(timeout)
}
func (s *state) resetState(validators ValidatorSet) {
s.validators = validators
s.round = 0
s.quorum, _ = getQuorumNumbers(s.validators.VotingPower())
s.latestPC = []SignedContainer{}
s.acceptedPB = nil
s.commitSent = false
s.latestPreparedProposedBlock = nil
s.finalisedBlockSent = false
// initialize message sets
s.proposalMessages = make(messageSetByRound[ProposalMessage])
s.preparedMessages = make(messageSetByRound[PrepareMessage])
s.commitMessages = make(messageSetByRound[CommitMessage])
s.roundChangeMessages = make(messageSetByRound[RoundChangeMessage])
}
func (s *state) SetRound(newRound uint64) {
s.round = newRound
}
func (s *state) addMessage(m QBFTMessageWithRecipient) bool {
votingPower, ok := s.validators.Exists(m.Sender)
if !ok {
return false
}
var inserted bool
from := m.Sender
if msg := m.Message.RoundChangeMessage; msg != nil {
inserted = s.roundChangeMessages.atRound(msg.Payload.UnsignedPayload.RoundChange.Round).addMessage(*msg, from, votingPower)
} else if msg := m.Message.PrepareMessage; msg != nil {
inserted = s.preparedMessages.atRound(msg.Payload.UnsignedPayload.Prepare.Round).addMessage(*msg, from, votingPower)
} else if msg := m.Message.ProposalMessage; msg != nil {
inserted = s.proposalMessages.atRound(msg.Payload.UnsignedPayload.Proposal.Round).addMessage(*msg, from, votingPower)
} else if msg := m.Message.CommitMessage; msg != nil {
inserted = s.commitMessages.atRound(msg.Payload.UnsignedPayload.Commit.Round).addMessage(*msg, from, votingPower)
}
return inserted
}
type messageSetByRound[T any] map[uint64]*messageSet[T]
func (m *messageSetByRound[T]) atRound(round uint64) *messageSet[T] {
if _, exists := (*m)[round]; !exists {
(*m)[round] = &messageSet[T]{
messageMap: make(map[NodeID]T),
}
}
return (*m)[round]
}
type messageSet[T any] struct {
messageMap map[NodeID]T
accumulatedVotingPower uint64
}
func (m *messageSet[T]) addMessage(message T, from NodeID, votingPower uint64) bool {
if _, exists := m.messageMap[from]; exists {
return false
}
m.messageMap[from] = message
m.accumulatedVotingPower += votingPower
return true
}
func (m *messageSet[T]) isQuorum(quorum uint64) bool {
return m.accumulatedVotingPower >= quorum
}