이전 포스팅에서 에러 핸들링에는 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
에러타입을 발생시킵니다.