Skip to content

feat(foreign-tx): wire svm chains into node - #4138

Open
frolvanya wants to merge 9 commits into
feat/svm-inspectorfrom
feat/svm-node-wiring
Open

feat(foreign-tx): wire svm chains into node#4138
frolvanya wants to merge 9 commits into
feat/svm-inspectorfrom
feat/svm-node-wiring

Conversation

@frolvanya

Copy link
Copy Markdown
Collaborator

Connects config -> inspector -> signing, so a node actually serves Solana and
Fogo verification requests. Before this PR the node still rejects them.

  • node config: fogo section added (solana already existed);
  • verify_foreign_tx: one typed inspector fan-out per chain
    (SolanaInspector / FogoInspector, so a slot mix-up is a compile error)
    and dispatch arms that replace the old
    bail!("ForeignChainRpcRequest::Solana is unsupported"); tests pin that
    each chain's config feeds its own slot;
  • health check: golden check + network-fingerprint probe for both chains;
  • operator docs, localnet templates and user-config gain both chains.

Every genesis hash committed here was read from a live node:
solana mainnet 5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d
solana devnet EtWTRABZaYq6iMfeYKouRu166VU2xqa1wcaWoxPkrZBG
fogo mainnet CDLtwKnaCoK157uaHQDj4fHu72AyD2519Cphmpiq6hvT
fogo testnet 9GGSFo95raqzZxWqKM5tGYvJp5iv4Dm565S4r8h5PEu9

Verified with the config tester against live endpoints (mainnet and testnet both
pass), including a negative check: pointing the Solana entry at Fogo's URL fails
with "chain id mismatch", so the check is not passing vacuously.

Copilot AI lite review requested due to automatic review settings August 13, 2026 13:20
@frolvanya
frolvanya force-pushed the feat/svm-node-wiring branch from 80ebf9c to 285b50c Compare August 13, 2026 13:20

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Wires SVM-based foreign chain verification (Solana and Fogo) end-to-end in the MPC node, connecting operator config through inspector fan-out into verify_foreign_tx, and extending health-check/config-tester/docs so nodes can validate and serve these chains instead of rejecting them.

Changes:

  • Adds typed Solana/Fogo inspector fan-out and request dispatch for verify_foreign_tx (plus config parsing / wiring tests).
  • Extends foreign-chain health checks with SVM genesis-hash fingerprint probing and golden vectors for Solana/Fogo.
  • Updates operator/localnet documentation and templates to include Solana/Fogo configuration and Solana localnet request args.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
docs/running-an-mpc-node-in-tdx-external-guide.md Adds Solana/Fogo foreign_chains examples for testnet/mainnet deployments.
docs/localnet/mpc-configs/config.yaml.template Adds Solana config to localnet YAML template (needs follow-up for Fogo + comment correctness per PR comments).
docs/localnet/mpc-config.template.toml Adds Solana config to localnet TOML template (needs follow-up for Fogo + comment correctness per PR comments).
docs/localnet/localnet.md Documents how to generate a fresh Solana signature and run a Solana verify_foreign_transaction call.
docs/localnet/args/verify_foreign_tx_solana.json Adds a localnet request fixture for Solana verification (with placeholder tx id).
docs/foreign-chain-transactions.md Documents SVM fingerprint probing (getGenesisHash) and tabulates Solana/Fogo genesis hashes.
deployment/cvm-deployment/user-config.toml Adds Solana/Fogo config blocks for CVM deployment user config (testnet + commented mainnet variant).
crates/node/src/web.rs Extends debug/config surface to report configured provider counts for Fogo.
crates/node/src/tests/foreign_chain_configuration.rs Ensures foreign chain configuration setup includes the new fogo slot.
crates/node/src/providers/verify_foreign_tx/sign.rs Adds Solana/Fogo dispatch to SVM inspectors for request execution.
crates/node/src/providers/verify_foreign_tx.rs Adds Solana/Fogo inspectors to the node wiring and tests to pin correct config-to-slot mapping.
crates/node-config/src/foreign_chains.rs Adds fogo to config model and parsing/validation tests.
crates/foreign-chain-health-check/src/probe.rs Implements provider probing for Solana and Fogo using their inspectors.
crates/foreign-chain-health-check/src/lib.rs Runs SVM checks for Solana/Fogo instead of skipping them as “not yet supported”.
crates/foreign-chain-health-check/src/golden.rs Introduces SVM golden vectors (genesis hash) for mainnet/testnet Solana/Fogo.
crates/foreign-chain-health-check/src/checks.rs Adds check_svm that validates chain identity via canonicalized genesis hash.
crates/foreign-chain-config-tester/README.md Updates config tester docs to reflect SVM chain checks and expected output.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread docs/localnet/mpc-configs/config.yaml.template
Comment thread docs/localnet/mpc-config.template.toml
Comment thread crates/node/src/providers/verify_foreign_tx.rs
@claude

claude Bot commented Aug 13, 2026

Copy link
Copy Markdown

Pull request overview

This PR connects the already-merged SVM inspector to the rest of the node so that Solana and Fogo verification requests are actually served instead of rejected. It adds a fogo node-config section (solana already existed), fills the solana/fogo inspector slots in ForeignChainInspectors, replaces the bail!("ForeignChainRpcRequest::Solana is unsupported") arm with a shared execute_svm_request helper used by both SVM chains, and wires both chains into the two health-check routes (golden identity check + network-fingerprint probe). Operator-facing templates and docs gain both chains, with every genesis hash reportedly read back from a live node.

Changes:

  • mpc-node-config: new fogo: Option<ForeignChainConfig> section, mapped to dtos::ForeignChain::Fogo in all_configured_chains, so it feeds registration, validation and the whitelist verifier like every other chain.
  • mpc-node: solana/fogo FanOut<SvmInspector<HttpClient, _>> slots built through with_http_client; sign.rs dispatches both variants through one generic execute_svm_request; /debug provider counts gain fogo.
  • foreign-chain-health-check: SvmVector golden entries (mainnet + testnet), check_svm genesis-hash identity check, run_svm fan-out, and getGenesisHash probe arms for Solana and Fogo.
  • Docs/config: user-config.toml, TDX guide, localnet templates and a new verify_foreign_tx_solana.json fixture; the fingerprint tables in docs/foreign-chain-transactions.md are updated and the stale "solana … has no inspector" passage is corrected.

Reviewed changes

Per-file summary
File Description
crates/foreign-chain-config-tester/README.md Describes SVM chains as identity-checked rather than replayed; sample output gains a solana row.
crates/foreign-chain-health-check/src/checks.rs New check_svm<Chain>: compares the provider's canonicalized getGenesisHash against the golden value.
crates/foreign-chain-health-check/src/golden.rs SvmVector type plus solana/fogo genesis hashes for mainnet and testnet; base58 decode test extended.
crates/foreign-chain-health-check/src/lib.rs run_svm per-provider loop; solana moves out of the "not yet supported" block, fogo added; chain-list test updated.
crates/foreign-chain-health-check/src/probe.rs Fingerprint-probe arms for ForeignChain::Solana and ForeignChain::Fogo; TODO comment narrowed.
crates/node-config/src/foreign_chains.rs fogo config section, DTO mapping, and a parse/validate test for it.
crates/node/src/providers/verify_foreign_tx.rs solana/fogo inspector slots; new tests pinning that each config feeds only its own slot.
crates/node/src/providers/verify_foreign_tx/sign.rs Solana/Fogo dispatch arms delegating to the new generic execute_svm_request.
crates/node/src/tests/foreign_chain_configuration.rs fogo: None added to the exhaustive ForeignChainsConfig literal.
crates/node/src/web.rs fogo provider count in the debug endpoint; Fogo URL added to the redaction assertions.
deployment/cvm-deployment/user-config.toml Testnet solana (devnet) + fogo sections, and the commented mainnet variants.
docs/foreign-chain-transactions.md Fingerprint tables gain solana/fogo; corrects the passage claiming Solana has no inspector.
docs/localnet/args/verify_foreign_tx_solana.json New request fixture: placeholder tx_id, rent-sysvar AccountState extractor.
docs/localnet/localnet.md Solana walkthrough, including a snippet that patches in a fresh finalized signature.
docs/localnet/mpc-config.template.toml, docs/localnet/mpc-configs/config.yaml.template Localnet solana section with the mainnet genesis hash.
docs/running-an-mpc-node-in-tdx-external-guide.md Solana/Fogo blocks for the testnet and mainnet config examples.

Findings

Blocking (must fix before merge):

  • crates/node/src/providers/verify_foreign_tx/sign.rs:140 — the dispatch arms are the exact hazard the PR guards against one file over (verify_foreign_tx.rs:157: "a config.solana/config.fogo swap still type-checks"), but nothing pins them. execute_svm_request is generic over Chain, so Solana(request) => … self.inspectors.fogo … compiles cleanly, and the consequence is worse than a config-slot swap: every node substitutes identically, so FanOut's cross-provider agreement check cannot catch it and the network signs a ForeignTxSignPayloadV1 asserting a Solana transaction over data read from Fogo. Please pin request-variant → inspector-slot the same way you pinned config → slot. A cheap seam is to extract the selection, e.g.

    impl ForeignChainInspectors<HttpClient> {
        fn svm(&self, chain: dtos::ForeignChain) -> Option<&FanOut<SvmInspector<HttpClient, ???>>> {}
    }

    — or, since the two slots have different Chain types, a small #[cfg(test)] assertion that each arm reaches the fan-out built from the corresponding config (two mock SVM endpoints answering distinguishable getTransaction payloads works, mirroring crates/e2e-tests/tests/foreign_chain_tx_validation.rs).

  • crates/foreign-chain-health-check/src/checks.rs:218, crates/foreign-chain-health-check/src/lib.rs:102, crates/foreign-chain-health-check/src/probe.rs:111 — the new health-check code paths ship untested, against engineering-standards.md §Add tests ("if the change was reverted, these tests would fail"). Concretely, all of these survive the current suite: stubbing check_svm to Ok(()), dropping the got != expected comparison, swapping golden.solanagolden.fogo in run_svm calls, or reverting the two probe arms to ProbeNotImplemented. golden.rs:242 only proves the constants are 32 base58 bytes — it cannot catch a mainnet/devnet or solana/fogo mix-up. The sibling check_sui landed with check_sui__should_pass_when_provider_is_on_the_expected_network and check_sui__should_fail_when_chain_id_differs (checks.rs:385, checks.rs:400), and probe.rs already tests every other wired chain (probe_all_providers__should_report_every_evm_chain_on_its_expected_network_as_healthy). httpmock is in scope in both modules and getGenesisHash is a single-value JSON-RPC response, so the equivalents are a few lines each.

