全面掌握Solidity智能合约开发

2024年11月25日更新 208 人订阅
原价: ¥ 26 限时优惠
专栏简介 比特币区块结构Merkle树及简单支付验证分析 非对称加密技术- RSA算法数学原理分析 智能合约语言 Solidity 教程系列2 - 地址类型介绍 剖析非同质化代币ERC721-全面解析ERC721标准 搞懂 Solidity 事件Event - 如何在DApp中使用 以太坊扩容 之 分片(Sharding) 智能合约语言 Solidity 教程系列12 - 库的使用 深入理解Plasma(四)Plasma Cash 技术工坊42期 - 区块链子链技术及墨客链的实现方案 脱颖而出 | 成都链安入选『腾讯区块链加速器全球32强』 参与Eth2 Staking系列(2) - 激励篇 应用案例之黄金资产证券化Digix白皮书和DGD解读 全面理解智能合约升级 测试文章123456 简析主流匿名币:Dash、门罗币、Zcash、SERO 以太坊ERC1155协议分析及代码测试 Hyperledger Fabric 1.4 Kafka分布式环境搭建 跟我学 Solidity :开发环境 跟我学 Solidity:关于变量 跟我学 Solidity : 变量的存储 跟我学 Solidity :引用变量 跟我学 Solidity :函数 跟我学 Solidity :合约的创建和继承 跟我学 Solidity :工厂模式 用Web3.js构建第一个Dapp 跟我学Solidity:事件 Solidity 中 immutable (不可变量)与constant(常量) [译] Solidity 0.6.x更新:继承 解析 Solidity 0.6 新引入的 try/catch 特性 探究新的 Solidity 0.8 版本 探索以太坊合约委托调用(DelegateCall) 停止使用Solidity的transfer() 使用工厂提高智能合约安全性 Solidity 怎样写出最节省Gas的智能合约[译] Solidity 优化 - 编写 O(1) 复杂度的可迭代映射 Solidity 优化 - 控制 gas 成本 Solidity 优化 - 减少智能合约的 gas 消耗的8种方法 Solidity 优化 - 如何维护排序列表 Solidity 优化:打包变量优化 gas 在 Solidity中使用值数组以降低 gas 消耗 Solidity 技巧:如何减少字节码大小及节省 gas 计算Solidity 函数的Gas 消耗 "Stack Too Deep(堆栈太深)" 解决方案 合约实践:避免区块Gas限制导致问题 如何缩减合约以规避合约大小限制 Solidity 类特性 安全的处理 ERC20 转账(解决非标准 ERC20 问题) Solidity 十大常见安全问题 [译]更好Solidity合约调试工具: console.log 智能合约开发的最佳实践 - 强烈推荐

在 Solidity中使用值数组以降低 gas 消耗

  • Tiny熊
  • 发布于 2020-08-20 18:53
  • 阅读 1879

本文讨论如何使用值数组(Value Array)替换引用数组(Reference Array)来减少 Solidity 智能合约的gas 消耗。

背景

我们Datona Labs在开发和测试Solidity数据访问合约(S-DAC:Smart-Data-Access-Contract)模板过程中,经常需要使用只有很小数值的小数组(数组元素个数少)。在本示例中,研究了使用值数组(Value Array)是否比引用数组(Reference Array)更高效。

讨论

Solidity支持内存(memory)中的分配数组,这些数组会很浪费空间(参考 文档),而存储(storage)中的数组则会消耗大量的gas来分配和访问存储。但是Solidity所运行的以太坊虚拟机(EVM)有一个256位(32字节)机器字长。正是后一个特性使我们能够考虑使用值数组(Value Array)。在机器字长的语言中,例如32位(4字节),值数组(Value Array)不太可能实用。

我们可以使用值数组(Value Array)减少存储空间和gas消耗吗?

译者注:机器字长 是指每一个指令处理的数据长度。

比较值数组与引用数组

引用数组(Reference Array)

在 Solidity 中,数组通常是引用类型。这意味着每当在程序中遇到变量符号时,都会使用指向数组的指针,不过也有一些例外情况会生成一个拷贝(参考文档-引用类型)。在以下代码中,将10个元素的 8位uint users 的数组传递给setUser函数,该函数设置users数组中的一个元素:

contract TestReferenceArray {
    function test() public pure {
        uint8[10] memory users;

        setUser(users, 5, 123);
        require(users[5] == 123);
    }

    function setUser(uint8[10] memory users, uint index, uint8 ev) 
    public pure {
        users[index] = ev;
    }
}

函数返回后,users数组元素将被更改。

值数组(Value Arrays)

值数组是以值类型保存的数组。这意味着在程序中遇到变量符号,就会使用其值。

contract TestValueArray {
    function test() public pure {
        uint users;

        users = setUser(users, 5, 12345);
        require(users == ...);
    }

    function setUser(uint users, uint index, uint ev) public pure 
    returns (uint) {
        return ...;
    }
}

请注意,在函数返回之后,函数的users参数将保持不变,因为它是通过值传递的,为了获得更改后的值,需要将函数返回值赋值给users变量。

Solidity bytes32 值数组

Solidity 在 bytesX(X=1..32)类型中提供了一个部分值数组。这些字节元素可以使用数组方式访问单独读取,例如:

    ...
    bytes32 bs = "hello";
    byte b = bs[0];
    require(bs[0] == 'h');
    ...

但不幸的是,在Solidity 目前的版本中,我们无法使用数组访问方式写入某个字节:

    ...
    bytes32 bs = "hello";
    bs[0] = 'c'; // 不可以实现
    ...

让我们使用Solidity的 using for 导入库的方式为bytes32类型添加新能力:

library bytes32lib {
    uint constant bits = 8;
    uint constant elements = 32;

    function set(bytes32 va, uint index, byte ev) internal pure 
    returns (bytes32) {
        require(index < elements);
        index = (elements - 1 - index) * bits;
        return bytes32((uint(va) & ~(0x0FF << index)) | 
                        (uint(uint8(ev)) << index));
    }
}

这个库提供了set()函数,它允许调用者将bytes32变量中的任何字节设置为想要的字节值。根据你的需求,你可能希望为你使用的其他bytesX类型生成类似的库。

测试一把

让我们导入该库并测试它:

import "bytes32lib.sol";

contract TestBytes32 {
    using bytes32lib for bytes32;

    function test1() public pure {
        bytes32 va = "hello";
        require(va[0] == 'h');
        // 类似 va[0] = 'c'; 的功能
        va = va.set(0, 'c');
        require(va[0] == 'c');
    }
}

在这里,你可以清楚地看到set()函数的返回值被分配回参数变量。如果缺少赋值,则变量将保持不变,require()就是来验证它。

可能的固定长度值数组

在Solidity机器字长为256位(32字节),我们可以考虑以下可能的值数组。

固定长度值数组

这些是以些Solidity可用整型匹配的固定长度的值数组:


                         固定长度值数组
类型          类型名       描述
uint128[2]   uint128a2   2个128位元素的值数组
uint64[4]    uint64a4    4个64位元素的值数组
uint32[8]    u...

剩余50%的内容订阅专栏后可查看

点赞 1
收藏 0
分享

0 条评论

请先 登录 后评论