在撰寫智能合約的時候需要注意的一個主要的安全特性:防止溢位和下溢。為了防止這些情況,OpenZeppelin建立了一個叫做SafeMath的庫(library),默認情況下可以防止這些問題。
什么是溢位(overflow)
假設我們有一個uint8, 只能存盤8 bit資料。這意味著我們能存盤的最大數字就是二進制11111111(或者說十進制的2^8-1 =255).
來看看下面的代碼。最后 number 將會是什么值?

在這個例子中,我們導致了溢位---雖然我們加了1,但是number出乎意料地等于0了。
下溢(underflow)也類似,如果你從一個等于0的uint8減去1, 它將變成255 (因為uint是無符號的,其不能等于負數)。
分析 SafeMath原始碼
1.加法,僅限內部呼叫,回傳 uint256
require(c>=a && c>=b); //驗證結果: 兩個正數相加,和一定大于每個加數

2.減法,僅限內部呼叫,回傳 uint256
require(b <= a) 因為回傳值需要是 正數,所以此處判斷 b必須小于等于a

3.乘法,僅限內部呼叫,回傳 uint256
uint256 c = a * b; 容易溢位,比如 a=2,b=2^255 乘積 2^256 剛好溢位。結果取后面的256位(全為0),導致 c=0。
所以使用 (a == 0 || c / a == b),驗證結果的一致性。

4.除法,僅限內部呼叫,回傳 uint256
require(b > 0), 確保被除數不能為0
require(a == b * c + a % b);防止溢位,驗證結果的一致性

總結:
不要直接使用簡單的 "+-*/" ,盡量使用 library SafeMath 中的函式,避免整數溢位的隱患。
附:完整原始碼
pragma solidity ^0.4.24;
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
* - Addition cannot overflow.
*/
function safeAdd(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
* - Subtraction cannot overflow.
*/
function safeSub(uint256 a, uint256 b) internal pure returns (uint256) {
return safeSub(a, b, "SafeMath: subtraction overflow");
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
* - Subtraction cannot overflow.
*
* NOTE: This is a feature of the next version of OpenZeppelin Contracts.
* @dev Get it via `npm install @openzeppelin/contracts@next`.
*/
function safeSub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
* - Multiplication cannot overflow.
*/
function safeMul(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.
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function safeDiv(uint256 a, uint256 b) internal pure returns (uint256) {
return safeDiv(a, b, "SafeMath: division by zero");
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts with custom message on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
* NOTE: This is a feature of the next version of OpenZeppelin Contracts.
* @dev Get it via `npm install @openzeppelin/contracts@next`.
*/
function safeDiv(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
// Solidity only automatically asserts when dividing by 0
require(b > 0, errorMessage);
uint256 c = a / b;
return c;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function safeMod(uint256 a, uint256 b) internal pure returns (uint256) {
return safeMod(a, b, "SafeMath: modulo by zero");
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts with custom message when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*
* NOTE: This is a feature of the next version of OpenZeppelin Contracts.
* @dev Get it via `npm install @openzeppelin/contracts@next`.
*/
function safeMod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b;
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/30171.html
標籤:區塊鏈技術
上一篇:分布式存盤上的災備資料管理
