帳戶儲存中的 (key,value) 對和相應的修改後的 Merkle patricia 樹
在黃皮書(第 4.1 節,storageRoot)中提到了它
storageRoot: Merkle Patricia 樹根節點的 256 位雜湊,用於編碼帳戶的儲存內容(256 位整數值之間的映射),作為來自 Keccak 256 位雜湊的映射編碼到樹中RLP 編碼的 256 位整數值的 256 位整數鍵。雜湊正式表示為 σ
$$ a $$_s。
從上面我可以理解的是,對於儲存映射的所有鍵值對**(k,v),(Kecak(k), RLP(v))**將用於儲存的修改後的 merkle trie,其中 Keccak(k)將作為值 RLP(v) 的鍵
我的問題是:
1.在賬戶的儲存內容中,這些(k,v)是什麼,即keys和values?
一個例子的解釋會非常有幫助。
2.為什麼使用Keccak(k)作為Merkle patricia樹的key,而不是直接使用k?
提前致謝。
在帳戶的儲存內容中,這些 (k,v) 是什麼,即鍵和值?
合約程式碼可以隨意使用。例如,在這個 Solidity 程式碼中,編譯器將索引 0
var1
和索引 1var2
:pragma solidity 0.4.20; contract Test { uint public var1; address public var2; function test() public { var1 = 5; var2 = address(6); } }
所以呼叫後的 (k,v) 對
test()
:(0,5) (1,6)
您可以在本文中找到更多詳細資訊:https ://medium.com/@hayeah/diving-into-the-ethereum-vm-part-2-storage-layout-bc5349cb11b7
2.為什麼使用Keccak(k)作為Merkle patricia樹的key,而不是直接使用k?
乙太坊 wiki的Design Rationale文件中對此進行了解釋:
使用 sha3(k) 作為“安全樹”中的密鑰(在狀態和帳戶儲存嘗試中使用):這使得通過設置 64 層深度和重複呼叫的最大不利鏈的分歧節點來 DoS 嘗試變得更加困難對它們進行 SLOAD 和 SSTORE。請注意,這使得列舉樹變得更加困難;如果您想在客戶端中具有列舉功能,最簡單的方法是維護一個數據庫映射 sha3(k) -> k。
上一個答案
我不確定,但我的猜測是使用雜湊會導致更平衡的 trie。如果您想像一個 Patricia trie,其中條目按索引順序添加,則 trie 的一側通常會比另一側重。另一方面,當使用散列時,新元素被添加到隨機位置。插入/刪除/查找在平衡的 trie 中提供更一致的性能。
也有可能使用散列會產生更小的樹,因為可能會有更多的葉子和擴展節點,而在基於索引的樹中會有更多的分支節點。
為了展示使用連續索引作為鍵如何導致不平衡的 trie,讓我們假設在 trie 的某個級別有一個分支節點,其中只有第一個和第二個半字節指向其他一些節點:
<hash0> branch [<hash1>, <hash2>, NULL,..<13 NULLs>, value]
如果此分支位於 trie 的第 n 級(可以有 64 個級別,因為鍵是 32 個字節,root 位於第 0 級),那麼它將
2 ^ ((64 - n) * 4 - 8)
插入到 trie 中,直到第 3 個半字節變為非 NULL。例如,如果此分支位於根目錄,您將需要
2 ^ 248
在第三個半字節變為非 NULL 之前插入鍵,這是不可能的(但是,這樣的分支首先不可能位於根級別,因為它需要2 ^ 247
鍵達到這種狀態,但有可能達到更高級別的特里)。一般來說,左側半字節比右側半字節更有可能為非 NULL,這意味著左側的 trie 更重。