[solidity] Error Handling (assert, require, revert)

Seokhun Yoon·2022년 2월 21일
1
post-thumbnail
post-custom-banner

Error Handling

이전 포스팅에서 에러 핸들링에는 assert(), require(), revert()가 있다는 것을 잠깐 언급했었다.
이 세가지 메서드들은 Solidity Version 0.4.10 부터 추가된 기능으로, 모두 조건을 충족하지 못하면 함수 실행을 중단하고 상태를 되돌리는 기능을 한다.
그렇다면 어떤 차이점이 있고 언제 어떤 메서드를 사용해야 할까?

1. assert()

  • 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된 변수를 호출할 경우.

2. require()

  • 데이터가 없는 에러 혹은 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 키워드로 새로운 컨트랙트를 생성했지만 정상적으로 완료되지 않은 경우

3. revert()

revert 명령어 또는 revert 함수, 두 가지 형태로 revert를 트리거 할 수 있다.
단일로 사용되기 보다 if/else 구문과 함께 사용된다.

  • revert 명령어 : 괄호 없이 사용자 정의 에러를 직접 인수로 받는다.
revert CustomError(arg1, arg2)

보통 사용자 정의 오류 인스턴스를 사용하면 문자열 설명보다 훨씬 더 저렴하다.
(에러 인스턴스의 이름, 즉 인코딩된 4 Bytes만으로도 오류를 설명할 수 있기 때문)

  • revert 함수 : 괄호를 사용하며 문자열을 인수로 받을수도 있다.
revert();						// 오류 데이터 없이 revert
revert("error description");	// Error(string) 에러를 생성

+ Gas refunds

  • require()revert()는 가스비를 환불해준다.
  • assert()는 가스비 환불이 안된다.

내용 수정 (2022/05/22)

  • 0.8.0 이하 버전 (0.8.0 포함)
    assert()의 가스비 환불이 안되고 Panic이라는 에러 타입도 존재하지 않습니다.
  • 0.8.x (0.8.0 제외)
    assert()에서도 가스비 환불이 됩니다. 그리고 공식문서에서는 오직 내부적 에러 테스트 용도 및 불변성 체크 용도로 사용하라고 적혀있습니다.
    또한, assert()로 인해 에러가 발생하면 Panic 에러타입을 발생시킵니다.





참고 사이트

profile
블록체인 개발자를 꿈꾸다
post-custom-banner

0개의 댓글