github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/types/result.go (about) 1 package types 2 3 import ( 4 "bytes" 5 "encoding/hex" 6 "encoding/json" 7 "fmt" 8 "math" 9 "strings" 10 11 "github.com/gogo/protobuf/proto" 12 13 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/codec" 14 "github.com/tendermint/go-amino" 15 16 ctypes "github.com/fibonacci-chain/fbc/libs/tendermint/rpc/core/types" 17 ) 18 19 // GasInfo defines tx execution gas context. 20 type GasInfo struct { 21 // GasWanted is the maximum units of work we allow this tx to perform. 22 GasWanted uint64 23 24 // GasUsed is the amount of gas actually consumed. 25 GasUsed uint64 26 } 27 28 // Result is the union of ResponseFormat and ResponseCheckTx. 29 type Result struct { 30 // Data is any data returned from message or handler execution. It MUST be length 31 // prefixed in order to separate data from multiple message executions. 32 Data []byte 33 34 // Log contains the log information from message or handler execution. 35 Log string 36 37 // Events contains a slice of Event objects that were emitted during message or 38 // handler execution. 39 Events Events 40 } 41 42 // SimulationResponse defines the response generated when a transaction is successfully 43 // simulated by the Baseapp. 44 type SimulationResponse struct { 45 GasInfo 46 Result *Result 47 } 48 49 // ABCIMessageLogs represents a slice of ABCIMessageLog. 50 type ABCIMessageLogs []ABCIMessageLog 51 52 // ABCIMessageLog defines a structure containing an indexed tx ABCI message log. 53 type ABCIMessageLog struct { 54 MsgIndex uint16 `json:"msg_index"` 55 Log string `json:"log"` 56 57 // Events contains a slice of Event objects that were emitted during some 58 // execution. 59 Events StringEvents `json:"events"` 60 } 61 62 func (log ABCIMessageLog) MarshalJsonToBuffer(buf *bytes.Buffer) error { 63 var err error 64 65 err = buf.WriteByte('{') 66 if err != nil { 67 return err 68 } 69 70 buf.WriteString(`"msg_index":`) 71 blob, err := json.Marshal(log.MsgIndex) 72 if err != nil { 73 return err 74 } 75 _, err = buf.Write(blob) 76 if err != nil { 77 return err 78 } 79 err = buf.WriteByte(',') 80 if err != nil { 81 return err 82 } 83 84 buf.WriteString(`"log":`) 85 blob, err = json.Marshal(log.Log) 86 if err != nil { 87 return err 88 } 89 _, err = buf.Write(blob) 90 if err != nil { 91 return err 92 } 93 err = buf.WriteByte(',') 94 if err != nil { 95 return err 96 } 97 98 buf.WriteString(`"events":`) 99 err = log.Events.MarshalJsonToBuffer(buf) 100 if err != nil { 101 return err 102 } 103 104 return buf.WriteByte('}') 105 } 106 107 func NewABCIMessageLog(i uint16, log string, events Events) ABCIMessageLog { 108 return ABCIMessageLog{ 109 MsgIndex: i, 110 Log: log, 111 Events: StringifyEvents(events), 112 } 113 } 114 115 // String implements the fmt.Stringer interface for the ABCIMessageLogs type. 116 func (logs ABCIMessageLogs) String() (str string) { 117 if logs != nil { 118 raw, err := logs.MarshalToJson() 119 if err != nil { 120 raw, err = codec.Cdc.MarshalJSON(logs) 121 } 122 if err == nil { 123 str = string(raw) 124 } 125 } 126 127 return str 128 } 129 130 var abciMessageLogsBufferPool = amino.NewBufferPool() 131 132 func (logs ABCIMessageLogs) MarshalToJson() ([]byte, error) { 133 buf := abciMessageLogsBufferPool.Get() 134 defer abciMessageLogsBufferPool.Put(buf) 135 err := logs.MarshalJsonToBuffer(buf) 136 if err != nil { 137 return nil, err 138 } 139 return amino.GetBytesBufferCopy(buf), nil 140 } 141 142 func (logs ABCIMessageLogs) MarshalJsonToBuffer(buf *bytes.Buffer) error { 143 var err error 144 if logs == nil { 145 _, err = buf.WriteString("null") 146 return err 147 } 148 149 err = buf.WriteByte('[') 150 if err != nil { 151 return err 152 } 153 for i, log := range logs { 154 if i != 0 { 155 err = buf.WriteByte(',') 156 if err != nil { 157 return err 158 } 159 } 160 err = log.MarshalJsonToBuffer(buf) 161 if err != nil { 162 return err 163 } 164 } 165 return buf.WriteByte(']') 166 } 167 168 // TxResponse defines a structure containing relevant tx data and metadata. The 169 // tags are stringified and the log is JSON decoded. 170 type TxResponse struct { 171 Height int64 `json:"height"` 172 TxHash string `json:"txhash"` 173 Codespace string `json:"codespace,omitempty"` 174 Code uint32 `json:"code,omitempty"` 175 Data string `json:"data,omitempty"` 176 RawLog string `json:"raw_log,omitempty"` 177 Logs ABCIMessageLogs `json:"logs,omitempty"` 178 Info string `json:"info,omitempty"` 179 GasWanted int64 `json:"gas_wanted,omitempty"` 180 GasUsed int64 `json:"gas_used,omitempty"` 181 Tx Tx `json:"tx,omitempty"` 182 Timestamp string `json:"timestamp,omitempty"` 183 } 184 185 // NewResponseResultTx returns a TxResponse given a ResultTx from tendermint 186 func NewResponseResultTx(res *ctypes.ResultTx, tx Tx, timestamp string) TxResponse { 187 if res == nil { 188 return TxResponse{} 189 } 190 191 parsedLogs, _ := ParseABCILogs(res.TxResult.Log) 192 193 return TxResponse{ 194 TxHash: res.Hash.String(), 195 Height: res.Height, 196 Codespace: res.TxResult.Codespace, 197 Code: res.TxResult.Code, 198 Data: strings.ToUpper(hex.EncodeToString(res.TxResult.Data)), 199 RawLog: res.TxResult.Log, 200 Logs: parsedLogs, 201 Info: res.TxResult.Info, 202 GasWanted: res.TxResult.GasWanted, 203 GasUsed: res.TxResult.GasUsed, 204 Tx: tx, 205 Timestamp: timestamp, 206 } 207 } 208 209 // NewResponseFormatBroadcastTxCommit returns a TxResponse given a 210 // ResultBroadcastTxCommit from tendermint. 211 func NewResponseFormatBroadcastTxCommit(res *ctypes.ResultBroadcastTxCommit) TxResponse { 212 if res == nil { 213 return TxResponse{} 214 } 215 216 if !res.CheckTx.IsOK() { 217 return newTxResponseCheckTx(res) 218 } 219 220 return newTxResponseDeliverTx(res) 221 } 222 223 func newTxResponseCheckTx(res *ctypes.ResultBroadcastTxCommit) TxResponse { 224 if res == nil { 225 return TxResponse{} 226 } 227 228 var txHash string 229 if res.Hash != nil { 230 txHash = res.Hash.String() 231 } 232 233 parsedLogs, _ := ParseABCILogs(res.CheckTx.Log) 234 235 return TxResponse{ 236 Height: res.Height, 237 TxHash: txHash, 238 Codespace: res.CheckTx.Codespace, 239 Code: res.CheckTx.Code, 240 Data: strings.ToUpper(hex.EncodeToString(res.CheckTx.Data)), 241 RawLog: res.CheckTx.Log, 242 Logs: parsedLogs, 243 Info: res.CheckTx.Info, 244 GasWanted: res.CheckTx.GasWanted, 245 GasUsed: res.CheckTx.GasUsed, 246 } 247 } 248 249 func newTxResponseDeliverTx(res *ctypes.ResultBroadcastTxCommit) TxResponse { 250 if res == nil { 251 return TxResponse{} 252 } 253 254 var txHash string 255 if res.Hash != nil { 256 txHash = res.Hash.String() 257 } 258 259 parsedLogs, _ := ParseABCILogs(res.DeliverTx.Log) 260 261 return TxResponse{ 262 Height: res.Height, 263 TxHash: txHash, 264 Codespace: res.DeliverTx.Codespace, 265 Code: res.DeliverTx.Code, 266 Data: strings.ToUpper(hex.EncodeToString(res.DeliverTx.Data)), 267 RawLog: res.DeliverTx.Log, 268 Logs: parsedLogs, 269 Info: res.DeliverTx.Info, 270 GasWanted: res.DeliverTx.GasWanted, 271 GasUsed: res.DeliverTx.GasUsed, 272 } 273 } 274 275 // NewResponseFormatBroadcastTx returns a TxResponse given a ResultBroadcastTx from tendermint 276 func NewResponseFormatBroadcastTx(res *ctypes.ResultBroadcastTx) TxResponse { 277 if res == nil { 278 return TxResponse{} 279 } 280 281 parsedLogs, _ := ParseABCILogs(res.Log) 282 283 return TxResponse{ 284 Code: res.Code, 285 Data: res.Data.String(), 286 RawLog: res.Log, 287 Logs: parsedLogs, 288 TxHash: res.Hash.String(), 289 } 290 } 291 292 func (r TxResponse) String() string { 293 var sb strings.Builder 294 sb.WriteString("Response:\n") 295 296 if r.Height > 0 { 297 sb.WriteString(fmt.Sprintf(" Height: %d\n", r.Height)) 298 } 299 if r.TxHash != "" { 300 sb.WriteString(fmt.Sprintf(" TxHash: %s\n", r.TxHash)) 301 } 302 if r.Code > 0 { 303 sb.WriteString(fmt.Sprintf(" Code: %d\n", r.Code)) 304 } 305 if r.Data != "" { 306 sb.WriteString(fmt.Sprintf(" Data: %s\n", r.Data)) 307 } 308 if r.RawLog != "" { 309 sb.WriteString(fmt.Sprintf(" Raw Log: %s\n", r.RawLog)) 310 } 311 if r.Logs != nil { 312 sb.WriteString(fmt.Sprintf(" Logs: %s\n", r.Logs)) 313 } 314 if r.Info != "" { 315 sb.WriteString(fmt.Sprintf(" Info: %s\n", r.Info)) 316 } 317 if r.GasWanted != 0 { 318 sb.WriteString(fmt.Sprintf(" GasWanted: %d\n", r.GasWanted)) 319 } 320 if r.GasUsed != 0 { 321 sb.WriteString(fmt.Sprintf(" GasUsed: %d\n", r.GasUsed)) 322 } 323 if r.Codespace != "" { 324 sb.WriteString(fmt.Sprintf(" Codespace: %s\n", r.Codespace)) 325 } 326 if r.Timestamp != "" { 327 sb.WriteString(fmt.Sprintf(" Timestamp: %s\n", r.Timestamp)) 328 } 329 330 return strings.TrimSpace(sb.String()) 331 } 332 333 // Empty returns true if the response is empty 334 func (r TxResponse) Empty() bool { 335 return r.TxHash == "" && r.Logs == nil 336 } 337 338 // SearchTxsResult defines a structure for querying txs pageable 339 type SearchTxsResult struct { 340 TotalCount int `json:"total_count"` // Count of all txs 341 Count int `json:"count"` // Count of txs in current page 342 PageNumber int `json:"page_number"` // Index of current page, start from 1 343 PageTotal int `json:"page_total"` // Count of total pages 344 Limit int `json:"limit"` // Max count txs per page 345 Txs []TxResponse `json:"txs"` // List of txs in current page 346 } 347 348 func NewSearchTxsResult(totalCount, count, page, limit int, txs []TxResponse) SearchTxsResult { 349 return SearchTxsResult{ 350 TotalCount: totalCount, 351 Count: count, 352 PageNumber: page, 353 PageTotal: int(math.Ceil(float64(totalCount) / float64(limit))), 354 Limit: limit, 355 Txs: txs, 356 } 357 } 358 359 // ParseABCILogs attempts to parse a stringified ABCI tx log into a slice of 360 // ABCIMessageLog types. It returns an error upon JSON decoding failure. 361 func ParseABCILogs(logs string) (res ABCIMessageLogs, err error) { 362 err = json.Unmarshal([]byte(logs), &res) 363 return res, err 364 } 365 366 // WrapServiceResult wraps a result from a protobuf RPC service method call in 367 // a Result object or error. This method takes care of marshaling the res param to 368 // protobuf and attaching any events on the ctx.EventManager() to the Result. 369 func WrapServiceResult(ctx Context, res proto.Message, err error) (*Result, error) { 370 if err != nil { 371 return nil, err 372 } 373 374 var data []byte 375 if res != nil { 376 data, err = proto.Marshal(res) 377 if err != nil { 378 return nil, err 379 } 380 } 381 382 var events []Event 383 if evtMgr := ctx.EventManager(); evtMgr != nil { 384 events = evtMgr.Events() 385 } 386 387 return &Result{ 388 Data: data, 389 Events: events, 390 }, nil 391 }