fix(rpc): guard nil height deref in CometBlockResultByNumber#1067
fix(rpc): guard nil height deref in CometBlockResultByNumber#1067Aboudjem wants to merge 2 commits intocosmos:mainfrom
Conversation
Greptile SummaryThis PR fixes an intermittent nil pointer dereference panic in Key changes:
Minor issues found:
Confidence Score: 5/5
Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A["CometBlockResultByNumber(ctx, height *int64)"] --> B{height != nil?}
B -- "yes" --> C["heightAttr = *height"]
B -- "no" --> D["heightAttr = 0 (default)"]
C --> E["Start tracing span with heightAttr"]
D --> E
E --> F{height != nil && *height == 0?}
F -- "yes (zero remapped)" --> G["height = nil"]
F -- "no" --> H["height unchanged"]
G --> I["RPCClient.BlockResults(ctx, nil)"]
H --> I
I --> J{err != nil?}
J -- "yes" --> K["❌ BEFORE: fmt.Errorf(..., *height, err)\n💥 PANIC if height is nil"]
J -- "yes" --> L["✅ AFTER: fmt.Errorf(..., heightAttr, err)\n✔ Safe — heightAttr is always int64"]
J -- "no" --> M["return res, nil"]
style K fill:#ffcccc,stroke:#cc0000
style L fill:#ccffcc,stroke:#009900
Last reviewed commit: 3c077ef |
rpc/backend/comet_test.go
Outdated
| expectPanic bool | ||
| expectErr bool |
There was a problem hiding this comment.
Unused struct field expectPanic
The expectPanic field is declared in the test case struct but is never read or used anywhere in the test body. All cases rely on require.NotPanics to assert no panic, and none of the test cases even set expectPanic: true. This dead field is misleading — a future maintainer might assume it drives some assertion when it does not.
Either remove the field or wire it up to an actual require.Panics / require.NotPanics branch:
| expectPanic bool | |
| expectErr bool | |
| testCases := []struct { | |
| name string | |
| height *int64 | |
| rpcErr error | |
| expectErr bool | |
| }{ |
| res, err := b.RPCClient.BlockResults(ctx, height) | ||
| if err != nil { | ||
| return nil, fmt.Errorf("failed to fetch block result from CometBFT %d: %w", *height, err) | ||
| return nil, fmt.Errorf("failed to fetch block result from CometBFT %d: %w", heightAttr, err) |
There was a problem hiding this comment.
Ambiguous height in error message when caller passes nil
When CometBlockResultByNumber is called with a nil height (i.e., "fetch latest block"), heightAttr defaults to 0. If BlockResults then fails, the error message will read "failed to fetch block result from CometBFT 0: ...", which is indistinguishable from a caller that explicitly requested block 0 (which is also remapped to nil). This is a pre-existing ambiguity but the fix keeps it intact.
Consider using a more descriptive format string to differentiate the two cases, for example:
heightStr := "latest"
if heightAttr != 0 {
heightStr = fmt.Sprintf("%d", heightAttr)
}
return nil, fmt.Errorf("failed to fetch block result from CometBFT (height=%s): %w", heightStr, err)This is a minor style concern and does not affect correctness.
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Fixes #1066.
Was tracing an intermittent crash on a pruned node that only showed up under load. The stack trace pointed at
comet.go:71in the error path ofCometBlockResultByNumber. When the caller passes height=0, the pointer gets set to nil before theBlockResultsRPC call. If that call fails (timeout, pruned state, etc), the error formatting dereferences the nil pointer and panics.The fix captures the height value before the nil reassignment and uses it in the error message. The variable already existed for the tracing span attribute so this just reuses it in the format string.
Added a table-driven test covering the zero-height error path to confirm it no longer panics.