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 }