github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/engine/common/rpc/convert/events.go (about) 1 package convert 2 3 import ( 4 "encoding/json" 5 "fmt" 6 7 "google.golang.org/protobuf/types/known/timestamppb" 8 9 "github.com/onflow/cadence/encoding/ccf" 10 jsoncdc "github.com/onflow/cadence/encoding/json" 11 12 "github.com/onflow/flow-go/model/flow" 13 14 accessproto "github.com/onflow/flow/protobuf/go/flow/access" 15 "github.com/onflow/flow/protobuf/go/flow/entities" 16 ) 17 18 // EventToMessage converts a flow.Event to a protobuf message 19 // Note: this function does not convert the payload encoding 20 func EventToMessage(e flow.Event) *entities.Event { 21 return &entities.Event{ 22 Type: string(e.Type), 23 TransactionId: e.TransactionID[:], 24 TransactionIndex: e.TransactionIndex, 25 EventIndex: e.EventIndex, 26 Payload: e.Payload, 27 } 28 } 29 30 // MessageToEvent converts a protobuf message to a flow.Event 31 // Note: this function does not convert the payload encoding 32 func MessageToEvent(m *entities.Event) flow.Event { 33 return flow.Event{ 34 Type: flow.EventType(m.GetType()), 35 TransactionID: flow.HashToID(m.GetTransactionId()), 36 TransactionIndex: m.GetTransactionIndex(), 37 EventIndex: m.GetEventIndex(), 38 Payload: m.GetPayload(), 39 } 40 } 41 42 // EventsToMessages converts a slice of flow.Events to a slice of protobuf messages 43 // Note: this function does not convert the payload encoding 44 func EventsToMessages(flowEvents []flow.Event) []*entities.Event { 45 events := make([]*entities.Event, len(flowEvents)) 46 for i, e := range flowEvents { 47 event := EventToMessage(e) 48 events[i] = event 49 } 50 return events 51 } 52 53 // MessagesToEvents converts a slice of protobuf messages to a slice of flow.Events 54 // Note: this function does not convert the payload encoding 55 func MessagesToEvents(l []*entities.Event) []flow.Event { 56 events := make([]flow.Event, len(l)) 57 for i, m := range l { 58 events[i] = MessageToEvent(m) 59 } 60 return events 61 } 62 63 // EventToMessageFromVersion converts a flow.Event to a protobuf message, converting the payload 64 // encoding from CCF to JSON if the input version is CCF 65 func EventToMessageFromVersion(e flow.Event, version entities.EventEncodingVersion) (*entities.Event, error) { 66 message := EventToMessage(e) 67 68 if len(e.Payload) > 0 { 69 switch version { 70 case entities.EventEncodingVersion_CCF_V0: 71 convertedPayload, err := CcfPayloadToJsonPayload(e.Payload) 72 if err != nil { 73 return nil, fmt.Errorf("could not convert event payload from CCF to Json: %w", err) 74 } 75 message.Payload = convertedPayload 76 case entities.EventEncodingVersion_JSON_CDC_V0: 77 default: 78 return nil, fmt.Errorf("invalid encoding format %d", version) 79 } 80 } 81 82 return message, nil 83 } 84 85 // MessageToEventFromVersion converts a protobuf message to a flow.Event, and converts the payload 86 // encoding from CCF to JSON if the input version is CCF 87 func MessageToEventFromVersion(m *entities.Event, inputVersion entities.EventEncodingVersion) (*flow.Event, error) { 88 event := MessageToEvent(m) 89 switch inputVersion { 90 case entities.EventEncodingVersion_CCF_V0: 91 convertedPayload, err := CcfPayloadToJsonPayload(event.Payload) 92 if err != nil { 93 return nil, fmt.Errorf("could not convert event payload from CCF to Json: %w", err) 94 } 95 event.Payload = convertedPayload 96 return &event, nil 97 case entities.EventEncodingVersion_JSON_CDC_V0: 98 return &event, nil 99 default: 100 return nil, fmt.Errorf("invalid encoding format %d", inputVersion) 101 } 102 } 103 104 // EventsToMessagesWithEncodingConversion converts a slice of flow.Events to a slice of protobuf messages, converting 105 // the payload encoding from CCF to JSON if the input version is CCF 106 func EventsToMessagesWithEncodingConversion( 107 flowEvents []flow.Event, 108 from entities.EventEncodingVersion, 109 to entities.EventEncodingVersion, 110 ) ([]*entities.Event, error) { 111 if from == entities.EventEncodingVersion_JSON_CDC_V0 && to == entities.EventEncodingVersion_CCF_V0 { 112 return nil, fmt.Errorf("conversion from format %s to %s is not supported", from.String(), to.String()) 113 } 114 115 if from == to { 116 return EventsToMessages(flowEvents), nil 117 } 118 119 events := make([]*entities.Event, len(flowEvents)) 120 for i, e := range flowEvents { 121 event, err := EventToMessageFromVersion(e, from) 122 if err != nil { 123 return nil, fmt.Errorf("could not convert event at index %d from format %d: %w", 124 e.EventIndex, from, err) 125 } 126 events[i] = event 127 } 128 return events, nil 129 } 130 131 // MessagesToEventsWithEncodingConversion converts a slice of protobuf messages to a slice of flow.Events, converting 132 // the payload encoding from CCF to JSON if the input version is CCF 133 func MessagesToEventsWithEncodingConversion( 134 messageEvents []*entities.Event, 135 from entities.EventEncodingVersion, 136 to entities.EventEncodingVersion, 137 ) ([]flow.Event, error) { 138 if from == entities.EventEncodingVersion_JSON_CDC_V0 && to == entities.EventEncodingVersion_CCF_V0 { 139 return nil, fmt.Errorf("conversion from format %s to %s is not supported", from.String(), to.String()) 140 } 141 142 if from == to { 143 return MessagesToEvents(messageEvents), nil 144 } 145 146 events := make([]flow.Event, len(messageEvents)) 147 for i, m := range messageEvents { 148 event, err := MessageToEventFromVersion(m, from) 149 if err != nil { 150 return nil, fmt.Errorf("could not convert event at index %d from format %d: %w", 151 m.EventIndex, from, err) 152 } 153 events[i] = *event 154 } 155 return events, nil 156 } 157 158 // ServiceEventToMessage converts a flow.ServiceEvent to a protobuf message 159 func ServiceEventToMessage(event flow.ServiceEvent) (*entities.ServiceEvent, error) { 160 bytes, err := json.Marshal(event.Event) 161 if err != nil { 162 return nil, fmt.Errorf("cannot marshal service event: %w", err) 163 } 164 165 return &entities.ServiceEvent{ 166 Type: event.Type.String(), 167 Payload: bytes, 168 }, nil 169 } 170 171 // MessageToServiceEvent converts a protobuf message to a flow.ServiceEvent 172 func MessageToServiceEvent(m *entities.ServiceEvent) (*flow.ServiceEvent, error) { 173 rawEvent := m.Payload 174 eventType := flow.ServiceEventType(m.Type) 175 se, err := flow.ServiceEventJSONMarshaller.UnmarshalWithType(rawEvent, eventType) 176 177 return &se, err 178 } 179 180 // ServiceEventListToMessages converts a slice of flow.ServiceEvents to a slice of protobuf messages 181 func ServiceEventListToMessages(list flow.ServiceEventList) ( 182 []*entities.ServiceEvent, 183 error, 184 ) { 185 entities := make([]*entities.ServiceEvent, len(list)) 186 for i, serviceEvent := range list { 187 m, err := ServiceEventToMessage(serviceEvent) 188 if err != nil { 189 return nil, fmt.Errorf("failed to convert service event at index %d to message: %w", i, err) 190 } 191 entities[i] = m 192 } 193 return entities, nil 194 } 195 196 // MessagesToServiceEventList converts a slice of flow.ServiceEvents to a slice of protobuf messages 197 func MessagesToServiceEventList(m []*entities.ServiceEvent) ( 198 flow.ServiceEventList, 199 error, 200 ) { 201 parsedServiceEvents := make(flow.ServiceEventList, len(m)) 202 for i, serviceEvent := range m { 203 parsedServiceEvent, err := MessageToServiceEvent(serviceEvent) 204 if err != nil { 205 return nil, fmt.Errorf("failed to parse service event at index %d from message: %w", i, err) 206 } 207 parsedServiceEvents[i] = *parsedServiceEvent 208 } 209 return parsedServiceEvents, nil 210 } 211 212 // CcfPayloadToJsonPayload converts a CCF-encoded payload to a JSON-encoded payload 213 func CcfPayloadToJsonPayload(p []byte) ([]byte, error) { 214 if len(p) == 0 { 215 return p, nil 216 } 217 218 val, err := ccf.Decode(nil, p) 219 if err != nil { 220 return nil, fmt.Errorf("unable to decode from ccf format: %w", err) 221 } 222 res, err := jsoncdc.Encode(val) 223 if err != nil { 224 return nil, fmt.Errorf("unable to encode to json-cdc format: %w", err) 225 } 226 return res, nil 227 } 228 229 // CcfEventToJsonEvent returns a new event with the payload converted from CCF to JSON 230 func CcfEventToJsonEvent(e flow.Event) (*flow.Event, error) { 231 convertedPayload, err := CcfPayloadToJsonPayload(e.Payload) 232 if err != nil { 233 return nil, err 234 } 235 return &flow.Event{ 236 Type: e.Type, 237 TransactionID: e.TransactionID, 238 TransactionIndex: e.TransactionIndex, 239 EventIndex: e.EventIndex, 240 Payload: convertedPayload, 241 }, nil 242 } 243 244 // CcfEventsToJsonEvents returns a new event with the payload converted from CCF to JSON 245 func CcfEventsToJsonEvents(events []flow.Event) ([]flow.Event, error) { 246 convertedEvents := make([]flow.Event, len(events)) 247 for i, e := range events { 248 payload, err := CcfPayloadToJsonPayload(e.Payload) 249 if err != nil { 250 return nil, fmt.Errorf("failed to convert event payload for event %d: %w", i, err) 251 } 252 e.Payload = payload 253 convertedEvents[i] = e 254 } 255 return convertedEvents, nil 256 } 257 258 // MessagesToBlockEvents converts a protobuf EventsResponse_Result messages to a slice of flow.BlockEvents. 259 func MessagesToBlockEvents(blocksEvents []*accessproto.EventsResponse_Result) []flow.BlockEvents { 260 evs := make([]flow.BlockEvents, len(blocksEvents)) 261 for i, ev := range blocksEvents { 262 evs[i] = MessageToBlockEvents(ev) 263 } 264 265 return evs 266 } 267 268 // MessageToBlockEvents converts a protobuf EventsResponse_Result message to a flow.BlockEvents. 269 func MessageToBlockEvents(blockEvents *accessproto.EventsResponse_Result) flow.BlockEvents { 270 return flow.BlockEvents{ 271 BlockHeight: blockEvents.BlockHeight, 272 BlockID: MessageToIdentifier(blockEvents.BlockId), 273 BlockTimestamp: blockEvents.BlockTimestamp.AsTime(), 274 Events: MessagesToEvents(blockEvents.Events), 275 } 276 } 277 278 func BlockEventsToMessages(blocks []flow.BlockEvents) ([]*accessproto.EventsResponse_Result, error) { 279 results := make([]*accessproto.EventsResponse_Result, len(blocks)) 280 281 for i, block := range blocks { 282 event, err := BlockEventsToMessage(block) 283 if err != nil { 284 return nil, err 285 } 286 results[i] = event 287 } 288 289 return results, nil 290 } 291 292 func BlockEventsToMessage(block flow.BlockEvents) (*accessproto.EventsResponse_Result, error) { 293 eventMessages := make([]*entities.Event, len(block.Events)) 294 for i, event := range block.Events { 295 eventMessages[i] = EventToMessage(event) 296 } 297 timestamp := timestamppb.New(block.BlockTimestamp) 298 return &accessproto.EventsResponse_Result{ 299 BlockId: block.BlockID[:], 300 BlockHeight: block.BlockHeight, 301 BlockTimestamp: timestamp, 302 Events: eventMessages, 303 }, nil 304 }