Skip to content

Commit a2d5a64

Browse files
committed
Introduced an additional structure to represent signed and unsigned hotstuff proposal. Updated SafetyRules interface and implementation
1 parent 5a2d8b6 commit a2d5a64

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+176
-180
lines changed

Diff for: consensus/hotstuff/consumer.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ type VoteAggregationViolationConsumer interface {
6060
// Prerequisites:
6161
// Implementation must be concurrency safe; Non-blocking;
6262
// and must handle repetition of the same events (with some processing overhead).
63-
OnVoteForInvalidBlockDetected(vote *model.Vote, invalidProposal *model.Proposal)
63+
OnVoteForInvalidBlockDetected(vote *model.Vote, invalidProposal *model.SignedProposal)
6464
}
6565

6666
// TimeoutAggregationViolationConsumer consumes outbound notifications about Active Pacemaker violations specifically
@@ -138,7 +138,7 @@ type ParticipantConsumer interface {
138138
// Prerequisites:
139139
// Implementation must be concurrency safe; Non-blocking;
140140
// and must handle repetition of the same events (with some processing overhead).
141-
OnReceiveProposal(currentView uint64, proposal *model.Proposal)
141+
OnReceiveProposal(currentView uint64, proposal *model.SignedProposal)
142142

143143
// OnReceiveQc notifications are produced by the EventHandler when it starts processing a
144144
// QuorumCertificate [QC] constructed by the node's internal vote aggregator.

Diff for: consensus/hotstuff/event_handler.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ type EventHandler interface {
3939
// consensus participant.
4040
// All inputs should be validated before feeding into this function. Assuming trusted data.
4141
// No errors are expected during normal operation.
42-
OnReceiveProposal(proposal *model.Proposal) error
42+
OnReceiveProposal(proposal *model.SignedProposal) error
4343

4444
// OnLocalTimeout handles a local timeout event by creating a model.TimeoutObject and broadcasting it.
4545
// No errors are expected during normal operation.

Diff for: consensus/hotstuff/eventhandler/event_handler.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ func (e *EventHandler) OnReceiveTc(tc *flow.TimeoutCertificate) error {
164164
// consensus participant.
165165
// All inputs should be validated before feeding into this function. Assuming trusted data.
166166
// No errors are expected during normal operation.
167-
func (e *EventHandler) OnReceiveProposal(proposal *model.Proposal) error {
167+
func (e *EventHandler) OnReceiveProposal(proposal *model.SignedProposal) error {
168168
block := proposal.Block
169169
curView := e.paceMaker.CurView()
170170
log := e.log.With().
@@ -429,7 +429,7 @@ func (e *EventHandler) proposeForNewViewIfPrimary() error {
429429
lastViewTC = nil
430430
}
431431

432-
// Construct Own Proposal
432+
// Construct Own SignedProposal
433433
// CAUTION, design constraints:
434434
// (i) We cannot process our own proposal within the `EventHandler` right away.
435435
// (ii) We cannot add our own proposal to Forks here right away.
@@ -491,7 +491,7 @@ func (e *EventHandler) proposeForNewViewIfPrimary() error {
491491
// It is called AFTER the block has been stored or found in Forks
492492
// It checks whether to vote for this block.
493493
// No errors are expected during normal operation.
494-
func (e *EventHandler) processBlockForCurrentView(proposal *model.Proposal) error {
494+
func (e *EventHandler) processBlockForCurrentView(proposal *model.SignedProposal) error {
495495
// sanity check that block is really for the current view:
496496
curView := e.paceMaker.CurView()
497497
block := proposal.Block
@@ -526,7 +526,7 @@ func (e *EventHandler) processBlockForCurrentView(proposal *model.Proposal) erro
526526
// ownVote generates and forwards the own vote, if we decide to vote.
527527
// Any errors are potential symptoms of uncovered edge cases or corrupted internal state (fatal).
528528
// No errors are expected during normal operation.
529-
func (e *EventHandler) ownVote(proposal *model.Proposal, curView uint64, nextLeader flow.Identifier) error {
529+
func (e *EventHandler) ownVote(proposal *model.SignedProposal, curView uint64, nextLeader flow.Identifier) error {
530530
block := proposal.Block
531531
log := e.log.With().
532532
Uint64("block_view", block.View).

Diff for: consensus/hotstuff/eventhandler/event_handler_test.go

+8-8
Original file line numberDiff line numberDiff line change
@@ -132,14 +132,14 @@ func NewSafetyRules(t *testing.T) *SafetyRules {
132132

133133
// SafetyRules will not vote for any block, unless the blockID exists in votable map
134134
safetyRules.On("ProduceVote", mock.Anything, mock.Anything).Return(
135-
func(block *model.Proposal, _ uint64) *model.Vote {
135+
func(block *model.SignedProposal, _ uint64) *model.Vote {
136136
_, ok := safetyRules.votable[block.Block.BlockID]
137137
if !ok {
138138
return nil
139139
}
140140
return createVote(block.Block)
141141
},
142-
func(block *model.Proposal, _ uint64) error {
142+
func(block *model.SignedProposal, _ uint64) error {
143143
_, ok := safetyRules.votable[block.Block.BlockID]
144144
if !ok {
145145
return model.NewNoVoteErrorf("block not found")
@@ -179,7 +179,7 @@ func NewForks(t *testing.T, finalized uint64) *Forks {
179179
}
180180

181181
f.On("AddValidatedBlock", mock.Anything).Return(func(proposal *model.Block) error {
182-
log.Info().Msgf("forks.AddValidatedBlock received Proposal for view: %v, QC: %v\n", proposal.View, proposal.QC.View)
182+
log.Info().Msgf("forks.AddValidatedBlock received SignedProposal for view: %v, QC: %v\n", proposal.View, proposal.QC.View)
183183
return f.addProposal(proposal)
184184
}).Maybe()
185185

@@ -228,7 +228,7 @@ type BlockProducer struct {
228228
}
229229

230230
func (b *BlockProducer) MakeBlockProposal(view uint64, qc *flow.QuorumCertificate, lastViewTC *flow.TimeoutCertificate) (*flow.Header, error) {
231-
return model.ProposalToFlow(&model.Proposal{
231+
return model.ProposalToFlow(&model.SignedProposal{
232232
Block: helper.MakeBlock(
233233
helper.WithBlockView(view),
234234
helper.WithBlockQC(qc),
@@ -258,8 +258,8 @@ type EventHandlerSuite struct {
258258

259259
initView uint64 // the current view at the beginning of the test case
260260
endView uint64 // the expected current view at the end of the test case
261-
parentProposal *model.Proposal
262-
votingProposal *model.Proposal
261+
parentProposal *model.SignedProposal
262+
votingProposal *model.SignedProposal
263263
qc *flow.QuorumCertificate
264264
tc *flow.TimeoutCertificate
265265
newview *model.NewViewEvent
@@ -1033,9 +1033,9 @@ func createVote(block *model.Block) *model.Vote {
10331033
}
10341034
}
10351035

1036-
func createProposal(view uint64, qcview uint64) *model.Proposal {
1036+
func createProposal(view uint64, qcview uint64) *model.SignedProposal {
10371037
block := createBlockWithQC(view, qcview)
1038-
return &model.Proposal{
1038+
return &model.SignedProposal{
10391039
Block: block,
10401040
SigData: nil,
10411041
}

Diff for: consensus/hotstuff/eventloop/event_loop.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import (
2222
// it contains an attached insertionTime that is used to measure how long we have waited between queening proposal and
2323
// actually processing by `EventHandler`.
2424
type queuedProposal struct {
25-
proposal *model.Proposal
25+
proposal *model.SignedProposal
2626
insertionTime time.Time
2727
}
2828

@@ -263,7 +263,7 @@ func (el *EventLoop) loop(ctx context.Context) error {
263263
}
264264

265265
// SubmitProposal pushes the received block to the proposals channel
266-
func (el *EventLoop) SubmitProposal(proposal *model.Proposal) {
266+
func (el *EventLoop) SubmitProposal(proposal *model.SignedProposal) {
267267
queueItem := queuedProposal{
268268
proposal: proposal,
269269
insertionTime: time.Now(),

Diff for: consensus/hotstuff/eventloop/event_loop_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ func TestReadyDoneWithStartTime(t *testing.T) {
258258
require.NoError(t, err)
259259

260260
done := make(chan struct{})
261-
eh.On("OnReceiveProposal", mock.AnythingOfType("*model.Proposal")).Run(func(args mock.Arguments) {
261+
eh.On("OnReceiveProposal", mock.AnythingOfType("*model.SignedProposal")).Run(func(args mock.Arguments) {
262262
require.True(t, time.Now().After(startTime))
263263
close(done)
264264
}).Return(nil).Once()

Diff for: consensus/hotstuff/forks/block_builder_test.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,8 @@ func (bb *BlockBuilder) AddVersioned(qcView uint64, blockView uint64, qcVersion
7777

7878
// Proposals returns a list of all proposals added to the BlockBuilder.
7979
// Returns an error if the blocks do not form a connected tree rooted at genesis.
80-
func (bb *BlockBuilder) Proposals() ([]*model.Proposal, error) {
81-
blocks := make([]*model.Proposal, 0, len(bb.blockViews))
80+
func (bb *BlockBuilder) Proposals() ([]*model.SignedProposal, error) {
81+
blocks := make([]*model.SignedProposal, 0, len(bb.blockViews))
8282

8383
genesisBlock := makeGenesis()
8484
genesisBV := &BlockView{
@@ -99,7 +99,7 @@ func (bb *BlockBuilder) Proposals() ([]*model.Proposal, error) {
9999
if qc.View+1 != bv.View {
100100
lastViewTC = helper.MakeTC(helper.WithTCView(bv.View - 1))
101101
}
102-
proposal := &model.Proposal{
102+
proposal := &model.SignedProposal{
103103
Block: &model.Block{
104104
View: bv.View,
105105
QC: qc,
@@ -177,7 +177,7 @@ func makeGenesis() *model.CertifiedBlock {
177177
}
178178

179179
// toBlocks converts the given proposals to slice of blocks
180-
func toBlocks(proposals []*model.Proposal) []*model.Block {
180+
func toBlocks(proposals []*model.SignedProposal) []*model.Block {
181181
blocks := make([]*model.Block, 0, len(proposals))
182182
for _, b := range proposals {
183183
blocks = append(blocks, b.Block)

Diff for: consensus/hotstuff/forks/forks.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,7 @@ func (f *Forks) checkForAdvancingFinalization(certifiedBlock *model.CertifiedBlo
401401
parentBlock := parentVertex.(*BlockContainer).Block()
402402

403403
// Note: we assume that all stored blocks pass Forks.EnsureBlockIsValidExtension(block);
404-
// specifically, that Proposal's ViewNumber is strictly monotonically
404+
// specifically, that SignedProposal's ViewNumber is strictly monotonically
405405
// increasing which is enforced by LevelledForest.VerifyVertex(...)
406406
// We denote:
407407
// * a DIRECT 1-chain as '<-'

Diff for: consensus/hotstuff/helper/block.go

+12-9
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,12 @@ func WithBlockQC(qc *flow.QuorumCertificate) func(*model.Block) {
5656
}
5757
}
5858

59-
func MakeProposal(options ...func(*model.Proposal)) *model.Proposal {
60-
proposal := &model.Proposal{
61-
Block: MakeBlock(),
59+
func MakeProposal(options ...func(*model.SignedProposal)) *model.SignedProposal {
60+
proposal := &model.SignedProposal{
61+
Proposal: model.Proposal{
62+
Block: MakeBlock(),
63+
LastViewTC: nil,
64+
},
6265
SigData: unittest.SignatureFixture(),
6366
}
6467
for _, option := range options {
@@ -67,20 +70,20 @@ func MakeProposal(options ...func(*model.Proposal)) *model.Proposal {
6770
return proposal
6871
}
6972

70-
func WithBlock(block *model.Block) func(*model.Proposal) {
71-
return func(proposal *model.Proposal) {
73+
func WithBlock(block *model.Block) func(*model.SignedProposal) {
74+
return func(proposal *model.SignedProposal) {
7275
proposal.Block = block
7376
}
7477
}
7578

76-
func WithSigData(sigData []byte) func(*model.Proposal) {
77-
return func(proposal *model.Proposal) {
79+
func WithSigData(sigData []byte) func(*model.SignedProposal) {
80+
return func(proposal *model.SignedProposal) {
7881
proposal.SigData = sigData
7982
}
8083
}
8184

82-
func WithLastViewTC(lastViewTC *flow.TimeoutCertificate) func(*model.Proposal) {
83-
return func(proposal *model.Proposal) {
85+
func WithLastViewTC(lastViewTC *flow.TimeoutCertificate) func(*model.SignedProposal) {
86+
return func(proposal *model.SignedProposal) {
8487
proposal.LastViewTC = lastViewTC
8588
}
8689
}

Diff for: consensus/hotstuff/integration/filters_test.go

+7-7
Original file line numberDiff line numberDiff line change
@@ -34,28 +34,28 @@ func BlockVotesBy(voterID flow.Identifier) VoteFilter {
3434
}
3535

3636
// ProposalFilter is a filter function for dropping Proposals.
37-
// Return value `true` implies that the the given Proposal should be
38-
// dropped, while `false` indicates that the Proposal should be received.
39-
type ProposalFilter func(*model.Proposal) bool
37+
// Return value `true` implies that the the given SignedProposal should be
38+
// dropped, while `false` indicates that the SignedProposal should be received.
39+
type ProposalFilter func(*model.SignedProposal) bool
4040

41-
func BlockNoProposals(*model.Proposal) bool {
41+
func BlockNoProposals(*model.SignedProposal) bool {
4242
return false
4343
}
4444

45-
func BlockAllProposals(*model.Proposal) bool {
45+
func BlockAllProposals(*model.SignedProposal) bool {
4646
return true
4747
}
4848

4949
// BlockProposalRandomly drops proposals randomly with a probability of `dropProbability` ∈ [0,1]
5050
func BlockProposalRandomly(dropProbability float64) ProposalFilter {
51-
return func(*model.Proposal) bool {
51+
return func(*model.SignedProposal) bool {
5252
return rand.Float64() < dropProbability
5353
}
5454
}
5555

5656
// BlockProposalsBy drops all proposals originating from the specified `proposerID`
5757
func BlockProposalsBy(proposerID flow.Identifier) ProposalFilter {
58-
return func(proposal *model.Proposal) bool {
58+
return func(proposal *model.SignedProposal) bool {
5959
return proposal.Block.ProposerID == proposerID
6060
}
6161
}

Diff for: consensus/hotstuff/integration/instance_test.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ type Instance struct {
5959
queue chan interface{}
6060
updatingBlocks sync.RWMutex
6161
headers map[flow.Identifier]*flow.Header
62-
pendings map[flow.Identifier]*model.Proposal // indexed by parent ID
62+
pendings map[flow.Identifier]*model.SignedProposal // indexed by parent ID
6363

6464
// mocked dependencies
6565
committee *mocks.DynamicCommittee
@@ -151,7 +151,7 @@ func NewInstance(t *testing.T, options ...Option) *Instance {
151151
stop: cfg.StopCondition,
152152

153153
// instance data
154-
pendings: make(map[flow.Identifier]*model.Proposal),
154+
pendings: make(map[flow.Identifier]*model.SignedProposal),
155155
headers: make(map[flow.Identifier]*flow.Header),
156156
queue: make(chan interface{}, 1024),
157157

@@ -403,7 +403,7 @@ func NewInstance(t *testing.T, options ...Option) *Instance {
403403
minRequiredWeight := committees.WeightThresholdToBuildQC(uint64(len(in.participants)) * weight)
404404
voteProcessorFactory := mocks.NewVoteProcessorFactory(t)
405405
voteProcessorFactory.On("Create", mock.Anything, mock.Anything).Return(
406-
func(log zerolog.Logger, proposal *model.Proposal) hotstuff.VerifyingVoteProcessor {
406+
func(log zerolog.Logger, proposal *model.SignedProposal) hotstuff.VerifyingVoteProcessor {
407407
stakingSigAggtor := helper.MakeWeightedSignatureAggregator(weight)
408408
stakingSigAggtor.On("Verify", mock.Anything, mock.Anything).Return(nil).Maybe()
409409

@@ -597,7 +597,7 @@ func (in *Instance) Run() error {
597597
}
598598
case msg := <-in.queue:
599599
switch m := msg.(type) {
600-
case *model.Proposal:
600+
case *model.SignedProposal:
601601
// add block to aggregator
602602
in.voteAggregator.AddBlock(m)
603603
// then pass to event handler
@@ -629,7 +629,7 @@ func (in *Instance) Run() error {
629629
}
630630
}
631631

632-
func (in *Instance) ProcessBlock(proposal *model.Proposal) {
632+
func (in *Instance) ProcessBlock(proposal *model.SignedProposal) {
633633
in.updatingBlocks.Lock()
634634
defer in.updatingBlocks.Unlock()
635635
_, parentExists := in.headers[proposal.Block.QC.BlockID]

Diff for: consensus/hotstuff/mocks/consumer.go

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: consensus/hotstuff/mocks/event_handler.go

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: consensus/hotstuff/mocks/event_loop.go

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: consensus/hotstuff/mocks/participant_consumer.go

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)