github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/consensus/hotstuff/vote_collector.go (about) 1 package hotstuff 2 3 import ( 4 "github.com/rs/zerolog" 5 6 "github.com/onflow/flow-go/consensus/hotstuff/model" 7 "github.com/onflow/flow-go/model/flow" 8 ) 9 10 // VoteConsumer consumes all votes for one specific view. It is registered with 11 // the `VoteCollector` for the respective view. Upon registration, the 12 // `VoteCollector` feeds votes into the consumer in the order they are received 13 // (already cached votes as well as votes received in the future). Only votes 14 // that pass de-duplication and equivocation detection are passed on. CAUTION, 15 // VoteConsumer implementations must be 16 // - NON-BLOCKING and consume the votes without noteworthy delay, and 17 // - CONCURRENCY SAFE 18 type VoteConsumer func(vote *model.Vote) 19 20 // OnQCCreated is a callback which will be used by VoteCollector to submit a QC when it's able to create it 21 type OnQCCreated func(*flow.QuorumCertificate) 22 23 // VoteCollectorStatus indicates the VoteCollector's status 24 // It has three different status. 25 type VoteCollectorStatus int 26 27 const ( 28 // VoteCollectorStatusCaching is for the status when the block has not been received. 29 // The vote collector in this status will cache all the votes without verifying them 30 VoteCollectorStatusCaching VoteCollectorStatus = iota 31 32 // VoteCollectorStatusVerifying is for the status when the block has been received, 33 // and is able to process all votes for it. 34 VoteCollectorStatusVerifying 35 36 // VoteCollectorStatusInvalid is for the status when the block has been verified and 37 // is invalid. All votes to this block will be collected to slash the voter. 38 VoteCollectorStatusInvalid 39 ) 40 41 // VoteCollector collects votes for the same block, produces QC when enough votes are collected 42 // VoteCollector takes a callback function to report the event that a QC has been produced. 43 var collectorStatusNames = [...]string{"VoteCollectorStatusCaching", 44 "VoteCollectorStatusVerifying", 45 "VoteCollectorStatusInvalid"} 46 47 func (ps VoteCollectorStatus) String() string { 48 if ps < 0 || int(ps) > len(collectorStatusNames) { 49 return "UNKNOWN" 50 } 51 return collectorStatusNames[ps] 52 } 53 54 // VoteCollector collects all votes for a specified view. On the happy path, it 55 // generates a QC when enough votes have been collected. 56 // The VoteCollector internally delegates the vote-format specific processing 57 // to the VoteProcessor. 58 type VoteCollector interface { 59 // ProcessBlock performs validation of block signature and processes block with respected collector. 60 // Calling this function will mark conflicting collector as stale and change state of valid collectors 61 // It returns nil if the block is valid. 62 // It returns model.InvalidProposalError if block is invalid. 63 // It returns other error if there is exception processing the block. 64 ProcessBlock(block *model.Proposal) error 65 66 // AddVote adds a vote to the collector 67 // When enough votes have been added to produce a QC, the QC will be created asynchronously, and 68 // passed to EventLoop through a callback. 69 // No errors are expected during normal operations. 70 AddVote(vote *model.Vote) error 71 72 // RegisterVoteConsumer registers a VoteConsumer. Upon registration, the collector 73 // feeds all cached votes into the consumer in the order they arrived. 74 // CAUTION, VoteConsumer implementations must be 75 // * NON-BLOCKING and consume the votes without noteworthy delay, and 76 // * CONCURRENCY SAFE 77 RegisterVoteConsumer(consumer VoteConsumer) 78 79 // View returns the view that this instance is collecting votes for. 80 // This method is useful when adding the newly created vote collector to vote collectors map. 81 View() uint64 82 83 // Status returns the status of the vote collector 84 Status() VoteCollectorStatus 85 } 86 87 // VoteProcessor processes votes. It implements the vote-format specific processing logic. 88 // Depending on their implementation, a VoteProcessor might drop votes or attempt to construct a QC. 89 type VoteProcessor interface { 90 // Process performs processing of single vote. This function is safe to call from multiple goroutines. 91 // Expected error returns during normal operations: 92 // * VoteForIncompatibleBlockError - submitted vote for incompatible block 93 // * VoteForIncompatibleViewError - submitted vote for incompatible view 94 // * model.InvalidVoteError - submitted vote with invalid signature 95 // * model.DuplicatedSignerError - vote from a signer whose vote was previously already processed 96 // All other errors should be treated as exceptions. 97 Process(vote *model.Vote) error 98 99 // Status returns the status of the vote processor 100 Status() VoteCollectorStatus 101 } 102 103 // VerifyingVoteProcessor is a VoteProcessor that attempts to construct a QC for the given block. 104 type VerifyingVoteProcessor interface { 105 VoteProcessor 106 107 // Block returns which block that will be used to collector votes for. Transition to VerifyingVoteCollector can occur only 108 // when we have received block proposal so this information has to be available. 109 Block() *model.Block 110 } 111 112 // VoteProcessorFactory is a factory that can be used to create a verifying vote processors for a specific proposal. 113 // Depending on factory implementation it will return processors for consensus or collection clusters 114 type VoteProcessorFactory interface { 115 // Create instantiates a VerifyingVoteProcessor for processing votes for a specific proposal. 116 // Caller can be sure that proposal vote was successfully verified and processed. 117 // Expected error returns during normal operations: 118 // * model.InvalidProposalError - proposal has invalid proposer vote 119 Create(log zerolog.Logger, proposal *model.Proposal) (VerifyingVoteProcessor, error) 120 }