Solidity использует функции revert
, require
и assert
в качестве исключений возврата состояния для обработки ошибок. revert
является общим, assert
следует использовать только для проверки внутренних ошибок и инвариантов, а require
следует использовать для проверки допустимых условий, таких как входные данные или переменные состояния контракта или возвращаемые значения из вызовов внешних контрактов.
Начиная с версии 0.4.22 Solidity можно указать необязательный аргумент причины с помощью функций revert
и require
. Это означает, что такие функции, как
function myFunction(uint256 input) public view returns (uint256) {
require(input >= 5); return input * input - 25;
}
теперь можно обогатить, как
function myFunction(uint256 input) public view returns (uint256) {
require(input >= 5, "myFunction only accepts arguments which are greater than or equal to 5");
return input * input - 25;
}
Это выглядит как приятное улучшение, но как я могу использовать Web3j
, чтобы фактически проверить, был ли отменен переход с eth_call
на myFunction
и какова была сопутствующая причина?
Как поясняется в запросе на вытягивание, в котором добавлена функция Вернуть с указанием причины, строка причины закодирована как вызов функции Error(string)
, включая селектор функций. Это означает, что когда вышеуказанная функция возвращается из-за функции require
, результатом будет:
0x08c379a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000476d7946756e6374696f6e206f6e6c79206163636570747320617267756d656e747320776869636820617265206772656174686572207468616e206f7220657175616c20746f203500000000000000000000000000000000000000000000000000
Небольшое форматирование дает нам:
0x08c379a0
// Function selector 0000000000000000000000000000000000000000000000000000000000000020
// Offset of string return value 0000000000000000000000000000000000000000000000000000000000000047
// Length of string return value (the revert reason) 6d7946756e6374696f6e206f6e6c79206163636570747320617267756d656e74
// first 32 bytes of the revert reason 7320776869636820617265206772656174686572207468616e206f7220657175
// next 32 bytes of the revert reason 616c20746f203500000000000000000000000000000000000000000000000000
// last 7 bytes of the revert reason
Если мы используем EthCall
Web3j
при вызове функции myFunction
, эта причина возврата может быть извлечена следующим образом:
public Optional<String> getRevertReason(EthCall ethCall) { String errorMethodId = "0x08c379a0"; // Numeric.toHexString(Hash.sha3("Error(string)".getBytes())) // .substring(0, 10) List<TypeReference<Type>> revertReasonTypes = Collections.singletonList( TypeReference.create((Class<Type>) abiTypes.getType("string") ) ); if (!ethCall.hasError() && ethCall.getValue() != null && ethCall.getValue().startsWith(errorMethodId)) {
String encodedRevertReason = ethCall.getValue().substring(errorMethodId.length()); List<Type> decoded = FunctionReturnDecoder.decode(encodedRevertReason, revertReasonTypes); Utf8String decodedRevertReason = (Utf8String) decoded.get(0); return Optional.of(decodedRevertReason.getValue()); } return Optional.empty(); }
Что вернет Optional
строки «myFunction принимает только аргументы, которые больше или равны 5».
Первоначально опубликовано на www.dhondt.tech.