github.com/koko1123/flow-go-1@v0.29.6/model/flow/service_event.go (about)

     1  package flow
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  
     7  	"github.com/fxamacker/cbor/v2"
     8  	"github.com/vmihailenco/msgpack/v4"
     9  
    10  	cborcodec "github.com/koko1123/flow-go-1/model/encoding/cbor"
    11  )
    12  
    13  const (
    14  	ServiceEventSetup  = "setup"
    15  	ServiceEventCommit = "commit"
    16  )
    17  
    18  // ServiceEvent represents a service event, which is a special event that when
    19  // emitted from a service account smart contract, is propagated to the protocol
    20  // and included in blocks. Service events typically cause changes to the
    21  // protocol state. See EpochSetup and EpochCommit events in this package for examples.
    22  //
    23  // This type represents a generic service event and primarily exists to simplify
    24  // encoding and decoding.
    25  type ServiceEvent struct {
    26  	Type  string
    27  	Event interface{}
    28  }
    29  
    30  // ServiceEventList is a handy container to enable comparisons
    31  type ServiceEventList []ServiceEvent
    32  
    33  func (sel ServiceEventList) EqualTo(other ServiceEventList) (bool, error) {
    34  	if len(sel) != len(other) {
    35  		return false, nil
    36  	}
    37  
    38  	for i, se := range sel {
    39  		equalTo, err := se.EqualTo(&other[i])
    40  		if err != nil {
    41  			return false, fmt.Errorf("error while comparing service event index %d: %w", i, err)
    42  		}
    43  		if !equalTo {
    44  			return false, nil
    45  		}
    46  	}
    47  
    48  	return true, nil
    49  }
    50  
    51  func (se *ServiceEvent) UnmarshalJSON(b []byte) error {
    52  
    53  	var enc map[string]interface{}
    54  	err := json.Unmarshal(b, &enc)
    55  	if err != nil {
    56  		return err
    57  	}
    58  
    59  	tp, ok := enc["Type"].(string)
    60  	if !ok {
    61  		return fmt.Errorf("missing type key")
    62  	}
    63  	ev, ok := enc["Event"]
    64  	if !ok {
    65  		return fmt.Errorf("missing event key")
    66  	}
    67  
    68  	// re-marshal the event, we'll unmarshal it into the appropriate type
    69  	evb, err := json.Marshal(ev)
    70  	if err != nil {
    71  		return err
    72  	}
    73  
    74  	var event interface{}
    75  	switch tp {
    76  	case ServiceEventSetup:
    77  		setup := new(EpochSetup)
    78  		err = json.Unmarshal(evb, setup)
    79  		if err != nil {
    80  			return err
    81  		}
    82  		event = setup
    83  	case ServiceEventCommit:
    84  		commit := new(EpochCommit)
    85  		err = json.Unmarshal(evb, commit)
    86  		if err != nil {
    87  			return err
    88  		}
    89  		event = commit
    90  	default:
    91  		return fmt.Errorf("invalid type: %s", tp)
    92  	}
    93  
    94  	*se = ServiceEvent{
    95  		Type:  tp,
    96  		Event: event,
    97  	}
    98  	return nil
    99  }
   100  
   101  func (se *ServiceEvent) UnmarshalMsgpack(b []byte) error {
   102  
   103  	var enc map[string]interface{}
   104  	err := msgpack.Unmarshal(b, &enc)
   105  	if err != nil {
   106  		return err
   107  	}
   108  
   109  	tp, ok := enc["Type"].(string)
   110  	if !ok {
   111  		return fmt.Errorf("missing type key")
   112  	}
   113  	ev, ok := enc["Event"]
   114  	if !ok {
   115  		return fmt.Errorf("missing event key")
   116  	}
   117  
   118  	// re-marshal the event, we'll unmarshal it into the appropriate type
   119  	evb, err := msgpack.Marshal(ev)
   120  	if err != nil {
   121  		return err
   122  	}
   123  
   124  	var event interface{}
   125  	switch tp {
   126  	case ServiceEventSetup:
   127  		setup := new(EpochSetup)
   128  		err = msgpack.Unmarshal(evb, setup)
   129  		if err != nil {
   130  			return err
   131  		}
   132  		event = setup
   133  	case ServiceEventCommit:
   134  		commit := new(EpochCommit)
   135  		err = msgpack.Unmarshal(evb, commit)
   136  		if err != nil {
   137  			return err
   138  		}
   139  		event = commit
   140  	default:
   141  		return fmt.Errorf("invalid type: %s", tp)
   142  	}
   143  
   144  	*se = ServiceEvent{
   145  		Type:  tp,
   146  		Event: event,
   147  	}
   148  	return nil
   149  }
   150  
   151  func (se *ServiceEvent) UnmarshalCBOR(b []byte) error {
   152  
   153  	var enc map[string]interface{}
   154  	err := cbor.Unmarshal(b, &enc)
   155  	if err != nil {
   156  		return err
   157  	}
   158  
   159  	tp, ok := enc["Type"].(string)
   160  	if !ok {
   161  		return fmt.Errorf("missing type key")
   162  	}
   163  	ev, ok := enc["Event"]
   164  	if !ok {
   165  		return fmt.Errorf("missing event key")
   166  	}
   167  
   168  	evb, err := cborcodec.EncMode.Marshal(ev)
   169  	if err != nil {
   170  		return err
   171  	}
   172  
   173  	var event interface{}
   174  	switch tp {
   175  	case ServiceEventSetup:
   176  		setup := new(EpochSetup)
   177  		err = cbor.Unmarshal(evb, setup)
   178  		if err != nil {
   179  			return err
   180  		}
   181  		event = setup
   182  	case ServiceEventCommit:
   183  		commit := new(EpochCommit)
   184  		err = cbor.Unmarshal(evb, commit)
   185  		if err != nil {
   186  			return err
   187  		}
   188  		event = commit
   189  	default:
   190  		return fmt.Errorf("invalid type: %s", tp)
   191  	}
   192  
   193  	*se = ServiceEvent{
   194  		Type:  tp,
   195  		Event: event,
   196  	}
   197  	return nil
   198  }
   199  
   200  func (se *ServiceEvent) EqualTo(other *ServiceEvent) (bool, error) {
   201  	if se.Type != other.Type {
   202  		return false, nil
   203  	}
   204  	switch se.Type {
   205  	case ServiceEventSetup:
   206  		setup, ok := se.Event.(*EpochSetup)
   207  		if !ok {
   208  			return false, fmt.Errorf("internal invalid type for ServiceEventSetup: %T", se.Event)
   209  		}
   210  		otherSetup, ok := other.Event.(*EpochSetup)
   211  		if !ok {
   212  			return false, fmt.Errorf("internal invalid type for ServiceEventSetup: %T", other.Event)
   213  		}
   214  		return setup.EqualTo(otherSetup), nil
   215  
   216  	case ServiceEventCommit:
   217  		commit, ok := se.Event.(*EpochCommit)
   218  		if !ok {
   219  			return false, fmt.Errorf("internal invalid type for ServiceEventCommit: %T", se.Event)
   220  		}
   221  		otherCommit, ok := other.Event.(*EpochCommit)
   222  		if !ok {
   223  			return false, fmt.Errorf("internal invalid type for ServiceEventCommit: %T", other.Event)
   224  		}
   225  		return commit.EqualTo(otherCommit), nil
   226  	default:
   227  		return false, fmt.Errorf("unknown serice event type: %s", se.Type)
   228  	}
   229  }