Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions go/shared/cosmossdk/cursor.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,14 @@ func (c *Cursor) Decode(b64 string) error {
return errors.Wrapf(err, "failed to unmarshal cursor: %s", bytes)
}

// json.Unmarshal into the existing State map keeps caller-supplied keys and stores a JSON
// null pointer value as a nil *CursorState. Drop those nil entries so a malformed cursor
// (e.g. {"state":{"x":null}}) can't leave a nil pointer to be dereferenced downstream.
for source, state := range c.State {
if state == nil {
delete(c.State, source)
}
}
Comment on lines +43 to +50

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Deleting nil entries can still leave a nil-deref path for expected sources.

At Line 48, deleting c.State[source] removes the initialized entry entirely. In go/shared/cosmossdk/tx.go (context snippet, source-page sync loop), history.Cursor.State[source].Page is dereferenced without an existence check after Decode; a cursor like {"state":{"<expected_source>":null}} can still panic there.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@go/shared/cosmossdk/cursor.go` around lines 43 - 50, The loop in cursor.go
that deletes nil entries from c.State causes missing keys and can lead to
nil-pointer dereferences later (e.g., history.Cursor.State[source].Page in
tx.go); instead of delete(c.State, source) replace nil values with a non-nil
default (e.g., c.State[source] = &CursorState{} or an equivalent zero-value
CursorState) so the key remains present but safe to dereference; update the loop
that iterates c.State to assign a default CursorState when state == nil.


return nil
}
3 changes: 3 additions & 0 deletions go/shared/cosmossdk/history.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ func (h *History) filterByCursor(txs []HistoryTx) ([]HistoryTx, error) {
if tx.GetHeight() == h.Cursor.BlockHeight {
found := false
for _, s := range h.Cursor.State {
if s == nil {
continue
}
if tx.GetTxID() == s.TxID {
found = true
break
Expand Down
Loading