fix: recover typed node rejections on every JSON-RPC method#1411
Open
zancas wants to merge 1 commit into
Open
Conversation
Only two of the 28 JSON-RPC methods recovered the node's typed rejection from the indexer error's `source()` chain: `sendrawtransaction` walked for the typed `RpcError`, and `getblock` recognized a single hard-coded transport case. The other 26 mapped every error through `invalid_params_error_object`, so a node rejection reached the client as a generic invalid-params object with the wrong code and no legacy error code — the JSON-RPC face of the masking family in #1404. An in-code comment acknowledged the gap: "Currently all errors are hidden from downstream client, a full fix should be implemented." This commit implements that full fix (#1407). The shared walk skeleton, `error_object_from_source_chain`, now takes its fallback as a parameter instead of hard-coding an internal-server-error object. A new general translator, `error_object_from_indexer_error`, recovers the typed `RpcError` when the chain carries one and forwards its code and message; otherwise it falls back to the exact invalid-params object the plain-delegation methods returned before, so non-rejection errors keep their wire shape and behavior changes only when a node rejection is present. All 26 plain-delegation sites now use it. `getblock` keeps its zcashd-compatible "block not found" arm ahead of the generic recovery rather than instead of it, and `sendrawtransaction` retains its internal-error fallback unchanged. Following the test-first order, the translator tests were written before the fix and the meaningful case confirmed red: `getblock` masked a legacy-code -25 rejection as a -32603 internal error. Six tests now cover the three translators — recovery plus fallback pinning for each — built on a small nestable wrapper fixture, since the translators consume only `source()` chains. The stale "temporary fix" comment is replaced with a description of the implemented design. Closes #1407. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.
Closes #1407. Top of the #1404 follow-up stack — the base branch is
test/1406-passthrough-contract-tests(PR #1410, which stacks on #1409 → #1405); retarget as the stack merges. Only the top commit belongs to this PR.Problem
Only two of the 28 JSON-RPC methods recovered the node's typed rejection from the indexer error's
source()chain:sendrawtransactionwalked for the typedRpcError, andgetblockrecognized a single hard-coded transport case (HTTP 500 → "block not found"). The other 26 mapped every error throughinvalid_params_error_object, so a node rejection of, say,getrawtransactionorz_gettreestatereached the client as a generic invalid-params object — wrong code, no legacy error code, reason buried in a data string. This is the JSON-RPC face of the masking family from #1404, and an in-code comment acknowledged it: "Currently all errors are hidden from downstream client, a full fix should be implemented."Fix
error_object_from_source_chain(the shared walk skeleton) now takes its fallback as a parameter;internal_error_objectis extracted alongsideinvalid_params_error_object.error_object_from_indexer_error, recovers the typedRpcErrorwhen the chain carries one and forwards its code and message. Otherwise it falls back to the exact invalid-params object the plain-delegation methods returned before — non-rejection errors keep their wire shape, so behavior changes only when a node rejection is present.getblockkeeps its zcashd-compatible "block not found" arm ahead of the generic recovery rather than instead of it.sendrawtransactionis behaviorally unchanged.Tests (translator tests written first; the meaningful case confirmed red)
Before the fix,
getblock_error_object_from_indexer_errormasked a legacy-code-25rejection as a-32603internal error — that test was confirmed red, then green. Six tests now cover the three translators (recovery plus fallback pinning for each), built on a small nestableWrapfixture: the translators consume onlysource()chains, so a minimal typed wrapper reproduces exactly what they see from production error types.Verification
cargo fmt --all --checkclean,cargo clippy --workspace --all-targetsclean, andcargo nextest runon the production set green — 376/376, the prior 370 plus the six new translator tests.🤖 Generated with Claude Code