深入探討以太坊虛擬機器(EVM)

作者:Gimer Cervera,以太坊智慧合約開發者翻譯:善歐巴,金色財經

介紹

本文深入探討以太坊虛擬機(EVM)和Solidity Assembly,以實現智慧合約優化和安全性。

以太坊虛擬機器(EVM)是以太坊網路的核心元件。 EVM 是一款軟體,允許部署和執行以高階語言(例如Solidity)編寫的智慧合約。編寫合約後,將其編譯為字節碼並部署到EVM。 EVM 運行在以太坊網路的每個節點上。

Solidity Assembly 是一種低階程式語言,可讓開發人員在更接近EVM 本身的層級編寫程式碼。它提供了對智慧合約執行的更精細的控制,允許僅透過更高層級的Solidity 程式碼無法實現的最佳化和自訂。

Solidity 中用於內嵌彙編的語言稱為Yul。該程式語言充當編譯為EVM 字節碼的中介。它被設計為一種低階語言,使開發人員能夠更細緻地控制智慧合約的執行。它可以在獨立模式下使用,也可以在Solidity 中進行內聯彙編。 Yul 被設計為一種基於低階堆疊的語言,使開發人員能夠編寫更優化、更有效率的程式碼。在解釋Solidity 組裝之前,我們需要了解EVM 的組件如何運作。

EVM 是一台準圖靈完備的狀態機。在這種情況下,術語「準」意味著流程的執行僅限於有限數量的計算步驟,具體取決於任何給定智慧合約執行可用的Gas 量。這就是以太坊處理停止問題和執行可能(惡意或意外)永遠運行的情況的方式。這樣就避免了以太坊平台全面癱瘓的情況。

Gas是衡量在以太坊中完成交易所需的計算量的概念。交易成本以以太幣支付,並與Gas 和Gas 價格相關。我們在過程中的目標是學習如何在不影響安全性的情況下最大限度地減少消耗的Gas總量。

程式碼最佳化問題

內嵌彙編是一種在較低層級存取EVM 的方法。它繞過了Solidity 的幾個重要的安全功能和檢查。正確使用內聯彙編可以顯著降低執行成本。但是,您應該僅將其用於需要它的任務,並且僅當您知道自己在做什麼時。使用內聯彙編優化程式碼可能會為您的程式碼帶來新的安全問題。要掌握內聯彙編,我們需要了解EVM 及其元件的工作原理。

在EVM中,每次第一次訪問任何儲存變數時都必須付費,這稱為「冷」訪問,需要花費2100個gas。第二次或連續一次稱為「熱」訪問,需要花費100 Gas。

以下程式碼是我們如何使用Yul 優化程式碼的範例。函數SetData1以傳統方式使用Solidity為全域變數值設定新值。我們第一次分配這個新值時需要花費22514 個gas。第二個花費則少得多,即5414 Gas。

函數setData2實作內聯彙編。內嵌彙編區塊以assembly { … } 標記,其中大括號內的程式碼是Yul 語言的程式碼。此時無需了解原始程式碼,只需記住該軟體正在較低層級存取儲存空間即可。因此,執行成本會更低。

在我們的範例中,第一次修改該值將花費22484 個Gas。連續幾次,成本為5384 Gas。差異可能看起來並不顯著,但是我們應該考慮到這段程式碼可能會執行數千次。

ZlEcJa5qttwq275Wh8CSJLzQvYgFSEUD9OuI4tp3.png

為什麼儲存這麼貴?請記住,我們處於一個去中心化的世界,資料不僅僅儲存在一個地方,而是儲存在數以萬計的節點上。如果未來的交易需要存取或更改它,它還必須可供網路中的每個節點輕鬆使用。此資料的總體成本等於其消耗的儲存空間和在整個網路上產生該資料的計算量的總和。

EVM 堆疊、儲存和記憶體

EVM 是一種基於堆疊的機器,它在稱為堆疊的資料結構上運行,該結構保存值並執行操作。 EVM 有自己的一組指令(稱為操作碼),用於執行讀取和寫入儲存、呼叫其他合約以及執行數學運算等任務。堆疊依照後進先出(LIFO)方式運行,請參見圖1,這表示最近插入的項目儲存在堆疊的頂部,並且是第一個要刪除的項目。

ErTKbn1SRoeL6bCljlu7WoUgpf9Cw4tKmpq5xTLT.png

當執行智能合約時,EVM 會建立一個包含各種資料結構和狀態變數的執行上下文。執行完成後,執行上下文將被丟棄,為下一個合約做好準備。在執行期間,EVM 會維護一個臨時內存,該內存在事務之間不會持續存在。 EVM 執行深度為1024 項的堆疊機。每個項目都是一個256 位元字,選擇此大小是為了方便使用256 位元雜湊和橢圓曲線加密。

