This repository is a Rust workspace around BNB Chain, used to compare, verify, and experiment with BSC's two client implementations: the official Go implementation bsc (geth-bsc) and the official Rust implementation reth-bsc.
The workspace follows strict Rust conventions (edition 2024, eyre, tracing, mandatory clippy lints) and ships a consistency probe, bsc-consistency-probe, which cross-checks block headers (notably the stateRoot) returned by both clients at the same height, and—in truth mode—verifies that account/storage leaves from eth_getProof are genuinely committed under the reported stateRoot via Merkle proof.
中文版: README.zh.md
The workspace uses a Cargo workspace layout: executable crates live under bin/*, and the root Cargo.toml aggregates them via members = ["bin/*"] while centralizing shared dependencies in the root [workspace.dependencies]. Reusable libraries would go under crates/*, which the members list is reserved for.
bin/bsc-consistency-probe— Go vs Rust consistency probe (see next section).
Go bsc is the authoritative client actually run by BSC mainnet's 45 active validators; Rust reth-bsc is currently experimental—it syncs and serves read RPC, mines on private networks (verified, see below), but is unproven as a mainnet validator, lacks some finality APIs (e.g. eth_getFinalizedHeader), and treats the safe/finalized tags as latest.
Therefore, any critical workload that trusts a Rust node as a state source (e.g. a MEV searcher / DEX aggregator running in-process revm simulation) should cross-validate the stateRoot against Go before trusting its data.
compare— In the height range[start, end], compares Go vs Rust block headers field-by-field at the same height (includingstateRoot/receiptsRoot/transactionsRoot), printing per-block diffs and a summary.truth— Pulls account/storage proofs viaeth_getProofand verifies, per MPT rules, that the leaves are genuinely committed under the reportedstateRoot. Pass only--go(Go as the trusted source) or both--goand--rustfor a three-way trusted cross-check.
compareprobes--workersheights at a time (default 8). One block probe issues four JSON-RPC calls, so this is what bounds how much of a public endpoint's capacity a wide--start..--endrange consumes. Results are reported in ascending height order regardless of which endpoint answers first.- A height whose probe fails is reported as a diff on its own row rather than silently dropping out of the range, because dropping it would understate the failures the caller asked about.
- Any inconsistent or unprobeable block makes the exit status non-zero, so
compareis usable directly as a CI gate. A summary line always prints first. - Every request is bounded by
--timeout-ms(default 10 000). The timeout covers the whole exchange, not just the send, so an endpoint that accepts a connection and then goes quiet fails the block instead of waiting indefinitely. Lower it when a wedged node must be reported quickly rather than accurately. - Without both
--startand--end, the range is the--blocksmost recent heights (default 20) ending at the Go endpoint's head. Passing--startabove--endis rejected: an empty range would print0/0 blocks consistentand exit zero, which is indistinguishable from a pass.
# Cross-validate block headers for heights 38_000_000..=38_000_100 (Go vs Rust)
cargo run -p bsc-consistency-probe -- compare \
--go https://bsc-mainnet.bnbchain.org \
--rust https://your-reth-bsc.example.com \
--start 38000000 --end 38000100 --workers 8
# Verify a Merkle proof for an account and its storage slots, trusting Go
cargo run -p bsc-consistency-probe -- truth \
--go https://bsc-mainnet.bnbchain.org \
--addresses 0xBb4cDB9CBD36b01bc983AEC51fA2D8C5B2F3f3A7 \
--storage-slots 0x0,0x1 --block 38000100
# Three-way trusted check: both Go and Rust act as proof sources
cargo run -p bsc-consistency-probe -- truth \
--go https://bsc-mainnet.bnbchain.org \
--rust https://your-reth-bsc.example.com \
--addresses 0xBb4cDB9CBD36b01bc983AEC51fA2D8C5B2F3f3A7 \
--storage-slots 0x0 --block 38000100This workspace uses just for common tasks.
just setup # install toolchain and git hooks
just check # type-check
just test # run tests (incl. proptest)
just lint # fmt + sort + clippy -D warnings + typos + rumdl
just build # build the workspace
just mutation # cargo-mutants mutation testingThe workspace enables clippy pedantic (warn) and denies several panic-prone patterns: unwrap / expect / panic, todo, dbg!, println!/eprintln! in library code, and #[allow(...)] attributes; unused_must_use is denied. Library code must use tracing instead of println. A CLI binary may lift the print lint via #![expect(clippy::print_stdout)] at the top of main.rs. The HTTP client is uniformly hpx (rustls-tls); reqwest is forbidden.
In-depth BSC dual-client (Go vs Rust) analysis:
- English: docs/bsc-diff.md
- 中文: docs/bsc-diff.zh.md
Private-network experiments (Go-only / Rust-only / mixed) and one-script setup:
- English: docs/privnet.md, privnet/README.md
- 中文: docs/privnet.zh.md, privnet/
Apache-2.0