EVM Transaction Viewer 比較

NIC Lin
Taipei Ethereum Meetup
14 min readNov 1, 2022

這篇文章會比較常用的三個 EVM Transaction Viewer 的優缺點

Photo by José Ramon Martinez on Unsplash

最近 Samczsun 推出了自己寫的 Transaction Viewerhttps://tx.eth.samczsun.com/。因此我順便將它和其他常用的 Transaction Viewer 例如 Ethtx.infoTenderly 做一個比較。

目前以 Tenderly 支援的鏈最多,tx.eth.samczsun.com 次之,Ethtx.info 只有支援 Mainnet 及 Goerli。不過 Ethtx.info 有開源,可以自己拿來跑自己想要支援的其他 EVM 鏈。

Tl;dr

  • tx.eth.samczsun.com 的風格和 Ethtx.info 很像,都是走簡潔 UI 路線,但細節比 Ethtx.info 還多,除了包含一筆交易發生了什麼事、哪些地址被牽連,或細到每個 function call 實際修改了哪些 storage 都有。如果你想瞭解一筆複雜套利交易的影響或一個攻擊事件的攻擊細節,它會是一個很理想的工具。
  • Tenderly 提供了很豐富的介面和操作,還可以一步一步深入每個 function call 的呼叫及執行,另外還有模擬器,非常適合你想要透過一筆交易來更深入理解 EVM 的執行、並透過模擬器實驗自己的理解及想法。

我們會以 Samczsun 當時提供的這筆套利交易為範例,展示這筆交易在三種不同 Transaction Viewer 所呈現的資訊並比較。

Ethtx.info

範例交易

Ethtx.info 有如 Etherscan 上所呈現的一筆交易最基本的資訊,也有額外的資訊,包含這筆交易所影響的地址的代幣餘額變化(不只是 ETH,一般 ERC20 也會有),以及一開始 Ethtx.info 被廣泛使用的原因:呈現交易執行過程的 Execution Trace。

註:Etherscan 也可以看交易的 Execution Trace,但是是原始沒有處理過的

Etherscan 可以看原始的 Geth/Parity Execution Trace,但很難看

地址的代幣餘額變化

注意這個餘額變化是按照 Transfer event 所計算,所以如果遇到代幣是 Spoof Token 的話,背後並不代表真的有代幣轉帳

Ethtx.info 交易的代幣餘額變化

Label 地址

如果合約有在 Etherscan 驗證的話,Ethtx.info 會將地址 label 成合約名稱來顯示,例如上圖裡的 [receiver] SoloMargin。點擊這些地址或合約都會直接連到它們的 Etherscan 頁面。

註:交易的 From 和 To 地址會在前面額外加上 [sender][receiver]

Execution Trace

Ethtx.info 交易的 Execution Trace

每一條列都是一個 function call。這個樹狀結構的第二列([1667813]: [receiver] SoloMargin.operate(…))是 Top Level Call,然後依序執行 sub function call。

  • 每一個條列最左邊是這個 function call 消耗的 gas,例如第一列的 1419243 。註:第二列的 gas 消耗比第一列高是因為第一列是交易執行完後的 gas 消耗,其中包含 gas refund。
  • 如果有橘色框框標起來代表是 delegate call。有些會在後面用橘色顯示 delegate call 到的合約,例如第三列看到的 OperationImpl。但像是後面 USDC 的 delegate call 就沒有顯示它 delegate call 到的合約
  • 最後面的括號是這個 function call 的回傳值,例如第四列的 (value=1000...000)

tx.eth.samczsun.com

範例交易

交易基本資訊

首先 tx.eth.samczsun.com 比 Ethtx.info 多了一些交易的基本資訊,例如 Nonce、Tx Index、Tx Type 及 Gas fee 等等資訊。另外交易的手續費及後面看到的代幣餘額變化,它都會把它轉換成當時的美金價值。

註:這些資訊 Etherscan 上也都會顯示,包含將代幣金額轉換成當時美金價值等等

