Skip to content

Commit e9353d9

Browse files
authored
fix: use flat JSON format for seid /status response parsing (#39)
## Summary - The `statusResponse` struct expected a JSONRPC `result` wrapper (`{"result":{"sync_info":{...}}}`) but seid returns a flat format (`{"sync_info":{...}}`). This caused `LatestHeight` to silently fail on every poll — `strconv.ParseInt("")` returned an error each time — leaving the `await-condition` task stuck indefinitely even after the target height was reached. - Same wrapper assumption existed in `result_export.go` for both `/status` and `/block_results` endpoints; fixed both. ## Root cause Discovered while debugging a `pacific-1-shadow-replayer` pre-init Job where `seid` had synced past the target height (198.8M vs 198.7M target) but the sidecar task never detected it. The TCP connection was established and HTTP 200s were flowing, but the JSON parse always produced an empty string for `latest_block_height`. ## Test plan - [x] All existing tests updated to use the flat format and pass - [x] `go test ./sidecar/... -count=1` — all 7 packages pass
1 parent a4116b3 commit e9353d9

5 files changed

Lines changed: 24 additions & 30 deletions

File tree

sidecar/rpc/status.go

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,10 @@ type NodeStatus struct {
3333
func (c *StatusClient) Endpoint() string { return c.endpoint }
3434

3535
type statusResponse struct {
36-
Result struct {
37-
SyncInfo struct {
38-
LatestBlockHeight string `json:"latest_block_height"`
39-
CatchingUp bool `json:"catching_up"`
40-
} `json:"sync_info"`
41-
} `json:"result"`
36+
SyncInfo struct {
37+
LatestBlockHeight string `json:"latest_block_height"`
38+
CatchingUp bool `json:"catching_up"`
39+
} `json:"sync_info"`
4240
}
4341

4442
// NewStatusClient creates a client targeting the given RPC endpoint.
@@ -79,14 +77,14 @@ func (c *StatusClient) Status(ctx context.Context) (*NodeStatus, error) {
7977
return nil, fmt.Errorf("decoding /status: %w", err)
8078
}
8179

82-
h, err := strconv.ParseInt(rpcResp.Result.SyncInfo.LatestBlockHeight, 10, 64)
80+
h, err := strconv.ParseInt(rpcResp.SyncInfo.LatestBlockHeight, 10, 64)
8381
if err != nil {
84-
return nil, fmt.Errorf("parsing latest_block_height %q: %w", rpcResp.Result.SyncInfo.LatestBlockHeight, err)
82+
return nil, fmt.Errorf("parsing latest_block_height %q: %w", rpcResp.SyncInfo.LatestBlockHeight, err)
8583
}
8684

8785
return &NodeStatus{
8886
LatestBlockHeight: h,
89-
CatchingUp: rpcResp.Result.SyncInfo.CatchingUp,
87+
CatchingUp: rpcResp.SyncInfo.CatchingUp,
9088
}, nil
9189
}
9290

sidecar/rpc/status_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99

1010
func TestStatusClient_LatestHeight(t *testing.T) {
1111
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
12-
_, _ = w.Write([]byte(`{"result":{"sync_info":{"latest_block_height":"12345","catching_up":false}}}`))
12+
_, _ = w.Write([]byte(`{"sync_info":{"latest_block_height":"12345","catching_up":false}}`))
1313
}))
1414
defer srv.Close()
1515

@@ -25,7 +25,7 @@ func TestStatusClient_LatestHeight(t *testing.T) {
2525

2626
func TestStatusClient_CatchingUp(t *testing.T) {
2727
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
28-
_, _ = w.Write([]byte(`{"result":{"sync_info":{"latest_block_height":"100","catching_up":true}}}`))
28+
_, _ = w.Write([]byte(`{"sync_info":{"latest_block_height":"100","catching_up":true}}`))
2929
}))
3030
defer srv.Close()
3131

