区块链大学区块链区块链研习社

以太坊ABI介绍(二)

2018-10-16  本文已影响2人  JouyPub

上一篇我们讲了ABI中的参数含义 以太坊ABI介绍(一),但是只有函数定义也是不行的,我们还需要调用,当调用一个函数时也需要对该函数进行编码,这样EVM才能执行,那么以太坊是如何生成可供EVM调用的字节码的。

生成的字节码主要分两部分:函数选择器和参数编码

函数选择器

即函数编码,对函数名称+参数类型进行sha3(keccak256)哈希运算之后,取前4个字节

1、方法一:
安装pyethereum [https://github.com/ethereum/pyethereum/#installation]

> from ethereum.utils import sha3
> sha3("set(uint256").hex()
'0x60fe47b16ed402aae66ca03d2bfc51478ee897c26a1158669c7058d5f24898f4'

> sha3("setA(uint256)")[0:4].hex()
'60fe47b1'

2、方法二:
打开Ganache,默认端口7545,然后再命令行执行以下命令

curl -X POST -i http://localhost:7545 --data '{
  "jsonrpc":"2.0",
  "method":"web3_sha3",
  "params":["set(uint256)"]
}'

返回结果:
{
  "jsonrpc": "2.0",
  "result": "0x60fe47b16ed402aae66ca03d2bfc51478ee897c26a1158669c7058d5f24898f4"
}

3、方法三:

const Web3 = require('web3')
const web3 = new Web3()
console.log(web3.sha3('set(uint256)'))
# 0x60fe47b16ed402aae66ca03d2bfc51478ee897c26a1158669c7058d5f24898f4

取前四个字节(一个字节=2个16进制字符)即:0x60fe47b1

参数编码

由于函数编码占用了4个字节,所以参数编码从第五位开始

参数的编码根据类型的不同,编码方式也有所区别。主要分为固定类型和动态类型

1、固定类型

2、动态类型

编码规则

固定类型的编码就很简单,直接将参数值转成32字节长度的16进制即可。但是有区别的是:不足32bytes时,数字类型,如果是正数高位补0,如果是负数高位补1,布尔类型高位补0,字节类型、字符串类型在低位补全
动态类型的编码稍微复杂点,如果是固定长度就不需要计算偏移量,如果是不定长度就需要先计算偏移量,并在最后加上长度和具体值的编码,详细步骤下面会介绍

具体编码过程

介绍的例子和官方文档一样,如果理解有偏差可以查看源文档

pragma solidity ^0.4.16;

contract Foo {
  function baz(uint32 x, bool y) public pure returns (bool r) { r = x > 32 || y; }
  function bar(bytes3[2] memory) public pure {}
  function f(uint, uint32[], bytes10, bytes) public pure {}
}
案例

案例一:
函数:baz(bytes3[2] memory)
调用:baz(69, true)

const Web3 = require('web3')

const web3 = new Web3()
console.log(web3.sha3('f(uint256,uint32[],bytes10,bytes)'))
0xcdcd77c0
0x0000000000000000000000000000000000000000000000000000000000000045
0x0000000000000000000000000000000000000000000000000000000000000001

返回:该函数返回的是true,output将会是

0x0000000000000000000000000000000000000000000000000000000000000000

案例二:
函数:bar(bytes3[2] memory)
调用:bar(["abc", "def"])

0xfce353f6
0x6162630000000000000000000000000000000000000000000000000000000000
0x6465660000000000000000000000000000000000000000000000000000000000

案例三:
函数:f(uint,uint32[],bytes10,bytes)
调用:f(0x123, [0x456, 0x789], "1234567890", "Hello, world!")

0x8be65246
0000000000000000000000000000000000000000000000000000000000000123
0000000000000000000000000000000000000000000000000000000000000080
3132333435363738393000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000e0
0000000000000000000000000000000000000000000000000000000000000002
0000000000000000000000000000000000000000000000000000000000000456
0000000000000000000000000000000000000000000000000000000000000789
000000000000000000000000000000000000000000000000000000000000000d
48656c6c6f2c20776f726c642100000000000000000000000000000000000000

以上就是以太坊调用函数时生成字节码的完整过程了!

欢迎订阅「K叔区块链」 - 专注于区块链技术学习
博客地址:http://www.jouypub.com
上一篇 下一篇

猜你喜欢

热点阅读