Skip to content

Commit 1306e52

Browse files
bors[bot]Alexander Hentschel
andauthored
Merge #4190
4190: Alex/use qc of uncertified block optimization r=AlexHentschel a=AlexHentschel Implements part 2 of #4154 > 2. Forks can ingest `Proposals` as well as `CertifiedBlock`s. The finality logic in Forks accounts for the certifying QC. ## Approach taken in this PR * I added a revised implementation of Forks, which I called `Forks2` * `Forks2` is not yet used by any business logic (will be done in subsequent PR) * extended tests to cover logic for adding `CertifiedBlock`s * the old `Forks` and its unit tests remain in the code base, as they are still used * to avoid conflicts, I have moved the tests into the testing package `forks_test` * both `Forks` and its unit tests will be removed in subsequent PR Co-authored-by: Alexander Hentschel <[email protected]>
2 parents 747b575 + b2f43b7 commit 1306e52

File tree

14 files changed

+1581
-81
lines changed

14 files changed

+1581
-81
lines changed

consensus/hotstuff/forks/blockQC.go

Lines changed: 0 additions & 1 deletion
This file was deleted.

consensus/hotstuff/forks/block_builder_test.go

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -42,51 +42,54 @@ func NewBlockBuilder() *BlockBuilder {
4242
}
4343
}
4444

