github.com/koko1123/flow-go-1@v0.29.6/fvm/environment/event_emitter.go (about) 1 package environment 2 3 import ( 4 "fmt" 5 6 "github.com/onflow/cadence" 7 8 "github.com/koko1123/flow-go-1/fvm/errors" 9 "github.com/koko1123/flow-go-1/fvm/state" 10 "github.com/koko1123/flow-go-1/fvm/systemcontracts" 11 "github.com/koko1123/flow-go-1/fvm/tracing" 12 "github.com/koko1123/flow-go-1/model/flow" 13 "github.com/koko1123/flow-go-1/module/trace" 14 ) 15 16 const ( 17 DefaultEventCollectionByteSizeLimit = 256_000 // 256KB 18 ) 19 20 type EventEmitterParams struct { 21 ServiceEventCollectionEnabled bool 22 EventCollectionByteSizeLimit uint64 23 EventEncoder EventEncoder 24 } 25 26 func DefaultEventEmitterParams() EventEmitterParams { 27 return EventEmitterParams{ 28 ServiceEventCollectionEnabled: false, 29 EventCollectionByteSizeLimit: DefaultEventCollectionByteSizeLimit, 30 EventEncoder: NewCadenceEventEncoder(), 31 } 32 } 33 34 // EventEmitter collect events, separates out service events, and enforces 35 // event size limits. 36 // 37 // Note that scripts do not emit events, but must expose the API in compliance 38 // with the runtime environment interface. 39 type EventEmitter interface { 40 // Cadence's runtime API. Note that the script variant will return 41 // OperationNotSupportedError. 42 EmitEvent(event cadence.Event) error 43 44 Events() []flow.Event 45 ServiceEvents() []flow.Event 46 47 Reset() 48 } 49 50 type ParseRestrictedEventEmitter struct { 51 txnState *state.TransactionState 52 impl EventEmitter 53 } 54 55 func NewParseRestrictedEventEmitter( 56 txnState *state.TransactionState, 57 impl EventEmitter, 58 ) EventEmitter { 59 return ParseRestrictedEventEmitter{ 60 txnState: txnState, 61 impl: impl, 62 } 63 } 64 65 func (emitter ParseRestrictedEventEmitter) EmitEvent(event cadence.Event) error { 66 return parseRestrict1Arg( 67 emitter.txnState, 68 trace.FVMEnvEmitEvent, 69 emitter.impl.EmitEvent, 70 event) 71 } 72 73 func (emitter ParseRestrictedEventEmitter) Events() []flow.Event { 74 return emitter.impl.Events() 75 } 76 77 func (emitter ParseRestrictedEventEmitter) ServiceEvents() []flow.Event { 78 return emitter.impl.ServiceEvents() 79 } 80 81 func (emitter ParseRestrictedEventEmitter) Reset() { 82 emitter.impl.Reset() 83 } 84 85 var _ EventEmitter = NoEventEmitter{} 86 87 // NoEventEmitter is usually used in the environment for script execution, 88 // where emitting an event does nothing. 89 type NoEventEmitter struct{} 90 91 func (NoEventEmitter) EmitEvent(event cadence.Event) error { 92 return nil 93 } 94 95 func (NoEventEmitter) Events() []flow.Event { 96 return []flow.Event{} 97 } 98 99 func (NoEventEmitter) ServiceEvents() []flow.Event { 100 return []flow.Event{} 101 } 102 103 func (NoEventEmitter) Reset() { 104 } 105 106 type eventEmitter struct { 107 tracer tracing.TracerSpan 108 meter Meter 109 110 chain flow.Chain 111 txID flow.Identifier 112 txIndex uint32 113 payer flow.Address 114 115 EventEmitterParams 116 eventCollection *EventCollection 117 } 118 119 // NewEventEmitter constructs a new eventEmitter 120 func NewEventEmitter( 121 tracer tracing.TracerSpan, 122 meter Meter, 123 chain flow.Chain, 124 txInfo TransactionInfoParams, 125 params EventEmitterParams, 126 ) EventEmitter { 127 emitter := &eventEmitter{ 128 tracer: tracer, 129 meter: meter, 130 chain: chain, 131 txID: txInfo.TxId, 132 txIndex: txInfo.TxIndex, 133 payer: txInfo.TxBody.Payer, 134 EventEmitterParams: params, 135 } 136 137 emitter.Reset() 138 return emitter 139 } 140 141 func (emitter *eventEmitter) Reset() { 142 // TODO: for now we are not resetting meter here because we don't check meter 143 // metrics after the first metering failure and when limit is disabled. 144 emitter.eventCollection = NewEventCollection(emitter.meter) 145 } 146 147 func (emitter *eventEmitter) EventCollection() *EventCollection { 148 return emitter.eventCollection 149 } 150 151 func (emitter *eventEmitter) EmitEvent(event cadence.Event) error { 152 defer emitter.tracer.StartExtensiveTracingChildSpan( 153 trace.FVMEnvEmitEvent).End() 154 155 err := emitter.meter.MeterComputation(ComputationKindEmitEvent, 1) 156 if err != nil { 157 return fmt.Errorf("emit event failed: %w", err) 158 } 159 160 payload, err := emitter.EventEncoder.Encode(event) 161 if err != nil { 162 return errors.NewEventEncodingError(err) 163 } 164 165 payloadSize := uint64(len(payload)) 166 167 flowEvent := flow.Event{ 168 Type: flow.EventType(event.EventType.ID()), 169 TransactionID: emitter.txID, 170 TransactionIndex: emitter.txIndex, 171 EventIndex: emitter.eventCollection.TotalEventCounter(), 172 Payload: payload, 173 } 174 175 // TODO: to set limit to maximum when it is service account and get rid of this flag 176 isServiceAccount := emitter.payer == emitter.chain.ServiceAddress() 177 178 if emitter.ServiceEventCollectionEnabled { 179 ok, err := IsServiceEvent(event, emitter.chain.ChainID()) 180 if err != nil { 181 return fmt.Errorf("unable to check service event: %w", err) 182 } 183 if ok { 184 eventEmitError := emitter.eventCollection.AppendServiceEvent(flowEvent, payloadSize) 185 // skip limit if payer is service account 186 if !isServiceAccount && eventEmitError != nil { 187 return eventEmitError 188 } 189 } 190 // We don't return and append the service event into event collection 191 // as well. 192 } 193 194 eventEmitError := emitter.eventCollection.AppendEvent(flowEvent, payloadSize) 195 // skip limit if payer is service account 196 if !isServiceAccount { 197 return eventEmitError 198 } 199 200 return nil 201 } 202 203 func (emitter *eventEmitter) Events() []flow.Event { 204 return emitter.eventCollection.events 205 } 206 207 func (emitter *eventEmitter) ServiceEvents() []flow.Event { 208 return emitter.eventCollection.serviceEvents 209 } 210 211 type EventCollection struct { 212 events flow.EventsList 213 serviceEvents flow.EventsList 214 eventCounter uint32 215 meter Meter 216 } 217 218 func NewEventCollection(meter Meter) *EventCollection { 219 return &EventCollection{ 220 events: make([]flow.Event, 0, 10), 221 serviceEvents: make([]flow.Event, 0, 10), 222 eventCounter: uint32(0), 223 meter: meter, 224 } 225 } 226 227 func (collection *EventCollection) Events() []flow.Event { 228 return collection.events 229 } 230 231 func (collection *EventCollection) AppendEvent(event flow.Event, size uint64) error { 232 collection.events = append(collection.events, event) 233 collection.eventCounter++ 234 return collection.meter.MeterEmittedEvent(size) 235 } 236 237 func (collection *EventCollection) ServiceEvents() []flow.Event { 238 return collection.serviceEvents 239 } 240 241 func (collection *EventCollection) AppendServiceEvent( 242 event flow.Event, 243 size uint64, 244 ) error { 245 collection.serviceEvents = append(collection.serviceEvents, event) 246 collection.eventCounter++ 247 return collection.meter.MeterEmittedEvent(size) 248 } 249 250 func (collection *EventCollection) TotalByteSize() uint64 { 251 return collection.meter.TotalEmittedEventBytes() 252 } 253 254 func (collection *EventCollection) TotalEventCounter() uint32 { 255 return collection.eventCounter 256 } 257 258 // IsServiceEvent determines whether or not an emitted Cadence event is 259 // considered a service event for the given chain. 260 func IsServiceEvent(event cadence.Event, chain flow.ChainID) (bool, error) { 261 262 // retrieve the service event information for this chain 263 events, err := systemcontracts.ServiceEventsForChain(chain) 264 if err != nil { 265 return false, fmt.Errorf( 266 "unknown system contracts for chain (%s): %w", 267 chain.String(), 268 err) 269 } 270 271 eventType := flow.EventType(event.EventType.ID()) 272 for _, serviceEvent := range events.All() { 273 if serviceEvent.EventType() == eventType { 274 return true, nil 275 } 276 } 277 278 return false, nil 279 }