Skip to content

feat: add isIndexed/waitForIndexed #472

Open
ltardivo wants to merge 2 commits into
stagingfrom
feat/waitForIndexed
Open

feat: add isIndexed/waitForIndexed #472
ltardivo wants to merge 2 commits into
stagingfrom
feat/waitForIndexed

Conversation

@ltardivo

Copy link
Copy Markdown
Collaborator

For reliable post-write sync across the stack, instead of sprinkling await sleep(…) calls after every broadcast, new, transfer, or state-changing operation, you can now use computer.waitForIndexed(revOrTxId) to wait until the indexer has committed the Output rows. The result is dramatically fewer flaky tests, faster CI, and predictable behavior under load or on regtest. We also refactored the hot mempool path in the indexer for quicker UTXO visibility while keeping everything eventually consistent and idempotent.

Lib

New public API on Computer (and RestClient)

// Check status
const status = await computer.isIndexed(txIdOrRev);
// { indexed: boolean, hasOutputs: boolean, hasInputs: boolean }

// Wait with sensible defaults (30s timeout, 100ms poll)
await computer.waitForIndexed(txIdOrRev);

// Or tune it
await computer.waitForIndexed(txIdOrRev, { timeoutMs: 10_000, pollMs: 50 });
  • Full TypeScript declarations and JSDoc included.
  • The new GET /tx/:txId/indexed endpoint powers the feature (see Node section).

Migration tip
Replace patterns like this:

await token.transfer(...)
await sleep(500)           // flaky

with:

const txId = await token.transfer(...)
await computer.waitForIndexed(txId)

Node

  • New route GET /v1/:chain/:network/tx/:txId/indexed returns indexer readiness.
  • OutputAction refactored for a faster hot path:
    • Phase 1 (insertSpendGraph): short transaction that commits Output + Input rows immediately → UTXOs and indexed status become visible right away.
    • Phase 2 (propagateMods): separate, idempotent transaction for mod inheritance (safe to retry after ZMQ re-delivery).
  • Updated transaction-strategy comments and DAO layer for clarity and maintainability.
  • All reorg, orphan, and mempool-cleanup paths remain fully atomic.

Contracts, Components & Tests (Public + Private)

Hundreds of sleep calls removed or replaced across:

  • TBC20, TBC777, TBC777M
  • chess-contracts (including the big confirmChainTip helper, now just faucet + waitForIndexed)
  • components (SmartObjectFunction now uses waitForIndexed)
  • swap

Tests are now faster, more deterministic, and no longer depend on magic timing values.

ltardivo added 2 commits July 10, 2026 10:45
This change adds isIndexed and waitForIndexed to Computer and RestClient so callers can poll until the indexer has committed Output rows for a txId (or revision) instead of relying on fixed sleep delays. A corresponding GET /tx/:txId/indexed route was added to the node.
The mempool hot path was restructured: insertAndUpdateMod now performs a short Phase-1 transaction (insertSpendGraph) that commits outputs + inputs immediately, making the UTXO set and indexed status visible to getUTXOs, queries, and waitForIndexed as quickly as possible. Mod propagation (parent lookup + descendant updates) moves to a separate, idempotent Phase-2 step that can safely retry or run after ZMQ re-delivery.
All affected tests across lib-secret, node-secret, and swap2 were updated to use the new helpers (or simply remove now-unnecessary sleeps). The result eliminates the main source of timing flakiness, gives callers explicit control over read-after-write consistency, and keeps the critical indexer path short while preserving atomicity guarantees for reorg and recovery paths.
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