Skip to content

Remote config integrity: verify pins, list each chain once in the bundled list and chain types - #1318

Closed
takemiyamakoto wants to merge 3 commits into
masterfrom
hotfix/remote-config-integrity
Closed

takemiyamakoto wants to merge 3 commits into
masterfrom
hotfix/remote-config-integrity

Conversation

@takemiyamakoto

Copy link
Copy Markdown
Contributor

Summary

Follow-up to #1317. It fixes three config-integrity gaps that #1317 left open. Stacked on #1317 (hotfix/dev-chains-avail-dedupe @ 1cbd903), so until #1317 merges, the diff to master also shows its commit.

  1. Bundled fallback chain list repeated three chains. fearless/Modules/LiquidityPools/LiquidityPoolDetails/Resources/chains.json listed Manta Pacific Mainnet (169), Enjin Relaychain (d8761d3c…) and Liberland (6bd89e05…) twice, as a block of three. This PR removes the second block (76 → 73 chains).
    • The Manta Pacific and Enjin copies were identical.
    • The removed Liberland copy listed only LLD and had no XCM. The kept copy lists LLD, LLM and XOR with the SORA route, as the production and development lists do.
    • The order now matches the development list.
    • The app reads this file only when ChainSyncService.fetchLocalData is true, and it is false today. If it were true, sanitizingRemoteChains would refuse the whole list with duplicateRemoteChainIdentifier. None of the three chains is retired or app-owned, so none is filtered out before that check.
  2. Production chain types repeated one chain. remote-config/production/chains/all_chains_types.json listed 6d8d9f145c2177fa83512492cdd80a71e29f22473f4a8943a6292149ac319fb9 twice. That chainId is the SORA Kusama parachain (2011), which NetworkRetirement retires.
    • Index 54: runtime_id 1, with numeric type ids ("Phase": "78", "17": "GenericEvent", …).
    • Index 98: runtime_id 14, with sora2_parachain_runtime::RuntimeEvent / RuntimeCall.
    • This PR removes index 54 and keeps index 98. The next section explains why.
  3. Nothing verified the ownedSha256 pins in config/remote-config-imports.json. scripts/verify-remote-config.py now checks every pin.

Why the index-98 types entry stays

Every reader of chainTypesSourceUrl folds the array into a [String: Data] map with partialResult[chainId] = data, so the last entry for a chainId wins. The readers are:

  • the app's ChainsTypesSyncService, created in ChainRegistryFactory;
  • SnapshotHotBootBuilder, both its remote fallback and the map ChainsTypesSyncService saved;
  • the SSF ChainsTypesSyncService that ChainRegistryAssembly and XcmAssembly use.

The types URL has no F_DEV branch, so every build, Debug included, reads this production file. Builds have therefore always used index 98. Removing index 54 leaves the map unchanged: I checked it is identical before and after, with 109 chainIds.

Provenance: shared-features-utils 8791e434 ("Update chains.json (#1056)", 2025-01-20, "Add SORA parachain types") appended the runtime 14 entries for both SORA parachains. It did not remove the older Kusama entry.

The development all_chains_types.json and the bundled types.json still hold the runtime_id 1 entry, and I left them as they are. No build reads the development types file. The bundled one is read only when ChainsTypesSyncService.fetchLocalData is true, and it is false today. The chain is retired and is in no chain list.

Audit changes (scripts/verify-remote-config.py)

The audit now also fails in these cases:

  • A chainId is repeated in a chain list (*/chains/v*/chains*.json, as before), in a chain types file (*/chains/all_chains_types.json), or in the bundled chains.json / types.json. Other documents may still repeat chainIds, for example the XCM files.
  • config/remote-config-imports.json is missing or unreadable.
  • A pin is malformed or repeated.
  • A pinned file is missing. Only exact-case paths inside remote-config/ count, so ../ and case slips also fail.
  • A pinned file's SHA-256 differs from its ownedSha256. The message gives both digests.

The output gains a pinnedFiles count. There are 12 new tests in scripts/test-remote-config.py, and the docs describe the checks.

Data edits

  • One commit carries the data edits, the re-pin and the log entry, as the manifest rule requires.
  • production/chains/all_chains_types.json is re-pinned: ced6c59d… → cbef0d2d….
  • One corrections entry is appended to the manifest.
  • The registry table in docs/ChainRegistryVersions.md is refreshed.

Results

All checks ran locally; the project doesn't gate on hosted CI.

  • Head: dab448005fb86406368e8e78917e04df9c6a2b37.
  • Commits: 936220434 (data fix, re-pin, log, registry table) and dab448005 (audit, tests, docs).
  • Both commits are green on their own. At 936220434, the old audit passes.
