Summary
The current buy/sell flow submits a Soroban transaction and immediately updates the database. If the server crashes between submission and the database write, the transaction may have executed on-chain but the database reflects the pre-transaction state — leading to permanent inconsistency. This issue implements a write-ahead log that guarantees the server can always recover to a consistent state after a crash, even mid-submission.
Scope
1. WAL table
- Add a
SorobanWALEntry table: id, operation (buy/sell), wallet, creatorWallet, amount, expectedSupplyBefore, xdrPayload, state (PENDING | SUBMITTED | CONFIRMED | FAILED | ROLLED_BACK), txHash, submittedAt, confirmedAt, error, createdAt
- Write the WAL entry with state PENDING inside the same database transaction that validates the request — before any Soroban call is made
- Only proceed to Soroban submission after the WAL entry is durably written
2. Submission and confirmation
- After WAL entry is written, submit the Soroban transaction and update the WAL entry to SUBMITTED with the
txHash
- Poll Horizon for the transaction result; on confirmation update to CONFIRMED and apply all database side effects (balance update, holder count, price snapshot, transaction history) in a single atomic database transaction
- On submission failure: update WAL entry to FAILED with the error, roll back any optimistic state
3. Recovery worker
- On server startup, scan for WAL entries in PENDING or SUBMITTED state older than 30 seconds
- For PENDING entries: the transaction was never submitted — mark as ROLLED_BACK
- For SUBMITTED entries: query Horizon for the
txHash result; if confirmed apply side effects and mark CONFIRMED; if failed mark FAILED; if still pending re-poll up to 10 times with exponential backoff before marking FAILED
- Recovery worker runs once at startup and then every 60 seconds
4. Idempotency guard
- Before applying database side effects from a confirmed transaction, check whether a WAL entry for that
txHash has already been applied — if so skip (idempotent confirmation)
- Apply all side effects in a single database transaction with the WAL state update to CONFIRMED as the last operation so a crash during side-effect application results in a re-applied confirmation on next recovery
5. Integration tests
- Simulate a crash between WAL PENDING write and Soroban submission — run recovery worker — assert WAL entry is ROLLED_BACK and no side effects applied
- Simulate a crash between SUBMITTED and CONFIRMED database write — run recovery worker — assert side effects are applied exactly once
- Submit two requests with the same idempotency key — assert only one WAL entry and one set of side effects
- Confirm the final database state after recovery matches what a crash-free execution would produce
Acceptance Criteria
ETA: 24 hours
Coordinate on Telegram
Summary
The current buy/sell flow submits a Soroban transaction and immediately updates the database. If the server crashes between submission and the database write, the transaction may have executed on-chain but the database reflects the pre-transaction state — leading to permanent inconsistency. This issue implements a write-ahead log that guarantees the server can always recover to a consistent state after a crash, even mid-submission.
Scope
1. WAL table
SorobanWALEntrytable:id,operation(buy/sell),wallet,creatorWallet,amount,expectedSupplyBefore,xdrPayload,state(PENDING | SUBMITTED | CONFIRMED | FAILED | ROLLED_BACK),txHash,submittedAt,confirmedAt,error,createdAt2. Submission and confirmation
txHash3. Recovery worker
txHashresult; if confirmed apply side effects and mark CONFIRMED; if failed mark FAILED; if still pending re-poll up to 10 times with exponential backoff before marking FAILED4. Idempotency guard
txHashhas already been applied — if so skip (idempotent confirmation)5. Integration tests
Acceptance Criteria
ETA: 24 hours
Coordinate on Telegram