將 Etherscan 上的交易資訊也顯示出來

手動 Label 地址

tx.eth.samczsun.com 讓你可以自己 label 某個地址:

滑鼠移到地址上方會顯示 Edit Label,已經 Label 過的也可以再次 Edit
輸入你為這個地址取的名稱
接下來這個地址全都會換成這個名稱

地址的代幣餘額變化

它會統整一個地址的總美金價值餘額變化,點擊箭頭可以看到實際的代幣餘額變化及相對應的美金價值變化。

不同地址的總美金價值餘額變化
一個地址實際的代幣餘額變化及相對的美金價值變化

Decoded Actions

這個是它所解析這筆交易執行了什麼操作的列表,但不太清楚它解析的參考來源及能夠解析哪些操作。

Execution Trace/Call Trace

大致上和 Ethtx.info 很像,但其實很多細節資訊都是點擊後可以展開的

註:它的第一列就是 Top Level Call,它省去「function call 是從交易的 From 開始的」這個資訊。

和 Ethtx.info 差不多的顯示介面

另外可以看到它在每個 function call 的 gas 消耗的左邊再插入顯示 call type,例如 delegatecallstaticcall 等。而且它還有 log type,表示一個 event emission,這可以讓你知道哪個 function emit 了什麼 event,而不像 Ethtx.info 或 Tenderly只能一次看整筆交易所 emit 的全部 event。

點擊最左邊的框框可以看到這個 function call 更豐富的統整資訊。log type 也可以。

點擊最左邊的框框可以顯示 function call 更豐富的統整資訊
function call 的細節,包含 function signature、(Decoded) input/output
log type 也可以顯示,也就是 event 的 data

再來是點擊眼睛圖示可以顯示這個 function call 所讀取、改動的 storage。

點擊眼睛圖示展開 storage 存取細節,sload 是讀取、sstore 是寫入

點擊 sload/sstore 都可以看到 storage 更多資訊,例如 storage slot。它也會嘗試搭配合約原始碼來解析這個 storage slot 對應到合約的哪個變數。

storage 細節。Decoded 部分是嘗試搭配合約原始碼解析是存取哪個變數

Hash Preimage

如果一個 hash 值的 preimage(即 hash 的 input)出現過的話,它會將 preimage 呈現出來,以這筆交易為例:

將 0x8cc9…dcfa 解析成 keccak(0x009311…0000)

原本 execution trace 裡只有 .push(_object=0x8cc9…dcfa, …),但因為前面步驟執行過 0x8cc9…dcfa = keccak(0x009311…0000),所以當它看到 0x8cc9…dcfa 時就可以自動將 0x8cc9…dcfa 解析成 keccak(0x009311…0000) 的形式。

以上就是 tx.eth.samczsun.com 的介紹,可以看得出來它介面和 Ethtx.info 一樣都是簡單直接的呈現方式,但它的資訊比 Ethtx.info 豐富很多。基本上可以用來取代 Ethtx.info,唯一的缺點可能是還未開源,如果突然停止服務只能先用其他選項。

Tenderly

範例交易

Tenderly 的介面豐富很多,Overview 的介面就包含了交易基本資訊(但代幣不會轉換成美金價值顯示)及 Execution Trace。Overview 的 Execution Trace 只有顯示 function 名稱,但可以點擊右邊的 View in Debugger 直接跳轉到 Debugger 去進行 debug(debug 待會會介紹),Tenderly 這個 Execution Trace 的設計可以讓你快速定位到某個 function call 裡去 debug。

註:如果合約有在 Etherscan 驗證的話,點擊 function call 會顯示 function 的 snippet,但個人覺得幫助不大。

Overview 的 Execution Trace 可以直接跳轉到指定的 function call 去 debug
Tenderly 有不同標籤頁來呈現交易的不同資訊

Events

Tenderly 的 events 和 Ethtx.info 一樣,都只有顯示整筆交易所有 emit 的 event。

State Changes

