Подсчитайте, сколько места можно сэкономить после самоуничтожения контракта

Я хочу провести краткий анализ, чтобы количественно определить, сколько можно освободить при самоуничтожении контракта. Как я могу рассчитать, сколько места могут сэкономить узлы при самоуничтожении данного контракта?

Я понимаю, что «ничего в блокчейне не уничтожается», но я также понимаю, что нет необходимости локально хранить состояние контракта, если этот контракт сейчас самоуничтожается. Никто не может вызвать этот контракт, и после самоуничтожения этот контракт навсегда не повлияет на будущее состояние, поскольку состояние контракта не может ни измениться (кроме отправленного в него ETH), ни быть вызванным. Кроме того, в upcode SELFDESTRUCT встроен стимул (то есть отрицательный газ), который на самом деле не имеет смысла, если узлы ничего не получают от уничтожения контрактов. Зачем создавать стимул для чего-то, что не имело бы никаких преимуществ? Должна быть потенциальная выгода от освобождения контрактов.

Это решается на уровне клиента? Если это так, я предполагаю, что разные клиенты могут по-разному относиться к саморазрушающимся контрактам. В любом случае, как я могу это вычислить?

Примеры: Глядя на контракт краудсейла KyberNetwork , становится ясно, что этот контракт больше никогда не будет использоваться, аналогичная ситуация с большинством контрактов на продажу токенов. Сколько места могут освободить узлы, не сохраняя состояние этого контракта?

Ответы (2)

Согласно этому ответу, вы можете assembly { size := extcodesize(addr) }узнать точный размер кода по адресу. Объяснение этому здесь .

Таким образом, вы можете вызвать это перед выполнением самоуничтожения и передать это как событие или сохранить его где-то в значении.

Разве это не возвращает только данные кода, а не размер состояния, который занимает этот контракт? То есть 2 контракта могут иметь одинаковый байтовый код, но могут иметь очень разное состояние, где один может иметь 1 миллион записей, а другой 0. Я полагаю, что количество записей также влияет на пространство, которое каждый контракт занимает на узле.

Вдохновленный https://ethereum.stackexchange.com/a/40280/7457 , я нашел относительно простой способ сделать это.

После полной синхронизации вашего узла вам необходимо запросить состояние trie по интересующему вас адресу контракта, используя что-то вроде

//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 значения, где 3-е значение — это storageRoot для этого конкретного контракта.

Указав новый корень, мы создаем readStream для просмотра всех узлов в этой части дерева состояний;

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

Полный скрипт можно найти здесь .