github.com/cosmos/cosmos-sdk@v0.50.10/types/events.go (about)

     1  package types
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"reflect"
     7  	"strings"
     8  
     9  	abci "github.com/cometbft/cometbft/abci/types"
    10  	"github.com/cosmos/gogoproto/jsonpb"
    11  	proto "github.com/cosmos/gogoproto/proto"
    12  	"golang.org/x/exp/maps"
    13  	"golang.org/x/exp/slices"
    14  
    15  	"github.com/cosmos/cosmos-sdk/codec"
    16  )
    17  
    18  type EventManagerI interface {
    19  	Events() Events
    20  	ABCIEvents() []abci.Event
    21  	EmitTypedEvent(tev proto.Message) error
    22  	EmitTypedEvents(tevs ...proto.Message) error
    23  	EmitEvent(event Event)
    24  	EmitEvents(events Events)
    25  }
    26  
    27  // ----------------------------------------------------------------------------
    28  // Event Manager
    29  // ----------------------------------------------------------------------------
    30  
    31  var _ EventManagerI = (*EventManager)(nil)
    32  
    33  // EventManager implements a simple wrapper around a slice of Event objects that
    34  // can be emitted from.
    35  type EventManager struct {
    36  	events Events
    37  }
    38  
    39  func NewEventManager() *EventManager {
    40  	return &EventManager{EmptyEvents()}
    41  }
    42  
    43  func (em *EventManager) Events() Events { return em.events }
    44  
    45  // EmitEvent stores a single Event object.
    46  // Deprecated: Use EmitTypedEvent
    47  func (em *EventManager) EmitEvent(event Event) {
    48  	em.events = em.events.AppendEvent(event)
    49  }
    50  
    51  // EmitEvents stores a series of Event objects.
    52  // Deprecated: Use EmitTypedEvents
    53  func (em *EventManager) EmitEvents(events Events) {
    54  	em.events = em.events.AppendEvents(events)
    55  }
    56  
    57  // ABCIEvents returns all stored Event objects as abci.Event objects.
    58  func (em EventManager) ABCIEvents() []abci.Event {
    59  	return em.events.ToABCIEvents()
    60  }
    61  
    62  // EmitTypedEvent takes typed event and emits converting it into Event
    63  func (em *EventManager) EmitTypedEvent(tev proto.Message) error {
    64  	event, err := TypedEventToEvent(tev)
    65  	if err != nil {
    66  		return err
    67  	}
    68  
    69  	em.EmitEvent(event)
    70  	return nil
    71  }
    72  
    73  // EmitTypedEvents takes series of typed events and emit
    74  func (em *EventManager) EmitTypedEvents(tevs ...proto.Message) error {
    75  	events := make(Events, len(tevs))
    76  	for i, tev := range tevs {
    77  		res, err := TypedEventToEvent(tev)
    78  		if err != nil {
    79  			return err
    80  		}
    81  		events[i] = res
    82  	}
    83  
    84  	em.EmitEvents(events)
    85  	return nil
    86  }
    87  
    88  // TypedEventToEvent takes typed event and converts to Event object
    89  func TypedEventToEvent(tev proto.Message) (Event, error) {
    90  	evtType := proto.MessageName(tev)
    91  	evtJSON, err := codec.ProtoMarshalJSON(tev, nil)
    92  	if err != nil {
    93  		return Event{}, err
    94  	}
    95  
    96  	var attrMap map[string]json.RawMessage
    97  	err = json.Unmarshal(evtJSON, &attrMap)
    98  	if err != nil {
    99  		return Event{}, err
   100  	}
   101  
   102  	// sort the keys to ensure the order is always the same
   103  	keys := maps.Keys(attrMap)
   104  	slices.Sort(keys)
   105  
   106  	attrs := make([]abci.EventAttribute, 0, len(attrMap))
   107  	for _, k := range keys {
   108  		v := attrMap[k]
   109  		attrs = append(attrs, abci.EventAttribute{
   110  			Key:   k,
   111  			Value: string(v),
   112  		})
   113  	}
   114  
   115  	return Event{
   116  		Type:       evtType,
   117  		Attributes: attrs,
   118  	}, nil
   119  }
   120  
   121  // ParseTypedEvent converts abci.Event back to a typed event.
   122  func ParseTypedEvent(event abci.Event) (proto.Message, error) {
   123  	concreteGoType := proto.MessageType(event.Type)
   124  	if concreteGoType == nil {
   125  		return nil, fmt.Errorf("failed to retrieve the message of type %q", event.Type)
   126  	}
   127  
   128  	var value reflect.Value
   129  	if concreteGoType.Kind() == reflect.Ptr {
   130  		value = reflect.New(concreteGoType.Elem())
   131  	} else {
   132  		value = reflect.Zero(concreteGoType)
   133  	}
   134  
   135  	protoMsg, ok := value.Interface().(proto.Message)
   136  	if !ok {
   137  		return nil, fmt.Errorf("%q does not implement proto.Message", event.Type)
   138  	}
   139  
   140  	attrMap := make(map[string]json.RawMessage)
   141  	for _, attr := range event.Attributes {
   142  		attrMap[attr.Key] = json.RawMessage(attr.Value)
   143  	}
   144  
   145  	attrBytes, err := json.Marshal(attrMap)
   146  	if err != nil {
   147  		return nil, err
   148  	}
   149  
   150  	unmarshaler := jsonpb.Unmarshaler{AllowUnknownFields: true}
   151  	if err := unmarshaler.Unmarshal(strings.NewReader(string(attrBytes)), protoMsg); err != nil {
   152  		return nil, err
   153  	}
   154  
   155  	return protoMsg, nil
   156  }
   157  
   158  // ----------------------------------------------------------------------------
   159  // Events
   160  // ----------------------------------------------------------------------------
   161  
   162  type (
   163  	// Event is a type alias for an ABCI Event
   164  	Event abci.Event
   165  
   166  	// Events defines a slice of Event objects
   167  	Events []Event
   168  )
   169  
   170  // NewEvent creates a new Event object with a given type and slice of one or more
   171  // attributes.
   172  func NewEvent(ty string, attrs ...Attribute) Event {
   173  	e := Event{Type: ty}
   174  
   175  	for _, attr := range attrs {
   176  		e.Attributes = append(e.Attributes, attr.ToKVPair())
   177  	}
   178  
   179  	return e
   180  }
   181  
   182  // NewAttribute returns a new key/value Attribute object.
   183  func NewAttribute(k, v string) Attribute {
   184  	return Attribute{k, v}
   185  }
   186  
   187  // EmptyEvents returns an empty slice of events.
   188  func EmptyEvents() Events {
   189  	return make(Events, 0)
   190  }
   191  
   192  func (a Attribute) String() string {
   193  	return fmt.Sprintf("%s: %s", a.Key, a.Value)
   194  }
   195  
   196  // ToKVPair converts an Attribute object into a CometBFT key/value pair.
   197  func (a Attribute) ToKVPair() abci.EventAttribute {
   198  	return abci.EventAttribute{Key: a.Key, Value: a.Value}
   199  }
   200  
   201  // AppendAttributes adds one or more attributes to an Event.
   202  func (e Event) AppendAttributes(attrs ...Attribute) Event {
   203  	for _, attr := range attrs {
   204  		e.Attributes = append(e.Attributes, attr.ToKVPair())
   205  	}
   206  	return e
   207  }
   208  
   209  // GetAttribute returns an attribute for a given key present in an event.
   210  // If the key is not found, the boolean value will be false.
   211  func (e Event) GetAttribute(key string) (Attribute, bool) {
   212  	for _, attr := range e.Attributes {
   213  		if attr.Key == key {
   214  			return Attribute{Key: attr.Key, Value: attr.Value}, true
   215  		}
   216  	}
   217  	return Attribute{}, false
   218  }
   219  
   220  // AppendEvent adds an Event to a slice of events.
   221  func (e Events) AppendEvent(event Event) Events {
   222  	return append(e, event)
   223  }
   224  
   225  // AppendEvents adds a slice of Event objects to an exist slice of Event objects.
   226  func (e Events) AppendEvents(events Events) Events {
   227  	return append(e, events...)
   228  }
   229  
   230  // ToABCIEvents converts a slice of Event objects to a slice of abci.Event
   231  // objects.
   232  func (e Events) ToABCIEvents() []abci.Event {
   233  	res := make([]abci.Event, len(e))
   234  	for i, ev := range e {
   235  		res[i] = abci.Event{Type: ev.Type, Attributes: ev.Attributes}
   236  	}
   237  
   238  	return res
   239  }
   240  
   241  // GetAttributes returns all attributes matching a given key present in events.
   242  // If the key is not found, the boolean value will be false.
   243  func (e Events) GetAttributes(key string) ([]Attribute, bool) {
   244  	attrs := make([]Attribute, 0)
   245  	for _, event := range e {
   246  		if attr, found := event.GetAttribute(key); found {
   247  			attrs = append(attrs, attr)
   248  		}
   249  	}
   250  
   251  	return attrs, len(attrs) > 0
   252  }
   253  
   254  // Common event types and attribute keys
   255  const (
   256  	EventTypeTx = "tx"
   257  
   258  	AttributeKeyAccountSequence = "acc_seq"
   259  	AttributeKeySignature       = "signature"
   260  	AttributeKeyFee             = "fee"
   261  	AttributeKeyFeePayer        = "fee_payer"
   262  
   263  	EventTypeMessage = "message"
   264  
   265  	AttributeKeyAction = "action"
   266  	AttributeKeyModule = "module"
   267  	AttributeKeySender = "sender"
   268  	AttributeKeyAmount = "amount"
   269  )
   270  
   271  type (
   272  	// StringAttributes defines a slice of StringEvents objects.
   273  	StringEvents []StringEvent
   274  )
   275  
   276  func (se StringEvents) String() string {
   277  	var sb strings.Builder
   278  
   279  	for _, e := range se {
   280  		fmt.Fprintf(&sb, "\t\t- %s\n", e.Type)
   281  
   282  		for _, attr := range e.Attributes {
   283  			fmt.Fprintf(&sb, "\t\t\t- %s\n", attr)
   284  		}
   285  	}
   286  
   287  	return strings.TrimRight(sb.String(), "\n")
   288  }
   289  
   290  // StringifyEvent converts an Event object to a StringEvent object.
   291  func StringifyEvent(e abci.Event) StringEvent {
   292  	res := StringEvent{Type: e.Type}
   293  
   294  	for _, attr := range e.Attributes {
   295  		res.Attributes = append(
   296  			res.Attributes,
   297  			Attribute{Key: attr.Key, Value: attr.Value},
   298  		)
   299  	}
   300  
   301  	return res
   302  }
   303  
   304  // StringifyEvents converts a slice of Event objects into a slice of StringEvent
   305  // objects.
   306  func StringifyEvents(events []abci.Event) StringEvents {
   307  	res := make(StringEvents, 0, len(events))
   308  
   309  	for _, e := range events {
   310  		res = append(res, StringifyEvent(e))
   311  	}
   312  
   313  	return res
   314  }
   315  
   316  // MarkEventsToIndex returns the set of ABCI events, where each event's attribute
   317  // has it's index value marked based on the provided set of events to index.
   318  func MarkEventsToIndex(events []abci.Event, indexSet map[string]struct{}) []abci.Event {
   319  	indexAll := len(indexSet) == 0
   320  	updatedEvents := make([]abci.Event, len(events))
   321  
   322  	for i, e := range events {
   323  		updatedEvent := abci.Event{
   324  			Type:       e.Type,
   325  			Attributes: make([]abci.EventAttribute, len(e.Attributes)),
   326  		}
   327  
   328  		for j, attr := range e.Attributes {
   329  			_, index := indexSet[fmt.Sprintf("%s.%s", e.Type, attr.Key)]
   330  			updatedAttr := abci.EventAttribute{
   331  				Key:   attr.Key,
   332  				Value: attr.Value,
   333  				Index: index || indexAll,
   334  			}
   335  
   336  			updatedEvent.Attributes[j] = updatedAttr
   337  		}
   338  
   339  		updatedEvents[i] = updatedEvent
   340  	}
   341  
   342  	return updatedEvents
   343  }