Free 30-min Web3 Consultation
Book Now
Smart Contract Security Audits
Learn More
Custom DeFi Protocol Development
Explore
Full-Stack Web3 dApp Development
View Services
Free 30-min Web3 Consultation
Book Now
Smart Contract Security Audits
Learn More
Custom DeFi Protocol Development
Explore
Full-Stack Web3 dApp Development
View Services
Free 30-min Web3 Consultation
Book Now
Smart Contract Security Audits
Learn More
Custom DeFi Protocol Development
Explore
Full-Stack Web3 dApp Development
View Services
Free 30-min Web3 Consultation
Book Now
Smart Contract Security Audits
Learn More
Custom DeFi Protocol Development
Explore
Full-Stack Web3 dApp Development
View Services
LABS
Guides

How to Run Upgrade Dry Runs

A technical guide for developers and node operators to simulate and test blockchain protocol upgrades using testnets, local forks, and simulation tools to prevent mainnet failures.
Chainscore © 2026
introduction
SMART CONTRACT SECURITY

Introduction to Upgrade Dry Runs

A guide to simulating and validating smart contract upgrades before mainnet deployment to prevent critical failures.

An upgrade dry run is the process of simulating a smart contract upgrade in a forked or test environment that mirrors the state of the mainnet. This is a critical security practice for protocols using upgradeable contracts, as it allows developers to verify that the new logic deploys correctly, initializes properly, and interacts with existing storage and dependencies without unintended side effects. Unlike standard unit tests, a dry run validates the upgrade path itself, catching issues like storage layout incompatibilities, initialization function failures, or broken integrations with other on-chain components before any real user funds are at risk.

To execute a dry run, you typically use a tool like Hardhat or Foundry to fork the target blockchain at a specific block. This creates a local sandbox with an exact copy of the live contract state. You then deploy the new implementation contract and simulate the upgrade via the proxy's admin functions. Key checks during this process include verifying that all state variables are preserved, all external and internal function calls succeed, and that access control permissions (like the onlyOwner modifier) are correctly enforced in the new version. This step is essential for catching storage collisions, where new variables inadvertently overwrite existing data slots.

For developers using common upgrade patterns like the Transparent Proxy or UUPS, specific considerations apply. With UUPS, you must ensure the upgrade function (upgradeTo) is present and correctly implemented in the new logic contract. For both patterns, you must verify that the proxy's storage layout remains consistent; adding new variables must always be appended to the end of the existing layout. A failed dry run might reveal that a migrate function reverts due to a gas limit or that a newly introduced library address is incorrectly set. Tools like OpenZeppelin Upgrades Plugins can automate many of these checks.

Beyond basic functionality, a comprehensive dry run should include integration testing with the broader protocol ecosystem. This means simulating user interactions—such as deposits, swaps, or governance votes—both before and after the upgrade simulation to ensure no core user flows are broken. It's also advisable to run the upgrade on a public testnet after the local dry run succeeds, as this exposes the new contracts to real gas costs and potential front-running vectors. The final output of a successful dry run is a high-confidence deployment script and a verified set of post-upgrade contract addresses for the mainnet proposal.

prerequisites
SETUP

Prerequisites for Running a Dry Run

Before you can safely test a smart contract upgrade, you must configure your environment with the correct tools and access.

A dry run simulates a smart contract upgrade on a forked version of the target network without broadcasting any transactions. This requires three core components: a local development environment (like Foundry or Hardhat), access to a forking node provider (such as Alchemy or Infura), and the proposed upgrade payload. You will also need the private keys for the relevant administrative accounts to sign the simulation, though no real funds are spent.

First, ensure your development framework is configured for mainnet forking. For example, in a Foundry project, your foundry.toml file must specify an RPC URL for the chain you're targeting (e.g., Ethereum Mainnet) and enable forking. You'll need an API key from a node service provider. The command anvil --fork-url $RPC_URL creates a local Anvil instance that mirrors the live state, which is the sandbox for your dry run.

Next, you must have the exact upgrade payload ready. This is the encoded transaction data that would be sent to the proxy admin or governance contract to execute the upgrade. It typically includes the address of the new implementation contract and any initialization call data. This payload is usually generated by tools like OpenZeppelin Upgrades Plugins or your project's deployment scripts.

Finally, access to the private keys of the upgrade authority is essential for signing the simulated transaction. While the dry run occurs off-chain, the simulation must validate signatures and permissions as the real transaction would. Use environment variables (e.g., PRIVATE_KEY) to load these keys securely into your script. Never hardcode private keys.

With these prerequisites met—a forked network, the upgrade payload, and authorized signer keys—you can execute a dry run script. This script will deploy the new implementation to the fork, call the upgrade function, and trace the execution to identify any reverts, gas cost issues, or state changes, all without any on-chain risk.

key-concepts
PRACTICAL GUIDE

Key Concepts for Upgrade Testing

Learn the essential steps and tools for safely testing smart contract upgrades before deploying to mainnet.

IMPLEMENTATION GUIDE

Dry Run Methods by Blockchain

