Populus: el contrato falla debido al límite de gas de solidez

  • plataforma darwin -- Python 2.7.12, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
  • complementos: población == 2.0.1
  • Sistema operativo: Mac OS X

Creo que me enfrento a este error debido al límite de gas predeterminado del compilador Solidity que es 3,000,000.

[P] ¿Cómo podría aumentar el límite de gas de mi compilador de solidez debido a este error u otro límite de gas del que lee populus?

in estimate_gas-> ¿excede el límite de gas? Cuando elimino alguna función dentro de mi contrato, el error se soluciona. Supongo que hay un límite de gas para que populus implemente el contrato, ¿es posible extenderlo? Si es así, ¿cómo?

Error:

========================================== FAILURES ==========================================
________________________________________ test_receipt ________________________________________

web3 = <web3.main.Web3 object at 0x1061af2d0>
accounts = ['0x82A978B3f5962A5b0957d9ee9eEf472EE55B42F1', '0x7d577a597B2742b498Cb5Cf0C26cDCD726d39E6e', '0xDCEceAF3fc5C0a63d195d6...1d7585Bd0577402861E5', '0x13cBB8D99C6C4e0f2728C7d72606e78A29C4E224', '0x77dB2BEBBA79Db42a978F896968f4afCE746ea1F', ...]
chain = <populus.chain.tester.TesterChain object at 0x105489b50>

    def test_receipt(web3, accounts, chain): #{
        web3._requestManager = web3.manager
        global blkArrayIndex;
        global runTime;
>       my_contract, _   = chain.provider.get_or_deploy_contract('eBlocBroker');

tests/test.py:39:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/Library/Python/2.7/site-packages/populus/contracts/provider.py:143: in get_or_deploy_contract
    deploy_kwargs=deploy_kwargs,
/Library/Python/2.7/site-packages/populus/contracts/provider.py:121: in deploy_contract
    kwargs=deploy_kwargs,
/Library/Python/2.7/site-packages/web3/contract.py:311: in deploy
    txn_hash = cls.web3.eth.sendTransaction(deploy_transaction)
/Library/Python/2.7/site-packages/web3/eth.py:216: in sendTransaction
    get_buffered_gas_estimate(self.web3, transaction),
/Library/Python/2.7/site-packages/web3/utils/transactions.py:28: in get_buffered_gas_estimate
    gas_estimate = web3.eth.estimateGas(gas_estimate_transaction)
/Library/Python/2.7/site-packages/web3/eth.py:263: in estimateGas
    [transaction],
/Library/Python/2.7/site-packages/web3/manager.py:93: in request_blocking
    response = self._make_request(method, params)
/Library/Python/2.7/site-packages/web3/manager.py:76: in _make_request
    return request_func(method, params)
/Library/Python/2.7/site-packages/web3/middleware/attrdict.py:20: in middleware
    response = make_request(method, params)
/Library/Python/2.7/site-packages/web3/middleware/formatting.py:23: in middleware
    response = make_request(method, formatted_params)
/Library/Python/2.7/site-packages/web3/middleware/formatting.py:25: in middleware
    response = make_request(method, params)
/Library/Python/2.7/site-packages/web3/middleware/exception_handling.py:20: in middleware
    return make_request(method, params)
/Library/Python/2.7/site-packages/web3/providers/tester.py:86: in middleware
    return make_request(method, params)
/Library/Python/2.7/site-packages/web3/providers/tester.py:115: in make_request
    response = rpc_fn(*params)
/Library/Python/2.7/site-packages/testrpc/rpc.py:138: in eth_estimateGas
    return self.client.estimate_gas(**formatted_transaction)
/Library/Python/2.7/site-packages/testrpc/client/client.py:253: in estimate_gas
    txn_hash = self.send_transaction(*args, **kwargs)
/Library/Python/2.7/site-packages/testrpc/client/client.py:263: in send_transaction
    self._send_transaction(*args, **kwargs)
/Library/Python/2.7/site-packages/testrpc/client/client.py:58: in inner
    return client_method(self, *args, **kwargs)
/Library/Python/2.7/site-packages/testrpc/client/utils.py:104: in inner
    return fn(*bytes_args, **bytes_kwargs)
/Library/Python/2.7/site-packages/testrpc/client/client.py:225: in _send_transaction
    output = self.evm.send(sender=sender, to=to, value=value, evmdata=data)