Tenderly 有提供 storage 變化資訊,但不像 tx.eth.samczsun.com 一樣以每個 function call 為單位來顯示,而且只有在交易結束後 storage 值有變化才會顯示。這表示你看到的是整筆交易執行完的 storage 變化,而不會包含交易曾經讀取了什麼 storage 或是如果 storage 最後被改回原本的值也不會顯示。想要了解一筆交易實際存取了哪些 storage 透過 tx.eth.samczsun.com 會比較好。

Debugger

Debugger 則是 Tenderly 強大的功能之一,清楚易讀的頁面分成四格呈現: Execution Trace(左上搭配左下)、當前的合約代碼位置(右上,如果合約有驗證才會顯示)及每個 function call 的細節(右下)。

你可以透過上圖中間藍色的 PreviousNext 按鈕前後來回在不同 function call 之間切換,搭配右上方的合約代碼位置來了解哪個 function call 帶了什麼 input 進來、會執行什麼運算或帶了什麼 input 到下一個 function call。

此外你還可以使用紫色的 Evaluate 按鈕來存取 function 執行當下的變數值,甚至可以直接寫 Solidity 代碼來操作這些變數或進行任何你想要的運算。

註:Evaluate 需要註冊才能使用。

以 1inch 合約的 swap function 為例,用 Evaluate 存取執行到 swap function 裡的 dstToken 變數的值
得到 dstToken 變數當下的值
可以直接套用 Solidity 語法上去計算!不一定要存取變數,把它當 interactive console 也可以

最後一個很有幫助的功能則是重新模擬交易,當你研究一筆交易到某個程度,想驗證一些假設例如交易帶的 calldata 有某個值不一樣、或嘗試同樣一筆交易換到不同時空背景(例如在另一個區塊時的狀態)去執行的結果,你可以直接用 Re-simulate 來模擬。

點擊右上角的 Re-simulate 來重新模擬交易

它會帶上原本交易的資訊,但每個資訊你都可以任意修改,從交易的 From、Input Data 到區塊、時間戳、Gas 及 Gas Price 等等。

你可以任意修改交易資訊然後模擬看看

你也可以任意指定合約狀態,例如修改指定合約某個 storage 的值。這邊以修改 USDC 合約的 paused 變數為例,我們將 storage slot 0x0000000000000000000000000000000000000000000000000000000000000001的 value 設為 0x000000000000000000000001f0d160dec1749afaf5a831668093b1431f7c8527。(原本的 value 是 0x000000000000000000000000f0d160dec1749afaf5a831668093b1431f7c8527

因為 USDC 合約裡將 pauserpaused 兩個變數 pack 在同一個 slot,所以才會看到 value 後面有個 pauser 地址 0xf0d160dec1749afaf5a831668093b1431f7c8527。將地址前面 1 byte 設為 true(01)後就等於將 paused 變數設為 true。

pause USDC 合約

然後執行 Simulate Transaction

執行結果為 USDC paused 所以交易失敗

或是將 1inch Aggregator 設為 USDC 黑名單(將 storage slot 0x91ae7637a1c6d8961153fa2495a272f99bc363035a969c0cc200d32f1d26bd97 的 value 設為 0x0000000000000000000000000000000000000000000000000000000000000001

將 1inch Aggregator 設為 USDC 黑名單
執行結果為 1inch 被黑名單所以交易失敗

註:要怎麼拿到交易裡這些參數確切的 storage slot 和 value?提示:前面提到過的某個 Viewer 可以查看

以上是 Ethtx.info、tx.eth.samczsun.com 及 Tenderly 這三個 Transaction Viewer 的比較。你不一定要挑一個來固定用,而是按照你當下需求來使用。

tx.eth.samczsun.com 簡潔快速,Tenderly 可深入模擬但運行速度較慢。如果只是需要快速看一筆交易的概覽的話,用 tx.eth.samczsun.com;如果想深入去實驗、理解某筆交易裡某個合約的某個 function 怎麼執行的話,用 Tenderly。

--

--