4

I want to do some brief analysis to quantify how much one could free when self-destructing a contract. How could I calculate how much space can nodes save when selfdestructing a given contract?

I understand that "nothing on the blockchain is destroyed", but I also understand that there is no need to locally store the state of a contract if this contract is now self-destructed. No-one can call this contract onward and the future state trie will forever be unaffected by this contract after the self-destruction, since the state of the contract can't change (apart from ETH sent to it) nor be called. In addition, there is an incentive built in the SELFDESTRUCT upcode (i.e. negative gas) that doesn't really make sense if nodes gain nothing from having contracts destroyed. Why create an incentive for something that would have no benifits? There must be a potential benefit from freeing contracts.

Is this dealt at the client level? If so, I assume different clients might deal with self-destructed contracts differently. In either case, how can I calculate this?

Examples: Looking at the KyberNetwork crowdsale contract, it's clear that this contract will never be used again, a similar situation in most token sale contract. How much space could nodes free by not storing the state of this contract?

2 Answers 2

0

According to this answer, you can use assembly { size := extcodesize(addr) } to know the exact size of the code at an address. The explanation for that is here.

So you can call that before doing a self destruct and emit that as an event or store it in a value somewhere.

1
  • 1
    Doesn't this only return the code data and not the state size this contract occupies? I.e. 2 contracts could have the same byte code, but could have very different state, where one could have 1m entries and the other one 0. I would imagine the number of entries also influences the space each contract takes on a node.
    – PhABC
    Mar 21, 2018 at 20:30
0

Inspired by https://ethereum.stackexchange.com/a/40280/7457, I found a relatively easy way to do this.

After having your full node synced, you need to query the state trie at the contract address you are interested, using something like

//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) { ... })

You then need to decode the value obtained (since rlp encoded), such that

var decodedVal = rlp.decode(val); 

This returns 4 values, where the 3rd value is the storageRoot for this specific contract.

Specifying the new root, we create a readStream to go over all the nodes within this part of the state 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();

Then you can just read each child node in the contract's storage trie, calculate how many bytes they take and sum all these values ;

// 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;
});

A complete script can be found here.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.