以太坊源碼細節(3):StateRoot爲什麼不能取代ReceiptsRoot

背景

在各種區塊鏈項目中(例如以太坊),節點往往需要維護三個 Trie Root
https://github.com/ethereum/go-ethereum:44a3b8c04cf18dc0a796f96d5972beb0e3cbe79b:core/types/block.go,L69-86:
block的header數據結構
stateRoot TransactionsRoot ReceiptsRoot
問題在於ReceiptsRoot的必要性。我們是否能省略ReceiptsRoot,僅檢查stateRoot是否正確來對block的transaction是否執行正確。

Root存儲的內容

  • TransactionsRoot
    TransactionsRoot 存儲的是 block中transactions組成的Trie的Root
    TransactionsRoot的作用最簡單,用於接收者檢查block中transactions的完整性。
  • ReceiptsRoot
    ReceiptsRoot存儲的是交易回執內容
    receipts交易回執
    receipt本身記錄交易是否在block被成功執行。
receipts, logs, usedGas, err := bc.processor.Process(block, statedb, bc.vmConfig)
  • StateRoot
    StateRoot 記錄的是 transaction執行結束之後的世界狀態。
	if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); header.Root != root {
		return fmt.Errorf("invalid merkle root (remote: %x local: %x)", header.Root, root)
	}

但是這個StateRoot 和 ReceiptRoot的作用彷彿就相似了。
都是檢查狀態改變結果是否正確。

ReceiptsRoot與StateRoot 作用的差異

作用上很相似,都是檢查transaction執行結果是否正確。
爲啥要實現兩邊呢,我們是否可以通過比較StateRoot和header中一致,來保障transaction的內容正確和執行順序正確?

仔細看一下Receipts的內容

ReceiptsRoot

在這裏插入圖片描述
我們發現除了result.Failed()來記錄transaction執行是否成功外,還有一個receipt.GasUsed域值得關注。
這個域表示當前transaction執行後,該block一共消耗了多少Gas。
所以明顯receiptsRoot還有transactions執行順序的一致性。

但是順序一致,依舊可以通過stateRoot的一致來檢查。

StateRoot

state
我們看stateRoot的內容,有Account的內容。StateRoot更多是世界環境的Root。所以他更多是表達transaction執行後的世界。

總結

receiptRoot 和 StateRoot的作用都是檢查transaction執行是否正確可靠。
不同點在於receiptRoot只是表示transaction執行成功失敗還有執行順序。
StateRoot的作用是記錄 transaction執行結束之後的世界狀態。

注意,以太坊允許uncle block這種孤塊的存在。
當一個BP節點本身處在一條非主流分叉上時,它所產生的StateRoot與接收者執行後的StateRoot不同
如果單純比較StateRoot不同而盲目的認爲BP節點是evil節點,就有些不公正。
我們可以通過比較receiptsRoot來對transaction的執行正確性達成一致,不必在乎執行的環境是否相同。
這樣以太坊就對uncle block更加友善了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章