Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tests on testnet are buggy when using Contract.at #1144

Closed
PatrickAlphaC opened this issue Jul 9, 2021 · 9 comments · Fixed by #1689
Closed

Tests on testnet are buggy when using Contract.at #1144

PatrickAlphaC opened this issue Jul 9, 2021 · 9 comments · Fixed by #1689

Comments

@PatrickAlphaC
Copy link
Contributor

Environment information

  • brownie Version: 1.14.6
  • ganache-cli Version: N/A
  • solc Version: N/A
  • Python Version: 3.9.5
  • OS: OSX

What was wrong?

When running tests on a live network like kovan, brownie attempts to "tear down" instances with the close function and calls _remove_contract from a list it gathers:

On line 468

for contract in [x for v in self._containers.values() for x in v._contracts]

This can bring in duplicates, so when brownie dels them, it runs into a keyerror since it will have already deleted it.

Here is a full output:

patrick@iMac: [~/code/nft-mix -  (main)] $ brownie test --network kovan -s
Brownie v1.14.6 - Python development framework for Ethereum

================================================================================= test session starts ==================================================================================
platform darwin -- Python 3.9.5, pytest-6.2.3, py-1.10.0, pluggy-0.13.1 -- /Library/Frameworks/Python.framework/Versions/3.9/bin/python3
cachedir: .pytest_cache
hypothesis profile 'brownie-verbose' -> verbosity=2, deadline=None, max_examples=50, stateful_step_count=10, report_multiple_bugs=False, database=DirectoryBasedExampleDatabase(PosixPath('/Users/patrick/.brownie/hypothesis'))
rootdir: /Users/patrick/code/nft-mix
plugins: eth-brownie-1.14.6, web3-5.18.0, xdist-1.34.0, forked-1.3.0, hypothesis-6.10.0, flaky-3.7.0
collected 3 items                                                                                                                                                                      

tests/integration/test_advanced_int.py::test_can_create_advanced_collectible_integration PASSED

