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 }