/Library/Python/2.7/site-packages/ethereum/tester.py:338: in send
    return self._send(*args, **kwargs)["output"]
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <ethereum.tester.state object at 0x1061af590>
sender = '\x04HR\xb2\xa6p\xad\xe5@~x\xfb(c\xc5\x1d\xe9\xfc\xb9eB\xa0q\x86\xfe:\xed\xa6\xbb\x8a\x11m'
to = '', value = 0
evmdata = "```@R4\x15a\x00\x0fW`\x00\x80\xfd[C`\x00\x81\x90UP3`\x01`\x00a\x01\x00\n\x81T\x81s\xff\xff\xff\xff\xff\xff\xff\xff\xf...c3V[P\x90V[\x90V\x00\xa1ebzzr0X Ks\x04pt'-\x02$\\\xbf\x86\x9c\x0f\xf8\xfa\xbf\x97\xda\xb8/\xd6X\xc8|\xadp\xc6JQpC\x00)"
funid = None, abi = None, profiling = 0

    def _send(self, sender, to, value, evmdata='', funid=None, abi=None,  # pylint: disable=too-many-arguments
              profiling=0):
        # pylint: disable=too-many-locals

        if funid is not None or abi is not None:
            raise Exception(
                'Send with funid+abi is deprecated. Please use the abi_contract mechanism'
            )

        start_time = time.time()
        gas_used = self.block.gas_used

        sendnonce = self.block.get_nonce(privtoaddr(sender))
        transaction = transactions.Transaction(sendnonce, gas_price, gas_limit, to, value, evmdata)
        self.last_tx = transaction
        transaction.sign(sender)
        recorder = None

        if profiling > 1:
            recorder = LogRecorder(
                disable_other_handlers=True,
                log_config=TRACE_LVL_MAP[3],
            )

        try:
            (success, output) = processblock.apply_transaction(self.block, transaction)

            if not success:
>               raise TransactionFailed()
E               TransactionFailed

/Library/Python/2.7/site-packages/ethereum/tester.py:296: TransactionFailed
------------------------------------- Captured log call --------------------------------------
rpc.py                     129 INFO     eth_blockNumber
============================ 1 failed, 4 warnings in 1.41 seconds ============================

Actualizar:

La forma en que uso Populus:

$ mkdir populus_workspace && cd populus_workspace
$ [~/populus_workspace] populus init
Created Directory: ./contracts
Created Example Contract: ./contracts/Greeter.sol
Created Directory: ./tests
Created Example Tests: ./tests/test_greeter.py
$ py.test --capture=fd tests/test_greeter.py -s --disable-pytest-warnings
==================================== test session starts =====================================
platform darwin -- Python 2.7.10, pytest-3.5.0, py-1.5.3, pluggy-0.6.0
rootdir: /Users/alper/mu, inifile:
plugins: populus-2.0.1
collected 2 items

tests/test_greeter.py ..

============================ 2 passed, 6 warnings in 0.82 seconds ============================

Basado en la respuesta de @mafrasi2 cuando probé:

 my_contract, _   = chain.provider.get_or_deploy_contract('eBlocBroker', deploy_transaction={"gas": 4000001})

Recibo el siguiente mensaje de error:

