Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions 27_ABIEncode/ABIEncode.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,16 @@ contract ABIEncode{
result = abi.encodePacked(x, addr, name, array);
}

// 动态类型没有边界时,encodePacked 可能把不同输入拼成同一字节序列
function collisionPacked() public pure returns(bool) {
return keccak256(abi.encodePacked("ab", "c")) == keccak256(abi.encodePacked("a", "bc"));
}

// abi.encode 保留类型和长度边界,适合为动态参数构造哈希
function safeHash() public pure returns(bool) {
return keccak256(abi.encode("ab", "c")) != keccak256(abi.encode("a", "bc"));
}

function encodeWithSignature() public view returns(bytes memory result) {
result = abi.encodeWithSignature("foo(uint256,address,string,uint256[2])", x, addr, name, array);
}
Expand Down
16 changes: 16 additions & 0 deletions 27_ABIEncode/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,22 @@ function encodePacked() public view returns(bytes memory result) {

编码的结果为`0x000000000000000000000000000000000000000000000000000000000000000a7a58c0be72be218b41c608b7fe7c5bb630736c713078414100000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006`,由于`abi.encodePacked`对编码进行了压缩,长度比`abi.encode`短很多。

#### 动态参数的拼接歧义

`abi.encodePacked`不会记录动态参数之间的边界,因此不同输入可能产生相同的字节序列:`abi.encodePacked("ab", "c")`和`abi.encodePacked("a", "bc")`都编码为`0x616263`。如果直接对这种结果签名或哈希,攻击者可能把一组参数替换成另一组参数。

```solidity
function collisionPacked() public pure returns(bool) {
return keccak256(abi.encodePacked("ab", "c")) == keccak256(abi.encodePacked("a", "bc"));
}

function safeHash() public pure returns(bool) {
return keccak256(abi.encode("ab", "c")) != keccak256(abi.encode("a", "bc"));
}
```

当哈希输入包含多个动态类型(例如`string`、`bytes`或动态数组)时,不要用`abi.encodePacked`直接拼接;优先使用`abi.encode`保留类型和长度边界。`abi.encodePacked`更适合参数边界本来就固定且不会产生歧义的场景。

### `abi.encodeWithSignature`

与`abi.encode`功能类似,只不过第一个参数为`函数签名`,比如`"foo(uint256,address,string,uint256[2])"`。当调用其他合约的时候可以使用。
Expand Down
Loading