Solidity开发模式 - 紧密变量打包

使用 OpenZeppelin 和 Ethers.js 在 Solidity 中使用 ECDSA 验证链下结果和白名单 使用 OpenZeppelin 和 Ethers.js 在 Solidity 中使用 ECDSA 验证链下结果和白名单 介绍 作为一名区块链开发者或该领域的热衷者,我们应该对以太坊的高gas问题并不陌生。以太坊的价格坚挺在3000美元区域,而Gas 价格平均上涨 50-70 Gwei,每笔交易的 Gas 费用越来越贵,一次简单的转账大约需要 4 美元。 有一个解决gas问题的方法,就是把这个计算放到链下,让服务器来做这个工作。 许多在线ECDSA教程涉及到数学的使用,关于s, r, v的一些东西,我们所 阅读详情

本文是Solidity开发模式系列第三篇

目的

优化存储加载定长变量的gas消耗

动机

这个模式的主要目的就是节约gas。这种特殊模式很容易应用,它不会影响任何合约逻辑。所要做的就是按照正确顺序声明状态变量。我们利用EVM分配存储的方式,减少合约部署gas,以及方法调用成本。以太坊存储是一个键值存储,键值都为32字节。分配存储时,所有定长变量(除了映射和动态数组)都会按声明顺序从位置0开始依次写下。最常用数据类型(例如byte32, uint, int)只占用一个32字节插槽。此模式介绍如何尽可能使用较小的数据类型(例如byte16,uint32)来节省gas,因为EVM可以将它们打包在一个32字节的插槽里,从而减少存储。EVM也会将多个多个读写合并到一个操作中,从而节约gas。这个底层行为被称为"紧密打包",不幸的是,目前,优化器还不会自动实现这种行为。

适用性

在以下条件时使用紧密变量打包模式

  • 希望降低合约交互成本。
  • 使用多个状态变量,并且可以使用较小的数据类型代替。
  • 使用由多个变量构成的结构,并且可以使用较小的数据类型代替。
  • 使用静态数组,并且可以使用较小的数据类型代替。

参与者和协作

一般来说,这个模式唯一的参与者是实现它的合约。与合约交互的其它所有实体都不会受到影响,因为只改变了数据的存储方式。

实现

正如"适用性"一节所述,此模式可用于状态变量,结构体内部和静态数组。它的实现非常直接,分为两步:

  1. 使用保证代码正确执行的最小数据类型。例如,德国的邮政编码最多有5为数字。因此,uint16数据类型(uint16最多表示数字216-1=65535)不够,需要使用```uint24```类型的变量(```uint24```最多表示数字224-1=16777215),足够保存所有邮政编码。

  2. 将同一组的数据类型放到一个32字节的插槽中,并在代码中逐个声明它们。将数据类型分组很重要,因为EVM按照给定顺序逐个保存变量。这只适用于状态变量和结构体内部。数组只有一种数据类型,不需要顺序。
    将尽量多的变量存储在一个插槽中,只要它们的存储总小于等于32字节大小。例如,一个bool变量占用一个字节,uint8也是一个字节,uint16是两个字节,uint32是四个字节,依次类推。字节数据类型的存储大小更容易,例如,byte4就是四个字节。所以32个uint8变量的存储空间和1个uint256变量相同。只有当变量依次声明才有效,因为如果必须在变量间保存一个大数据类型,则需要新插槽。

代码示例

下面例子展示了本模式在结构体中的应用

// This code has not been professionally audited, therefore I cannot make any promises about
// safety or correctness. Use at own risk.
contract StructPackingExample {
    
    struct CheapStruct {
        uint8 a;
        uint8 b;
        uint8 c;
        uint8 d;
        bytes1 e;
        bytes1 f;
        bytes1 g;
        bytes1 h;
    }
    
    CheapStruct example;
    
    function addCheapStruct() public {
        CheapStruct memory someStruct = CheapStruct(1,2,3,4,"a","b","c","d");
        example = someStruct;
    }
}

第5行声明了一个使用本模式的结构体对象。这8个变量每个需要一个字节的存储空间,并且没有被更大的数据类型打断,因此它们会被打包进一个存储槽中,并使用32个字节中的8个。这意味着我们在这个存储槽中还可以添加更多的变量。第19行,首先初始化一个结构体对象,然后写入第20行的存储器中。

Gas分析

为了量化所需gas的潜在减少量,使用在线Solidity编译器Remix进行测试。上面示例代码与存储相同输入数据但不使用最小数据类型方案进行对比,并改变变量顺序以阻止EVM采用紧密打包的方式。因此,8个变量将使用8个存储槽。实验代码可以在GitHub上。结果如下表所示:

Tightly Packed StructStruct without Tight Packing
Contract Creation133172116560
Saving Struct to Storage57821161636

