Solidity에서도 try/catch
가 존재한다. 그 특징들에 대해서 알아보자.
특징
1.assert/revert/require
에러 핸들링
try/catch문 안에서assert/revert/require
로 인한 에러가 나면, catch로 넘어가지 않고 개발자가 의도한 에러로 판단하여 정상적으로 프로그램을 종료한다.
try/catch문 밖에서assert/revert/require
로 인한 에러가 나면, catch로 넘어가서 에러를 핸들할 수 있다.
2. catch의 3가지 종류
catch Error(string memory reason) { ... }
: revert 나 require를 통해 생성된 에러
catch Panic(uint errorCode) { ... }
: assert를 통해 생성된 에러 (예: 0으로 나누면 errorcode로 0x12를 리턴)
catch(bytesmemoryLowLevelData) { ... }
: 로우 레벨 에러
3. 어디서 사용하는가?
(1) 외부 스마트 컨트랙트 함수를 호출할 때 : 다른 스마트 컨트랙트를 인스턴스화 한 뒤, 인스턴스로 함수 호출할 때 사용
(2) 외부 스마트 컨트랙트를 생성할 때 : 다른 스마트 컨트랙트를 인스턴스화 생성할 때 사용함
(3) 스마트 컨트랙트 내에서 함수를 부를 때 : this를 통해 try/catch를 사용함
아래 상황에 따라 만든 예시 코드를 remix
에 넣고 테스트를 해보면 어떻게 에러가 핸들링되는지, 그리고 어떤 상황에서 catch로 넘어가지 않고 에러가 발생하는지 알 수 있다.
중간중간에 주석으로 revert()함수를 넣어두었다. 하나씩 풀어보면서 어떻게 결과가 나오는지 확인해보자.
assert() 에러에 대한 코드는 이전포스팅을 참고하세요!
catch
뒤에 Error
, Panic
그리고 LowLevelError
로 나눠서 각각 에러를 핸들링 할 수 있다.
contract math {
function division(uint256 _num1, uint256 _num2) public pure returns (uint256) {
// 나누기 함수
require(_num1<10, "num1 should not be more than 10");
return _num1/_num2;
}
}
contract runner {
event catchErr(string _name, string _err);
event catchPanic(string _name, uint256 _err);
event catchLowLevelErr(string _name, bytes _err);
// 외부 컨트랙트 math를 인스턴스화 하기
math public mathInstance = new math();
function playTryCatch(uint256 _num1, uint256 _num2) public returns(uint256, bool) {
try mathInstance.division(_num1, _num2) returns(uint256 value) {
return(value, true);
} catch Error(string memory _err) { // num1이 10보다 크면?
emit catchErr("revert/require", _err);
return(0,false);
} catch Panic(uint256 _errorCode) { // num1에 10보다 작은 수를, 그리고 num2에 0을 넣으면?
emit catchPanic("assertError/Panic", _errorCode); // num2가 0일때 에러코드는 0x12
return (0, false);
} catch (bytes memory _errorCode) {
emit catchLowLevelErr("LowLevelError", _errorCode);
return (0, false);
}
}
}
catch
뒤에 Error
, Panic
그리고 매개변수를 받지 않고 에러를 핸들링한다.
contract character {
string private name;
uint256 private power;
constructor (string memory _name, uint256 _power) {
// revert("error"); // 여기서 에러를 내면 어떻게 될까?
name = _name;
power = _power;
}
}
contract runner {
event catchOnly(string _name, string _err);
function playTryCatch(string memory _name, uint256 _power) public returns(bool successOrFail) {
// revert("errors outside of the try/catch block"); // 여기서 에러를 내면 어떻게 될까?
try new character(_name, _power) { // try/catch에서 catch 컨트랙트를 직접 인스턴스화
// revert("errors in the try/catch block"); // 여기서 에러를 내면 어떻게 될까?
return(true);
} catch {
emit catchOnly("catch", "Errors");
return (false);
}
}
}
catch
뒤에 Error
, Panic
그리고 매개변수를 받지 않고 에러를 핸들링한다.
contract runner2 {
event catchOnly(string _name, string _err);
function simple() public returns(uint256) {
// revert("error"); // 여기서 에러를 내면 어떻게 될까?
return 4;
}
function playTryCatch(string memory _name, uint256 _power) public returns(uint256, bool) {
try this.simple() returns(uint256 _value) { // this를 통해 내부 함수 불러옴
return(_value, true);
} catch {
emit catchOnly("catch", "Errors");
return (0, false);
}
}
}
잘 참고하고 갑니다!