Skip to content

Commit

Permalink
fix: TODO: use base64.URLEncoding to modify TestQueryBlockByHash (#711)
Browse files Browse the repository at this point in the history
* bugfix: use base64.URLEncoding on test and fix typo

* feature: add BlockByHashRequestHandlerFn on RPC

* bugfix

* fix: codecov
  • Loading branch information
tnasu authored Oct 14, 2022
1 parent fae516e commit 1e7db5c
Show file tree
Hide file tree
Showing 7 changed files with 135 additions and 60 deletions.
2 changes: 1 addition & 1 deletion client/grpc/tmservice/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ func (s queryServer) GetBlockByHash(_ context.Context, req *GetBlockByHashReques
if n == 0 {
return nil, status.Error(codes.InvalidArgument, "block hash cannot be empty")
}
return nil, status.Error(codes.InvalidArgument, "The length of blcok hash must be 32")
return nil, status.Error(codes.InvalidArgument, "the length of block hash must be 32")
}

res, err := getBlockByHash(s.clientCtx, req.Hash)
Expand Down
12 changes: 6 additions & 6 deletions client/grpc/tmservice/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package tmservice_test

import (
"context"
"encoding/base64"
"fmt"
"testing"

Expand Down Expand Up @@ -98,7 +99,7 @@ func (s IntegrationTestSuite) TestQueryBlockByHash() {
err string
}{
{blkhash, false, ""},
{bytes.HexBytes("wrong hash"), true, "The length of blcok hash must be 32: invalid request"},
{bytes.HexBytes("wrong hash"), true, "the length of block hash must be 32: invalid request"},
{bytes.HexBytes(""), true, "block hash cannot be empty"},
}

Expand All @@ -112,11 +113,10 @@ func (s IntegrationTestSuite) TestQueryBlockByHash() {
}
}

// TODO: Unlike gRPC, REST requests often fail. Need to understand the cause later
//restRes, err := rest.GetRequest(fmt.Sprintf("%s/lbm/base/ostracon/v1/block/%s", val.APIAddress, base64.StdEncoding.EncodeToString(blkhash)))
//s.Require().NoError(err)
//var blockInfoRes tmservice.GetBlockByHashResponse
//s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(restRes, &blockInfoRes))
restRes, err := rest.GetRequest(fmt.Sprintf("%s/lbm/base/ostracon/v1/block/%s", val.APIAddress, base64.URLEncoding.EncodeToString(blkhash)))
s.Require().NoError(err)
var blockInfoRes tmservice.GetBlockByHashResponse
s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(restRes, &blockInfoRes))
}

func (s IntegrationTestSuite) TestQueryBlockByHeight() {
Expand Down
49 changes: 48 additions & 1 deletion client/rpc/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package rpc

import (
"context"
"crypto/sha256"
"encoding/base64"
"fmt"
"net/http"
"strconv"
Expand Down Expand Up @@ -73,6 +75,24 @@ func getBlock(clientCtx client.Context, height *int64) ([]byte, error) {
return legacy.Cdc.MarshalJSON(res)
}

func getBlockByHash(clientCtx client.Context, hash []byte) ([]byte, error) {
// get the node
node, err := clientCtx.GetNode()
if err != nil {
return nil, err
}

// header -> BlockchainInfo
// header, tx -> Block
// results -> BlockResults
res, err := node.BlockByHash(context.Background(), hash)
if err != nil {
return nil, err
}

return legacy.Cdc.MarshalJSON(res)
}

// get the current blockchain height
func GetChainHeight(clientCtx client.Context) (int64, error) {
node, err := clientCtx.GetNode()
Expand All @@ -89,6 +109,33 @@ func GetChainHeight(clientCtx client.Context) (int64, error) {
return height, nil
}

// REST handler to get a block by hash
func BlockByHashRequestHandlerFn(clientCtx client.Context) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)

hash := vars["hash"]
blockHash, err := base64.URLEncoding.DecodeString(hash)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest,
"couldn't decode block hash by Base64URLDecode.")
return
}
if n := len(blockHash); n != sha256.Size {
rest.WriteErrorResponse(w, http.StatusBadRequest,
"the length of block hash must be 32")
return
}

output, err := getBlockByHash(clientCtx, blockHash)
if rest.CheckInternalServerError(w, err) {
return
}

rest.PostProcessResponseBare(w, clientCtx, output)
}
}

// REST handler to get a block
func BlockRequestHandlerFn(clientCtx client.Context) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
Expand All @@ -97,7 +144,7 @@ func BlockRequestHandlerFn(clientCtx client.Context) http.HandlerFunc {
height, err := strconv.ParseInt(vars["height"], 10, 64)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest,
"couldn't parse block height. Assumed format is '/block/{height}'.")
"couldn't parse block height. Assumed format is '/blocks/{height}'.")
return
}