当不适用最小数据类型时,合约创建的gas成本大约便宜12%。这可以解释,因为EVM通常一次操作32个字节。它需要额外的操作来将变量大小变为最小数据类型大小,这个例子中是从byte32变为byte1,这需要额外的gas。当合约保存结构体变量时,这个成本得到补偿。这个示例中,我们节省了7个存储槽,相当于节省了大约64%的gas。这些gas不仅只节省一次,每次保存一个新结构体都会节省一次。

结果

在盲目实施之前,必须评估采用本模式的结果。巨大的好处是在合约生命周期内可能节省大量的gas。但如果没有实现正确,也可能达到相反的,花费更多gas的结果。它只适用于静态大小的状态变量。方法参数和动态大小的数组并不能获益。相反,正如Gas分析部分合约创建成本显示,EVM操作最小数据类型成本更高。重新排列变量的顺序会导致另个问题,降低可读性。变量通常按照逻辑顺序声明,更改这个顺序会使审核代码更加困难,并使用户和开发人员感到困惑。

已知应用

这种模式的实现很难被发现,因为很难区分变量类型和顺序的选择是基于紧密打包还是其它原因。直到目前,还没有一个合约被发现是经过深思熟虑使用这个模式。一个值得注意的例子是Roshambo,一个石头剪刀布的游戏,移动和决胜局保存在一个结构体的uint8变量中,这允许紧密打包。但是看起来这个设计决策并没有考虑本模式,因为它还可以做进一步优化。

另个例子是Etherization合约,一个类似文明游戏的去中心化应用。在这个合约中,每个玩家保存在一个结构体中。它可以采用最小数据类型,甚至可能不用破坏游戏逻辑。如果这样做,保存一个新玩家的gas消耗会显著降低。


更多Solidity开发模式

