feat(solana): honor server-provided blockhash from 402 extra (x402#2693) - #7
Merged
Conversation
When the 402 requirement carries extra.recentBlockhash, sign with it and skip the client-side getLatestBlockhash RPC entirely — zero RPC calls on the payment path, and the tx is pinned to a blockhash the settling RPC has observed (fresher than the 10s client cache, so less blockhash-expiry settle retry tail). Absent or malformed values fall back to the RPC fetch.
This was referenced Aug 4, 2026
added 4 commits
August 3, 2026 22:46
The server-provided blockhash fast path leaked into the async poll re-sign path. pollPaymentPayload exists precisely to re-sign long image/video jobs with a FRESH blockhash every 30s, but it passes the same PaymentOption every time — so once the signer preferred extra.recentBlockhash, every re-sign silently reused the original, increasingly expired hash. Signing still succeeds locally, so nothing surfaces until settlement fails at the gateway, which is the exact failure the re-sign machinery exists to prevent. Gate the fast path behind allowServerBlockhash: CreateSolanaPaymentPayload passes true and keeps the zero-RPC win on the submit path, pollPaymentPayload passes false and fetches fresh. option.Extra is left untouched so the envelope still echoes "accepted" verbatim. Also reject the all-zero hash: base58 decodes "111...1" successfully, so a server sending it would have had the client sign an unsettleable transaction. Tests: - TestPollPaymentPayloadForcesFreshBlockhash pins the regression (watched it fail against the unfixed re-sign path) - the fallback test now asserts the RPC-fetched hash actually reaches the signed transaction, and covers the zero hash and non-string types - TestCreateSolanaPaymentPayloadBlockhashRPCFailure covers the re-wired no-server-hash + RPC-down error path Found by /review: the poll regression was flagged independently by the performance specialist, the Claude adversarial pass, and Codex.
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.
What
When the 402 payment requirement carries
extra.recentBlockhash, the SVM exact-scheme signer uses it directly and skips the client-sidegetLatestBlockhashRPC — zero RPC calls on the payment path. Absent or malformed values fall back to the existing cached RPC fetch.Why
Implements the client half of x402-foundation/x402#2693 (spec fix by ludo/Solana team): the server-provided blockhash is fresher than anything the client can cache (our 10s TTL meant up to ~12s-old blockhashes) AND is pinned to an RPC view the settling side has observed — both shrink the blockhash-expiry settle retry tail behind sol.blockrun.ai's p95.
Testing
TestCreateSolanaPaymentPayloadUsesServerBlockhash: zero RPC calls + tx carries the server hash (TDD, watched fail first)TestCreateSolanaPaymentPayloadFallsBackWithoutServerBlockhash: absent/malformed extra falls back to RPC