EVM 具有以下元件,請參閱圖2:

  • 堆疊:EVM 的堆疊是一種以後輸入先輸出(LIFO) 方式運作的資料結構,用於在智慧合約執行期間儲存臨時值。

  • 儲存:永久存儲,是以太坊狀態的一部分,僅在第一次初始化為零。

  • 記憶體:易失性、動態大小的位元組數組,用於儲存合約執行期間的中間資料。每次建立新的執行上下文時,記憶體都會初始化為零。

  • Calldata:這也是一個揮發性資料儲存區域,類似記憶體。然而它儲存不可變的資料。它旨在保存作為智能合約交易的一部分發送的資料。

  • 程式計數器:程式計數器(PC) 指向EVM 要執行的下一指令。 PC通常在一指令執行後增加一個位元組。

  • 虛擬ROM:智能合約作為字節碼儲存在該區域。虛擬ROM 是唯讀的。

byS0PEfxE9E3EAlqlseO5P36kgSUAJ4RXlEpWJxG.png

EVM 堆疊

在這個架構中,程式的指令和資料保存在記憶體中,程式的執行由指向堆疊頂部的堆疊指標控制。堆疊指標追蹤下一個值或指令將在堆疊上保存或檢索的位置。當程式運行時,它將值添加到堆疊中並對已經存在的值執行操作。當程式碼想要將兩個數字相加時,它將數字壓入堆疊,然後對頂部的兩個值執行加法操作。然後結果返回到堆疊。

SLyBgI6MX0FvAU6B3i9jQkAvd9V1ACc7FR1Mlkp3.png

基於堆疊的架構最重要的特徵之一是它允許高度簡單且有效率的操作執行。由於堆疊是一種LIFO 資料結構,因此可以輕鬆快速地處理資料和指令。

EVM 有自己的一組指令,稱為操作碼。操作碼用於執行讀取和寫入儲存、呼叫其他合約以及執行數學運算等任務。 EVM 指令集提供您可能期望的大部分操作,包括:

  • 堆疊操作:POP、PUSH、DUP、SWAP

  • 算術/比較/位元:ADD、SUB、GT、LT、AND、OR

  • 環境:CALLER、CALLVALUE、NUMBER

  • 記憶體操作:MLOAD、MSTORE、MSTORE8、MSIZE

  • 儲存操作:SLOAD、SSTORE

  • 程式計數器相關操作碼:JUMP、JUMPI、PC、JUMPDEST

  • 停止操作碼:STOP、RETURN、REVERT、INVALID、SELFDESTRUCT

EVM儲存

EVM 儲存是非揮發性空間,保存256 位元–> 256 位元的鍵值對。合約中的儲存槽位總數為2²⁵⁶,這是一個非常龐大的插槽數量。區塊鏈上的每個智能合約都有自己的儲存空間。

在函數呼叫期間,儲存用於在函數呼叫之間需要記住的資料。它用於儲存即使在智慧合約執行結束後也需要可用的變數和資料結構。

1HMGlMM7NtpaHHsnMiAq1AEaILWPXt4dG3VwqyKy.png

存取儲存的操作碼是:SLOAD 和SSTORE

此帳戶的存儲是永久資料存儲,僅由智能合約使用。外部擁有的帳戶(EOA) 將始終沒有代碼且儲存空間為空。

EVM記憶體

內存是架構中的易失性內存,其資料在區塊鏈中不持久。記憶體是一種隨機存取資料結構,在智慧合約執行期間儲存臨時資料。

S3MF42KoITdlBytrmQc3NNV8NNmTkTWz2DqDUO1A.png

記憶體分為四部分:2 個槽用於暫存空間,1 個槽用於空閒記憶體指針,0 槽和1 個槽指向可用的空閒記憶體。前64 個位元組的空間將由雜湊方法使用,雜湊方法在最終返回最終輸出之前需要臨時空間來儲存中間輸出。

空閒記憶體指標只是指向空閒記憶體開始位置的指標。它確保智能合約追蹤哪些記憶體位置已寫入以及哪些仍然可用。這可以防止合約覆蓋已分配給另一個變數的某些記憶體。圖6 顯示了記憶體是如何劃分的:

g3imQHTd89wyatS2hNwKZHK4Ys4SANntyutufP7c.png

記憶體用於儲存不需要保存在記憶體中的變數和資料結構。智慧合約執行期間可以調整記憶體大小,但存取速度比堆疊更慢且成本更高。

考慮記憶體是零初始化的,用於存取記憶體的操作碼是:MLOAD、MSTORE、MSTORE8

概括

在本文中,我們回顧了與以太坊虛擬機器(EVM)相關的一些基本概念。實作內聯彙編程式碼需要深入了解EVM。這是因為我們正在與EVM 的一些元件進行互動。在以後的課程中,我們將更詳細地分析其他EVM 元素,例如:儲存、記憶體和Calldata。此外,我們還將回顧字節碼、Gas 和應用程式二進位介面(ABI) 等重要概念。最後,我們將討論操作碼的工作原理以及更多內聯彙編範例,以安全地優化智慧合約的執行。

Total
0
Shares
Related Posts