Почему бросок Solidity потребляет весь газ?

Когда вы throwисключение, весь газ потребляется . Чем обосновано такое дизайнерское решение?

Ответы (4)

Весь газ потребляется, потому что у EVM по существу есть только 1 исключение: Out of Gas.

Чтобы увидеть это яснее, взгляните на разницу между «чистым» исключением и ошибкой из-за плохого/глючного/недействительного кода EVM. Out of Gas является первым. Теперь есть такие ошибки, как опустошение стека, неверный JUMP и неверный код операции: их можно назвать «исключениями», но они больше похожи на ошибки, чем на исключение EVM, потому что разработчик контракта не написал валидный код EVM в соответствии с правилами. ЭВМ. Например, недопустимый код операции подобен написанию «класса» вместо «функции» в Javascript: собственный Javascript не имеет «класса», в отличие от такого языка, как Java. При переполнении стека это похоже на то, как разработчик говорит EVM добавить 2 числа, но разработчик не предоставляет 2-е число.

Обратите также внимание на то, как «исключение» в EVM отличается от других языков. Например, в EVM нет исключения деления на ноль (хотя Solidity 0.4+ будет генерировать исключение для этого). Предполагая действительный код EVM, исключений нет, за исключением Out of Gas.

Поскольку есть только исключение Out of Gas, эти другие ошибки были сделаны так, чтобы вести себя как Out of Gas. Это относительно согласуется с некоторыми принципами проектирования Ethereum по обобщению и минимизации сложности. Другими словами, при реализации поведения переполнения стека, недопустимого JUMP и недопустимого кода операции для протокола проще и легче повторно использовать реализацию и поведение Out of Gas.

В других ответах объясняется, как Solidity компилируется throwв недопустимый JUMP. (Вместо этого Serpent использует недопустимый код операции и вызывает его invalidвместо throw.)

РЕДАКТИРОВАТЬ: выпуск Byzantium включает EIP 140 , новый код операции, названный REVERTв EVM, который:

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

throwустаревает в пользу revert(), require(),assert()

classдопустимое ключевое слово в javascript, используемое для определения класса.
@0xcaff Спасибо, да, JavaScript тоже развивается и classдобавлен в ECMAScript 2015 developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… (все еще требуется время, чтобы стандарты ECMA стали широко известны и приняты).

Инструкция Solidity throwкомпилируется в недопустимую инструкцию JUMP (т. е. переход в недопустимое место).

В разделе 9.4.2 Желтой книги объясняется, как работает исключительная остановка , в главе 8 объясняется, что в этом случае газ не возмещается.

В главе 8 говорится:

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

И возвращаясь к главе 7:

Если такого исключения не происходит, то оставшийся газ возвращается отправителю, и теперь измененное состояние сохраняется.

Почему было принято такое решение, у меня нет информации.

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

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

Это не объясняет причину того, почему он разработан таким образом. Многие примеры в документации Solidity используют throwтак, как будто это лучший способ сделать что-то. Но это явно не так, если это стоит звонящим максимальную плату.
Согласно вашему объяснению, это должно стоить не более того количества газа, которое уже было израсходовано в транзакции до момента возникновения исключения (наивная реализация может «отменять» каждую операцию по одной за раз).
Это потребует добавления системы для отслеживания всех изменений состояния, в том числе при вызовах других контрактов, что на самом деле невозможно.