Skip to content

test(api_remote): retry second mint on scanner-lag 422 - #83

Merged
TaprootFreak merged 1 commit into
developfrom
test/mint-retry-on-scanner-lag
May 23, 2026
Merged

test(api_remote): retry second mint on scanner-lag 422#83
TaprootFreak merged 1 commit into
developfrom
test/mint-retry-on-scanner-lag

Conversation

@TaprootFreak

Copy link
Copy Markdown
Contributor

Problem

send_commit_roundtrip_moves_balance runs after mint_roundtrip_lands_balance_and_proof in the single-threaded suite. Both call /api/mint. The FIRST mint succeeds because num_pubkeys = 0 at startup → server takes the no-prev-commitment branch. The SECOND mint computes prev_commitment_pubkey = generate_public_key(0) and needs its merkle proof from the SMT — which requires the FIRST mint's Taproot inscription to be (a) confirmed on Mutinynet (~30 s block time) and (b) observed by the scanner (30 s Esplora poll). Until ~60 s elapse, the server returns 422 with Unable to get merkle proofs for provided public key.

The test had a retry loop around /api/send for this exact condition (lines ~985-1015) but no retry around the second mint. Result: today's Deploy DEV job's API E2E against DEV step failed at api_remote.rs:958 with assert_eq!(mint_status, StatusCode::OK) because the scanner had not yet caught up between the first and second mint.

Fix

Apply the SAME retry pattern from /api/send to the second mint call:

  • Retry only on 422 + "Unable to get merkle proofs".
  • Bounded by the existing SEND_RETRY_DEADLINE / SEND_RETRY_INTERVAL constants (identical scanner-lag, identical timeout).
  • Final timeout → dev_skip! (matches send-side behavior).
  • Any other status → falls through to assert_eq! with body context (now also surfaces error body in failure message, small improvement).

Why this scope is sufficient

Audited every /api/mint callsite in api_remote.rs:

Test Vulnerable? Reason
mint_roundtrip_lands_balance_and_proof No First test, fresh DB, num_pubkeys=0, server takes no-prev-commitment branch
mint_empty_body_returns_422 No Validation-error path, never reaches scanner state
mint_invalid_hex_address_returns_422 No Same
mint_wrong_address_length_returns_422 No Same
send_commit_roundtrip_moves_balance Yes — fixed Second mint hits get_merkle_proofs(generate_public_key(N-1))

No server-side change needed; this is a test-resilience improvement only.

Test plan

  • CI green (lint + heavy tests + coverage gate).
  • Deploy DEVAPI E2E against DEV step green over multiple runs (state-reset + first-mint + second-mint roundtrip).

send_commit_roundtrip_moves_balance runs after mint_roundtrip in the
single-threaded suite. The second mint requires the FIRST mint's
Taproot inscription to be confirmed on Mutinynet (~30 s block time)
and observed by the scanner (30 s Esplora poll interval), otherwise
/api/mint returns 422 "Unable to get merkle proofs for provided
public key".

The same scanner-lag is already handled around /api/send in this
test via a retry loop. Apply the same pattern to the second mint
call so a fresh DEV state (post-reset or right after the first mint)
doesn't flake the suite.

Falls through to dev_skip! if the deadline elapses, matching the
existing /api/send behavior — preserves the "DEV flake skip, real
failure assert" semantics.
@TaprootFreak
TaprootFreak marked this pull request as ready for review May 23, 2026 12:09
@TaprootFreak
TaprootFreak merged commit 5bc7d12 into develop May 23, 2026
6 of 7 checks passed
TaprootFreak added a commit that referenced this pull request May 23, 2026
The scanner polled Esplora every 30 s for the chain tip, producing
up to ~60 s of lag (Mutinynet 30 s blocks + 30 s scanner poll) before
new mint inscriptions became visible to /api/mint and /api/send.
Test-side stopgaps in api_remote.rs (PR #83) papered over the lag
but the underlying breakage manifested in two error classes
("Unable to get merkle proofs" and "Unable to get mmr inclusion
proof for the previous root") and gated test execution behind
multi-minute retries.

Subscribe to mempool.space WebSocket (wss://mutinynet.com/api/v1/ws
or the configured ESPLORA_WS_URL) for block events. New tips arrive
within tens of milliseconds and feed an mpsc<BlockHash> channel
that the existing scanner_runtime drains. The SMT/MMR write path
is unchanged - only the trigger source moves from sleep to
recv().await. A 90 s liveness watchdog reconnects on half-open
WS; reconnect-with-backoff handles transient disconnects; on
reconnect, the current tip is fetched via the existing EsploraClient
to plug any gap.

Publisher: replaces the 5 s PROPAGATION_WAIT_SECS sleep between
commit and reveal with a track-tx WS subscription on the commit
txid (30 s safety-net timeout - surfaces as a hard error rather
than silent fallback).

CI lint: a Lint & Build step now fails on tokio::time::{sleep,
interval} in scanner*.rs / publisher.rs unless guarded by
#[allow(scanner_polling)] with a justifying comment. Documented
in CONTRIBUTING.md as a project invariant.

ZMQ subscriber (feature = "zmq") is reserved for self-host
operators; kept as a dormant feature flag in this PR.

The test-side retry stopgaps in api_remote.rs (PR #83) will be
removed in a follow-up PR once event-driven scanning is observed
stable on DEV. See #84.

Closes #84.
TaprootFreak added a commit that referenced this pull request May 23, 2026
The scanner polled Esplora every 30 s for the chain tip, producing
up to ~60 s of lag (Mutinynet 30 s blocks + 30 s scanner poll) before
new mint inscriptions became visible to /api/mint and /api/send.
Test-side stopgaps in api_remote.rs (PR #83) papered over the lag
but the underlying breakage manifested in two error classes
("Unable to get merkle proofs" and "Unable to get mmr inclusion
proof for the previous root") and gated test execution behind
multi-minute retries.

Subscribe to mempool.space WebSocket (wss://mutinynet.com/api/v1/ws
or the configured ESPLORA_WS_URL) for block events. New tips arrive
within tens of milliseconds and feed an mpsc<BlockHash> channel
that the existing scanner_runtime drains. The SMT/MMR write path
is unchanged - only the trigger source moves from sleep to
recv().await. A 90 s liveness watchdog reconnects on half-open
WS; reconnect-with-backoff handles transient disconnects; on
reconnect, the current tip is fetched via the existing EsploraClient
to plug any gap.

Publisher: replaces the 5 s PROPAGATION_WAIT_SECS sleep between
commit and reveal with a track-tx WS subscription on the commit
txid (30 s safety-net timeout - surfaces as a hard error rather
than silent fallback).

CI lint: a Lint & Build step now fails on tokio::time::{sleep,
interval} in scanner*.rs / publisher.rs unless guarded by
#[allow(scanner_polling)] with a justifying comment. Documented
in CONTRIBUTING.md as a project invariant.

ZMQ subscriber (feature = "zmq") is reserved for self-host
operators; kept as a dormant feature flag in this PR.

The test-side retry stopgaps in api_remote.rs (PR #83) will be
removed in a follow-up PR once event-driven scanning is observed
stable on DEV. See #84.

Closes #84.
TaprootFreak added a commit that referenced this pull request May 23, 2026
The scanner polled Esplora every 30 s for the chain tip, producing
up to ~60 s of lag (Mutinynet 30 s blocks + 30 s scanner poll) before
new mint inscriptions became visible to /api/mint and /api/send.
Test-side stopgaps in api_remote.rs (PR #83) papered over the lag
but the underlying breakage manifested in two error classes
("Unable to get merkle proofs" and "Unable to get mmr inclusion
proof for the previous root") and gated test execution behind
multi-minute retries.

Subscribe to mempool.space WebSocket (wss://mutinynet.com/api/v1/ws
or the configured ESPLORA_WS_URL) for block events. New tips arrive
within tens of milliseconds and feed an mpsc<BlockHash> channel
that the existing scanner_runtime drains. The SMT/MMR write path
is unchanged - only the trigger source moves from sleep to
recv().await. A 90 s liveness watchdog reconnects on half-open
WS; reconnect-with-backoff handles transient disconnects; on
reconnect, the current tip is fetched via the existing EsploraClient
to plug any gap.

Publisher: replaces the 5 s PROPAGATION_WAIT_SECS sleep between
commit and reveal with a track-tx WS subscription on the commit
txid (30 s safety-net timeout - surfaces as a hard error rather
than silent fallback).

CI lint: a Lint & Build step now fails on tokio::time::{sleep,
interval} in scanner*.rs / publisher.rs unless guarded by
#[allow(scanner_polling)] with a justifying comment. Documented
in CONTRIBUTING.md as a project invariant.

ZMQ subscriber (feature = "zmq") is reserved for self-host
operators; kept as a dormant feature flag in this PR.

The test-side retry stopgaps in api_remote.rs (PR #83) will be
removed in a follow-up PR once event-driven scanning is observed
stable on DEV. See #84.

Closes #84.
TaprootFreak added a commit that referenced this pull request May 23, 2026
The scanner polled Esplora every 30 s for the chain tip, producing
up to ~60 s of lag (Mutinynet 30 s blocks + 30 s scanner poll) before
new mint inscriptions became visible to /api/mint and /api/send.
Test-side stopgaps in api_remote.rs (PR #83) papered over the lag
but the underlying breakage manifested in two error classes
("Unable to get merkle proofs" and "Unable to get mmr inclusion
proof for the previous root") and gated test execution behind
multi-minute retries.

Subscribe to mempool.space WebSocket (wss://mutinynet.com/api/v1/ws
or the configured ESPLORA_WS_URL) for block events. New tips arrive
within tens of milliseconds and feed an mpsc<BlockHash> channel
that the existing scanner_runtime drains. The SMT/MMR write path
is unchanged - only the trigger source moves from sleep to
recv().await. A 90 s liveness watchdog reconnects on half-open
WS; reconnect-with-backoff handles transient disconnects; on
reconnect, the current tip is fetched via the existing EsploraClient
to plug any gap.

Publisher: replaces the 5 s PROPAGATION_WAIT_SECS sleep between
commit and reveal with a track-tx WS subscription on the commit
txid (30 s safety-net timeout - surfaces as a hard error rather
than silent fallback).

CI lint: a Lint & Build step now fails on tokio::time::{sleep,
interval} in scanner*.rs / publisher.rs unless guarded by
#[allow(scanner_polling)] with a justifying comment. Documented
in CONTRIBUTING.md as a project invariant.

ZMQ subscriber (feature = "zmq") is reserved for self-host
operators; kept as a dormant feature flag in this PR.

The test-side retry stopgaps in api_remote.rs (PR #83) will be
removed in a follow-up PR once event-driven scanning is observed
stable on DEV. See #84.

Closes #84.
TaprootFreak added a commit that referenced this pull request May 23, 2026
The scanner polled Esplora every 30 s for the chain tip, producing
up to ~60 s of lag (Mutinynet 30 s blocks + 30 s scanner poll) before
new mint inscriptions became visible to /api/mint and /api/send.
Test-side stopgaps in api_remote.rs (PR #83) papered over the lag
but the underlying breakage manifested in two error classes
("Unable to get merkle proofs" and "Unable to get mmr inclusion
proof for the previous root") and gated test execution behind
multi-minute retries.

Subscribe to mempool.space WebSocket (wss://mutinynet.com/api/v1/ws
or the configured ESPLORA_WS_URL) for block events. New tips arrive
within tens of milliseconds and feed an mpsc<BlockHash> channel
that the existing scanner_runtime drains. The SMT/MMR write path
is unchanged - only the trigger source moves from sleep to
recv().await. A 90 s liveness watchdog reconnects on half-open
WS; reconnect-with-backoff handles transient disconnects; on
reconnect, the current tip is fetched via the existing EsploraClient
to plug any gap.

Publisher: replaces the 5 s PROPAGATION_WAIT_SECS sleep between
commit and reveal with a track-tx WS subscription on the commit
txid (30 s safety-net timeout - surfaces as a hard error rather
than silent fallback).

CI lint: a Lint & Build step now fails on tokio::time::{sleep,
interval} in scanner*.rs / publisher.rs unless guarded by
in CONTRIBUTING.md as a project invariant.

ZMQ subscriber (feature = "zmq") is reserved for self-host
operators; kept as a dormant feature flag in this PR.

The test-side retry stopgaps in api_remote.rs (PR #83) will be
removed in a follow-up PR once event-driven scanning is observed
stable on DEV. See #84.

Closes #84.
TaprootFreak added a commit that referenced this pull request May 23, 2026
…#87)

The scanner polled Esplora every 30 s for the chain tip, producing
up to ~60 s of lag (Mutinynet 30 s blocks + 30 s scanner poll) before
new mint inscriptions became visible to /api/mint and /api/send.
Test-side stopgaps in api_remote.rs (PR #83) papered over the lag
but the underlying breakage manifested in two error classes
("Unable to get merkle proofs" and "Unable to get mmr inclusion
proof for the previous root") and gated test execution behind
multi-minute retries.

Subscribe to mempool.space WebSocket (wss://mutinynet.com/api/v1/ws
or the configured ESPLORA_WS_URL) for block events. New tips arrive
within tens of milliseconds and feed an mpsc<BlockHash> channel
that the existing scanner_runtime drains. The SMT/MMR write path
is unchanged - only the trigger source moves from sleep to
recv().await. A 90 s liveness watchdog reconnects on half-open
WS; reconnect-with-backoff handles transient disconnects; on
reconnect, the current tip is fetched via the existing EsploraClient
to plug any gap.

Publisher: replaces the 5 s PROPAGATION_WAIT_SECS sleep between
commit and reveal with a track-tx WS subscription on the commit
txid (30 s safety-net timeout - surfaces as a hard error rather
than silent fallback).

CI lint: a Lint & Build step now fails on tokio::time::{sleep,
interval} in scanner*.rs / publisher.rs unless guarded by
in CONTRIBUTING.md as a project invariant.

ZMQ subscriber (feature = "zmq") is reserved for self-host
operators; kept as a dormant feature flag in this PR.

The test-side retry stopgaps in api_remote.rs (PR #83) will be
removed in a follow-up PR once event-driven scanning is observed
stable on DEV. See #84.

Closes #84.
TaprootFreak added a commit that referenced this pull request May 23, 2026
The scanner polled Esplora every 30 s for the chain tip, producing
up to ~60 s of lag (Mutinynet 30 s blocks + 30 s scanner poll) before
new mint inscriptions became visible to /api/mint and /api/send.
Test-side stopgaps in api_remote.rs (PR #83) papered over the lag
but the underlying breakage manifested in two error classes
("Unable to get merkle proofs" and "Unable to get mmr inclusion
proof for the previous root") and gated test execution behind
multi-minute retries.

Subscribe to mempool.space WebSocket (wss://mutinynet.com/api/v1/ws
or the configured ESPLORA_WS_URL) for block events. New tips arrive
within tens of milliseconds and feed an mpsc<BlockHash> channel
that the existing scanner_runtime drains. The SMT/MMR write path
is unchanged - only the trigger source moves from sleep to
recv().await. A 90 s liveness watchdog reconnects on half-open
WS; reconnect-with-backoff handles transient disconnects; on
reconnect, the current tip is fetched via the existing EsploraClient
to plug any gap.

Publisher: replaces the 5 s PROPAGATION_WAIT_SECS sleep between
commit and reveal with a track-tx WS subscription on the commit
txid (30 s safety-net timeout - surfaces as a hard error rather
than silent fallback).

CI lint: a Lint & Build step now fails on tokio::time::{sleep,
interval} in scanner*.rs / publisher.rs unless guarded by
in CONTRIBUTING.md as a project invariant.

ZMQ subscriber (feature = "zmq") is reserved for self-host
operators; kept as a dormant feature flag in this PR.

The test-side retry stopgaps in api_remote.rs (PR #83) will be
removed in a follow-up PR once event-driven scanning is observed
stable on DEV. See #84.

Closes #84.
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