Почему это потенциальное нарушение шаблона «Проверки-Эффекты-Взаимодействие»?

Это то, что Ремикс говорит мне. Теперь, когда я смотрю на документацию о том, что это значит, кажется, что речь идет, как я понимаю, о рекурсивном вводе потока управления (если):

Передача эфира всегда может включать в себя выполнение кода, поэтому получателем может быть контракт, который вызывает возврат.

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

/*
 * Allows a user to buy tokens for Ether.
 */
function buy() public payable {
    // check that the amount of ether sent is greater than 0
    require(msg.value > 0);
    // check the amount sent is enough for at least one token
    require(msg.value >= tokenPriceInWei);

    // NOTE: balance is automatically updated by the payable modifier

    // calculate tokens to be distributed as integer
    uint numToDistribute = msg.value / tokenPriceInWei;
    // calculate remainder to be refunded, e.g. 7.1eth sent, 1.1eth to be refunded
    uint refundableRemainderInWei = msg.value - (toWei(numToDistribute));

    // distribute token to sender
    distribute(msg.sender, numToDistribute);
    // refund the remainder
    msg.sender.transfer(refundableRemainderInWei);

    Bought(msg.sender, numToDistribute);
}

/*
 * Distribute tokens from distributor to a receiver.
 */
function distribute(address _receiver, uint _amount) private {
    // check for at least one token, if not something went wrong
    require(_amount > 0);
    // check for balance overflow, causing incorrect balances value
    require(balances[_receiver] + _amount > balances[_receiver]);

    // decrement from distributor and increment receiver
    balances[distributor] -= _amount;
    balances[_receiver] += _amount;
}

Кроме того, если кто-нибудь может сказать мне, почему стоимость газа для этого метода высока до бесконечности и почему он говорит то же самое, когда я пытаюсь развернуть контракт через Mist и не могу развернуть, это действительно сделало бы мой день!

Спасибо, если вы дочитали до этого места и за любой совет, который вы можете дать этому подающему надежды инженеру по смарт-контрактам!

Вам также необходимо включить содержимое distributefunction. Remix может учитывать это при проверке уязвимости повторного входа и при оценке газа.
Привет, извините, я забыл, добавил сейчас!

Ответы (1)

Измените это:

// refund the remainder
msg.sender.transfer(refundableRemainderInWei);
Bought(msg.sender, numToDistribute);

К этому: // refund the remainder Bought(msg.sender, numToDistribute); msg.sender.transfer(refundableRemainderInWei);

Атаку с повторным входом можно рассматривать как неожиданное изменение потока перед важным изменением состояния. Итак, хорошая защита — привести свой дом в порядок, прежде чем передать управление другому контракту, что transferи происходит.

Размещение эмиттера событий перед transferгарантирует, что журнал обновляется и корректен. Это «оптимистичный учет». Если transferпо какой-то причине произойдет сбой, это вызовет откат, и событие не будет сгенерировано.

Газ неизвестен или, возможно, бесконечен, потому что transferприемники неизвестны. Это могут быть внешние счета, которые просто принимают средства. С другой стороны, это могут быть контракты с резервными функциями, которые запускаются при получении средств (это передача управления потоком).

В лучшем случае эти функции будут использовать неизвестное количество газа. Это может быть бесконечно , если они наотрез откажутся принимать эфир (случайно или намеренно).

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

Надеюсь, это поможет.

Но разве события не отображаются в журнале до тех пор, пока транзакция не будет завершена и добыта? Если это так, то это спорный вопрос, потому что ни вызывающий контракт, ни вызываемый контракт не могут читать сгенерированные события.