matter-labs / foundry-zksync

Fork of Foundry tailored for zkSync environment
Apache License 2.0
299 stars 130 forks source link

Deployment crashes #361

Closed PatrickAlphaC closed 5 months ago

PatrickAlphaC commented 6 months ago

Component

Forge

Have you ensured that all of these are up to date?

What version of Foundry are you on?

forge 0.0.2 (5ae06f9 2024-04-30T00:24:57.466082000Z)

What command(s) is the bug in?

forge script

Operating System

macOS (Intell)

Describe the bug

Zksync Testnet Issues

If you create a default project with forge init and try to deploy with a deploy script like such:

forge script script/Counter.s.sol --zksync --rpc-url zksync-sepolia --account yellow --sender $DEFAULT_SENDER --broadcast --verify -vvvv

After running the following script (and entering password for decrypting the yellow key), the program crashes with:


Script ran successfully.
Enter keystore password:

## Setting up 1 EVM.
==========================
Simulated On-chain Traces:

  [0] 0x0000000000000000000000000000000000000000::fallback()
    └─ ← <empty revert data>

Transactions saved to: xxx

Sensitive values saved to: xxx

Error: 
Failed to get EIP-1559 fees

This can be fixed by adding --legacy to the script (making them type0 transactions). You'll then have to update foundry.toml with the following:


[etherscan]
zksync-sepolia = { key = "${ETHERSCAN_API_KEY}", url = "https://explorer.sepolia.era.zksync.dev/contract_verification", chain = 300 }

Otherwise it'll fail with:

Chain 300

Estimated gas price: 0.264893396 gwei

Estimated total gas used for script: 469939

Estimated amount required: 0.000124483737622844 ETH

==========================

Transactions saved to:xxx

Sensitive values saved to: xxx

Error: 
Etherscan API key wasn't found for chain id 300. On-chain execution aborted

And then it will just freeze, and get stuck here forever:


