Skip to content

feat(portal): opt-in PORTAL_ALLOW_MISSING_ACCESS_LIST for RPCs that omit accessList (e.g. SQD zkSync proxy)#173

Open
abernatskiy wants to merge 1 commit into
mainfrom
fix/allow-missing-access-list
Open

feat(portal): opt-in PORTAL_ALLOW_MISSING_ACCESS_LIST for RPCs that omit accessList (e.g. SQD zkSync proxy)#173
abernatskiy wants to merge 1 commit into
mainfrom
fix/allow-missing-access-list

Conversation

@abernatskiy

Copy link
Copy Markdown

Summary

Fix — an opt-in escape hatch

Add PORTAL_ALLOW_MISSING_ACCESS_LIST (default OFF, matching the fork's PORTAL_* boolean convention):

Before → after (default, on SQD's zkSync proxy):

RpcProviderError: Invalid RPC response: 'transaction.accessList' is a required property on type 0x2 transactions
Please report this error to the RPC operator.

The message's meta now reads:

This RPC provider omits the spec-required 'accessList' on typed transactions. If that is expected for this endpoint (e.g. SQD's zkSync proxy), set PORTAL_ALLOW_MISSING_ACCESS_LIST=1 to store the missing access list as NULL and continue; otherwise report this to the RPC operator.

Why an env knob, not a config field

The check lives in upstream core (standardizeTransactions), reached from many call sites; threading a config parameter would balloon the wiring patch and drift across ponder versions. The knob is read once per call (hoisted above the tx loop — cheap, and toggleable per call in tests), consistent with the fork's other PORTAL_* env settings.

Scope / invariants preserved

  • Escape hatch for absent lists only: a present access list still round-trips unchanged with the knob on — the guard never fabricates or drops a real one.
  • Untouched regardless of the knob: legacy (0x0), OP deposit (0x7e), and unknown/system envelopes (e.g. Arbitrum internals) — none require an access list.
  • Applied to all 5 tracked wiring patches (0.15.17, 0.16.60.16.9), regenerated per PUBLISHING.md (git diff); the only change in each patch is the gate + hoisted read + reworded error.

Test plan

  • scripts/sync-upstream.sh 0.16.9 --test green — adds 3 tests to portal/realtime-standardize.test.ts:
    • default (knob unset) → missing accessList still throws and the message names the knob;
    • knob set → missing accessList on 0x1/0x2/0x3/0x4 passes through and encodes to NULL;
    • knob set → a present accessList is preserved unchanged (no fabrication/loss).
  • biome check . clean.
  • The existing (a–e) default-behavior cases still pass (knob defaults OFF).

Follow-up (not in this PR)

This is a mitigation, not a cure for the proxy's non-compliance. Open design question: whether the fork should additionally auto-detect a zkSync-family chain and default the knob on for it, and/or whether SQD's zkSync proxy should be made to emit the spec-required field. Tracked in the test report's deferred section.

🤖 Generated with Claude Code

…mit accessList

The fork's hardened RPC-path accessList-required check (in standardizeTransactions,
added by every wiring patch) crashes any app whose RPC/proxy omits the spec-required
accessList on typed-envelope txs. In practice this hits SQD's own zkSync RPC proxy,
which returns type-0x2 txs with no accessList key at all (verified 11/11 across 50
blocks) — a fork-introduced regression vs stock ponder on a supported chain.

The guard is right in general (it prevents fabricating an empty/NULL access list over
a real one, #27/#32), so keep it as the default. Add an opt-in knob (default OFF,
matching the PORTAL_* boolean convention):
  - unset  → unchanged loud RpcProviderError, whose meta now NAMES the knob;
  - set    → the missing value flows through and stores as an honest NULL (as the
             Portal path already does for column-less datasets, #110/#111).

Read once per standardizeTransactions call (hoisted above the tx loop — cheap, and
toggleable per call in tests). Applied to all 5 tracked wiring patches (0.15.17,
0.16.6-0.16.9), regenerated per PUBLISHING.md. Adds 3 tests to realtime-standardize
covering: default-throws-and-names-knob, knob-passes-through-to-NULL on 0x1/2/3/4,
and knob-preserves-a-present-list.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011h8zdhxsC8A2bcFqZRcjeB
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant