Dapp 개발을 위한 테스트를 하는 도 중 다음과 같은 오류가 발생하였다.
구글링 해보니 산술연산을 한 결괏값이 타입의 허용 범위를 넘어서 overflow 됐다고 알려주는 것 같았다.
Solidity에서 고정 크기 정수에 대한 산술 연산은 연산 결과가 데이터 유형으로 나타낼 수 있는 최댓값 또는 최솟값을 초과할 경우 Overflow 또는 Underflow 오류가 발생할 수 있는데. Overflow는 최댓값을 초과한 경우, Underflow는 최솟값을 초과할 경우 나타난다.
그래서 컨트랙트 함수내의 산술연산하는 부분을 살펴보았고 다음과 같이 오입력 된 연산을 발견할 수 있었다.
mapping(address => mapping(address => uint256)) public allowance;
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
require(_value <= balanceOf[_from]);
require(allowance[_from][msg.sender] >= _value);
// add the balance for transferFrom
balanceOf[_to] += _value;
// subtract the balance for transferFrom
balanceOf[_from] -= _value;
allowance[msg.sender][_from] -= _value; // 에러를 발생한 이유
emit Transfer(_from, _to, _value);
return true;
}
transferFrom은 허용된 spender의 토큰을 원하는 곳으로 전송할 수 있는 함수이다. 해당 함수 부분 중 allowance[msg.sender][_from] -= _value가 아닌 allowance[_from][msg.sender]가 되어야 토큰을 보내는 주소(from)에서 보내는 토큰의 값만큼 뺄 수가 있다.
mapping(address => mapping(address => uint256)) public allowance;
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
require(_value <= balanceOf[_from]);
require(allowance[_from][msg.sender] >= _value);
// add the balance for transferFrom
balanceOf[_to] += _value;
// subtract the balance for transferFrom
balanceOf[_from] -= _value;
allowance[_from][msg.sender] -= _value; // 에러를 발생한 이유
emit Transfer(_from, _to, _value);
return true;
}
mapping이 헷갈려서 오입력을 한듯하다. 처음에는 uint의 타입 범위설정이 잘못된 줄 알고 uint부분을 보다가 시간을 많이 썻다. overflow, underflow는 자주 발생하는 오류이고 해당 오류가 발생하면 보안에 치명적인 듯하다.
찾아보니 해당 오류를 더 방지할 수 있는 Safe Math 라이브러리가 있는 것을 발견했다. 듣고 있는 강의가 끝나면 해당 라이브러리를 도입해 볼 예정이다.
- Safe Math 참고 블로그