Skip to content

fix(gateway): retry on addMilestone write-throw (estimateGas read-lag under burst) - #163

Open
LamaSu wants to merge 1 commit into
masterfrom
fix/v2-addmilestone-write-retry
Open

fix(gateway): retry on addMilestone write-throw (estimateGas read-lag under burst)#163
LamaSu wants to merge 1 commit into
masterfrom
fix/v2-addmilestone-write-retry

Conversation

@LamaSu

@LamaSu LamaSu commented Jun 16, 2026

Copy link
Copy Markdown
Owner

Residual after #161 (the 1/3 concurrency failure)

#161 (trust-receipt) fixed the stale getMilestoneCount read and is verified live: single create works (escrow 0xcdC811…, milestoneCount=1 on-chain), concurrency went 0/3 → 2/3. But 1/3 still returned fast_track_failed.

Root cause (from logs, not inferred)

The failed create's logs show: escrow created, then nothing — no milestone-confirmed, no dropped, no reverted, no retry. That pattern is only produced by the addMilestone writeContract throwing before the receipt wait. The existing try wrapped only waitForTransactionReceipt, so a write-throw skipped the retry → straight to fast_track_failed.

Most likely: eth_estimateGas for addMilestone runs against the just-created escrow and hits a load-balanced public-RPC replica that hasn't synced the createEscrowV2 yet → "execution reverted". Same read-lag class as the getMilestoneCount bug #161 fixed, on a different call.

Fix

Move the addMilestone writeContract inside the existing try, so a write-throw is treated like a dropped receipt — abandon the escrow, mint a fresh one. Safe because:

  • the retry re-reads the nonce (line 294) → no nonce leak;
  • a write that throws at estimateGas never broadcast a tx → no double-add;
  • the createEscrowV2 round-trip on the next attempt gives the RPC time to sync;
  • a mined-but-reverted tx still throws immediately (real contract error).

Verification

  • tsc: 0 new errors in paid-job-flow.ts (the line-21 import error is pre-existing unbuilt-workspace noise).
  • signer-lock test: 3/3.
  • Post-deploy: 3+ concurrent creates all return an escrow, no fast_track_failed.

🤖 Generated with Claude Code

… under burst)

Residual after #161: under burst concurrency, ~1/N creates still returned
fast_track_failed. Logs showed the escrow created, then NO milestone-confirmed,
dropped, reverted, or retry line — the signature of the addMilestone writeContract
THROWING before the receipt wait. The existing try only wrapped
waitForTransactionReceipt, so a write-throw propagated straight to
fast_track_failed with no retry.

Cause: eth_estimateGas for addMilestone runs against the just-created escrow and
hits a load-balanced public-RPC replica that hasn't synced the createEscrowV2 yet
-> "execution reverted". Same read-lag class as the getMilestoneCount bug #161
fixed, on a different call.

Fix: move the addMilestone writeContract inside the existing try, so a write-throw
is treated like a dropped receipt — abandon the escrow and mint a fresh one. The
retry re-reads the nonce (no leak) and the createEscrowV2 round-trip gives the RPC
time to sync. A mined-but-reverted tx still throws immediately.

Context: #161 (trust-receipt) is verified live — single create works (0xcdC811,
milestoneCount=1 on-chain) and 2/3 concurrent succeed. This targets the residual
1/3 (the write-throw path); to be verified post-deploy.

Co-Authored-By: Claude Opus 4.8 (1M context) <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