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  }