fix(blocks): treat a malformed blocks/latest response as a failed poll - #688
Open
2xburnt wants to merge 2 commits into
Open
fix(blocks): treat a malformed blocks/latest response as a failed poll#6882xburnt wants to merge 2 commits into
2xburnt wants to merge 2 commits into
Conversation
fetchLatest trusts the response shape. An endpoint that answers 200 with
something other than a block - an error body, a rate-limit page, a proxy
interstitial - is stored as `latest`. Its missing chain_id then fails this
check:
if (!this.earliest || this.earliest?...chain_id != this.latest?...chain_id) {
this.earliest = this.latest;
this.recents = [];
}
That branch exists to detect a chain switch, but a junk payload trips it
identically, so `earliest` and `recents` are wiped. The visible effect is the
average block time snapping back to the 1000ms placeholder and the recent-blocks
list emptying, intermittently, with nothing surfaced to the user.
Observed against a flaky endpoint: the average block time read 1679 -> 6117 ->
1000 -> 3844 ms against a true 4060 ms, with recents dropping 4 -> 1. With the
payload validated it converged to 3957 ms and neither value reset, while a third
of responses were still being rejected as malformed.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f03fbaced0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
The guard only checked `block.header.height`, so a partial response carrying a height but no chain_id still passed and was assigned to `latest`. The chain_id comparison immediately below then saw undefined against the previous chain, reset `earliest` and `recents`, and reproduced exactly the state loss this change is meant to prevent. Thanks @chatgpt-codex-connector for spotting it - the original comment even described that mechanism while the condition missed it. Verified by serving 13 consecutive 200s shaped as `{ block: { header: { height: "999999" } } }` with chain_id omitted: earliest stays at 32184677, chain_id stays cosmoshub-4, recents keeps growing, and the partial is never stored as `latest`.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
fetchLatest trusts the response shape. An endpoint that answers 200 with something other than a block - an error body, a rate-limit page, a proxy interstitial - is stored as
latest. Its missing chain_id then fails this check:if (!this.earliest || this.earliest?...chain_id != this.latest?...chain_id) {
this.earliest = this.latest;
this.recents = [];
}
That branch exists to detect a chain switch, but a junk payload trips it identically, so
earliestandrecentsare wiped. The visible effect is the average block time snapping back to the 1000ms placeholder and the recent-blocks list emptying, intermittently, with nothing surfaced to the user.Observed against a flaky endpoint: the average block time read 1679 -> 6117 ->
1000 -> 3844 ms against a true 4060 ms, with recents dropping 4 -> 1. With the payload validated it converged to 3957 ms and neither value reset, while a third of responses were still being rejected as malformed.