Hardhat Forking

Ethereum developers primarily use state forking to simulate upgrades on a local copy of mainnet. The most common tool is Hardhat's hardhat_reset RPC method.

Key Steps:

  1. Fork mainnet at a specific block: npx hardhat node --fork https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY
  2. Deploy your upgrade contract to the forked network.
  3. Use hardhat_reset to revert the fork to its original state for repeated tests.

Example Hardhat Configuration:

javascript
module.exports = {
  networks: {
    hardhat: {
      forking: {
        url: process.env.MAINNET_RPC_URL,
        blockNumber: 19238210
      }
    }
  }
};

This method allows you to test interactions with live protocols like Uniswap or Aave before deploying.

step-by-step-evm
DEVELOPER TUTORIAL

Step-by-Step: Ethereum Upgrade Dry Run

A practical guide for developers and node operators to safely test and validate Ethereum client upgrades before mainnet deployment.

An Ethereum upgrade dry run is the process of simulating a network hard fork or client update in a controlled, isolated environment. This is a critical step for node operators, client teams, and application developers to verify that new software versions function correctly, are compatible with existing infrastructure, and do not introduce consensus failures. Running a dry run on a dedicated testnet or a local devnet allows you to identify and resolve issues without risking real funds or disrupting the live Ethereum network. It is a mandatory best practice for any significant protocol change, such as the transition from Proof-of-Work to Proof-of-Stake or the implementation of new EIPs.

To begin a dry run, you must first select the appropriate testing environment. For testing client upgrades, the Sepolia or Holesky testnets are ideal as they mimic mainnet conditions. For testing entirely new fork logic or custom parameters, you can spin up a local development network using tools like geth --dev or a multi-client devnet using the Ethereum Foundation's Launchpad. Ensure all participants in the test—other nodes, validators, and tooling—are running the candidate upgrade version. The goal is to create a replica of the intended mainnet upgrade scenario.

The core of the dry run involves monitoring the network through the upgrade's activation epoch or block height. Use your client's logs and metrics (e.g., geth's console, teku's log output, Prometheus metrics) to watch for consensus failures, block production halts, or syncing issues. Key checks include verifying that the chain continues to finalize, that validators assigned to the new duties perform them correctly, and that the state transition logic for the new fork rules is applied. Any divergence in chain head between clients running the same version indicates a critical bug that must be addressed before mainnet deployment.

Beyond consensus, you must test the integration with your operational stack. This includes staking infrastructure (validator clients, key management), monitoring and alerting systems, RPC endpoints for dApps, and block explorers. Ensure your upgrade and rollback procedures—such as database migrations or reverting to a previous client version—are documented and tested. A successful dry run is not just about the chain progressing; it's about your entire node setup remaining stable and functional through the transition. This step often uncovers operational issues not present in unit tests.

Finally, participate in or monitor coordinated shadow forks. These are long-running testnets that replay mainnet state and traffic, providing the most realistic pre-production environment. Client teams like Nethermind and Besu frequently run these. After completing your dry run, compile a report detailing the client version, test environment, any issues encountered, and their resolutions. Sharing findings with client teams and the community on forums like Ethereum R&D Discord or GitHub issues contributes to the overall security and smooth execution of the Ethereum upgrade.

step-by-step-solana
VALIDATOR OPERATIONS

Step-by-Step: Solana Upgrade Dry Run

A practical guide to executing a local test of a Solana network upgrade before applying it to your mainnet validator. This process is critical for identifying potential issues and ensuring a smooth transition.

A Solana upgrade dry run is the process of simulating a network upgrade on a local test environment that mirrors the mainnet state. This allows validator operators to verify that their node configuration, custom programs, and tooling will function correctly with the new runtime version. The primary tool for this is the solana-test-validator, which can be configured to load a snapshot of the mainnet ledger and apply a specific target software version. Running a dry run is considered a best practice for any major or minor upgrade, especially those involving changes to the Solana runtime, transaction processing, or system programs.

To begin, you need to install the target version of the Solana CLI tools you intend to test. Use solana-install init to switch versions. For example, to test v1.18.0, you would run solana-install init 1.18.0. Next, you must obtain a recent snapshot of the mainnet ledger. The Solana Foundation provides public snapshot archives. You can download one using a command like wget -r -l1 -A "snapshot-*.tar.zst" -nH --cut-dirs=2 https://snapshots.mainnet-beta.solana.com/. Ensure you have sufficient disk space, as a full snapshot can be over 500GB.

