ethereum python

时间:2018-05-05 21:56:31

标签: python ethereum solidity web3

我正在玩以太坊和蟒蛇,我遇到了一些我无法理解的奇怪行为。在使用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 unittest代码

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契约函数,并且python可以看到True常量。

  1. 为什么用return_true调用transact={"from": self.w3.eth.accounts[0]}会导致函数的返回值为HexBytes(...)
  2. 为什么return_address返回的地址与我的期望不同?
  3. 我认为我对气体如何影响函数调用存在某种根本性的误解。

1 个答案:

答案 0 :(得分:1)

  1. 返回的值是区块链上的交易哈希。进行交易时(即,使用“交易”而不是“调用”时),区块链会被修改,您正在使用的库将返回交易哈希。在该过程中,您必须已支付以太币才能修改区块链。但是,以只读模式运行完全不需要醚,因此无需指定气体。

  2. 以开头的“ 0x”折扣,以太坊地址的长度为40,但是在您的测试中,您使用的是39个字符长的地址,因此此处缺少“ 1”。意思是,测试是正确的,您输入的内容有误。

Offtopic,return_truereturn_address在Solidity中均应标记为view,因为它们实际上并未修改状态。我很确定您会在混音中收到警告。完成此操作后,就无需使用“交易”和支付以太币来访问这两种方法,您可以免费使用“通话”来实现。

编辑

忘记提及:如果使用transact后需要访问事务哈希,可以对返回的.hex()对象调用HexBytes方法。这样一来,您就可以将交易哈希值作为字符串使用,通常比HexBytes有用。

希望对您有帮助!