부동소숫점 정밀도
- 솔리티디(0.4.24 기준)는 고정 소숫점과 부동소숫점을 지원하지 않는다.
- 즉, 부동소숫점의 정밀도를 int타입 변수로 조절해야 한다.
취약점
1 contract FunWithNumbers {
2 uint constant public tokensPerEth = 10;
3 uint constant public weiPerEth = 1e18;
4 mapping(address => uint) public balances;
5
6 function buyTokens() public payable {
7 // convert wei to eth, then multiply by token rate
8 uint tokens = msg.value/weiPerEth*tokensPerEth;
9 balances[msg.sender] += tokens;
10 }
11
12 function sellTokens(uint tokens) public {
13 require(balances[msg.sender] >= tokens);
14 uint eth = tokens/tokensPerEth;
15 balances[msg.sender] -= tokens;
16 msg.sender.transfer(eth*weiPerEth);
17 }
18 }
- 위 코드의 8행에서 정수 나눗셈에서 문제가 발생한다.
- 정수 타입으로 1/10을 하면 0이 된다. 이것은 변수의 타입이 정수이기 때문에 발생한다.
예방기법
- 비율을 사용할 때는 분자에 큰 수가 올 수 있는지 확인해야 한다.
- 약간의 소숫점 정밀도 손실은 있겠지만, 가능하면 분자를 크게 한 후 나눗셈을 하라.
- 더욱 좋은 방법은 매우 높은 정밀도로 변수값을 변환해서 계산한 후, 요구되는 값으로 변환하는 것이다.