Skip to content

Refuse addresses Alchemy cannot serve and keep one address's gap out of health (B08) - #22

Closed
AsyncAssassin wants to merge 1 commit into
mainfrom
fix/alchemy-unmapped-chains
Closed

AsyncAssassin wants to merge 1 commit into
mainfrom
fix/alchemy-unmapped-chains

Conversation

@AsyncAssassin

Copy link
Copy Markdown
Owner

Summary

B08 from the merged review of v0.4.0, with the CHANGELOG wording of B19 and the foreign-cursor case deferred from #15; 0.4.1 is released once all fixes are merged. Under type=alchemy the seeded local-evm chain is enabled but has no Alchemy network. An address registered there got 201. Its first sync turned the provider state to FETCH_FAILED and /actuator/health into 503, contrary to the 0.4.0 note that one bad address no longer does. The next start then stopped on the rollout preflight, and the address could only be fixed with SQL.

  • Registration: ChainProviderPort.supportsChain(chainId) (default true) tells whether the active provider serves a chain; Alchemy serves the mapped ones. Registration refuses any other chain with 404 Unsupported chain, as decided for this finding. The detail now names the case: "The chain is not configured, is disabled, or is not served by the active provider." The three cases stay indistinguishable, as before.
  • Health: a configuration gap of one address is a new AddressConfigurationException, a subclass of ProviderConfigurationException. That covers its chain without a network, its asset without an enabled config, and a block with more events than a page. It stays terminal for that address's runs, but it is shown as lastDataError and health stays UP, like invalid data. A rejected key or an outage still turns health DOWN.
  • Addresses from before the switch: the preflight rule for them stays fatal, as the card recommends. docs/alchemy-runbook.md has the SQL.
  • A cursor another provider wrote, such as the demo simulator's sim:… after a demo run on the same database, now fails with "…is not valid JSON, so another provider wrote it; clear the address's sync_cursors row to start it under Alchemy (docs/alchemy-runbook.md, section 6)". The runbook row gives the SQL and what the next start skips.
  • B19 wording: the 0.4.0 notes, the README, the runbook, and the preflight's KDoc said sync runs retry until Alchemy answers after an outage at startup. They retry up to max-attempts (five by default, about 7.5 minutes of backoff) and then fail, and nothing probes again. The README, the runbook, and the KDoc now say so, and [Unreleased] corrects the 0.4.0 note instead of rewriting the released entry. A periodic re-probe stays with B19 in batch 3.

CHANGELOG.md lists the changes under [Unreleased] → Fixed; docs/api.md, docs/architecture.md, and docs/testing.md describe them.

Verification

  • ./gradlew clean check: 276 tests, 0 failures, 2 skipped (the env-gated Alchemy live smoke).

  • AlchemyChainProviderTests: a request for local-evm, and one whose asset has no enabled config, throw AddressConfigurationException without an RPC call. The state stays probe-succeeded, the reason is lastDataError, and health is UP. supportsChain is true for eth-sepolia only.

  • AlchemyChainProviderHealthIndicatorTests encoded the old behavior, an unmapped chain turning health DOWN; it now expects UP with lastDataError.

  • AlchemyProviderSyncIntegrationTests (e2e with type=alchemy): registering on local-evm throws UnsupportedChainException and stores nothing. AccountAndAddressApiIntegrationTests checks the new 404 detail.

  • AlchemyCursorTests: a sim: token and a JSON cursor marked http name the fix.

  • Mutation check: each change removed on its own turns its test red. That covers the registration check, supportsChain, the data-error branch, and the cursor message.

  • Live against the real Alchemy Sepolia endpoint (prod, type=alchemy; the key only in the environment, 0 occurrences in the log), the main jar against this branch:

    Step main This branch
    register an address on local-evm 201 404 Unsupported chain
    register an address on eth-sepolia 201 201
    sync the Sepolia address SUCCEEDED SUCCEEDED
    alchemyChainProvider health UP, fetch-succeeded UP, fetch-succeeded

This PR and #15 to #21 each add a section under [Unreleased] in CHANGELOG.md, so each later merge needs a one-file rebase. The other files merge cleanly with all of them.

… out of health

Under type=alchemy the seeded local-evm chain is enabled but has no
Alchemy network. An address registered there got 201, its first sync
turned the provider state to FETCH_FAILED and /actuator/health into
503, contrary to the 0.4.0 note that one bad address no longer does,
and the next start stopped on the rollout preflight.

The provider port says whether it serves a chain, and registration
refuses one it cannot serve with 404 Unsupported chain; the detail
now names that case. A configuration gap of one address, its chain
without a network, its asset without an enabled config, or a block
larger than a page, is an AddressConfigurationException: still
terminal for its runs, but shown as lastDataError while health stays
UP. A cursor another provider wrote, such as the demo simulator's,
now fails with a message that says so and points to the runbook.

The 0.4.0 notes also said that after an outage at startup sync runs
retry until Alchemy answers; they retry up to max-attempts and then
fail, and nothing probes again. The README, the runbook, and the
preflight's description now say so.
@AsyncAssassin

Copy link
Copy Markdown
Owner Author

Combined into #23 together with the other batch-1 fixes, so they merge without a rebase per PR. This description keeps the detailed evidence for its fix.

@AsyncAssassin
AsyncAssassin deleted the fix/alchemy-unmapped-chains branch September 24, 2026 05:21
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