@@ -79,8 +79,8 @@ func TestStatusClient_InvalidBlockHeight(t *testing.T) {
7979
name string
8080
payload string
8181
}{
82-
{"empty height", `{"result":{"sync_info":{"latest_block_height":"","catching_up":false}}}`},
83-
{"non-numeric height", `{"result":{"sync_info":{"latest_block_height":"abc","catching_up":false}}}`},
82+
{"empty height", `{"sync_info":{"latest_block_height":"","catching_up":false}}`},
83+
{"non-numeric height", `{"sync_info":{"latest_block_height":"abc","catching_up":false}}`},
8484
}
8585
for _, tt := range tests {
8686
t.Run(tt.name, func(t *testing.T) {

sidecar/tasks/await_condition_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ func heightServer(heights ...int64) *httptest.Server {
2525
idx++
2626
}
2727
mu.Unlock()
28-
fmt.Fprintf(w, `{"result":{"sync_info":{"latest_block_height":"%d","catching_up":false}}}`, heights[i])
28+
fmt.Fprintf(w, `{"sync_info":{"latest_block_height":"%d","catching_up":false}}`, heights[i])
2929
}))
3030
}
3131

sidecar/tasks/result_export.go

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -244,19 +244,17 @@ func queryLatestHeight(ctx context.Context, rpcEndpoint string) (int64, error) {
244244
}
245245

246246
var rpcResp struct {
247-
Result struct {
248-
SyncInfo struct {
249-
LatestBlockHeight string `json:"latest_block_height"`
250-
} `json:"sync_info"`
251-
} `json:"result"`
247+
SyncInfo struct {
248+
LatestBlockHeight string `json:"latest_block_height"`
249+
} `json:"sync_info"`
252250
}
253251
if err := json.NewDecoder(resp.Body).Decode(&rpcResp); err != nil {
254252
return 0, fmt.Errorf("decoding /status response: %w", err)
255253
}
256254

257-
h, err := strconv.ParseInt(rpcResp.Result.SyncInfo.LatestBlockHeight, 10, 64)
255+
h, err := strconv.ParseInt(rpcResp.SyncInfo.LatestBlockHeight, 10, 64)
258256
if err != nil {
259-
return 0, fmt.Errorf("parsing latest_block_height %q: %w", rpcResp.Result.SyncInfo.LatestBlockHeight, err)
257+
return 0, fmt.Errorf("parsing latest_block_height %q: %w", rpcResp.SyncInfo.LatestBlockHeight, err)
260258
}
261259
if h <= 0 {
262260
return 0, fmt.Errorf("latest_block_height is %d, node may still be syncing", h)
@@ -285,14 +283,12 @@ func queryBlockResults(ctx context.Context, rpcEndpoint string, height int64) (j
285283
return nil, fmt.Errorf("HTTP %d: %s", resp.StatusCode, bytes.TrimSpace(body))
286284
}
287285

288-
var rpcResp struct {
289-
Result json.RawMessage `json:"result"`
290-
}
291-
if err := json.NewDecoder(resp.Body).Decode(&rpcResp); err != nil {
292-
return nil, fmt.Errorf("decoding response: %w", err)
286+
body, err := io.ReadAll(resp.Body)
287+
if err != nil {
288+
return nil, fmt.Errorf("reading response body: %w", err)
293289
}
294290

295-
return rpcResp.Result, nil
291+
return json.RawMessage(body), nil
296292
}
297293

298294
func parseExportConfig(params map[string]any) (ResultExportConfig, error) {

sidecar/tasks/result_export_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,9 @@ func fakeRPCServer(latestHeight int64) *httptest.Server {
4141
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
4242
switch {
4343
case r.URL.Path == "/status":
44-
fmt.Fprintf(w, `{"result":{"sync_info":{"latest_block_height":"%d"}}}`, latestHeight)
44+
fmt.Fprintf(w, `{"sync_info":{"latest_block_height":"%d"}}`, latestHeight)
4545
case r.URL.Path == "/block_results":
46-
fmt.Fprint(w, `{"result":{}}`)
46+
fmt.Fprint(w, `{}`)
4747
default:
4848
http.NotFound(w, r)
4949
}
@@ -134,7 +134,7 @@ func TestExportRPCNon200Status(t *testing.T) {
134134

135135
func TestQueryLatestHeight_ZeroHeight(t *testing.T) {
136136
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
137-
fmt.Fprint(w, `{"result":{"sync_info":{"latest_block_height":"0"}}}`)
137+
fmt.Fprint(w, `{"sync_info":{"latest_block_height":"0"}}`)
138138
}))
139139
defer srv.Close()
140140

0 commit comments

Comments
 (0)