Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Consensus] Approval Processing Core -> Sealing Core #736

Merged
merged 84 commits into from
Jun 4, 2021
Merged
Show file tree
Hide file tree
Changes from 56 commits
Commits
Show all changes
84 commits
Select commit Hold shift + click to select a range
40dc39a
Added basic engine implementation for approvals engine
durkmurder May 17, 2021
6c16fef
Updated test conditions
durkmurder May 18, 2021
19b60c5
Replacing sealing core with new implementation
durkmurder May 18, 2021
442a1ec
Fixed approval processing tests. Partially fixed old tests
durkmurder May 18, 2021
9e1c565
Removed receipt processing from sealing engine
durkmurder May 19, 2021
93e9355
Updated initialization
durkmurder May 19, 2021
d5839db
Updated tests
durkmurder May 19, 2021
ff3105a
Updated tests. Cleanup
durkmurder May 19, 2021
c80cfa6
Merge branch 'master' of https://github.com/onflow/flow-go into yurii…
durkmurder May 19, 2021
a3bf7b9
Refactored of consensus engines. Added skeleton for matching engine
durkmurder May 19, 2021
7039b25
Added logs. Updated godoc
durkmurder May 19, 2021
ea9b290
Implemented matching engine and core
durkmurder May 20, 2021
4a0d08f
Updated defualt config
durkmurder May 20, 2021
881adff
Removed modules that aren't used anymore
durkmurder May 20, 2021
4d12dd0
Added matching engine tests. Updated mocks. Tests refactoring
durkmurder May 20, 2021
87cfd3b
Added finalization distributor for consensus node engines. Updated te…
durkmurder May 20, 2021
397ffe3
Merge branch 'master' of https://github.com/onflow/flow-go into yurii…
durkmurder May 20, 2021
003f921
Fixed tests. Removed leftovers
durkmurder May 20, 2021
0a5a7c5
Linted
durkmurder May 20, 2021
c4c43d3
Removed more legacy files
durkmurder May 20, 2021
b799719
• separated Notifier as a separate component from MessageHandler;
May 21, 2021
cab8ce5
consistent naming for callback `OnFinalizedBlock`
May 21, 2021
e8bbea8
• also named implementation of callback `OnFinalizedBlock` accordingl…
May 21, 2021
58fcbfa
minor code-compactification
May 21, 2021
747ef63
• cleanup of all mentions of ResultApprovalProcessor (as it was previ…
May 21, 2021
f18aee1
micro godoc revision
May 21, 2021
1e579e5
extended goDoc
May 21, 2021
a7ca45d
removed field `requiredApprovalsForSealConstruction` from `ApprovalCo…
May 21, 2021
ab0ebbe
Merge pull request #740 from onflow/alex/5417-approval-processing-eng…
durkmurder May 21, 2021
04ba8dc
Apply suggestions from PR
durkmurder May 21, 2021
65a1d36
Added back sealing tracker
durkmurder May 21, 2021
688a1bf
Added tracker of sealing state when requesting missing approvals
durkmurder May 21, 2021
b9024c7
Fixed sealing engine initialization
durkmurder May 21, 2021
a1eb253
Fixed unittests
durkmurder May 21, 2021
d828bc8
Updated tracing for matching & sealing engines
durkmurder May 21, 2021
9ccd70e
Updated how results are feed to sealing engine. Updated hotstuff even…
durkmurder May 21, 2021
691e1cd
Updated sealing engine with new implementation of message handler
durkmurder May 21, 2021
056eddd
Updated godoc
durkmurder May 21, 2021
a1208aa
Added workaround for handling genesis block. Updated tests
durkmurder May 21, 2021
e929872
Apply suggestions from PR comments
durkmurder May 24, 2021
c619f79
Added logic for repopulating collectors tree. Added tests
durkmurder May 25, 2021
21eaaf7
Apply suggestions from PR review
durkmurder May 26, 2021
4796d6f
Implemented monotonous counter for sealing.Core. Replaced atomic oper…
durkmurder May 26, 2021
23019b0
Update core.go
durkmurder May 26, 2021
71b6ea4
Updated assignment collector tree to finalize forks over multiple blocks
durkmurder May 26, 2021
715005c
Merge branch 'yurii/5417-approval-processing-engine' of https://githu…
durkmurder May 26, 2021
4abd541
Updated how processable incorporated results are handled
durkmurder May 26, 2021
dae4cc7
Apply suggestions from PR review
durkmurder May 27, 2021
5f0e650
Merge branch 'master' of https://github.com/onflow/flow-go into yurii…
durkmurder May 31, 2021
f087e3d
Merge branch 'yurii/5417-approval-processing-engine' of https://githu…
durkmurder May 31, 2021
0320624
Implemented traversing of valid descendants when repopulating results…
durkmurder May 31, 2021
3eb8166
updated goDoc of notifier.
May 31, 2021
63d0eac
moved `SignatureCollector` from package flow to package `approvals`
May 31, 2021
49d3c2f
updated imports for tests after moving SignatureCollector
May 31, 2021
dc31871
removed originID from matching.Core.ProcessReceipt
Jun 1, 2021
275f047
minor revision of sealing.Core
Jun 1, 2021
b62f6fd
Merge pull request #769 from onflow/alex/5417-approval-processing-eng…
durkmurder Jun 1, 2021
db2bb4e
Merge branch 'yurii/5417-approval-processing-engine' of https://githu…
durkmurder Jun 1, 2021
64aae7f
Fixed tests
durkmurder Jun 1, 2021
997b9ff
Merge branch 'yurii/5417-approval-processing-engine' of https://githu…
durkmurder Jun 1, 2021
7e5f2ed
Added back check for originID
durkmurder Jun 1, 2021
d6a3f7e
Merge branch 'yurii/5417-approval-processing-engine' of https://githu…
durkmurder Jun 1, 2021
684d630
Apply comments from PR review
durkmurder Jun 1, 2021
ccba22c
• minor goDoc revisions
Jun 1, 2021
bc3e532
• minor revisions for code comments
Jun 2, 2021
40edcae
AssignmentCollector now checks _first_ the cache before doing expensi…
Jun 2, 2021
ccb19d3
• ApprovalCollector: added logic for sealing right away if no approva…
Jun 2, 2021
2d5f120
Merge pull request #774 from onflow/alex/5417-approval-processing-eng…
durkmurder Jun 2, 2021
b6066d2
Added extra logs
durkmurder Jun 2, 2021
4f0ee34
Merge branch 'yurii/5417-approval-processing-engine' of https://githu…
durkmurder Jun 2, 2021
8b26d8e
Merge branch 'master' of https://github.com/onflow/flow-go into yurii…
durkmurder Jun 2, 2021
db2a08c
Updated logs
durkmurder Jun 2, 2021
5f9808e
Merge branch 'yurii/5417-approval-processing-engine' of https://githu…
durkmurder Jun 2, 2021
102d919
attempt 1 to fix test
Jun 3, 2021
0c3bf01
updated integration test to only seal if two receipts are known
Jun 3, 2021
0c808a5
updated imports
Jun 3, 2021
c5a6b09
removed sleep in test to see, if waiting for two receipts before seal…
Jun 3, 2021
1a7da01
Merge pull request #780 from onflow/alex/attempting_integration_test_fix
durkmurder Jun 3, 2021
7efd30b
Apply suggestions from code review
durkmurder Jun 3, 2021
e39ec83
Merge pull request #765 from onflow/yurii/5216-repopulate-assignment-…
durkmurder Jun 3, 2021
1c8a645
Linted. Added check for 2 receipts before sealing
durkmurder Jun 3, 2021
64914fa
Added fallback solution for sealing recovery. Updated tests
durkmurder Jun 4, 2021
498c741
Merge branch 'master' of https://github.com/onflow/flow-go into yurii…
durkmurder Jun 4, 2021
70cd038
Updated godoc
durkmurder Jun 4, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ generate-mocks:
GO111MODULE=on mockery -name '.*' -dir="state/protocol/events" -case=underscore -output="./state/protocol/events/mock" -outpkg="mock"
GO111MODULE=on mockery -name '.*' -dir=engine/execution/computation/computer -case=underscore -output="./engine/execution/computation/computer/mock" -outpkg="mock"
GO111MODULE=on mockery -name '.*' -dir=engine/execution/state -case=underscore -output="./engine/execution/state/mock" -outpkg="mock"
GO111MODULE=on mockery -name '.*' -dir=engine/consensus -case=underscore -output="./engine/consensus/mock" -outpkg="mock"
GO111MODULE=on mockery -name '.*' -dir=fvm -case=underscore -output="./fvm/mock" -outpkg="mock"
GO111MODULE=on mockery -name '.*' -dir=fvm/state -case=underscore -output="./fvm/mock/state" -outpkg="mock"
GO111MODULE=on mockery -name '.*' -dir=ledger -case=underscore -output="./ledger/mock" -outpkg="mock"
Expand Down
126 changes: 78 additions & 48 deletions cmd/consensus/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/onflow/flow-go/consensus/hotstuff"
"github.com/onflow/flow-go/consensus/hotstuff/blockproducer"
"github.com/onflow/flow-go/consensus/hotstuff/committees"
"github.com/onflow/flow-go/consensus/hotstuff/notifications/pubsub"
"github.com/onflow/flow-go/consensus/hotstuff/pacemaker/timeout"
"github.com/onflow/flow-go/consensus/hotstuff/persister"
"github.com/onflow/flow-go/consensus/hotstuff/verification"
Expand All @@ -24,6 +25,7 @@ import (
synceng "github.com/onflow/flow-go/engine/common/synchronization"
"github.com/onflow/flow-go/engine/consensus/compliance"
"github.com/onflow/flow-go/engine/consensus/ingestion"
"github.com/onflow/flow-go/engine/consensus/matching"
"github.com/onflow/flow-go/engine/consensus/provider"
"github.com/onflow/flow-go/engine/consensus/sealing"
"github.com/onflow/flow-go/model/bootstrap"
Expand Down Expand Up @@ -73,24 +75,22 @@ func main() {
requiredApprovalsForSealConstruction uint
emergencySealing bool

err error
mutableState protocol.MutableState
privateDKGData *bootstrap.DKGParticipantPriv
guarantees mempool.Guarantees
results mempool.IncorporatedResults
receipts mempool.ExecutionTree
approvals mempool.Approvals
seals mempool.IncorporatedResultSeals
pendingReceipts mempool.PendingReceipts
prov *provider.Engine
receiptRequester *requester.Engine
syncCore *synchronization.Core
comp *compliance.Engine
conMetrics module.ConsensusMetrics
mainMetrics module.HotstuffMetrics
receiptValidator module.ReceiptValidator
approvalValidator module.ApprovalValidator
chunkAssigner *chmodule.ChunkAssigner
err error
mutableState protocol.MutableState
privateDKGData *bootstrap.DKGParticipantPriv
guarantees mempool.Guarantees
receipts mempool.ExecutionTree
seals mempool.IncorporatedResultSeals
pendingReceipts mempool.PendingReceipts
prov *provider.Engine
receiptRequester *requester.Engine
syncCore *synchronization.Core
comp *compliance.Engine
conMetrics module.ConsensusMetrics
mainMetrics module.HotstuffMetrics
receiptValidator module.ReceiptValidator
chunkAssigner *chmodule.ChunkAssigner
finalizationDistributor *pubsub.FinalizationDistributor
)

cmd.FlowNode(flow.RoleConsensus.String()).
Expand Down Expand Up @@ -150,10 +150,6 @@ func main() {

resultApprovalSigVerifier := signature.NewAggregationVerifier(encoding.ResultApprovalTag)

approvalValidator = validation.NewApprovalValidator(
node.State,
resultApprovalSigVerifier)

sealValidator := validation.NewSealValidator(
node.State,
node.Storage.Headers,
Expand Down Expand Up @@ -183,10 +179,6 @@ func main() {
guarantees, err = stdmap.NewGuarantees(guaranteeLimit)
return err
}).
Module("execution results mempool", func(node *cmd.FlowNodeBuilder) error {
results, err = stdmap.NewIncorporatedResults(resultLimit)
return err
}).
Module("execution receipts mempool", func(node *cmd.FlowNodeBuilder) error {
receipts = consensusMempools.NewExecutionTree()
// registers size method of backend for metrics
Expand All @@ -196,10 +188,6 @@ func main() {
}
return nil
}).
Module("result approvals mempool", func(node *cmd.FlowNodeBuilder) error {
approvals, err = stdmap.NewApprovals(approvalLimit)
return err
}).
Module("block seals mempool", func(node *cmd.FlowNodeBuilder) error {
// use a custom ejector so we don't eject seals that would break
// the chain of seals
Expand All @@ -223,8 +211,43 @@ func main() {
syncCore, err = synchronization.New(node.Logger, synchronization.DefaultConfig())
return err
}).
Module("finalization distributor", func(node *cmd.FlowNodeBuilder) error {
finalizationDistributor = pubsub.NewFinalizationDistributor()
return nil
}).
Component("sealing engine", func(node *cmd.FlowNodeBuilder) (module.ReadyDoneAware, error) {

resultApprovalSigVerifier := signature.NewAggregationVerifier(encoding.ResultApprovalTag)

config := sealing.DefaultConfig()
config.EmergencySealingActive = emergencySealing
config.RequiredApprovalsForSealConstruction = requiredApprovalsForSealConstruction

e, err := sealing.NewEngine(
node.Logger,
node.Tracer,
conMetrics,
node.Metrics.Engine,
node.Metrics.Mempool,
node.Network,
node.Me,
node.Storage.Headers,
node.Storage.Payloads,
node.State,
node.Storage.Seals,
chunkAssigner,
resultApprovalSigVerifier,
seals,
config,
)

// subscribe for finalization events from hotstuff
finalizationDistributor.AddOnBlockFinalizedConsumer(e.OnFinalizedBlock)
finalizationDistributor.AddOnBlockIncorporatedConsumer(e.OnBlockIncorporated)

return e, err
}).
Component("matching engine", func(node *cmd.FlowNodeBuilder) (module.ReadyDoneAware, error) {
receiptRequester, err = requester.New(
node.Logger,
node.Metrics.Engine,
Expand All @@ -241,34 +264,39 @@ func main() {
return nil, err
}

match, err := sealing.NewEngine(
core := matching.NewCore(
node.Logger,
node.Metrics.Engine,
node.Tracer,
node.Metrics.Mempool,
conMetrics,
node.Network,
node.Metrics.Mempool,
node.State,
node.Me,
receiptRequester,
node.Storage.Receipts,
node.Storage.Headers,
node.Storage.Index,
results,
node.Storage.Receipts,
receipts,
approvals,
seals,
pendingReceipts,
chunkAssigner,
seals,
receiptValidator,
approvalValidator,
requiredApprovalsForSealConstruction,
emergencySealing,
receiptRequester,
matching.DefaultConfig(),
)

receiptRequester.WithHandle(match.HandleReceipt)
e, err := matching.NewEngine(
node.Logger,
node.Network,
node.Me,
node.Metrics.Engine,
node.Metrics.Mempool,
core,
)
if err != nil {
return nil, err
}

return match, err
// subscribe engine to inputs from other node-internal components
receiptRequester.WithHandle(e.HandleReceipt)
finalizationDistributor.AddOnBlockFinalizedConsumer(e.OnFinalizedBlock)

return e, err
}).
Component("provider engine", func(node *cmd.FlowNodeBuilder) (module.ReadyDoneAware, error) {
prov, err = provider.New(
Expand Down Expand Up @@ -404,7 +432,9 @@ func main() {
node.Storage.Index,
node.RootChainID,
)
// make compliance engine as a FinalizationConsumer

notifier.AddConsumer(finalizationDistributor)

// initialize the persister
persist := persister.New(node.DB, node.RootChainID)

Expand Down
3 changes: 1 addition & 2 deletions cmd/consensus/notifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package main
import (
"github.com/rs/zerolog"

"github.com/onflow/flow-go/consensus/hotstuff"
"github.com/onflow/flow-go/consensus/hotstuff/notifications"
"github.com/onflow/flow-go/consensus/hotstuff/notifications/pubsub"
"github.com/onflow/flow-go/model/flow"
Expand All @@ -13,7 +12,7 @@ import (
)

func createNotifier(log zerolog.Logger, metrics module.HotstuffMetrics, tracer module.Tracer, index storage.Index, chain flow.ChainID,
) hotstuff.Consumer {
) *pubsub.Distributor {
telemetryConsumer := notifications.NewTelemetryConsumer(log, chain)
tracingConsumer := notifications.NewConsensusTracingConsumer(log, tracer, index)
metricsConsumer := metricsconsumer.NewMetricsConsumer(metrics)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package pubsub

import (
"sync"

"github.com/onflow/flow-go/consensus/hotstuff/model"
"github.com/onflow/flow-go/model/flow"
)

type OnBlockFinalizedConsumer = func(finalizedBlockID flow.Identifier)
type OnBlockIncorporatedConsumer = func(incorporatedBlockID flow.Identifier)

// FinalizationDistributor subscribes for finalization events from hotstuff and distributes it to subscribers
type FinalizationDistributor struct {
blockFinalizedConsumers []OnBlockFinalizedConsumer
blockIncorporatedConsumers []OnBlockIncorporatedConsumer
lock sync.RWMutex
}

func NewFinalizationDistributor() *FinalizationDistributor {
return &FinalizationDistributor{
blockFinalizedConsumers: make([]OnBlockFinalizedConsumer, 0),
blockIncorporatedConsumers: make([]OnBlockIncorporatedConsumer, 0),
lock: sync.RWMutex{},
}
}

func (p *FinalizationDistributor) AddOnBlockFinalizedConsumer(consumer OnBlockFinalizedConsumer) {
p.lock.Lock()
defer p.lock.Unlock()
p.blockFinalizedConsumers = append(p.blockFinalizedConsumers, consumer)
}
func (p *FinalizationDistributor) AddOnBlockIncorporatedConsumer(consumer OnBlockIncorporatedConsumer) {
p.lock.Lock()
defer p.lock.Unlock()
p.blockIncorporatedConsumers = append(p.blockIncorporatedConsumers, consumer)
}

func (p *FinalizationDistributor) OnEventProcessed() {}

func (p *FinalizationDistributor) OnBlockIncorporated(block *model.Block) {
p.lock.RLock()
defer p.lock.RUnlock()
for _, consumer := range p.blockIncorporatedConsumers {
consumer(block.BlockID)
}
}

func (p *FinalizationDistributor) OnFinalizedBlock(block *model.Block) {
p.lock.RLock()
defer p.lock.RUnlock()
for _, consumer := range p.blockFinalizedConsumers {
consumer(block.BlockID)
}
}

func (p *FinalizationDistributor) OnDoubleProposeDetected(*model.Block, *model.Block) {}

func (p *FinalizationDistributor) OnReceiveVote(uint64, *model.Vote) {}

func (p *FinalizationDistributor) OnReceiveProposal(uint64, *model.Proposal) {}

func (p *FinalizationDistributor) OnEnteringView(uint64, flow.Identifier) {}

func (p *FinalizationDistributor) OnQcTriggeredViewChange(*flow.QuorumCertificate, uint64) {}

func (p *FinalizationDistributor) OnProposingBlock(*model.Proposal) {}

func (p *FinalizationDistributor) OnVoting(*model.Vote) {}

func (p *FinalizationDistributor) OnQcConstructedFromVotes(*flow.QuorumCertificate) {}

func (p *FinalizationDistributor) OnStartingTimeout(*model.TimerInfo) {}

func (p *FinalizationDistributor) OnReachedTimeout(*model.TimerInfo) {}

func (p *FinalizationDistributor) OnQcIncorporated(*flow.QuorumCertificate) {}

func (p *FinalizationDistributor) OnForkChoiceGenerated(uint64, *flow.QuorumCertificate) {}

func (p *FinalizationDistributor) OnDoubleVotingDetected(*model.Vote, *model.Vote) {}

func (p *FinalizationDistributor) OnInvalidVoteDetected(*model.Vote) {}
26 changes: 12 additions & 14 deletions engine/consensus/approvals/approval_collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,12 @@ import (
// collecting aggregated signatures for chunks that reached seal construction threshold,
// creating and submitting seal candidates once signatures for every chunk are aggregated.
type ApprovalCollector struct {
incorporatedBlock *flow.Header // block that incorporates execution result
incorporatedResult *flow.IncorporatedResult // incorporated result that is being sealed
chunkCollectors []*ChunkApprovalCollector // slice of chunk collectorTree that is created on construction and doesn't change
aggregatedSignatures *AggregatedSignatures // aggregated signature for each chunk
seals mempool.IncorporatedResultSeals // holds candidate seals for incorporated results that have acquired sufficient approvals; candidate seals are constructed without consideration of the sealability of parent results
numberOfChunks int // number of chunks for execution result, remains constant
requiredApprovalsForSealConstruction uint // min number of approvals required for constructing a candidate seal
incorporatedBlock *flow.Header // block that incorporates execution result
incorporatedResult *flow.IncorporatedResult // incorporated result that is being sealed
chunkCollectors []*ChunkApprovalCollector // slice of chunk collectorTree that is created on construction and doesn't change
aggregatedSignatures *AggregatedSignatures // aggregated signature for each chunk
seals mempool.IncorporatedResultSeals // holds candidate seals for incorporated results that have acquired sufficient approvals; candidate seals are constructed without consideration of the sealability of parent results
numberOfChunks int // number of chunks for execution result, remains constant
}

func NewApprovalCollector(result *flow.IncorporatedResult, incorporatedBlock *flow.Header, assignment *chunks.Assignment, seals mempool.IncorporatedResultSeals, requiredApprovalsForSealConstruction uint) *ApprovalCollector {
Expand All @@ -32,13 +31,12 @@ func NewApprovalCollector(result *flow.IncorporatedResult, incorporatedBlock *fl

numberOfChunks := result.Result.Chunks.Len()
return &ApprovalCollector{
incorporatedResult: result,
incorporatedBlock: incorporatedBlock,
numberOfChunks: numberOfChunks,
chunkCollectors: chunkCollectors,
requiredApprovalsForSealConstruction: requiredApprovalsForSealConstruction,
aggregatedSignatures: NewAggregatedSignatures(uint64(numberOfChunks)),
seals: seals,
incorporatedResult: result,
incorporatedBlock: incorporatedBlock,
numberOfChunks: numberOfChunks,
chunkCollectors: chunkCollectors,
aggregatedSignatures: NewAggregatedSignatures(uint64(numberOfChunks)),
seals: seals,
}
Copy link
Member

@AlexHentschel AlexHentschel Jun 2, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am wondering how this code will behave, when requiredApprovalsForSealConstruction = 0. In this case, sealing should proceed, even if all verifiers are offline.

My theory on how the current implementation will behave is:

  • the only code paths reaching ApprovalCollector.SealResult() are:

    • emergency sealing
      func (ac *AssignmentCollector) CheckEmergencySealing(finalizedBlockHeight uint64) error {
      for _, collector := range ac.allCollectors() {
      sealable := ac.emergencySealable(collector, finalizedBlockHeight)
      if sealable {
      err := collector.SealResult()
    • processing an approval
      func (c *ApprovalCollector) ProcessApproval(approval *flow.ResultApproval) error {
      chunkIndex := approval.Body.ChunkIndex
      if chunkIndex >= uint64(len(c.chunkCollectors)) {
      return engine.NewInvalidInputErrorf("approval collector chunk index out of range: %v", chunkIndex)
      }
      // there is no need to process approval if we have already enough info for sealing
      if c.aggregatedSignatures.HasSignature(chunkIndex) {
      return nil
      }
      collector := c.chunkCollectors[chunkIndex]
      aggregatedSignature, collected := collector.ProcessApproval(approval)
      if !collected {
      return nil
      }
      approvedChunks := c.aggregatedSignatures.PutSignature(chunkIndex, aggregatedSignature)
      if approvedChunks < c.numberOfChunks {
      return nil // still missing approvals for some chunks
      }
      return c.SealResult()
  • Hence, if all verifiers are offline, we will not generate seals until the result is emergency sealed, even if requiredApprovalsForSealConstruction = 0.

I think the better behaviour would be produce a candidate seal right away, as soon as we construct the ApprovalCollector

This is already implemented in PR #774

}

Expand Down
10 changes: 8 additions & 2 deletions engine/consensus/approvals/approval_collector_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,17 @@ func (s *ApprovalCollectorTestSuite) TestProcessApproval_ValidApproval() {
// met for each chunk.
func (s *ApprovalCollectorTestSuite) TestProcessApproval_SealResult() {
expectedSignatures := make([]flow.AggregatedSignature, s.IncorporatedResult.Result.Chunks.Len())
s.sealsPL.On("Add", mock.Anything).Return(true, nil).Once()
s.sealsPL.On("Add", mock.Anything).Run(
func(args mock.Arguments) {
seal := args.Get(0).(*flow.IncorporatedResultSeal)
require.Equal(s.T(), s.Block.ID(), seal.Seal.BlockID)
require.Equal(s.T(), s.IncorporatedResult.Result.ID(), seal.Seal.ResultID)
},
).Return(true, nil).Once()

for i, chunk := range s.Chunks {
var err error
sigCollector := flow.NewSignatureCollector()
sigCollector := NewSignatureCollector()
for verID := range s.AuthorizedVerifiers {
approval := unittest.ResultApprovalFixture(unittest.WithChunk(chunk.Index), unittest.WithApproverID(verID))
err = s.collector.ProcessApproval(approval)
Expand Down
Loading