以太坊python中不直观的solidity合约返回值

Posted

技术标签:

【中文标题】以太坊python中不直观的solidity合约返回值【英文标题】:Unintuitive solidity contract return values in ethereum python 【发布时间】:2018-10-16 02:07:44 【问题描述】:

我正在玩弄以太坊和 python,但我遇到了一些我无法理解的奇怪行为。在使用 python w3 客户端调用合同函数时,我无法理解返回值是如何工作的。这是一个最小的例子,它以几种不同的方式让我感到困惑:

合同:

编译指示 ^0.4.0; 合同测试 功能测试() 函数 return_true() 公共返回 (bool) 返回真; 函数 return_address() 公共返回 (地址) 返回0x11111111111111111111111111111111111111;

Python 单元测试代码

从 web3 导入 Web3,EthereumTesterProvider 从 solc 导入 compile_source 从 web3.contract 导入 ConciseContract 导入单元测试 导入操作系统 def get_contract_source(文件名): 使用 open(file_name) 作为 f: 返回 f.read() 类TestContract(unittest.TestCase): CONTRACT_FILE_PATH = "test.sol" DEFAULT_PROPOSAL_ADDRESS = "0x111111111111111111111111111111111111111" 默认设置(自我): # 使用 MIT 许可证从 https://github.com/ethereum/web3.py/tree/1802e0f6c7871d921e6c5f6e43db6bf2ef06d8d1 复制 # 稍作修改以使用此单元测试 contract_source_code = get_contract_source(self.CONTRACT_FILE_PATH) compiled_sol = compile_source(contract_source_code) # 编译好的源代码 contract_interface =compiled_sol[':test'] # web3.py 实例 self.w3 = Web3(EthereumTesterProvider()) # 实例化和部署合约 self.contract = self.w3.eth.contract(abi=contract_interface['abi'], bytecode=contract_interface['bin']) # 从已部署的合约中获取交易哈希 tx_hash = self.contract.constructor().transact('from': self.w3.eth.accounts[0]) # 获取 tx 收据以获取合约地址 tx_receipt = self.w3.eth.getTransactionReceipt(tx_hash) self.contract_address = tx_receipt['contractAddress'] # 简洁模式下的合约实例 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): # 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): # 次通过 self.assertEqual(True, self.contract_instance.return_true()) def test_return_address(self): # 失败并出现 AssertionError: '0x1111111111111111111111111111111111111111' != '0x011111111111111111111111111111111111111' self.assertEqual(self.DEFAULT_PROPOSAL_ADDRESS, self.contract_instance.return_address())

我有三种方法对合约中的功能进行测试。在其中一个中,返回非True 值,而是返回HexBytes。在另一种情况下,合约函数返回一个地址常量,但 python 看到的值与预期的不同。在另一种情况下,我在没有气体的情况下调用 return_true 合约函数,python 可以看到 True 常量。

    为什么用transact="from": self.w3.eth.accounts[0]调用return_true会导致函数的返回值为HexBytes(...)? 为什么return_address 返回的地址与我预期的不同?

我认为我对气体如何影响函数调用存在某种根本性的误解。

【问题讨论】:

交易没有返回值。如果您发送交易,则结果是交易哈希。然后您可以等待交易被挖掘并查看结果,但没有返回值可用。如果您改为call 方法,则在本地计算结果而不向网络的其余部分发送事务,并在响应中将函数的返回值发回给您。 啊,我明白了。谢谢! 【参考方案1】:

    返回值是区块链上的交易哈希。交易时(即,当使用“交易”而不是“调用”时)区块链被修改,并且您使用的库返回交易哈希。在此过程中,您必须支付以太币才能修改区块链。但是,在只读模式下运行完全不需要以太币,因此不需要指定 gas。

    扣除开头的“0x”,以太坊地址的长度为 40,但在您的测试中,您使用的是 39 个字符长的地址,因此那里缺少一个“1”。意思是,测试是正确的,你的输入有错误。

题外话,return_truereturn_address 在 Solidity 中都应该标记为 view,因为它们实际上并没有修改状态。我很确定你会在混音中收到警告。一旦你这样做了,就不需要使用“交易”和支付以太币来访问这两种方法,你可以免费使用“调用”来做到这一点。

编辑

忘了提一下:如果您在使用transact 后需要访问事务哈希,您可以在返回的HexBytes 对象上调用.hex() 方法。这会将交易哈希作为字符串提供给您,这通常比 HexBytes 更有用。

希望对你有帮助!

【讨论】:

以上是关于以太坊python中不直观的solidity合约返回值的主要内容,如果未能解决你的问题,请参考以下文章

多线程——爬取以太坊Solidity智能合约代码的简约Python爬虫

第一行代码:以太坊-使用Solidity语言开发和测试智能合约

solidity开发以太坊代币智能合约

用基于 Python 的开发框架 Brownie 部署以太坊智能合约

用基于 Python 的开发框架 Brownie 部署以太坊智能合约

基于以太坊的智能合约开发教程Solidity 合约的销毁