前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >2019-01-03 solidity代码性能优化

2019-01-03 solidity代码性能优化

作者头像
oracle3
发布2022-05-13 08:34:44
1880
发布2022-05-13 08:34:44
举报
文章被收录于专栏:oracle3技术大杂烩

最近做一个项目,发现solidity的代码对性能影响非常大,这里把每个版本的代码做了比较

1. 第一个版本,使用string操作

代码语言:javascript
复制
    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. 第二个版本,使用bytes操作

代码语言:javascript
复制
    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. 第三个版本,使用abi.encodePacked 处理bytes

代码语言:javascript
复制
    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)
        }
      } 
    }

性能对比,执行1000次耗时:

版本

方法

耗时(ms)

1

string

3650

2

bytes

2478

3

abi

232

说明solidity代码的优化空间也是非常大的,需要尽可能使用基础的数据类型和系统函数来提升性能

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-05-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 第一个版本,使用string操作
  • 2. 第二个版本,使用bytes操作
  • 3. 第三个版本,使用abi.encodePacked 处理bytes
  • 性能对比,执行1000次耗时:
  • 说明solidity代码的优化空间也是非常大的,需要尽可能使用基础的数据类型和系统函数来提升性能
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档