之前我們說過NEO智慧合約的除錯問題,過去了一段時間,有很多東西都發生了比較大的變化。讓我們重新再來探討一下這個話題。
先說日期,2018年4月27日,馬上迎來勞動節。
以後可能還會再次談論這個話題。
然後明確幾個問題,把一些經常糾結的地方先說清楚
- 如果你連neo同步區塊還沒搞明白,先不要湊智慧合約開發這個熱鬧。
- 我們只討論C#開發智慧合約的除錯問題,其它的暫無工具開發計劃。
- NEO官方沒有智慧合約除錯工具,所以我們的工具是有很多定製的成分。
為什麼要除錯
一次編碼,按下f5,一切正常,揮一揮衣袖就瀟灑的離開,那是傳說。
當程式碼執行不符合預期時,我們需要深入分析問題,需要更精細的觀測手段。
而NEO官方並沒有提供這樣的工具,於是我們開發了一攬子工具用於解決除錯問題
他們是:
- NeonDebug 替換的c#智慧合約編譯器
- NeoGUI-NEL 定製版NeoGUI 或者 NeoCli-NEl 定製版的NeoCli
- NeonDebugGUI,智慧合約執行情況觀測工具
為了3的正常執行,1 2 都是必須的,如果你想知道為什麼,原始碼可以告訴你答案
https://github.com/NewEconoLab/neondebug
https://github.com/NewEconoLab/neo-gui-nel
合約的編譯
你可曾聽過NeoVM,AVM檔案,就是智慧合約編譯生成的那東西,就是NeoVM的位元組碼,叫AVM是因為以前叫小蟻,ant的A,這個副檔名沒一起改。
為了方便不那麼瞭解虛擬機器的開發者理解,我和C#的類庫機制做一個對比。
這個AVM相當於是DLL,要除錯一個c# DLL,你需要DLL PDB cs原始碼三部分內容。DLL儲存位元組碼,PDB儲存位元組碼地址和原始碼位置的對映,這樣才能在斷點時根據位元組碼執行位置定位到原始碼位置,而cs原始碼,就是為了讓你除錯時對照到程式碼
那麼:
DLL-》AVM
PDB-》?
cs-》cs
標準的c#編譯器neon.exe(如果不知道neon.exe,再好好補一下C#智慧合約編譯的相關資料),只生成了一個AVM和一個ABI檔案,這個ABI是介面說明。
PDB對應的角色是空缺的
所以你需要 NEL 的 Neon.exe ,編譯neondebug倉庫的neondebug專案可以得到這個替換的neon.exe
設定環境變數,保證在任何路徑可以執行neon
注意紅框部分,有Debug字樣
這個替換的編譯器,就專門解決那個缺失的PDB問題,這個編譯器和官方編譯器程式碼隨時同步更新,你直接使用這個替換的編譯器就行,任何更新都會同步,不需要切換回官方編譯器。
重啟VS2017之後,來編譯一個智慧合約試試
注意紅框部分,已經使用了我們的替換版本編譯 有(debug)字樣
下一行告訴你,在c:\neo\smartcontracts輸出了些什麼,讓我們來看看。
首先原來的avm照樣輸出,這些是另外多輸出的
檔名全部替換為了合約hash,avm還是那個avm
Abi.json還是那個abi
Cs是把智慧合約原始碼copy 過來的,只支援一個智慧合約專案有一個程式碼檔案,所以不要分檔案。
Map就是替代PDB的那個了,他記錄位元組碼地址和原始碼地址的對映關係
生成在這個路徑也是有意義的,除錯檢視工具會直接來這個路徑找合約,以前需要用除錯檢視工具再開啟一次合約,現在不用了,直接用同一個路徑。
合約的呼叫
A,用neogui 測試執行合約
用neogui-nel,測試執行一個合約,只有nel定製版支援。
試執行固定產生一個0x00 的log檔案,看這個log就可以除錯了,這個下一節再說,我們這裡之說產生log檔案的辦法。
產生這個log是除錯的唯一辦法。
B 、用NEOCLI 測試執行合約
呼叫NEOCLI -NEL的 rpc invokescript 介面,會在返回值多返回一個fulllog欄位,將其儲存為檔案,就是這個llvmhex檔案,可以用來除錯。
只有nel定製版支援
C、用NEOGUI發交易
用NEL定製版NEOGUI發起交易,只有nel定製版支援
發起交易,
會得到交易id同名的llvm檔案
Id[0]
Id[1]
這種為鑑權合約的log
只有通過neogui nel定製版發起交易 或者 neocli nel定製版的 rpc介面 sendraw發起交易
才會產生鑑權合約的log,才可以除錯鑑權合約,其他只除錯應用合約
D、通過NEOCLI的sendraw RPC 發起交易
只有nel定製版支援
會得到交易id同名的llvm檔案
Id[0]
Id[1]
這種為鑑權合約的log
E、通過其他方式產生的交易
由於交易會同步給每一個節點,定製的neo-gui-nel,和neo-gui-cli
可以得到所有的交易,無論是誰產生的。
但是做智慧合約的除錯的LOG是很耗時的,所以他並不總是開啟的,有一個開關去控制他
這個開關在config.json裡面
NEOGUI-nel的設定為true,表示只生成這個GUI自己發起的交易的LOG
開啟這個同步就會變得非常慢,除錯的時候再用。
NEOGUI-nel不修改這個config 也可以開啟生成任何人發起的交易的開關
這裡按一下讓他顯示為=false,然後之後同步的每一筆交易都會生成除錯LOG了
這個只在記憶體修改,每次開啟neo-gui都要看一眼。
合約的除錯
編譯,啟動NeonDebugGUI
略,他也在NeonDebug倉庫中
使用Load 開啟對應的llvmhex.txt檔案即可除錯
這兩個load,一個是開啟一個對話方塊,一個是輸入txid自己去找,結果都一樣。
功能介紹
開啟除錯LOG以後
圖中紅黃藍部分先注意一下
紅色部分最重要,首先觀察合約執行狀態 halt break 為vm正常停機,程式正常走到結束。
Fault break為vm異常停機,你可以直接反著從最下邊看看到底怎麼了。
紅色部分為整個VM內Dump下來的執行流程,也就是整個智慧合約的過程到底幹了什麼,從紅色部分選擇最上面一項,然後用鍵盤的方向鍵下,往下挪,先完整的看幾個合約,可以建立一些基本的感覺。
黃色部分為智慧合約原始碼,當紅色部分選中條目變化時,如果能找到對應的原始碼,黃色部分就會跳轉高亮。
通常最主要的除錯觀測方法就是選紅色、看黃色。
然後藍色部分收集了所有syscall,因為neoVM的虛擬機器自身是純計算,所有對鏈產生影響或者和鏈互訪的功能都是通過syscall進行的,看一個合約有哪些syscall就能快速瞭解這個合約的行為,當然這需要建立在熟悉的基礎上,只要多看,就能熟悉。
除錯小提示
- 紅色部分最重要
- 選中條目時,執行棧顯示的這條指令執行之後的狀態。
比如
Equal指令是==表示式,他顯示的false只能告訴你是不想等,要看是誰和誰比較,往前倒退一條指令
倒退後觀測計算棧,valuetool 會幫助你顯示這個資料可能是什麼
- 是多條虛擬機器指令對應一條cs原始碼,並且有些是對應不到的。
記住這一點,而不能只盯著原始碼,左邊最重要,左邊要選到關鍵的程式碼。
你要搞清楚那些最關鍵的指令,比如syscall appcall equal
這並不會有多複雜,知道找關鍵指令就會快很多。
- 一定要熟悉syscall
最重要的storage.put 就是一個syscall