Skip to content

feat(outpost-eth): chunked WIRE->ETH envelope delivery; platform envelope cap 32K - #566

Merged
jglanz merged 1 commit into
masterfrom
feature/ethereum-envelope-chunking
Aug 14, 2026
Merged

jglanz merged 1 commit into
masterfrom
feature/ethereum-envelope-chunking

Conversation

@jglanz

@jglanz jglanz commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator

Summary

WIRE->ETH envelopes over 8 192 bytes could break the exchange. This PR moves the Ethereum relay to the Solana-style compiled 8 192-byte chunk loop and applies the platform-wide envelope-cap reduction 65 536 → 32 768 (EIP-7825: a cold near-64K outbound emit ≈ 45 M gas, ~2.7× the 16 777 216 per-tx cap).

Companion PRs: wire-ethereum feature/ethereum-envelope-chunking, wire-solana + wire-tools-ts fix/adjusting-max-envelope-size-to-32k.

Changes

  • Relay (outpost_ethereum_client): 5-arg epoch_in (epochIn(uint32,uint16,uint16,uint32,bytes), selector c3e558bc); owner-bound resume via envelopeChunkState eth_call at latest (adopt only on owner+epoch+shape match; stale-header path-2 retry checks next_epoch_index and SKIPS if advanced; current-epoch shape mismatch → discardEnvelopeChunks then restart; discard revert tolerated as already-clear, logged); per-chunk deadline; sequential receipt-confirmed; NO terminal call, NO crank. Zero libfc changes.
  • Cap: OPP_MAX_ENVELOPE_BYTES = 32'768 (both clients + derived hex/RPC guards); ETHEREUM_MAX_CHUNK_BYTES = 8'192 mirror.
  • Depot coherence: sysio.msgch packing cap → 32 768 (the depot SIZES the envelopes; left at 64 K it would build envelopes the outposts reject → epoch stall). Constant-only, no ABI delta. Copy-back scoped to sysio.msgch.{wasm,abi}; abi byte-identical.
  • --batch-delivery-timeout-ms: sizing-rule comment + SHARED-knob clause (it also bounds the depot push_action completion wait at :818; safe post-WIRE-331). No behavior change.
  • MAX_SCHEDULED_BATCH_OPERATORS rationale restated against 32 K (comment-only in sysio.epoch.hpp; wasm untouched — out-of-table touch, noted deliberately).

Verification

Full build; unit_test (1517), plugin_test, contracts_unit_test (635), test_fc, and all three plugin binaries green. New tests: chunk-count math (4 @ 32K, no +1 terminal), resume decision table + 8 stub-driven delivery cases (in-order, resume, peer-owned ignore, discard-restart, revert-tolerance, epoch-advanced skip, mid-sequence deadline expiry, oversized-storedBytes resume), Solana chunk math 49/50/512, EIP-7825 gas_limit_cap_exceeded pin. RLP regression vector untouched.

Full 14-flow local suite: 14/14 SUCCEEDED against this branch + companions (all four OPP directions circulating; live relay chunk=N/M evidence). Live envelopes measured 653 B (3 ops) → 2 766 B (21 ops), ~115 B/op — all single-chunk; multi-chunk is exhaustively proven at the hardhat + stub layers (no practical local roster reaches 8 192 B; documented fallback per plan).

Notes for reviewers

  • Pre-existing wasm drift (NOT in this PR): sysio.{epoch,opreg,uwrit,chalg,reserv}.wasm rebuild 94–119 B different from their committed copies on master (the PR fix(msgch): rebuild sysio.msgch.wasm from its current source #561 pattern) — deliberately not staged; flagging for a separate refresh.
  • Ops runbook: (1) size batch-delivery-timeout-ms per chunks × (block time + margin) — shared knob, see comment; (2) a depot setconfig changing operators_per_epoch (≠7) needs the OPPInbound upgrade FIRST; (3) every EVM client policy should set max_gas_limit two-sided (≥ ~7 M, ≤ 16 777 216) — policy-free clients are unbounded (maximum_policy).

🤖 Generated with Claude Code

@jglanz
jglanz requested a review from a team August 14, 2026 00:12
heifner
heifner previously approved these changes Aug 14, 2026

@heifner heifner 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.

Approved — epochIn changes selector, so this lands together with wire-ethereum #181 and the proxy upgrade; confirmed that is the plan.

Verified the chunk-count math and per-chunk slicing against _checkChunkShape, the resume ladder against receivedChunks, the terminal-chunk guard, and the 32K cap across outpost_client.hpp, the Solana mirror, sysio.msgch, and OPPCommon.sol.

Non-blocking:

  • envelope_chunk_count_math pins 49/50/512 as literals derived from SOLANA_MAX_CHUNK_BYTES = 672; #552 moves that constant to 668, so whichever lands second turns the test red. Deriving the expectations from the constant avoids it.
  • discard_and_restart treats every json_rpc_error as OPP_ChunkBufferMissing at debug level — insufficient funds, nonce errors, and provider rate limiting land there too, and the next call then takes a shape mismatch with no record of the real cause.
  • The shared batch-operator timeout comment says an undersized tick converges from the on-chain high-water mark. That holds for Ethereum, but the Solana relay still stages from chunk zero every tick — worth scoping the claim to Ethereum.
  • abi_uint_output documents failing closed, but std::stoull stops at the first non-digit, so a 0x quantity would read 0. Not reachable with the current decoder; a from_chars swap would keep it true by construction.

…lope cap 32K

Replace the single-tx OPPInbound.epochIn(bytes) delivery with the compiled
8192-byte chunk loop (Solana pattern): 5-arg epoch_in tx fn, owner-bound
resume via envelopeChunkState at latest (epoch-advanced skip, discard-all
wedge escape), per-chunk deadline, sequential receipt-confirmed submission.
ETHEREUM_MAX_CHUNK_BYTES = 8'192 mirrors wire-ethereum OPPCommon.sol.

Platform cap reduction 65'536 -> 32'768 (EIP-7825 per-tx gas cap):
OPP_MAX_ENVELOPE_BYTES in outpost_client.hpp (both clients + derived
hex/RPC guards), the depot sysio.msgch packing cap (coherence - the depot
sizes the envelopes the outposts now reject above 32K), contract-test
mirrors, and the Solana client chunk math (49/50/512).

- ABI fixture regenerated from the recompiled OPPInbound artifact; new
  epochIn selector c3e558bc pinned (5-input assertions).
- batch-delivery-timeout-ms: sizing-rule comment incl. the SHARED-knob
  clause (also bounds the depot push_action wait at :818; safe
  post-WIRE-331). No behavior change.
- MAX_SCHEDULED_BATCH_OPERATORS sizing rationale restated against 32K
  (comment-only; sysio.epoch wasm untouched).
- Only sysio.msgch.{wasm,abi} copied back; abi byte-identical (no ABI
  delta, no TS regen).

Gates: full build; unit_test (1517), plugin_test, contracts_unit_test
(635), test_fc, and the three plugin binaries all green. Test additions:
chunk-count math, resume decision table + 8 stub-driven delivery cases
(incl. mid-sequence deadline expiry and oversized storedBytes resume),
EIP-7825 gas_limit_cap_exceeded pin.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Change-Id: I33600e69ed2d9580330ea9761b7ab8ad4fea9283
@jglanz
jglanz force-pushed the feature/ethereum-envelope-chunking branch from 09d3059 to b79e36d Compare August 14, 2026 19:06
@jglanz
jglanz merged commit acd2b7e into master Aug 14, 2026
11 checks passed
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.

2 participants