Contract-Invocation
簡單智能合約的非確定性結果
我目前正在調試一個更複雜的智能合約,由於我不明白的原因,儘管輸入相同,但它的行為不同。更準確地說,它在多次部署時為相同的輸入返回不同的值。我試圖盡可能簡化契約和對 web3.py 的呼叫。以下智能合約是我能想到的最小工作範例,但仍然存在此問題:
pragma solidity ^0.4.0; contract TestContract { bytes32 recorded_value; bytes32 recorded_salt; //Unused, but required for the problem to appear function TestContract(bytes32 value, bytes32 salt) public { recorded_value = value; } function getHash() public constant returns (bytes32) { return keccak256(recorded_value); } }
這就是我編譯和呼叫智能合約的方式:
#Based on the source code from https://github.com/pipermerriam/web3.py import json import web3 from web3 import Web3, HTTPProvider, TestRPCProvider from solc import compile_source from web3.contract import ConciseContract w3 = Web3(TestRPCProvider()) def deploy_smart_contract(source_code_file_path, contract_name, constructor_arguments): with open(source_code_file_path) as f: commitment_helper_source_code = f.read() compiled_sol = compile_source(commitment_helper_source_code) contract_interface = compiled_sol['<stdin>:' + contract_name] smart_contract = w3.eth.contract(contract_interface['abi'], bytecode=contract_interface['bin']) tx_hash = smart_contract.deploy(transaction={'from': w3.eth.accounts[0]}, args=constructor_arguments) tx_receipt = w3.eth.getTransactionReceipt(tx_hash) smart_contract_address = tx_receipt['contractAddress'] deployed_smart_contract = w3.eth.contract(contract_interface['abi'], smart_contract_address, ContractFactoryClass=ConciseContract) return deployed_smart_contract, smart_contract def print_hex(char_array): output = "0x"; for char in char_array: output += str("%02x" % ord(char)) return output contract_instance, contract = deploy_smart_contract('contract.sol', 'TestContract', {Web3.toBytes(123), Web3.toBytes(100)}) value = contract_instance.getHash() print("Hash: " + print_hex(value))
如果我多次執行此程式碼,結果如下所示:
(.venv-py3) andreas@***:/media/sf_temp$ python test.py 127.0.0.1 - - [27/Jan/2018 15:39:56] "POST / HTTP/1.1" 200 499 127.0.0.1 - - [27/Jan/2018 15:39:56] "POST / HTTP/1.1" 200 48 127.0.0.1 - - [27/Jan/2018 15:39:56] "POST / HTTP/1.1" 200 44 127.0.0.1 - - [27/Jan/2018 15:39:56] "POST / HTTP/1.1" 200 1350 127.0.0.1 - - [27/Jan/2018 15:39:56] "POST / HTTP/1.1" 200 107 127.0.0.1 - - [27/Jan/2018 15:39:56] "POST / HTTP/1.1" 200 391 127.0.0.1 - - [27/Jan/2018 15:39:56] "POST / HTTP/1.1" 200 391 Hash: 0x4cab01aa70c7d27ce12007ae744261ed3e0ee9162bc588f68526ea903ec2eb99 (.venv-py3) andreas@***:/media/sf_temp$ python test.py 127.0.0.1 - - [27/Jan/2018 15:39:58] "POST / HTTP/1.1" 200 499 127.0.0.1 - - [27/Jan/2018 15:39:58] "POST / HTTP/1.1" 200 48 127.0.0.1 - - [27/Jan/2018 15:39:58] "POST / HTTP/1.1" 200 44 127.0.0.1 - - [27/Jan/2018 15:39:58] "POST / HTTP/1.1" 200 1350 127.0.0.1 - - [27/Jan/2018 15:39:58] "POST / HTTP/1.1" 200 107 127.0.0.1 - - [27/Jan/2018 15:39:58] "POST / HTTP/1.1" 200 391 127.0.0.1 - - [27/Jan/2018 15:39:58] "POST / HTTP/1.1" 200 391 Hash: 0x75a12a7aab601952ef71dd6da71725eaa4eb7883096067546c8ae3f99cc9222e
注意不同的雜湊。這種情況每隔幾次我執行智能合約就會發生一次,但出乎意料的是,似乎沒有與時間或任何其他環境變數相關的模式。這裡發生了什麼?
不使用的時候也會出現這個問題
keccak256
。然後輸出有時會顯示0x7b00000000000000000000000000000000000000000000000000000000000000
而不是0x6400000000000000000000000000000000000000000000000000000000000000
,但它更難激發。當我刪除參數(來自契約和我的 API 呼叫)時,問題完全消失recorded_salt
了salt
,所以我假設我以某種方式錯誤地呼叫了建構子。
這真的很微妙。正如我在 Github 上打開的問題的答案所指出的:
您正在使用一組參數。集合沒有排序,所以當你迭代它們時,它們會出現什麼順序是半隨機的。如果您只是將其更改為元組或列表
$$ .. $$你會變得一致$$ t $$結果。
所以解決方案是為建構子參數使用一個列表(注意方括號而不是花括號):
contract_instance, contract = deploy_smart_contract('contract.sol', 'TestContract', [Web3.toBytes(123), Web3.toBytes(100)])