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  }