Skip to content

Commit 34e826d

Browse files
authored
fix(rpc): allow query latest block (#1760)
## Overview Allow querying latest `/block` without requiring `?height=` param for CometBFT compat. Fixes #1758 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Enhanced parameter handling to support `*StrInt64` type with improved error handling. - **Bug Fixes** - Fixed handling of nullable `Height` parameter in `Block` function to prevent potential dereference issues. - **Tests** - Updated test cases to cover scenarios for valid/malformed requests and different parameter conditions. - **Refactor** - Modified `Height` field in `blockArgs` struct to use `*StrInt64` for better nullability support. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
1 parent 59e574e commit 34e826d

File tree

4 files changed

+37
-7
lines changed

4 files changed

+37
-7
lines changed

rpc/json/handler.go

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,13 +131,17 @@ func (h *handler) newHandler(methodSpec *method) func(http.ResponseWriter, *http
131131
for i := 0; i < methodSpec.argsType.NumField(); i++ {
132132
field := methodSpec.argsType.Field(i)
133133
name := field.Tag.Get("json")
134-
if !values.Has(name) {
134+
kind := field.Type.Kind()
135+
// pointers can be skipped from required check
136+
if kind != reflect.Pointer && !values.Has(name) {
135137
h.encodeAndWriteResponse(w, nil, fmt.Errorf("missing param '%s'", name), int(json2.E_INVALID_REQ))
136138
return
137139
}
138140
rawVal := values.Get(name)
139141
var err error
140-
switch field.Type.Kind() {
142+
switch kind {
143+
case reflect.Pointer:
144+
err = setPointerParam(rawVal, &args, i)
141145
case reflect.Bool:
142146
err = setBoolParam(rawVal, &args, i)
143147
case reflect.Int, reflect.Int64:
@@ -204,6 +208,26 @@ func (h *handler) encodeAndWriteResponse(w http.ResponseWriter, result interface
204208
}
205209
}
206210

211+
func setPointerParam(rawVal string, args *reflect.Value, i int) error {
212+
if rawVal == "" {
213+
return nil
214+
}
215+
field := args.Elem().Field(i)
216+
switch {
217+
// only *StrInt64 is supported for now
218+
case field.Type() == reflect.TypeOf(blockArgs{}.Height):
219+
val, err := strconv.ParseInt(rawVal, 10, 64)
220+
if err != nil {
221+
return err
222+
}
223+
strInt64Val := StrInt64(val)
224+
args.Elem().Field(i).Set(reflect.ValueOf(&strInt64Val))
225+
return nil
226+
default:
227+
return fmt.Errorf("unsupported pointer type: %v", field)
228+
}
229+
}
230+
207231
func setBoolParam(rawVal string, args *reflect.Value, i int) error {
208232
v, err := strconv.ParseBool(rawVal)
209233
if err != nil {

rpc/json/service.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,12 @@ func (s *service) GenesisChunked(req *http.Request, args *genesisChunkedArgs) (*
179179
}
180180

181181
func (s *service) Block(req *http.Request, args *blockArgs) (*ctypes.ResultBlock, error) {
182-
return s.client.Block(req.Context(), (*int64)(&args.Height))
182+
var height *int64
183+
if args.Height != nil {
184+
h := int64(*args.Height)
185+
height = &h
186+
}
187+
return s.client.Block(req.Context(), height)
183188
}
184189

185190
func (s *service) BlockByHash(req *http.Request, args *blockByHashArgs) (*ctypes.ResultBlock, error) {

rpc/json/service_test.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,11 @@ func TestREST(t *testing.T) {
6464
bodyContains string
6565
}{
6666

67-
{"invalid/malformed request", "/block?so{}wrong!", http.StatusOK, int(json2.E_INVALID_REQ), ``},
68-
{"invalid/missing param", "/block", http.StatusOK, int(json2.E_INVALID_REQ), `missing param 'height'`},
69-
{"valid/no params", "/abci_info", http.StatusOK, -1, `"last_block_height":"345"`},
67+
{"valid/malformed request", "/block?so{}wrong!", http.StatusOK, int(json2.E_INTERNAL), ``},
7068
// to keep test simple, allow returning application error in following case
69+
{"invalid/missing required param", "/header", http.StatusOK, int(json2.E_INVALID_REQ), `missing param 'height'`},
70+
{"valid/missing optional param", "/block", http.StatusOK, int(json2.E_INTERNAL), "failed to load hash from index"},
71+
{"valid/no params", "/abci_info", http.StatusOK, -1, `"last_block_height":"345"`},
7172
{"valid/int param", "/block?height=321", http.StatusOK, int(json2.E_INTERNAL), "failed to load hash from index"},
7273
{"invalid/int param", "/block?height=foo", http.StatusOK, int(json2.E_PARSE), "failed to parse param 'height'"},
7374
{"valid/bool int string params",

rpc/json/types.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ type genesisChunkedArgs struct {
3636
ID StrInt `json:"chunk"`
3737
}
3838
type blockArgs struct {
39-
Height StrInt64 `json:"height"`
39+
Height *StrInt64 `json:"height"`
4040
}
4141
type blockByHashArgs struct {
4242
Hash []byte `json:"hash"`

0 commit comments

Comments
 (0)