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  }