github.com/onflow/flow-go@v0.33.17/consensus/hotstuff/votecollector/factory.go (about) 1 package votecollector 2 3 import ( 4 "fmt" 5 6 "github.com/rs/zerolog" 7 8 "github.com/onflow/flow-go/consensus/hotstuff" 9 "github.com/onflow/flow-go/consensus/hotstuff/model" 10 "github.com/onflow/flow-go/consensus/hotstuff/signature" 11 ) 12 13 // baseFactory instantiates VerifyingVoteProcessors. Depending on the specific signing 14 // scheme (e.g. for main consensus, or collector clusters), a different baseFactory can 15 // be used. 16 // CAUTION: the baseFactory creates the VerifyingVoteProcessor for the given block. It 17 // does _not_ check the proposer's vote for its own block. The API reflects this by 18 // expecting a `model.Block` as input (which does _not_ contain the proposer vote) as 19 // opposed to `model.Proposal` (combines block with proposer's vote). 20 // Therefore, baseFactory does _not_ implement `hotstuff.VoteProcessorFactory` by itself. 21 // The VoteProcessorFactory adds the missing logic to verify the proposer's vote, by 22 // wrapping the baseFactory (decorator pattern). 23 type baseFactory func(log zerolog.Logger, block *model.Block) (hotstuff.VerifyingVoteProcessor, error) 24 25 // VoteProcessorFactory implements `hotstuff.VoteProcessorFactory`. Its main purpose 26 // is to construct instances of VerifyingVoteProcessors for a given block proposal. 27 // VoteProcessorFactory 28 // * delegates the creation of the actual instances to baseFactory 29 // * adds the logic to verify the proposer's vote for its own block 30 // Thereby, VoteProcessorFactory guarantees that only proposals with valid proposer 31 // vote are accepted (as per API specification). Otherwise, an `model.InvalidProposalError` 32 // is returned. 33 type VoteProcessorFactory struct { 34 baseFactory baseFactory 35 } 36 37 var _ hotstuff.VoteProcessorFactory = (*VoteProcessorFactory)(nil) 38 39 // Create instantiates a VerifyingVoteProcessor for the given block proposal. 40 // A VerifyingVoteProcessor are only created for proposals with valid proposer votes. 41 // Expected error returns during normal operations: 42 // * model.InvalidProposalError - proposal has invalid proposer vote 43 func (f *VoteProcessorFactory) Create(log zerolog.Logger, proposal *model.Proposal) (hotstuff.VerifyingVoteProcessor, error) { 44 processor, err := f.baseFactory(log, proposal.Block) 45 if err != nil { 46 return nil, fmt.Errorf("instantiating vote processor for block %v failed: %w", proposal.Block.BlockID, err) 47 } 48 49 err = processor.Process(proposal.ProposerVote()) 50 if err != nil { 51 if model.IsInvalidVoteError(err) { 52 return nil, model.NewInvalidProposalErrorf(proposal, "invalid proposer vote: %w", err) 53 } 54 return nil, fmt.Errorf("processing proposer's vote for block %v failed: %w", proposal.Block.BlockID, err) 55 } 56 return processor, nil 57 } 58 59 // NewStakingVoteProcessorFactory implements hotstuff.VoteProcessorFactory for 60 // members of a collector cluster. For their cluster-local hotstuff, collectors 61 // only sign with their staking key. 62 func NewStakingVoteProcessorFactory(committee hotstuff.DynamicCommittee, onQCCreated hotstuff.OnQCCreated) *VoteProcessorFactory { 63 base := &stakingVoteProcessorFactoryBase{ 64 committee: committee, 65 onQCCreated: onQCCreated, 66 } 67 return &VoteProcessorFactory{ 68 baseFactory: base.Create, 69 } 70 } 71 72 // NewCombinedVoteProcessorFactory implements hotstuff.VoteProcessorFactory fo 73 // participants of the Main Consensus committee. 74 // 75 // With their vote, members of the main consensus committee can contribute to hotstuff and 76 // the random beacon. When a consensus participant signs with its random beacon key, it 77 // contributes to HotStuff consensus _and_ the Random Beacon. As a fallback, a consensus 78 // participant can sign with its staking key; thereby it contributes only to consensus but 79 // not the random beacon. There should be an economic incentive for the nodes to preferably 80 // sign with their random beacon key. 81 func NewCombinedVoteProcessorFactory(committee hotstuff.DynamicCommittee, onQCCreated hotstuff.OnQCCreated) *VoteProcessorFactory { 82 base := &combinedVoteProcessorFactoryBaseV2{ 83 committee: committee, 84 onQCCreated: onQCCreated, 85 packer: signature.NewConsensusSigDataPacker(committee), 86 } 87 return &VoteProcessorFactory{ 88 baseFactory: base.Create, 89 } 90 } 91 92 /* ***************************** VerifyingVoteProcessor constructors for bootstrapping ***************************** */ 93 94 // NewBootstrapCombinedVoteProcessor directly creates a CombinedVoteProcessorV2, 95 // suitable for the collector's local cluster consensus. 96 // Intended use: only for bootstrapping. 97 // UNSAFE: the proposer vote for `block` is _not_ validated or included 98 func NewBootstrapCombinedVoteProcessor(log zerolog.Logger, committee hotstuff.DynamicCommittee, block *model.Block, onQCCreated hotstuff.OnQCCreated) (hotstuff.VerifyingVoteProcessor, error) { 99 factory := &combinedVoteProcessorFactoryBaseV2{ 100 committee: committee, 101 onQCCreated: onQCCreated, 102 packer: signature.NewConsensusSigDataPacker(committee), 103 } 104 return factory.Create(log, block) 105 } 106 107 // NewBootstrapStakingVoteProcessor directly creates a `StakingVoteProcessor`, 108 // suitable for the collector's local cluster consensus. 109 // Intended use: only for bootstrapping. 110 // UNSAFE: the proposer vote for `block` is _not_ validated or included 111 func NewBootstrapStakingVoteProcessor(log zerolog.Logger, committee hotstuff.DynamicCommittee, block *model.Block, onQCCreated hotstuff.OnQCCreated) (hotstuff.VerifyingVoteProcessor, error) { 112 factory := &stakingVoteProcessorFactoryBase{ 113 committee: committee, 114 onQCCreated: onQCCreated, 115 } 116 return factory.Create(log, block) 117 }