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  }