github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/module/executiondatasync/execution_data/cache/cache.go (about) 1 package cache 2 3 import ( 4 "context" 5 "fmt" 6 7 "github.com/onflow/flow-go/model/flow" 8 "github.com/onflow/flow-go/module/executiondatasync/execution_data" 9 "github.com/onflow/flow-go/module/mempool" 10 "github.com/onflow/flow-go/storage" 11 ) 12 13 // ExecutionDataCache is a read-through cache for ExecutionData. 14 type ExecutionDataCache struct { 15 backend execution_data.ExecutionDataGetter 16 17 headers storage.Headers 18 seals storage.Seals 19 results storage.ExecutionResults 20 cache mempool.ExecutionData 21 } 22 23 // NewExecutionDataCache returns a new ExecutionDataCache. 24 func NewExecutionDataCache( 25 backend execution_data.ExecutionDataGetter, 26 headers storage.Headers, 27 seals storage.Seals, 28 results storage.ExecutionResults, 29 cache mempool.ExecutionData, 30 ) *ExecutionDataCache { 31 return &ExecutionDataCache{ 32 backend: backend, 33 34 headers: headers, 35 seals: seals, 36 results: results, 37 cache: cache, 38 } 39 } 40 41 // ByID returns the execution data for the given ExecutionDataID. 42 // 43 // Expected errors during normal operations: 44 // - BlobNotFoundError if some CID in the blob tree could not be found from the blobstore 45 // - MalformedDataError if some level of the blob tree cannot be properly deserialized 46 // - BlobSizeLimitExceededError if some blob in the blob tree exceeds the maximum allowed size 47 func (c *ExecutionDataCache) ByID(ctx context.Context, executionDataID flow.Identifier) (*execution_data.BlockExecutionDataEntity, error) { 48 execData, err := c.backend.Get(ctx, executionDataID) 49 if err != nil { 50 return nil, err 51 } 52 53 return execution_data.NewBlockExecutionDataEntity(executionDataID, execData), nil 54 } 55 56 // ByBlockID returns the execution data for the given block ID. 57 // 58 // Expected errors during normal operations: 59 // - storage.ErrNotFound if a seal or execution result is not available for the block 60 // - BlobNotFoundError if some CID in the blob tree could not be found from the blobstore 61 // - MalformedDataError if some level of the blob tree cannot be properly deserialized 62 // - BlobSizeLimitExceededError if some blob in the blob tree exceeds the maximum allowed size 63 func (c *ExecutionDataCache) ByBlockID(ctx context.Context, blockID flow.Identifier) (*execution_data.BlockExecutionDataEntity, error) { 64 if execData, ok := c.cache.ByID(blockID); ok { 65 return execData, nil 66 } 67 68 executionDataID, err := c.LookupID(blockID) 69 if err != nil { 70 return nil, err 71 } 72 73 execData, err := c.backend.Get(ctx, executionDataID) 74 if err != nil { 75 return nil, err 76 } 77 78 execDataEntity := execution_data.NewBlockExecutionDataEntity(executionDataID, execData) 79 80 _ = c.cache.Add(execDataEntity) 81 82 return execDataEntity, nil 83 } 84 85 // ByHeight returns the execution data for the given block height. 86 // 87 // Expected errors during normal operations: 88 // - storage.ErrNotFound if a seal or execution result is not available for the block 89 // - BlobNotFoundError if some CID in the blob tree could not be found from the blobstore 90 // - MalformedDataError if some level of the blob tree cannot be properly deserialized 91 // - BlobSizeLimitExceededError if some blob in the blob tree exceeds the maximum allowed size 92 func (c *ExecutionDataCache) ByHeight(ctx context.Context, height uint64) (*execution_data.BlockExecutionDataEntity, error) { 93 blockID, err := c.headers.BlockIDByHeight(height) 94 if err != nil { 95 return nil, err 96 } 97 98 return c.ByBlockID(ctx, blockID) 99 } 100 101 // LookupID returns the ExecutionDataID for the given block ID. 102 // 103 // Expected errors during normal operations: 104 // - storage.ErrNotFound if a seal or execution result is not available for the block 105 func (c *ExecutionDataCache) LookupID(blockID flow.Identifier) (flow.Identifier, error) { 106 seal, err := c.seals.FinalizedSealForBlock(blockID) 107 if err != nil { 108 return flow.ZeroID, fmt.Errorf("failed to lookup seal for block %s: %w", blockID, err) 109 } 110 111 result, err := c.results.ByID(seal.ResultID) 112 if err != nil { 113 return flow.ZeroID, fmt.Errorf("failed to lookup execution result for block %s: %w", blockID, err) 114 } 115 116 return result.ExecutionDataID, nil 117 }