Solidity是一种类似于JavaScript的语言,它面向对象,支持多继承,可以一次返回多个值。在开发智能合约的过程中,对应++、–这类操作要考虑变量的定义域,即要考虑变量的上溢与下溢问题。
- 数据上溢
uint8 numA = 255;
numA++;
uint8的定义域为[0,255],现在numA已经到顶了,numA++会使num变成0(由于256已经超过定义域,它会越过256,变成0),即数据发生上溢(越过上边界,叫上溢)。255 --> 256 -->0 上溢。
- 数据下溢
uint8 numB = 0;
numB--;
numB本身是低水位线,现在numB-- 会使num变成255(由于-1已经超过定义域,所以它会越过-1,变成255),即数据发生下溢(越过下边界,叫下溢)。0–> -1 --> 255 下溢。
可以通过引用 OpenZeppelin的 SafeMath v2.5.x,或者自定义一个SafeMath合约,来避免该问题。
库是 Solidity 中一种特殊的合约,它给原始数据类型增加了一些方法: add(), sub(), mul(), 以及 div()。
先引用或者import SafeMath库,然后声明 using SafeMath for uint256 ,再通过变量名来调用这些方法。
import "./safemath.sol"; //1)引用库
using SafeMath for uint256; //2)声明指定的类型
uint256 a = 5;
uint256 b = a.add(3); // 5 + 3 = 8 //3)用变量名来调用方法
uint256 c = a.mul(2); // 5 * 2 = 10
1、库合约
//safemath.sol
pragma solidity ^0.4.18;
/**
* @title SafeMath
* @dev Math operations with safety checks that throw on error
*/
library SafeMath {
/**
* @dev Multiplies two numbers, throws on overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
assert(c / a == b);
return c;
}
/**
* @dev Integer division of two numbers, truncating the quotient.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
// assert(b > 0); // Solidity automatically throws when dividing by 0
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
/**
* @dev Substracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
assert(b <= a);
return a - b;
}
/**
* @dev Adds two numbers, throws on overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
assert(c >= a);
return c;
}
}
/**
* @title SafeMath32
* @dev SafeMath library implemented for uint32
*/
library SafeMath32 {
function mul(uint32 a, uint32 b) internal pure returns (uint32) {
if (a == 0) {
return 0;
}
uint32 c = a * b;
assert(c / a == b);
return c;
}
function div(uint32 a, uint32 b) internal pure returns (uint32) {
// assert(b > 0); // Solidity automatically throws when dividing by 0
uint32 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
function sub(uint32 a, uint32 b) internal pure returns (uint32) {
assert(b <= a);
return a - b;
}
function add(uint32 a, uint32 b) internal pure returns (uint32) {
uint32 c = a + b;
assert(c >= a);
return c;
}
}
/**
* @title SafeMath16
* @dev SafeMath library implemented for uint16
*/
library SafeMath16 {
function mul(uint16 a, uint16 b) internal pure returns (uint16) {
if (a == 0) {
return 0;
}
uint16 c = a * b;
assert(c / a == b);
return c;
}
function div(uint16 a, uint16 b) internal pure returns (uint16) {
// assert(b > 0); // Solidity automatically throws when dividing by 0
uint16 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
function sub(uint16 a, uint16 b) internal pure returns (uint16) {
assert(b <= a);
return a - b;
}
function add(uint16 a, uint16 b) internal pure returns (uint16) {
uint16 c = a + b;
assert(c >= a);
return c;
}
}
library SafeMath8 {
function mul(uint8 a, uint8 b) internal pure returns (uint8) {
if (a == 0) {
return 0;
}
uint8 c = a * b;
assert(c / a == b);
return c;
}
function div(uint8 a, uint8 b) internal pure returns (uint8) {
// assert(b > 0); // Solidity automatically throws when dividing by 0
uint8 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
function sub(uint8 a, uint8 b) internal pure returns (uint8) {
assert(b <= a);
return a - b;
}
function add(uint8 a, uint8 b) internal pure returns (uint8) {
uint8 c = a + b;
assert(c >= a);
return c;
}
}
2、自增修改
2.1 案例A 简单变量
//原文1
uint numA;
numA++;
//修改1
import "./safemath.sol";
using SafeMath for uint256;
uint numA;
//numA++;
numA = numA.add(1);
2.2 案例B map变量
//原文2
mapping(address => uint) ownerAppleCount;
ownerAppleCount[msg.sender]++;
//修改2
import "./safemath.sol";
using SafeMath for uint256;
mapping(address => uint) ownerAppleCount;
//ownerAppleCount[msg.sender]++;
ownerAppleCount[msg.sender] = ownerAppleCount[msg.sender].add(1);
2.3 案例C 结构体变量
//原文3
struct Apple {
uint32 id;
uint weight;
string color;
}
Apple zhaoApple = Apple(100,150,"red");
zhaoApple.weight++;
//修改3
import "./safemath.sol";
using SafeMath for uint256;
using SafeMath32 for uint32;
struct Apple {
uint32 id;
uint weight;
string color;
}
Apple zhaoApple = Apple(100,150,"red");
//zhaoApple.weight++;
zhaoApple.weight = zhaoApple.weight.add(1);
3、自减修改
3.1 案例D
//原文4
uint8 numB;
numB--;
//修改4
import "./safemath.sol";
using SafeMath8 for uint8;
uint8 numB;
numB--;
numB = numB.sub(1);