Skip to content

Latest commit

 

History

History
123 lines (82 loc) · 10.7 KB

16.asciidoc

File metadata and controls

123 lines (82 loc) · 10.7 KB

Vyper: 面向合約的程式語言

研究表明,具有跟蹤漏洞的智能合約可能導致意外執行。https://arxiv.org/pdf/1802.06038.pdf[最近的一項研究] 分析了970,898份合約。它概述了跟蹤漏洞的三個基本類別(已經導致以太坊用戶的災難性資金損失)。這些類別包括
  • 自殺合約。可以被任意地址殺死的合約

  • 貪婪的合約,在某個執行狀態後無法釋放ether

  • 浪費合約,不經意地將ether釋放到任意地址

Vyper是一種面向合約的實驗性程式語言,面向以太坊虛擬機(EVM)。Vyper致力於通過簡化程式碼並使其對人類可讀而提供卓越的審計能力。Vyper的一個原則是讓開發人員幾乎不可能編寫誤導性程式碼。這可以通過多種方式完成,我們將在下面介紹。

與 Solidity 比較

本節是那些正在考慮使用Vyper程式語言開發智能合約的人的參考。該部分主要對比了Vyper與Solidity的對比; 概覽,合理的推理,為什麼Vyper不包括以下傳統的物件導向編程(OOP)概念:

Modifiers

在Solidity中,你可以使用修飾器編寫函數。例如,以下函數`changeOwner`將在一個名為`onlyBy`的修飾器中運行程式碼,作為其執行的一部分。

function changeOwner(address _newOwner)
    public
    onlyBy(owner)
{
    owner = _newOwner;
}

正如我們在下面看到的,名為`onlyBy`的修飾器強制執行與所有權相關的規則。雖然修飾器很強大(能夠改變函數體中發生的事情),但它們也可能導致誤導性的程式碼執行。例如,確保`changeOwner`函數邏輯的唯一方法是每次實現程式碼時檢查並測試`onlyBy`修飾器。顯然,如果將來更改修改器,則調用它的函數可能會產生與最初預期不同的結果。

modifier onlyBy(address _account)
{
    require(msg.sender == _account);
    _;
}

總的來說,修飾器的通常用例是在函數執行之前執行單個檢查。鑑於這種情況,Vyper的建議是完全取消修飾器,並簡單地使用內聯檢查和斷言作為函數的一部分。這樣做將提高審計能力和可讀性,因為Vyper函數將在明顯的視線中遵循邏輯內聯序列,而不必引用已在別處編寫的修飾器程式碼。

類繼承

繼承允許開發者通過從現有軟體庫中獲取預先存在的功能,屬性和行為來利用預先編寫的程式碼。繼承功能強大,可以促進程式碼的重用。Solidity支持多重繼承以及多態,雖然這些被認為是物件導向編程的一些最重要的特性,但Vyper並不支持它們。Vyper堅持認為繼承的實現要求編碼人員和審計人員在多個檔案之間跳轉,以便了解程式正在做什麼。Vyper還了解優先級規則以及多個繼承如何使程式碼過於複雜而無法理解。鑑於Solidity 關於繼承的文件給出了多重繼承為何有問題的例子,這是一個公平的陳述。

內聯彙編

內聯彙編為開發人員提供了以低級別訪問以太坊虛擬機(EVM)的機會。使用內聯彙編程式碼(在更高級別的源程式碼中)時,開發人員可以通過直接訪問EVM操作碼指令來執行操作。例如,以下內聯彙編程式碼通過使用EVM操作碼mload在記憶體位置0x80處添加3。

3 0x80 mload add 0x80 mstore

如前所述,Vyper致力於為開發人員和程式碼審計人員提供最易讀的程式碼。雖然內聯彙編可以提供強大的細粒度控制,但Vyper程式語言不支持它。

函數重載

具有相同名稱和不同參數選項的多個函數定義會導致在任何給定時間調用哪個函數時會產生很多混淆。隨著函數重載,編寫誤導程式碼會更容易( foo(“hello”)記錄“hello”但foo(“hello”,“world”)竊取你的資金。)函數重載的另一個問題是它使程式碼更難以搜索,因為你必須跟蹤哪個調用指的是哪個功能。

變數類型轉換

類型轉換是一種允許開發者將變數從一種數據類型轉換為另一種數據類型的機制。

前置條件和後置條件

Vyper明確處理前置條件,後置條件和狀態更改。雖然這會產生冗餘程式碼,但它也允許最大的可讀性和安全性。在Vyper中編寫智能合約時,開發人員應遵守以下3點。理想情況下,應仔細考慮3個點中的每個點,然後在程式碼中進行詳細記錄。這樣做將改進程式碼的設計,最終使程式碼更具可讀性和可審計性。

  • 條件 - 以太坊狀態變數的當前狀態/條件是什麼

  • 效果 - 這個智能合約程式碼對執行狀態變數的條件有什麼影響,即什麼會影響,什麼不會受到影響?這些影響是否與智能合約的意圖一致?

  • 交互 - 現在已經詳盡地處理了前兩個步驟,現在是運行程式碼的時候了。在部署之前,邏輯上逐步執行程式碼並考慮執行程式碼的所有可能的永久結果,後果和方案,包括與其他合約的交互。

一種新的編程範式

