Неинтуитивные возвращаемые значения контракта солидности в python ethereum - PullRequest
0 голосов
/ 06 мая 2018

Я играю с ethereum и python, и у меня какое-то странное поведение, которое я не могу понять. У меня возникают проблемы с пониманием того, как возвращаемые значения работают при вызове функции контракта с клиентом Python w3. Вот минимальный пример, который смущает меня несколькими способами:

Контракт:

pragma solidity ^0.4.0;

contract test {
    function test(){

    }

    function return_true() public returns (bool) {
        return true;
    }

    function return_address() public returns (address) {
        return 0x111111111111111111111111111111111111111;
    }
}

Код юнит-теста Python

from web3 import Web3, EthereumTesterProvider
from solc import compile_source
from web3.contract import ConciseContract
import unittest
import os


def get_contract_source(file_name):
    with open(file_name) as f:
        return f.read()


class TestContract(unittest.TestCase):
    CONTRACT_FILE_PATH = "test.sol"
    DEFAULT_PROPOSAL_ADDRESS = "0x1111111111111111111111111111111111111111"

    def setUp(self):
        # copied from https://github.com/ethereum/web3.py/tree/1802e0f6c7871d921e6c5f6e43db6bf2ef06d8d1 with MIT licence
        # has slight modifications to work with this unittest
        contract_source_code = get_contract_source(self.CONTRACT_FILE_PATH)
        compiled_sol = compile_source(contract_source_code)  # Compiled source code
        contract_interface = compiled_sol[':test']
        # web3.py instance
        self.w3 = Web3(EthereumTesterProvider())
        # Instantiate and deploy contract
        self.contract = self.w3.eth.contract(abi=contract_interface['abi'], bytecode=contract_interface['bin'])
        # Get transaction hash from deployed contract
        tx_hash = self.contract.constructor().transact({'from': self.w3.eth.accounts[0]})
        # Get tx receipt to get contract address
        tx_receipt = self.w3.eth.getTransactionReceipt(tx_hash)
        self.contract_address = tx_receipt['contractAddress']
        # Contract instance in concise mode
        abi = contract_interface['abi']
        self.contract_instance = self.w3.eth.contract(address=self.contract_address, abi=abi,
                                                      ContractFactoryClass=ConciseContract)

    def test_return_true_with_gas(self):
        # Fails with HexBytes('0xd302f7841b5d7c1b6dcff6fca0cd039666dbd0cba6e8827e72edb4d06bbab38f') != True
        self.assertEqual(True, self.contract_instance.return_true(transact={"from": self.w3.eth.accounts[0]}))

    def test_return_true_no_gas(self):
        # passes
        self.assertEqual(True, self.contract_instance.return_true())

    def test_return_address(self):
        # fails with AssertionError: '0x1111111111111111111111111111111111111111' != '0x0111111111111111111111111111111111111111'
        self.assertEqual(self.DEFAULT_PROPOSAL_ADDRESS, self.contract_instance.return_address())

У меня есть три метода, выполняющих тестирование функций в контракте. В одном из них возвращается не True значение и вместо него HexBytes. В другом случае функции контракта возвращают адресную константу, но python видит значение, отличное от ожидаемого. В еще одном случае я вызываю контрактную функцию return_true без газа, а постоянная True видна Python.

  1. Почему при вызове return_true с transact={"from": self.w3.eth.accounts[0]} возвращаемое значение функции будет HexBytes(...)?
  2. Почему адрес, возвращаемый return_address, отличается от того, что я ожидал?

Я думаю, что у меня есть какое-то фундаментальное неправильное понимание того, как газ влияет на вызовы функций.

...