Skip to content

Commit 2688450

Browse files
authored
Merge pull request #8186 from onflow/leo/optimize-collection-index-metrics
Optimize CollectionFinalized with BlockIDByCollectionID
2 parents 1f65016 + 13fc578 commit 2688450

File tree

4 files changed

+70
-5
lines changed

4 files changed

+70
-5
lines changed

module/state_synchronization/indexer/collection_executed_metric.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,11 @@ func (c *CollectionExecutedMetricImpl) CollectionFinalized(light *flow.LightColl
5858
lightID := light.ID()
5959
if ti, found := c.collectionsToMarkFinalized.Get(lightID); found {
6060

61-
block, err := c.blocks.ByCollectionID(lightID)
61+
blockID, err := c.blocks.BlockIDByCollectionID(lightID)
6262
if err != nil {
6363
c.log.Warn().Err(err).Msg("could not find block by collection ID")
6464
return
6565
}
66-
blockID := block.ID()
6766

6867
for _, t := range light.Transactions {
6968
c.accessMetrics.TransactionFinalized(t, ti)

storage/blocks.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,20 @@ type Blocks interface {
9292
// to decode an existing database value
9393
ByCollectionID(collID flow.Identifier) (*flow.Block, error)
9494

95+
// BlockIDByCollectionID returns the block ID for the finalized block which includes the guarantee for the given collection
96+
// (the collection guarantee such that `CollectionGuarantee.CollectionID == collID`).
97+
// NOTE: This method is only available for collections included in finalized blocks.
98+
// While consensus nodes verify that collections are not repeated within the same fork,
99+
// each different fork can contain a recent collection once. Therefore, we must wait for
100+
// finality.
101+
// CAUTION: this method is not backed by a cache and therefore comparatively slow!
102+
//
103+
// Error returns:
104+
// - storage.ErrNotFound if no FINALIZED block exists containing the expected collection guarantee
105+
// - generic error in case of unexpected failure from the database layer, or failure
106+
// to decode an existing database value
107+
BlockIDByCollectionID(collID flow.Identifier) (flow.Identifier, error)
108+
95109
// BatchIndexBlockContainingCollectionGuarantees produces mappings from the IDs of [flow.CollectionGuarantee]s to the block ID containing these guarantees.
96110
// The caller must acquire [storage.LockIndexBlockByPayloadGuarantees] and hold it until the database write has been committed.
97111
//

storage/mock/blocks.go

Lines changed: 30 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

storage/store/blocks.go

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -209,21 +209,43 @@ func (b *Blocks) ProposalByHeight(height uint64) (*flow.Proposal, error) {
209209
// - generic error in case of unexpected failure from the database layer, or failure
210210
// to decode an existing database value
211211
func (b *Blocks) ByCollectionID(collID flow.Identifier) (*flow.Block, error) {
212+
blockID, err := b.BlockIDByCollectionID(collID)
213+
if err != nil {
214+
return nil, err
215+
}
216+
return b.ByID(blockID)
217+
}
218+
219+
// BlockIDByCollectionID returns the block ID for the finalized block which includes the guarantee for the
220+
// given collection (the collection guarantee such that `CollectionGuarantee.CollectionID == collID`).
221+
// This function returns the finalized _consensus_ block including the specified collection, not the cluster
222+
// block which defines the collection.
223+
// NOTE: This method is only available for collections included in finalized blocks.
224+
// While consensus nodes verify that collections are not repeated within the same fork,
225+
// each different fork can contain a recent collection once. Therefore, we must wait for
226+
// finality.
227+
// CAUTION: this method is not backed by a cache and therefore comparatively slow!
228+
//
229+
// Error returns:
230+
// - storage.ErrNotFound if no FINALIZED block exists containing the expected collection guarantee
231+
// - generic error in case of unexpected failure from the database layer, or failure
232+
// to decode an existing database value
233+
func (b *Blocks) BlockIDByCollectionID(collID flow.Identifier) (flow.Identifier, error) {
212234
guarantee, err := b.payloads.guarantees.ByCollectionID(collID)
213235
if err != nil {
214-
return nil, fmt.Errorf("could not look up guarantee: %w", err)
236+
return flow.ZeroID, fmt.Errorf("could not look up guarantee: %w", err)
215237
}
216238
var blockID flow.Identifier
217239
err = operation.LookupBlockContainingCollectionGuarantee(b.db.Reader(), guarantee.ID(), &blockID)
218240
if err != nil {
219-
return nil, fmt.Errorf("could not look up block: %w", err)
241+
return flow.ZeroID, fmt.Errorf("could not look up block: %w", err)
220242
}
221243
// CAUTION: a collection can be included in multiple *unfinalized* blocks. However, the implementation
222244
// assumes a one-to-one map from collection ID to a *single* block ID. This holds for FINALIZED BLOCKS ONLY
223245
// *and* only in the absence of byzantine collector clusters (which the mature protocol must tolerate).
224246
// Hence, this function should be treated as a temporary solution, which requires generalization
225247
// (one-to-many mapping) for soft finality and the mature protocol.
226-
return b.ByID(blockID)
248+
return blockID, nil
227249
}
228250

229251
// BatchIndexBlockContainingCollectionGuarantees produces mappings from the IDs of [flow.CollectionGuarantee]s to the block ID containing these guarantees.

0 commit comments

Comments
 (0)