Go-Ethereum

計算自毀合約後可以節省多少空間

  • April 18, 2018

我想做一些簡短的分析來量化一個人在自毀契約時可以釋放多少。我如何計算節點在自毀給定合約時可以節省多少空間?

我理解“區塊鏈上沒有任何東西被破壞”,但我也理解如果該合約現在自毀,則無需在本地儲存該合約的狀態。沒有人可以繼續呼叫這個合約,並且在自毀後,未來的狀態樹將永遠不受這個合約的影響,因為合約的狀態不能改變(除了發送給它的 ETH)也不能被呼叫。此外,SELFDESTRUCT 升級碼(即負氣體)中內置了一個激勵機制,如果節點從合約被銷毀中得不到任何收益,這實際上是沒有意義的。為什麼要為沒有好處的東西創造激勵?釋放契約必須有潛在的好處。

這是在客戶端級別處理的嗎?如果是這樣,我假設不同的客戶可能會以不同的方式處理自毀契約。無論哪種情況,我該如何計算?

範例: 查看KyberNetwork 眾籌合約,很明顯該合約將永遠不會被再次使用,大多數代幣銷售合約的情況類似。通過不儲存該合約的狀態,節點可以釋放多少空間?

https://ethereum.stackexchange.com/a/40280/7457的啟發,我找到了一種相對簡單的方法來做到這一點。

在你的全節點同步之後,你需要在你感興趣的合約地址查詢狀態樹,使用類似的東西

//Create database, where dbPath is the path to your data
var db = levelup(leveldown(dbPath));

// Can be obtained with web3.eth.getBlock(<blockNumber>).stateRoot
var ROOT = '0x5e27b33d4fa2349b744f7c80c60f5bcdfa9c0754b7f2be61972b220bf2ec4d78'; // 2092500

//Create trie object
var trie = new Trie(db, ROOT);

// ... 

//Query the contract at 
trie.get('0x' + addressHash, function (err, val) { ... })

然後您需要解碼獲得的值(因為rlp編碼),這樣

var decodedVal = rlp.decode(val); 

這將返回 4 個值,其中第三個值是該特定合約的 storageRoot。

指定新的根,我們創建一個 readStream 來遍歷狀態 trie 的這一部分中的所有節點;

// 3rd element in the array is storage root, 1st - nonce, 2nd - balance, var storageRoot = decodedVal[2];

//Set trie root to storageRoot
trie.root = storageRoot;

//Create stream for nodes in trie
var stream = trie.createReadStream();

然後您可以讀取合約儲存樹中的每個子節點,計算它們佔用的字節數並將所有這些值相加;

// Will count the byte size of the contract's storage
var contractStorageSize = 0;

stream.on('data', function (data) {
 // Obtain Buffer value for current storage node
 var decodedValNode = rlp.decode(data.value);

 // Update contract Storage size
 contractStorageSize += decodedValNode.byteLength;
});

可以在此處找到完整的腳本。

根據這個答案,您可以使用assembly { size := extcodesize(addr) }來了解地址處程式碼的確切大小。對此的解釋是here

因此,您可以在進行自毀之前呼叫它並將其作為事件發出或將其儲存在某處的值中。

引用自:https://ethereum.stackexchange.com/questions/43478