首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在调用合同时使用abi.encodePacked

在调用合同时使用abi.encodePacked
EN

Ethereum用户
提问于 2022-02-20 18:55:17
回答 1查看 2.3K关注 0票数 2

我对abi.encode与abi.encodePacked的理解是,后者只是使用更压缩的输入参数表示。我认为abi.encode是调用其他契约时使用的默认编码,因此abi.encodePacked只应该用于序列化某些参数,而不是调用函数。

但是,我在调用中发现了使用abi.encodePacked的代码:

代码语言:javascript
运行
复制
  function setFirstTime(uint _timeStamp) public {
    timeZone1Library.delegatecall(abi.encodePacked(setTimeSignature, _timeStamp));
  }

这仅仅是因为timezone1Library是为理解abi.encodePacked而编译的吗?在更新版本的Solidity编译器中,这是默认的吗?

EN

回答 1

Ethereum用户

发布于 2022-02-20 19:52:50

abi.encodePacked是一种非标准编码,由于它与动态类型的模糊性,所以最好不要使用它,如果您不处理大小已经是32倍的动态类型和输入,那么它们都可以提供相同的输出。

我想你是从16级。保存拿来的那一段代码。其中,setTimeSignature被定义为:

代码语言:javascript
运行
复制
bytes4 constant setTimeSignature = bytes4(keccak256("setTime(uint256)"));

这不是一个动态类型,它是一个固定大小的bytes8数组,但是标准编码规范说:

请注意,对于任何X,len(enc(X))是32的倍数。

导致在4个字节之后填充28字节,这不是abi所期望的。您可以自己检查这些输出是否会产生不同的结果:

代码语言:javascript
运行
复制
function encodePacked(uint256 time) public view returns (bytes memory) {
    return abi.encodePacked(setTimeSignature, time);
}

// 0x3beb26c40000000000000000000000000000000000000000000000000000000000000000 (4 + 32 bytes)

function encode(uint256 time) public view returns (bytes memory) {
    return abi.encode(setTimeSignature, time);
}

// 0x3beb26c4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 (32 + 32 bytes)

调用数据的前4个字节应该是函数选择器,后面紧跟编码参数(使用标准编码)。这就是为什么他们使用abi.encodePacked对选择器进行编码,只占用4个字节。uint的编码与abi.encodeabi.encodePacked相同。

所有这些都是等价的,因为uint256不需要填充:

代码语言:javascript
运行
复制
function encodePacked(uint256 time) public view returns (bytes memory) {
    return abi.encodePacked(setTimeSignature, time);
}

function encodeHybrid(uint256 time) public view returns (bytes memory) {
    return abi.encodePacked(abi.encodePacked(setTimeSignature), abi.encode(time));
}

function encodeHybrid2(uint256 time) public view returns (bytes memory) {
    return abi.encodePacked(abi.encodePacked(setTimeSignature), abi.encodePacked(time));
}

这仅仅是因为timezone1Library是为理解abi.encodePacked而编译的吗?在更新版本的Solidity编译器中,这是默认的吗?

它之所以有效,只是因为它正确地生成了abi所期望的回调参数:4字节的函数选择器,然后是abi.encoded参数。它依靠一个特例来做到这一点。这种语法并不总是正确的(根据标准编码所需的动态类型或填充将导致错误的输出)。

您还可以使用更具可读性的语法,如:

代码语言:javascript
运行
复制
function encodeWithSignature(uint256 time) public view returns (bytes memory) {
    return abi.encodeWithSignature("setTime(uint256)", time);
}

它与上面的函数或您的初始示例完全相同,但是以一种更易读的方式,imo,而且它总是为参数生成一个正确编码的输出。

票数 2
EN
页面原文内容由Ethereum提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://ethereum.stackexchange.com/questions/122141

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档