Expand Down
1 change: 1 addition & 0 deletions client/rpc/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ func RegisterRoutes(clientCtx client.Context, r *mux.Router) {
r.HandleFunc("/syncing", NodeSyncingRequestHandlerFn(clientCtx)).Methods("GET")
r.HandleFunc("/blocks/latest", LatestBlockRequestHandlerFn(clientCtx)).Methods("GET")
r.HandleFunc("/blocks/{height}", BlockRequestHandlerFn(clientCtx)).Methods("GET")
r.HandleFunc("/block/{hash}", BlockByHashRequestHandlerFn(clientCtx)).Methods("GET")
r.HandleFunc("/validatorsets/latest", LatestValidatorSetRequestHandlerFn(clientCtx)).Methods("GET")
r.HandleFunc("/validatorsets/{height}", ValidatorSetRequestHandlerFn(clientCtx)).Methods("GET")
}
75 changes: 75 additions & 0 deletions client/rpc/rpc_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package rpc_test

import (
"encoding/base64"
"fmt"
"testing"

Expand Down Expand Up @@ -54,6 +55,80 @@ func (s *IntegrationTestSuite) TestLatestBlocks() {
var result ctypes.ResultBlock
err = legacy.Cdc.UnmarshalJSON(res, &result)
s.Require().NoError(err)

{
var result2 ctypes.ResultBlock
res, err := rest.GetRequest(fmt.Sprintf("%s/blocks/%d", val0.APIAddress, result.Block.Height))
s.Require().NoError(err)
err = legacy.Cdc.UnmarshalJSON(res, &result2)
s.Require().NoError(err)
s.Require().Equal(result, result2)
}
{
var result3 ctypes.ResultBlock
hash64 := base64.URLEncoding.EncodeToString(result.Block.Hash())
res, err := rest.GetRequest(fmt.Sprintf("%s/block/%s", val0.APIAddress, hash64))
s.Require().NoError(err)
err = legacy.Cdc.UnmarshalJSON(res, &result3)
s.Require().NoError(err)
s.Require().Equal(result, result3)
}
}

func (s *IntegrationTestSuite) TestBlockWithFailure() {
val0 := s.network.Validators[0]

tcs := []struct {
name string
height string
errRes string
}{
{
name: "parse error",
height: "a",
errRes: "{\"error\":\"couldn't parse block height. Assumed format is '/blocks/{height}'.\"}",
},
{
name: "bigger height error",
height: "1234567890",
errRes: "{\"error\":\"requested block height is bigger then the chain length\"}",
},
}
for _, tc := range tcs {
s.T().Run(tc.name, func(t *testing.T) {
res, err := rest.GetRequest(fmt.Sprintf("%s/blocks/%s", val0.APIAddress, tc.height))
s.Require().NoError(err)
s.Require().Equal(tc.errRes, string(res))
})
}
}

func (s *IntegrationTestSuite) TestBlockByHashWithFailure() {
val0 := s.network.Validators[0]

tcs := []struct {
name string
hash string
errRes string
}{
{
name: "base64 error",
hash: "wrong hash",
errRes: "{\"error\":\"couldn't decode block hash by Base64URLDecode.\"}",
},
{
name: "size error",
hash: base64.URLEncoding.EncodeToString([]byte{0}),
errRes: "{\"error\":\"the length of block hash must be 32\"}",
},
}
for _, tc := range tcs {
s.T().Run(tc.name, func(t *testing.T) {
res, err := rest.GetRequest(fmt.Sprintf("%s/block/%s", val0.APIAddress, tc.hash))
s.Require().NoError(err)
s.Require().Equal(tc.errRes, string(res))
})
}
}

func TestIntegrationTestSuite(t *testing.T) {
Expand Down
5 changes: 2 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ require (
github.com/tendermint/tm-db v0.6.7
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e
google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd
google.golang.org/grpc v1.48.0
google.golang.org/grpc v1.49.0
google.golang.org/protobuf v1.28.1
gopkg.in/yaml.v2 v2.4.0
)
Expand Down Expand Up @@ -122,7 +122,7 @@ require (
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/stretchr/objx v0.4.0 // indirect
github.com/subosito/gotenv v1.4.1 // indirect
github.com/tendermint/tendermint v0.34.19 // indirect
github.com/tendermint/tendermint v0.34.14 // indirect
github.com/zondax/hid v0.9.0 // indirect
go.etcd.io/bbolt v1.3.6 // indirect
golang.org/x/net v0.0.0-20220617184016-355a448f1bc9 // indirect
Expand All @@ -137,6 +137,5 @@ require (
replace (
github.com/99designs/keyring => github.com/cosmos/keyring v1.1.7-0.20210622111912-ef00f8ac3d76
github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1

google.golang.org/grpc => google.golang.org/grpc v1.33.2
)
Loading

0 comments on commit 1e7db5c

Please sign in to comment.