============================================================================= 1 passed, 2 skipped in 8.72s =============================================================================
  File "/Users/patrick/code/brownie/brownie/_cli/__main__.py", line 64, in main
    importlib.import_module(f"brownie._cli.{cmd}").main()
  File "/Users/patrick/code/brownie/brownie/_cli/test.py", line 61, in main
    return_code = pytest.main(pytest_args, ["pytest-brownie"])
  File "pytest-6.2.3-py3.9.egg/_pytest/config/__init__.py", line 162, in main
    ret: Union[ExitCode, int] = config.hook.pytest_cmdline_main(
  File "pluggy/hooks.py", line 286, in __call__
    return self._hookexec(self, self.get_hookimpls(), kwargs)
  File "pluggy/manager.py", line 93, in _hookexec
    return self._inner_hookexec(hook, methods, kwargs)
  File "pluggy/manager.py", line 84, in <lambda>
    self._inner_hookexec = lambda hook, methods, kwargs: hook.multicall(
  File "pluggy/callers.py", line 208, in _multicall
    return outcome.get_result()
  File "pluggy/callers.py", line 80, in get_result
    raise ex[1].with_traceback(ex[2])
  File "pluggy/callers.py", line 187, in _multicall
    res = hook_impl.function(*args)
  File "pytest-6.2.3-py3.9.egg/_pytest/main.py", line 316, in pytest_cmdline_main
    return wrap_session(config, _main)
  File "pytest-6.2.3-py3.9.egg/_pytest/main.py", line 311, in wrap_session
    config._ensure_unconfigure()
  File "pytest-6.2.3-py3.9.egg/_pytest/config/__init__.py", line 987, in _ensure_unconfigure
    self.hook.pytest_unconfigure(config=self)
  File "pluggy/hooks.py", line 286, in __call__
    return self._hookexec(self, self.get_hookimpls(), kwargs)
  File "pluggy/manager.py", line 93, in _hookexec
    return self._inner_hookexec(hook, methods, kwargs)
  File "pluggy/manager.py", line 84, in <lambda>
    self._inner_hookexec = lambda hook, methods, kwargs: hook.multicall(
  File "pluggy/callers.py", line 208, in _multicall
    return outcome.get_result()
  File "pluggy/callers.py", line 80, in get_result
    raise ex[1].with_traceback(ex[2])
  File "pluggy/callers.py", line 187, in _multicall
    res = hook_impl.function(*args)
  File "/Users/patrick/code/brownie/brownie/test/managers/base.py", line 263, in pytest_unconfigure
    project.close(raises=False)
  File "/Users/patrick/code/brownie/brownie/project/main.py", line 469, in close
    _remove_contract(contract)
  File "/Users/patrick/code/brownie/brownie/network/state.py", line 563, in _remove_contract
    del _contract_map[contract.address]
KeyError: '0xdD3782915140c8f3b190B5D67eAc6dc5760C46E9'

Please include information like:

Fix

This can be fixed easily by changing that one line to:

for contract in list(set([x for v in self._containers.values() for x in v._contracts])):
@PatrickAlphaC
Copy link
Contributor Author

PatrickAlphaC commented Jul 9, 2021

After doing some more testing, it looks like the Contract.at function is adding the duplicates.

If I have in my map.json a contract already, and then I call Contract.at it appears to add a duplicate contract into brownie, but only 1 is in themap.json

Commenting out this line also appears to do the trick of fixing the error

self._contracts.append(contract)

        contract._save_deployment()
        _add_contract(contract)
        # self._contracts.append(contract)
        if CONFIG.network_type == "live":
            _add_deployment(contract)

@PatrickAlphaC
Copy link
Contributor Author

PatrickAlphaC commented Jul 9, 2021

Ok, I think I got it.

It's adding a Contract the first time, and then a ProjectContract the second time:

> /Users/patrick/code/brownie/brownie/project/main.py(469)close()
    468         breakpoint()
--> 469         for contract in [x for v in self._containers.values() for x in v._contracts]:
    470             _remove_contract(contract)

ipdb> stuff = [x for v in self._containers.values() for x in v._contracts]
ipdb> stuff
[<VRFCoordinatorMock Contract '0xdD3782915140c8f3b190B5D67eAc6dc5760C46E9'>, <VRFCoordinatorMock Contract '0xdD3782915140c8f3b190B5D67eAc6dc5760C46E9'>, <AdvancedCollectible Contract '0x31989dd1D2F718561Fbe1dCaa8Cf00933C0800c3'>, <AdvancedCollectible Contract '0x39ebC36a317f4537829Cd67aC65E85497886a2bD'>, <LinkToken Contract '0xa36085F69e2889c224210F603D836748e7dC0088'>, <LinkToken Contract '0xa36085F69e2889c224210F603D836748e7dC0088'>]
ipdb> type(stuff[0])
<class 'brownie.network.contract.Contract'>
ipdb> type(stuff[1])
<class 'brownie.network.contract.ProjectContract'>

@PatrickAlphaC
Copy link
Contributor Author

contract = _find_contract(address) in contract.py will then return a Contract the first time.

@PatrickAlphaC
Copy link
Contributor Author

Aha.... I should use from_abi instead of at....

@PatrickAlphaC
Copy link
Contributor Author

Looks like we could do a few things:

  1. Stop recording contracts in the _contract_map
  2. Check to see if the address is already full in the _contract_map
  3. Disallow people to use at with contracts deployed outside of brownie

Happy to help here if there are any thoughts

@PatrickAlphaC PatrickAlphaC changed the title Tests on testnet are Tests on testnet are buggy when using Contract.at Jul 10, 2021
@PatrickAlphaC
Copy link
Contributor Author

I've gone deep down the brownie hole on this, and I think I see a few easy wins. Let me know what you think.

@zmeghji
Copy link

zmeghji commented May 2, 2022

@PatrickAlphaC How did you even get the tests running on Kovan? Whenever I try running tests in Brownie on a test network, I get the following error. They work fine on the mainnet-fork network though.

    def _request(method: str, args: List) -> int:
        try:
            response = web3.provider.make_request(method, args)  # type: ignore
            if "result" in response:
                return response["result"]
        except (AttributeError, RequestsConnectionError):
            raise RPCRequestError("Web3 is not connected.")
>       raise RPCRequestError(response["error"]["message"])
E       brownie.exceptions.RPCRequestError: The method evm_snapshot does not exist/is not available

../../.local/pipx/venvs/eth-brownie/lib/python3.8/site-packages/brownie/network/rpc/ganache.py:129: RPCRequestError

@xrave110
Copy link

xrave110 commented Aug 3, 2022

@PatrickAlphaC How did you even get the tests running on Kovan? Whenever I try running tests in Brownie on a test network, I get the following error. They work fine on the mainnet-fork network though.

    def _request(method: str, args: List) -> int:
        try:
            response = web3.provider.make_request(method, args)  # type: ignore
            if "result" in response:
                return response["result"]
        except (AttributeError, RequestsConnectionError):
            raise RPCRequestError("Web3 is not connected.")
>       raise RPCRequestError(response["error"]["message"])
E       brownie.exceptions.RPCRequestError: The method evm_snapshot does not exist/is not available

../../.local/pipx/venvs/eth-brownie/lib/python3.8/site-packages/brownie/network/rpc/ganache.py:129: RPCRequestError

I have the same issue, kovan works when I write brownie run but not working for brownie test.
Screenshot from 2022-08-03 17-39-14
Does anybody know how to fix it ?

UPDATE 04-08-2022:
Removing this function helped (it is default function after baking the aave/flashloans).
Screenshot from 2022-08-04 19-49-22

@PatrickAlphaC
Copy link
Contributor Author

I just used from_abi instead of at

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants