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

区块链审计 如何测试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?”

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

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

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


http://www.kler.cn/news/309712.html

相关文章:

  • WSL中使用AMBER GPU串行版
  • 【数据仓库】数据仓库常见的数据模型——范式模型
  • LeetCode 2332.坐上公交的最晚时间 (双指针 + 贪心)
  • kubernetes架构
  • 上调铁矿石产量预期后,淡水河谷股价能否重振?
  • MUNIK谈ASPICE系列专题分享(九)ASPICE对项目需求管理的实践分享
  • 2.Springboot之ApplicationContextListenerConfig
  • 【四范式】浅谈NLP发展的四个范式
  • 怀揣热爱 躬耕不惫 ——记新宁县金石镇水头学校朱文文老师
  • 雷池waf:三步轻松卸载指南
  • Redis - 集群篇 - 集群模式
  • 系统安全设计规范(Word完整版)
  • 如何用麦肯锡方法分析问题和解决问题?
  • navicate连接oracle数据库probable oracle net admin error
  • C++:内部类,匿名对象,操作符new与delete
  • uniapp 做一个查看图片的组件,图片可缩放移动
  • python中Web API 框架
  • Html css样式总结
  • 使用CUBE_MX实现STM32 DMA 功能(存储器到存储器)
  • Miracast/WifiDisplay开发相关的深入调研分析-android投屏实战开发
  • 字幕编辑用什么软件好?盘点国内外7款视频加字幕软件,简单高效!
  • [SWPU2019]Web11
  • Java文件输入输出及其常用类
  • Nginx反向代理出现502 Bad Gateway问题的解决方案
  • 如何使用 LangChain 的内置工具和工具包:深入探讨与实践指南
  • [Web安全 网络安全]-文件包含漏洞
  • 八股(8)——Spring,SpringBoot
  • 虾皮商品数据api全解析:高效获取,精准运营新利器
  • 记八月十五灵隐寺一游
  • presto/trino native 向量化 大数据计算引擎