2019-01-03 solidity代碼性能優(yōu)化

最近做一個(gè)項(xiàng)目谁撼,發(fā)現(xiàn)solidity的代碼對(duì)性能影響非常大柿究,這里把每個(gè)版本的代碼做了比較

1. 第一個(gè)版本摊鸡,使用string操作


    function KVStoragePut(string key, string value) public whenNotPaused onlyUser returns(uint256[1] p) {
      bytes32[] memory keyBytes = StrToBytes32Array(key);
      uint256 keyLen = keyBytes.length;
      
      bytes32[] memory valueBytes = StrToBytes32Array(value);
      uint256 valueLen = valueBytes.length;
      
      uint256[] memory input = new uint256[](1 + keyLen + 1 + valueLen + 1);
      input[0] = keyLen;
      for(uint256 i=0;i<keyLen;i++) {
          input[i+1] = (uint256)(keyBytes[i]);
      }
      
      input[1 + keyLen] = valueLen;
      for(i=0;i<valueLen;i++) {
          input[i+2+keyLen] = (uint256)(valueBytes[i]);
      }
      
      uint256 len = (1 + keyLen + 1 + valueLen + 1) * 32;
      assembly {
        // call KVStoragePut precompile
        if iszero(call(not(0), 0x0a, 0, input, len, p, 0x20)) {
          revert(0, 0)
        }
      } 
    }

    function StrToBytes32Array(string p_str) internal pure returns(bytes32[]){
        bytes  memory lbts_para;  //the result of convert p_str to bytes
        uint li_paralength;   //lbts_para's length
        string memory ls_new; //the result of convert ont bytes32 to string
        bytes32 lbt_row;      // the new bytes32 data  
        bytes32[] memory lbt_result32;    //the return bytes32 array     
        uint li_rowcount; // bytes32 array's length
        uint li_temp;  
        uint li_sum; //the total byte32 array's bytes amount
        uint li_colidx;  //the new column's index
        uint li_resultlength ; // the result bytes32 array's length 

        lbts_para = bytes(p_str); //ex:'1234' = 0x31323334
        li_paralength = lbts_para.length;  //ex: 4 
        bytes memory lbts_new = new bytes(32); //for store to arrays32 array
        // lbt_result32.length=0; //ininial the array32 array
        
        if (li_paralength <= 32 ){  //if actul data length is less equal than 32,use assemble method
             assembly {
              lbt_row := mload(add(p_str, 32))
            }
            // lbt_result32.length = 1;
            lbt_result32 = new bytes32[](1);
            lbt_result32[0] = lbt_row; 
        } else {
            //li_rowcount :calculate the bytes32 array's length
            li_rowcount = li_paralength/32;
            li_temp = li_paralength%32;
            if (li_temp > 0 )
                li_rowcount = li_rowcount +1;
            //li_sum :the total bytes amount of bytes32 array
            lbt_result32 = new bytes32[](li_rowcount);

            li_sum = li_rowcount *32;
            li_colidx = 0;
            for (uint p = 1;p<= li_sum;p++){
                //decide whether to add a new row
                li_temp = p%32;  //if equal 0,add a new row
                if (li_temp == 0 ){
                    if (p > li_paralength) 
                        lbts_new[li_colidx] = 0x0;
                    else
                        lbts_new[li_colidx] = lbts_para[p - 1];
                    li_colidx = 0;
                    ls_new = string(lbts_new);
                    assembly {
                        lbt_row := mload(add(ls_new, 32))
                    }
                    // li_resultlength = lbt_result32.length ;
                    li_resultlength = li_resultlength +1;
                    // lbt_result32.length = li_resultlength;
                    lbt_result32[li_resultlength - 1] = lbt_row;
                }else {
                    if (p > li_paralength) 
                        lbts_new[li_colidx] = 0x0;
                    else
                        lbts_new[li_colidx] = lbts_para[p - 1];
                    li_colidx = li_colidx +1;
                }

            }

        }

        return lbt_result32;

    }


