-
Notifications
You must be signed in to change notification settings - Fork 175
/
factory.go
117 lines (104 loc) · 5.35 KB
/
factory.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
package votecollector
import (
"fmt"
"github.com/rs/zerolog"
"github.com/onflow/flow-go/consensus/hotstuff"
"github.com/onflow/flow-go/consensus/hotstuff/model"
"github.com/onflow/flow-go/consensus/hotstuff/signature"
)
// baseFactory instantiates VerifyingVoteProcessors. Depending on the specific signing
// scheme (e.g. for main consensus, or collector clusters), a different baseFactory can
// be used.
// CAUTION: the baseFactory creates the VerifyingVoteProcessor for the given block. It
// does _not_ check the proposer's vote for its own block. The API reflects this by
// expecting a `model.Block` as input (which does _not_ contain the proposer vote) as
// opposed to `model.Proposal` (combines block with proposer's vote).
// Therefore, baseFactory does _not_ implement `hotstuff.VoteProcessorFactory` by itself.
// The VoteProcessorFactory adds the missing logic to verify the proposer's vote, by
// wrapping the baseFactory (decorator pattern).
type baseFactory func(log zerolog.Logger, block *model.Block) (hotstuff.VerifyingVoteProcessor, error)
// VoteProcessorFactory implements `hotstuff.VoteProcessorFactory`. Its main purpose
// is to construct instances of VerifyingVoteProcessors for a given block proposal.
// VoteProcessorFactory
// * delegates the creation of the actual instances to baseFactory
// * adds the logic to verify the proposer's vote for its own block
// Thereby, VoteProcessorFactory guarantees that only proposals with valid proposer
// vote are accepted (as per API specification). Otherwise, an `model.InvalidProposalError`
// is returned.
type VoteProcessorFactory struct {
baseFactory baseFactory
}
var _ hotstuff.VoteProcessorFactory = (*VoteProcessorFactory)(nil)
// Create instantiates a VerifyingVoteProcessor for the given block proposal.
// A VerifyingVoteProcessor are only created for proposals with valid proposer votes.
// Expected error returns during normal operations:
// * model.InvalidProposalError - proposal has invalid proposer vote
func (f *VoteProcessorFactory) Create(log zerolog.Logger, proposal *model.Proposal) (hotstuff.VerifyingVoteProcessor, error) {
processor, err := f.baseFactory(log, proposal.Block)
if err != nil {
return nil, fmt.Errorf("instantiating vote processor for block %v failed: %w", proposal.Block.BlockID, err)
}
err = processor.Process(proposal.ProposerVote())
if err != nil {
if model.IsInvalidVoteError(err) {
return nil, model.NewInvalidProposalErrorf(proposal, "invalid proposer vote: %w", err)
}
return nil, fmt.Errorf("processing proposer's vote for block %v failed: %w", proposal.Block.BlockID, err)
}
return processor, nil
}
// NewStakingVoteProcessorFactory implements hotstuff.VoteProcessorFactory for
// members of a collector cluster. For their cluster-local hotstuff, collectors
// only sign with their staking key.
func NewStakingVoteProcessorFactory(committee hotstuff.DynamicCommittee, onQCCreated hotstuff.OnQCCreated) *VoteProcessorFactory {
base := &stakingVoteProcessorFactoryBase{
committee: committee,
onQCCreated: onQCCreated,
}
return &VoteProcessorFactory{
baseFactory: base.Create,
}
}
// NewCombinedVoteProcessorFactory implements hotstuff.VoteProcessorFactory fo
// participants of the Main Consensus committee.
//
// With their vote, members of the main consensus committee can contribute to hotstuff and
// the random beacon. When a consensus participant signs with its random beacon key, it
// contributes to HotStuff consensus _and_ the Random Beacon. As a fallback, a consensus
// participant can sign with its staking key; thereby it contributes only to consensus but
// not the random beacon. There should be an economic incentive for the nodes to preferably
// sign with their random beacon key.
func NewCombinedVoteProcessorFactory(committee hotstuff.DynamicCommittee, onQCCreated hotstuff.OnQCCreated) *VoteProcessorFactory {
base := &combinedVoteProcessorFactoryBaseV2{
committee: committee,
onQCCreated: onQCCreated,
packer: signature.NewConsensusSigDataPacker(committee),
}
return &VoteProcessorFactory{
baseFactory: base.Create,
}
}
/* ***************************** VerifyingVoteProcessor constructors for bootstrapping ***************************** */
// NewBootstrapCombinedVoteProcessor directly creates a CombinedVoteProcessorV2,
// suitable for the collector's local cluster consensus.
// Intended use: only for bootstrapping.
// UNSAFE: the proposer vote for `block` is _not_ validated or included
func NewBootstrapCombinedVoteProcessor(log zerolog.Logger, committee hotstuff.DynamicCommittee, block *model.Block, onQCCreated hotstuff.OnQCCreated) (hotstuff.VerifyingVoteProcessor, error) {
factory := &combinedVoteProcessorFactoryBaseV2{
committee: committee,
onQCCreated: onQCCreated,
packer: signature.NewConsensusSigDataPacker(committee),
}
return factory.Create(log, block)
}
// NewBootstrapStakingVoteProcessor directly creates a `StakingVoteProcessor`,
// suitable for the collector's local cluster consensus.
// Intended use: only for bootstrapping.
// UNSAFE: the proposer vote for `block` is _not_ validated or included
func NewBootstrapStakingVoteProcessor(log zerolog.Logger, committee hotstuff.DynamicCommittee, block *model.Block, onQCCreated hotstuff.OnQCCreated) (hotstuff.VerifyingVoteProcessor, error) {
factory := &stakingVoteProcessorFactoryBase{
committee: committee,
onQCCreated: onQCCreated,
}
return factory.Create(log, block)
}