2020.코딩일지

[solidity] error/try-catch문 (feat.솔리디티깨부수기) 본문

Block Chain

[solidity] error/try-catch문 (feat.솔리디티깨부수기)

개발하는라푼젤 2022. 12. 5. 13:27
728x90

error

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;

//에러핸들러: require, revert, assert, try/catch
    /*
    0.4.22 ~ 0.7.x
    assert: gas를 다 소비한 후, 특정한 조건에 부합하지 않으면 (false일 때) 에러를 발생시킨다.
    revert: 조건없이 에러를 발생시키고, gas를 환불시켜준다.
    require: 특정한 조건에 부합하지 않으면(false일 때) 에러를 발생시키고, gas를 환불시켜준다.
    */
    /*
    0.8.0. 포함X
    0.8.1~
    assert: 오직 내부적 에러 테스트 용도, 불변성 체크용도.
            assert가 에러를 발생시키면, panic(uint256)이라는 에러타입의 에러 발생
    */

contract lec21 {
    //0.7.0.ver(3000000 gas) //	0.8.x.ver(21232 gas) : test용 
    function assertNow() public pure {
        assert(false);
    }
    //0.7.0.ver(21344 gas) // 0.8.x.ver(21520 gas)  예상가스비용지불하고, revert에 걸려서 나머지는 환불
    function revertNow() public pure {
        revert("error!!");//무조건 에러를 뱉으니까 실현적이지 않아서, if나 require(=if+revert)를 쓴다
    }
    //0.7.0.ver(21338 gas) // 0.8.x.ver(21520 gas)
    function requireNow() public pure {
        require(false, "occurred");
    }

    function onlyAdults(uint256 _age) public pure returns(string memory) {
        if(_age < 19) { //if문은 true일때 revert가 작동하지만
            revert("You are not allowed to pay for the cigarette");
        }
        return "Tour payment is acceeded";
    }
        //require문은 false일때 revert가 작동하다
    function onlyAdults2(uint256 _age) public pure returns (string memory) {
        require(_age>19,"You are not allowed to pay for the cigarette" );
        return "Tour payment is acceeded";
    }
    
}

 

 

try-catch문

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
 /*
    0.6 버전 이후
        try/catch 왜 써야하는가?
            기존의 에러 핸들러 assert/revert/require는 에러를 발생시키고 프로그램을 끝냄
            그러나, try/catch로 에러가 났어도, "프로그램을 종료시키지않고 어떠한 대처를 하게" 만들 수 있다.

        trh/catch의 특징 
        1. 
        try/catch문 안에서, assert/revert/require을 통해 에러가 난다면 catch는 에러를 잡지 못하고,
                개발자가 의도한지 알고 정상적으로 프로그램을 끝낸다.
        try/catch문 밖에서,⭐️assert/revert/require을 통해 에러가 난다면 catch는 에러를 잡고, 에러를 핸들할 수 있다

        2. 3가지 catch
        catch Error(string memory reason) {...} : revert나 require를 통해 생성된 에러용도
        catch Panic(uint errorCode) {...} : assert를 통해 생성된 에러가 날 때 이 catch에 잡힌다.
        (errorCode는 솔리디티이 정의 Panic에러에서 확인 - 0.8.1 버전부터 있다)
        catch(bytesmemoryLowLevelData){...} : 이 catch는 로우 레벨에러를 잡는다.

        3. 어디서 쓰는가?
        외부 스마트 컨트랙을 함수로 부를 때 : 다른 스컨을 인스턴스화 해서, try/catch문이 있는 스컨의 함수를 불러와서 사용.
        외부 스마트 컨트랙을 생성할 때 : 다른 스컨을 인스턴스화 생성 할 때 씀.
        스컨 내에서 함수를 부를 때 : this를 통해 try/catch를 씀
    */
contract math {
    function division(uint256 _num1, uint256 _num2) public pure returns (uint256) {
        require(_num1<10, "num1 shoud not be more than 10"); //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 public mathInstance = new math(); //위의 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){ //_num2가 0인경우 //0.8.1.ver에서만 확인가능하다
            emit catchPanic("asserError/Panic", _errorCode);
            return(0,false);
        }catch (bytes memory _errorCode) {
            emit catchLowLevelErr("LowlevelError", _errorCode);
            return(0,false);
        }
    }
}
Comments