Я сталкиваюсь с некоторым неинтуитивным поведением в солидности, когда один из моих контрактов вызывает другой. Я проверяю контракты с web3py
. Вот самый минимальный пример, который я мог придумать. Обратите внимание, что на самом деле это может быть не минимальный пример, потому что причины сбоев не распространяются от ethereum до web3py.
Foo.sol:
pragma solidity ^0.4.0;
import "./Bar.sol";
contract Foo {
Bar public bar;
function Foo(){
bar = new Bar();
}
function test() returns (uint) { return 1; }
function test2() {}
function execute() {
bar.run();
}
}
Bar.sol
pragma solidity ^0.4.0;
import "./Foo.sol";
contract Bar {
address bar_address;
function Bar(){
bar_address = msg.sender;
}
function run() {
Foo foo = Foo(bar_address);
// foo.test(); # fails
foo.test2(); # succeeds
}
}
test.py
from web3 import Web3, EthereumTesterProvider
import unittest
import os
from eth_tester.exceptions import TransactionFailed
import tests.utils.utils as utils
from web3.utils.filters import Filter
class TestMycroToken(unittest.TestCase):
PROJECT_ROOT = os.path.dirname(os.path.dirname(__file__))
CONTRACT_ROOT = os.path.join(PROJECT_ROOT, "contracts")
TEST_CONTRACT_ROOT = os.path.join(CONTRACT_ROOT, "test_contracts")
def test_foo(self):
w3 = Web3(EthereumTesterProvider())
proposal_contract, proposal_contract_address, proposal_contract_instance = utils.create_contract(
self.CONTRACT_ROOT, os.path.join(self.TEST_CONTRACT_ROOT, "Foo.sol"), "Foo", w3 )
proposal_contract_instance.execute(transact={'from': self.w3.eth.accounts[1]})
Когда Bar.run
вызывает Foo.test2()
, тест проходит успешно, но когда вызывается Foo.test()
, тест не пройден.
utils.create_contract
более или менее соответствует тому, что показано в быстром запуске для web3py с некоторыми изменениями для обработки компиляции нескольких файлов.
Я получаю следующую трассировку стека для ошибки:
/Users/paymahn/mycro/venv/bin/python /Applications/PyCharm.app/Contents/helpers/pycharm/_jb_unittest_runner.py --target test_mycro_token.TestMycroToken.test_foo
Launching unittests with arguments python -m unittest test_mycro_token.TestMycroToken.test_foo in /Users/paymahn/mycro/tests
Ran 1 test in 0.692s
FAILED (errors=1)
Error
Traceback (most recent call last):
File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/eth_tester/utils/formatting.py", line 85, in wrapper
return to_wrap(*args, **kwargs)
File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/eth_tester/backends/pyethereum/v16/main.py", line 439, in estimate_gas
transaction=transaction,
File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/eth_tester/backends/pyethereum/v16/main.py", line 157, in _estimate_evm_transaction
return _send_evm_transaction(tester_module, evm, transaction_for_estimate)
File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/eth_tester/backends/pyethereum/v16/main.py", line 145, in _send_evm_transaction
evmdata=transaction.get('data', b''),
File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/ethereum/tester.py", line 338, in send
return self._send(*args, **kwargs)["output"]
File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/ethereum/tester.py", line 296, in _send
raise TransactionFailed()
ethereum.tester.TransactionFailed
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/usr/local/Cellar/python/3.6.4_4/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/case.py", line 59, in testPartExecutor
yield
File "/usr/local/Cellar/python/3.6.4_4/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/case.py", line 605, in run
testMethod()
File "/Users/paymahn/mycro/tests/test_mycro_token.py", line 125, in test_foo
proposal_contract_instance.execute(transact={'from': self.w3.eth.accounts[1]})
File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/contract.py", line 777, in __call__
return self.__prepared_function(*args, **kwargs)
File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/contract.py", line 790, in __prepared_function
return getattr(self._function(*args), modifier)(modifier_dict)
File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/contract.py", line 1028, in transact
**self.kwargs)
File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/contract.py", line 1305, in transact_with_contract_function
txn_hash = web3.eth.sendTransaction(transact_transaction)
File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/eth.py", line 247, in sendTransaction
get_buffered_gas_estimate(self.web3, transaction),
File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/utils/transactions.py", line 72, in get_buffered_gas_estimate
gas_estimate = web3.eth.estimateGas(gas_estimate_transaction)
File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/eth.py", line 288, in estimateGas
[transaction],
File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/manager.py", line 103, in request_blocking
response = self._make_request(method, params)
File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/manager.py", line 86, in _make_request
return request_func(method, params)
File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/middleware/gas_price_strategy.py", line 18, in middleware
return make_request(method, params)
File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/middleware/formatting.py", line 21, in middleware
response = make_request(method, formatted_params)
File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/middleware/attrdict.py", line 18, in middleware
response = make_request(method, params)
File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/middleware/formatting.py", line 21, in middleware
response = make_request(method, formatted_params)
File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/middleware/normalize_errors.py", line 9, in middleware
result = make_request(method, params)
File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/middleware/validation.py", line 44, in middleware
return make_request(method, post_validated_params)
File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/middleware/formatting.py", line 21, in middleware
response = make_request(method, formatted_params)
File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/providers/eth_tester/middleware.py", line 315, in middleware
return make_request(method, [filled_transaction] + params[1:])
File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/middleware/fixture.py", line 12, in middleware
return make_request(method, params)
File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/middleware/formatting.py", line 21, in middleware
response = make_request(method, formatted_params)
File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/providers/eth_tester/main.py", line 46, in make_request
response = delegator(self.ethereum_tester, params)
File "cytoolz/functoolz.pyx", line 232, in cytoolz.functoolz.curry.__call__
File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/web3/providers/eth_tester/defaults.py", line 36, in call_eth_tester
return getattr(eth_tester, fn_name)(*fn_args, **fn_kwargs)
File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/eth_tester/main.py", line 466, in estimate_gas
raw_gas_estimate = self.backend.estimate_gas(raw_transaction)
File "/Users/paymahn/mycro/venv/lib/python3.6/site-packages/eth_tester/utils/formatting.py", line 88, in wrapper
raise old_to_new_exceptions[type(e)] from e
eth_tester.exceptions.TransactionFailed