Launch the test validator with the snapshot and the desired runtime version. The key command includes the --limit-ledger-size flag to manage disk usage and the --clone parameter to replicate specific accounts (like your validator's vote account). An example command is:

bash
solana-test-validator \
  --ledger ./test-ledger \
  --reset \
  --limit-ledger-size 500000 \
  --snapshot /path/to/snapshot.tar.zst \
  --clone <YOUR_VOTE_ACCOUNT_PUBKEY> \
  --bpf-program <PROGRAM_PUBKEY> <PATH_TO_SO_FILE> \
  --rpc-port 8899

This starts a local RPC endpoint where you can interact with the cloned state.

Once the validator is running, you should perform a series of functional tests. This includes: sending transactions, staking SOL, voting, interacting with your deployed smart contracts, and using any monitoring or automation scripts. Monitor the validator logs for errors, warnings, or panics. Pay special attention to the execution of your custom programs loaded via --bpf-program. The goal is to ensure all critical operations succeed under the new software version. This phase may reveal incompatibilities that require program redeployment or configuration changes.

After successful testing, you must cleanly stop the validator and analyze the results. A critical final step is to verify the upgrade mechanism itself by simulating the on-chain process. You can use the solana-validator tool with the --require-tower and --hard-fork flags on your local network to test the consensus transition. Document any issues encountered and their resolutions. This dry run process significantly de-risks the mainnet upgrade, protecting your stake and contributing to network stability. Always consult the official Solana Upgrade Documentation for version-specific instructions.

METHODOLOGY

Upgrade Simulation Tool Comparison

A feature and performance comparison of tools for simulating smart contract upgrades on EVM chains.

Feature / MetricChainscore Upgrade SimulatorTenderly ForkHardhat Fork

Simulation Environment

Deterministic sandbox

Forked mainnet node

Local Hardhat Network

Execution Speed

< 2 seconds

30-60 seconds

5-10 seconds

State Persistence Between Runs

Gas Usage Estimation

Storage Layout Diff Analysis

Automated Upgrade Safety Checks

Cost per Simulation

Free

$0.10-0.50 (est.)

Free

Requires RPC Endpoint / API Key

Supports Custom Solidity Versions

0.4.11 - 0.8.x

Node-dependent

Configurable

UPGRADE SAFETY

Common Dry Run Mistakes to Avoid

Dry running a smart contract upgrade is a critical safety step, but common pitfalls can lead to false confidence. This guide covers frequent errors and how to fix them.

A passing dry run that fails on mainnet often indicates a state dependency or environmental difference. Dry runs typically execute against a simulated or forked state, which may not match the live contract's exact conditions.

Key differences to check:

  • Storage layout mismatches: The new contract's storage variables must be compatible. Use slither-check-upgradeability or hardhat-upgrades validation.
  • Missing constructor logic: Proxy constructors are not called on upgrade. Initialization must be in an initialize function.
  • Gas limit differences: The forked testnet may have a higher gas limit than the target block's limit. Always check gasUsed in the dry run receipt.
  • Chain-specific addresses: Hardcoded oracle or manager addresses (e.g., 0x...) may differ between networks.
UPGRADE DRY RUNS

Frequently Asked Questions

Common questions and troubleshooting steps for developers preparing and executing upgrade simulations on Ethereum smart contracts.

An upgrade dry run is a simulation of a smart contract upgrade process on a forked version of the Ethereum mainnet or testnet. It is a critical security practice that allows developers to test the deployment and initialization logic of a new implementation contract without broadcasting any real transactions to the live network.

This process is necessary to:

  • Verify correctness: Ensure the new contract bytecode deploys correctly and the proxy points to it.
  • Test initialization: Confirm that the initialize or migration function executes without errors and sets the correct initial state.
  • Estimate gas costs: Get accurate gas estimates for the actual upgrade transaction.
  • Catch integration failures: Identify issues with storage layout compatibility or function selectors before risking mainnet funds.

Tools like Hardhat, Foundry, and Tenderly are commonly used to create a local fork and execute the dry run.

conclusion
BEST PRACTICES

Conclusion and Next Steps

You have successfully learned how to execute a controlled upgrade dry run using Chainscore's Forge. This final section summarizes key takeaways and outlines the next steps for integrating this process into your development workflow.

Running a dry run is a non-negotiable step for secure smart contract upgrades. It allows you to validate the upgrade path in a production-like environment without risking live assets or disrupting service. The primary goal is to catch potential issues—such as storage layout conflicts, initialization errors, or unexpected side effects—before they reach mainnet. By using a dedicated testnet or a forked mainnet state, you simulate the exact conditions your users will experience.

To operationalize this practice, integrate upgrade dry runs into your CI/CD pipeline. Tools like Foundry's forge script or Hardhat tasks can automate the deployment and verification steps you performed manually. Consider setting up a staging environment that mirrors your mainnet configuration, including dependencies on external protocols like Chainlink oracles or other DeFi contracts. Automating these checks ensures every proposed upgrade is rigorously tested, reducing human error and increasing deployment confidence.

Your next steps should involve exploring more advanced validation techniques. Investigate tools like Slither or MythX for static analysis of your upgrade diff to detect security vulnerabilities. For complex upgrades, consider formal verification using the Certora Prover to mathematically prove critical properties are preserved. Finally, document your upgrade procedure and establish a clear rollback plan. A well-documented process, combined with the empirical confidence gained from dry runs, forms the foundation of a robust and secure upgrade lifecycle for any protocol.

How to Run Upgrade Dry Runs on Ethereum and Solana | ChainScore Guides