github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/client/rpc/block.go (about)

     1  package rpc
     2  
     3  import (
     4  	"fmt"
     5  	"net/http"
     6  	"strconv"
     7  
     8  	"github.com/gorilla/mux"
     9  	"github.com/spf13/cobra"
    10  	"github.com/spf13/viper"
    11  
    12  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/client/context"
    13  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/client/flags"
    14  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/codec"
    15  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/rest"
    16  
    17  	tmliteProxy "github.com/fibonacci-chain/fbc/libs/tendermint/lite/proxy"
    18  )
    19  
    20  // BlockCommand returns the verified block data for a given heights
    21  func BlockCommand() *cobra.Command {
    22  	cmd := &cobra.Command{
    23  		Use:   "block [height]",
    24  		Short: "Get verified data for a the block at given height",
    25  		Args:  cobra.MaximumNArgs(1),
    26  		RunE:  printBlock,
    27  	}
    28  	cmd.Flags().StringP(flags.FlagNode, "n", "tcp://localhost:26657", "Node to connect to")
    29  	viper.BindPFlag(flags.FlagNode, cmd.Flags().Lookup(flags.FlagNode))
    30  	cmd.Flags().Bool(flags.FlagTrustNode, false, flags.TrustNodeUsage)
    31  	viper.BindPFlag(flags.FlagTrustNode, cmd.Flags().Lookup(flags.FlagTrustNode))
    32  	return cmd
    33  }
    34  
    35  func getBlock(cliCtx context.CLIContext, height *int64) ([]byte, error) {
    36  	// get the node
    37  	node, err := cliCtx.GetNode()
    38  	if err != nil {
    39  		return nil, err
    40  	}
    41  
    42  	// header -> BlockchainInfo
    43  	// header, tx -> Block
    44  	// results -> BlockResults
    45  	res, err := node.Block(height)
    46  	if err != nil {
    47  		return nil, err
    48  	}
    49  
    50  	if !cliCtx.TrustNode {
    51  		check, err := cliCtx.Verify(res.Block.Height)
    52  		if err != nil {
    53  			return nil, err
    54  		}
    55  
    56  		if err := tmliteProxy.ValidateHeader(&res.Block.Header, check); err != nil {
    57  			return nil, err
    58  		}
    59  
    60  		if err = tmliteProxy.ValidateBlock(res.Block, check); err != nil {
    61  			return nil, err
    62  		}
    63  	}
    64  
    65  	if cliCtx.Indent {
    66  		return codec.Cdc.MarshalJSONIndent(res, "", "  ")
    67  	}
    68  
    69  	return codec.Cdc.MarshalJSON(res)
    70  }
    71  
    72  func getBlockInfo(cliCtx context.CLIContext, height *int64) ([]byte, error) {
    73  	// get the node
    74  	node, err := cliCtx.GetNode()
    75  	if err != nil {
    76  		return nil, err
    77  	}
    78  
    79  	// header -> BlockchainInfo
    80  	// header, tx -> Block
    81  	// results -> BlockResults
    82  	res, err := node.BlockInfo(height)
    83  	if err != nil {
    84  		return nil, err
    85  	}
    86  
    87  	if !cliCtx.TrustNode {
    88  		check, err := cliCtx.Verify(res.Header.Height)
    89  		if err != nil {
    90  			return nil, err
    91  		}
    92  
    93  		if err := tmliteProxy.ValidateHeader(&res.Header, check); err != nil {
    94  			return nil, err
    95  		}
    96  	}
    97  
    98  	if cliCtx.Indent {
    99  		return codec.Cdc.MarshalJSONIndent(res, "", "  ")
   100  	}
   101  
   102  	return codec.Cdc.MarshalJSON(res)
   103  }
   104  
   105  // get the current blockchain height
   106  func GetChainHeight(cliCtx context.CLIContext) (int64, error) {
   107  	node, err := cliCtx.GetNode()
   108  	if err != nil {
   109  		return -1, err
   110  	}
   111  
   112  	status, err := node.Status()
   113  	if err != nil {
   114  		return -1, err
   115  	}
   116  
   117  	height := status.SyncInfo.LatestBlockHeight
   118  	return height, nil
   119  }
   120  
   121  // CMD
   122  
   123  func printBlock(cmd *cobra.Command, args []string) error {
   124  	var height *int64
   125  	// optional height
   126  	if len(args) > 0 {
   127  		h, err := strconv.Atoi(args[0])
   128  		if err != nil {
   129  			return err
   130  		}
   131  		if h > 0 {
   132  			tmp := int64(h)
   133  			height = &tmp
   134  		}
   135  	}
   136  
   137  	output, err := getBlock(context.NewCLIContext(), height)
   138  	if err != nil {
   139  		return err
   140  	}
   141  
   142  	fmt.Println(string(output))
   143  	return nil
   144  }
   145  
   146  // REST
   147  // REST handler to get a block info
   148  func BlockInfoRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
   149  	return func(w http.ResponseWriter, r *http.Request) {
   150  		vars := mux.Vars(r)
   151  
   152  		height, err := strconv.ParseInt(vars["height"], 10, 64)
   153  		if err != nil {
   154  			rest.WriteErrorResponse(w, http.StatusBadRequest,
   155  				"couldn't parse block height. Assumed format is '/block/{height}'.")
   156  			return
   157  		}
   158  
   159  		chainHeight, err := GetChainHeight(cliCtx)
   160  		if err != nil {
   161  			rest.WriteErrorResponse(w, http.StatusInternalServerError, "failed to parse chain height")
   162  			return
   163  		}
   164  
   165  		if height > chainHeight {
   166  			rest.WriteErrorResponse(w, http.StatusNotFound, "requested block height is bigger then the chain length")
   167  			return
   168  		}
   169  
   170  		output, err := getBlockInfo(cliCtx, &height)
   171  		if err != nil {
   172  			rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
   173  			return
   174  		}
   175  
   176  		rest.PostProcessResponseBare(w, cliCtx, output)
   177  	}
   178  }
   179  
   180  // REST handler to get a block
   181  func BlockRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
   182  	return func(w http.ResponseWriter, r *http.Request) {
   183  		vars := mux.Vars(r)
   184  
   185  		height, err := strconv.ParseInt(vars["height"], 10, 64)
   186  		if err != nil {
   187  			rest.WriteErrorResponse(w, http.StatusBadRequest,
   188  				"couldn't parse block height. Assumed format is '/block/{height}'.")
   189  			return
   190  		}
   191  
   192  		chainHeight, err := GetChainHeight(cliCtx)
   193  		if err != nil {
   194  			rest.WriteErrorResponse(w, http.StatusInternalServerError, "failed to parse chain height")
   195  			return
   196  		}
   197  
   198  		if height > chainHeight {
   199  			rest.WriteErrorResponse(w, http.StatusNotFound, "requested block height is bigger then the chain length")
   200  			return
   201  		}
   202  
   203  		output, err := getBlock(cliCtx, &height)
   204  		if err != nil {
   205  			rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
   206  			return
   207  		}
   208  
   209  		rest.PostProcessResponseBare(w, cliCtx, output)
   210  	}
   211  }
   212  
   213  // REST handler to get the latest block
   214  func LatestBlockRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
   215  	return func(w http.ResponseWriter, r *http.Request) {
   216  		output, err := getBlock(cliCtx, nil)
   217  		if err != nil {
   218  			rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
   219  			return
   220  		}
   221  
   222  		rest.PostProcessResponseBare(w, cliCtx, output)
   223  	}
   224  }