github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/engine/access/state_stream/backend/event_retriever.go (about) 1 package backend 2 3 import ( 4 "context" 5 "fmt" 6 "time" 7 8 "github.com/rs/zerolog" 9 10 "github.com/onflow/flow-go/engine/access/index" 11 "github.com/onflow/flow-go/model/flow" 12 "github.com/onflow/flow-go/storage" 13 "github.com/onflow/flow-go/utils/logging" 14 ) 15 16 // EventsResponse represents the response containing events for a specific block. 17 type EventsResponse struct { 18 BlockID flow.Identifier 19 Height uint64 20 Events flow.EventsList 21 BlockTimestamp time.Time 22 } 23 24 // EventsRetriever retrieves events by block height. It can be configured to retrieve events from 25 // the events indexer(if available) or using a dedicated callback to query it from other sources. 26 type EventsRetriever struct { 27 log zerolog.Logger 28 headers storage.Headers 29 getExecutionData GetExecutionDataFunc 30 eventsIndex *index.EventsIndex 31 useEventsIndex bool 32 } 33 34 // GetAllEventsResponse returns a function that retrieves the event response for a given block height. 35 // Expected errors: 36 // - codes.NotFound: If block header for the specified block height is not found. 37 // - error: An error, if any, encountered during getting events from storage or execution data. 38 func (b *EventsRetriever) GetAllEventsResponse(ctx context.Context, height uint64) (*EventsResponse, error) { 39 var response *EventsResponse 40 var err error 41 if b.useEventsIndex { 42 response, err = b.getEventsFromStorage(height) 43 } else { 44 response, err = b.getEventsFromExecutionData(ctx, height) 45 } 46 47 if err == nil { 48 header, err := b.headers.ByHeight(height) 49 if err != nil { 50 return nil, fmt.Errorf("could not get header for height %d: %w", height, err) 51 } 52 response.BlockTimestamp = header.Timestamp 53 54 if b.log.GetLevel() == zerolog.TraceLevel { 55 b.log.Trace(). 56 Hex("block_id", logging.ID(response.BlockID)). 57 Uint64("height", height). 58 Int("events", len(response.Events)). 59 Msg("sending events") 60 } 61 } 62 63 return response, err 64 } 65 66 // getEventsFromExecutionData returns the events for a given height extract from the execution data. 67 // Expected errors: 68 // - error: An error indicating issues with getting execution data for block 69 func (b *EventsRetriever) getEventsFromExecutionData(ctx context.Context, height uint64) (*EventsResponse, error) { 70 executionData, err := b.getExecutionData(ctx, height) 71 if err != nil { 72 return nil, fmt.Errorf("could not get execution data for block %d: %w", height, err) 73 } 74 75 var events flow.EventsList 76 for _, chunkExecutionData := range executionData.ChunkExecutionDatas { 77 events = append(events, chunkExecutionData.Events...) 78 } 79 80 return &EventsResponse{ 81 BlockID: executionData.BlockID, 82 Height: height, 83 Events: events, 84 }, nil 85 } 86 87 // getEventsFromStorage returns the events for a given height from the index storage. 88 // Expected errors: 89 // - error: An error indicating any issues with the provided block height or 90 // an error indicating issue with getting events for a block. 91 func (b *EventsRetriever) getEventsFromStorage(height uint64) (*EventsResponse, error) { 92 blockID, err := b.headers.BlockIDByHeight(height) 93 if err != nil { 94 return nil, fmt.Errorf("could not get header for height %d: %w", height, err) 95 } 96 97 events, err := b.eventsIndex.ByBlockID(blockID, height) 98 if err != nil { 99 return nil, fmt.Errorf("could not get events for block %d: %w", height, err) 100 } 101 102 return &EventsResponse{ 103 BlockID: blockID, 104 Height: height, 105 Events: events, 106 }, nil 107 }