ethereum / web3.py

A python interface for interacting with the Ethereum blockchain and ecosystem.
http://web3py.readthedocs.io
MIT License
4.94k stars 1.68k forks source link

Solidity error parsing doesn't work with Ganache #1793

Closed dmytrotkk closed 3 years ago

dmytrotkk commented 3 years ago
astroid==2.4.2
asyncio==3.4.3
attrdict==2.0.1
attrs==19.3.0
base58==2.0.0
bitarray==1.2.2
bleach==3.1.5
bump2version==1.0.0
bumpversion==0.6.0
certifi==2020.4.5.1
chardet==3.0.4
click==7.1.2
coverage==5.1
cytoolz==0.10.1
docutils==0.16
ECPy==1.2.3
entrypoints==0.3
eth-abi==2.1.1
eth-account==0.5.4
eth-hash==0.2.0
eth-keyfile==0.5.1
eth-keys==0.2.4
eth-rlp==0.1.2
eth-typing==2.2.1
eth-utils==1.9.5
flake8==3.7.9
future==0.18.2
hexbytes==0.2.0
hidapi==0.9.0.post2
idna==2.9
importlib-metadata==1.6.0
ipfshttpclient==0.7.0a1
isort==4.3.21
jsonschema==3.2.0
keyring==21.2.1
lazy-object-proxy==1.4.3
ledgerblue==0.1.31
lru-dict==1.1.6
mccabe==0.6.1
mock==4.0.2
more-itertools==8.3.0
multiaddr==0.0.9
netaddr==0.7.19
nose==1.3.7
packaging==20.4
parsimonious==0.8.1
pathtools==0.1.2
Pillow==7.1.2
pkginfo==1.5.0.1
pluggy==0.13.1
protobuf==3.12.2
py==1.8.1
pycodestyle==2.5.0
pycryptodome==3.9.7
pycryptodomex==3.9.7
pyflakes==2.1.1
Pygments==2.6.1
pylint==2.5.3
pyparsing==2.4.7
pyrsistent==0.16.0
pytest==5.4.2
pytest-cov==2.8.1
python-u2flib-host==3.0.3
PyYAML==5.3.1
Random-Word==1.0.4
readme-renderer==26.0
requests==2.23.0
requests-toolbelt==0.9.1
rlp==1.2.0
-e git+git@github.com:skalenetwork/sgx.py.git@d2a82b04eb788cf8894da0ac4b387a6055c24b37#egg=sgx.py
six==1.15.0
-e git+git@github.com:skalenetwork/skale.py.git@616d964407e8f5cbbe34bb2e4f8eea0bff9a2db8#egg=skale.py
toml==0.10.1
toolz==0.10.0
tqdm==4.46.0
twine==3.1.1
typed-ast==1.4.1
typing-extensions==3.7.4.2
urllib3==1.25.9
varint==1.0.2
watchdog==0.10.2
wcwidth==0.2.3
web3==5.13.0
webencodings==0.5.1
websocket-client==0.57.0
websockets==8.1
when-changed==0.3.0
wrapt==1.12.1
zipp==3.1.0

What was wrong?

The latest version of web3py was unable to handle Solidity revert thrown by ganache (Docker container trufflesuite/ganache-cli:beta):

Traceback (most recent call last):
  File "/Users/dmytro/skalenetwork/skale.py/skale/transactions/tools.py", line 57, in make_dry_run_call
    estimated_gas = estimate_gas(skale.web3, method, opts)
  File "/Users/dmytro/skalenetwork/skale.py/skale/transactions/tools.py", line 71, in estimate_gas
    estimated_gas = method.estimateGas(opts)
  File "/Users/dmytro/skalenetwork/skale.py/venv/lib/python3.7/site-packages/web3/contract.py", line 1044, in estimateGas
    **self.kwargs
  File "/Users/dmytro/skalenetwork/skale.py/venv/lib/python3.7/site-packages/web3/contract.py", line 1618, in estimate_gas_for_function
    return web3.eth.estimateGas(estimate_transaction, block_identifier)
  File "/Users/dmytro/skalenetwork/skale.py/venv/lib/python3.7/site-packages/web3/module.py", line 44, in caller
    result = w3.manager.request_blocking(method_str, params, error_formatters)
  File "/Users/dmytro/skalenetwork/skale.py/venv/lib/python3.7/site-packages/web3/manager.py", line 157, in request_blocking
    apply_error_formatters(error_formatters, response)
  File "/Users/dmytro/skalenetwork/skale.py/venv/lib/python3.7/site-packages/web3/manager.py", line 62, in apply_error_formatters
    formatted_response = pipe(response, error_formatters)
  File "cytoolz/functoolz.pyx", line 669, in cytoolz.functoolz.pipe
  File "cytoolz/functoolz.pyx", line 644, in cytoolz.functoolz.c_pipe
  File "/Users/dmytro/skalenetwork/skale.py/venv/lib/python3.7/site-packages/web3/_utils/method_formatters.py", line 511, in raise_solidity_error_on_revert
    if data.startswith('Reverted '):
AttributeError: 'dict' object has no attribute 'startswith'

How can it be fixed?

Ganache response format looks like that:

{'id': 24, 'jsonrpc': '2.0', 'error': {'message': 'VM Exception while processing transaction: revert Delegation perios is already set', 'code': -32000, 'data': {'stack': 'o: VM Exception while processing transaction: revert Delegation perios is already set\n    at Function.o.fromResults (/app/ganache-core.docker.cli.js:6:120966)\n    at e.exports (/app/ganache-core.docker.cli.js:41:2270035)', 'name': 'o'}}}

And that's how web3py tries to parse error section:

data = response['error'].get('data', '')
if data.startswith('Reverted '):

But error field in ganache response is dict so this line fails. Additional handler for ganache should be added to this section.

wolovim commented 3 years ago

Thanks for the report - Ganache indeed was not part of my test set. Will jump in here this afternoon.

dmytrotkk commented 3 years ago

@marcgarreau Here's the proposed fix:

if not isinstance(response['error'], dict):
    raise ValueError('Error expected to be a dict')

data = response['error'].get('data', '')

# Ganache case:
if isinstance(data, dict) and data.get('stack'):
    revert_msg = 'revert '
    reason = data['stack'][data['stack'].find(revert_msg)+len(revert_msg):data['stack'].rfind('\\n')]
    raise SolidityError(f'execution reverted: {reason}')

# Parity/OpenEthereum case:
if data.startswith('Reverted '):

Should I submit the PR or you will work on that?

wolovim commented 3 years ago

PR would be great, thanks! The reason parsing logic is hairy, but I don't think there will be any particularly elegant/non-brittle solution. Can bikeshed in the PR.

dmytrotkk commented 3 years ago

@marcgarreau actually I decided to drop parsing logic and just return revert reason as is.

znss1989 commented 3 years ago

Encountering the same issue, also when using ganache. Before, fixes are patched, is there any workaround for web3.py usage? Thanks.

kclowes commented 3 years ago

Closed in #1794. Thanks @dmitry-tk!