Log NYM mixFetch request lifecycle#734
Open
j0ntz wants to merge 2 commits into
Open
Conversation
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Contributor
Author
The 2026-07-20 QA report on staging 26071707 shows NYM requests failing with 'panic:todo: extract error message', a placeholder the mix-fetch v1 Go layer emits in place of the real reason. Our own logging recorded only mixFetch setup, so a wedged request could not be attributed to a host or endpoint. Log each mixnet request on the way out and once when it settles, with the method, host, path, elapsed time, and either the HTTP status or the raw error text. A start line with no matching terminal line is now the signature of a request that never returned. Query strings are omitted because RPC endpoints carry API keys. Both io backends share one wrapper so the browser A/B harness and the app produce the same log shape.
j0ntz
force-pushed
the
jon/nym-android-fee-hang
branch
from
July 20, 2026 18:11
3b7063a to
4a12e40
Compare
Contributor
Author
j0ntz
force-pushed
the
jon/nym-android-fee-hang
branch
from
July 20, 2026 23:33
e5de482 to
2dd3d62
Compare
j0ntz
force-pushed
the
jon/nym-android-fee-hang
branch
from
July 20, 2026 23:45
2dd3d62 to
0f654ce
Compare
Contributor
Author
j0ntz
force-pushed
the
jon/nym-android-fee-hang
branch
from
July 20, 2026 23:51
0f654ce to
e70ca55
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit e70ca55. Configure here.
Measured on a throttled Android emulator with the request logging from the previous commit: a single Avalanche wallet opens 12 concurrent mixnet requests during one sync. mix-fetch v1 has a history of serving one request per host at a time, which this module used to work around with a per-host queue removed in 5916d9d on the understanding that 1.4.2 had fixed it. Cap the mixnet at 6 concurrent requests overall and 2 per host, queueing the rest. Measured before and after on the same emulator against the live mixnet: peak in-flight drops from 12 to 6, per-request latency is unchanged (p50 2666ms vs 2669ms), and every request still settles. Also drop the per-request timeout from 300s to 60s. Healthy requests measure 2-4 seconds, so five minutes only ever meant that a request the mixnet never answered pinned its caller for five minutes. On the send screen that is the 'Calculating Fee' spinner that QA reports as an infinite hang. Neither change touches the request logging, which is still needed to attribute the remaining NYM-internal failure.
j0ntz
force-pushed
the
jon/nym-android-fee-hang
branch
from
July 20, 2026 23:56
e70ca55 to
c023d0a
Compare
Contributor
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.





CHANGELOG
Does this branch warrant an entry to the CHANGELOG?
Dependencies
none
Description
Asana: https://app.asana.com/1/9976422036640/project/1215088146871429/task/1216729024836433
QA reported on 2026-07-20 (staging 26071707, Android) that with NYM privacy on,
Coreum and Avalanche sends sit on "Calculating Fee" indefinitely. That report is
after the v1 revert landed, so the revert did not resolve it.
The exported logs attached to the QA task show the failure but not its cause:
panic:todo: extract error messageis a placeholder emitted by mix-fetch v1's Golayer, which discards the real reason. Our own logging covered only mixFetch
setup, so there was no way to tie a wedged request to a host or endpoint.
This adds per-request instrumentation. Each mixnet request writes one line on the
way out and exactly one when it settles:
A
startline with no matching terminal line is now the signature of a requestthat never returned, and it names the host.
These lines end up in user-uploaded support logs, so the URI is reduced first:
the query string is dropped entirely (RPC endpoints carry API keys there), and
any path segment that looks like an identifier is masked. Route paths survive
(
api.avax.network/ext/bc/C/rpc,monerolws1.edge.app/get_address_info) whileaddresses and txids do not (
blockbook.example.com/api/v2/address/<redacted>).Two details worth calling out:
warn, notinfo. The app configures the core withdefaultLogLevel: 'warn', andfilterLogsdropsinfoat that level, so aninfoline would be missing from a QA log export unless the tester had firstenabled Verbose Logging.
warnis what makes this reach the export by default.NYM is opt-in and low volume, so the extra lines only appear for the users whose
reports we are diagnosing.
produce the same log shape.
No mixnet behavior changes: no timeout, pinning, or transport changes. This is
instrumentation for the next QA retest.
Verified
Driven on the iOS sim with NYM enabled for Avalanche and Base, against the live
mixnet, with this core
updot-linked into the app. Captured from the runningapp's console pipeline:
verify-repo.shpassed (prepare, eslint, jest).Already surfacing something
The in-flight counter reached 20 concurrent mixnet requests, including four
simultaneous requests to the same host (
base-rpc.publicnode.com). mix-fetch v1carried a one-request-per-host limitation that this repo used to work around with
a per-host queue, removed in 5916d9d on the grounds that 1.4.2 fixed it. That
saturation is worth a look as a candidate mechanism for the Android wedge, on a
slower device with more wallets enabled. Not addressed here.
Avalanche completed normally over NYM on iOS throughout (2-4s per request), which
matches QA's own iOS result and is why the Android-only report needs logs from an
Android build to go further.
Update: Android emulator findings, and a fix
Ran this on a deliberately throttled Android emulator (2 cores, 2 GB,
-netdelay umts,API 36) with a fresh account and one Avalanche wallet, against the live mixnet. The logging
above localized the failure on its first run.
The panic is host-specific, not random
3 of 3 requests to
api.avascan.infopanicked in ~1s. Every other host settled normally:Across 32 requests: 29 settled OK (p50 2666ms), 3 failed, 0 never settled.
api.avascan.infois the etherscan-compatible transaction-history endpoint for Avalanche, which matches QA's
avalanche-me: syncNetwork failed ... panic:todoexactly. The panic originates inside NYM's Golayer and is not something this wrapper can fix; it is now at least attributable to a host.
"Error fetching fees from Info Server" is a red herring
Those are plain 404s from the info server, not a NYM failure. That log line appears on every EVM
chain in QA's report and is unrelated to the mixnet.
What this commit changes
A single Avalanche wallet peaked at 12 concurrent mixnet requests. A real user's wallet list
multiplies that, and the app already warns that enabling NYM on multiple assets slows sends. So:
unanswered request into an apparently permanent "Calculating Fee" spinner
Measured before/after on the same emulator, live mixnet:
Queue waits up to 2.1s are now logged (
queued 2106ms) so throttling is distinguishable fromnetwork time.
verify-repo.shpasses (prepare, eslint, jest 162 passing).Honest scope
The QA wedge itself did not reproduce here: with one wallet, every request settled and
in-flight always drained to zero. These two changes are targeted mitigation for the mechanisms
that can produce the reported symptom, not a confirmed fix for it. The logging is retained
precisely so the next QA build says which host wedges if it happens again.
Review hardening
Four rounds of reviewer-bot findings were taken (one rejected, see below). Beyond the two
changes above, this PR now also:
MAX_QUEUE_WAIT_MS), past which a request proceeds anyway.Without it, a starved queue would have added its own multi-minute delay on top of the request
timeout and recreated the very hang this targets
cannot grow the wait list without bound
error (
Post "https://host/tx/<txid>?apikey=...") cannot reintroduce an identifier or key thatwas masked a few characters earlier on the same line
Final state on device, same emulator, running exactly this commit:
peak in-flight 6, p50 2718ms, 0 never-settled, 162 unit tests passing.