Skip to content

Commit 8e28b80

Browse files
author
Alexander Hentschel
committed
• refactored Forks interface to reflect new version
• minor simplification of tests
1 parent 3410e79 commit 8e28b80

File tree

4 files changed

+224
-220
lines changed

4 files changed

+224
-220
lines changed

consensus/hotstuff/forks.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ type Forks interface {
4444
// blocks beyond the finalized root block it was initialized with.
4545
FinalityProof() (*FinalityProof, bool)
4646

47-
// AddProposal appends the given block to the tree of pending
47+
// AddValidatedBlock appends the validated block to the tree of pending
4848
// blocks and updates the latest finalized block (if applicable). Unless the parent is
4949
// below the pruning threshold (latest finalized view), we require that the parent is
5050
// already stored in Forks. Calling this method with previously processed blocks
@@ -69,7 +69,7 @@ type Forks interface {
6969
// breaking the safety guarantees of HotStuff (or there is a critical bug / data
7070
// corruption). Forks cannot recover from this exception.
7171
// - All other errors are potential symptoms of bugs or state corruption.
72-
AddProposal(proposal *model.Block) error
72+
AddValidatedBlock(proposal *model.Block) error
7373

7474
// AddCertifiedBlock appends the given certified block to the tree of pending
7575
// blocks and updates the latest finalized block (if finalization progressed).

consensus/hotstuff/forks/block_builder_test.go

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,9 @@ func (bb *BlockBuilder) AddVersioned(qcView uint64, blockView uint64, qcVersion
7575
return bb
7676
}
7777

78-
// Blocks returns a list of all blocks added to the BlockBuilder.
78+
// 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) Blocks() ([]*model.Proposal, error) {
80+
func (bb *BlockBuilder) Proposals() ([]*model.Proposal, error) {
8181
blocks := make([]*model.Proposal, 0, len(bb.blockViews))
8282

8383
genesisBlock := makeGenesis()
@@ -124,6 +124,16 @@ func (bb *BlockBuilder) Blocks() ([]*model.Proposal, error) {
124124
return blocks, nil
125125
}
126126

127+
// Blocks returns a list of all blocks added to the BlockBuilder.
128+
// Returns an error if the blocks do not form a connected tree rooted at genesis.
129+
func (bb *BlockBuilder) Blocks() ([]*model.Block, error) {
130+
proposals, err := bb.Proposals()
131+
if err != nil {
132+
return nil, fmt.Errorf("BlockBuilder failed to generate proposals: %w", err)
133+
}
134+
return toBlocks(proposals), nil
135+
}
136+
127137
func makePayloadHash(view uint64, qc *flow.QuorumCertificate, blockVersion int) flow.Identifier {
128138
return flow.MakeID(struct {
129139
View uint64
@@ -165,3 +175,12 @@ func makeGenesis() *model.CertifiedBlock {
165175
}
166176
return &certifiedGenesisBlock
167177
}
178+
179+
// toBlocks converts the given proposals to slice of blocks
180+
func toBlocks(proposals []*model.Proposal) []*model.Block {
181+
blocks := make([]*model.Block, 0, len(proposals))
182+
for _, b := range proposals {
183+
blocks = append(blocks, b.Block)
184+
}
185+
return blocks
186+
}

consensus/hotstuff/forks/forks.go

Lines changed: 20 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import (
1515
// The same approach has later been adopted by the Diem team resulting in DiemBFT v4:
1616
// https://developers.diem.com/papers/diem-consensus-state-machine-replication-in-the-diem-blockchain/2021-08-17.pdf
1717
// Forks is NOT safe for concurrent use by multiple goroutines.
18-
type Forks2 struct {
18+
type Forks struct {
1919
finalizationCallback module.Finalizer
2020
notifier hotstuff.FinalizationConsumer
2121
forest forest.LevelledForest
@@ -26,19 +26,14 @@ type Forks2 struct {
2626
finalityProof *hotstuff.FinalityProof
2727
}
2828

29-
// TODO:
30-
// - update `hotstuff.Forks` interface to represent Forks2
31-
// - update business logic to of consensus participant and follower to use Forks2
32-
//
33-
// As the result, the following should apply again
34-
var _ hotstuff.Forks = (*Forks2)(nil)
29+
var _ hotstuff.Forks = (*Forks)(nil)
3530

36-
func NewForks2(trustedRoot *model.CertifiedBlock, finalizationCallback module.Finalizer, notifier hotstuff.FinalizationConsumer) (*Forks2, error) {
31+
func NewForks(trustedRoot *model.CertifiedBlock, finalizationCallback module.Finalizer, notifier hotstuff.FinalizationConsumer) (*Forks, error) {
3732
if (trustedRoot.Block.BlockID != trustedRoot.CertifyingQC.BlockID) || (trustedRoot.Block.View != trustedRoot.CertifyingQC.View) {
3833
return nil, model.NewConfigurationErrorf("invalid root: root QC is not pointing to root block")
3934
}
4035

41-
forks := Forks2{
36+
forks := Forks{
4237
finalizationCallback: finalizationCallback,
4338
notifier: notifier,
4439
forest: *forest.NewLevelledForest(trustedRoot.Block.View),
@@ -56,15 +51,15 @@ func NewForks2(trustedRoot *model.CertifiedBlock, finalizationCallback module.Fi
5651
}
5752

5853
// FinalizedView returns the largest view number where a finalized block is known
59-
func (f *Forks2) FinalizedView() uint64 {
54+
func (f *Forks) FinalizedView() uint64 {
6055
if f.finalityProof == nil {
6156
return f.trustedRoot.Block.View
6257
}
6358
return f.finalityProof.Block.View
6459
}
6560

6661
// FinalizedBlock returns the finalized block with the largest view number
67-
func (f *Forks2) FinalizedBlock() *model.Block {
62+
func (f *Forks) FinalizedBlock() *model.Block {
6863
if f.finalityProof == nil {
6964
return f.trustedRoot.Block
7065
}
@@ -75,13 +70,13 @@ func (f *Forks2) FinalizedBlock() *model.Block {
7570
// the subsequent view, which proves finality.
7671
// CAUTION: method returns (nil, false), when Forks has not yet finalized any
7772
// blocks beyond the finalized root block it was initialized with.
78-
func (f *Forks2) FinalityProof() (*hotstuff.FinalityProof, bool) {
73+
func (f *Forks) FinalityProof() (*hotstuff.FinalityProof, bool) {
7974
return f.finalityProof, f.finalityProof != nil
8075
}
8176

8277
// GetBlock returns (BlockProposal, true) if the block with the specified
8378
// id was found and (nil, false) otherwise.
84-
func (f *Forks2) GetBlock(blockID flow.Identifier) (*model.Block, bool) {
79+
func (f *Forks) GetBlock(blockID flow.Identifier) (*model.Block, bool) {
8580
blockContainer, hasBlock := f.forest.GetVertex(blockID)
8681
if !hasBlock {
8782
return nil, false
@@ -90,7 +85,7 @@ func (f *Forks2) GetBlock(blockID flow.Identifier) (*model.Block, bool) {
9085
}
9186

9287
// GetBlocksForView returns all known blocks for the given view
93-
func (f *Forks2) GetBlocksForView(view uint64) []*model.Block {
88+
func (f *Forks) GetBlocksForView(view uint64) []*model.Block {
9489
vertexIterator := f.forest.GetVerticesAtLevel(view)
9590
blocks := make([]*model.Block, 0, 1) // in the vast majority of cases, there will only be one proposal for a particular view
9691
for vertexIterator.HasNext() {
@@ -101,7 +96,7 @@ func (f *Forks2) GetBlocksForView(view uint64) []*model.Block {
10196
}
10297

10398
// IsKnownBlock checks whether block is known.
104-
func (f *Forks2) IsKnownBlock(blockID flow.Identifier) bool {
99+
func (f *Forks) IsKnownBlock(blockID flow.Identifier) bool {
105100
_, hasBlock := f.forest.GetVertex(blockID)
106101
return hasBlock
107102
}
@@ -113,7 +108,7 @@ func (f *Forks2) IsKnownBlock(blockID flow.Identifier) bool {
113108
// - the block already exists in the consensus state
114109
//
115110
// UNVALIDATED: expects block to pass Forks.EnsureBlockIsValidExtension(block)
116-
func (f *Forks2) IsProcessingNeeded(block *model.Block) bool {
111+
func (f *Forks) IsProcessingNeeded(block *model.Block) bool {
117112
if block.View < f.FinalizedView() || f.IsKnownBlock(block.BlockID) {
118113
return false
119114
}
@@ -148,7 +143,7 @@ func (f *Forks2) IsProcessingNeeded(block *model.Block) bool {
148143
// forest (but is above the pruned view). Represents violation of condition 3.
149144
// - model.InvalidBlockError if the block violates condition 1. or 2.
150145
// - generic error in case of unexpected bug or internal state corruption
151-
func (f *Forks2) EnsureBlockIsValidExtension(block *model.Block) error {
146+
func (f *Forks) EnsureBlockIsValidExtension(block *model.Block) error {
152147
if block.View < f.forest.LowestLevel { // exclusion (i)
153148
return nil
154149
}
@@ -200,7 +195,7 @@ func (f *Forks2) EnsureBlockIsValidExtension(block *model.Block) error {
200195
// breaking the safety guarantees of HotStuff (or there is a critical bug / data
201196
// corruption). Forks cannot recover from this exception.
202197
// - All other errors are potential symptoms of bugs or state corruption.
203-
func (f *Forks2) AddCertifiedBlock(certifiedBlock *model.CertifiedBlock) error {
198+
func (f *Forks) AddCertifiedBlock(certifiedBlock *model.CertifiedBlock) error {
204199
if !f.IsProcessingNeeded(certifiedBlock.Block) {
205200
return nil
206201
}
@@ -227,7 +222,7 @@ func (f *Forks2) AddCertifiedBlock(certifiedBlock *model.CertifiedBlock) error {
227222
return nil
228223
}
229224

230-
// AddProposal appends the given block to the tree of pending
225+
// AddValidatedBlock appends the validated block to the tree of pending
231226
// blocks and updates the latest finalized block (if applicable). Unless the parent is
232227
// below the pruning threshold (latest finalized view), we require that the parent is
233228
// already stored in Forks. Calling this method with previously processed blocks
@@ -252,7 +247,7 @@ func (f *Forks2) AddCertifiedBlock(certifiedBlock *model.CertifiedBlock) error {
252247
// breaking the safety guarantees of HotStuff (or there is a critical bug / data
253248
// corruption). Forks cannot recover from this exception.
254249
// - All other errors are potential symptoms of bugs or state corruption.
255-
func (f *Forks2) AddProposal(proposal *model.Block) error {
250+
func (f *Forks) AddValidatedBlock(proposal *model.Block) error {
256251
if !f.IsProcessingNeeded(proposal) {
257252
return nil
258253
}
@@ -299,7 +294,7 @@ func (f *Forks2) AddProposal(proposal *model.Block) error {
299294
// - model.ByzantineThresholdExceededError if conflicting QCs have been detected.
300295
// Forks cannot recover from this exception.
301296
// - All other errors are potential symptoms of bugs or state corruption.
302-
func (f *Forks2) checkForByzantineEvidence(block *model.Block) error {
297+
func (f *Forks) checkForByzantineEvidence(block *model.Block) error {
303298
err := f.EnsureBlockIsValidExtension(block)
304299
if err != nil {
305300
return fmt.Errorf("consistency check on block failed: %w", err)
@@ -325,7 +320,7 @@ func (f *Forks2) checkForByzantineEvidence(block *model.Block) error {
325320
// - model.ByzantineThresholdExceededError if conflicting QCs have been detected.
326321
// Forks cannot recover from this exception.
327322
// - All other errors are potential symptoms of bugs or state corruption.
328-
func (f *Forks2) checkForConflictingQCs(qc *flow.QuorumCertificate) error {
323+
func (f *Forks) checkForConflictingQCs(qc *flow.QuorumCertificate) error {
329324
it := f.forest.GetVerticesAtLevel(qc.View)
330325
for it.HasNext() {
331326
otherBlock := it.NextVertex() // by construction, must have same view as qc.View
@@ -352,7 +347,7 @@ func (f *Forks2) checkForConflictingQCs(qc *flow.QuorumCertificate) error {
352347
// checkForDoubleProposal checks if the input proposal is a double proposal.
353348
// A double proposal occurs when two proposals with the same view exist in Forks.
354349
// If there is a double proposal, notifier.OnDoubleProposeDetected is triggered.
355-
func (f *Forks2) checkForDoubleProposal(block *model.Block) {
350+
func (f *Forks) checkForDoubleProposal(block *model.Block) {
356351
it := f.forest.GetVerticesAtLevel(block.View)
357352
for it.HasNext() {
358353
otherVertex := it.NextVertex() // by construction, must have same view as block
@@ -377,7 +372,7 @@ func (f *Forks2) checkForDoubleProposal(block *model.Block) {
377372
// (weighted by stake) in the network, breaking the safety guarantees of HotStuff (or there
378373
// is a critical bug / data corruption). Forks cannot recover from this exception.
379374
// - generic error in case of unexpected bug or internal state corruption
380-
func (f *Forks2) checkForAdvancingFinalization(certifiedBlock *model.CertifiedBlock) error {
375+
func (f *Forks) checkForAdvancingFinalization(certifiedBlock *model.CertifiedBlock) error {
381376
// We prune all blocks in forest which are below the most recently finalized block.
382377
// Hence, we have a pruned ancestry if and only if either of the following conditions applies:
383378
// (a) If a block's parent view (i.e. block.QC.View) is below the most recently finalized block.
@@ -463,7 +458,7 @@ func (f *Forks2) checkForAdvancingFinalization(certifiedBlock *model.CertifiedBl
463458
// (weighted by stake) in the network, breaking the safety guarantees of HotStuff (or there
464459
// is a critical bug / data corruption). Forks cannot recover from this exception.
465460
// - generic error in case of bug or internal state corruption
466-
func (f *Forks2) collectBlocksForFinalization(qc *flow.QuorumCertificate) ([]*model.Block, error) {
461+
func (f *Forks) collectBlocksForFinalization(qc *flow.QuorumCertificate) ([]*model.Block, error) {
467462
lastFinalized := f.FinalizedBlock()
468463
if qc.View < lastFinalized.View {
469464
return nil, model.ByzantineThresholdExceededError{Evidence: fmt.Sprintf(

0 commit comments

Comments
 (0)