Hardhat Network Forking: Gas Estimation Consistency Across Local and Forked States
0 reputation · 06 Jun 2021, 18:04 UTC
0 reputation · 06 Jun 2021, 18:04 UTC
Hardhat Network allows for integration testing without production credentials by utilizing the hardhat_impersonateAccount method and network forking. This enables the simulation of complex interactions using the state of a live blockchain while keeping transactions local.
A design challenge arises when comparing gas estimation behavior between a clean local environment and a forked network. Because forked networks mirror the actual state of a production chain, the gas costs for complex smart contract interactions may diverge from those observed in a fresh local deployment.
Given these environment differences, how can developers ensure gas estimation remains consistent when transitioning from a clean state to a forked state? Does the Hardhat Network provider apply specific overrides to gas calculations during forking to align with local defaults?
32275 reputation · 07 Jun 2021, 03:59 UTC
Hardhat’s local node and a forked Hardhat network use different gas‑estimation engines. The local node runs an internal algorithm that approximates the required gas, while a forked node forwards the request to the upstream RPC’s eth_estimateGas endpoint. Because the RPC sees the live mempool and network‑specific heuristics, the two estimates can diverge.
maxFeePerGas, maxPriorityFeePerGas) may be handled differently.hardhat.config.js for both environments.
module.exports = {
solidity: {
version: "0.8.20",
settings: { optimizer: { enabled: true, runs: 200 } }
}
};
module.exports = {
networks: {
hardhat: {
forking: {
url: process.env.ALCHEMY_MAINNET, // or Infura
blockNumber: 17800000 // example
}
}
}
};
const tx = {
to: contract.address,
data: contract.interface.encodeFunctionData("foo", [42]),
gasPrice: ethers.utils.parseUnits("50", "gwei"),
maxFeePerGas: ethers.utils.parseUnits("100", "gwei"),
maxPriorityFeePerGas: ethers.utils.parseUnits("2", "gwei")
};
hardhat console --network localhost and hardhat console --network hardhat to compare provider.send("eth_estimateGas", [tx]) outputs. The values should differ by no more than a few hundred gas units.
hardhat: {
blockGasLimit: 12000000
}
network.provider.send("eth_estimateGas", …) call on both networks to isolate the estimation logic.
The recommendation above assumes you are forking at a specific block. If you are forking from the latest block or from a very old block, the base state can influence the estimate. Could you confirm which block number you used for forking? That detail may change the suggested block‑specific adjustments.
Consistency is achieved by aligning compiler settings, gas fields, block number, and optionally the block gas limit. After those alignments, the local and forked estimations should converge.
Use comments to ask for clarification. Post a solution as an answer.
32,275 reputation · 06 Jun 2021, 20:46 UTC
To build on the discussion regarding estimator differences, it is important to highlight that gas divergence often stems from storage state rather than just the estimation engine. In a clean local environment, contract storage slots are typically empty (zeroed), whereas a forked state contains actual production data.
Because updating a storage slot from zero to non-zero (SSTORE) is significantly more expensive than updating an existing non-zero value, the same function call can yield different gas results based on the fork's state. To verify if state is the primary driver of your divergence, you can:
eth_estimateGas a second time on the same forked instance.If the second estimate aligns closer to your local environment, the discrepancy is likely due to cold vs. warm storage access and initialization costs inherent to the production state you are mirroring.