智能合约从入门到精通:Solidity语法之内存变量的布局和状态变量的存储模型 简介:在前面我们已经讲过Solidity语言的一些语法内容,在矩阵元JUICE开放平台的JIDE开发时,一定要注意Layout in Memory和Layout of State Variables in Storage,即内存变量的布局和状态变量的存储模型。内存变量的布局(Layout in Memory)Solidity预留了3个32字节大小的槽位:0-64:哈希方法的暂存空间(scratch... 阅读详情

相关推荐

以太坊智能合约Solidity的优化

存储中状态变量 静态大小的变量(除映射和动态大小的数组类型之外的所有内容)在从位置开始的存储中连续布局0。根据以下规则,如果可能,将需要少于32个字节的多个项目打包到单个存储槽中: • 存储槽中的第一项存储为低阶对齐。 • 基本类型仅使用存储它们所需的许多字节。 • 如果基本类型不适合存储槽的剩余部分,则将其移动到下一个存储槽。 • 结构和数组数据总是从一个新的槽开始并占据整个槽(但是根据这些规则...

u012310362的博客 1669

Solidity--如何实现椭圆算法签名(ECDSA)

椭圆算法签名椭圆曲线算法签名(ECDSA)是一种数字签名算法,其基于椭圆曲线密码学(ECC)。它是一种非对称密码算法,即发送方和接收方都有不同的密钥。在数字签名中,发送方使用它的私钥对数据进行签名,以证明数据的完整性和发送方身份。接收方可以使用发送方的公钥验证签名,以确认数据没有被篡改。ECDSA在许多方面都优于其他数字签名算法,例如RSA,因为它更加安全且计算效率更高。然而,它也有一些缺点,例如密钥长度必须比RSA大得多,以达到相同的安全级别。

知识的共享,拓宽视野,深化思考,获得新的启发. 3006

智能合约语言Solidity Solidity API

链客,专为开发者而生,有问必答! 此文章来自链客区块链技术问答社区,未经允许拒绝转载。 Solidity 是以太坊智能合约编程语言,阅读本文前,你应该对以太坊、智能合约有所了解,如果你还不了解,建议你先看以太坊是什么? Solidity API 主要表现为Solidity 内置的特殊的变量及函数,他们存在于全局命名空间里,主要分为以下几类: 有关区块和交易的属性 ABI编码函数 有关错误处理 有...

weixin_44172023的博客 345

solidity-以太坊区块链Truffle-webpack开发入门 (十) 管理包和打包EthPM

管理包和打包 原文地址 EthPM是Ethereum一个新的包管理工具,遵循ERC190 spec的智能合约的规则,而且支持Ethereum的很多开发工具 使用EthPM安装包: $ truffle install <package name> 指定版号: $ truffle install <package name>@<version>...

u012360598的专栏 497

【Solidity】4.单位和全局可变量 - 深入理解Solidity

单位和全局可变量Ether单元一个字面上的数字可以带有wei,finney,szabo或者以太网的后缀,可以在以太网的子目录之间进行转换,其中没有后缀的以太网货币号被假定为魏。 2 ether == 2000 finney评估为true。时间单位可以使用文字数字后的秒,分,小时,天,周和年份进行后缀转换,其中以秒为单位,以下列方式将单位视为天真的时间单位: 1 == 1 seconds 1 minu

Code Metaverse 8605

拆开一个烧坏的IGBT模块,手把手教你识别过压、过流、过温的“案发现场”

本文详细解析了IGBT模块失效分析的实战技巧,通过观察铝层熔化纹路、焊锡溢出形态等物理痕迹,手把手教你识别过压、过流、过温的典型失效模式。文章提供了从基础工具包到现场快速诊断的完整流程,帮助工程师精准定位IGBT模块失效的根本原因。

weixin_30655569的博客 423

solidity-以太坊区块链Truffle-webpack开发入门 (八) 合约交互 Interact

合约交互 原文地址 合约交互的操作可以定义为两类: read和write 在合约中 read 操作被称作 call ,write 操作被称为 transaction call操作不会花费coin(钱,这里被称为‘gas’),写操作会花费gas 总结transaction的特点就是: 花费gas 改变网络状态 不会立刻处理完成 但是会返回一个transaction的I...

u012360598的专栏 1161

Ubuntu22.04安装ROS1

代表使用 2 线程进行编译,可以根据 CPU 适当调整。如果出现小乌龟窗口,说明安装成功 🎉!启动成功,则打开另一个终端,测试。需要解决一些兼容性问题,因为。由于 Ubuntu 22.04。过程,确保成功安装。

asafriend的博客 4642

自己整理的,剪刀石头布的代码,应该可以用

石头剪刀布

Jasoncong111的博客 291

基于FPGA的工业相机项目大赏1——cmos线阵相机

●CMOS CL0402 作为图像传感芯片,曝光后产生一定格式的图像数据;●FPGA ZYNQ7020 作为主控芯片负责cmos驱动控制、图像像素的采集、cmos寄存器的配置、cameralink协议的实现、上位机串口通信的实现;●Cameralink端子实现图像数据的高速串行发送,将数据传送至采集卡PC端。系统工作流程如下: FPGA 上电加载配置程序,计算机通过异步串口向 FPGA 发送控制信息,FPGA对接收的控制信息进行分析判断。

weixin_41895751的博客 6397

国科大——形式语言与自动机理论(0812课程)——作业

此次作业题考察,包括但不限于有限自动机、无限自动机、正则文法、正则表达式以及正则语言的性质,题考查下推自动机相关的知识,题考查图灵机相关的知识。此课程建议本科学习过课程的同学选修,成绩占比:考试100%。此课程虽然留有作业,但可做也可不做,且不考勤。

qq_54145399的博客 705

Solidity开发模式

前面写了智能合约开发模式总结了针对智能合约开发的通用模式,原文中还有一些模式只适用于Solidity开发,选出认为不错的几篇翻译整理。 本文介绍的每个模式都含有实例代码(Solidity 0.4.20)和详细说明。 安全转账 - 确保安全转账以太币 内存数组构建 - 高效地使用gas从合约中汇总或提取数据 紧密变量打包 - 优化存储加载定长变量的gas消耗 参考文章 Solidity Patter...

feifeilb的博客 243

比特大陆校招笔试

我当时做的时候没有概念(上边倒计时我一直以为是一个模块的),所以第一个模块写的太长了导致最后才留15分钟快速选的(一共18道题),有一题最后没有选上,两题没有认真看题目瞎选的,求求求过过过!选择题:主要考高中物理题、数学题(念过高中的一定会,但是需要时间算,需要留25分钟左右的时间做)第一道就是写个人的内容,什么最近读过的书,最近的感受等等;分为两个模块,考试内容超级无敌简单,但是注意时间掌握。注意这里别花太长的时间,不然后边来不及。第二道逻辑分析题,需要你写解答。

Domainwa的博客 668

智能合约语言 Solidity 教程系列8 - Solidity API

这是Solidity教程系列文章第8篇介绍Solidity API,它们主要表现为内置的特殊的变量及函数,存在于全局命名空间里。 写在前面 Solidity 是以太坊智能合约编程语言,阅读本文前,你应该对以太坊、智能合约有所了解, 如果你还不了解,建议你先看以太坊是什么 欢迎订阅区块链技术专栏阅读更全面的分析文章。 Solidity API 主要表现为Solidity 内置的特殊的变量及...

深入浅出区块链 1391

高性能网站设计之缓存更新的套路

看到好些人在写更新缓存数据代码时,先删除缓存,然后再更新数据库,而后续的操作会把数据再装载的缓存中。然而,这个是逻辑是错误的。试想,两个并发操作,一个是更新操作,另一个是查询操作,更新操作删除缓存后,查询操作没有命中缓存,先把老数据读出来后放到缓存中,然后更新操作更新了数据库。于是,在缓存中的数据还是老的数据,导致缓存中的数据是脏的,而且还一直这样脏下去了。 我不知道为什么这么多人用的都是这

代码技巧 1万+

Altium Designer应用技巧1: 功能模块的复用方法

Altium Designer应用技巧1: 功能模块的复用方法      我们在使用Altium Designer进行电路图设计时,常会遇到功能模块的复用问题,例如我们经常需要将12V以DC-DC的方式转换成5V,这在很多线路板上都会应用到。现在我们普通的做法是,每个板子都重新绘制一遍,像这样DC-DC的电路,很浪费时间。那么如何采用提高工作效率呢?我们可以采取Altium Desi

snmplink的博客 1万+

深入理解Solidity——存储中状态变量的布局

存储中状态变量的布局(Layout of State Variables in Storage) 静态尺寸大小的变量(除了映射和动态尺寸大小的数组类型(的其他类型变量))在存储中,是从位置0连续存储。如果可能的话,不足32个字节的多个条目被紧凑排列在一个单一的存储块,参见以下规则: 在存储块中的第一项是存储低阶对齐的。 基本类型只使用了正好存储它们的字节数。 如果一个基本类型不适合存储块的剩...

黄嘉成的博客 1818

20 硬件工程师笔面试高频考点真题解析——寄存器

摘要: 寄存器是由多个边沿触发的D触发器组成的多位存储单元,用于同步时序电路中的数据暂存、隔离毛刺、跨时钟域同步等。选型需考虑位宽、触发方式(边沿/电平)、异步控制、电气参数等。核心时序参数包括建立时间(Tsu)、保持时间(Thold)和时钟输出延迟(Tco)。寄存器广泛应用于时序逻辑、流水线分割、毛刺消除、跨时钟域同步及计数分频等场景。同步复位依赖时钟边沿,时序易收敛但需时钟支持;异步复位独立于时钟,上电可靠但需注意亚稳态风险。

XU157303764的博客 1342

最全Solidity面试问题及答案

顺序:检查条件 → 修改状态 → 外部调用,防止重入攻击。ERC20 授权抢跑攻击使用anonymous关键字声明的事件,不存储事件签名到日志主题,节省gas但无法按事件类型过滤。自定义错误:keccak256(Error(string))[:4]+ 参数,require错误字符串:Error(string)全哈希。前者gas更省。代理合约从信标合约动态获取实现地址,允许批量升级多个代理的指向。EIP-3448定义的MetaProxy,使用最小字节码代理模式,通过CREATE2实现确定性部署地址。

Theoweb3|优快云 wwh1st|GitHub theoweb3|TG theo_liu|X theoweb33|gmail wwh9th 华语区Web3基础设施建设者;Web3开源社区共建者;博客沉淀去中心化等各类工程经验。 1392

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

Solidity 审计预算有限:优先检查资产流向和权限入口

区块链项目的安全审计费用动辄数万甚至数十万美元,对于预算有限的开发团队或初创项目而言,试图在早期覆盖全部形式化验证与顶尖机构的人工全量审计并不现实。资金有限的情况下,把预算投给哪些环节能带来最高的安全收益与性能回报?本文从智能合约代码编写、自动化安全审计工具链配置以及核心 Gas 优化策略入手,拆解一条高效且低成本的安全落地路径。

qq_40635035的博客 5330

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

智能合约语言 Solidity Solidity API

想知道更多关于区块链技术知识,请百度【链客区块链技术问答社区】 链客,有问必答!! Solidity 是以太坊智能合约编程语言,阅读本文前,你应该对以太坊、智能合约有所了解,如果你还不了解,建议你先看以太坊是什么? Solidity API 主要表现为Solidity 内置的特殊的变量及函数,他们存在于全局命名空间里,主要分为以下几类:...

weixin_34343308的博客 124

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

零基础入门Solidity:Awesome Web3中的智能合约开发指南

Solidity是一种面向对象的高级编程语言,专为在以太坊区块链上实现智能合约而设计。作为Awesome Web3项目中核心的智能合约开发语言,Solidity让开发者能够构建去中心化应用(DApps)的后端逻辑,从简单的代币到复杂的DeFi协议。本指南将带你从零开始掌握Solidity的基础知识,并利用Awesome Web3资源库快速上手智能合约开发。 [![Awesome Web3资源概览

gitblog_00126的博客 296
上一篇: Solidity开发模式 - 内存数组构建
下一篇: Solidity开发模式
feifeilb
博客等级 码龄22年 22粉丝 38原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值