Vyper的創作為新的編程範式打開了大門。例如,Vyper正在刪除類繼承以及其他功能,因此可以說Vyper偏離了傳統的物件導向編程(OOP)範例,這很好。

歷史上,OOP提供了一種表示現實世界物件的機制。例如,OOP允許實例化可以從person類繼承的employee物件。然而,從價值轉移和/或智能合約的角度來看,那些渴望功能性編程範式的人會同意,交易性編程絕不適合上述傳統的OOP範式。簡而言之,交易計算是與現實世界物件分開的世界。例如,你最後一次持有交易或正向鏈接業務規則的時間是什麼時候?

似乎Vyper沒有與OOP範例或函數式編程範例完全一致(完整的原因列表超出了本章的範圍)。出於這個原因,在開發的早期階段,我們能夠如此大膽地推出新的軟體開發範例嗎?一個致力於未來證明區塊鏈可執行程式碼的人。一個可以防止在不可改變的環境中造成災難性資金損失的人。區塊鏈革命中經歷的過去事件有機地為這一領域的進一步研究和發展創造了新的機會。也許這種研究和開發的結果最終可能導致軟體開發的新的不變性範式分類。

裝飾符

@private @public @constant @payable 這樣的裝飾符在每個函數的開頭宣告。

Private

@private 使合約外部的函數無法訪問此函數。

Public

@public 使該函數公開可見和可執行。例如,即使是以太坊錢包也會在查看合約時顯示公共函數。

Constant

@constant 開始的函數不允許狀態變數的改變,實際上,如果函數嘗試更改狀態變數,編譯器將拒絕整個程式(帶有適當的警告)。如果該函數用於更改狀態變數,則不要在函數的開頭使用`@ constant`。

Payable

只有以 @payable 開頭宣告的函數才能接收價值。

Vyper明確地實現了裝飾符的邏輯。例如,如果一個函數前面有一個`@appay`裝飾符和一個`@ constant`裝飾符,那麼Vyper程式碼編譯過程就會失敗。當然,這是有道理的,因為常量函數(僅從全局狀態讀取的函數)永遠不需要參與值的轉移。此外,每個Vyper函數必須以`@ public`或`@private`裝飾符開頭,以避免編譯失敗。同時使用`@public`裝飾符和`@private`裝飾符的Vyper函數也會導致編譯失敗。

在線程式碼編輯器和編譯器

Vyper在以下URL <https://vyper.online> 上有自己的在線程式碼編輯器和編譯器。這個Vyper在線編譯器允許你僅使用Web瀏覽器編寫智能合約,然後將其編譯為 Bytecode ,ABI和LLL。Vyper在線編譯器具有各種預先編寫的智能合約,以方便你使用。這些包括簡單的公開拍賣,安全的遠程購買,ERC20 token等。

使用命令行編譯

每個Vyper合約都保存在擴展名為.v.py的單個檔案中。 安裝完成後,Vyper可以通過運行以下命令來編譯和提供 Bytecode

vyper ~/hello_world.v.py

通過運行以下命令可以獲得人類可讀的ABI程式碼(JSON格式)

vyper -f json ~/hello_world.v.py

讀寫數據

智能合約可以將數據寫入兩個地方,即以太坊的全球狀態查找樹或以太坊的鏈數據。雖然儲存,讀取和修改數據的成本很高,但這些儲存操作是大多數智能合約的必要組成部分。

全局狀態

給定智能合約中的狀態變數儲存在以太坊的全局狀態查找樹中,給定的智能合約只能儲存,讀取和修改與該合約地址相關的數據(即智能合約無法讀取或寫入其他智能合約)。

Log

如前所述,智能合約也可以通過日誌事件寫入以太坊的鏈數據。雖然Vyper最初使用 __log__ 語法來宣告這些事件,但已經進行了更新,使Vyper的事件宣告更符合Solidity的原始語法。例如,Vyper宣告的一個名為MyLog的事件最初是 MyLog: __log__({arg1: indexed(bytes[3])}),Vyper的語法現在變為 MyLog: event({arg1: indexed(bytes[3])})。需要注意的是,在Vyper中執行日誌事件仍然是如下 log.MyLog("123")

雖然智能合約可以寫入以太坊的鏈數據(通過日誌事件),但智能合約無法讀取他們創建的鏈上日誌事件。儘管如此,通過日誌事件寫入以太坊的鏈數據的一個好處是,可以在公共鏈上由輕客戶端發現和讀取日誌。例如,挖到的塊中的logsBloom值可以指示是否存在日誌事件。一旦建立,就可以通過日誌路徑獲取 logs → data inside a given transaction receipt。

ERC20令牌接口實現

Vyper已將ERC20實施為預編譯合約,並允許預設使用它。 Vyper中的合約必須宣告為全域變數。宣告ERC20變數的範例可以是

token: address(ERC20)

操作碼(OPCODES)

智能合約的程式碼主要使用Solidity或Vyper等高階語言編寫。編譯器負責獲取高級程式碼並創建它的低級解釋,然後可以在以太坊虛擬機(EVM)上執行。編譯器可以提取程式碼的最低表示(在EVM執行之前)是操作碼。在這種情況下,需要高階語言(如Vyper)的每個實現來提供適當的編譯機制(編譯器)以允許(除其他之外)將高級程式碼編譯到通用預定義的EVM操作碼中。一個很好的例子是Vyper實現了以太坊的分片操作碼。