Non-blocking (nits, follow-ups, suggestions):

  • docs/localnet/localnet.md:507 — the snippet rewrites the tracked docs/localnet/args/verify_foreign_tx_solana.json in place, so following the walkthrough leaves the operator's working tree dirty with a mainnet signature that goes stale anyway. Suggest leaving the patched copy in /tmp and pointing the call at it:
    jq --arg tx "$TX_HEX" '.request.request.Solana.tx_id = $tx' \
      docs/localnet/args/verify_foreign_tx_solana.json > /tmp/verify_foreign_tx_solana.json
    with file-args /tmp/verify_foreign_tx_solana.json in the near contract call-function line below.
  • crates/foreign-chain-health-check/src/golden.rs:34, lib.rs:322, checks.rs:215 — the same rationale ("SVM providers prune historical transactions, so identity is checked instead") is restated in three doc comments within one crate. Per engineering-standards.md §Write helpful code comments, keep it at the definition (check_svm) and let the other two be intra-doc links to it.
  • crates/foreign-chain-health-check/src/checks.rs:218 — for SVM, check_svm is now byte-for-byte the same assertion the fingerprint probe already makes (getGenesisHash, canonicalized, compared), unlike check_sui, which additionally inspects a checkpointed transaction. Given TODO(#3969) plans to retire the golden route, it may be worth deciding now whether the SVM golden entries earn their keep or whether the probe alone should cover these chains.
  • deployment/cvm-deployment/user-config.toml:286 — Fogo ships with a single public provider on both networks, so its fan-out degenerates to one source and FanOut's cross-provider agreement check is vacuous for that chain (every other chain in the template has 2–4). A short comment saying that is intentional until a second Fogo endpoint exists would save operators the question.

⚠️ Issues found

@frolvanya
frolvanya force-pushed the feat/svm-node-wiring branch from 285b50c to 33f3143 Compare August 13, 2026 13:31
@frolvanya
frolvanya force-pushed the feat/svm-node-wiring branch from 33f3143 to b9f01ce Compare August 13, 2026 14:36
@frolvanya
frolvanya force-pushed the feat/svm-node-wiring branch 2 times, most recently from 796ab4b to 3cb07e1 Compare August 13, 2026 15:51
@frolvanya
frolvanya force-pushed the feat/svm-node-wiring branch from e88458d to b904c1d Compare August 13, 2026 16:49
@anodar
anodar self-requested a review August 24, 2026 11:33
@frolvanya

Copy link
Copy Markdown
Collaborator Author

@claude review

@claude

claude Bot commented Aug 26, 2026

Copy link
Copy Markdown

Pull request overview

Node-wiring layer of the SVM stack: connects operator config to inspector fan-out to verify_foreign_tx dispatch, so a node actually serves Solana and Fogo verification requests instead of bail!-ing on them. Adds the missing fogo config section, fills the solana/fogo slots in ForeignChainInspectors, routes both request variants through a shared generic execute_svm_request, and wires both chains into the two health-check routes (golden identity check + fingerprint probe). Docs, localnet templates and the CVM user-config gain both chains.

Since the last round the health-check test gap was closed properly: check_svm, run_svm and both probe arms now have tests that would fail if the wiring were reverted or crossed. The remaining problem is the other direction — making Solana supported invalidated three pre-existing tests built around Solana being unsupported, and the PR re-pointed them at Sui instead of deleting them. Cargo test: other is currently red.

Changes:

  • mpc-node-config: fogo section, mapped to dtos::ForeignChain::Fogo in all_configured_chains (and so iter_chains, registration, validation).
  • mpc-node: solana/fogo FanOut<SvmInspector<HttpClient, _>> slots; sign.rs dispatches both variants through one generic execute_svm_request; /debug counts gain fogo.
  • foreign-chain-health-check: SvmVector golden entries, check_svm, run_svm, getGenesisHash probe arms, plus tests for each.
  • Docs/config: user-config.toml, TDX guide, localnet templates, verify_foreign_tx_solana.json fixture, Solana localnet walkthrough.

Reviewed changes

Per-file summary
File Description
crates/foreign-chain-config-tester/README.md SVM chains described as identity-checked, not replayed; sample output gains a solana row.
.../health-check/src/checks.rs New check_svm<Chain> comparing canonicalized getGenesisHash to the golden value, plus pass/fail tests.
.../health-check/src/golden.rs SvmVector plus solana/fogo genesis hashes for mainnet and testnet; base58 test extended.
.../health-check/src/lib.rs run_svm per-provider loop; solana out of the "not yet supported" block, fogo added; cross-chain vector test.
.../health-check/src/probe.rs Probe arms for Solana/Fogo, must_put_chain slots, healthy/wrong-network tests; ProbeNotImplemented tests re-pointed at Sui.
crates/node-config/src/foreign_chains.rs fogo config section, DTO mapping, parse/validate test.
crates/node/src/providers/verify_foreign_tx.rs solana/fogo inspector slots and tests pinning each config to its own slot.
crates/node/src/providers/verify_foreign_tx/sign.rs Solana/Fogo dispatch arms delegating to the new generic execute_svm_request.
crates/node/src/tests/{foreign_chain_configuration,verify_foreign_tx_gating}.rs fogo: None in exhaustive ForeignChainsConfig literals.
crates/node/src/web.rs fogo provider count in /debug; Fogo URL added to the redaction assertions.
deployment/cvm-deployment/user-config.toml Testnet solana (devnet) + fogo sections and the commented mainnet variants.
docs/foreign-chain-transactions.md Probe and fingerprint-value tables gain solana/fogo; "which chains read the field" paragraph rewritten.
docs/localnet/args/verify_foreign_tx_solana.json New fixture: placeholder tx_id, rent-sysvar AccountState extractor.
docs/localnet/localnet.md Solana walkthrough; snippet writes the patched copy to /tmp.
docs/localnet/mpc-config.template.toml, docs/localnet/mpc-configs/config.yaml.template Localnet solana section with the mainnet genesis hash.
docs/running-an-mpc-node-in-tdx-external-guide.md Solana/Fogo blocks for the testnet and mainnet config examples.

Findings follow in the next comment.

@claude

claude Bot commented Aug 26, 2026

Copy link
Copy Markdown

Findings (continued from the previous comment)

Blocking (must fix before merge):

  • crates/foreign-chain-health-check/src/probe.rs:813 and :838 — the two ProbeNotImplemented tests were re-pointed from Solana to Sui, but Sui has a probe: the ForeignChain::Sui => probe_chain(... SuiInspector ...) arm sits directly above the _ => catch-all this PR edits. With CLOSED_PORT_URL, prepare_sui builds a GrpcSuiClient fine and the connection then fails, so the status is Unreachable, not ProbeNotImplemented — which is exactly what the adjacent probe_all_providers__should_report_an_unreachable_sui_provider asserts for the identical config. Both re-pointed assertions are now false.

    Why no good substitute existed: after this PR no ForeignChainsConfig field is left without a probe — Ton is the only unprobed chain and it has no config slot (must_put_chain panics on it). So probe_all_providers__should_report_a_chain_with_no_fingerprint_probe_as_not_implemented is no longer expressible and should be deleted rather than re-pointed. probe_all_providers__should_report_every_configured_chain_under_its_own_chain only needs two chains keyed separately, so keep Sui there and assert what it actually produces:

    assert_eq!(
        must_status_of(&report, ForeignChain::Sui, "publicnode"),
        ProviderStatus::Unreachable
    );
  • crates/foreign-chain-health-check/src/lib.rs:489check_all_providers__should_skip_configured_but_unsupported_chains still configures solana (rpc_url https://rpc.example.com) and asserts Status::Skipped(reason) containing "not yet supported", but this PR deletes the only mark_skipped(..., "not yet supported by the node", ...) call in the crate. golden.solana is Some for mainnet, so run_svm now runs for real: the test fails with Status::Failed(...) and issues a live outbound HTTP request from a unit test. Nothing is "configured but unsupported" any more — delete the test.

    Together these two account for the red Cargo test: other check; worth confirming it is green before merge rather than treating it as pre-existing.

  • docs/foreign-chain-transactions.md:574 — stale sentence, now contradicted by the table two lines below it: "Every chain with an inspector is probed, each by the RPC below. solana has none, so it ignores expected_network_fingerprint." The PR adds | solana, fogo | getGenesisHash | to that very table. Doc drift is review-blocking per CLAUDE.md; the second sentence can just be dropped, since every chain with an inspector is now probed.

  • docs/foreign-chain-transactions.md:747 — the replacement paragraph lists the chains that read expected_network_fingerprint as "starknet, bitcoin, aptos, the EVM chains and the SVM chains today" and omits sui, which has had a GetServiceInfo probe since before this PR and appears in the probe table above. A Sui operator would conclude the field is ignored for their chain, when leaving it unset actually reports every Sui provider as MissingExpectedFingerprint.

  • crates/node/src/providers/verify_foreign_tx/sign.rs:219 — still open from the previous round: the request-variant to inspector-slot mapping is unpinned. execute_svm_request is generic over Chain, so Solana(request) => ... self.inspectors.fogo ... type-checks, and unlike a config-slot swap every node substitutes identically, so FanOut's cross-provider agreement cannot catch it. Not repeating the rationale — see the earlier comment for the suggested seam.

Non-blocking (nits, follow-ups):

  • crates/foreign-chain-health-check/src/probe.rs:160// nothing to probe them it. is a half-finished edit; it also fits on one line: // TODO(#4003): Ton has no inspector to probe it with.
  • crates/foreign-chain-health-check/src/lib.rs:535"ethereum" is appended to the expected list, but it is already the first entry of that same list; the loop just checks the row twice.
  • crates/foreign-chain-health-check/src/checks.rs:218 — the Chain parameter on check_svm is decorative: network_fingerprint/canonical_fingerprint are implemented for SvmInspector<Client, Chain> with only Chain: Send + Sync and never touch it, so check_svm::<Solana> and check_svm::<Fogo> are the same function; only expected_genesis_hash separates the chains. Fine in itself, but it reads as type-level protection it does not give — drop the parameter or say so in the doc comment.
  • crates/foreign-chain-health-check/src/checks.rs:386 and lib.rs:451mock_genesis_hash is defined verbatim twice and is byte-identical to the pre-existing probe.rs::mock_fingerprint. None of the three asserts the method name, so a probe pointed at the wrong RPC method would still pass.
  • crates/foreign-chain-health-check/src/lib.rs:428config_at differs from the existing config_with_provider only in the rpc_url; consider parameterizing the existing helper.
  • crates/foreign-chain-config-tester/README.md:52 — the sample output gains a solana row but not fogo, and the totals move to 5 passed; inconsistent either way if the sample is meant to show a fully-configured node.
  • Previously raised, still open: the "SVM providers prune historical transactions" rationale restated in three doc comments in one crate (golden.rs:34, lib.rs:333, checks.rs:215), and Fogo shipping with a single public provider in deployment/cvm-deployment/user-config.toml, which makes its fan-out agreement check vacuous.

⚠️ Issues found

@frolvanya
frolvanya force-pushed the feat/svm-node-wiring branch from e3f7fb8 to 2ac18cd Compare August 26, 2026 18:54
@near near deleted a comment from claude Bot Aug 26, 2026
@frolvanya

Copy link
Copy Markdown
Collaborator Author

@claude review

@claude

claude Bot commented Aug 26, 2026

Copy link
Copy Markdown

Pull request overview

Node-wiring layer of the SVM stack: connects operator config → inspector fan-out → verify_foreign_tx dispatch, so a node actually serves Solana and Fogo verification requests instead of bail!-ing on them. Adds the missing fogo config section, fills the solana/fogo slots in ForeignChainInspectors, routes both request variants through a shared generic execute_svm_request, and wires both chains into the two health-check routes (golden identity check + fingerprint probe). Docs, localnet templates and the CVM user-config gain both chains.

Since the last round every health-check finding is resolved: the ProbeNotImplemented test is deleted rather than re-pointed at Sui (which has a probe and would report Unreachable); should_report_every_configured_chain_under_its_own_chain now uses Bitcoin and asserts Unreachable, matching what starknet_only + CLOSED_PORT_URL already produces at probe.rs:595; should_skip_configured_but_unsupported_chains is replaced with an Ethereum-on-testnet skip (TESTNET.ethereum is None, so nothing reaches the network); the duplicated "ethereum" entry is gone; the localnet snippet writes to /tmp; and the foreign-chain-transactions.md passages are consistent with the new probe table.

Changes:

  • mpc-node-config: fogo section, mapped to dtos::ForeignChain::Fogo in all_configured_chains (and so iter_chains, registration, validation).
  • mpc-node: solana/fogo FanOut<SvmInspector<HttpClient, _>> slots; sign.rs dispatches both variants through one generic execute_svm_request; /debug counts gain fogo.
  • foreign-chain-health-check: SvmVector golden entries, check_svm, run_svm, getGenesisHash probe arms, plus tests for each.
  • Docs/config: user-config.toml, TDX guide, localnet templates, verify_foreign_tx_solana.json fixture, Solana localnet walkthrough.

Reviewed changes

Per-file summary
File Description
crates/foreign-chain-config-tester/README.md SVM chains described as identity-checked, not replayed; sample output gains a solana row.
crates/foreign-chain-health-check/src/checks.rs New check_svm<Chain> comparing the canonicalized getGenesisHash to the golden value, plus pass/fail tests.
crates/foreign-chain-health-check/src/golden.rs SvmVector plus solana/fogo genesis hashes for mainnet and testnet; base58 decode test extended.
crates/foreign-chain-health-check/src/lib.rs run_svm per-provider loop; solana out of the "not yet supported" block, fogo added; cross-chain vector test; two pre-existing tests re-based onto Ethereum/testnet.
crates/foreign-chain-health-check/src/probe.rs Probe arms for Solana/Fogo, must_put_chain slots, healthy/wrong-network tests; the ProbeNotImplemented test deleted, the "own chain" test moved to Bitcoin.
crates/node-config/src/foreign_chains.rs fogo config section, DTO mapping, parse/validate test.
crates/node/src/providers/verify_foreign_tx.rs solana/fogo inspector slots and tests pinning each config to its own slot.
crates/node/src/providers/verify_foreign_tx/sign.rs Solana/Fogo dispatch arms delegating to the new generic execute_svm_request.
crates/node/src/tests/{foreign_chain_configuration,verify_foreign_tx_gating}.rs fogo: None in the exhaustive ForeignChainsConfig literals.
crates/node/src/web.rs fogo provider count in /debug; Fogo URL added to the redaction assertions.
deployment/cvm-deployment/user-config.toml Testnet solana (devnet) + fogo sections and the commented mainnet variants.
docs/foreign-chain-transactions.md Probe and fingerprint-value tables gain solana/fogo; the two stale ProbeNotImplemented / "no inspector" sentences removed.
docs/localnet/args/verify_foreign_tx_solana.json New fixture: placeholder tx_id, rent-sysvar AccountState extractor.
docs/localnet/localnet.md Solana walkthrough; the patched fixture is written to /tmp.
docs/localnet/mpc-config.template.toml, docs/localnet/mpc-configs/config.yaml.template Localnet solana section with the mainnet genesis hash.
docs/running-an-mpc-node-in-tdx-external-guide.md Solana/Fogo blocks for the testnet and mainnet config examples.

Findings

Blocking (must fix before merge):

  • crates/node/src/providers/verify_foreign_tx/sign.rs:219 — unchanged from the previous two rounds, and now the only test gap left in the PR: the headline behaviour change (a node serves Solana/Fogo instead of bail!("ForeignChainRpcRequest::Solana is unsupported")) has no test that would fail if it were reverted, and the request-variant → inspector-slot mapping is unpinned. execute_svm_request is generic over Chain, so Solana(request) => … self.inspectors.fogo … type-checks; unlike a config-slot swap, every node substitutes identically, so FanOut's cross-provider agreement cannot catch it. Per engineering-standards.md §Add tests this needs coverage either way.

    The seam already exists and would close both halves at once: crates/e2e-tests/tests/foreign_chain_tx_validation.rs has one verify_<chain> helper per chain against an httpmock provider, all driven from verify_foreign_transaction__should_sign_all_supported_chains (:614). Adding verify_solana / verify_fogo with distinguishable getTransaction payloads pins each arm to its own fan-out. Note that configuring Solana in that cluster invalidates the "chain not in the foreign chain config" negative at :655, which currently uses Solana — it needs a chain that stays unconfigured (Fogo cannot be it if you add both).

Non-blocking (nits, follow-ups):

  • crates/foreign-chain-health-check/src/probe.rs:298ANY_FINGERPRINT's doc comment ("For a chain with no probe: the value is never read, only whether it is set at all") is now false. Its one remaining use is Bitcoin in should_report_every_configured_chain_under_its_own_chain, and Bitcoin does have a probe: probe_chain canonicalizes the value via BitcoinInspector::canonical_fingerprint before use. The test passes only because the provider is unreachable, not because the value is unread.
  • crates/foreign-chain-health-check/src/probe.rs:159 — with Solana and Fogo wired, every chain that has a ForeignChainsConfig slot now has a probe arm, so the _ => catch-all is unreachable through iter_chains() and ProviderStatus::ProbeNotImplemented is dead (its only test was correctly deleted here). Consider spelling the arm out as ForeignChain::Ton => … so that a future chain gaining a config slot without a probe is a compile error rather than a silent ProbeNotImplemented row. The comment also reads as a wrapped half-sentence and fits on one line.
  • crates/foreign-chain-health-check/src/probe.rs:877 — "a cross-wired arm would compare Solana's against Fogo's" overstates what the test pins. SolanaInspector and FogoInspector differ only in the Chain marker, which neither network_fingerprint nor canonical_fingerprint reads, so swapping the inspector types between the two arms is unobservable; the expected fingerprint and the URL both come from the config slot, which chain already selects. What the test genuinely pins is that neither chain falls through to _ => ProbeNotImplemented — worth saying that instead. (The sibling comment in lib.rs:437, about a crossed golden vector binding, is accurate — that one really is the discriminator.)
  • Previously raised, still open:
    • the "SVM providers prune historical transactions" rationale restated in three doc comments in one crate (golden.rs:33, lib.rs:333, checks.rs:215) — keep it at check_svm and intra-doc-link the other two;
    • mock_genesis_hash defined verbatim in both checks.rs:387 and lib.rs:447, and byte-identical to the pre-existing probe.rs::mock_fingerprint; none of the three asserts the JSON-RPC method name, so a probe pointed at the wrong method still passes;
    • lib.rs:431config_at differs from config_with_provider only in the rpc_url; parameterize the existing helper;
    • checks.rs:218 — the Chain parameter on check_svm is decorative (check_svm::<Solana> and check_svm::<Fogo> are the same function); it reads as type-level protection it does not provide;
    • crates/foreign-chain-config-tester/README.md:50 — the sample output gains solana but not fogo (and the totals move to 5 passed), inconsistent if the sample is meant to show a fully-configured node;
    • deployment/cvm-deployment/user-config.toml:286 — Fogo ships with a single public provider on both networks, so its fan-out degenerates to one source and the cross-provider agreement check is vacuous for that chain; every other chain in the template has 2–4. A one-line note that this is intentional until a second endpoint exists would save operators the question.

⚠️ Issues found

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.

2 participants