我对abi.encode与abi.encodePacked的理解是,后者只是使用更压缩的输入参数表示。我认为abi.encode是调用其他契约时使用的默认编码,因此abi.encodePacked只应该用于序列化某些参数,而不是调用函数。
但是,我在调用中发现了使用abi.encodePacked的代码:
function setFirstTime(uint _timeStamp) public {
timeZone1Library.delegatecall(abi.encodePacked(setTimeSignature, _timeStamp));
}
这仅仅是因为timezone1Library
是为理解abi.encodePacked而编译的吗?在更新版本的Solidity编译器中,这是默认的吗?
发布于 2022-02-20 19:52:50
abi.encodePacked是一种非标准编码,由于它与动态类型的模糊性,所以最好不要使用它,如果您不处理大小已经是32倍的动态类型和输入,那么它们都可以提供相同的输出。
我想你是从16级。保存拿来的那一段代码。其中,setTimeSignature
被定义为:
bytes4 constant setTimeSignature = bytes4(keccak256("setTime(uint256)"));
这不是一个动态类型,它是一个固定大小的bytes8数组,但是标准编码规范说:
请注意,对于任何X,len(enc(X))是32的倍数。
导致在4个字节之后填充28字节,这不是abi所期望的。您可以自己检查这些输出是否会产生不同的结果:
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.encode
和abi.encodePacked
相同。
所有这些都是等价的,因为uint256不需要填充:
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参数。它依靠一个特例来做到这一点。这种语法并不总是正确的(根据标准编码所需的动态类型或填充将导致错误的输出)。
您还可以使用更具可读性的语法,如:
function encodeWithSignature(uint256 time) public view returns (bytes memory) {
return abi.encodeWithSignature("setTime(uint256)", time);
}
它与上面的函数或您的初始示例完全相同,但是以一种更易读的方式,imo,而且它总是为参数生成一个正确编码的输出。
https://ethereum.stackexchange.com/questions/122141
复制相似问题