github.com/ari-anchor/sei-tendermint@v0.0.0-20230519144642-dc826b7b56bb/internal/rpc/core/tx.go (about)

     1  package core
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"sort"
     8  
     9  	tmquery "github.com/ari-anchor/sei-tendermint/internal/pubsub/query"
    10  	"github.com/ari-anchor/sei-tendermint/internal/state/indexer"
    11  	tmmath "github.com/ari-anchor/sei-tendermint/libs/math"
    12  	"github.com/ari-anchor/sei-tendermint/rpc/coretypes"
    13  	"github.com/ari-anchor/sei-tendermint/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.tendermint.com/master/rpc/#/Info/tx
    20  func (env *Environment) Tx(ctx context.Context, req *coretypes.RequestTx) (*coretypes.ResultTx, error) {
    21  	// if index is disabled, return error
    22  	if !indexer.KVSinkEnabled(env.EventSinks) {
    23  		return nil, errors.New("transaction querying is disabled due to no kvEventSink")
    24  	}
    25  
    26  	for _, sink := range env.EventSinks {
    27  		if sink.Type() == indexer.KV {
    28  			r, err := sink.GetTxByHash(req.Hash)
    29  			if r == nil {
    30  				return nil, fmt.Errorf("tx (%X) not found, err: %w", req.Hash, err)
    31  			}
    32  
    33  			var proof types.TxProof
    34  			if req.Prove {
    35  				block := env.BlockStore.LoadBlock(r.Height)
    36  				proof = block.Data.Txs.Proof(int(r.Index))
    37  			}
    38  
    39  			return &coretypes.ResultTx{
    40  				Hash:     req.Hash,
    41  				Height:   r.Height,
    42  				Index:    r.Index,
    43  				TxResult: r.Result,
    44  				Tx:       r.Tx,
    45  				Proof:    proof,
    46  			}, nil
    47  		}
    48  	}
    49  
    50  	return nil, fmt.Errorf("transaction querying is disabled on this node due to the KV event sink being disabled")
    51  }
    52  
    53  // TxSearch allows you to query for multiple transactions results. It returns a
    54  // list of transactions (maximum ?per_page entries) and the total count.
    55  // More: https://docs.tendermint.com/master/rpc/#/Info/tx_search
    56  func (env *Environment) TxSearch(ctx context.Context, req *coretypes.RequestTxSearch) (*coretypes.ResultTxSearch, error) {
    57  	if !indexer.KVSinkEnabled(env.EventSinks) {
    58  		return nil, fmt.Errorf("transaction searching is disabled due to no kvEventSink")
    59  	} else if len(req.Query) > maxQueryLength {
    60  		return nil, errors.New("maximum query length exceeded")
    61  	}
    62  
    63  	q, err := tmquery.New(req.Query)
    64  	if err != nil {
    65  		return nil, err
    66  	}
    67  
    68  	for _, sink := range env.EventSinks {
    69  		if sink.Type() == indexer.KV {
    70  			results, err := sink.SearchTxEvents(ctx, q)
    71  			if err != nil {
    72  				return nil, err
    73  			}
    74  
    75  			// sort results (must be done before pagination)
    76  			switch req.OrderBy {
    77  			case "desc", "":
    78  				sort.Slice(results, func(i, j int) bool {
    79  					if results[i].Height == results[j].Height {
    80  						return results[i].Index > results[j].Index
    81  					}
    82  					return results[i].Height > results[j].Height
    83  				})
    84  			case "asc":
    85  				sort.Slice(results, func(i, j int) bool {
    86  					if results[i].Height == results[j].Height {
    87  						return results[i].Index < results[j].Index
    88  					}
    89  					return results[i].Height < results[j].Height
    90  				})
    91  			default:
    92  				return nil, fmt.Errorf("expected order_by to be either `asc` or `desc` or empty: %w", coretypes.ErrInvalidRequest)
    93  			}
    94  
    95  			// paginate results
    96  			totalCount := len(results)
    97  			perPage := env.validatePerPage(req.PerPage.IntPtr())
    98  
    99  			page, err := validatePage(req.Page.IntPtr(), perPage, totalCount)
   100  			if err != nil {
   101  				return nil, err
   102  			}
   103  
   104  			skipCount := validateSkipCount(page, perPage)
   105  			pageSize := tmmath.MinInt(perPage, totalCount-skipCount)
   106  
   107  			apiResults := make([]*coretypes.ResultTx, 0, pageSize)
   108  			for i := skipCount; i < skipCount+pageSize; i++ {
   109  				r := results[i]
   110  
   111  				var proof types.TxProof
   112  				if req.Prove {
   113  					block := env.BlockStore.LoadBlock(r.Height)
   114  					proof = block.Data.Txs.Proof(int(r.Index))
   115  				}
   116  
   117  				apiResults = append(apiResults, &coretypes.ResultTx{
   118  					Hash:     types.Tx(r.Tx).Hash(),
   119  					Height:   r.Height,
   120  					Index:    r.Index,
   121  					TxResult: r.Result,
   122  					Tx:       r.Tx,
   123  					Proof:    proof,
   124  				})
   125  			}
   126  
   127  			return &coretypes.ResultTxSearch{Txs: apiResults, TotalCount: totalCount}, nil
   128  		}
   129  	}
   130  
   131  	return nil, fmt.Errorf("transaction searching is disabled on this node due to the KV event sink being disabled")
   132  }