智慧合約解構
第一部分·前言
想象一下,你正在駕駛著1969年的Mustang Mach在美國西部的公路上快速行駛,陽光照耀在華麗的鍍金輪輞上,整條道路只有你和沙漠,一望無際的地平線見證著你和落日的追逐... ...
心曠神怡間,突然一身巨響,你335馬力的快馬被滾滾的白煙吞沒,瞬間變成了蒸汽機車,於是你被迫停在路邊。
你打算看看出現了什麼問題,當你翻開前車蓋,發現自己完全看不懂。你根本就不知道這該死的機器是怎麼工作的,於是你拿起手機準備求救,發現附近沒有信號... ...
上面描述的情形是不是和你正在做的DApp開發很像?在開發Dapp的過程中,在類比中,豪車是你的智慧合約,輪輞和改造過的地方是那些經過深思熟慮的小細節。而一旦出現問題,你就需要在智慧合約EVM位元組碼中尋找答案,大部分情況下你都完全不知道發生了什麼。
如果你是Dapp的開發者,並且遇到過上面的尷尬狀況的話,那麼以後再也不用擔心了!
因為,本系列文章的目的就是解構一個簡單的Solidity合約,檢視其位元組碼,並將其分解為可識別的結構,直至最低級別。我們將開啟Solidity這臺跑車的引擎蓋。在本系列的最後,您在檢視或除錯EVM位元組碼時應該感覺很舒服。本系列的重點是揭開Solidity編譯器生成的EVM位元組碼的神祕面紗,它真的比它看起來簡單得多。
以下是我們解構時要使用到的智慧合約程式碼:
注意:此合約容易受到溢位攻擊,我們只是為了說明問題,所以力求簡潔。
編譯合約
為了編譯合約,我們將使用Remix(地址:https://remix.ethereum.org)。
當你開啟Remix編譯器,單擊檔案瀏覽器區域上方左上角的+按鈕,建立新的智慧合約。將檔名設定為BasicToken.sol。建立好之後,將上面的程式碼貼上到編輯器上。
在右側,轉到“ Setting”的選項中,確保選中了“ Enable Personal Mode”。另外,要注意選擇的Solidity編譯器版本是
“ version:0.4.24 +commit.e67f0147.Emscripten.clang ”。
這兩個細節非常重要,否則你將無法檢視文中討論的位元組碼。
接下來,你可以進入Compile選項並單擊Details按鈕,你會看到一個彈出視窗,裡面包含Solidity編譯器生成的所有東西,其中一個是名為BYTECODE的JSON物件,它具有“object”屬性,這個就是編譯的合約程式碼,它的程式碼是這樣的:
沒錯,這些程式碼完全沒有可讀性(至少對於正常人而言)。
部署合約
接下來,轉到Remix中的Run部分。首先,確保您使用的是Javascript VM。這基本上是一個嵌入式Javascript EVM +網路,理想的以太坊訓練場。確保在ComboBox中選擇了BasicToken ,並在Deploy輸入框中輸入數字10000 。接下來,單擊“ Deploy”按鈕進行部署。這部署的是我們建立的BasicToken智慧合約例項,最初提供的10000個token由當前在ComboBox帳戶頂部選擇的帳戶擁有,該帳戶會保留我們設定的所有token供應。
在“ Run”選項卡的“Deployed Contracts”中,您可以看到已部署的智慧合約,其中包含與合約進行互動的三個欄位:transfer,balanceOf和totalSupply。在這裡,我們能夠與剛剛部署的智慧合約例項進行互動。
但在此之前,讓我們來看看合同的“Deploy”(部署)究竟是什麼意思:
在頁面底部的控制檯區域中,你可以看到一條日誌“creation of BasicToken pending ...”,然後是一個包含各種欄位的事務條目:from,to,value,data,logs和hash。單擊此條目以展開交易信息,你應該看到transaction的date、input,以及我們上面提到的位元組碼。所以,建立一個智慧合約例項,其中會包含自己的地址和程式碼。
我們將在下一篇文章中詳細研究這transaction個過程。
反彙編位元組碼
在控制檯中心,transaction框框的右側,有個“ debug”(除錯)按鈕。點選這個按鈕,你將啟用Remix右側區域中的Debugger選項。我們可以一起看看Instructions部分,如果向下滾動,應該是出現以下內容:
...(縮寫)
為了確保你前面的操作沒有出錯,你可以把你所操作的Remix編譯器中看到的內容與上面進行比較。
這其實就是合約的反彙編位元組碼。如果您按位元組掃描原始位元組碼(一次兩個字元),則EVM會識別與特定操作關聯的特定操作碼。例如:
Line"/>
反彙編的程式碼非常低階並且很難看懂,但是我們可以通過這種方式可以開始理解它。
Opcode
在解構智慧合約程式碼開始之前,你將需要一個基本的工具集理解單個opcode,如PUSH,ADD,SWAP,DUP等的操作碼,到最後,每個操作嗎只能從EVM的堆疊,記憶體或屬於合約的儲存中壓入一個項或消費一個項。
要檢視EVM可以處理的所有可用操作碼,可以檢視Pyethereum,上面顯示了操作碼列表。要了解每個操作碼的工作原理,Solidity官方的彙編文件也是一個很好的參考。即使它不是與原始操作碼一一對應,但是非常接近(它實際上是Yul,介於Solidity和EVM位元組碼之間的中間語言)。如果你能讀懂技術文件,可以閱讀以太坊黃皮書,其實歸根結底都是上面的內容。
雖然和大家推薦了這麼多文件,現在從頭到尾閱讀這些資源沒有什麼意義,你只要記住有這麼個資料就行,我們將在需要的時候使用到它們。
指令
上面反彙編程式碼中的每一行都是EVM執行的操作指令,每條指令都包含一個操作碼,例如,讓我們採用其中一條指令,指令88,將數字4推送到堆疊。這個特殊的反彙編程式解釋說明如下:
儘管反彙編的程式碼能讓我們更加理解底層的東西,但它還是讓人摸不著頭腦。我們需要一個能夠解構所有問題的方法。
策略
任何一開始看上去不可能完成的任務,其實都可以通過不斷的拆解,分解成可以解決的任務,我們遇到的問題也不例外,面對這個問題,我所採取的策略就是“分而治之”。
我們可以試圖找到反彙編程式碼的分叉點,並逐漸分解,直到分解成很小的塊,我們將在Remix的偵錯程式中逐步完成。
在下圖中,我們可以看到我們對反彙編程式碼進行的第一次拆分(我將在下一篇文章中對其進行全面分析)。
如果你不瞭解圖表,也不要擔心,你不用一開始就什麼都會,我們的系列文章將會循序漸進的介紹。現在就跟著我們的節奏,不斷深入你的豪車的內部結構吧。
*本文由Alejandro Santander首發於medium,由獵豹區塊鏈安全中心翻譯並整理*
來源:區塊鏈藍海
本文由布洛克專欄作者釋出,不代表布洛克觀點,版權歸作者所有
——TheEnd——
關注“布洛克科技”