-
Notifications
You must be signed in to change notification settings - Fork 217
Expand file tree
/
Copy pathvote_collector.go
More file actions
129 lines (109 loc) · 6.05 KB
/
Copy pathvote_collector.go
File metadata and controls
129 lines (109 loc) · 6.05 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
121
122
123
124
125
126
127
128
129
package hotstuff
import (
"github.com/rs/zerolog"
"github.com/onflow/flow-go/consensus/hotstuff/model"
"github.com/onflow/flow-go/model/flow"
)
// VoteConsumer consumes all votes for one specific view. It is registered with
// the `VoteCollector` for the respective view. Upon registration, the
// `VoteCollector` feeds votes into the consumer in the order they are received
// (already cached votes as well as votes received in the future). Only votes
// that pass de-duplication and equivocation detection are passed on. CAUTION,
// VoteConsumer implementations must be
// - NON-BLOCKING and consume the votes without noteworthy delay, and
// - CONCURRENCY SAFE
type VoteConsumer func(vote *model.Vote)
// OnQCCreated is a callback which will be used by VoteCollector to submit a QC when it's able to create it
type OnQCCreated func(*flow.QuorumCertificate)
// VoteCollectorStatus indicates the VoteCollector's status
// It has three different status.
type VoteCollectorStatus int
const (
// VoteCollectorStatusCaching is for the status when the block has not been received.
// The vote collector in this status will cache all the votes without verifying them
VoteCollectorStatusCaching VoteCollectorStatus = iota
// VoteCollectorStatusVerifying is for the status when the block has been received,
// and is able to process all votes for it.
VoteCollectorStatusVerifying
// VoteCollectorStatusInvalid is for the status when the block has been verified and
// is invalid. All votes to this block will be collected to slash the voter.
VoteCollectorStatusInvalid
)
// VoteCollector collects votes for the same block, produces QC when enough votes are collected
// VoteCollector takes a callback function to report the event that a QC has been produced.
var collectorStatusNames = [...]string{"VoteCollectorStatusCaching",
"VoteCollectorStatusVerifying",
"VoteCollectorStatusInvalid"}
func (ps VoteCollectorStatus) String() string {
if ps < 0 || int(ps) > len(collectorStatusNames) {
return "UNKNOWN"
}
return collectorStatusNames[ps]
}
// VoteCollector collects all votes for a specified view. On the happy path, it
// generates a QC when enough votes have been collected.
// The VoteCollector internally delegates the vote-format specific processing
// to the VoteProcessor.
type VoteCollector interface {
// ProcessBlock performs validation of block signature and processes block with respected collector.
// Calling this function will mark conflicting collector as stale and change state of valid collectors
// It returns nil if the block is valid.
// It returns [model.InvalidProposalError] if block is invalid.
// It returns other error if there is exception processing the block.
ProcessBlock(block *model.SignedProposal) error
// AddVote adds a vote to the vote collector. The vote must be for the `VoteCollector`'s view (otherwise,
// an exception is returned). When enough votes have been added to produce a QC, the QC will be created
// asynchronously, and passed to EventLoop through a callback.
// All byzantine edge cases are handled internally via callbacks to notifier.
// Under normal execution only exceptions are propagated to caller.
AddVote(vote *model.Vote) error
// RegisterVoteConsumer registers a VoteConsumer. Upon registration, the collector
// feeds all cached votes into the consumer in the order they arrived.
// CAUTION, VoteConsumer implementations must be
// * NON-BLOCKING and consume the votes without noteworthy delay, and
// * CONCURRENCY SAFE
RegisterVoteConsumer(consumer VoteConsumer)
// View returns the view that this instance is collecting votes for.
// This method is useful when adding the newly created vote collector to vote collectors map.
View() uint64
// Status returns the status of the vote collector
Status() VoteCollectorStatus
}
// VoteProcessor processes votes. It implements the vote-format specific processing logic.
// Depending on their implementation, a VoteProcessor might drop votes or attempt to construct a QC.
type VoteProcessor interface {
// Process performs processing of single vote. This function is safe to call from multiple goroutines.
//
// Expected error returns during normal operations:
// - [VoteForIncompatibleBlockError] if vote is for incompatible block
// - [VoteForIncompatibleViewError] if vote is for incompatible view
// - [model.InvalidVoteError] if vote has invalid signature
// - [model.DuplicatedSignerError] if the same vote from the same signer has been already added
//
// All other errors should be treated as exceptions.
Process(vote *model.Vote) error
// Status returns the status of the vote processor
Status() VoteCollectorStatus
}
// VerifyingVoteProcessor is a VoteProcessor that attempts to construct a QC for a specific block
// (provided at construction time).
//
// IMPORTANT: The VerifyingVoteProcessor provides the final defense against any vote-equivocation attacks
// for its specific block. These attacks typically aim at multiple votes from the same node being counted
// towards the supermajority threshold. The VerifyingVoteProcessor must withstand attacks by the
// leader concurrently utilizing stand-alone votes and votes embedded into the proposal.
type VerifyingVoteProcessor interface {
VoteProcessor
// Block returns which block that will be used to collector votes for. Transition to VerifyingVoteCollector can occur only
// when we have received block proposal so this information has to be available.
Block() *model.Block
}
// VoteProcessorFactory is a factory that can be used to create a verifying vote processors for a specific proposal.
// Depending on factory implementation it will return processors for consensus or collection clusters
type VoteProcessorFactory interface {
// Create instantiates a VerifyingVoteProcessor for processing votes for a specific proposal.
// Caller can be sure that proposal vote was successfully verified and processed.
// Expected error returns during normal operations:
// * [model.InvalidProposalError] - proposal has invalid proposer vote
Create(log zerolog.Logger, proposal *model.SignedProposal) (VerifyingVoteProcessor, error)
}