| 知乎專欄 | 多維度架構 | | | 微信號 netkiller-ebook | | | QQ群:128659835 請註明“讀者” |
什麼是整型溢出呢?在solidity編寫合約時,定義整型一般是用uint8, uint256。一個變數如果定義為uint8表示的無符號的8位整型,即取值範圍為0-255。當給這個變數賦值256時,即整型溢出變成了0,以此類推257變成了1。
pragma solidity ^0.4.24;
//author: netkiller <netkiller@msn.com>
//homepage: http://www.netkiller.cn
contract NetkillerOverflowTest{
function add(uint8 a, uint8 b) pure public returns (uint8){
uint8 result = a + b;
return result;
}
function sub(uint8 a, uint8 b) pure public returns (uint8){
uint8 result = a - b;
return result;
}
function mul(uint8 a, uint8 b) pure public returns (uint8){
uint8 result = a * b;
return result;
}
function div(uint8 a, uint8 b) pure public returns (uint8){
uint8 result = a / b;
return result;
}
}
調用上面合約,運行結果
254 + 1 = 255 254 + 2 = 0 254 + 3 = 1
減法運行結果
10 - 20 = 246
乘法運行結果
51 * 5 = 255 51 * 6 = 50
再來測試乘法
255 / 10 = 25
這有點想千年蟲問題,即99年變成00年後,你無法區分1900年還是2000年。
現在測試一下uint256,uint256支持的取值範圍是0到2^256-1
pragma solidity ^0.4.24;
//author: netkiller <netkiller@msn.com>
//homepage: http://www.netkiller.cn
contract TestUint256Overflow {
// (2**256 – 1) + 1 = 0 向上溢出測試
function overflow() pure public returns (uint256 _overflow) {
uint256 max = 2 ** 256 - 1;
return max + 1;
}
// 0 – 1 = 2**256 – 1 向下溢出測試
function underflow() pure public returns (uint256 _underflow) {
uint256 min = 0;
return min - 1;
}
}
運行結果
_overflow : 0 _underflow : 115792089237316195423570985008687907853269984665640564039457584007913129639935
第一個函數溢出為 0,第二個函數 0 - 1 = 115792089237316195423570985008687907853269984665640564039457584007913129639935
解決溢出問題使用SafeMath庫
pragma solidity ^0.4.24;
//author: netkiller <netkiller@msn.com>
//homepage: http://www.netkiller.cn
library SafeMath {
function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {
if (a == 0) {
return 0;
}
c = a * b;
assert(c / a == b);
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return a / b;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
assert(b <= a);
return a - b;
}
function add(uint256 a, uint256 b) internal pure returns (uint256 c) {
c = a + b;
assert(c >= a);
return c;
}
}
contract NetkillerSafeMath {
using SafeMath for uint256;
function add(uint256 a, uint256 b) pure public returns (uint256){
uint256 result = a.add(b);
return result;
}
function sub(uint256 a, uint256 b) pure public returns (uint256){
uint256 result = a.sub(b);
return result;
}
function mul(uint256 a, uint256 b) pure public returns (uint256){
uint256 result = a.mul(b);
return result;
}
function div(uint256 a, uint256 b) pure public returns (uint256){
uint256 result = a.div(b);
return result;
}
}
測試 SafeMath
add(115792089237316195423570985008687907853269984665640564039457584007913129639934,1) => 115792089237316195423570985008687907853269984665640564039457584007913129639935 add(115792089237316195423570985008687907853269984665640564039457584007913129639935,1) => 拋出異常