如何确定正确的合约编译选项?

Posted

技术标签:

【中文标题】如何确定正确的合约编译选项?【英文标题】:How to determine correct contract compilation options? 【发布时间】:2018-12-05 20:24:20 【问题描述】:

我已成功将合同部署到 Kaleido,但我无法弄清楚如何正确验证它。这是部署合约的源代码,我已经验证了最后一条打印语句打印的地址出现在我的 Kaleido 区块链中:

从 web3 导入 web3 从 web3.providers 导入 HTTPProvider 从 solc 导入 compile_source # Solidity 源代码 contract_source_code = ''' 编译指示 ^0.4.0; 合同迎宾 字符串公共问候语; 功能迎宾员() 问候 = '你好'; 功能 setGreeting(字符串 _greeting)公共 问候=_问候; 函数 greet() 常量返回(字符串) 回礼; ''' compiled_sol = compile_source(contract_source_code) # 编译好的源代码 contract_interface = compiled_sol[':Greeter'] w3 = Web3(HTTPProvider("https://XXXXX:YYYYY@ZZZZZZZ.kaleido.io")) contract_ = w3.eth.contract( abi=contract_interface['abi'], bytecode=contract_interface['bin']) # 注意:与万花筒交互时,gasPrice 必须为 0(我认为是因为我选择的共识算法) # 这似乎与发送自哪个帐户无关 construct_txn = contract_.constructor().buildTransaction( “来自”:w3.eth.accounts[0], “气体”:1728712, 'gasPrice': 0) txn = w3.eth.sendTransaction(construct_txn) tx_receipt = w3.eth.getTransactionReceipt(txn) contract_address = tx_receipt['contractAddress'] 打印(合同地址)

当我尝试验证我的合约时,我被要求提供源代码、合约名称、编译器版本以及是否使用了优化。

我使用以下请求的源代码

编译指示 ^0.4.0; 合同迎宾 字符串公共问候语; 功能迎宾员() 问候 = '你好'; 功能 setGreeting(字符串 _greeting)公共 问候=_问候; 函数 greet() 常量返回(字符串) 回礼;

我使用Greeter 作为合约名称。 solc --version 返回 Version: 0.4.24+commit.e67f0147.Darwin.appleclang,我发现它是在 5 月 16 日提交的:https://github.com/ethereum/solidity/search?q=e67f0147&type=Commits。

我已经尝试了以下所有编译器版本 + 启用优化的组合:0.4.24, 0.4.24-nightly.2018.5.16 x 优化已启用,优化已禁用,但这些组合均无效。当我尝试 0.4.24-nightly.2018.5.16 时出现以下错误,因为未启用编译器和优化。:

编译结果与位于 0x4c94e89d5ec3125339906109f143673f40868df2 的输入创建字节码不匹配。 编译失败:[“警告:这是一个预发布的编译器版本,请不要在生产中使用它。\n”,”:6:5:警告:不推荐将构造函数定义为与合约同名的函数。请改用 \"constructor(...) ... \"。\n function Greeter() \n ^(相关源代码部分从这里开始并跨越多行)。\n",":6:5 :警告:未指定可见性。默认为 \"public\"。\n function Greeter() \n ^(相关源代码部分从此处开始并跨越多行)。\n",":14:5: 警告:未指定可见性。默认为 \"public\"。\n 函数 greet() 常量返回(字符串)\n ^(相关源部分从此处开始并跨越多行)。\n"] 。

【问题讨论】:

将代码中的编译指示更改为 0.4.24 并选择非夜间构建。 还是没有运气。我将我的编译指示更改为pragma solidity ^0.4.24;,并尝试使用启用和禁用的优化进行验证,但两次都被拒绝了。 【参考方案1】:

您不需要编译器参数来验证合约。只有在极少数情况下,您才需要了解它们。我目前使用的是 0.4.21 编译器,并且能够仅使用合约 Solidity 源代码来验证我的合约。

我可能会建议在你的合约编译指示中指定你正在使用的特定编译器,而不是 ^0.4.0。

当我尝试验证时,我也在使用Geth PoA 环境,并且必须对您的代码进行一些修改才能使其正常工作。您使用的是 Quorum 环境吗?哪种协议?

这是我从 README 中的快速入门示例中获取的代码:

import json
import web3

from web3 import Web3, HTTPProvider
from solc import compile_source
from web3.contract import ConciseContract
from web3.middleware import geth_poa_middleware

# Solidity source code
contract_source_code = '''
pragma solidity ^0.4.21;

contract Greeter 
    string public greeting;

    function Greeter() public 
        greeting = 'Hello';
    

    function setGreeting(string _greeting) public 
        greeting = _greeting;
    

    function greet() public returns (string) 
        return greeting;
    

'''

compiled_sol = compile_source(contract_source_code) # Compiled source code
contract_interface = compiled_sol['<stdin>:Greeter']

# web3.py instance
w3 = Web3(HTTPProvider("https://YYY:ZZZ@XXXXXX.us-east-2.kaleido.io"))
w3.middleware_stack.inject(geth_poa_middleware, layer=0)

# set pre-funded account as sender
w3.eth.defaultAccount = w3.eth.accounts[0]

# Instantiate and deploy contract
Greeter = w3.eth.contract(abi=contract_interface['abi'], bytecode=contract_interface['bin'])

# Submit the transaction that deploys the contract
tx_hash = Greeter.constructor().transact()

# Wait for the transaction to be mined, and get the transaction receipt
tx_receipt = w3.eth.waitForTransactionReceipt(tx_hash)
print(tx_receipt.contractAddress)
# Create the contract instance with the newly-deployed address
greeter = w3.eth.contract(
    address=tx_receipt.contractAddress,
    abi=contract_interface['abi'],
)

# Display the default greeting from the contract
print('Default contract greeting: '.format(
    greeter.functions.greet().call()
))

print('Setting the greeting to Nihao...')
tx_hash = greeter.functions.setGreeting('Nihao').transact()
# Wait for transaction to be mined...
w3.eth.waitForTransactionReceipt(tx_hash)


# Display the new greeting value
print('Updated contract greeting: '.format(
    greeter.functions.greet().call()
))

# When issuing a lot of reads, try this more concise reader:
reader = ConciseContract(greeter)
assert reader.greet() == "Nihao"

如果您确实需要知道如何找到编译时参数,它们通常以kwargs 的形式提供给编译函数。这是可以发挥作用的源代码行:https://github.com/ethereum/py-solc/blob/c595d84d9f0ef5f5da0a5d79e7d5fcabecfe5f06/solc/main.py#L106

【讨论】:

我使用 Quorum 和 RAFT 作为协议。我认为我不需要知道使用的编译器选项,只需要知道编译器版本以及是否启用了优化。您必须进行哪些更改才能使合同验证生效?

以上是关于如何确定正确的合约编译选项?的主要内容,如果未能解决你的问题,请参考以下文章

如何确定哪个Xlint选项对应于编译器警告?

编译 OpenCL 应用程序和使用可用编译器选项的正确方法

如何开发编译部署调用智能合约

使用交叉编译器时如何确定配置的主机值

是否可以从 gcc 的源代码中确定或设置编译器选项?

solidity 智能合约(3):使用truffle编译部署及测试合约