block = <Block(#1 2bb28319)>, tx = <Transaction(751d)>

    def validate_transaction(block, tx):

        def rp(what, actual, target):
            return '%r: %r actual:%r target:%r' % (tx, what, actual, target)

        # (1) The transaction signature is valid;
        if not tx.sender:  # sender is set and validated on Transaction initialization
            if block.number >= config.default_config["METROPOLIS_FORK_BLKNUM"]:
                tx._sender = normalize_address(config.default_config["METROPOLIS_ENTRY_POINT"])
            else:
                raise UnsignedTransaction(tx)
        if block.number >= config.default_config["HOMESTEAD_FORK_BLKNUM"]:
                tx.check_low_s()

        # (2) the transaction nonce is valid (equivalent to the
        #     sender account's current nonce);
        acctnonce = block.get_nonce(tx.sender)
        if acctnonce != tx.nonce:
            raise InvalidNonce(rp('nonce', tx.nonce, acctnonce))

        # (3) the gas limit is no smaller than the intrinsic gas,
        # g0, used by the transaction;
        if tx.startgas < tx.intrinsic_gas_used:
            raise InsufficientStartGas(rp('startgas', tx.startgas, tx.intrinsic_gas_used))

        # (4) the sender account balance contains at least the
        # cost, v0, required in up-front payment.
        total_cost = tx.value + tx.gasprice * tx.startgas
        if block.get_balance(tx.sender) < total_cost:
            raise InsufficientBalance(rp('balance', block.get_balance(tx.sender), total_cost))

        # check block gas limit
        if block.gas_used + tx.startgas > block.gas_limit:
>           raise BlockGasLimitReached(rp('gaslimit', block.gas_used + tx.startgas, block.gas_limit))
E           BlockGasLimitReached: <Transaction(751d)>: 'gaslimit' actual:4000001 target:4000000

/Library/Python/2.7/site-packages/ethereum/processblock.py:112: BlockGasLimitReached

Respuestas (2)

Desafortunadamente, no puede hacer esto en la línea de comandos en este momento. Sin embargo, Populus también le permite usar un script para implementar su contrato, lo que le brinda mucha personalización.

El ejemplo de la documentación utiliza la cantidad de gas predeterminada:

txhash = Crowdsale.deploy(
    transaction={"from": beneficiary},
    args=[beneficiary, multisig_address, 1]
)

Simplemente puede cambiar esto agregando "gas": xal parámetro de transacción:

txhash = Crowdsale.deploy(
    transaction={"from": beneficiary, "gas": 4000000},
    args=[beneficiary, multisig_address, 1]
)

En general, puede usar toda la funcionalidad de web3py en Populus. Incluso hay una funcionalidad para estimar automáticamente la cantidad de gas necesaria de antemano:

gas_needed = Crowdsale.constructor(beneficiary, multisig_address, 1).estimateGas()

Editar:

Creo que tu problema ocurre cuando llamas get_or_deploy_contract(). En ese caso, puedes usar:

chain.provider.get_or_deploy_contract('eBlocBroker', deploy_transaction={"gas": 4000000})

Edición 2:

Después de pasar por un montón de código, tengo algo de información nueva. Populus usa su testercadena por defecto. La testercadena representa EthereumTesterProviderde web3py. Ahora, hay dos versiones de EthereumTesterProvider: una usa eth-tester y la otra usa eth-testrpc . El segundo está en desuso, pero es el que usa Populus. Ahora, hay dos formas de establecer el límite de gas del bloque en eth-testrpc:

  • o bien, configure la variable de entorno TESTRPC_GAS_LIMITen algo muy alto como 8000000 antes de llamarpy.test ...
  • o coloque este fragmento en su archivo test_*.py:

    import pytest
    
    @pytest.fixture(scope="session", autouse=True)
    def adjust_block_gas_limit():
        import testrpc.client
        testrpc.client.client.DEFAULT_GAS_LIMIT = 8000000
    
Intenté su enfoque, recibí este error: E BlockGasLimitReached: <Transaction(751d)>: 'gaslimit' actual:4000001 target:4000000 /Library/Python/2.7/site-packages/ethereum/processblock.py:112: BlockGasLimitReachedy cuando lo intenté, 4000000todavía da el mismo error inicial. @mafrasi2
Su límite de gas de bloque es demasiado pequeño entonces. ¿Qué cadena estás usando para probar?
Populus usa su propia cadena de simulación. No sé cómo aumenta el límite de gas del bloque, está vinculado al límite de gas del compilador de solidez.
@alper Estoy bastante seguro de que mi nueva solución funcionará para usted :)
Bueno, sí, obviamente se suponía que debías ponerlo fuera de la función de prueba. No puedo sostener tu mano en cada línea de código que escribes....

Según la respuesta de @ mafrasi2, cambiar el valor dentro test_*.pydel archivo no ayudó.


Por defecto DEFAULT_GAS_LIMITse le asigna 4000000.

Consulte eth-testrpc/testrpc/client/client.py :

DEFAULT_GAS_LIMIT = t.gas_limit = t.GAS_LIMIT = int(os.environ.get('TESTRPC_GAS_LIMIT', 4000000))

Necesitamos aumentar DEFAULT_GAS_LIMITel valor.

$ pip show eth-testrpc | grep 'Location'
Location: /Library/Python/2.7/site-packages
$ cd /Library/Python/2.7/site-packages
$ grep -r 'TESTRPC_GAS_LIMIT' .
./testrpc/client/client.py:DEFAULT_GAS_LIMIT = t.gas_limit = t.GAS_LIMIT = int(os.environ.get('TESTRPC_GAS_LIMIT', 4000000))

Luego abra ./testrpc/client/client.pycon su editor y actualice 4000000con un valor mayor.


Ejemplo test.py: (Para ejecutar: py.test --capture=fd test.py -s --disable-pytest-warnings)

import pytest
def test_receipt(web3, accounts, chain): #{    
    my_contract, _   = chain.provider.get_or_deploy_contract('myContractName');
    ...
#}
Puedes hacer eso. Aunque es realmente una mala práctica...
Porque se supone que no solo debes editar los paquetes de python instalados. ¿Qué sucede cuando actualizas el paquete? ¿Qué sucede cuando otros programas instalados esperan el paquete original? I
Mi segunda solución definitivamente funciona cuando haces lo que dije. ¿Intentaste usar el primero? Solo corre export TESTRPC_GAS_LIMIT=8000000antes de correr pytest. También puede poner esto en su ~/.bash_profile para configurar la variable de entorno automáticamente cada vez que inicie la terminal.
export TESTRPC_GAS_LIMIT=8000000funciona, pero el segundo enfoque no funcionó en mi caso, sigue dando: BlockGasLimitReached error.