45-
// Add adds a block with the given qcView and blockView.
46-
func (f *BlockBuilder) Add(qcView uint64, blockView uint64) {
47-
f.blockViews = append(f.blockViews, &BlockView{
45+
// Add adds a block with the given qcView and blockView. Returns self-reference for chaining.
46+
func (bb *BlockBuilder) Add(qcView uint64, blockView uint64) *BlockBuilder {
47+
bb.blockViews = append(bb.blockViews, &BlockView{
4848
View: blockView,
4949
QCView: qcView,
5050
})
51+
return bb
5152
}
5253

5354
// GenesisBlock returns the genesis block, which is always finalized.
54-
func (f *BlockBuilder) GenesisBlock() *model.Block {
55-
return makeGenesis().Block
55+
func (bb *BlockBuilder) GenesisBlock() *model.CertifiedBlock {
56+
return makeGenesis()
5657
}
5758

5859
// AddVersioned adds a block with the given qcView and blockView.
59-
// In addition the version identifier of the QC embedded within the block
60+
// In addition, the version identifier of the QC embedded within the block
6061
// is specified by `qcVersion`. The version identifier for the block itself
6162
// (primarily for emulating different payloads) is specified by `blockVersion`.
62-
// [3,4] denotes a block of view 4, with a qc of view 3
63-
// [3,4'] denotes a block of view 4, with a qc of view 3, but has a different BlockID than [3,4]
64-
// [3,4'] can be created by AddVersioned(3, 4, 0, 1)
65-
// [3',4] can be created by AddVersioned(3, 4, 1, 0)
66-
func (f *BlockBuilder) AddVersioned(qcView uint64, blockView uint64, qcVersion int, blockVersion int) {
67-
f.blockViews = append(f.blockViews, &BlockView{
63+
// [(◄3) 4] denotes a block of view 4, with a qc for view 3
64+
// [(◄3) 4'] denotes a block of view 4 that is different than [(◄3) 4], with a qc for view 3
65+
// [(◄3) 4'] can be created by AddVersioned(3, 4, 0, 1)
66+
// [(◄3') 4] can be created by AddVersioned(3, 4, 1, 0)
67+
// Returns self-reference for chaining.
68+
func (bb *BlockBuilder) AddVersioned(qcView uint64, blockView uint64, qcVersion int, blockVersion int) *BlockBuilder {
69+
bb.blockViews = append(bb.blockViews, &BlockView{
6870
View: blockView,
6971
QCView: qcView,
7072
BlockVersion: blockVersion,
7173
QCVersion: qcVersion,
7274
})
75+
return bb
7376
}
7477

7578
// Blocks returns a list of all blocks added to the BlockBuilder.
7679
// Returns an error if the blocks do not form a connected tree rooted at genesis.
77-
func (f *BlockBuilder) Blocks() ([]*model.Proposal, error) {
78-
blocks := make([]*model.Proposal, 0, len(f.blockViews))
80+
func (bb *BlockBuilder) Blocks() ([]*model.Proposal, error) {
81+
blocks := make([]*model.Proposal, 0, len(bb.blockViews))
7982

80-
genesisBQ := makeGenesis()
83+
genesisBlock := makeGenesis()
8184
genesisBV := &BlockView{
82-
View: genesisBQ.Block.View,
83-
QCView: genesisBQ.QC.View,
85+
View: genesisBlock.Block.View,
86+
QCView: genesisBlock.CertifyingQC.View,
8487
}
8588

8689
qcs := make(map[string]*flow.QuorumCertificate)
87-
qcs[genesisBV.QCIndex()] = genesisBQ.QC
90+
qcs[genesisBV.QCIndex()] = genesisBlock.CertifyingQC
8891

89-
for _, bv := range f.blockViews {
92+
for _, bv := range bb.blockViews {
9093
qc, ok := qcs[bv.QCIndex()]
9194
if !ok {
9295
return nil, fmt.Errorf("test fail: no qc found for qc index: %v", bv.QCIndex())
@@ -145,6 +148,7 @@ func makeBlockID(block *model.Block) flow.Identifier {
145148
})
146149
}
147150

151+
// constructs the genesis block (identical for all calls)
148152
func makeGenesis() *model.CertifiedBlock {
149153
genesis := &model.Block{
150154
View: 1,

consensus/hotstuff/forks/blockcontainer.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,17 @@ func (b *BlockContainer) Level() uint64 { return b.Proposal.Block.Vi
2121
func (b *BlockContainer) Parent() (flow.Identifier, uint64) {
2222
return b.Proposal.Block.QC.BlockID, b.Proposal.Block.QC.View
2323
}
24+
25+
// BlockContainer wraps a block proposal to implement forest.Vertex
26+
// so the proposal can be stored in forest.LevelledForest
27+
type BlockContainer2 model.Block
28+
29+
var _ forest.Vertex = (*BlockContainer2)(nil)
30+
31+
func ToBlockContainer2(block *model.Block) *BlockContainer2 { return (*BlockContainer2)(block) }
32+
func (b *BlockContainer2) Block() *model.Block { return (*model.Block)(b) }
33+
34+
// Functions implementing forest.Vertex
35+
func (b *BlockContainer2) VertexID() flow.Identifier { return b.BlockID }
36+
func (b *BlockContainer2) Level() uint64 { return b.View }
37+
func (b *BlockContainer2) Parent() (flow.Identifier, uint64) { return b.QC.BlockID, b.QC.View }

consensus/hotstuff/forks/forks.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ type Forks struct {
4747
var _ hotstuff.Forks = (*Forks)(nil)
4848

4949
func New(trustedRoot *model.CertifiedBlock, finalizationCallback module.Finalizer, notifier hotstuff.FinalizationConsumer) (*Forks, error) {
50-
if (trustedRoot.Block.BlockID != trustedRoot.QC.BlockID) || (trustedRoot.Block.View != trustedRoot.QC.View) {
50+
if (trustedRoot.Block.BlockID != trustedRoot.CertifyingQC.BlockID) || (trustedRoot.Block.View != trustedRoot.CertifyingQC.View) {
5151
return nil, model.NewConfigurationErrorf("invalid root: root QC is not pointing to root block")
5252
}
5353

@@ -307,7 +307,7 @@ func (f *Forks) updateFinalizedBlockQC(blockContainer *BlockContainer) error {
307307
if ancestryChain.oneChain.Block.View != b.Block.View+1 {
308308
return nil
309309
}
310-
return f.finalizeUpToBlock(b.QC)
310+
return f.finalizeUpToBlock(b.CertifyingQC)
311311
}
312312

313313
// getTwoChain returns the 2-chain for the input block container b.

0 commit comments

Comments
 (0)