ethereum / eth-tester

Tool suite for testing ethereum applications.
MIT License
365 stars 147 forks source link

Create similar interface to `ethereum.tools.tester` #156

Closed HarryR closed 5 years ago

HarryR commented 5 years ago

The ethereum.tools.tester interface is really useful, it allows me to provide the source code for a smart-contract, have it automatically compiled, then interact with it as if it were a normal object.

This is documented at: https://github.com/ethereum/pyethereum/wiki/Using-pyethereum.tester

I think this is an invaluable component of the Python Ethereum ecosystem, but PyEthereum doesn't support the new opcodes (which are emitted as part of the standard prelude by the Solidity 0.5.x compiler), and eth-tester is not just incompatible with ethereum.tools.tester but doesn't provide an easy to use wrapper interface.

Cross-posting from the PyEthereum issue: https://github.com/ethereum/pyethereum/issues/897

Example:

import unittest
from ethereum.tools import tester
from binascii import hexlify
import bls

class TestBLSValidators(unittest.TestCase):
    def setUp(self):
        env = tester.get_env(None)
        env.config['BLOCK_GAS_LIMIT'] = 5**10
        chain = tester.Chain(env=env) 

        with open('BN256G2.sol') as handle:
            source = handle.read()
            BN256G2 = chain.contract(source, language='solidity')
        with open('BLSValidators.sol') as handle:
            source = handle.read()
            self.contract = chain.contract(source, libraries={'BN256G2': hexlify(BN256G2.address)}, language='solidity')

    def test_ProvePublicKey(self):
        sk, pk = bls.bls_keygen()
        sig = bls.bls_prove_key(sk)
        print(self.contract.ProvePublicKey(bls.g2_to_list(pk), bls.g1_to_list(sig)))
pipermerriam commented 5 years ago

eth-tester is meant to be low level so adding high level APIs for interacting with smart contracts is a wontfix.

Have you looked into doing this using web3.py?

https://web3py.readthedocs.io/en/latest/examples.html#contract-unit-tests-in-python

I'm closing as wontfix but only because I don't believe this functionality belongs in this specific library. I'd still like to understand your use case and understand whether we have tooling and documentation to accommodate it.

HarryR commented 5 years ago

I am just looking for something which is either compatible with or as easy to use as ethereum.tools.tester, and neither eth-tester or Web3.py are as graceful. See the snippet of Python I provided, this is as it's intended to be used - the amount of boilerplate compared to Web3.py is minimal and the code is very straightforward to use and understand.

However, PyEthereum seems unmaintained...

pipermerriam commented 5 years ago

cc @njgheorghita

We've intentionally left compilation out of web3.py so that's a complicated one. It turns out that maintaining code that does compilation that handles anything other than the most trivial cases is costly. We've experimented with the concept in some places like pytest-ethereum but none of those efforts are beyond experimentation.

Is there more than the compilation part? @njgheorghita wanna chime in on any specifics about where our efforts on doing compilation in the context of testing ended up or whether any of the ethpm work you've done might help here.

HarryR commented 5 years ago

ya, I think I'm just gonna give up on this for now.

Web3.py is a pain to use, and py-evm won't deploy my contract:

eth.exceptions.OutOfGas: Out of gas: Needed 3667297905244114039569722029634114410016020266953094191085303361019466583388654759774060364 - Remaining 2129283 - Reason: Expanding memory 0 -> 1386621896605064455585312431868615197199104358752

*rolleyes* wtf

Neither eth-tester or py-evm seem to provide a nice way of emitting an opcode trace to find out why. At least with PyEthereum I can turn logging on, but I can't even seem to do that for py-evm. And the examples for Web3.py are outdated and APIs expose way too much of the internals so they break at every revision.

It's a shame, the workflow for PyEthereum was really simple to use and let me write unittests for Solidity code in Python without needing hundreds of lines of bootstrap code.

pipermerriam commented 5 years ago

@HarryR I'm sorry your experience has been what it is. I've spoken with @kclowes who's leading development of the web3 library that we've got some shortcomings to address with respect to the things you've surfaced. Here's my take-away at what we're going to try to make better.

If you want to try and get at the trace logs, I think you can get there with something close to the following.

import logging
logger = logging.getLogger('eth')
logger.setLevel(0)  # might also work at 5 or 8, can't remember which is our DEBUG2 log level

You may also need to hook the logger up to the stdout stream or something to get at the logs.