ABI(Contract Application Binary Interface)详解
ABI是以太坊合约间相互调用的一种消息格式,包括从链外部调用链,或者合约之间的相互调用,类似于常见的rpc协议一样,也就是定义操作函数签名,参数编码,返回结果编码等。
1、函数
使用ABI协议的时候,必须要求在编译的时候知道类型,不支持动态类型编译。同时,协议假设编译期间知道另一个合约的接口定义,所以协议返回没有明确定义内容类型。
函数选择器:调用一个函数时,前四个字节指定了要调用函数的签名,计算方式是使用函数签名的keccak256
的哈希,取4个字节。e.g.:
bytes4(keccak256("fuc(uint32,bool)"))
参数编码:因为函数签名占用了4个字节,参数编码从第五个字节开始。
编码方式:区分了动态内容和固定大小类型,动态内容类型有:
- bytes
- string
- T[]不定长数组
- T[k]定长数组
初次之外的都是固定大小代的类型。固定大小的类型按原位置存储在当前块中,动态类型的数据独立存储在其他数据块中。
2、Events事件
Events是从以太坊日志/事件监听机制的一个抽象。日志实体包含合约地址,最多4个的主体topic和任意长度的二进制数据内容。Events依赖ABI函数来解析,日志实体被当做一个自定义的数据结构。
事件有事件名称和参数,我们将他们分为两个系列:需要索引和不需要索引。需要索引的,最多不超过3个,和事件签名的hash一起组成日志实体的topic。那些不需要索引的内容组成了事件的字节数组内容。
日志实体使用的ABI描述如下:
- address,合约地址,由以太坊内部提供
- topics[0],
keccak(EVENT_NAME+"("+EVENT_ARGS.map(canonical_type_of).join(",")+")")
,其中的canonical_type_of
是返回函数的规范型(Canonical form),如,uint indexed foo
,返回的应该是uint256
。如果事件本身是匿名定义的,那么Topic[0]
将不会自动生成。 - topics[n],
EVENT_INDEXED_ARGS[n-1]
,其中的EVENT_INDEXED_ARGS
表示指定成要索引的事件参数。 - data,
abi_serialise(EVENT_NON_INDEXED_ARGS)
使用ABI协议序列化的没有指定为索引的其它的参数。abi_serialise()
是ABI序列函数,用来返回一系列的函数定义的类型值。
3、JSON 格式
JSON格式的合约接口,可以描述为:
type
: 可取值有function
,constructor
,fallback
(无名称的默认函数)- name: 函数的名字
inputs
: 一系列的对象,每个对象包含下述属性:name
: 参数名称type
: 参数的规范型(Canonical Type)
。
outputs
: 一系列的类似inputs
的对象,如果无返回值时,可以省略constant
:true
表示函数声明自己不会改变区块链的状态。payable
:true
表示函数可以接收ether
,否则表示不能。
type字段可以省略,默认取值function,payable和constant也可以省略,默认都是false。构造器函数和回退函数,没有name或者outputs,回退函数也没有inputs。
事件的json描述非常类似:
type
: 取值都是"event"
name
: 事件名字inputs
: 一系列的输入参数,每个参数包括:name
: 参数名字type
: 参数类型components
: used for tuple types (more below).indexed
: 如果是日志的topic,取值是true,否则是false
anonymous
:true
表示事件是匿名的
详情可参考:https://solidity.readthedocs.io/en/develop/abi-spec.html?highlight=abi