Skip to content

feat: probe Bitcoin provider by genesis block hash - #4067

Merged
haiyuechen-nearone merged 5 commits into
mainfrom
4003-probe-bitcoin-genesis-hash
Aug 14, 2026
Merged

feat: probe Bitcoin provider by genesis block hash#4067
haiyuechen-nearone merged 5 commits into
mainfrom
4003-probe-bitcoin-genesis-hash

Conversation

@haiyuechen-nearone

@haiyuechen-nearone haiyuechen-nearone commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Closes #4091.

Bitcoin has no chain id, so the fingerprint is the genesis block hash and the probe is getblockhash at height 0, the method the inspector's canonical chain check already uses.

Notes for review

  • Nothing is trimmed. Leading zeros are digits of the hash and the genesis hash opens with ten of them, so normalization is lowercase with an optional 0x prefix stripped. Text that is not 64 hex characters reads back unchanged, so the report shows what the provider actually claimed.

@haiyuechen-nearone haiyuechen-nearone changed the title feat(probe): probe Bitcoin for its genesis block hash feat: probe Bitcoin for its genesis block hash Aug 5, 2026
@haiyuechen-nearone
haiyuechen-nearone marked this pull request as ready for review August 5, 2026 16:13
@claude

claude Bot commented Aug 5, 2026

Copy link
Copy Markdown

Pull request overview

Adds the Bitcoin leg of the network-fingerprint probe (#4003). Since Bitcoin exposes no chain id, the fingerprint is the genesis block hash, obtained via getblockhash at height 0 — the same RPC the inspector's canonical-chain check already relies on, so no new provider capability is required. BitcoinInspector gains a NetworkFingerprintInspector impl and the health-check probe routes ForeignChain::Bitcoin through it; normalization is lowercase plus an optional 0x strip, with leading zeros preserved because they are digits of the hash.

The implementation mirrors the Starknet/EVM legs of the same stack one-for-one (canonical_text on the transport response type, canonical_fingerprint delegating to it, classify_rpc_client_error on the RPC call), so retry/timeout/fan-out behavior is inherited and already covered by the shared tests. Two things reduce rollout risk: probe_all_providers is not yet called from any binary, and both shipped configs (deployment/cvm-deployment/user-config.toml:137, docs/localnet/mpc-config.template.toml:64) already carry a bitcoin fingerprint, so newly activating the probe cannot flip those deployments to MissingExpectedFingerprint.

Changes:

  • NetworkFingerprintInspector for BitcoinInspector: getblockhash(0), RPC errors classified via classify_rpc_client_error.
  • New GetBlockHashResponse text newtype with canonical_text() (lowercase, optional 0x/0X strip, non-64-hex text returned verbatim) plus an rstest table covering canonical / upper-cased / prefixed / not-a-hash / too-short / not-hex.
  • Health-check probe wires ForeignChain::Bitcoin; the "no probe" test fixture moves from Bitcoin to Solana and mock_chain_id becomes mock_fingerprint now that answers are not all chain ids.
  • Integration test asserting the request shape (getblockhash, params:[0]) and case normalization; ignored manual test against a live provider.
  • Docs: probe table gains the bitcoin row, normalization paragraph and the "which chains read the field" paragraph updated.

Reviewed changes

Per-file summary
File Description
crates/foreign-chain-inspector/src/bitcoin/inspector.rs Adds the NetworkFingerprintInspector impl and the GENESIS_BLOCK_HEIGHT constant.
crates/foreign-chain-rpc-interfaces/src/bitcoin.rs Adds GetBlockHashResponse with canonical_text() and its unit-test table.
crates/foreign-chain-health-check/src/probe.rs Routes ForeignChain::Bitcoin to probe_chain; renames the not-implemented fixture to Solana and mock_chain_id to mock_fingerprint; adds healthy / wrong-network Bitcoin tests.
crates/foreign-chain-inspector/tests/bitcoin_inspector.rs Integration test asserting the probe's RPC shape and lowercase normalization.
crates/foreign-chain-inspector/tests/bitcoin_rpc_manual.rs Ignored live-provider test pinning the shipped mainnet fingerprint.
docs/foreign-chain-transactions.md Probe table row, normalization sentence, and the list of chains that read expected_network_fingerprint.

Findings

No blocking issues. Correctness spot checks that held up: canonical_fingerprint is idempotent as the trait requires (a 64-hex value lowercases to itself, a 0x-prefixed value strips once, non-hash text is a fixed point); the 64-char hash plus optional prefix stays well inside NetworkFingerprint::MAX_CHARS = 96, so no real fingerprint is truncated before comparison; BITCOIN_MAINNET and BITCOIN_TESTNET3 match the real genesis hashes and the values already documented at docs/foreign-chain-transactions.md:678; and a non-string result still lands on MalformedResponse rather than being reported as a network mismatch.

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

  • docs/foreign-chain-transactions.md:699 — only the first line of the paragraph was re-wrapped, leaving this one at 114 columns while the rest of the file wraps near 100. Re-flowing the paragraph keeps future diffs on it minimal.
  • crates/foreign-chain-health-check/src/probe.rs:810 and :833 — the two new Bitcoin tests spell out the ForeignChainsConfig { bitcoin: Some(..), ..Default::default() } literal, while every Starknet test goes through the starknet_only helper (which is what bitcoin_only became for Solana at :310). A bitcoin_only helper alongside solana_only would keep the fixtures uniform.

✅ Approved

@haiyuechen-nearone haiyuechen-nearone self-assigned this Aug 6, 2026
Base automatically changed from 4003-probe-evm-chain-identity to main August 7, 2026 12:12
@haiyuechen-nearone
haiyuechen-nearone force-pushed the 4003-probe-bitcoin-genesis-hash branch from 665e20a to 605f520 Compare August 7, 2026 13:09
@haiyuechen-nearone haiyuechen-nearone changed the title feat: probe Bitcoin for its genesis block hash feat(probe): identify Bitcoin by its genesis block hash Aug 7, 2026
@haiyuechen-nearone haiyuechen-nearone changed the title feat(probe): identify Bitcoin by its genesis block hash feat: identify Bitcoin by its genesis block hash Aug 7, 2026
@haiyuechen-nearone haiyuechen-nearone changed the title feat: identify Bitcoin by its genesis block hash feat: probe Bitcoin provider by genesis block hash Aug 7, 2026
@haiyuechen-nearone
haiyuechen-nearone force-pushed the 4003-probe-bitcoin-genesis-hash branch 2 times, most recently from f270c33 to 9dde2cc Compare August 7, 2026 19:43
netrome
netrome previously approved these changes Aug 7, 2026

@netrome netrome left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Nice stuff, thanks!

})
.await
}
// TODO(#4003): probe Aptos and Sui. Ethereum, Solana and Ton have no inspector, so

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reminds me, we need to pick up the Ton inspector. Daniel's PR is growing stale there 😅

