This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
reth-bsc is not a fork of Reth. It is a downstream crate that re-uses Reth's NodeBuilder API to assemble a BSC-compatible client. Everything BSC-specific (Parlia consensus, BSC hardforks, system contracts, PoSA mining, MEV/Parlia/Miner RPCs, EVN peer features, BSC precompiles) lives here; generic EL behavior comes from upstream Reth pinned by git tag in Cargo.toml.
- Workspace members: the root crate (binary
reth-bsc, libraryreth_bsc) andtesting/bsc-ef-tests(execution-spec tests harness). - All
reth-*deps are pinned to one released tag inCargo.toml(currentlytag = "v0.1.2"). If you change the Reth pin, update everyreth-*line — a mismatched pin produces duplicate-crate build failures.testing/bsc-ef-tests/Cargo.tomlpins its own ~15reth-*deps to the same tag and must move in lockstep (its one exception isreth-primitives-traits, which tracks abnb-chain/reth-corebranch). Bumping only the root manifest puts two revisions of the same crates in the graph and fails withmultiple different versions of crate reth_chainspeconChainSpectypes.cargo checkandcargo check --all-targetsdo not catch this — verify withcargo clippy --workspace --tests --all-featuresorcargo test --all. build.rsscanssrc/system_contracts/<hardfork>/{mainnet,chapel,rialto}/*at build time and emitssrc/system_contracts/embedded_contracts.rs(aphf_mapkeyed as"<hardfork>_<network>_<contract>"). It also records the git SHA intoRETH_BSC_GIT_SHA/RETH_BSC_GIT_SHA_LONGused at startup and in the P2P client string. If you add a new hardfork directory with system contracts, add it to thehardforkslist inbuild.rsso cargo rebuilds when those files change.
Build:
cargo build # debug
cargo build --release # plain release
make build # release + jemalloc,asm-keccak + target-cpu=native
make maxperf # LTO=fat, single codegen-unit release
make bench-test # maxperf + `bench-test` feature (exposes engine_forkchoiceUpdatedV1)The jemalloc feature is enabled by default and requires tikv-jemallocator on Unix; do not build with --no-default-features casually.
Lint / hygiene (match CI in .github/workflows/ci.yml):
cargo check
cargo clippy --workspace --tests --all-features # CI runs with RUSTFLAGS="-D warnings"
cargo +nightly udeps --workspace --lib --examples --tests --benches --all-features --locked
cargo fmt # nightly rustfmt settings in rustfmt.tomlTests:
cargo test --all -- --test-threads=1 # CI setting; many tests touch global OnceLocks / env
cargo test -p reth_bsc <test_name> # run a single test (substring match)
cargo test -p reth_bsc module::path::test_fn -- --exact --nocaptureExecution-spec tests (network-download fixtures):
make download-eest # pulls EEST v5.4.0 fixtures into testing/bsc-ef-tests/execution-spec-tests
make ef-tests # cargo test -p bsc-ef-tests --release --features ef-tests,jemalloc,asm-keccak
make ef-tests-nextest # same, via cargo-nextest
make clean-eestRun (binary is reth-bsc, chain ids bsc, bsc-testnet):
./target/release/reth-bsc node --chain bsc --datadir ./data_dir
./target/release/reth-bsc node --full --chain bsc --datadir ./data_dir # full nodeThe non-obvious cross-cutting pieces — read these together when anything spans components:
-
src/main.rsis the integration point. It parsesBscCliArgs, then usesCli::<BscChainSpecParser, BscCliArgs>::parse().run_with_components::<BscNode>(...). The async closure:- applies the genesis-hash override,
- hydrates the global
MiningConfig(CLI > env > defaults) and loads the signing key from keystore / hex, - initializes the global BLS signer (CLI > env),
- builds and stores
EvnConfig(EVN peer-tx-broadcast policy), - parses proxyed peer IDs,
- calls
.extend_rpc_modules(...)to register BSC-only RPC namespaces (parlia,mev,miner, BSC eth-extensions, blob). It removes reth's built-insminer_setExtra/setGasPrice/setGasLimitandeth_coinbasebefore registering our versions — don't re-add them upstream-style, - sends the beacon engine handle back to the network via a oneshot and stores the engine-API mpsc sender globally.
-
src/shared.rsholds nearly all cross-component globals asOnceLocks + a fewRwLocks: snapshot provider, header/block-number accessors, engine-API sender, network handle, payload-events broadcast, bid-package queue, proxyed peer IDs, IPC client, miner runtime knobs, etc. Components register into these from different phases of startup (consensus module publishes the snapshot provider, then the miner waits up to ~10s for it — seenode::engine::BscPayloadServiceBuilder). When adding a cross-phase dependency, extendshared.rsrather than threading handles through builders. -
src/node/mod.rs→BscNodecomposes:BscPoolBuilder(pool),BscExecutorBuilder(EVM),BscPayloadServiceBuilder(payload + miner bootstrap),BscNetworkBuilder,BscConsensusBuilder.BscNodeAddOnswiresBscEthApiBuilderplus engine/payload validators (src/node/engine_api/). -
Consensus (
src/consensus/parlia/) is PoA via Parlia:consensus.rsis the main engine,snapshot.rsmaintains validator-set history at epoch boundaries,provider.rsexposesSnapshotProvider(published toshared::SNAPSHOT_PROVIDER),vote_pool.rs+vote.rs+bls_signer.rsimplement BLS vote attestation,forkchoice_rule.rsis the BSC-specific fork-choice rule,go_rng.rsreproduces Go's RNG for validator-order determinism. -
EVM extensions (
src/evm/andsrc/node/evm/):src/evm/handler.rsandsrc/evm/precompiles/*add BSC-specific precompiles (BLS, CometBFT/Tendermint light-client, IAVL, double-sign,tm_secp256k1).src/node/evm/{pre_execution,post_execution}.rsimplement BSC's pre/post-block hooks (system-contract calls for epoch transitions, fee distribution, validator updates).src/evm/blacklist.rsis the BSC transaction blacklist. -
PoSA mining (
src/node/miner/): optional; started byBscPayloadServiceBuilderonly whenMiningConfig::is_mining_enabled()is true. Entry pointBscMiner::startruns the build-loop;payload.rsbuilds blocks,bid_simulator.rsruns MEV bid simulation,signer.rswraps the validator signing key,util.rshas timing/turn/backoff helpers. The miner waits for the snapshot provider to be published by consensus before starting. Configuration flows: CLI--mining.*→ envBSC_MINING_*/BSC_PRIVATE_KEY/BSC_GAS_LIMIT/BSC_MINING_INTERVAL_MS→MiningConfig::from_env()→set_global_mining_config. SeeMINING.mdandMINING_QUICKSTART.mdfor user-facing docs. -
Hardforks (
src/hardforks/bsc.rs) defines the full BSC hardfork schedule (Ramanujan → Niels → MirrorSync → Bruno → Euler → Gibbs → Nano → Moran → Planck → Luban → Plato → Hertz → Kepler → Feynman → FeynmanFix → HaberFix → Bohr → Pascal → Prague → Lorentz → Maxwell → Fermi …). BSC timestamps are real block timestamps (not EL post-merge seconds-since-unix-epoch) and many system-contract behaviors are keyed to them. When touching fork gating, check both this file andsrc/chainspec/{bsc,bsc_chapel,bsc_rialto}.rs. -
Network (
src/node/network/):bsc_protocol/is the custom BSC sub-protocol,handshake.rs/upgrade_status.rsimplement BSC's upgrade-status handshake extension (and signal the EVN intent).evn.rs+evn_peers.rsimplement the Enhanced Validator Network behavior (disable incoming tx broadcast from flagged peers; activates only after head-timestamp lag <BSC_EVN_SYNC_LAG_SECS, default 30s).block_import/is the BSC block-import service (separateIncomingBlockvsIncomingMinedBlockchannels). -
Chainspec (
src/chainspec/):BscChainSpecwraps reth'sChainSpec.genesis_override.rslets--genesis-hashinject a custom genesis hash (the miner/consensus must treat it consistently — consult both sides before changing). Supported chains:bsc(mainnet, genesis.json),bsc-testnet/chapel,bsc-rialto,local(local.rs, usesgenesis_local.jsonwhich is gitignored). -
RPC namespaces (
src/rpc/):parlia.rs(validator/snapshot queries),mev.rs(bid submission + MEV APIs),miner.rs(BSC redefinitions ofminer_set*),eth_ext.rs(eth_coinbase,eth_health),blob.rs(blob fetching from pool/provider). All are merged inmain.rs's.extend_rpc_modulesclosure.
- Global
OnceLocks inshared.rs: tests that instantiate a node or publish into globals must run single-threaded (--test-threads=1, as CI does). Don'texpectonset_*globals — every setter returnsErrif already initialized; real callers log a warning and continue. - Pinned Reth rev: bump every
reth-*entry inCargo.tomland intesting/bsc-ef-tests/Cargo.tomlto the same rev, in one change. A partial bump compiles undercargo checkand only fails later underclippy --workspace --tests --all-features/cargo test --all, as a confusingexpected ChainSpec, found ChainSpectype mismatch caused by two copies ofreth_chainspecin the graph. - Auto-generated file:
src/system_contracts/embedded_contracts.rsis written bybuild.rs— don't edit by hand; add/modify undersrc/system_contracts/<hardfork>/<network>/and extend thehardforkslist inbuild.rsif a new hardfork is introduced. - IPC is required:
main.rspanics if--ipc.disableis set; many BSC features (local mining RPC bridge, engine-API plumbing) assume IPC is available. - EVN is off by default, activates late: even with
--evn.enabled, behavior is gated on head-timestamp lag (BSC_EVN_SYNC_LAG_SECS, default 30s) so it won't kick in mid-sync. - CI runs cargo test with
--test-threads=1: parallel runs will flake because of the globals above.