solidity 源文件的布局

2022-05-11 18:06 更新

源文件可以包含任意數量的 合約定義import、 pragmausing for指令以及 struct、enumfunction、 error 和常量變量定義。

SPDX 許可證標識符

如果智能合約的源代碼可用,則可以更好地建立對智能合約的信任。由于提供源代碼總是涉及版權方面的法律問題,Solidity 編譯器鼓勵使用機器可讀的SPDX 許可證標識符。每個源文件都應以說明其許可證的注釋開頭:

// SPDX-License-Identifier: MIT

編譯器不會驗證許可證是否是 SPDX 允許的列表的一部分,但它會在字節(jié)碼元數據中包含提供的字符串。

如果您不想指定許可證或者源代碼不是開源的,請使用特殊值UNLICENSED。請注意UNLICENSED(不允許使用,不在 SPDX 許可證列表中)與UNLICENSE(向所有人授予所有權利)不同。Solidity 遵循npm 建議。

當然,提供此注釋并不能免除您與許可相關的其他義務,例如必須在每個源文件或原始版權所有者中提及特定的許可標題。

編譯器在文件級別的文件中的任何位置都可以識別注釋,但建議將其放在文件的頂部。

有關如何使用 SPDX 許可證標識符的更多信息,請訪問 SPDX 網站。

編譯指示

pragma關鍵字用于啟用某些編譯器功能或檢查。pragma 指令始終位于源文件的本地,因此如果要在整個項目中啟用它,則必須將 pragma 添加到所有文件中。如果您導入另一個文件,該文件中的編譯指示不會自動應用于導入文件。

版本編譯指示

源文件可以(并且應該)使用版本編譯指示進行注釋,以拒絕使用可能引入不兼容更改的未來編譯器版本進行編譯。我們試圖將它們保持在絕對最低限度,并以語義變化也需要以語法變化的方式引入它們,但這并不總是可能的。因此,至少對于包含重大更改的版本,通讀更改日志總是一個好主意。這些版本始終具有形式 0.x.0x.0.0.

版本編譯指示使用如下:pragma solidity ^0.5.2;

具有上述行的源文件不能使用 0.5.2 版本之前的編譯器進行編譯,并且它也不能在從 0.6.0 版本開始的編譯器上工作(這第二個條件是通過 using 添加的^)。因為在 version 0.6.0之前不會有重大更改,您可以確保您的代碼按照您的預期方式編譯。編譯器的確切版本不固定,因此仍然可以發(fā)布錯誤修復版本。

可以為編譯器版本指定更復雜的規(guī)則,這些規(guī)則與npm使用的語法相同。

筆記
使用版本編譯指示不會更改編譯器的版本。它也不會啟用或禁用編譯器的功能。它只是指示編譯器檢查其版本是否與 pragma 所需的版本匹配。如果不匹配,編譯器會發(fā)出錯誤。

ABI 編碼器編譯指示

通過使用?pragma abicoder v1?或pragma abicoder v2您可以在 ABI 編碼器和解碼器的兩種實現(xiàn)之間進行選擇。

新的 ABI 編碼器 (v2) 能夠編碼和解碼任意嵌套的數組和結構。它可能會產生不太理想的代碼,并且沒有像舊編碼器那樣接受過多的測試,但從 Solidity 0.6.0 開始被認為是非實驗性的。您仍然必須使用pragma abicoder v2;。 由于它將默認從 Solidity 0.8.0 開始激活,因此可以選擇使用 ?pragma abicoder v1;?。

新編碼器支持的類型集是舊編碼器支持的類型的嚴格超集。使用它的合約可以與沒有限制的合約進行交互。僅當非?abicoder v2?合約不嘗試進行需要僅由新編碼器支持的解碼類型的調用時,反向才是可能的。編譯器可以檢測到這一點并將發(fā)出錯誤。只需為您的合同啟用?abicoder v2?就足以使錯誤消失。

筆記
此編譯指示適用于激活它的文件中定義的所有代碼,無論該代碼最終在何處結束。這意味著選擇了源文件以使用 ABI coder v1 編譯的合約仍然可以包含通過從另一個合約繼承來使用新編碼器的代碼。如果新類型僅在內部使用而不在外部函數簽名中使用,則允許這樣做。
筆記
在 Solidity 0.7.4 之前,可以使用?pragma experimental ABIEncoderV2? 選擇 ABI coder v2 ,但無法顯式選擇 coder v1,因為它是默認設置。

