Cyfrin / foundry-devops

395 stars 52 forks source link

Vm.DirEntry path string uses "\" symbol instead of "/" #25

Closed pautib closed 1 week ago

pautib commented 3 weeks ago

Hi everyone,

After following this section https://updraft.cyfrin.io/courses/foundry/foundry-fund-me/solidity-integration-tests of the Foundry course, the call to the function DevOpsTools.get_most_recent_deployment("FundMe", block.chainid); was returning the following error to me:

[FAIL. Reason: setup failed: revert: No deployment artifacts were found for specified chain] setUp() (gas: 0)

I placed a console.log on the paths that were being retrieved on the get_most_recent_deployment function to check why my deployments were not being checked:


for (uint256 i = 0; i < entries.length; i++) {
            Vm.DirEntry memory entry = entries[i];
            console.log("Here: ", entry.path);
            if (
                entry.path.contains(string.concat("/", vm.toString(chainId), "/")) && entry.path.contains(".json")
                    && !entry.path.contains("dry-run")
            ) {

and it returned this:

Logs:
  The chain to use:  11155111
  Here:  C:/Users/jqd79530/Documents/Foundry/foundry-fund-me/broadcast\DeployFundMe.s.sol
  Here:  C:/Users/jqd79530/Documents/Foundry/foundry-fund-me/broadcast\DeployFundMe.s.sol\11155111
  Here:  C:/Users/jqd79530/Documents/Foundry/foundry-fund-me/broadcast\DeployFundMe.s.sol\11155111\run-1724018228.json
  Here:  C:/Users/jqd79530/Documents/Foundry/foundry-fund-me/broadcast\DeployFundMe.s.sol\11155111\run-1724101935.json
  Here:  C:/Users/jqd79530/Documents/Foundry/foundry-fund-me/broadcast\DeployFundMe.s.sol\11155111\run-latest.json
  Here:  C:/Users/jqd79530/Documents/Foundry/foundry-fund-me/broadcast\DeployFundMe.s.sol\31337
  Here:  C:/Users/jqd79530/Documents/Foundry/foundry-fund-me/broadcast\DeployFundMe.s.sol\31337\run-1724018316.json
  Here:  C:/Users/jqd79530/Documents/Foundry/foundry-fund-me/broadcast\DeployFundMe.s.sol\31337\run-1724018357.json
  Here:  C:/Users/jqd79530/Documents/Foundry/foundry-fund-me/broadcast\DeployFundMe.s.sol\31337\run-latest.json

After the broadcast folder, the path uses '\' instead of '/'. To overcome this problem I just replaced the '/' with '\' in the previous if statement to run my integration test. I would like to know if there is a better solution for this issue. I don't even know the root cause of it. Maybe it is because I am using Windows or because there is an error within this Vm.DirEntry struct.

This has been the get_most_recent_deployment() function I used:


    function get_most_recent_deployment(
        string memory contractName,
        uint256 chainId,
        string memory relativeBroadcastPath
    ) internal view returns (address) {
        address latestAddress = address(0);
        uint256 lastTimestamp;

        bool runProcessed;
        Vm.DirEntry[] memory entries = vm.readDir(relativeBroadcastPath, 3);
        for (uint256 i = 0; i < entries.length; i++) {
            Vm.DirEntry memory entry = entries[i];
            console.log("Here: ", entry.path);
            if (
                entry.path.contains(string.concat("\\", vm.toString(chainId), "\\")) && entry.path.contains(".json")
                    && !entry.path.contains("dry-run")
            ) {
                runProcessed = true;
                string memory json = vm.readFile(entry.path);

                uint256 timestamp = vm.parseJsonUint(json, ".timestamp");

                if (timestamp > lastTimestamp) {
                    latestAddress = processRun(json, contractName, latestAddress);

                    // If we have found some deployed contract, update the timestamp
                    // Otherwise, the earliest deployment may have been before `lastTimestamp` and we should not update
                    if (latestAddress != address(0)) {
                        lastTimestamp = timestamp;
                    }
                }
            }
        }

        if (!runProcessed) {
            revert("No deployment artifacts were found for specified chain");
        }

        if (latestAddress != address(0)) {
            return latestAddress;
        } else {
            revert("No contract deployed");
        }
    }
cromewar commented 3 weeks ago

Hello, @pautib! You're correct about the issue with relative paths—there is indeed a difference between Unix-based systems and Windows. On Windows, paths use \, while Unix-based systems (like Linux and macOS) use /. This discrepancy can cause problems when working across different environments.

Assuming you're using WSL (Windows Subsystem for Linux) on your Windows machine, it's best to ensure all your projects are within the WSL file structure. This way, you can use Unix-style paths (/) consistently, which also makes your code more portable across different development environments.

If you’re not using WSL yet, I highly recommend setting it up, as it provides a much cleaner and more consistent environment for development compared to the native Windows environment.

However, if you're using Git Bash instead of WSL, let me know, and I can suggest an alternative approach. Also, if you’re interested in sharpening your WSL skills, feel free to check out our WSL course for smart contract developers on YouTube. It’s completely optional, but it might be helpful!

pautib commented 3 weeks ago

Hi @cromewar! I followed your tutorial. I already had WSL 1 installed. I installed foundry, node in my home directory together with VS Code. I copied my foundry-fund-me repo in that folder as well. Unit tests are running correctly, but I have an issue when it comes to making request to the alchemy node, either to deploy a new contract or to get the information of an already deployed one. I don't have this issue when I run the commands in git bash on Windows. These are the errors I get:

When running an integration test on sepolia:

pautib@IGT2N4Q7D3:~/Projects/Foundry/foundry-fund-me$ forge test --match-test test_user_can_fund_and_owner_withdraw_interactions --fork-url $SEPOLIA_RPC_URL
[⠒] Compiling...
No files changed, compilation skipped
Error: 
Could not instantiate forked environment with fork url: https://eth-sepolia.g.alchemy.com/v2/yGAsmRIGXTACcoDiGIUhyDuMfNZqdtp8

Context:
- Error #0: Failed to get latest block number
- Error #1: error sending request for url (https://eth-sepolia.g.alchemy.com/v2/yGAsmRIGXTACcoDiGIUhyDuMfNZqdtp8)
- Error #2: error sending request for url (https://eth-sepolia.g.alchemy.com/v2/yGAsmRIGXTACcoDiGIUhyDuMfNZqdtp8)
- Error #3: client error (Connect)
- Error #4: invalid peer certificate: UnknownIssuer

When deploying on Sepolia:

pautib@IGT2N4Q7D3:~/Projects/Foundry/foundry-fund-me$ forge script script/DeployFundMe.s.sol --rpc-url $SEPOLIA_RPC_URL
Error: 
error sending request for url (https://eth-sepolia.g.alchemy.com/v2/yGAsmRIGXTACcoDiGIUhyDuMfNZqdtp8)

Context:
- Error #0: error sending request for url (https://eth-sepolia.g.alchemy.com/v2/yGAsmRIGXTACcoDiGIUhyDuMfNZqdtp8)
- Error #1: client error (Connect)
- Error #2: invalid peer certificate: UnknownIssuer

If I test the previous test on anvil, I got a different kind of error. The contract is retrieved from the blockhain, but I am not able to use the getOwner() method, which is external. This is the error I got:

    ├─ [0] 0xa513E6E4b8f2a923D98304ec87F64353C4D5C853::getOwner() [staticcall]
    │   └─ ← [Stop] 
    └─ ← [Revert] EvmError: Revert

And this is the code I have on my setUp():

    function setUp() external {
        console.log("The chain to use: ", block.chainid);
        address mostRecentlyDeployed = DevOpsTools.get_most_recent_deployment("FundMe", block.chainid);
        console.log("Most recently deployed address: ", mostRecentlyDeployed);
        fundMe = FundMe(payable(mostRecentlyDeployed));
        console.log("Owner ", FundMe(payable(mostRecentlyDeployed)).getOwner()); // It fails here
        vm.deal(USER, USER_STARTING_BALANCE);
    }
pautib commented 3 weeks ago

Hi again @cromewar,

after checking a bit I realized that the ZScaler installed on my computer prevented the RPC calls from being executed. This is what I did to overcome the issue:

I went to Manage user certificates from the Control Panel, right-clicked on the ZScaler certificate, and exported it with the name: zscaler.cer

certifications

The certificate was downloaded in my C:/Windows/System32 directory. Then, I followed the instructions given in this link:

https://stackoverflow.com/questions/72167566/wsl-docker-curl-60-ssl-certificate-problem-unable-to-get-local-issuer-certi

Thus, I run the following from the WSL console:

openssl x509 -inform DER -in /mnt/c/Windows/System32/zscaler.cer -out ./zscaler.crt
sudo cp zscaler.crt /usr/local/share/ca-certificates/
sudo update-ca-certificates

After the last command, the folder /etc/ssl/certs/ca-certificates.crt is updated with the certificate and I was able to deploy on Sepolia and run my integration test without issues in WSL:

forge script script/DeployFundMe.s.sol:DeployFundMe --rpc-url $(SEPOLIA_RPC_URL) --account $(ACCOUNT) --broadcast --verify --etherscan-api-key $(ETHERSCAN_API_KEY) -vvvv

forge test --match-test test_user_can_fund_and_owner_withdraw_interactions --fork-url $SEPOLIA_RPC_URL

I still have the issue that the same test is not working for me using the anvil node, but it may be due to the following warning displayed:

error

cromewar commented 1 week ago

Amazing job @pautib