require는 솔리디티 함수를 실행하거나 실행하지 않을 조건을 설정할 때 사용한다.
보통 조건문은 if를 사용하지만 if문은 의미 없는 경우의 수까지 함수를 실행시켜 가스비가 의미 없이 소비되는 경우가 발생한다.
솔리디티 코드를 작성할 때에는 가스비가 최소한으로 들도록 설계해야 한다.
따라서, 특정 경우 아예 함수를 실행시키지 않도록 할 필요성이 존재하여 require 문이 탄생하게 되었다.
function A() {
require([실행 조건], "[false일 경우 띄울 메시지]");
rest of code;
}
> 아래 [예시] 를 통해 require문이 가진 여러 특성을 살펴본다.
[예시 1] : require 조건이 false이면, 상태를 변화시키지 않아 가스비가 발생하지 않는다. (에러 메시지 확인)
[예시 2] : require 조건이 false이면, require문의 위치에 상관없이 전체 함수를 실행하기 전의 상태로 돌아간다.
[예시3] : require문을 return 뒤에 쓰지 않도록 주의할 것
[예시4] : require문이 존재하는 경우, 함수 속의 함수도 실행되기 전으로 돌아간다.
require 조건이 false이면, 상태를 변화시키지 않아 가스비가 발생하지 않는다. (에러 메시지 확인)
function require_2(uint _n) public returns(string memory) {
require(_n <= 10, "_n should not be higher than 10. ");
a = _n;
if(0 <= a && a <= 2) {
return "A";
} else if(3 <= a && a <= 5) {
return "B";
} else if(6 <= a && a <= 8) {
return "c";
} else {
return "D";
}
}
[예시 1]의 코드에서, require_2(11)을 입력해 require 조건을 만족하지 않을 경우, 다음과 같은 에러 메시지가 등장한다:
"the transation has been reverted to the initial state"
에러 메시지의 의미를 생각해보면, 원 상태로 복구되었다는 의미가 된다. 원 상태로 보구되었다는 의미는 곧 "상태(변수)가 변하지 않았다"가 되기 때문에 결국 가스비를 쓰지 않는 것이다.
require 조건이 false이면, require문의 위치에 상관없이 전체 함수를 실행하기 전의 상태로 돌아간다.
function require_3(uint _n) public returns(string memory) {
a = _n;
require(_n <= 10, "_n should not be higher than 10. ");
if(0 <= a && a <= 2) {
return "A";
} else if(3 <= a && a <= 5) {
return "B";
} else if(6 <= a && a <= 8) {
return "c";
} else {
return "D";
}
}
function getA() public view returns(uint) {
return a;
}
위 코드를 보면, require문 전에 'a = _n;' 코드가 존재하는 것을 볼 수 있다. 이 경우, require문에 반하는 경우, a=_n;이 실행될까? 즉, require문은 require 문이 작성되기 전의 줄까지의 상태로 되돌리는 것일까? 아니면 function require_3()을 실행하기 전의 상태로 되돌리는 것일까? 실행해보면 결과를 통해 확인할 수 있다.
실행 결과, require 조건을 만족하지 않는 경우, a에 _n이 입력되지 않은 것을 볼 수 있다. (바로 전 줄로 돌아가서 a에 _n이 들어가는 게 아님!)
즉, require문은 아예 함수를 누르기 전으로 되돌린다.
require문을 return 뒤에 쓰지 않도록 주의할 것
function require2_1() public pure returns(uint) {
uint a = 1;
bool b;
require(b, "go back");
return a;
}
a가 반환되지 않는다. 즉, require 조건에 걸려, uint a = 1;을 하기 전의 상태로 되돌아간다.
[require문이 return 뒤에 존재하는 경우]:
function require2_2() public pure returns(uint) {
uint a = 1;
bool b;
return a;
require(b, "go back");
}
require문이 존재하는 경우, 함수 속의 함수도 실행되기 전으로 돌아간다.
contract Require3 {
uint a;
function setAasFive() public {
a = 5;
}
function getInput(uint _n) public {
setAasFive();
require(_n >= 10, "go back");
}
function getA() public view returns(uint) {
return a;
}
}