github.com/badrootd/nibiru-cometbft@v0.37.5-0.20240307173500-2a75559eee9b/rpc/core/tx.go (about) 1 package core 2 3 import ( 4 "errors" 5 "fmt" 6 "sort" 7 8 cmtmath "github.com/badrootd/nibiru-cometbft/libs/math" 9 cmtquery "github.com/badrootd/nibiru-cometbft/libs/pubsub/query" 10 ctypes "github.com/badrootd/nibiru-cometbft/rpc/core/types" 11 rpctypes "github.com/badrootd/nibiru-cometbft/rpc/jsonrpc/types" 12 "github.com/badrootd/nibiru-cometbft/state/txindex/null" 13 "github.com/badrootd/nibiru-cometbft/types" 14 ) 15 16 // Tx allows you to query the transaction results. `nil` could mean the 17 // transaction is in the mempool, invalidated, or was not sent in the first 18 // place. 19 // More: https://docs.cometbft.com/v0.37/rpc/#/Info/tx 20 func Tx(ctx *rpctypes.Context, hash []byte, prove bool) (*ctypes.ResultTx, error) { 21 // if index is disabled, return error 22 if _, ok := env.TxIndexer.(*null.TxIndex); ok { 23 return nil, fmt.Errorf("transaction indexing is disabled") 24 } 25 26 r, err := env.TxIndexer.Get(hash) 27 if err != nil { 28 return nil, err 29 } 30 31 if r == nil { 32 return nil, fmt.Errorf("tx (%X) not found", hash) 33 } 34 35 var proof types.TxProof 36 if prove { 37 block := env.BlockStore.LoadBlock(r.Height) 38 proof = block.Data.Txs.Proof(int(r.Index)) 39 } 40 41 return &ctypes.ResultTx{ 42 Hash: hash, 43 Height: r.Height, 44 Index: r.Index, 45 TxResult: r.Result, 46 Tx: r.Tx, 47 Proof: proof, 48 }, nil 49 } 50 51 // TxSearch allows you to query for multiple transactions results. It returns a 52 // list of transactions (maximum ?per_page entries) and the total count. 53 // More: https://docs.cometbft.com/v0.37/rpc/#/Info/tx_search 54 func TxSearch( 55 ctx *rpctypes.Context, 56 query string, 57 prove bool, 58 pagePtr, perPagePtr *int, 59 orderBy string, 60 ) (*ctypes.ResultTxSearch, error) { 61 // if index is disabled, return error 62 if _, ok := env.TxIndexer.(*null.TxIndex); ok { 63 return nil, errors.New("transaction indexing is disabled") 64 } else if len(query) > maxQueryLength { 65 return nil, errors.New("maximum query length exceeded") 66 } 67 68 q, err := cmtquery.New(query) 69 if err != nil { 70 return nil, err 71 } 72 73 results, err := env.TxIndexer.Search(ctx.Context(), q) 74 if err != nil { 75 return nil, err 76 } 77 78 // sort results (must be done before pagination) 79 switch orderBy { 80 case "desc": 81 sort.Slice(results, func(i, j int) bool { 82 if results[i].Height == results[j].Height { 83 return results[i].Index > results[j].Index 84 } 85 return results[i].Height > results[j].Height 86 }) 87 case "asc", "": 88 sort.Slice(results, func(i, j int) bool { 89 if results[i].Height == results[j].Height { 90 return results[i].Index < results[j].Index 91 } 92 return results[i].Height < results[j].Height 93 }) 94 default: 95 return nil, errors.New("expected order_by to be either `asc` or `desc` or empty") 96 } 97 98 // paginate results 99 totalCount := len(results) 100 perPage := validatePerPage(perPagePtr) 101 102 page, err := validatePage(pagePtr, perPage, totalCount) 103 if err != nil { 104 return nil, err 105 } 106 107 skipCount := validateSkipCount(page, perPage) 108 pageSize := cmtmath.MinInt(perPage, totalCount-skipCount) 109 110 apiResults := make([]*ctypes.ResultTx, 0, pageSize) 111 for i := skipCount; i < skipCount+pageSize; i++ { 112 r := results[i] 113 114 var proof types.TxProof 115 if prove { 116 block := env.BlockStore.LoadBlock(r.Height) 117 proof = block.Data.Txs.Proof(int(r.Index)) 118 } 119 120 apiResults = append(apiResults, &ctypes.ResultTx{ 121 Hash: types.Tx(r.Tx).Hash(), 122 Height: r.Height, 123 Index: r.Index, 124 TxResult: r.Result, 125 Tx: r.Tx, 126 Proof: proof, 127 }) 128 } 129 130 return &ctypes.ResultTxSearch{Txs: apiResults, TotalCount: totalCount}, nil 131 }