Skip to content

improve(gasless): isolate each record in restructureGaslessDeposits - #3747

Open
droplet-rl wants to merge 1 commit into
masterfrom
droplet/gasless-isolate-restructure
Open

improve(gasless): isolate each record in restructureGaslessDeposits#3747
droplet-rl wants to merge 1 commit into
masterfrom
droplet/gasless-isolate-restructure

Conversation

@droplet-rl

Copy link
Copy Markdown
Contributor

Split out of #3745 to keep that PR reviewable.

restructureGaslessDeposits() maps the whole API response in one flatMap, so a single record that won't restructure (unparseable depositId, unexpected witness shape) rejects the entire query. The API re-supplies every pending record next poll, so one malformed record starves every healthy message indefinitely — before any per-message guard downstream can run.

Extracts the per-record work and isolates it: a record that throws is logged and skipped, the rest are returned. The body moves unchanged, so most of the diff is the reindent.

🤖 Generated with Claude Code

restructureGaslessDeposits() maps the whole API response in a single
flatMap, so one record that won't restructure -- an unparseable
depositId, an unexpected witness shape -- rejects the entire query. The
API re-supplies every pending record on the next poll, so a single
malformed record starves every healthy message indefinitely.

Extract the per-record work and isolate it: a record that throws is
logged and skipped, the rest are returned. The body moves unchanged, so
most of this diff is the reindent.

Co-Authored-By: Claude <noreply@anthropic.com>
droplet-rl added a commit that referenced this pull request Aug 25, 2026
evaluateApiSignatures() has no per-message error boundary, so one bad
message takes down the whole poll. The API re-supplies it next tick, so
it does so once per tick indefinitely.

Add the boundary, and split the two failure classes it catches, because
they want opposite handling:

Malformed -- a derivation from the message payload throws. Deterministic,
so the message is dropped permanently and logged once per requestId.
_isProcessable() checks these at ingestion in _queryGaslessApi(), which
is also the only boundary initialize()'s observation pass gets: a
message whose inputToken won't parse used to fail every restart before
any healthy sibling was reached.

Operational -- an RPC or submission failure inside the state machine.
Never dropped; an outage hits every message at once, so treating one as
unprocessable would exclude healthy deposits with it. The message is
deferred: the fill lock is handed back, or later deposits from the same
depositor strand on an owner that is gone, and the state rewinds to
unclaimed only while nothing can be on chain yet. Past DEPOSIT_SUBMIT it
stays put, since re-running from INITIAL could submit the deposit twice.

restructureGaslessDeposits() needed the same isolation one level lower;
that is #3747, submitted separately.

Co-Authored-By: Claude <noreply@anthropic.com>
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