github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/engine/access/state_stream/backend/backend_events.go (about) 1 package backend 2 3 import ( 4 "context" 5 "fmt" 6 7 "github.com/rs/zerolog" 8 9 "github.com/onflow/flow-go/engine/access/state_stream" 10 "github.com/onflow/flow-go/engine/access/subscription" 11 "github.com/onflow/flow-go/fvm/errors" 12 "github.com/onflow/flow-go/model/flow" 13 "github.com/onflow/flow-go/storage" 14 ) 15 16 type EventsBackend struct { 17 log zerolog.Logger 18 19 subscriptionHandler *subscription.SubscriptionHandler 20 executionDataTracker subscription.ExecutionDataTracker 21 eventsRetriever EventsRetriever 22 } 23 24 // SubscribeEvents is deprecated and will be removed in a future version. 25 // Use SubscribeEventsFromStartBlockID, SubscribeEventsFromStartHeight or SubscribeEventsFromLatest. 26 // 27 // SubscribeEvents streams events for all blocks starting at the specified block ID or block height 28 // up until the latest available block. Once the latest is 29 // reached, the stream will remain open and responses are sent for each new 30 // block as it becomes available. 31 // 32 // Only one of startBlockID and startHeight may be set. If neither startBlockID nor startHeight is provided, 33 // the latest sealed block is used. 34 // 35 // Events within each block are filtered by the provided EventFilter, and only 36 // those events that match the filter are returned. If no filter is provided, 37 // all events are returned. 38 // 39 // Parameters: 40 // - ctx: Context for the operation. 41 // - startBlockID: The identifier of the starting block. If provided, startHeight should be 0. 42 // - startHeight: The height of the starting block. If provided, startBlockID should be flow.ZeroID. 43 // - filter: The event filter used to filter events. 44 // 45 // If invalid parameters will be supplied SubscribeEvents will return a failed subscription. 46 func (b *EventsBackend) SubscribeEvents(ctx context.Context, startBlockID flow.Identifier, startHeight uint64, filter state_stream.EventFilter) subscription.Subscription { 47 nextHeight, err := b.executionDataTracker.GetStartHeight(ctx, startBlockID, startHeight) 48 if err != nil { 49 return subscription.NewFailedSubscription(err, "could not get start height") 50 } 51 52 return b.subscriptionHandler.Subscribe(ctx, nextHeight, b.getResponseFactory(filter)) 53 } 54 55 // SubscribeEventsFromStartBlockID streams events starting at the specified block ID, 56 // up until the latest available block. Once the latest is 57 // reached, the stream will remain open and responses are sent for each new 58 // block as it becomes available. 59 // 60 // Events within each block are filtered by the provided EventFilter, and only 61 // those events that match the filter are returned. If no filter is provided, 62 // all events are returned. 63 // 64 // Parameters: 65 // - ctx: Context for the operation. 66 // - startBlockID: The identifier of the starting block. 67 // - filter: The event filter used to filter events. 68 // 69 // If invalid parameters will be supplied SubscribeEventsFromStartBlockID will return a failed subscription. 70 func (b *EventsBackend) SubscribeEventsFromStartBlockID(ctx context.Context, startBlockID flow.Identifier, filter state_stream.EventFilter) subscription.Subscription { 71 nextHeight, err := b.executionDataTracker.GetStartHeightFromBlockID(startBlockID) 72 if err != nil { 73 return subscription.NewFailedSubscription(err, "could not get start height from block id") 74 } 75 76 return b.subscriptionHandler.Subscribe(ctx, nextHeight, b.getResponseFactory(filter)) 77 } 78 79 // SubscribeEventsFromStartHeight streams events starting at the specified block height, 80 // up until the latest available block. Once the latest is 81 // reached, the stream will remain open and responses are sent for each new 82 // block as it becomes available. 83 // 84 // Events within each block are filtered by the provided EventFilter, and only 85 // those events that match the filter are returned. If no filter is provided, 86 // all events are returned. 87 // 88 // Parameters: 89 // - ctx: Context for the operation. 90 // - startHeight: The height of the starting block. 91 // - filter: The event filter used to filter events. 92 // 93 // If invalid parameters will be supplied SubscribeEventsFromStartHeight will return a failed subscription. 94 func (b *EventsBackend) SubscribeEventsFromStartHeight(ctx context.Context, startHeight uint64, filter state_stream.EventFilter) subscription.Subscription { 95 nextHeight, err := b.executionDataTracker.GetStartHeightFromHeight(startHeight) 96 if err != nil { 97 return subscription.NewFailedSubscription(err, "could not get start height from block height") 98 } 99 100 return b.subscriptionHandler.Subscribe(ctx, nextHeight, b.getResponseFactory(filter)) 101 } 102 103 // SubscribeEventsFromLatest subscribes to events starting at the latest sealed block, 104 // up until the latest available block. Once the latest is 105 // reached, the stream will remain open and responses are sent for each new 106 // block as it becomes available. 107 // 108 // Events within each block are filtered by the provided EventFilter, and only 109 // those events that match the filter are returned. If no filter is provided, 110 // all events are returned. 111 // 112 // Parameters: 113 // - ctx: Context for the operation. 114 // - filter: The event filter used to filter events. 115 // 116 // If invalid parameters will be supplied SubscribeEventsFromLatest will return a failed subscription. 117 func (b *EventsBackend) SubscribeEventsFromLatest(ctx context.Context, filter state_stream.EventFilter) subscription.Subscription { 118 nextHeight, err := b.executionDataTracker.GetStartHeightFromLatest(ctx) 119 if err != nil { 120 return subscription.NewFailedSubscription(err, "could not get start height from block height") 121 } 122 123 return b.subscriptionHandler.Subscribe(ctx, nextHeight, b.getResponseFactory(filter)) 124 } 125 126 // getResponseFactory returns a function that retrieves the event response for a given height. 127 // 128 // Parameters: 129 // - filter: The event filter used to filter events. 130 // 131 // Expected errors during normal operation: 132 // - subscription.ErrBlockNotReady: execution data for the given block height is not available. 133 func (b *EventsBackend) getResponseFactory(filter state_stream.EventFilter) subscription.GetDataByHeightFunc { 134 return func(ctx context.Context, height uint64) (response interface{}, err error) { 135 eventsResponse, err := b.eventsRetriever.GetAllEventsResponse(ctx, height) 136 if err != nil { 137 if errors.Is(err, storage.ErrNotFound) || 138 errors.Is(err, storage.ErrHeightNotIndexed) { 139 return nil, subscription.ErrBlockNotReady 140 } 141 return nil, fmt.Errorf("block %d is not available yet: %w", height, subscription.ErrBlockNotReady) 142 } 143 144 eventsResponse.Events = filter.Filter(eventsResponse.Events) 145 146 return eventsResponse, nil 147 } 148 }