Stage New audit (dab4480) Old audit (1cbd903)
A: #1317's data fails: 3 bundled repeats (169, d8761d3c, 6bd89e05) + chain types 6d8d9f14 passes
A1: only the bundled chains.json reverted fails: its 3 repeats passes
A2: only all_chains_types.json and its pin reverted fails: 6d8d9f14 repeated passes
B: data fixed, manifest not re-pinned fails: all_chains_types.json has SHA-256 cbef0d2d…, pinned ced6c59d… passes
C: a pinned file deleted fails: pinned file remote-config/production/chains/v2/chains.json is missing passes
D: head passes: {"documents": 34, "ownedReferences": 1988, "pinnedFiles": 949} passes

On a clean tree at head:

  • python3 scripts/test-remote-config.py: 28/28 OK, under Python 3.9.6 and 3.14.10.
  • python3 scripts/verify-remote-config.py . passes, and so does the run without an argument. All 949 pins match.

To reproduce the "before" run:

mkdir -p /tmp/before
git archive 1cbd9038d remote-config config/remote-config-imports.json fearless/Modules/LiquidityPools/LiquidityPoolDetails/Resources | tar -x -C /tmp/before
python3 scripts/verify-remote-config.py /tmp/before

Merge notes

🤖 Generated with Claude Code

takemiyamakoto and others added 3 commits November 7, 2026 18:54
remote-config/development/chains/v13/chains_dev.json listed Avail DA
Mainnet (b91746b4...) twice, as the shared-features-utils f2ed4ccf list
it was imported from already did. Debug and Fearless Dev builds read
this list (F_DEV), and ChainSyncService.sanitizingRemoteChains refuses
a list that repeats a chainId, so every sync failed and those builds
kept only Bitcoin, Solana and Taira: no Polkaswap, no Substrate
networks.

Both copies were identical to the single production entry. Keep the one
at the production position (after Viction, next to Avail Turing
Testnet) and delete the other; no other entry changes.

- Re-pin the file's ownedSha256 and log the correction in
  config/remote-config-imports.json.
- scripts/verify-remote-config.py now fails on a versioned chain list
  that repeats a chainId; the previous audit passed this list.
- Refresh the owned-registry table in docs/ChainRegistryVersions.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ain types

The bundled fallback chain list
(fearless/Modules/LiquidityPools/LiquidityPoolDetails/Resources/chains.json)
repeated a block of three entries: Manta Pacific Mainnet (169), Enjin
Relaychain (d8761d3c...) and Liberland (6bd89e05...). Drop the second
block. The Manta Pacific and Enjin copies were identical. The dropped
Liberland copy listed only LLD and no XCM; the kept copy lists LLD, LLM
and XOR with the SORA route, as the production and development lists do.
The order now matches the development list (76 -> 73 chains).
ChainSyncService reads this file only when ChainSyncService.fetchLocalData
is true (false today); sanitizingRemoteChains would refuse the whole list
for these repeats.

remote-config/production/chains/all_chains_types.json listed the retired
SORA Kusama parachain (6d8d9f14...) twice: runtime_id 1 with numeric type
ids at index 54, and the runtime_id 14 entry that shared-features-utils
8791e434 appended in January 2025 at index 98. Every reader of the file
(ChainsTypesSyncService, SnapshotHotBootBuilder and the SSF
ChainsTypesSyncService) folds it into a map keyed by chainId, so the last
entry wins. Drop the index-54 entry and keep the one builds use; the map
the app builds is unchanged (110 -> 109 entries, 109 chainIds).

Re-pin the chain types file's ownedSha256 (ced6c59d... -> cbef0d2d...),
log both edits in config/remote-config-imports.json and refresh the
registry table in docs/ChainRegistryVersions.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…and the bundled fallback

scripts/verify-remote-config.py now also fails when:
- the bundled fallback chains.json or types.json
  (fearless/Modules/LiquidityPools/LiquidityPoolDetails/Resources) repeats
  a chainId. ChainSyncService.sanitizingRemoteChains refuses a whole chain
  list that does;
- a chain types file (remote-config/*/chains/all_chains_types.json) repeats
  a chainId. Its readers keep the last entry and drop the others silently;
- config/remote-config-imports.json is missing or unreadable, a pin is
  malformed or repeated, a pinned file is missing (exact-case paths inside
  remote-config/ only), or a pinned file's SHA-256 differs from its
  ownedSha256. Nothing checked these pins before.

The output gains a pinnedFiles count. Other documents (for example the XCM
files) may still repeat a chainId. Twelve tests added (28 pass); the docs
describe the checks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@takemiyamakoto

Copy link
Copy Markdown
Contributor Author

Folded into #1326, which brings every open iOS PR into master in one change, so one code-owner approval covers it. This PR's branch is kept.

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