###
Finding wallets for all the necessary addresses...
##
Sending transactions [0 - 0].
⠁ [00:00:00] [#################################################################################################################################] 1/1 txes (0.0s)
Transactions saved to: xxx/run-latest.json

Sensitive values saved to:xxx/run-latest.json

##
Waiting for receipts.
⠁ [00:00:00] [-----------------------------------------------------------------------------------------------------------------------------] 0/1 receipts (0.0s)

Requested action items

  1. Add docs for adding the sample config to the toml
  2. Figure out how to get past the EIP-1559 error
  3. Figure out how to get past the deployment freezing

ZkSync Mainne Issues

However, everything works "pretty good" for zksync mainnet, except, my contracts are not being verified. I get this in foundry:


ONCHAIN EXECUTION COMPLETE & SUCCESSFUL.
Total Paid: 0.000005884325 ETH (235373 gas * avg 0.025 gwei)

We haven't found any matching bytecode for the following contracts: [0xd3f8d13e3e1d0c978a242ea71b177e5d04586f4b].

This may occur when resuming a verification, but the underlying source code or compiler version has changed.
##
Start verification for (0) contracts
All (0) contracts were verified!

Transactions saved to: xxx

Sensitive values saved to:  xxx
dutterbutter commented 6 months ago

@PatrickAlphaC thanks for flagging. Will triage this accordingly.

dutterbutter commented 6 months ago

@PatrickAlphaC hmmm i cannot reproduce exactly....

Again --verify is not supported just yet so that needs to be removed from the cmd. Nonetheless the following command works fine for me:

forge script script/Counter.s.sol --zksync --rpc-url https://sepolia.era.zksync.dev --account yellow --sender $DEFAULT_SENDER --broadcast -vvvv

Steps taken to reproduce:

  1. Update to latest forge by re-executing the ./install-foundry-zksync script
  2. Run: forge init
  3. Setup ENV vars (DEFAULT_SENDER)
  4. Setup wallet import - alias to "yellow" with password
  5. Run: forge script script/Counter.s.sol --zksync --rpc-url https://sepolia.era.zksync.dev --account yellow --sender $DEFAULT_SENDER --broadcast -vvvv
  6. Output successful

Can you share the script you are executing? When I run forge init this is the script template provided:

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import {Script, console} from "forge-std/Script.sol";

contract CounterScript is Script {
    function setUp() public {}

    function run() public {
        vm.broadcast();
    }
}

I just want to confirm we are testing the same thing!

ciaranightingale commented 6 months ago

Hey @dutterbutter here are the exact steps to reproduce:

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import {Script, console} from "forge-std/Script.sol";
+import {Counter} from "../src/Counter.sol";

contract CounterScript is Script {
    function setUp() public {}

    function run() public {
-        vm.broadcast();
+        vm.startBroadcast();
+        Counter counter = new Counter();
+        vm.stopBroadcast();
    }
}

You will see the following error in the terminal output:

Error: 
Failed to get EIP-1559 fees
MexicanAce commented 5 months ago

Wanted to provide an update that we're unable to replicate based on the latest set of instructions. I made the changes to script/Counter.s.sol but no error output.

We've also run this against era_test_node fork seplia-testnet with the same response:

Script ran successfully.

## Setting up 1 EVM.
==========================
Simulated On-chain Traces:
  [0] 0x0000000000000000000000000000000000000000::fallback()
    └─ ← <empty revert data>
Here's the full output I see when I'm using `ZKSYNC_SEPOLIA_RPC_URL=https://sepolia.era.zksync.dev`: ```bash $ forge script script/Counter.s.sol --rpc-url $ZKSYNC_SEPOLIA_RPC_URL --private-key $TEST_PRIVATE_KEY --broadcast --zksync -vvvv [⠒] Compiling... [⠑] Compiling 27 files with 0.8.24 [⠘] Solc 0.8.24 finished in 988.29ms Compiler run successful with warnings: Warning (2072): Unused local variable. --> script/Counter.s.sol:13:9: | 13 | Counter counter = new Counter(); | ^^^^^^^^^^^^^^^ ┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ │ Warning: Your code or one of its dependencies uses the 'extcodesize' instruction, which is │ │ usually needed in the following cases: │ │ 1. To detect whether an address belongs to a smart contract. │ │ 2. To detect whether the deploy code execution has finished. │ │ zkSync Era comes with native account abstraction support (so accounts are smart contracts, │ │ including private-key controlled EOAs), and you should avoid differentiating between contracts │ │ and non-contract addresses. │ └──────────────────────────────────────────────────────────────────────────────────────────────────┘ --> lib/forge-std/src/StdCheats.sol Warning: Unused local variable. --> script/Counter.s.sol:13:9: | 13 | Counter counter = new Counter(); | ^^^^^^^^^^^^^^^ Traces: [35516] CounterScript::run() ├─ [0] VM::startBroadcast() │ └─ ← () ├─ [0] → new @0x9a624948A8602E573d1F65aD089cFE43833e4Fd0 │ └─ ← 864 bytes of code ├─ [0] VM::stopBroadcast() │ └─ ← () └─ ← () Script ran successfully. ## Setting up 1 EVM. ========================== Simulated On-chain Traces: [0] 0x0000000000000000000000000000000000000000::fallback() └─ ← ========================== Chain 300 Estimated gas price: 3.05 gwei Estimated total gas used for script: 149502440 Estimated amount required: 0.455982442 ETH ========================== ### Finding wallets for all the necessary addresses... ## Sending transactions [0 - 0]. ⠁ [00:00:00] [#####################################################################################################################################] 1/1 txes (0.0s) Transactions saved to: /Users/nick/test/issue-361/broadcast/Counter.s.sol/300/run-latest.json Sensitive values saved to: /Users/nick/test/issue-361/cache/Counter.s.sol/300/run-latest.json ## Waiting for receipts. ⠉ [00:00:00] [#################################################################################################################################] 1/1 receipts (0.0s) ##### 300 ✅ [Success]Hash: 0x3fd56c3c6c450057d38b4e8f12f7626f47242dee45d74061583c3929c318fbe2 Contract Address: 0x9a624948A8602E573d1F65aD089cFE43833e4Fd0 Block: 2518600 Paid: 0.000070207775 ETH (2808311 gas * 0.025 gwei) Transactions saved to: /Users/nick/test/issue-361/broadcast/Counter.s.sol/300/run-latest.json Sensitive values saved to: /Users/nick/test/issue-361/cache/Counter.s.sol/300/run-latest.json ========================== ONCHAIN EXECUTION COMPLETE & SUCCESSFUL. Total Paid: 0.000070207775 ETH (2808311 gas * avg 0.025 gwei) Transactions saved to: /Users/nick/test/issue-361/broadcast/Counter.s.sol/300/run-latest.json Sensitive values saved to: /Users/nick/test/issue-361/cache/Counter.s.sol/300/run-latest.json ```
MexicanAce commented 5 months ago

We're continuing to investigate and also dig deeper into the failure trace (operation is successful though)

PatrickAlphaC commented 5 months ago

@ciaranightingale was your operation successful here?

ciaranightingale commented 5 months ago

@MexicanAce Apologies for the delayed response. My output was slightly different & the deployment transaction was unsuccessful. This was my entire terminal output:

Traces:
  [35589] CounterScript::run()
    ├─ [0] VM::startBroadcast()
    │   └─ ← ()
    ├─ [0] → new <unknown>@0x6C3707c761377Ad65adcAC6fAB1Aece61D73d62A
    │   └─ ← 864 bytes of code
    ├─ [0] VM::stopBroadcast()
    │   └─ ← ()
    └─ ← 0x6C3707c761377Ad65adcAC6fAB1Aece61D73d62A

Script ran successfully.

== Return ==
0: contract Counter 0x6C3707c761377Ad65adcAC6fAB1Aece61D73d62A

## Setting up 1 EVM.
==========================
Simulated On-chain Traces:

  [0] 0x0000000000000000000000000000000000000000::fallback()
    └─ ← <empty revert data>

Transactions saved to: /Users/ciaranightingale/code/test-delete/broadcast/Counter.s.sol/300/run-latest.json

Sensitive values saved to: /Users/ciaranightingale/code/test-delete/cache/Counter.s.sol/300/run-latest.json

Error: 
Failed to get EIP-1559 fees
ciaranightingale commented 5 months ago

My forge version is 0.0.2 (baa4428 2024-05-27T00:25:28.651861000Z) and I'm running this on an Intel Mac Sonoma 14.4.1. I'm not sure what other information might help in debugging this but let me know if you think of anything and I'd be more than happy to hop on a call if that would help.

ciaranightingale commented 5 months ago

@MexicanAce I just reran this using the RPC you provided, and I got the same output as you - it seems strange that an Alchemy RPC doesn't work, as I was previously using an Alchemy RPC, but at least we know why now!

nbaztec commented 5 months ago

@ciaranightingale during our testing we've noticed that certain RPCs on certain chains would sometimes return an error when a storage value doesn't exist, meanwhile the usual behavior is to return the zero value. Could you perhaps verify if that's the case for alchemy api?

ciaranightingale commented 5 months ago

@nbaztec When running the original script:

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import {Script, console} from "forge-std/Script.sol";
import {Counter} from "src/Counter.sol";

contract CounterScript is Script {
    function setUp() public {}

    function run() public returns (Counter) {
        vm.startBroadcast();
        Counter counter = new Counter();
        vm.stopBroadcast();
        return counter;
    }
}

This is the output:

Traces:
  [35589] CounterScript::run()
    ├─ [0] VM::startBroadcast()
    │   └─ ← ()
    ├─ [0] → new <unknown>@0x899D06aC80598944eE5Efd2B45378883dd703DaF
    │   └─ ← 864 bytes of code
    ├─ [0] VM::stopBroadcast()
    │   └─ ← ()
    └─ ← 0x899D06aC80598944eE5Efd2B45378883dd703DaF

Script ran successfully.

== Return ==
0: contract Counter 0x899D06aC80598944eE5Efd2B45378883dd703DaF

## Setting up 1 EVM.
==========================
Simulated On-chain Traces:

  [0] 0x0000000000000000000000000000000000000000::fallback()
    └─ ← <empty revert data>

Transactions saved to: XX

Sensitive values saved to: XX

Error: 
Failed to get EIP-1559 fees

Whereas, if I modify the script to return a var a that has not been set, the output shows the zero. address. being. returned (notice the contract. address in the previous output return section). The error is the same:

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import {Script, console} from "forge-std/Script.sol";
import {Counter} from "src/Counter.sol";

contract CounterScript is Script {
    function setUp() public {}

    function run() public returns (Counter) {
        Counter a;
        vm.startBroadcast();
        Counter counter = new Counter();
        vm.stopBroadcast();
        return a;
    }
}

Output:

Traces:
  [35594] CounterScript::run()
    ├─ [0] VM::startBroadcast()
    │   └─ ← ()
    ├─ [0] → new <unknown>@0x899D06aC80598944eE5Efd2B45378883dd703DaF
    │   └─ ← 864 bytes of code
    ├─ [0] VM::stopBroadcast()
    │   └─ ← ()
    └─ ← 0x0000000000000000000000000000000000000000

Script ran successfully.

== Return ==
0: contract Counter 0x0000000000000000000000000000000000000000

## Setting up 1 EVM.
==========================
Simulated On-chain Traces:

  [0] 0x0000000000000000000000000000000000000000::fallback()
    └─ ← <empty revert data>

Transactions saved to: XX

Sensitive values saved to: XX

Error: 
Failed to get EIP-1559 fees

Is this what you meant for me to verify?

PatrickAlphaC commented 5 months ago

We found the culprit here. There was an issue with Alchemy's zkSync RPC URL. We have reported this issue to them. Ciara and I were using an Alchemy endpoint, while @MexicanAce was using a zksync endpoint which was working properly.

nbaztec commented 5 months ago

I'm glad that you managed to figure out the RPC issues. Just to expand on my earlier comment to @ciaranightingale

Is this what you meant for me to verify?

In our tests we realized that certain APIs would throw an error if a storage key did not exist.

So sending an eth_getStorageAt RPC request to an arbitrary address and slot, should ideally return the default zero-value.

{"method":"eth_getStorageAt","params":["0xE592427A0AEce92De3Edee1F18E0157C05861564", "0x1", "latest"],"id":1,"jsonrpc":"2.0"}

Expected (slot is empty):

{"jsonrpc":"2.0","id":1,"result":"0x0000000000000000000000000000000000000000000000000000000000000000"} 

But certain APIs would return an error instead of the default 0x0000000000000000000000000000000000000000000000000000000000000000 value. I'm not sure if this is the same issue Alchemy API had, but is good to keep in mind when using foundry and checking if an RPC url works "differently"