地址和数量 每一个参数(除了 列表/数组 和纯文本 —— 这些我们后文再说)的长度都是 32 字节,或者说 64 个十六进制字符。但以太坊地址只有 40 个字节长(不算 0x 的话)。为了解决这个问题,地址参数要用 0 来填充。在十六进制里面,0x0000123 和 0x123 是一样的,因此 0x0000000000000000000000004bbeeb066ed09b7aed07bf39eee0460dfa261520(上述事务中的地址参数)等同于 0x4bbeeb066ed09b7aed07bf39eee0460dfa261520,而且 0x00000000000000000000000000000000000000000000000002a34892d36d6c74 也就等于 0x2a34892d36d6c74。那为什么我们要填充这些 0 呢? 就像我们上面说到的,Solidity 合约可以接受的最大数值是 2256 - 1,刚好是 32 字节。使用固定的长度可以让 EVM 和其他应用在解码数据时候更轻松,因为你可以假设每一个参数的长度都是一样的。 那数组和字符串呢? 如上所述,在 input data 中使用数组和字符串,情形会有些许不同。因为数组本质是多个东西组成的一个列表。举个例子,1、2、3 三个数所组成的列表在大多数编程语言中都可以写为 [1, 2, 3]。要在事务中发送这种数据,列表中的每一个对象都要作为 32 字节一组的数据发送,列在 input data 的结尾。指明数组长度的指针就作为参数。 假定我们有一个叫做 calledmyFunction 的函数,接收一个地址和数字的数组作为参数,即 myFunction(address,uint256[])。该函数的函数签名是 0x4b294170。地址这一项,我们照上面所说的操作。因为我们的数组包含 3 个对象,数组的长度用十六进制表示为 0x3。然后每个对象都要占据恰好 32 自己的空间,且数组要放在所有其它参数之后,所以数组会从 32+32 = 64 字节之后开始。 000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003- 例子:input 数据要按照 32 字节一组来切分 - 因为字符串的长度是任意的(可能长过 32 字节),它们要按 32 字节一组来切分,处理方式跟数组相同。 像 Etherscan 这样的网站是如何解码 input data 的? 哈希函数是单向函数,所以如果你只有函数签名的哈希值,是不可能会恢复出函数签名的(你要试试暴力破解吗老弟)。合约的所有者可以将合约的 ABI 作为 JSON 文件上传,就像这个例子,这可以用来拿到函数签名的哈希值。 即使合约的所有者不上传合约的 ABI,也能够解码 input 数据(对大多数合约而言)。因为,ERC-20 合约函数的签名都是一样的,因此 Etherscan 只需使用一个预定义的合约 ABI 即可服务大部分合约。举个例子,ERC 20 合约的转账函数的合约 ABI 如下文所示 (责任编辑:admin) |