
이전 포스팅에서 에러 핸들링에는 assert(), require(), revert()가 있다는 것을 잠깐 언급했었다.
이 세가지 메서드들은 Solidity Version 0.4.10 부터 추가된 기능으로, 모두 조건을 충족하지 못하면 함수 실행을 중단하고 상태를 되돌리는 기능을 한다.
그렇다면 어떤 차이점이 있고 언제 어떤 메서드를 사용해야 할까?
Panic(uint256) 유형의 에러를 생성한다.제대로 작동하는 코드라면 아무리 잘못된 외부 입력에도 Panic 에러를 생성하지 않아야 한다.
그러나 만약 Panic 에러가 생긴다면 컨트랙트에 수정해야할 버그가 있는 것과 같다.
Panic이 발생하는 상황 및 에러 코드
- 0x00: Used for generic compiler inserted panics.
- 0x01:
assert(조건)의 조건이 거짓인 경우- 0x11: 수식 계산의 결과가
underflow또는overflow가 된 경우- 0x12: 0으로 나누기 또는 나머지 계산하는 경우 (e.g. 5 / 0 or 23 % 0)
- 0x21: 너무 크거나 혹은 음수인 값을
enum타입으로 변환하는 경우- 0x22: 잘못 인코딩된
storage byte array에 접근한 경우- 0x31: 빈 배열에서
.pop()을 호출한 경우- 0x32: 잘못된 범위의 인덱스 또는 음수인 인덱스를 통해
array,bytesN또는array slice에 접근한 경우
(i.e. x[i] where i >= x.length or i < 0).- 0x41: 너무 큰 메모리를 할당하거나 너무 큰 배열을 생성한 경우
- 0x51:
internal함수의zero-initialized된 변수를 호출할 경우.
Error(string) 타입의 에러를 생성한다.NOTE_
사용자 정의 에러에서는require()를 사용할 수 없지만, 대신 아래와 같이 사용할 수 있다.if(!condition) revert CustomError();
Error(string)가 발생하는 상황
require(조건)의 조건이 거짓인 경우revert()또는revert("description")을 사용한 경우- 코드가 없는 빈 컨트랙트를 대상으로
external함수를 호출한 경우payable이 없는public함수를 통해 이더를 받는 경우- 컨트랙트가
public getter함수를 통해 이더를 받는 경우
Error또는Panic가 발생하는 경우
.transfer()가 실패한다면,message call을 통해 함수를 호출했지만 정상적으로 완료되지 않은 경우
(로우 레벨 연산은 제외 :call,send,delegatecall,callcode,staticcall)new키워드로 새로운 컨트랙트를 생성했지만 정상적으로 완료되지 않은 경우
revert 명령어 또는 revert 함수, 두 가지 형태로 revert를 트리거 할 수 있다.
단일로 사용되기 보다 if/else 구문과 함께 사용된다.
revert 명령어: 괄호 없이 사용자 정의 에러를 직접 인수로 받는다.revert CustomError(arg1, arg2)보통 사용자 정의 오류 인스턴스를 사용하면 문자열 설명보다 훨씬 더 저렴하다.
(에러 인스턴스의 이름, 즉 인코딩된 4 Bytes만으로도 오류를 설명할 수 있기 때문)
revert 함수: 괄호를 사용하며 문자열을 인수로 받을수도 있다.revert(); // 오류 데이터 없이 revert revert("error description"); // Error(string) 에러를 생성
require()와 revert()는 가스비를 환불해준다.assert()는 가스비 환불이 안된다.내용 수정 (2022/05/22)
- 0.8.0 이하 버전 (0.8.0 포함)
assert()의 가스비 환불이 안되고Panic이라는 에러 타입도 존재하지 않습니다.- 0.8.x (0.8.0 제외)
assert()에서도 가스비 환불이 됩니다. 그리고 공식문서에서는 오직 내부적 에러 테스트 용도 및 불변성 체크 용도로 사용하라고 적혀있습니다.
또한, assert()로 인해 에러가 발생하면Panic에러타입을 발생시킵니다.