# Besu Deposit Contract Address Postmortem An analysis of the spec changes and the evolution of the Besu codebase leading to the omission of the `DEPOSIT_CONTRACT_ADDRESS` for Holesky and Sepolia. This ultimately lead to a supermajority chain split on Holesky since Geth and Nethermind had a similar bug: https://github.com/ethereum/pm/blob/master/Pectra/holesky-postmortem.md The point of this postmortem is not to assign blame, but rather help understand how we might avoid similar problems in the future. ## Potential Contributing Factors ### General * Testnets use different values for `DEPOSIT_CONTRACT_ADDRESS` compared to Mainnet * https://eips.ethereum.org/EIPS/eip-6110#configuration doesn't include testnet contract addresses * Unlike CLs, EL config files are different per client * Unlike CLs, EL config isn't considered part of the spec * https://github.com/eth-clients/holesky doesn't include `depositContractAddress` in any of the EL configs * https://github.com/eth-clients/sepolia only includes `depositContractAddress` for genesis.json; not besu.json or chainspec.json * No way to verify contract configuration between clients ### Besu specific * Besu defaults to Mainnet address if not present in config * Besu uses custom genesis config for automated tests rather than loading public testnet config * Various PR authors/reviewers spanning nearly 3 years - no single Besu dev championing the feature ## Learnings * Don't rely on defaults, fail early instead * https://github.com/hyperledger/besu/issues/8367 * https://github.com/jflo/besu/tree/failFastOnUndefinedSystemContract * Adopt `eth_config` https://hackmd.io/@shemnon/eth_config * https://github.com/hyperledger/besu/pull/8417 * Use a shared config between ELs (`eth_config` might mitigate this anyway) * https://github.com/hyperledger/besu/issues/7273 * A shared config could be used as part of the specification for a fork ## Timeline ### Oct 2020 https://eth2book.info/capella/part2/deposits-withdrawals/contract/ > The deposit contract was deployed on October the 14th, 2020, at 09:22:52 UTC to Ethereum address `0x00000000219ab540356cbb839cbe05303d7705fa`. ### Oct 2021 https://github.com/eth-clients/sepolia/ Sepolia launched (without deposit contract) ### June 2022 Sepolia deposit contract deployed on `Jun-09-2022 02:58:14 PM UTC` to `0x7f02C3E3c98b133055B8B348B2Ac625669Ed295D` ### December 2022 https://github.com/ethereum/EIPs/pull/6110 Initial spec only includes Mainnet `DEPOSIT_CONTRACT_ADDRESS` At this point Sepolia deposit contract existed but Holesky network did not exist. At time of writing (March 2025) the [spec still only contains the Mainnet `DEPOSIT_CONTRACT_ADDRESS`](https://github.com/ethereum/EIPs/blob/05662960071dcd5610f147884aa75210a713d81c/EIPS/eip-6110.md?plain=1#L47) ### June 2023 https://github.com/hyperledger/besu/pull/5295 _(EIP-6110: Add deposit validation and apis)_ - `DEFAULT_DEPOSIT_CONTRACT_ADDRESS` added: ``` public static final Address DEFAULT_DEPOSIT_CONTRACT_ADDRESS = Address.fromHexString("0x00000000219ab540356cbb839cbe05303d7705fa"); ``` - Wired up for "experimental EIPs fork", not yet wired up for Prague: ``` final Address depositContractAddress = genesisConfigOptions.getDepositContractAddress().orElse(DEFAULT_DEPOSIT_CONTRACT_ADDRESS); ``` - Explicit genesis config for Mainnet omitted - not a bug as default would be used. - Explicit genesis config for Sepolia omitted - this would have been a bug if Sepolia had gone through Pectra before Holesky. - **Holesky did not exist yet in order for configuration to be added!** - Explicit genesis config _was_ added as part of a custom test genesis file. ### Sept 2023 https://github.com/eth-clients/holesky Holesky launched with `DEPOSIT_CONTRACT_ADDRESS` predeployed in genesis to `0x4242424242424242424242424242424242424242` Besu did not add the `depositContractAddress` to the Holesky config that EIP-6110 would use (neither Mainnet, Sepolia nor Goerli had it either). ### March 2024 http://github.com/hyperledger/besu/pull/6783 _(Adding engine_getPayloadV4 and engine_newPayloadV4)_ - `DEFAULT_DEPOSIT_CONTRACT_ADDRESS` wired up for Prague fork ``` final Address depositContractAddress = genesisConfigOptions.getDepositContractAddress().orElse(DEFAULT_DEPOSIT_CONTRACT_ADDRESS); ``` ### May 2024 - Oct 2024 Various PRs (implementing various spec changes) by various people which refactored the location of the `DEFAULT_DEPOSIT_CONTRACT_ADDRESS` and wiring/loading code. These refactorings didn't have a significant impact on the root cause, but potentially contributed to diluting the knowledge and understanding of the system. https://github.com/hyperledger/besu/pull/7068 *(EIP-7685 General purpose execution layer requests)* https://github.com/hyperledger/besu/pull/7647 *(Add consolidationRequestContract in jsonGenesisConfig)* https://github.com/hyperledger/besu/pull/7771 *(Change requests to use flat encoding)*