Исключение в контракте отменяет весь стек, использует весь газ

Я добавил чек, чтобы убедиться, что когда я отправляю эфир, если он не работает, я пытаюсь прервать транзакцию с помощью броска. Например: Исключения на целостность

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

Бросок находится внутри сложной петли (бизнес-логика), но это похоже на приведенный выше пример:

// inside complicated business logic I wish to roll back if this fails
if (a.send(remittance) == false) {
    throw;
}

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

for(uint i = 0;i < callbacks.length; i++) {
    callbacks[i].oracleCallback(_value, _time, _info);
}

Я использую довольно недавнюю сборку ведущей ветви geth и довольно недавней сборки (в начале января) прочности.

Вот квитанция о транзакции (частный тестовый сервер):

{"transactionHash":"0x61474d8ecd82d5c95d7c9c548f5a4cd5213b16775809580189860bd69773c07a","transactionIndex":0,"blockNumber":440377,"blockHash":"0xb88779e44dabd14fcc55f7a0cdd31aaeab6417b990ed626748d8726463173bad","cumulativeGasUsed":800000,"gasUsed":800000,"contractAddress":null,"logs":[]}
5 голосов | спросил Paul S 5 FebruaryEurope/MoscowbFri, 05 Feb 2016 05:26:28 +0300000000amFri, 05 Feb 2016 05:26:28 +030016 2016, 05:26:28

1 ответ


4

Да, все исключения EVM приводят к откату всех изменений состояния, и весь газ лишается шахтера. Таким образом, хотя ошибки бросания удобны, иногда имеет смысл просто вернуть некоторое значение ошибки. Вы также можете использовать события, чтобы сигнализировать о возникновении исключения.

При вызове других контрактов все исключения затухают, за исключением случаев, когда вы используете send или call. Это низкоуровневые функции, отправляющие Ether или вызов метода другого контракта, но они возвращают только true или false, если возникло исключение.

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

uint gasPerCall = msg.gas / callbacks.length - 200000;
bytes4 abi = bytes4(sha3("oracleCallback(int256,uint256,bytes32)"));

for(uint i = 0; i < callbacks.length; i++) {
    if (callbacks[i].call.gas(gasPerCall)(abi, _value, _time, _info) == false) {
        FailedCallbackEvent(abi, gasPerCall, msg.gas);
    }
}

Замените типы в ABI на правильные типы. Если количество отправленного газа не имеет значения, вы можете просто использовать callbacks[i].call(abi,_value,_time,_info);

Если вы хотите отправить Ether вместе с вызовом, вы также можете использовать callbacks[i].call.value(1 ether)(abi,_value,_time,_info);

Это вернет true, если вызов преуспел, а false в противном случае.

См. документы

ответил Tjaden Hess 5 FebruaryEurope/MoscowbFri, 05 Feb 2016 05:59:00 +0300000000amFri, 05 Feb 2016 05:59:00 +030016 2016, 05:59:00

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

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

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