Solidity源文件的布局

源文件可以包含任意数量的 contract definitionsimport 指令, pragma directivesstructenumfunctionerrorconstant variable 定义。

SPDX许可证标识符

如果智能合约的源代码可用,则可以更好地建立对智能合约的信任。由于源代码的提供总是涉及到版权方面的法律问题,所以Solidity编译器鼓励使用机器可读的 SPDX license identifiers . 每个源文件都应以注释开头,说明其许可证:

// SPDX-License-Identifier: MIT

编译器不会验证许可证是否是 list allowed by SPDX ,但它在 bytecode metadata .

如果不想指定许可证或源代码不是开源的,请使用特殊值 UNLICENSED .

当然,提供此注释并不能免除您与许可相关的其他义务,例如必须在每个源文件或原始版权所有者中提到特定的许可头。

编译器可以在文件级别的文件中的任何位置识别注释,但建议将其放在文件的顶部。

有关如何使用SPDX许可证标识符的更多信息,请访问 SPDX website .

编译指示

这个 pragma 关键字用于启用某些编译器功能或检查。杂注指令始终是源文件的本地指令,因此如果要在整个项目中启用杂注,则必须将杂注添加到所有文件。如果你 import 另一个文件中,该文件中的杂注执行以下操作 not 自动应用于导入文件。

版本pragma

源文件可以(也应该)使用版本杂注进行注释,以拒绝使用将来可能引入不兼容更改的编译器版本进行编译。我们试图将这些限制保持在绝对的最低限度,并以一种方式引入它们,即语义的改变也需要语法的改变,但这并不总是可能的。因此,至少对于包含中断更改的版本,阅读变更日志始终是一个好主意。这些版本始终具有表单的版本 0.x.0x.0.0 .

pragma版本的用法如下: pragma solidity ^0.5.2;

具有上述行的源文件不使用0.5.2版之前的编译器编译,也不适用于从0.6.0版开始的编译器(第二个条件是通过使用 ^ ). 因为在版本之前不会有突破性的变化 0.6.0 ,可以确保代码按预期方式编译。编译器的确切版本没有被修复,因此仍然可以发布错误修复版本。

可以为编译器版本指定更复杂的规则,这些规则遵循 npm

注解

使用版本pragma 更改编译器的版本。它也是 启用或禁用编译器的功能。它只是指示编译器检查其版本是否与pragma所需的版本匹配。如果不匹配,编译器将发出一个错误。

ABI编码器语法

通过使用 pragma abicoder v1pragma abicoder v2 您可以在ABI编码器和解码器的两种实现之间进行选择。

新的ABI编码器(V2)能够对任意嵌套的数组和结构进行编码和解码。它可能会产生不太理想的代码,并且没有接受过与旧编码器一样多的测试,但在0.6.0版本中被认为是非试验性的。您仍然需要使用以下命令显式激活它 pragma abicoder v2; 。由于默认情况下将从Solidity 0.8.0开始激活,因此可以使用以下选项选择旧编码器 pragma abicoder v1;

