前言
- 最近看了一些奇怪的东西,触及到了知识盲区,就水了一篇博客记录一下
- 写的也不是很专业,只是按照个人理解,有错误的话欢迎及时交流 👀
- 参考了 👉 官方文档 👈
Function Selector
- 定义就不介绍了,不太清楚的可自行百度,直接来看例子(一看就懂,就不解释了)
- 参数包含结构体,相当于把结构体拆分成单个参数,只不过这些参数用
()
引起来
- 参数包含结构体,相当于把结构体拆分成单个参数,只不过这些参数用
1 | pragma solidity >=0.4.16 <0.9.0; |
Function Selector and Argument Encoding
动态类型的数据,比如动态数组,结构体,变长字节,其编码后存储其
offset
、length
、data
- 先把参数顺序存储:如果是定长数据类型,直接存储其
data
,如果是变长数据类型,先存储其offset
- 顺序遍历变长数据:先存储
offset
,对于第一个变长数据,先存储其offset = 0x20 * number
(number
是函数参数的个数 );对于下一个变长数据,其offset = offset_of_prev + 0x20 + 0x20 * number
(第一个0x20
是存储前一个变长数据的长度占用的大小,number
是前一个变长数据的元素个数) - 顺序遍历变长数据:存储完
offset
,接着就是遍历每个变长数据,分别存储其length
和data
- (
ps:
对于结构体这样的类型,存储的时候可把结构体内元素看成是一个新函数的参数,这样的话,对于结构体中的第一个变长数据,其offset = 0x20 * num
,num
是结构体元素的个数 )
- 先把参数顺序存储:如果是定长数据类型,直接存储其
对于上述的合约例子,其函数调用最终编码如下
test1("0x112233")
1 | 0x0d2032f1 // function selector |
test2(["0x112233", "0x445566"])
1 | 0x2b231dad // function selector |
test3(0x123, 1)
1 | 0x92e92919 // function selector |
test4(0x123, ["0x11221122", "0x33443344"], "0x31323334353637383930", "0x3132333435")
1 | 0x4d189ce2 // function selector |
test5(0x123, ["cxy", "pika", 123])
1 | 0x4ca373dc // function selector |
test6(0x123, [["cxy1", "pika1", 123], ["cxy2", "pika2", 456]])
1 | 由于是结构体数组,所以需要拆分,由内向外。内部是两个结构体,分别来看其encoding |
test7([[1, 2], [3]], ["one", "two", "three"])
1 | 同理进行由内向外的拆分,首先是[[1, 2], [3]]动态数组中的[1, 2]和[3]两个动态数组 |