Как стоимость изменения 2 переменных состояния и генерации 1 события может достигать 50 тысяч единиц газа?

У меня есть этот контракт:

pragma solidity ^0.4.23;
contract Test {
    event Event(address indexed wallet);

    mapping (address => bool) public authorizedWallets;

    uint256 public authorizedWalletCount;

    function add(address _wallet) external {
        _add(_wallet);
        emit Event(_wallet);
    }

    function _add(address _wallet) private {
        require(!authorizedWallets[_wallet]);
        authorizedWallets[_wallet] = true;
        authorizedWalletCount++;
    }
}

И я проверяю стоимость газа function addvia web3 v1.0.0-beta.34на NodeJS:

async function send(transaction) {
    let success = await web3.eth.personal.unlockAccount(OWNER_ADDRESS, OWNER_PASSWORD);
    let gas = await transaction.estimateGas({from: OWNER_ADDRESS, gasPrice: GAS_PRICE});
    console.log(`gas = ${gas}`);
    return await transaction.send({from: OWNER_ADDRESS, gasPrice: GAS_PRICE, gas: gas});
}

for (let i = 1; i < 10; i++) {
    let wallet = `0x5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5${i}`;
    let hash = await send(contract.methods.add(wallet));
}

Обратите внимание, что после того, как я напечатаю стоимость газа, я выполняю транзакцию, чтобы она вступила в силу для контракта, а затем и для стоимости газа следующей транзакции.

На первой итерации стоимость газа составляет 64827.

На каждой из следующих итераций стоимость газа составляет 49827.

Я полагаю, что эта разница сама по себе имеет смысл, поскольку первая транзакция, вероятно, меняет гораздо больше нулей на 1, чем каждая из следующих транзакций (я полагаю, в mapping (address => bool) public authorizedWalletsструктуре данных).

Что для меня не имеет особого смысла, так это то, почему каждая из этих транзакций такая дорогостоящая, поскольку выполняется всего несколько операций:

  • _add(_wallet);
    • require(!authorizedWallets[_wallet]);
    • authorizedWallets[_wallet] = true;
    • authorizedWalletCount++;
  • emit WalletAccepted(_wallet);

Я использую Parity и Ropsten для всего, что имеет значение (я считаю, что это не должно иметь значения, но, возможно, здесь я ошибаюсь).

Может кто-нибудь объяснить, почему стоимость этих нескольких операций достигает 50 000 единиц газа?

Спасибо!

Ответы (1)

  • 21 000 базовых затрат на газ для транзакций.
  • authorizedWallets[_wallet] = true;делает SSTORE изменение нуля на ненулевое, так что это 20 000 газа.
  • authorizedWalletCount++;меняет ли SSTORE ненулевое значение на ненулевое, так что это 5000 газа.
  • emit Event(_wallet);делает LOG2, который стоит 1125 газа.

Это 47 125, что довольно близко к вашему общему количеству. Добавьте SLOAD, немного хеширования и немного накладных расходов на перемещение вещей и вызов функций, и я думаю, что 49 827 вполне разумно.

Замена нуля на не ноль: разве стоимость этого не зависит от количества измененных битов (в данном случае - одного бита)? Тот же вопрос относительно «изменения ненулевого значения на ненулевое». Спасибо!
Нет, это не так.