@haiyuechen-nearone
haiyuechen-nearone force-pushed the 4003-probe-bitcoin-genesis-hash branch 2 times, most recently from 1888570 to eeb2b2d Compare August 11, 2026 16:23
kevindeforth
kevindeforth previously approved these changes Aug 13, 2026

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

Thank you!

/// RPC response for `getblockhash`: a block hash in the byte order block explorers render.
/// <https://developer.bitcoin.org/reference/rpc/getblockhash.html>
///
/// Kept as text rather than parsed into a [`TransportBitcoinBlockHash`].

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.

It's best to avoid paraphrasing the code (as per our engineering standards).
This comment would be more helpful if it explained why we keep it as a string instead of a TransportBitcoinBlockhash.

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.

Curious why Claude didn’t catch that. I recently added it to AGENTS.md too:

mpc/AGENTS.md

Line 139 in 4659ad7

AI-generated code tends to arrive with obvious comments: restating what the next line does, labeling steps (`// setup`, `// send the request`), or narrating the edit that produced the code. Strip these before submitting. Keep a comment only if it says something the code cannot; if a reader can reconstruct it from the names and types on the same screen, delete it. This applies doubly in tests, where the `// Given` / `// When` / `// Then` structure already tells the story.

Comment on lines +122 to +124
/// Bitcoin mainnet's genesis block hash, as shipped in `expected_network_fingerprint`.
const EXPECTED_NETWORK_FINGERPRINT: &str =
"000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f";

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.

as shipped in expected_network_fingerprint

What is this referring to? I don't understand that second part of the comment.

pbeza
pbeza previously approved these changes Aug 13, 2026
Bitcoin has no chain id, so `getblockhash` at height 0 is what tells its
networks apart. Normalization keeps leading zeros, since they are digits of the
hash rather than padding.
Starknet and the EVM chains already match the prefix either way, and an
operator writes this value by hand. Folds the two inspector tests into one that
answers the upper cased hash, and renames the mock helper, which no longer
serves only chain ids.
Say why the response type keeps the provider's text verbatim, and name the config field the manual test's fingerprint constant mirrors.
@haiyuechen-nearone
haiyuechen-nearone force-pushed the 4003-probe-bitcoin-genesis-hash branch from 3bb1fa8 to 26932d2 Compare August 13, 2026 19:45
@haiyuechen-nearone
haiyuechen-nearone added this pull request to the merge queue Aug 14, 2026
Merged via the queue into main with commit 8f2bb8c Aug 14, 2026
15 checks passed
@haiyuechen-nearone
haiyuechen-nearone deleted the 4003-probe-bitcoin-genesis-hash branch August 14, 2026 07:23
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.

Probe Bitcoin for its genesis block hash

4 participants