Skip to content

feat: move to hegota-testnet (chain 8141) and EIP-8250 keyed nonces - #25

Merged
Ghadi8 merged 5 commits into
mainfrom
ghadi/privacy-rpc
Sep 24, 2026
Merged

Ghadi8 merged 5 commits into
mainfrom
ghadi/privacy-rpc

Conversation

@Ghadi8

@Ghadi8 Ghadi8 commented Sep 24, 2026

Copy link
Copy Markdown
Member

What this changes

Moves the library from the chain-81410 frames devnet to hegota-testnet (chain 8141, rpc1.privacy.ethrex.xyz, ethrex bdfc5d8), whose frame transactions carry EIP-8250 keyed nonces in an 8-field envelope. It also removes the rule-set API, which now always prices identically, and exports a hegotaTestnet chain definition.

Why

81410 was only a stopgap while the 8141 faucet was broken. 8141 is the upstream ethrex line: its build is 341 commits ahead of, and 0 behind, the commit this library was pinned to. It refuses our 7-field bytes at decode (Error decoding field 'nonce_keys').

Breaking API changes, all in this release:

  • FrameTransaction.noncenonceKeys: bigint[] + nonceSeq: bigint; same for RpcFrameTransaction
  • getNonce({ key?, blockTag? }); getValidationData({ calls, chainId, nonceKeys, nonceSeq })
  • frameTxGas(tx), frameTxMaxCost(tx, blobBaseFee) and estimateFrameGas({ transaction }) lose the rules argument; RuleSet, compareRuleSets and GasDivergence are removed

Added:

  • prepareFrameTransaction(…, { nonceKeys }), which refuses keys that sit at different sequences
  • NONCE_MANAGER, keyedNonceSlot and getFrameNonceSeq (keyed nonces read through eth_getStorageAt)
  • MAX_NONCE_KEYS, nonceCalldata, KEYED_NONCE_FIRST_USE_STATE_GAS (97,920), NEW_ACCOUNT_STATE_GAS (183,600)
  • hegotaTestnet
  • scripts/send-eth-eoa.ts now simulates before broadcasting and refuses to send anything the node reports invalid

Docs: docs/DESIGN.md is rewritten as a compact spec of the client; docs/OPEN-ITEMS.md is removed.

How the new behaviour is pinned

  • A published figure, transcribed rather than derived: the two nonce state-gas figures are written as literals (64 and 120 state bytes × 1530), and the golden gas expectations are re-derived by hand with the working in comments
  • The golden byte vector or sig-hash from ethrex's frame_tx_wire_tests.rs: re-transcribed from bdfc5d8:69-70
  • Re-encoding captured chain data and reproducing the transaction hash: 14 new fixtures from 8141
  • A live receipt: test/chain.oracle.test.ts checks, per fixture, the recovered signer, our maxCost against the node's, and receipt gasUsed
  • N/A

Before choosing fixtures I ran the checks over all 198 frame transactions on the 8141 genesis. Every hash reproduced, every signer recovered, and every maxCost matched the node's exactly. The receipt formula is max(intrinsic + Σ execution, calldata floor) + Σ state: exact on 176, with the other 22 lower by storage refunds that frame receipts don't itemize. Fixtures come from the refund-free set.

The fixture suite can fail. With the nonce calldata taken out of the gas model, 26 of its tests fail.

Live: an ETH transfer from a funded code-less EOA through toEoaFrameAccount landed as 0xa05de9a4f929ac36a2d6b7ed09bdc6506656b3ac0c374c85a34f3b9e6954fc12 (block 129,105) and is fixture 14.

Load-bearing rules

  • No

  • Yes, and the argument for it is below

  • Golden vector and sig-hash replaced. Not edited to pass: re-transcribed verbatim from the same upstream test at the new pinned commit. scripts/hegota-testnet/frametx.py:113 asserts the same string.

  • Captured fixtures replaced. The 5 old ones came from a retired genesis and a 9-field envelope neither chain serves; they remain in git history. The replacements are unedited captures from scripts/capture-fixtures.ts, which can now capture specific transactions by hash.

  • Gas constants added as literal published figures, not derived.

  • Module order. New nonce and chain modules depend only on errors and viem. gas still doesn't import envelope, and encodeFrameTx still doesn't validate.

Checks

  • bun run test (340 passed)
  • bun run typecheck
  • bun run build && bunx @arethetypeswrong/cli --pack . (new root exports)
  • bun run test:live

Release impact

  • No release
  • Patch (fix)
  • Minor (feat)
  • Major (feat! or a BREAKING CHANGE: footer)

This breaks the public API, but ships as a minor under the pre-1.0 convention, as #24 did. .releaserc.json uses the default analyzer, so a ! or a BREAKING CHANGE: footer anywhere in the history would publish 1.0.0.

Comment thread scripts/capture-fixtures.ts Dismissed

@nikhilkumar1612 nikhilkumar1612 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

validate nonceKeys during transaction preparation

prepareFrameTransaction() currently validates only that nonceKeys is non-empty and that all selected keys have the same sequence.

It can therefore return a transaction containing consensus-invalid key sets such as:

[2n, 1n] // not strictly increasing
[1n, 1n] // duplicate keys
[0n, 1n] // key 0 mixed with another key
Array(17).fill(1n) // exceeds MAX_NONCE_KEYS

@Ghadi8
Ghadi8 merged commit abe1bac into main Sep 24, 2026
4 checks passed
@Ghadi8
Ghadi8 deleted the ghadi/privacy-rpc branch September 24, 2026 13:23
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 0.3.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants