以太坊官方ABI介绍地址:https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI
都是英文的看了好几遍才算看明白,总结其中的ABI编码规则,特别是其中的多个输入参数的方法体中又包含动态参数的方法在进行请求调用时的ABI编码生成规则总结如下:
就拿官方文档中的例子
function sam(bytes name, bool z, uint[] data)
如果我们想调用sam这个函数方法,并输入"dave"
, true
and [1,2,3]
这样的三个请求参数。生成ABI编码的方法分如下几个步骤。
1. 对函数方法的编码。去掉参数名称,只保留参数类型:sam(bytes,bool,uint256[]),再进行(Keccak哈希值取前4字节)。编码后的结果为0xa5643bf2
2. 分析第一个请求参数bytes属于动态类型,对于动态类型的请求参数编码,首先需要编码一个请求参数的放置位置的参数(有点拗口,意思就是你要传“dave”,那么你先确认下这个“dave”放在最终的ABI请求体中的哪一位传入)。开始分析:
a. 第一个32位属于第一个参数的,但是它为动态类型,所以此处需编码“dave”的参数的放置位置的值(不是输入参数的编码),先不确定位置在哪儿,暂时站着32位
b. 第二个32位属于第二个请求参数的,为bool类型,属于静态类型。可以直接转换输入值,此处为true,编码后的值为:0x0000000000000000000000000000000000000000000000000000000000000001(第二个32位)
c. 第三个32位属于第三个请求参数的,它也为动态类型,所以此处也需要放[1,2,3]的参数放置位置的值(不是输入参数的编码),此时也不确定到底是多少,咱接着往下走。
d. 第四个32位。按照静态类型来算的话,sam方法共3个请求参数,每个32位,上边已经有3个32位的编码了,算编码完了的,但是这里有2个动态类型,第一个32位和第三个32位被参数的所放位置的值给占了,第一个和第三个动态类型的值还没编码的,所以第四个32位就用该放“dave”参数的编码信息了,注意:此处就确定了“dave”的编码位置为32*3=96,对96进行16进制编码并补齐32位的结果为:0x0000000000000000000000000000000000000000000000000000000000000060(第一个32位)。确定了第一个32位的值后,我们再来看下第四位该传"dave"参数的什么值。注意它是动态类型,还不能直接传“dave”的编码值,此处传的是动态类型的长度,“dave”的长度为4,所以16进制编码并补齐32位后的结果为:0x0000000000000000000000000000000000000000000000000000000000000004(第四个32位)
e. 第五个32位。上边第四个传了“dave”的参数长度值,所以第五个就是“dave”的编码值,utf8编码”dave”的Hex值,右补齐32位,结果为: 0x6461766500000000000000000000000000000000000000000000000000000000(第五个32位)
f. 第六个32位。经过上边的步骤第一个和第二个输入参数都编码完成了,此处就应该放第三个参数[1,2,3]的长度值了。注意:此时就确定了第三个32位的值为5*32=160,换算为16进制并补齐32位的值就为:0x00000000000000000000000000000000000000000000000000000000000000a0(第三个32位)。然后接着还是第六个32位的值长度为3,转换为16进制编码并补齐32位后的结果为:0x0000000000000000000000000000000000000000000000000000000000000003(第六个32位)
g. 第七个32位。因为[1,2,3]是3个参数,所以此处得分开为3个uint256。第七位就为参数1的16进制编码并补齐32位的结果为:0x0000000000000000000000000000000000000000000000000000000000000001(第七个32位)
h. 第八个32位。为参数2的16进制编码并补齐32位的结果为:0x0000000000000000000000000000000000000000000000000000000000000002(第八个32位)
i. 第九个32位。为参数3的16进制编码并补齐32位的结果为:0x0000000000000000000000000000000000000000000000000000000000000003(第九个32位)
最终的转换结果为:
0xa5643bf2
0000000000000000000000000000000000000000000000000000000000000060
0000000000000000000000000000000000000000000000000000000000000001
00000000000000000000000000000000000000000000000000000000000000a0
0000000000000000000000000000000000000000000000000000000000000004
6461766500000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000003
0000000000000000000000000000000000000000000000000000000000000001
0000000000000000000000000000000000000000000000000000000000000002
0000000000000000000000000000000000000000000000000000000000000003