Skip to content

feat: implement whitelist gate in fake indexer, gate availability based on it - #4915

Merged
anodar merged 6 commits into
mainfrom
558-enforce-rpc-providers-whitelist-and-quorum-per-chain_2a
Oct 26, 2026
Merged

anodar merged 6 commits into
mainfrom
558-enforce-rpc-providers-whitelist-and-quorum-per-chain_2a

Conversation

@anodar

@anodar anodar commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

PR 2a/4 from https://github.com/near/mpc-private/issues/558

Also use Ethereum rpc mock instead of Bitcoin, as we're soon stopping support for Bitcoin.

Closes: https://github.com/near/mpc-private/issues/757

@github-actions

This comment was marked as resolved.

@github-actions

This comment was marked as resolved.

@anodar

anodar commented Oct 25, 2026

Copy link
Copy Markdown
Contributor Author

@claude code review, addressed your comments, please take a look.

CI: the "Extra CI checks" job (cargo make check-extra, i.e. cargo deny --all-features check including advisories) failed on this PR. The diff touches no Cargo.toml or lockfile, so this is most likely a new upstream RustSec advisory rather than something introduced here, but it should be confirmed and resolved on main before merging if that check is required.

This is being addressed in a separate PR: #4914

@github-actions

This comment was marked as resolved.

@anodar anodar changed the title test: implement whitelist gate in fake indexer, gate availability based on it feat: implement whitelist gate in fake indexer, gate availability based on it Oct 25, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Pull request overview

Part 2a of the RPC-provider whitelist series. The fake MPC contract used by in-process node tests now stores a per-chain provider whitelist and only reports a chain as available once it is whitelisted, mirroring the real contract's is_whitelisted key check. Node tests switch from a Bitcoin mock to an Ethereum mock (Bitcoin support is being dropped) and whitelist it explicitly, and the E2E foreign-tx test derives its whitelist from the nodes' local config via a new chain_entry_matching helper so the voted entries actually conform to the mock providers. Both points from the earlier review round (the un-whitelisted foreign_chain_configuration.rs test and the trailing-placeholder assumption) are addressed in this revision.

Changes:

  • FakeMpcContractState gains a foreign_chain_whitelist map, a whitelist_foreign_chain_providers setter that triggers recomputation, and a whitelist filter in recompute_available_foreign_chains; the "no whitelisting" deviation note is removed.
  • foreign_chain_configuration.rs now waits for registration, asserts the chain stays unavailable, then whitelists Solana and asserts availability, giving the new gate a direct test.
  • verify_foreign_tx_gating.rs and the shared request_verify_foreign_tx_and_await_response helper move from Bitcoin to an Ethereum mock serving eth_getTransactionReceipt and eth_getBlockByNumber; both cluster setups whitelist the mock.
  • E2E cluster.rs adds chain_entry_matching (placeholder stripped with split_once, auth scheme mapped from AuthConfig) with rstest coverage for all four auth kinds, a placeholder followed by a path segment, and the same-host behaviour.
  • E2E foreign_chain_tx_validation.rs builds the whitelist from fc_config.iter_chains() with quorum 1.

Reviewed changes

