github.com/cosmos/cosmos-sdk@v0.50.10/client/rpc/block.go (about)

     1  package rpc
     2  
     3  import (
     4  	"context"
     5  	"encoding/hex"
     6  	"fmt"
     7  	"time"
     8  
     9  	cmt "github.com/cometbft/cometbft/proto/tendermint/types"
    10  	coretypes "github.com/cometbft/cometbft/rpc/core/types"
    11  
    12  	"github.com/cosmos/cosmos-sdk/client"
    13  	sdk "github.com/cosmos/cosmos-sdk/types"
    14  )
    15  
    16  // GetChainHeight returns the current blockchain height.
    17  func GetChainHeight(clientCtx client.Context) (int64, error) {
    18  	node, err := clientCtx.GetNode()
    19  	if err != nil {
    20  		return -1, err
    21  	}
    22  
    23  	status, err := node.Status(context.Background())
    24  	if err != nil {
    25  		return -1, err
    26  	}
    27  
    28  	height := status.SyncInfo.LatestBlockHeight
    29  	return height, nil
    30  }
    31  
    32  // QueryBlocks performs a search for blocks based on BeginBlock and EndBlock
    33  // events via the CometBFT RPC. A custom query may be passed as described below:
    34  //
    35  // To tell which events you want, you need to provide a query. query is a
    36  // string, which has a form: "condition AND condition ..." (no OR at the
    37  // 	moment). condition has a form: "key operation operand". key is a string with
    38  // 	a restricted set of possible symbols ( \t\n\r\\()"'=>< are not allowed).
    39  // 	operation can be "=", "<", "<=", ">", ">=", "CONTAINS" AND "EXISTS". operand
    40  // 	can be a string (escaped with single quotes), number, date or time.
    41  
    42  //	Examples:
    43  //		  tm.event = 'NewBlock'               # new blocks
    44  //		  tm.event = 'CompleteProposal'       # node got a complete proposal
    45  //		  tm.event = 'Tx' AND tx.hash = 'XYZ' # single transaction
    46  //		  tm.event = 'Tx' AND tx.height = 5   # all txs of the fifth block
    47  //		  tx.height = 5                       # all txs of the fifth block
    48  //
    49  // For more information, see the /subscribe CometBFT RPC endpoint documentation
    50  func QueryBlocks(clientCtx client.Context, page, limit int, query, orderBy string) (*sdk.SearchBlocksResult, error) {
    51  	node, err := clientCtx.GetNode()
    52  	if err != nil {
    53  		return nil, err
    54  	}
    55  
    56  	resBlocks, err := node.BlockSearch(context.Background(), query, &page, &limit, orderBy)
    57  	if err != nil {
    58  		return nil, err
    59  	}
    60  
    61  	blocks, err := formatBlockResults(resBlocks.Blocks)
    62  	if err != nil {
    63  		return nil, err
    64  	}
    65  
    66  	result := sdk.NewSearchBlocksResult(int64(resBlocks.TotalCount), int64(len(blocks)), int64(page), int64(limit), blocks)
    67  
    68  	return result, nil
    69  }
    70  
    71  // get block by height
    72  func GetBlockByHeight(clientCtx client.Context, height *int64) (*cmt.Block, error) {
    73  	// get the node
    74  	node, err := clientCtx.GetNode()
    75  	if err != nil {
    76  		return nil, err
    77  	}
    78  
    79  	// header -> BlockchainInfo
    80  	// header, tx -> Block
    81  	// results -> BlockResults
    82  	resBlock, err := node.Block(context.Background(), height)
    83  	if err != nil {
    84  		return nil, err
    85  	}
    86  
    87  	out := sdk.NewResponseResultBlock(resBlock, resBlock.Block.Time.Format(time.RFC3339))
    88  	if out == nil {
    89  		return nil, fmt.Errorf("unable to create response block from comet result block: %v", resBlock)
    90  	}
    91  
    92  	return out, nil
    93  }
    94  
    95  func GetBlockByHash(clientCtx client.Context, hashHexString string) (*cmt.Block, error) {
    96  	hash, err := hex.DecodeString(hashHexString)
    97  	if err != nil {
    98  		return nil, err
    99  	}
   100  
   101  	// get the node
   102  	node, err := clientCtx.GetNode()
   103  	if err != nil {
   104  		return nil, err
   105  	}
   106  
   107  	resBlock, err := node.BlockByHash(context.Background(), hash)
   108  
   109  	if err != nil {
   110  		return nil, err
   111  	} else if resBlock.Block == nil {
   112  		return nil, fmt.Errorf("block not found with hash: %s", hashHexString)
   113  	}
   114  
   115  	out := sdk.NewResponseResultBlock(resBlock, resBlock.Block.Time.Format(time.RFC3339))
   116  	if out == nil {
   117  		return nil, fmt.Errorf("unable to create response block from comet result block: %v", resBlock)
   118  	}
   119  
   120  	return out, nil
   121  }
   122  
   123  // formatBlockResults parses the indexed blocks into a slice of BlockResponse objects.
   124  func formatBlockResults(resBlocks []*coretypes.ResultBlock) ([]*cmt.Block, error) {
   125  	out := make([]*cmt.Block, len(resBlocks))
   126  	for i := range resBlocks {
   127  		out[i] = sdk.NewResponseResultBlock(resBlocks[i], resBlocks[i].Block.Time.Format(time.RFC3339))
   128  		if out[i] == nil {
   129  			return nil, fmt.Errorf("unable to create response block from comet result block: %v", resBlocks[i])
   130  		}
   131  	}
   132  
   133  	return out, nil
   134  }