實驗性的Pragma

第二個 pragma 是實驗性 pragma。它可用于啟用默認情況下尚未啟用的編譯器或語言的功能。當前支持以下實驗性編譯指示:

ABIEncoderV2

因為 ABI 編碼器 v2 不再被認為是實驗性的,所以從 Solidity 0.7.4 開始可以通過?pragma abicoder v2?(請參見上文)選擇它。

SMTChecker

在構建 Solidity 編譯器時必須啟用此組件,因此它并非在所有 Solidity 二進制文件中都可用。構建說明解釋了如何激活此選項。在大多數版本中,它為 Ubuntu PPA 版本激活,但不適用于 Docker 映像、Windows 二進制文件或靜態(tài)構建的 Linux 二進制文件。如果您在本地安裝了 SMT 求解器并通過節(jié)點(而不是通過瀏覽器)運行 solc-js,則可以通過smtCallback為 solc-js 激活它 。

如果您使用?pragma experimental SMTChecker;?,那么您會收到額外 的安全警告,這些警告是通過查詢 SMT 求解器獲得的。該組件尚不支持 Solidity 語言的所有功能,并且可能會輸出許多警告。如果它報告不支持的功能,則分析可能不完全正確。

導入其他源文件

語法和語義

Solidity 支持導入語句,以幫助模塊化您的代碼,這些代碼類似于 JavaScript(從 ES6 開始)中可用的代碼。但是,Solidity 不支持默認導出的概念。

在全局級別,您可以使用以下形式的導入語句:

import "filename";

filename部分稱為導入路徑。此語句將所有全局符號從“文件名”(以及從那里導入的符號)導入當前全局范圍(與 ES6 不同,但向后兼容 Solidity)。不推薦使用這種形式,因為它會意外地污染命名空間。如果您在“文件名”中添加新的頂級項目,它們會自動出現(xiàn)在所有從“文件名”導入的文件中。最好顯式地導入特定符號。

以下示例創(chuàng)建一個新的全局符號symbolName,其成員是來自 的所有全局符號"filename"

import * as symbolName from "filename";

這導致所有全局符號都以symbolName.symbol.

這種語法的一個變體不是 ES6 的一部分,但可能有用的是:

import "filename" as symbolName;

這相當于。import * as symbolName from "filename";

如果存在命名沖突,您可以在導入時重命名符號。例如,下面的代碼分別創(chuàng)建了新的全局符號alias和從內部symbol2引用 symbol1和。symbol2"filename"

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

導入路徑

為了能夠在所有平臺上支持可重現(xiàn)的構建,Solidity 編譯器必須抽象出存儲源文件的文件系統(tǒng)的細節(jié)。由于這個原因,導入路徑不直接引用主機文件系統(tǒng)中的文件。相反,編譯器維護一個內部數據庫(虛擬文件系統(tǒng)或簡稱VFS),其中為每個源單元分配一個唯一的源單元名稱,該名稱是一個不透明且非結構化的標識符。導入語句中指定的導入路徑被翻譯成源單元名稱,用于在該數據庫中查找對應的源單元。

使用標準 JSON API,可以直接提供所有源文件的名稱和內容作為編譯器輸入的一部分。在這種情況下,源單元名稱確實是任意的。但是,如果您希望編譯器自動查找源代碼并將其加載到 VFS 中,則您的源單元名稱的結構需要使導入回調能夠找到它們。使用命令行編譯器時,默認導入回調僅支持從主機文件系統(tǒng)加載源代碼,這意味著您的源單元名稱必須是路徑。一些環(huán)境提供更通用的自定義回調。例如, Remix IDE提供了一個讓您從 HTTP、IPFS 和 Swarm URL 導入文件或直接引用 NPM 注冊表中的包

有關虛擬文件系統(tǒng)和編譯器使用的路徑解析邏輯的完整描述,請參見路徑解析

注釋

可以使用單行注釋 ( //) 和多行注釋 ( /*...*/)。

// 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 注釋,在樣式指南中有詳細說明。它們用三斜杠 ( ///) 或雙星號塊 ( ?/** ... */?) 編寫,應直接在函數聲明或語句上方使用。


以上內容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號