新编码器支持的类型集是旧编码器支持的类型的严格超集。使用它的合同可以不受限制地与不使用它的合同交互。只有当非`abicoder v2``约定不尝试进行需要仅由新编码器支持的解码类型的调用时,反向才是可能的。编译器可以检测到这一点,并将发出错误。简单地启用 abicoder v2 因为你们的合同足以消除这个错误。

注解

此编译指示适用于在其被激活的文件中定义的所有代码,无论该代码最终在哪里结束。这意味着其源文件被选择用ABI编码器v1编译的协定仍然可以通过从另一个协定继承来包含使用新编码器的代码。如果新类型仅在内部使用,而不在外部函数签名中使用,则允许这样做。

注解

直到坚固度0.7.4,可以通过使用以下方式选择ABI编码器v2 pragma experimental ABIEncoderV2 ,但无法显式选择编码器v1,因为它是默认的。

实验语用

第二个语用是实验语用。它可用于启用编译器的功能或默认情况下尚未启用的语言。目前支持以下实验语用:

阿比编码器2

因为ABI编码器v2不再被认为是实验性的,所以可以通过 pragma abicoder v2 (请参阅上文),因为坚固度为0.7.4。

SMTChecker

在构建solidity编译器时必须启用此组件,因此它在所有solidity二进制文件中都不可用。这个 build instructions 解释如何激活此选项。对于大多数版本的ubuntuppa版本,它都是激活的,但是对于Docker映像、Windows二进制文件或静态构建的Linux二进制文件则没有。它可以通过 smtCallback 如果您在本地安装了SMT解算器并通过节点(而不是通过浏览器)运行solc js。

如果你使用 pragma experimental SMTChecker; ,然后你得到额外的 safety warnings 通过查询SMT解算器获得。组件还不支持solidity语言的所有特性,可能会输出许多警告。如果它报告不支持的功能,分析可能不完全正确。

导入其他源文件

语法和语义

Solidity支持导入语句,以帮助模块化与JavaScript中类似的代码(从ES6开始)。但是,solidity不支持 default export .

在全局级别,可以使用以下表单的import语句:

import "filename";

这个 filename 部件称为 导入路径 。此语句将所有全局符号从“filename”(以及在那里导入的符号)导入到当前全局作用域(与ES6不同,但为了稳固而向后兼容)。不建议使用此表单,因为它会不可预知地污染命名空间。如果您在“filename”中添加新的顶级项目,则它们会自动出现在从“filename”导入的所有文件中。最好是显式导入特定符号。

以下示例创建新的全局符号 symbolName 其成员都是来自 "filename"

import * as symbolName from "filename";

这会导致所有全局符号的格式都可用 symbolName.symbol .

此语法的一个变体不是ES6的一部分,但可能有用,它是:

import "filename" as symbolName;

相当于 import * as symbolName from "filename"; .

如果存在命名冲突,可以在导入时重命名符号。例如,下面的代码创建新的全局符号 aliassymbol2 哪个参考 symbol1symbol2 从内部 "filename" ,分别。

import {symbol1 as alias, symbol2} from "filename";

导入路径

为了能够在所有平台上支持可重现的构建,固态编译器必须抽象出源文件所存储的文件系统的细节。因此,导入路径不直接引用主机文件系统中的文件。相反,编译器维护一个内部数据库( 虚拟文件系统VFS 简而言之),其中每个源单元被分配唯一的 源设备名称 它是不透明且非结构化的标识符。IMPORT语句中指定的导入路径被转换为源设备名称,并用于在此数据库中查找相应的源设备。

使用 Standard JSON API,可以直接提供所有源文件的名称和内容作为编译器输入的一部分。在这种情况下,源单元名称确实是任意的。但是,如果希望编译器自动查找源代码并将其加载到VFS中,则源单元名称的结构需要使 import callback 找出他们的位置。使用命令行编译器时,默认的导入回调仅支持从主机文件系统加载源代码,这意味着源单元名称必须是路径。某些环境提供更多功能的自定义回调。例如, Remix IDE 提供一个可以让您 import files from HTTP, IPFS and Swarm URLs or refer directly to packages in NPM registry

有关编译器使用的虚拟文件系统和路径解析逻辑的完整说明,请参见 Path Resolution

评论

单行注释 (// )多行注释 (/*...*/ )是可能的。

// This is a single-line comment.

/*
This is a
multi-line comment.
*/

注解

单行注释由UTF-8编码的任何Unicode行终止符(LF、VF、FF、CR、NEL、LS或PS)终止。在注释之后,终止符仍然是源代码的一部分,所以如果它不是ASCII符号(这些符号是NEL、LS和PS),它将导致解析器错误。

此外,还有另一种类型的注释,称为NatSpec注释,在 style guide 。它们是用三个劈开写的 (/// )或双星号挡路 (/** ... */ ),并且它们应该直接在函数声明或语句的上方使用。