NomicFoundation / edr

An Ethereum development runtime implementation that can be reused to build new developer tools.
MIT License
58 stars 14 forks source link

Better handling of unknown hardfork histories #522

Open fvictorio opened 5 months ago

fvictorio commented 5 months ago

PR https://github.com/NomicFoundation/hardhat/pull/5394 adds some naive hardfork histories for optimism/arbitrum chains, where the same (conservative) hardfork is used for all blocks.

The underlying problem here is this: if Hardhat/EDR doesn't have a hardfork history for a given chain id, then "historical" calls will fail. This was a compromise we decided to make when we added hardfork histories. What we didn't foresee is that making a call immediately after forking is executed as a historical call, because the call is run in the forked block, which is not considered local. This means that if you fork a chain whose history is not in the default config and you immediately make a call, then you'll get an error.

It's unclear what's the right fix here. Two ideas:

  1. Use the local hardfork for calls executed in the forked block. The forked block is already a weird block (e.g., it has an irregular state transition that changes the balances of the default accounts), so adding a little more weirdness seems like a fine compromise.
  2. Have a safe default hardfork for unknown chain ids (maybe printing a warning).

Notice that we can do both too.

fvictorio commented 5 months ago

I'm marking this as "Blocked" because we should either figure this out as part of the multichain effort, or re-visit it after that.

fullkomnun commented 5 months ago

That use-case of "making a call immediately after forking" before executing a tx (or otherwise causing a new block to be mined) is pretty common with deployment tests that use 'hardhat-deploy' community plugin as it by default fetch deployed bytecode and so to conditionally deploy only if it has to (runtime bytecode or constructor params changed etc) and deployment scripts are encouraged to be idempotent so they might perform queries before executing transactions.

  1. In my projects I used the workaround of forcing a block to be mined after forking in these cases. Is that the recommended approach?
  2. For Polygon PoS mainnet and Poylgon Amoy testnet I added the following custom history config:
      chains: {
        // Polygon PoS mainnet
        137: {
          hardforkHistory: {
            merge: 15_950_759, // Aalborg Hardfork (https://forum.polygon.technology/t/aalborg-hardfork-introducing-faster-deterministic-finality-with-milestones-action-required/12983)
            shanghai: 50_523_000, // Agra Hardfork (https://forum.polygon.technology/t/pip-28-agra-hardfork/13067)
            cancun: 54_876_000, // Napoli Hardfork (https://forum.polygon.technology/t/pip-31-napoli-hardfork/13348)
          },
        },
        // Polygon Amoy testnet
        80002: {
          hardforkHistory: {
            cancun: 0, // Amoy launched based on 'cancun'
          },
        },
        // ...
      }
fvictorio commented 5 months ago

Is that the recommended approach?

I'd say that adding custom hardfork histories, as you are doing, is a slightly better approach, because that way you don't have to mine a block everywhere where you use forking.