抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

abi编码的详解

1.abi.encode

abi.encode 将它的每个参数填充为32字节【32 * 8 =256位】(1byte = 8bit)的数据,并拼接在一起。

注:如果要和合约交互,使用的是abi.encode(实践操作)

1.1 abi.encode编码演示

定义的变量:

1
2
3
4
5
uint8 num1 = 1;
uint256 num2 = 1;
address _addr = 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4;
string name = "biyou";
bytes1 bs1 = 0xff;

代码1:

num1是uint8类型,占用1个字节

1
2
3
function testABIEncode1() external view returns(bytes memory reslut) {
reslut = abi.encode(num1, _addr, name, bs1);
}

代码2:

num2是uint256类型,占用32个字节

1
2
3
function testABIEncode2() external view returns(bytes memory reslut) {
reslut = abi.encode(num2, _addr, name, bs1);
}

看运行结果:

image-20240412172603158

由运行结果 比较num1num2的编码值可知,不管参数的数据类型是什么,它都将参数填充为32位。所以这两个函数的编码结果相同。

1.2 abi.encode 与合约交互 —- 以create2为例

create2 的使用请移步 ===》

【abi.encode】

通过 abi.encode对要部署合约的字节码和代传参数(id = 1, name = “biyou”)进行“非紧”打包:

1
2
3
4
5
6
// 非紧打包 -- 涉及了合约构造函数的参数 
function encodeBycode(uint id, string memory name) external pure returns(bytes memory result) {
bytes memory temp = type(Student).creationCode;
// 将字节码和参数进行紧打包
result = abi.encodePacked(temp, abi.encode(id,name));
}

运行结果的部分截图:

image-20240412172613937

将获取的bytecode的值,放入create2Address函数中,传入盐salt(biyou),计算 Student合约的地址

create2Address函数代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function create2Address(bytes memory bycode,string memory salt) external view returns(address result){
result = address(
uint160(
uint(
keccak256(abi.encodePacked(
// bytes1(0xff),
uint8(0xff), // 固定的一个字节的常数 0xff
address(this), //当前合约地址(create2合约地址)
keccak256(abi.encodePacked(salt)), //对盐进行紧打包
keccak256(bycode) //要计算的合约的字节码
))
)
)
);
}

运行结果:

image-20240412172634806

再将获取的地址通过remix上的At Address获取合约,并调用其中的函数检验结果:

At Address:

image-20240412172644123

验证结果(正确):

image-20240412172654928

【abi.encodePacked】

通过 abi.encodePacked对要部署合约的字节码和代传参数(id = 1, name = “biyou”)进行“非紧”打包:

1
2
3
4
5
// 紧打包
function encodePackedBycode(uint id, string memory name) external pure returns(bytes memory result) {
bytes memory temp = type(Student).creationCode;
result = abi.encodePacked(temp, abi.encodePacked(id,name));
}

运行结果的部分截图:

image-20240412172703540

将获取的bytecode的值,放入create2Address函数中,传入盐salt(biyou),计算 Student合约的地址

create2Address函数同上

运行结果:

image-20240412172712922

再将获取的地址通过remix上的At Address获取合约,并调用其中的函数检验结果:

At Address:

image-20240412172721474

运行结果(出错):

image-20240412172730666

2. abi.encodePacked

2.1 编码演示

将给定参数根据其所需最低空间编码。类似于abi.encode,但是会把其中填充的很多0省略。比如,只用1字节来编码uint类型。当你想省空间,并且不与合约交互的时候,可以使用abi.encodePacked,例如算一些数据 的hash时。

最低空间编码(个人理解): 因为在以太坊EVM中的ABI,默认给每个属性(字段)赋予一个 32字节(32 * 8 = 256位)的长度(不足部分被0填充), 实际占用长度取决于属性的类型。

整型:

1
>uint8 num = 1; // 这个占用8bit,即一个字节,前面将填充31 * 8 个零,又因为在以太坊中数据一般格式为16进制,16进制数的一位占四个 xxxx(x是0或1) 例: 0xff = 11111111

这样前面显示的0的个数为 31 * 8 / 4 = 62个(uint8 num = 1,本身表示为:0x01)

所以使用abi.encodePacked打包,将会是保留uint8本身的长度(8位)即1字节即0x01,

如图:

image-20240412172742074

1
>uint256 num2 = 1;//占用 256位,即 0x0000000000000000000000000000000000000000000000000000000000000001,因为num2声明为uint256明确指明了占用256位,所以EVM会给num2分配的最低空间为 256位

所以使用abi.encodePacked打包,将会是保留uint256本身的长度(256位)即32字节

如图:

image-20240412172750668

bytesn(n的范围是[1,32])类型:和uint类型类似 bytes1 ==> uint8

关于 bytes家族移步==》

image-20240412172759115

string类型:

将字符串转为bytes类型之后实际有多长就保留多长

字符串转bytes代码:

1
2
3
function stingConvertBytes(string memory _str) external pure returns(bytes memory result){
result = abi.encodePacked(_str);
}

image-20240412172813552

address类型:

因为address是160位的,所以只保留160位即可

image-20240412172821535

定义的变量:

1
2
3
4
5
uint8 num1 = 1;
uint256 num2 = 1;
address _addr = 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4;
string name = "biyou";
bytes1 bs1 = 0xff;

代码1:

num1是uint8类型,占用1个字节

num2是uint256类型,占用32个字节

_addr是address类型,占用20个字节

name是string类型,占用字节数取决于实际情况长度

bs1是bytes1类型,占用1个字节

1
2
3
function testABIEncodePacked1() external view returns(bytes memory reslut) {
reslut = abi.encodePacked(num1, _addr, name, bs1);
}

结果:

image-20240412172830976

代码2:

``num1是uint8类型,占用1个字节`

num2是uint256类型,占用32个字节

_addr是address类型,占用20个字节

name是string类型,占用字节数取决于实际情况长度

bs1是bytes1类型,占用1个字节

1
2
3
function testABIEncodePacked2() external view returns(bytes memory reslut) {
reslut = abi.encodePacked(num2, _addr, name, bs1);
}

看运行结果:

image-20240412172843267

3. 总结

不需要和其他合约交互的时候大多选择 abi.encodePacked的打包方式,包括签名操作什么的

需要与其他合约进行交互的则选择abi.encode的打包方式—其他的合约交互正在学习

评论



政策 · 统计 | 本站使用 Volantis 主题设计