当前位置: 首页 > news >正文

区块链审计 如何测试solidity的bool值占用几个字节

文章目录

  • 艾里卡的bool类型有多大?
    • 代码环节
  • 艾丽卡更精确的测试bool
    • 代码环节
  • bool的gas疑惑?


艾里卡的bool类型有多大?

木森和艾丽卡坐在他们的实验室里,面前摆着一本魔法书和一些奇怪的魔法工具。他们正在进行一项重要的研究——探索Solidity智能合约中不同数据类型占用的存储空间。

木森(兴奋地):“艾丽卡,看!我们已经设置好了实验环境。现在,我们要测试一下bool类型在智能合约中占用多少字节。”

艾丽卡(好奇地):“木森,什么是字节?能吃吗?”

木森(耐心地):“不,艾丽卡,字节不是食物。在魔法编程的世界里,字节是我们存储信息的基本单位。就像我们的魔法书,每一页都能记录很多魔法咒语。”

艾丽卡(恍然大悟):“哦,我明白了!那我们怎么开始测试呢?”

木森(指着电脑屏幕):“首先,我们要在Solidity中创建一个简单的合约,里面包含一个bool类型,还有一些其他类型的变量。”

艾丽卡(兴奋地):“然后呢?”

木森(认真地):“然后我们用一个神奇的命令,叫做cast storage,它会告诉我们每个变量在存储中的地址。”

艾丽卡(跳起来):“哇!那我们快试试吧!”

木森(输入命令):“好的,我已经输入了命令。现在,我们看看结果。”

他们等待了一会儿,电脑屏幕上显示出了结果。

木森(分析结果):“看,艾丽卡!bool类型和uint8类型占用的存储空间是一样的,都是一个字节。”

艾丽卡(惊讶地):“真的吗?那其他的数字类型呢?”

木森(继续分析):“我们可以用同样的方法测试uint16、uint32、uint64、uint128和uint256。每种类型占用的存储空间都是不同的。”

代码环节

示例:以下的一切测试是基于foundry环境搭建的

// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;contract Booltest{bool private x;uint8 private y =1;uint32 private z =0x22;
}

我们先编写一个最简单的合约,在这里只有一个bool类型以及后面的uint8和uint32类型,我们首先测试它占用多少字节。现在让我们运行,

cast storage 0x5FbDB2315678afecb367f032d93F642f64180aa3  0 --rpc-url http://127.0.0.1:8545   
0x0000000000000000000000000000000000000000000000000000000000220100

可以发现bool类型占用的是0x00,紧随其后的是unit8,它正好是0x01,0001他们都是两位,可以看出它们的大小是相同的。

艾丽卡更精确的测试bool

艾丽卡(兴奋地):“哇,那我们快试试吧!”

木森在魔法终端上输入了咒语,然后他们看到了结果:

0x0000000000000000000000000000000000000000000000000000000000220100

艾丽卡(疑惑):“木森,这个结果是什么意思?我只看到了一串数字。”

木森(耐心地):“这里的00代表bool类型的初始化值,01代表uint8类型的值是1。你看他们都有两位,这说明bool类型只占用了一个字节。”

艾丽卡(不满足):“但是,木森,这个结果不够精确。我们怎么知道它不是占用了更多的空间,只是我们看到的是00呢?”

木森(思考):“你说得对,艾丽卡。我们需要一个更精确的方法来验证。我们可以用hash运算来测试。如果两个值的hash值相同,那么它们的值就相同,特别是这个0,00,000这里面的虽然都是0,但是他们的hash肯定是不同的。”

艾丽卡(眼睛一亮):“好主意!那我们快用这个新咒语来测试吧!”

木森开始编写一个新的智能合约,用来计算每种类型的存储槽键的hash值。他使用了keccak256这个强大的hash函数,并且用console2.log来输出结果。

代码环节

不同uint类型的数据的0,在被放入储存槽之后,占用的是不同的空间,我们可以通过hash运算来验证,如果两个数据完全一致,那么他们的hash也必将相同,可是如果是0和00这样的虽然在值上面相同,但是hash值不相同

// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;import  {Test} from "lib/forge-std/src/Test.sol";
import "lib/forge-std/src/console2.sol";contract BooltestTest is Test {bool public boolVar;uint8 public uint8Var;uint16 public uint16Var;uint32 public uint32Var ;uint64 public uint64Var ;uint128 public uint128Var;uint256 public uint256Var;function setUp() public {}function testBoolAndUint8TypeSizes() public {// 计算存储槽的键console2.log("uint8 slot key:", uint256(keccak256(abi.encodePacked(uint8Var))));console2.log("uint16 slot key:", uint256(keccak256(abi.encodePacked(uint16Var))));console2.log("uint32 slot key:", uint256(keccak256(abi.encodePacked(uint32Var))));console2.log("uint64 slot key:", uint256(keccak256(abi.encodePacked(uint64Var))));console2.log("uint128 slot key:", uint256(keccak256(abi.encodePacked(uint128Var))));console2.log("uint256 slot key:", uint256(keccak256(abi.encodePacked(uint256Var))));console2.log("Storage slot for bool:", uint256(keccak256(abi.encodePacked(boolVar))));}
}

我们可以看到通过这样的比较,

  [13858] BooltestTest::testBoolAndUint8TypeSizes()├─ [0] console::log("uint8 slot key:", 85131057757245807317576516368191972321038229705283732634690444270750521936266 [8.513e76]) [staticcall]│   └─ ← [Stop] ├─ [0] console::log("uint16 slot key:", 38292439343987868037672198288784556730787963328266909981497454499372014593944 [3.829e76]) [staticcall]│   └─ ← [Stop] ├─ [0] console::log("uint32 slot key:", 105345537983141833900523177836038591426164988092870088428104961074093597336652 [1.053e77]) [staticcall]│   └─ ← [Stop] ├─ [0] console::log("uint64 slot key:", 500549258012437878224561338362079327067368301550791134293299473726337612750 [5.005e74]) [staticcall]│   └─ ← [Stop] ├─ [0] console::log("uint128 slot key:", 110620294328144418057589324861608220015688365608948720310623173341503153578932 [1.106e77]) [staticcall]│   └─ ← [Stop] ├─ [0] console::log("uint256 slot key:", 18569430475105882587588266137607568536673111973893317399460219858819262702947 [1.856e76]) [staticcall]│   └─ ← [Stop] ├─ [0] console::log("Storage slot for bool:", 85131057757245807317576516368191972321038229705283732634690444270750521936266 [8.513e76]) [staticcall]│   └─ ← [Stop] └─ ← [Stop] 

所有的uint类型都有不同的hash值,但是bool和uint8的hash值是一样的!
艾丽卡(兴奋地):“快看,木森!所有的uint类型都有不同的hash值,但是bool和uint8的hash值是一样的!”

木森(满意地):“是的,艾丽卡。这说明在Solidity中,bool类型确实只占用了一个字节的空间。”

bool的gas疑惑?

小镇的法师塔里,木森和艾丽卡正围坐在一张堆满了魔法书和卷轴的桌子旁。木森的眼睛在一本古老的魔法书上快速扫过,而艾丽卡则好奇地凑过来,她的大眼睛里充满了疑惑。

艾丽卡(疑惑地):“木森,这本书上说用uint256代替bool类型可以节省gas,这是怎么做到的呀?”

木森(思考片刻):“这个嘛,艾丽卡,这其实是一个关于魔法世界中资源管理的小技巧。在Solidity语言中,bool类型只占用1个字节,而uint256占用32个字节。但是,当涉及到存储和检索数据时,以太坊网络是以32字节的小块进行操作的。”

艾丽卡(更加困惑):“等等,如果uint256占用更多空间,为什么会更节省gas呢?”

木森(微笑):“这里的关键不在于占用的空间大小,而在于网络如何处理这些数据。想象一下,我们的魔法书不是一页一页的,而是每32页作为一个单元来保存。即使你只写了一页,我们也需要支付存储整个32页单元的费用。”

艾丽卡(恍然大悟):“哦,我明白了!所以如果我们用uint256,即使它占用了32页,也只算一个单元的费用,而不是bool那样,虽然只写了一页,但还是要为整个32页单元付费!”

木森(点头):“正是这样!而且,当我们需要修改bool值时,如果它单独占用一个存储单元,我们可能需要支付额外的gas来更改它,因为即使是微小的改变,网络也会将其视为对整个32字节单元的修改。”

艾丽卡(眼睛闪闪发光):“哇,这真是太聪明了!那我们是不是应该在所有的地方都使用uint256来代替bool呢?”

木森(摇摇手指):“也不尽然,艾丽卡。虽然在某些情况下使用uint256可以节省gas,但我们也要考虑代码的可读性和逻辑的清晰度。有时候,直接使用bool类型会让我们的魔法咒语更直观、更容易理解。”

艾丽卡(认真地):“而且,部署的时候似乎更长的会消耗更多的储存槽,消耗更多的gas?”

木森(疑惑):“啊?这个我也不太懂了”

艾丽卡(兴奋地):“那我们快去实验一下吧!我想看看这个技巧在实际中是怎么工作的。”

木森(无奈):“不行,不行。今天太饿了,我需要吃东西”

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 基于SpringBoot+Vue+MySQL的画师约稿平台系统
  • 【Unity-Lua】音乐播放器循环滚动播放音乐名
  • 【微服务】Ribbon(负载均衡,服务调用)+ OpenFeign(服务发现,远程调用)【详解】
  • 【Kubernetes】常见面试题汇总(二)
  • JVM: JDK内置命令 - JPS
  • 微信小程序-formData使用
  • 【MySQL】查询表中重复数据、模糊查询列信息、快速copy表数据(1)
  • 分布式锁-Redisson 可重入锁
  • 注意力机制的细节
  • redis群集的三种模式
  • Jenkins 通过 Version Number Plugin 自动生成和管理构建的版本号
  • crm如何做私域运营?
  • Harmony Next 文件命令操作(发送、读取、媒体文件查询)
  • 【Hot100】LeetCode—215. 数组中的第K个最大元素
  • Qt常用控件——QLineEdit
  • 「面试题」如何实现一个圣杯布局?
  • Android开发 - 掌握ConstraintLayout(四)创建基本约束
  • Angular 响应式表单 基础例子
  • canvas 高仿 Apple Watch 表盘
  • Centos6.8 使用rpm安装mysql5.7
  • CSS盒模型深入
  • exif信息对照
  • JS正则表达式精简教程(JavaScript RegExp 对象)
  • LintCode 31. partitionArray 数组划分
  • MQ框架的比较
  • Otto开发初探——微服务依赖管理新利器
  • python学习笔记-类对象的信息
  • Redis学习笔记 - pipline(流水线、管道)
  • Three.js 再探 - 写一个跳一跳极简版游戏
  • 开放才能进步!Angular和Wijmo一起走过的日子
  • 快速体验 Sentinel 集群限流功能,只需简单几步
  • 设计模式走一遍---观察者模式
  • 推荐一个React的管理后台框架
  • 一些关于Rust在2019年的思考
  • Spark2.4.0源码分析之WorldCount 默认shuffling并行度为200(九) ...
  • ​油烟净化器电源安全,保障健康餐饮生活
  • #{} 和 ${}区别
  • #100天计划# 2013年9月29日
  • $(selector).each()和$.each()的区别
  • (2020)Java后端开发----(面试题和笔试题)
  • (Bean工厂的后处理器入门)学习Spring的第七天
  • (C语言)输入一个序列,判断是否为奇偶交叉数
  • (vue)el-cascader级联选择器按勾选的顺序传值,摆脱层级约束
  • (补)B+树一些思想
  • (十七)Flask之大型项目目录结构示例【二扣蓝图】
  • (十五)Flask覆写wsgi_app函数实现自定义中间件
  • (文章复现)基于主从博弈的售电商多元零售套餐设计与多级市场购电策略
  • (一)、python程序--模拟电脑鼠走迷宫
  • (转)Oracle 9i 数据库设计指引全集(1)
  • *** 2003
  • .Net - 类的介绍
  • .NET 8.0 发布到 IIS
  • .NET Windows:删除文件夹后立即判断,有可能依然存在
  • .NET 反射 Reflect
  • .NET/C# 利用 Walterlv.WeakEvents 高性能地定义和使用弱事件