// setA tag_2: // Where to goto after method call tag_3
// Load first argument (the value 0x1). calldataload(0x4)
// Execute method. jump(tag_4) tag_4: // sstore(0x0, 0x1) 0x0 dup2 swap1 sstore tag_5: pop // end of program, will goto tag_3 and stop jump tag_3: // end of program stop
在进入方法部分之前,汇编做了两件事:
保存方法调用后返回的位置。
将 call data 中的参数加载到堆栈上。
在低级伪代码中:
1 2 3 4 5 6 7 8 9 10 11 12
// Saves the position to return to after method call. @returnTo = tag_3
tag_2: // setA // Loads the arguments from call data onto the stack. @arg1 = calldata[4:4+32] tag_4: // a = _a sstore(0x0, @arg1) tag_5 // return jump(@returnTo) tag_3: stop
将两个部分结合在一起:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
methodSelector = calldata[0:4]
if methodSelector == "0xee919d50": goto tag_2 // goto setA else: // No matching method. Fail. revert
# The first array lists the types of the arguments. # The second array lists the argument values. > encode_abi(["uint256", "uint256", "uint256"],[1, 2, 3]).hex() 0000000000000000000000000000000000000000000000000000000000000001 0000000000000000000000000000000000000000000000000000000000000002 0000000000000000000000000000000000000000000000000000000000000003
/************* HEAD (32*3 bytes) *************/ // arg1: look at position 0x60 for array data 0000000000000000000000000000000000000000000000000000000000000060 // arg2: look at position 0xe0 for array data 00000000000000000000000000000000000000000000000000000000000000e0 // arg3: look at position 0x160 for array data 0000000000000000000000000000000000000000000000000000000000000160
/************* TAIL (128**3 bytes) *************/ // position 0x60. Data for arg1. // Length followed by elements. 0000000000000000000000000000000000000000000000000000000000000003 00000000000000000000000000000000000000000000000000000000000000a1 00000000000000000000000000000000000000000000000000000000000000a2 00000000000000000000000000000000000000000000000000000000000000a3
// position 0xe0. Data for arg2. 0000000000000000000000000000000000000000000000000000000000000003 00000000000000000000000000000000000000000000000000000000000000b1 00000000000000000000000000000000000000000000000000000000000000b2 00000000000000000000000000000000000000000000000000000000000000b3
// position 0x160. Data for arg3. 0000000000000000000000000000000000000000000000000000000000000003 00000000000000000000000000000000000000000000000000000000000000c1 00000000000000000000000000000000000000000000000000000000000000c2 00000000000000000000000000000000000000000000000000000000000000c3
/************* HEAD (32*3 bytes) *************/ // arg1: 0xaaaa 000000000000000000000000000000000000000000000000000000000000aaaa // arg2: look at position 0x60 for array data 0000000000000000000000000000000000000000000000000000000000000060 // arg3: 0xbbbb 000000000000000000000000000000000000000000000000000000000000bbbb
/************* TAIL (128 bytes) *************/ // position 0x60. Data for arg2. 0000000000000000000000000000000000000000000000000000000000000003 00000000000000000000000000000000000000000000000000000000000000b1 00000000000000000000000000000000000000000000000000000000000000b2 00000000000000000000000000000000000000000000000000000000000000b3
// arg1: look at position 0x60 for string data 0000000000000000000000000000000000000000000000000000000000000060 // arg2: look at position 0xa0 for string data 00000000000000000000000000000000000000000000000000000000000000a0 // arg3: look at position 0xe0 for string data 00000000000000000000000000000000000000000000000000000000000000e0
// 0x60 (96). Data for arg1 0000000000000000000000000000000000000000000000000000000000000004 6161616100000000000000000000000000000000000000000000000000000000
// 0xa0 (160). Data for arg2 0000000000000000000000000000000000000000000000000000000000000004 6262626200000000000000000000000000000000000000000000000000000000
// 0xe0 (224). Data for arg3 0000000000000000000000000000000000000000000000000000000000000004 6363636300000000000000000000000000000000000000000000000000000000
对于每个字符串/字节数组,前 32 个字节编码了长度,紧跟着是字节。
如果字符串大于 32 字节,则使用多个 32 字节块:
1 2 3 4 5 6 7 8 9 10 11 12
// encode 48 bytes of string data ethereum.abi.encode_abi( ["string"], ["a" * (32+16)] ).hex()
// length of string is 0x30 (48) 0000000000000000000000000000000000000000000000000000000000000030 6161616161616161616161616161616161616161616161616161616161616161 6161616161616161616161616161616100000000000000000000000000000000
// arg1: The outer array is at position 0x20. 0000000000000000000000000000000000000000000000000000000000000020
// 0x20. Each element is the position of an inner array. 0000000000000000000000000000000000000000000000000000000000000003 0000000000000000000000000000000000000000000000000000000000000060 00000000000000000000000000000000000000000000000000000000000000e0 0000000000000000000000000000000000000000000000000000000000000160
// array[0] at 0x60 0000000000000000000000000000000000000000000000000000000000000003 00000000000000000000000000000000000000000000000000000000000000a1 00000000000000000000000000000000000000000000000000000000000000a2 00000000000000000000000000000000000000000000000000000000000000a3
// array[1] at 0xe0 0000000000000000000000000000000000000000000000000000000000000003 00000000000000000000000000000000000000000000000000000000000000b1 00000000000000000000000000000000000000000000000000000000000000b2 00000000000000000000000000000000000000000000000000000000000000b3
// array[2] at 0x160 0000000000000000000000000000000000000000000000000000000000000003 00000000000000000000000000000000000000000000000000000000000000c1 00000000000000000000000000000000000000000000000000000000000000c2 00000000000000000000000000000000000000000000000000000000000000c3