Per-file summary
File Description
crates/node/src/indexer/fake.rs Adds the whitelist map and setter; availability recomputation filters on whitelist membership (same semantics as the contract's contains_key); doc comment updated
crates/node/src/tests/foreign_chain_configuration.rs Waits for all nodes to register, asserts availability is empty, whitelists Solana, asserts availability; shared PROVIDER/PROVIDER_URL constants and a solana_whitelist helper
crates/node/src/tests/verify_foreign_tx_gating.rs Bitcoin mock/config replaced by an Ethereum mock; adds ethereum_whitelist and whitelists it in both setups; metric labels updated
crates/node/src/tests.rs Shared helper now sends an Ethereum EvmRpcRequest with Finalized finality
crates/e2e-tests/src/cluster.rs New chain_entry_matching(config, quorum) plus #[cfg(test)] rstest cases asserting every local provider matches as Conforming, and one asserting only the first of two same-host providers conforms
crates/e2e-tests/tests/foreign_chain_tx_validation.rs Whitelist derived from the local config via chain_entry_matching instead of placeholder_chain_entry

Verification notes (by reading, since the local checkout is at the base commit and the node/E2E CI jobs were still running):

  • The reworked configuration test depends on nodes registering only after the contract is Running, because the fake's vote_pk transition does not recompute availability. register_foreign_chains is called exclusively from the coordinator's running-state entry (crates/node/src/coordinator.rs:439), so the whitelist call at foreign_chain_configuration.rs:129 always runs against a Running state. No race.
  • The Ethereum mock's responses carry every field GetTransactionReceiptResponse and GetBlockByNumberResponse require, the finalized head (0x64) is past the receipt block (0xa), and the canonical lookup at 0xa returns the receipt's hash, so the inspector reaches Verdict::Extracted.
  • chain_entry_matching output was traced through match_provider/first_path_mismatch for the E2E URLs (http://127.0.0.1:p/{api_key} for Bitcoin, https://127.0.0.1:p/ for Ethereum via the proxy): all conform. validate_chain_entry imposes no scheme or host restrictions, so loopback entries pass on-chain validation.
  • placeholder_chain_entry is still used by the E2E foreign_chain_configuration.rs test, so it is not dead code.

Findings

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

  • crates/node/src/indexer/fake.rs:89 — whitelist_foreign_chain_providers applies entries without validate_chain_entry, so a test can whitelist something the real contract rejects (quorum 0, quorum above the provider count). Harmless today, but once the follow-up PRs make the node enforce the whitelist it read from this fake, an invalid fixture would exercise a state production can never reach. A cheap guard is an assert! on the quorum bounds in the setter, or adding near-mpc-sdk as a dev-dependency and calling validate_chain_entry.
  • crates/node/src/tests/foreign_chain_configuration.rs:129 — the whitelist step, which is what exercises the new gate, sits in the // Then block. Consider moving the registration wait into // Given and the whitelist call into // When, or splitting the gate check into its own test named for it, so the Given/When/Then structure names the behaviour under test.

✅ Approved

@anodar

anodar commented Oct 25, 2026

Copy link
Copy Markdown
Contributor Author

crates/node/src/indexer/fake.rs:89 — whitelist_foreign_chain_providers applies entries without validate_chain_entry, so a test can whitelist something the real contract rejects (quorum 0, quorum above the provider count)....

Leaving as is, fixtures in test don't use quorum 0 (followup PR has test related to this anyway).

crates/node/src/tests/foreign_chain_configuration.rs:129 — the whitelist step, which is what exercises the new gate, sits in the // Then block. Consider moving the registration wait into // Given and the whitelist call into // When, or splitting the gate check into its own test named for it, so the Given/When/Then structure names the behaviour under test.

Test is checking that no chain is available until it's whitelisted and then expected chains become available after they are whitelisted. Both checks should be in "// Then".

@anodar
anodar added this pull request to stack #4918 October 25, 2026 16:01
@gilcu3
gilcu3 self-requested a review October 26, 2026 10:13

@haiyuechen-nearone haiyuechen-nearone 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.

@gilcu3 gilcu3 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.

LGTM

Comment on lines +137 to +142
const PROVIDER: &str = "public";
const PROVIDER_URL: &str = "https://rpc.public.example.com";

fn solana_whitelist() -> BTreeMap<ForeignChain, ChainEntry> {
BTreeMap::from([(
ForeignChain::Solana,

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.

silly question: do we support Solana already?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes we do.

@anodar
anodar added this pull request to the merge queue Oct 26, 2026
Merged via the queue into main with commit 5ab4b06 Oct 26, 2026
17 checks passed
@anodar
anodar deleted the 558-enforce-rpc-providers-whitelist-and-quorum-per-chain_2a branch October 26, 2026 13:36
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.

3 participants