struct 中 bytes 和 string类型位置计算

本文探讨了在智能合约中,当值长度小于32字节时,bytes和string如何存储以及如何计算其位置。对于长度小于32字节的数据,长度乘以2会存储在高位字节中;若长度超过32字节,则存储位置由length乘以2加1决定,并在相应keccak256哈希位置存储数据。通过示例展示了不同长度值的存储和计算过程。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

contract Test {
    uint256 zero // slot 0
    uint256 one; // slot 1
    uint256 two; // slot 2
    uint256 there;// slot 3
   
    
    struct AAA {
        uint256 a;
        uint256 b;
        bytes c;
    }
    
     mapping(uint256 => AAA[]) public ddd; // slot 4

        constructor() {
        //ddd[2].push(AAA({a: 9, b: 10,c:"string input4"})); //小于32字节的
        ddd[2].push(AAA({a: 9, b: 10,c:"string input4 more than 64 hahaha"}));  

    }        
}

c的位置计算是通过一下:

uint256(keccak256(abi.encodePacked(keccak256(abi.encodePacked(2, 4)))) + 2

后边加的2 是通过index 算来的,a的index=0 c就是2了

c 的位置是:115422248451717562185388182079897522298857624646553443070743177396828943826236 值为:bytes32: ret 0x737472696e6720696e707574340000000000000000000000000000000000001a--1a--16转10进制为26--代表的识length(13)*2 =26 1a之前是数据转化完后就是string input4

但是如果大于32字节,c 的位置是:115422248451717562185388182079897522298857624646553443070743177396828943826236 此时存储的就是length(值为33)*2 +1 =67 返回是 bytes32: ret 0x0000000000000000000000000000000000000000000000000000000000000043 低位43 16转10进制为67,这是具体的字符串value存储的位置为uint256(keccak256(abi.encodePacked(slot))); slot 为c的位置115422248451717562185388182079897522298857624646553443070743177396828943826236

然后计算数据存储的位置48107489538665329287718715171855900440650012581208935513126464494439610548754 取对应位置的值:0x737472696e6720696e70757434206d6f7265207468616e203634206861686168 转string为:string input4 more than 64 hahah

知识补给:

bytes 和 string

bytes 和 string 的编码是相同的。 一般来说,编码与 bytes1[] 类似,即有一个槽用于存放数组本身和一个数据区, 这个数据区是用该槽的位置的 keccak256 哈希值计算的。 然而,对于较短的值(短于32字节),数组元素与长度一起存储在同一个槽中。

特别是:如果数据最多只有 31 字节长, 元素被存储在高阶字节中(左对齐),最低阶字节存储值 length * 2。 对于存储数据长度为 32 或更多字节的字节数,主槽 p 存储 length * 2 + 1, 数据照常存储在 keccak256(p)。这意味着您可以通过检查最低位是否被设置来区分短数组和长数组: 短数组(未设置)和长数组(设置)

//0x737472696e6720696e70757434206d6f7265207468616e203634206861686168

function bytes32ToString(bytes32 _bytes32) external pure returns (string memory) {

bytes memory bytesArray = new bytes(32);

for (uint256 i ; i < 32; i++) {

bytesArray[i] = _bytes32[i];

}

return string(bytesArray);

}

Struct是Python中用于处理二进制数据的模块之一。通过使用Struct的函数,可以将数据编码为一串字节。这个过程通常称为“打包”。我们可以使用Struct的pack()函数来打包数据。pack()函数有以下两个参数: 1. format:这是一个包含打包方式的字符串。在这个字符串中,我们可以指定各种数据类型其对应的字节数。例如,‘i’表示整形数据,占四个字节;‘f’表示浮点数据,占四个字节;‘s’表示字符串型数据,需要指定其长度。 2. arguments:这是一个包含要打包的数据的元组。这个元组的长度format字符串中指定的数据类型数量相等。 代码示例: ```python import struct # 打包一个整型一个浮点型数据 data = struct.pack(&#39;if&#39;, 123, 3.14) # 打包一个字符串型一个整型数据 data2 = struct.pack(&#39;2si&#39;, b&#39;ab&#39;, 456) print(data) # b&#39;{\xdc\x00\x00\x9d\xf1\x0b\x40&#39; print(data2) # b&#39;ab\x00\x00\x01\xc8&#39; ``` 在上述示例中,我们使用了两个不同的打包方式。第一个打包方式使用了‘if’格式字符串,并将整型数据123浮点型数据3.14打包在一起。第二个打包方式使用了‘2si’格式字符串,并将长度为2的字符串“ab”整型数据456打包在一起。 从输出结果中可以看出,两个打包结果都是一串字节。这些字节是可以被传输存储的。在需要读取这些字节并还原为数据的时候,我们可以使用Struct的unpack()函数。针对每个数据类型Struct都有对应的unpack格式字符串,使用unpack()函数时需要传入一串打包后的字节unpack格式字符串作为参数。unpack()函数将这些字节解包后,将解包后的数据以元组的形式返回。 本文只是对Struct模块打包的一些简单介绍,如果想要更深入地了解这个模块,请参考Python文档。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值