Разница между требованием и утверждением и разницей между возвратом и броском

Я смотрел документы и я искал разъяснения по поводу разницы между требованием и утверждением, а также бросать и возвращать.

  

assert (условие bool): отменять выполнение и возвращать изменения состояния, если   условие является ложным (использование для внутренней ошибки)

     

require (условие bool):   прервать выполнение и вернуть изменения состояния, если условие ложно (используйте   для искаженного ввода)

В частности, в отношении assert и require, как вы рисуете линию между неправильным вводом и внутренней ошибкой?

52 голоса | спросил Daniel Kobe 13 AMpThu, 13 Apr 2017 03:20:27 +030020Thursday 2017, 03:20:27

3 ответа


70

При выборе между assert() и require()

следует учитывать два аспекта:
  1. Эффективность газа
  2. Анализ байт-кода

1. Эффективность газа

assert(false) компилируется в 0xfe, что является недопустимым кодом операции, используя весь оставшийся газ и возвращая все изменения.

require(false) компилируется в 0xfd, который является кодом кода REVERT, что означает, что он вернет оставшийся газ. Код операции также может возвращать значение (полезно для отладки), но я не верю, что это поддерживается в Solidity с этого момента. (2017-11-21)

2. Анализ байт-кода

Из docs (выделено мной)

  

Функция require должна использоваться для обеспечения выполнения допустимых условий, таких как входные данные или переменные состояния контракта, или для проверки возвращаемых значений из вызовов внешних контрактов. При правильном использовании инструменты анализа могут оценить ваш контракт, чтобы определить условия и вызовы функций, которые достигнут неудачного утверждения. Правильно функционирующий код никогда не должен выходить из строя утверждения assert; если это произойдет, в вашем контракте есть ошибка, которую вы должны исправить.

Вышеприведенная выдержка является ссылкой на экспериментальный и недокументированный код SMTChecker.

Я использую несколько эвристик, чтобы помочь мне решить, что использовать.

Используйте require() для:

  • Подтверждение ввода пользователем
  • Подтвердите ответ от внешнего контракта
    то есть. используйте require(external.send(amount))
  • Проверять состояние состояния до выполнения операций изменения состояния, например, в условиях контракта owned
  • Как правило, вам следует чаще использовать require,
  • Как правило, он будет использоваться в начале функции.

Используйте assert() для:

  • проверить переполнение /недополнение
  • проверить инварианты
  • подтвердить состояние контракта после внесения изменений
  • избегать условий, которые никогда не должны быть когда-либо возможны.
  • Как правило, вы должны чаще использовать assert
  • Как правило, он будет использоваться в конце вашей функции.

В принципе, assert находится там, чтобы предотвратить что-то действительно плохое, но не должно быть возможно, чтобы условие оценивалось как false.

Историческое примечание:

Функции require() и assert() были добавлены в Solidity до викинга Византии в v0.4.10. До Византии они вели себя одинаково, но уже скомпилированы для разных кодов операций. Это означало, что некоторые контракты, развернутые до Византии вел себя по-разному после вилки, главным отличием было то, что началось возмещение неиспользуемого газа.

ответил maurelian 11 PM00000080000004231 2017, 20:56:42
16

Я использую require для проверки ввода, так как это немного более эффективно, если /throw.

function foo(uint amount) {
    require(amount < totalAmount);
    ...
}

Где в качестве assert следует использовать больше для обнаружения ошибок во время выполнения:

function foo(uint amount) {
    ...
    __check = myAmount;
        myAmount -= amount;
    assert(myAmount < __check);
    ...
}

revert вернет изменения и вернет неиспользованный газ в более поздней версии Ethereum, но ATM действует так же, как и выброс.

ответил o0ragman0o 13 AMpThu, 13 Apr 2017 04:33:27 +030033Thursday 2017, 04:33:27
1

Я думаю, что ни один из ответов не верен.

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

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

throw устарел в пользу возврата.

revert зарезервирован для условий ошибки, которые влияют на бизнес-логику. Например, кто-то посылает голосование, когда голосование уже близко.

require и revert в основном похожи на внутреннюю реализацию EVM, но разработчики оценят это различие.

ответил earizon 11 J0000006Europe/Moscow 2018, 16:44:32

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132