区块链学习笔记06 - SafeMath库的使用
首先,为什么使用SafeMath?为避免程序结果产生溢出,开发者应在运算中使用SafeMath。何为溢出?以太坊虚拟机(EVM)为整数指定固定大小的数据类型。这意味着一个整型变量只能有一定范围的数字表示。例如,一个 uint8 ,只能存储在范围 [0,255] 的数字。试图存储 256 到一个 uint8 将变成 0。不加注意的话,只要没有检查用户输入又执行计算,导致数字超出存储它们的...
首先,为什么使用SafeMath?
为避免程序结果产生溢出,开发者应在运算中使用SafeMath。
何为溢出?
以太坊虚拟机(EVM)为整数指定固定大小的数据类型。这意味着一个整型变量只能有一定范围的数字表示。例如,一个 uint8 ,只能存储在范围 [0,255] 的数字。试图存储 256 到一个 uint8 将变成 0。不加注意的话,只要没有检查用户输入又执行计算,导致数字超出存储它们的数据类型允许的范围,Solidity 中的变量就可以被用来组织攻击。
整数溢出的类型包括乘法溢出,加法溢出,减法溢出三种。
解决方案:1.在涉及到运算之前,先进行溢出判断,保证计算出的数据不超出此数据类型的表示范围。2.直接使用SafeMath库函数进行计算。
SafeMath的使用
第一步:导入SafeMath库文件
pragma solidity >=0.4.22 <0.6.0;
/**
* @title SafeMath
* @dev Unsigned math operations with safety checks that revert on error
*/
library SafeMath {
/**
* @dev Multiplies two unsigned integers, reverts on overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b);
return c;
}
/**
* @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
// Solidity only automatically asserts when dividing by 0
require(b > 0);
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
/**
* @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend).
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a);
uint256 c = a - b;
return c;
}
/**
* @dev Adds two unsigned integers, reverts on overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a);
return c;
}
/**
* @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo),
* reverts when dividing by zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b != 0);
return a % b;
}
}
第二步,引用
pragma solidity >=0.4.22 <0.6.0;
import "./safemath.sol";
contract jisuan{
uint a=2;
uint b=5;
uint c=8;
//引入safemath库
using SafeMath for uint256;
//加法
function addNum()public view returns(uint d){
d=a.add(b);
}
//减法
function subNum()public view returns(uint d){
d=b.sub(a);
}
//乘法
function mulNum()public view returns(uint d){
d=a.mul(b);
}
//除法
function divNum()public view returns(uint d){
d=c.div(a);
}
}
using for 的使用
1.与import的联系与区别
import是讲某个合约contract或者某个库lib导入到当前文件,它是using的前提;import后,当前文件内可以引用被引入文件内定义的library或contract。
举个栗子:
这里,如果没有先import,直接using,会报错。除非别的被import的文件再import了它。换句换说,就是
using的前提是需要直接或者间接的导入某个library.
using A for B,这里A通常是某个library里面定义的某个方法,B是某种数据类型,这句话是把A方法绑定到B类型上,相当于给B类型附加了一个A方法。(也有翻译为附着库的)
在上面的例子中,将LibContract里定义的方法绑定到所有的数据类型。但是一般我们不会在所有的类型实例上都去调用LibContract的方法,应该是要按需using的,这里偷懒就写*。
在通俗一点的例子就是,
比如 using LibInt for uint,然后LibInt里面有定义一个toString方法。我们有一个uint a;那么可以这样调用a.toString(),toString方法在定义的时候,第一个参数会是一个uint类型的变量,表示调用者。
using A for B, A的函数的第一个参数必须和B的数据类型一致。
还有这个方法是可以重载的,你可以定义好几个同名的方法,但是第一个参数的类型不同,调用的时候自动的根据调用类型选择某一种方法。
关于using for 可以参考:https://blog.csdn.net/qq_33764491/article/details/80604887
更多推荐
所有评论(0)