github.com/lino-network/lino@v0.6.11/client/blockchain/query.go (about)

     1  package blockchain
     2  
     3  import (
     4  	"encoding/hex"
     5  	"fmt"
     6  	"strconv"
     7  	"strings"
     8  	"time"
     9  
    10  	"github.com/cosmos/cosmos-sdk/client"
    11  	"github.com/cosmos/cosmos-sdk/client/context"
    12  	"github.com/cosmos/cosmos-sdk/client/rpc"
    13  	"github.com/cosmos/cosmos-sdk/codec"
    14  	sdk "github.com/cosmos/cosmos-sdk/types"
    15  	txutils "github.com/cosmos/cosmos-sdk/x/auth/client/utils"
    16  	"github.com/spf13/cobra"
    17  	tmliteProxy "github.com/tendermint/tendermint/lite/proxy"
    18  	ctypes "github.com/tendermint/tendermint/rpc/core/types"
    19  
    20  	// "github.com/lino-network/lino/utils"
    21  
    22  	linotypes "github.com/lino-network/lino/types"
    23  )
    24  
    25  func GetQueryCmd(cdc *codec.Codec) *cobra.Command {
    26  	cmd := &cobra.Command{
    27  		Use:                        "blockchain",
    28  		Short:                      "Blockchain-related Queries",
    29  		DisableFlagParsing:         true,
    30  		SuggestionsMinimumDistance: 2,
    31  		RunE:                       client.ValidateCmd,
    32  	}
    33  	cmd.AddCommand(
    34  		// txutils.QueryTxCmd(cdc),
    35  		rpc.ValidatorCommand(cdc),
    36  		rpc.BlockCommand(),
    37  	)
    38  	cmd.AddCommand(client.GetCommands(
    39  		getCmdTx(cdc),
    40  		getCmdHeight(cdc),
    41  		getCmdMessage(cdc),
    42  	)...)
    43  	return cmd
    44  }
    45  
    46  // GetCmdHeight -
    47  func getCmdHeight(cdc *codec.Codec) *cobra.Command {
    48  	return &cobra.Command{
    49  		Use:   "height",
    50  		Short: "height current block height",
    51  		Args:  cobra.ExactArgs(0),
    52  		RunE: func(cmd *cobra.Command, args []string) error {
    53  			cliCtx := context.NewCLIContext().WithCodec(cdc)
    54  			height, err := rpc.GetChainHeight(cliCtx)
    55  			if err != nil {
    56  				return err
    57  			}
    58  			fmt.Println(height)
    59  			return nil
    60  		},
    61  	}
    62  }
    63  
    64  type MsgPrintLayout struct {
    65  	Hash string    `json:"hash"`
    66  	Msgs []sdk.Msg `json:"msgs"`
    67  }
    68  
    69  // GetCmdBlock -
    70  func getCmdMessage(cdc *codec.Codec) *cobra.Command {
    71  	return &cobra.Command{
    72  		Use:   "msg",
    73  		Short: "msg <block-height>, print messages and results of the block height",
    74  		Args:  cobra.MaximumNArgs(1),
    75  		RunE: func(cmd *cobra.Command, args []string) error {
    76  			cliCtx := context.NewCLIContext().WithCodec(cdc)
    77  			var height *int64
    78  			// optional height
    79  			if len(args) > 0 {
    80  				h, err := strconv.Atoi(args[0])
    81  				if err != nil {
    82  					return err
    83  				}
    84  				if h > 0 {
    85  					tmp := int64(h)
    86  					height = &tmp
    87  				}
    88  			}
    89  
    90  			// get the node
    91  			node, err := cliCtx.GetNode()
    92  			if err != nil {
    93  				return err
    94  			}
    95  
    96  			// header -> BlockchainInfo
    97  			// header, tx -> Block
    98  			// results -> BlockResults
    99  			res, err := node.Block(height)
   100  			if err != nil {
   101  				return err
   102  			}
   103  
   104  			if !cliCtx.TrustNode {
   105  				check, err := cliCtx.Verify(res.Block.Height)
   106  				if err != nil {
   107  					return err
   108  				}
   109  
   110  				err = tmliteProxy.ValidateBlockMeta(res.BlockMeta, check)
   111  				if err != nil {
   112  					return err
   113  				}
   114  
   115  				err = tmliteProxy.ValidateBlock(res.Block, check)
   116  				if err != nil {
   117  					return err
   118  				}
   119  			}
   120  
   121  			decoder := linotypes.TxDecoder(cdc)
   122  			var result []MsgPrintLayout
   123  			for _, txbytes := range res.Block.Data.Txs {
   124  				hexstr := hex.EncodeToString(txbytes.Hash())
   125  				hexstr = strings.ToUpper(hexstr)
   126  				tx, err := decoder(txbytes)
   127  				if err != nil {
   128  					return err
   129  				}
   130  				result = append(result, MsgPrintLayout{
   131  					Hash: hexstr,
   132  					Msgs: tx.GetMsgs(),
   133  				})
   134  			}
   135  			out, err := cdc.MarshalJSONIndent(result, "", "  ")
   136  			if err != nil {
   137  				return err
   138  			}
   139  			fmt.Println(string(out))
   140  
   141  			return nil
   142  		},
   143  	}
   144  }
   145  
   146  // GetCmdTx -
   147  func getCmdTx(cdc *codec.Codec) *cobra.Command {
   148  	return &cobra.Command{
   149  		Use:   "tx",
   150  		Short: "tx <hash>",
   151  		Args:  cobra.ExactArgs(1),
   152  		RunE: func(cmd *cobra.Command, args []string) error {
   153  			cliCtx := context.NewCLIContext().WithCodec(cdc)
   154  			hashHexStr := args[0]
   155  			hash, err := hex.DecodeString(hashHexStr)
   156  			if err != nil {
   157  				return err
   158  			}
   159  
   160  			node, err := cliCtx.GetNode()
   161  			if err != nil {
   162  				return err
   163  			}
   164  
   165  			resTx, err := node.Tx(hash, !cliCtx.TrustNode)
   166  			if err != nil {
   167  				return err
   168  			}
   169  
   170  			if !cliCtx.TrustNode {
   171  				if err = txutils.ValidateTxResult(cliCtx, resTx); err != nil {
   172  					return err
   173  				}
   174  			}
   175  
   176  			_ = printTx(cdc, resTx.Tx)
   177  
   178  			resBlocks, err := getBlocksForTxResults(cliCtx, []*ctypes.ResultTx{resTx})
   179  			if err != nil {
   180  				return err
   181  			}
   182  
   183  			out, err := formatTxResult(cliCtx.Codec, resTx, resBlocks[resTx.Height])
   184  			if err != nil {
   185  				return err
   186  			}
   187  
   188  			fmt.Println(out)
   189  			return nil
   190  		},
   191  	}
   192  }
   193  
   194  func getBlocksForTxResults(cliCtx context.CLIContext, resTxs []*ctypes.ResultTx) (map[int64]*ctypes.ResultBlock, error) {
   195  	node, err := cliCtx.GetNode()
   196  	if err != nil {
   197  		return nil, err
   198  	}
   199  
   200  	resBlocks := make(map[int64]*ctypes.ResultBlock)
   201  
   202  	for _, resTx := range resTxs {
   203  		if _, ok := resBlocks[resTx.Height]; !ok {
   204  			resBlock, err := node.Block(&resTx.Height)
   205  			if err != nil {
   206  				return nil, err
   207  			}
   208  
   209  			resBlocks[resTx.Height] = resBlock
   210  		}
   211  	}
   212  
   213  	return resBlocks, nil
   214  }
   215  
   216  func formatTxResult(cdc *codec.Codec, resTx *ctypes.ResultTx, resBlock *ctypes.ResultBlock) (sdk.TxResponse, error) {
   217  	tx, err := parseTx(linotypes.TxDecoder(cdc), resTx.Tx)
   218  	if err != nil {
   219  		return sdk.TxResponse{}, err
   220  	}
   221  
   222  	return sdk.NewResponseResultTx(resTx, tx, resBlock.Block.Time.Format(time.RFC3339)), nil
   223  }
   224  
   225  func parseTx(decoder sdk.TxDecoder, txBytes []byte) (sdk.Tx, error) {
   226  	tx, err := decoder(txBytes)
   227  	if err != nil {
   228  		return nil, err
   229  	}
   230  
   231  	return tx, nil
   232  }
   233  
   234  func printTx(cdc *codec.Codec, txBytes []byte) error {
   235  	decoder := linotypes.TxDecoder(cdc)
   236  	msg, err := decoder(txBytes)
   237  	if err != nil {
   238  		return err
   239  	}
   240  	out, err2 := cdc.MarshalJSONIndent(msg, "", "  ")
   241  	if err2 != nil {
   242  		return err
   243  	}
   244  	fmt.Println(string(out))
   245  	return nil
   246  }