135 lines
3.9 KiB
Go
135 lines
3.9 KiB
Go
package rpc
|
|
|
|
import (
|
|
"context"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"time"
|
|
|
|
cmt "github.com/cometbft/cometbft/api/cometbft/types/v1"
|
|
coretypes "github.com/cometbft/cometbft/rpc/core/types"
|
|
|
|
"github.com/cosmos/cosmos-sdk/client"
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
)
|
|
|
|
// GetChainHeight returns the current blockchain height.
|
|
func GetChainHeight(clientCtx client.Context) (int64, error) {
|
|
node, err := clientCtx.GetNode()
|
|
if err != nil {
|
|
return -1, err
|
|
}
|
|
|
|
status, err := node.Status(context.Background())
|
|
if err != nil {
|
|
return -1, err
|
|
}
|
|
|
|
height := status.SyncInfo.LatestBlockHeight
|
|
return height, nil
|
|
}
|
|
|
|
// QueryBlocks performs a search for blocks based on BeginBlock and EndBlock
|
|
// events via the CometBFT RPC. A custom query may be passed as described below:
|
|
//
|
|
// To tell which events you want, you need to provide a query. query is a
|
|
// string, which has a form: "condition AND condition ..." (no OR at the
|
|
// moment). condition has a form: "key operation operand". key is a string with
|
|
// a restricted set of possible symbols ( \t\n\r\\()"'=>< are not allowed).
|
|
// operation can be "=", "<", "<=", ">", ">=", "CONTAINS" AND "EXISTS". operand
|
|
// can be a string (escaped with single quotes), number, date or time.
|
|
|
|
// Examples:
|
|
// tm.event = 'NewBlock' # new blocks
|
|
// tm.event = 'CompleteProposal' # node got a complete proposal
|
|
// tm.event = 'Tx' AND tx.hash = 'XYZ' # single transaction
|
|
// tm.event = 'Tx' AND tx.height = 5 # all txs of the fifth block
|
|
// tx.height = 5 # all txs of the fifth block
|
|
//
|
|
// For more information, see the /subscribe CometBFT RPC endpoint documentation
|
|
func QueryBlocks(clientCtx client.Context, page, limit int, query, orderBy string) (*sdk.SearchBlocksResult, error) {
|
|
node, err := clientCtx.GetNode()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
resBlocks, err := node.BlockSearch(context.Background(), query, &page, &limit, orderBy)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
blocks, err := formatBlockResults(resBlocks.Blocks)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
result := sdk.NewSearchBlocksResult(int64(resBlocks.TotalCount), int64(len(blocks)), int64(page), int64(limit), blocks)
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// GetBlockByHeight get block by height
|
|
func GetBlockByHeight(clientCtx client.Context, height *int64) (*cmt.Block, error) {
|
|
// get the node
|
|
node, err := clientCtx.GetNode()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// header -> BlockchainInfo
|
|
// header, tx -> Block
|
|
// results -> BlockResults
|
|
resBlock, err := node.Block(context.Background(), height)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
out := sdk.NewResponseResultBlock(resBlock, resBlock.Block.Time.Format(time.RFC3339))
|
|
if out == nil {
|
|
return nil, fmt.Errorf("unable to create response block from comet result block: %v", resBlock)
|
|
}
|
|
|
|
return out, nil
|
|
}
|
|
|
|
func GetBlockByHash(clientCtx client.Context, hashHexString string) (*cmt.Block, error) {
|
|
hash, err := hex.DecodeString(hashHexString)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// get the node
|
|
node, err := clientCtx.GetNode()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
resBlock, err := node.BlockByHash(context.Background(), hash)
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
} else if resBlock.Block == nil {
|
|
return nil, fmt.Errorf("block not found with hash: %s", hashHexString)
|
|
}
|
|
|
|
out := sdk.NewResponseResultBlock(resBlock, resBlock.Block.Time.Format(time.RFC3339))
|
|
if out == nil {
|
|
return nil, fmt.Errorf("unable to create response block from comet result block: %v", resBlock)
|
|
}
|
|
|
|
return out, nil
|
|
}
|
|
|
|
// formatBlockResults parses the indexed blocks into a slice of BlockResponse objects.
|
|
func formatBlockResults(resBlocks []*coretypes.ResultBlock) ([]*cmt.Block, error) {
|
|
out := make([]*cmt.Block, len(resBlocks))
|
|
for i := range resBlocks {
|
|
out[i] = sdk.NewResponseResultBlock(resBlocks[i], resBlocks[i].Block.Time.Format(time.RFC3339))
|
|
if out[i] == nil {
|
|
return nil, fmt.Errorf("unable to create response block from comet result block: %v", resBlocks[i])
|
|
}
|
|
}
|
|
|
|
return out, nil
|
|
}
|