fix(evm-rpc): encode Stable 0x3f nonceKey as a quantity, not a byte string#540
Open
elina-chertova wants to merge 1 commit into
Open
fix(evm-rpc): encode Stable 0x3f nonceKey as a quantity, not a byte string#540elina-chertova wants to merge 1 commit into
elina-chertova wants to merge 1 commit into
Conversation
…tring The 0x3f transaction encoder (encodeTransaction) and its signing counterpart (serializeTransaction) decoded tx.nonceKey with decodeHex. nonceKey is a JSON-RPC quantity: the node returns it in minimal form (e.g. "0x0"), which is odd-length and fails decodeHex's isHex assert, crashing tx-root / tx-sender verification. Even for even-length values it only matched by coincidence. Encode it as BigInt(nonceKey) so RLP uses the canonical minimal integer form. Verified against on-chain data (stable-testnet block 61696562): the computed transactionsRoot and recovered tx sender now match the block. Regression fixture added: evm/evm-rpc/test/fixtures/stable-testnet/61696562.
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.
Cause (proven)
dump-stable-testnet-0(imagesubsquid/evm-dump:3325a6fa) is in a crash-loop — 56 restarts in ~7h44m, deterministically stuck at block 61696562. The dump runs with--verify-tx-rootand--verify-tx-sender.Block 61696562 tx #1 (
0x0faaea3177859e347bffc7f601321d4b5c9501b0cd12eb219b499971ca063043) is a Stable type0x3ftransaction withnonceKey: "0x0". The0x3fencoder inverification.tsdecodesnonceKeywithdecodeHex:nonceKeyis a JSON-RPC quantity (a uint), and the node returns it in minimal form —"0x0". That string is odd-length, sodecodeHexfails itsassert(isHex(value))(isHex requires even length). The throw is fatal → the process crashes → it re-reads the same block on restart → crash-loop. This is both inencodeTransaction(tx-root) and inserializeTransaction(tx-sender), and both were exercised.The
0x3fhandler (decodeHex(nonceKey)) was introduced in7a1045150e33808ca828d7cdd56dd33c9b66cb5b("support 0x3f transaction type from stable network"). The one existing fixture (block 59083166) hasnonceKey: "0x8000000000000001"— even-length with no leading zeros, which is the one case wheredecodeHexand the correct quantity encoding produce identical RLP bytes, so the bug stayed hidden. Note the Tempo0x76encoder already encodesnonceKeywithBigInt(...).Fix
Encode
nonceKeyasBigInt(tx.nonceKey)(canonical minimal RLP integer) in both the0x3fbranch ofencodeTransactionandserializeTransaction.Verification (on-chain proof, red → green)
Reproduced against the live block from
https://rpc.testnet.stable.xyz:BigInt(nonceKey)the computed root equals the block'stransactionsRoot0x2834b06fceff67d7fa97915a2f32b13cbebd4edfc71fb956367a76a3e9cc27db;decodeHex-as-bytes and left-padded-32 candidates do not match.BigInt(nonceKey)recovers0x4820e7e4c3ee3a8ee654e62114a97faf7bce5614=tx.from.Regression fixture
evm/evm-rpc/test/fixtures/stable-testnet/61696562added; it is picked up by the existingtransactionsRoot verificationandtransaction sender recoverytests.AssertionError: isHex(value)atdecodeHex(matches the production crash).npx vitest run test/verification.test.ts→ 134 passed / 0 failed; fullnpm test→ 170 passed;npm run lint(tsc --noEmit) clean;rush build --to @subsquid/evm-rpcclean.Falsification
If a real
0x3ftransaction carries anonceKeythat is genuinely a byte string (not a quantity),BigInt(nonceKey)would drop leading zero bytes and the tx-root would mismatch. The on-chain reproduction above (root + sender both match) rules this out for stable-testnet; a mismatch on any future0x3ffixture would falsify it.