2. 第二個(gè)版本渗饮,使用bytes操作

    function KVStoragePut(bytes key, bytes value) public whenNotPaused onlyUser returns(uint256[1] p) {
      bytes32[] memory keyBytes = StrToBytes32Array(key);
      uint256 keyLen = keyBytes.length;
      
      bytes32[] memory valueBytes = StrToBytes32Array(value);
      uint256 valueLen = valueBytes.length;
      
      uint256[] memory input = new uint256[](1 + keyLen + 1 + valueLen + 1);
      input[0] = newKey.length;
      for(uint256 i=0;i<keyLen;i++) {
          input[i+1] = (uint256)(keyBytes[i]);
      }
      
      input[1 + keyLen] = value.length;
      for(i=0;i<valueLen;i++) {
          input[i+2+keyLen] = (uint256)(valueBytes[i]);
      }
      
      uint256 len = (1 + keyLen + 1 + valueLen + 1) * 32;
      assembly {
        // call KVStoragePut precompile
        if iszero(call(not(0), 0x0a, 0, input, len, p, 0x20)) {
          revert(0, 0)
        }
      } 
    }
 
    function StrToBytes32Array(bytes lbts_para) internal pure returns(bytes32[]){
        // bytes  memory lbts_para;  //the result of convert p_str to bytes
        uint li_paralength;   //lbts_para's length
        string memory ls_new; //the result of convert ont bytes32 to string
        bytes32 lbt_row;      // the new bytes32 data  
        bytes32[] memory lbt_result32;    //the return bytes32 array     
        uint li_rowcount; // bytes32 array's length
        uint li_temp;  
        uint li_sum; //the total byte32 array's bytes amount
        uint li_colidx;  //the new column's index
        uint li_resultlength ; // the result bytes32 array's length 

        // lbts_para = bytes(p_str); //ex:'1234' = 0x31323334
        li_paralength = lbts_para.length;  //ex: 4 
        bytes memory lbts_new = new bytes(32); //for store to arrays32 array
        // lbt_result32.length=0; //ininial the array32 array
        
        if (li_paralength <= 32 ){  //if actul data length is less equal than 32,use assemble method
             assembly {
              lbt_row := mload(add(lbts_para, 32))
            }
            // lbt_result32.length = 1;
            lbt_result32 = new bytes32[](1);
            lbt_result32[0] = lbt_row; 
        } else {
            //li_rowcount :calculate the bytes32 array's length
            li_rowcount = li_paralength/32;
            li_temp = li_paralength%32;
            if (li_temp > 0 )
                li_rowcount = li_rowcount +1;
            //li_sum :the total bytes amount of bytes32 array
            lbt_result32 = new bytes32[](li_rowcount);

            li_sum = li_rowcount *32;
            li_colidx = 0;
            for (uint p = 1;p<= li_sum;p++){
                //decide whether to add a new row
                li_temp = p%32;  //if equal 0,add a new row
                if (li_temp == 0 ){
                    if (p > li_paralength) 
                        lbts_new[li_colidx] = 0x0;
                    else
                        lbts_new[li_colidx] = lbts_para[p - 1];
                    li_colidx = 0;
                    ls_new = string(lbts_new);
                    assembly {
                        lbt_row := mload(add(ls_new, 32))
                    }
                    // li_resultlength = lbt_result32.length ;
                    li_resultlength = li_resultlength +1;
                    // lbt_result32.length = li_resultlength;
                    lbt_result32[li_resultlength - 1] = lbt_row;
                }else {
                    if (p > li_paralength) 
                        lbts_new[li_colidx] = 0x0;
                    else
                        lbts_new[li_colidx] = lbts_para[p - 1];
                    li_colidx = li_colidx +1;
                }

            }

        }

        return lbt_result32;

    }

3. 第三個(gè)版本,使用abi.encodePacked 處理bytes

    function KVStoragePut(bytes key, bytes value) public whenNotPaused onlyUser returns(uint256[1] p) {
      bytes memory input = abi.encodePacked((int8)(key.length),key,(int8)(value.length),value);
      
      uint256 len = input.length + 32;
      
      assembly {
        // call KVStoragePut precompile
        if iszero(call(not(0), 0x0a, 0, input, len, p, 0x20)) {
          revert(0, 0)
        }
      } 
    }

性能對(duì)比呆抑,執(zhí)行1000次耗時(shí):

版本 方法 耗時(shí)(ms)
1 string 3650
2 bytes 2478
3 abi 232

說(shuō)明solidity代碼的優(yōu)化空間也是非常大的岂嗓,需要盡可能使用基礎(chǔ)的數(shù)據(jù)類型和系統(tǒng)函數(shù)來(lái)提升性能

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市鹊碍,隨后出現(xiàn)的幾起案子厌殉,更是在濱河造成了極大的恐慌,老刑警劉巖侈咕,帶你破解...
    沈念sama閱讀 211,348評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件公罕,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡耀销,警方通過(guò)查閱死者的電腦和手機(jī)楼眷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,122評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人罐柳,你說(shuō)我怎么就攤上這事掌腰。” “怎么了张吉?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,936評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵齿梁,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我肮蛹,道長(zhǎng)勺择,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,427評(píng)論 1 283
  • 正文 為了忘掉前任蔗崎,我火速辦了婚禮酵幕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘缓苛。我一直安慰自己芳撒,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,467評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布未桥。 她就那樣靜靜地躺著笔刹,像睡著了一般。 火紅的嫁衣襯著肌膚如雪冬耿。 梳的紋絲不亂的頭發(fā)上舌菜,一...
    開(kāi)封第一講書(shū)人閱讀 49,785評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音亦镶,去河邊找鬼日月。 笑死,一個(gè)胖子當(dāng)著我的面吹牛缤骨,可吹牛的內(nèi)容都是我干的爱咬。 我是一名探鬼主播,決...
    沈念sama閱讀 38,931評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼绊起,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼精拟!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起虱歪,我...
    開(kāi)封第一講書(shū)人閱讀 37,696評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤蜂绎,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后笋鄙,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體师枣,經(jīng)...
    沈念sama閱讀 44,141評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,483評(píng)論 2 327
  • 正文 我和宋清朗相戀三年萧落,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了践美。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片劳殖。...
    茶點(diǎn)故事閱讀 38,625評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖拨脉,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情宣增,我是刑警寧澤玫膀,帶...
    沈念sama閱讀 34,291評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站爹脾,受9級(jí)特大地震影響帖旨,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜灵妨,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,892評(píng)論 3 312
  • 文/蒙蒙 一解阅、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧泌霍,春花似錦货抄、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至藤为,卻和暖如春怪与,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背缅疟。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工分别, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人存淫。 一個(gè)月前我還...
    沈念sama閱讀 46,324評(píng)論 2 360
  • 正文 我出身青樓耘斩,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親纫雁。 傳聞我的和親對(duì)象是個(gè)殘疾皇子煌往,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,492評(píng)論 2 348