验证
智能合约被设计为“无需信任”,这意味着用户在与合约交互之前不必信任第三方(例如开发人员和公司)。
作为去信任的必要条件,用户和其他开发人员必须能够验证智能合约的源代码。
源代码验证向用户和开发人员保证,发布的合约代码与在以太坊区块链上的合约地址上运行的代码相同。
重要的是要区分“源代码验证”和“形式验证”。
源代码验证,后面会详细解释,是指验证给定的智能合约的高级语言(例如Solidity)的源代码是否编译为相同的字节码以在合约地址执行。
但是,形式验证描述了验证智能合约的正确性,这意味着合约的行为符合预期。虽然依赖于上下文,但合约验证通常是指源代码验证。
什么是源代码验证?
在以太坊虚拟机 (EVM) 中部署智能合约之前,开发人员将合约的源代码(用 Solidity 或其他高级编程语言编写的指令)编译为字节码。
由于 EVM 无法解释高级指令,因此将源代码编译为字节码(即低级机器指令)对于在 EVM 中执行合约逻辑是必要的。
源代码验证是比较智能合约的源代码和合约创建过程中使用的编译字节码,以检测任何差异。
验证智能合约很重要,因为广告中的合约代码可能与区块链上运行的代码不同。
智能合约验证可以通过更高级别的语言来调查合约的功能,而无需阅读机器代码。
函数、值以及通常的变量名和注释与编译和部署的原始源代码保持一致。
这使得阅读代码变得更加容易。源代码验证还提供代码文档,以便最终用户知道智能合约的设计目的。
什么是全面验证?
源代码的某些部分不会影响已编译的字节码,例如注释或变量名。这意味着具有不同变量名和不同注释的两个源代码都能够验证同一个合约。
这样,恶意行为者可以在源代码中添加欺骗性评论或提供误导性变量名称,并使用与原始源代码不同的源代码验证合同。
可以通过将额外数据附加到字节码来避免这种情况,以作为源代码准确性的加密保证,并作为编译信息的指纹。 必要的信息可以在 Solidity 的合约元数据中找到,并且该文件的哈希值被附加到合约的字节码中。您可以在元数据游乐场中看到它的实际效果
元数据文件包含有关合约编译的信息,包括源文件及其哈希值。这意味着,如果任何编译设置甚至其中一个源文件中的一个字节发生变化,元数据文件就会发生变化。
因此,附加到字节码的元数据文件的哈希值也会发生变化。这意味着如果合约的字节码 + 附加的元数据哈希与给定的源代码和编译设置匹配,我们可以确定这与原始编译中使用的源代码完全相同,甚至没有一个字节不同。
这种利用元数据散列的验证称为“完全验证”(也称为“完美验证”)。如果元数据哈希不匹配或在验证中不被考虑,这将是“部分匹配”,这是目前验证合约的更常见方式。
如果没有经过全面验证,可能会插入不会反映在已验证源代码中的恶意代码。
大多数开发人员不知道完全验证,也不保留他们编译的元数据文件,因此部分验证是迄今为止验证合约的事实上的方法。
为什么源代码验证很重要?
不信任 Trustlessness
无需信任可以说是智能合约和去中心化应用程序(dapps)的最大前提。
智能合约是“不可变的”,无法更改;合约只会执行部署时代码中定义的业务逻辑。这意味着开发人员和企业在部署到以太坊后无法篡改合约代码。
要使智能合约无需信任,合约代码应可用于独立验证。虽然每个智能合约的编译字节码都在区块链上公开可用,但对于开发人员和用户来说,低级语言都难以理解。
项目通过发布合同的源代码来减少信任假设。但这导致了另一个问题:很难验证发布的源代码与合约字节码是否匹配。
在这种情况下,不信任的价值就丧失了,因为用户必须信任开发人员在将合约部署到区块链之前不会更改合约的业务逻辑(即通过更改字节码)。
源代码验证工具保证智能合约的源代码文件与汇编代码匹配。
结果是一个无需信任的生态系统,用户不会盲目信任第三方,而是在将资金存入合约之前验证代码。
用户安全
使用智能合约,通常会有很多钱处于危险之中。
这需要更高的安全保证,并在使用智能合约之前对其逻辑进行验证。
问题是不道德的开发人员可以通过在智能合约中插入恶意代码来欺骗用户。
如果没有验证,恶意智能合约可能会有后门、有争议的访问控制机制、可利用的漏洞以及其他危害用户安全的东西,而这些东西会未被发现。
发布智能合约的源代码文件可以让感兴趣的人(例如审计员)更轻松地评估合约中的潜在攻击向量。
通过多方独立验证智能合约,用户对其安全性有更强的保证。
如何验证以太坊智能合约的源代码
在以太坊上部署智能合约需要将带有数据有效负载(编译后的字节码)的交易发送到特殊地址。
数据负载是通过编译源代码生成的,加上合约实例的构造函数参数附加到事务中的数据负载。
编译是确定性的,这意味着如果使用相同的源文件和编译设置(例如编译器版本、优化器),它总是产生相同的输出(即合约字节码)。
验证智能合约基本上涉及以下步骤:
-
将源文件和编译设置输入到编译器。
-
编译器输出合约的字节码
-
在给定地址获取已部署合约的字节码
-
将部署的字节码与重新编译的字节码进行比较。 如果代码匹配,则使用给定的源代码和编译设置验证合约。
-
此外,如果字节码末尾的元数据散列匹配,则它将是完全匹配的。
请注意,这是对验证的简单描述,并且有许多例外情况不适用于此,例如具有不可变变量
源代码验证工具
验证合同的传统过程可能很复杂。
这就是为什么我们有工具来验证部署在以太坊上的智能合约的源代码。
这些工具自动化了大部分源代码验证,并为用户的利益策划了经过验证的合同。
Etherscan 以太扫描
虽然通常被称为以太坊区块链浏览器,但 Etherscan 还为智能合约开发人员和用户提供源代码验证服务。
Etherscan 允许您从原始数据负载(源代码、库地址、编译器设置、合约地址等)重新编译合约字节码。如果重新编译的字节码与链上合约的字节码(和构造函数参数)相关联,则合同已核实。
验证后,您的合约源代码会收到“已验证”标签,并在 Etherscan 上发布以供其他人审核。它还被添加到验证合同部分——一个带有验证源代码的智能合同存储库。
Etherscan 是验证合约最常用的工具。
但是,Etherscan 的合约验证有一个缺点:它无法比较链上字节码和重新编译的字节码的元数据哈希。因此,Etherscan 中的匹配是部分匹配。
Sourcify 采购
Sourcify 是另一种用于验证开源和去中心化合约的工具。
它不是区块浏览器,仅在不同的基于 EVM 的网络上验证合约。
它充当其他工具在其之上构建的公共基础设施,旨在使用元数据文件中的 ABI 和 NatSpec 注释实现更人性化的合同交互。
与 Etherscan 不同,Sourcify 支持与元数据哈希的完全匹配。
经过验证的合约在其 HTTP 和 IPFS 上的公共存储库中提供服务,这是一个分散的、内容寻址的存储。
这允许通过 IPFS 获取合约的元数据文件,因为附加的元数据哈希是 IPFS 哈希。
此外,还可以通过 IPFS 检索源代码文件,因为这些文件的 IPFS 哈希值也可以在元数据中找到。
可以通过在其 API 或 UI 上提供元数据文件和源文件,或使用插件来验证合约。
Sourcify 监控工具还会监听新区块上的合约创建,并尝试验证合约的元数据和源文件是否发布在 IPFS 上。
Tenderly 温柔地
Tenderly 是一个旨在加速以太坊智能合约开发人员工作流程的平台。
它还为开发人员提供源代码验证服务。
您可以选择通过导入源文件或 Solidity 编译器生成的元数据文件来验证您与 Tenderly 的合同。
与其他验证工具一样,Tenderly 需要合约地址/网络、编译器设置和优化功能等详细信息来验证任何智能合约。
可以私下验证合同,使其仅对您(和您团队的其他成员)可见。
公开验证合同使其对使用 Tenderly 平台的每个人都可见。
虽然对验证合同很有用,但 Tenderly 没有列表中其他工具可用的有用功能。
例如,它不允许最终用户检查合同是否经过验证(开发人员选择公开验证除外),并且不检查元数据哈希之间的匹配。
参考资料
https://ethereum.org/zh/developers/docs/smart-contracts/verifying/