Каковы ограничения для оценки газа и когда его оценка будет существенно ошибочной?

web3.eth.estimateGasа оценку газа JSON-RPC можно использовать, чтобы увидеть, сколько газа должно быть указано для транзакции, прежде чем создавать транзакцию.

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

Ответы (3)

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

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

Представьте себе простой контракт, который проверяет хэш самого последнего блока, а затем вызывает другой большой контракт, потребляющий газ, только если 10-й бит в хэше блока равен 1. Если вы используете AssessmentGas для измерения потребления транзакции, которая вызывает этот простой контракт , ваш результат будет полностью зависеть от того, содержит ли самый последний блок 1 в 10-м бите хэша блока. Если новый блок публикуется в промежутке между моментом, когда вы вызываете AssessmentGas, и моментом, когда транзакция фактически включена, ваша оценка с вероятностью 50 % будет совершенно ошибочной . Это может показаться надуманным примером, но многие контракты используют хэши блоков в качестве источника энтропии и меняют свое поведение в зависимости от того, что такое хеш. Так что это то, что определенно может произойти в дикой природе.

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

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

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

Вкратце:
если есть какой-либо способ изменить последствия вашей транзакции в зависимости от того, когда или кому она отправлена, существует вероятность того, что оценкаGas будет ошибочной на сколь угодно большие суммы. Примите дополнительные меры предосторожности.

Отличный ответ. Как майнеры могут включить режим траты газа и «никогда публично не публиковать эти частные транзакции»? Или это должен быть отдельный вопрос?
Под «никогда не публиковать публично» я имею в виду только то, что они никогда не отправляют транзакции другим майнерам для включения. Конечно, когда они включают транзакцию запуска/остановки в свой собственный блок, она публикуется как часть блока. Таким образом, тщательный анализ блокчейна все равно позволит понять, что они делают. Я имел в виду только то, что они никогда не «рискуют» в отношении того, может ли кто-то другой включить их транзакцию, отправив ее по сети p2p так, как будет отправлена ​​обычная транзакция. Имеет ли это смысл?
Да, спасибо. В tldr не так ясно, «кому это отправлено», потому что «кому» фиксируется в транзакции. Под «кому» вы имеете в виду свой пример транзакции, подписанной определенным ключом?
Ключевое слово «отправлено», а не адресовано: я говорил о том, какой майнер обрабатывает транзакцию. Но если эта часть сбивает с толку, я могу попытаться перефразировать.
Если все, что вы имеете в виду, это майнер, я думаю, что перефразирование было бы намного яснее :) пример «... меняться в зависимости от того, кто является майнером или когда он добывается»
Я не думаю, что второй пример в ответе на 100% правильный. Если майнер изменяет поведение в начале вычисления блока и никогда не публикует, это означает, что если кто-то выполняет транзакцию, ему потребуется много газа только в том случае, если этот кто-то совершил транзакцию для этого конкретного майнера, поскольку именно здесь происходит злая транзакция ( изменение сделка) есть. Шанс на это очень мал. @eth, что ты думаешь?
@NikaKurashvili Вы правы в том, что только конкретный майнер может воспользоваться преимуществом, и его шансы на добычу блока пропорциональны его хешрейту. Но то, что описывается, не предназначено для атак, которые могут выполнять все майнеры постоянно. Ничего противоречащего в том, что вы и ответ говорите.
Второй пример предвосхитил основную проблему сети Ethereum на сегодняшний день...

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

Это вполне может быть ошибкой в ​​текущей версии geth, но я обнаружил, что вызов метода, выдающего исключение, всегда дает один и тот же результат оценки газа, который представляет собой значение 50000000 единиц газа. При цене газа в 20000000000, по моей оценке, вызовы Gas приносили ровно 1 эфир, что казалось огромной суммой для простого вызова, вызывающего исключение.

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

Кстати, это значение «50000000», по-видимому, совпадает с тем, которое используется для инициализации переменных, связанных с газом, в исходном коде go API ( https://github.com/ethereum/go-ethereum/blob/master/eth/api .go ), что, кажется, намекает на то, что это скорее ошибка, чем фича ;-)

Проголосовал. Если вы можете, отправьте его на github.com/ethereum/go-ethereum/issues (и обновите ответ, указав, что происходит).
Интересно, что на самом деле мы специально использовали функцию AssessmentGas таким образом, чтобы определить, проголосовал ли кто-то уже за предложение DAO или пытался отправить DAO, когда оно было заблокировано. Поскольку мы знали, что при таких обстоятельствах контракт будет сброшен, мы оценим газ, и если он съест весь газ, мы отобразим предупреждение вместо отправки TX. Это предотвратило попытки людей проголосовать дважды или отправить DAO через интерфейс, где мы могли контролировать обмен сообщениями и, следовательно, сократить количество писем в службу поддержки.

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

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