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