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 }