solidity 語言安全·整型溢出

本文節選自《Netkiller Blockchain 手札》

 

Netkiller Blockchain 手札

Mr. Neo Chan, 陳景峯(BG7NYT)

中國廣東省深圳市龍華新區民治街道溪山美地 518131 +86 13113668890 <netkiller@msn.com>html

文檔始創於2018-02-10git

版權 © 2018 Netkiller(Neo Chan). All rights reserved.github

版權聲明web

轉載請與做者聯繫,轉載時請務必標明文章原始出處和做者信息及本聲明。運維

內容摘要函數

這一部關於區塊鏈開發及運維的電子書。區塊鏈

爲何會寫區塊鏈電子書?由於2018年是區塊鏈年,區塊鏈是一個風口,前幾個風口我都錯過了。例如web2.0, 雲, 大數據等等,都從身旁擦肩而過。因此我要抓住此次。測試

這本電子書是否會出版(紙質圖書)? 不會,由於互聯網技術更迭太快,紙質書籍的內容沒法實時更新,一本書動輒百元,很快就成爲垃圾,你會發現目前市面的上區塊鏈書籍至少是一年前寫的,內容已通過時,不少例子沒法正確運行。因此我不會出版,電子書的內容會追逐技術發展,及時跟進軟件版本的升級,作到內容最新,至少是主流。大數據

這本電子書與其餘區塊鏈書籍有什麼不一樣?市面上大部分區塊鏈書籍都是用2/3去講區塊鏈原理,只要不到 1/3 的乾貨,乾貨不夠理論來湊,通篇將理論或是大談特談區塊鏈行業,這些內容更可能是頭腦風暴,展望區塊鏈,均沒法落地實施。本書與那些書籍徹底不一樣,不講理論和原理,面向應用落地,注重例子,均是乾貨。ui

寫做原則,沒法落地的項目做者絕對不會寫。凡是寫入電子的內容均具有可操做,可落地。

電子書更新頻率?天天都會有新內容加入,更新頻率最遲不會超過一週,更新內容請關注 https://github.com/netkiller/netkiller.github.io/commits/master

本文采用碎片化寫做,原文會不按期更新,請儘可能閱讀原文 http://www.netkiller.cn/blockchain/index.html

您的打賞是個人寫做動力:http://www.netkiller.cn/blockchain/donations.html

接受 ETH 打賞:0x3e827461Cc53ed7c75A29187CfF39629FCAE3661

 

什麼是整型溢出呢?在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)  => 拋出異常
相關文章
相關標籤/搜索