Ethereum Contract ABI
以太坊合同ABI
此规范现在作为Solidity文档的一部分进行维护。
功能
基本设计
我们假设应用程序二进制接口(ABI)是强类型的,在编译时和静态时是已知的。不会提供自检机制。我们断言,在编译是可调用的contract都具有接口定义。
本规范不涉及接口是动态的或者运行时的情况。如果这些情况变得重要,那么它们可以作为以太坊生态系统内的设施进行充分处理。
Function Selector
函数调用的调用数据的前四个字节指定要调用的函数。它是函数的Keccak(SHA-3)哈希签名中的第一个(左边的,高位的big-endian)四个字节。签名被定义为基本原型的规范表达式,即带有括号的参数类型列表的函数名称。参数类型由一个逗号分隔 - 不使用空格。
参数编码
编码的参数跟随, 从第五个字节开始。这种编码也用于其他地方,例如返回值和事件参数都以相同的方式编码,而不用四个字节来指定函数。
类型
存在以下基本类型:
uint<M>
:无符号整数类型,M个
位0 < M <= 256
,,M % 8 == 0
。例如uint32
,uint8
,uint256
。int<M>
:二进制补码有符号整数类型的M
位0 < M <= 256
,,M % 8 == 0
。address
:相当于uint160
,除了假设的解释和语言类型。uint
,int
:同义词uint256
,int256
分别(不被用于计算功能选择)。bool
:相当于uint8
限制为值0和1fixed<M>x<N>
:有符号的定点小数的M
比特,0 < M <= 256
,M % 8 ==0
,和0 < N <= 80
,其表示的值v
作为v / (10 ** N)
。ufixed<M>x<N>
:无符号的变体fixed<M>x<N>
。fixed
,ufixed
:同义词fixed128x19
,ufixed128x19
分别(不被用于计算功能选择)。bytes<M>
:M
字节的二进制类型0 < M <= 32
。function
:相当于bytes24
:一个地址,后跟一个功能选择器
以下(固定大小)数组类型存在:
<type>[M]
:给定的固定长度类型的固定长度数组。
存在以下非固定大小类型:
bytes
:动态大小的字节序列。string
:动态大小的unicode字符串假定为UTF-8编码。<type>[]
:给定的固定长度类型的可变长度数组。
编码的形式规范
此规范现在作为Solidity文档的一部分进行维护。
现在我们将正式指定编码,以便它具有以下属性,如果某些参数是嵌套数组,则这些属性特别有用:
属性:
访问数值所需的读取次数至多是参数数组结构中值的深度,即需要四次读取才能检索
a_i[k][l][r]
。在ABI的以前版本中,读数的数量与最坏情况下动态参数的总数成线性关系。变量或数组元素的数据不与其他数据交错,并且是可重定位的,即它只使用相对“地址”
我们区分静态和动态类型。静态类型就地编码,动态类型在当前块之后的单独分配的位置进行编码。
定义:以下类型被称为“动态”:
bytes
string
T[]
为任何T
T[k]
任何动态T
和任何k > 0
所有其他类型被称为“静态”。
定义: len(a)
是二进制字符串中的字节数a
。len(a)
假定的类型是uint256
。
我们将enc
实际编码定义为ABI类型的值到二进制字符串的映射,这len(enc(X))
取决于X
当且仅当该类型X
是动态的值。
定义:对于任何ABI值X
,我们递归定义enc(X)
,根据类型X
是
T[k]
对于任何T
和k
:enc(X) = head(X[0]) ... head(X[k-1]) tail(X[0]) ... tail(X[k-1])
其中
head
和tail
被定义为X[i]
静态类型head(X[i]) = enc(X[i])
和tail(X[i]) = ""
(空字符串),head(X[i]) = enc(len(head(X[0]) ... head(X[k-1]) tail(X[0]) ... tail(X[i-1])))
tail(X[i]) = enc(X[i])
否则。请注意,在动态情况下,
head(X[i])
由于头部长度仅取决于类型而不取决于值,因此定义良好。它的值是开始tail(X[i])
相对于开始的偏移量enc(X)
。T[]
哪里X
有k
元素(k
假定是类型的uint256
):enc(X) = enc(k) enc([X[1], ..., X[k]])
即它被编码,就像它是一个静态大小的数组
k
,前缀的元素数量。bytes
,长度k
(假定是类型uint256
):enc(X) = enc(k) pad_right(X)
,即字节数被编码为一个 字节序列uint256
的实际值X
,接着是最小数量的零字节,这len(enc(X))
是32的倍数。string
:enc(X) = enc(enc_utf8(X))
,即X
UTF-8编码,这个值被解释为bytes
类型和进一步编码。请注意,此后续编码中使用的长度是utf-8编码字符串的字节数,而不是其字符数。uint<M>
:enc(X)
是大端编码X
,用零字节填充到较高(左)侧,长度是32字节的倍数。address
:就像uint160
这样int<M>
:enc(X)
是大端的二进制补码编码X
,在高位(左侧)填充0xff
负数X
,正数为零X
,字长为32字节的倍数。bool
:在这种uint8
情况下,1
用于true
和0
用于false
fixed<M>x<N>
:enc(X)
是enc(X * 2**N)
在哪里X * 2**N
被解释为一个int256
。fixed
:就像fixed128x19
这样ufixed<M>x<N>
:enc(X)
是enc(X * 2**N)
在哪里X * 2**N
被解释为一个uint256
。ufixed
:就像ufixed128x19
这样bytes<M>
:enc(X)
是X
用零字节填充的长度为32 的字节序列。
请注意,对于任何X
,len(enc(X))
是32的倍数。
函数选择器和参数编码
总而言之,f
使用参数调用函数a_1, ..., a_n
被编码为
function_selector(f) enc([a_1, ..., a_n])
和返回值v_1, ..., v_k
的f
被编码为
enc([v_1, ..., v_k])
其中的类型[a_1, ..., a_n]
和[v_1, ..., v_k]
被认为是固定长度的数组长度n
和k
分别。请注意严格地说,它 [a_1, ..., a_n]
可以是一个包含不同类型元素的“数组”,但是编码仍然可以很好地定义,因为假定的通用类型T
(上面)并没有被实际使用。
例子
此规范现在作为Solidity文档的一部分进行维护。
下面的contract
contract Foo {function bar(fixed[2] xy) {}function baz(uint32 x, bool y) returns (bool r) { r = x > 32 || y; }function sam(bytes name, bool z, uint[] data) {} }
因此,对于我们的Foo
例子,如果我们想call baz
与参数69
和true
,我们将通过68个字节总,可细分为:
0xcdcd77c0
:方法ID。这是作为签名的ASCII形式的Keccak散列的前4个字节而得出的baz(uint32,bool)
。0x0000000000000000000000000000000000000000000000000000000000000045
:第一个参数,一个uint32值69
填充到32个字节0x0000000000000000000000000000000000000000000000000000000000000001
:第二个参数 - 布尔值true
,填充为32个字节
总共:
0xcdcd77c000000000000000000000000000000000000000000000000000000000000000450000000000000000000000000000000000000000000000000000000000000001
它返回一个单一的bool
。例如,如果它返回false
,它的输出将是单字节数组0x0000000000000000000000000000000000000000000000000000000000000000
,单个布尔值。
如果我们想bar
用这个参数进行调用[2.125, 8.5]
,我们将总共传送68个字节,分解为:
0xab55044d
:方法ID。这是从签名派生的bar(fixed128x19[2])
。请注意,它将fixed
被其规范表示所替代fixed128x19
。0x0000000000000000000000000000000220000000000000000000000000000000
:第一个参数的第一部分,一个固定的128x19的值2.125
。0x0000000000000000000000000000000880000000000000000000000000000000
:第一个参数的第二部分,一个固定的128x19的值8.5
。
总共:
0xab55044d00000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000880000000000000000000000000000000
如果我们想叫sam
的论据"dave"
,true
而[1,2,3]
我们会通过292个字节总,细分为:
0xa5643bf2
:方法ID。这是从签名派生的sam(bytes,bool,uint256[])
。请注意,它将uint
被其规范表示所替代uint256
。0x0000000000000000000000000000000000000000000000000000000000000060
:第一个参数(动态类型)的数据部分的位置,从参数块的开始字节开始测量。在这种情况下0x60
。0x0000000000000000000000000000000000000000000000000000000000000001
:第二个参数:布尔值true。0x00000000000000000000000000000000000000000000000000000000000000a0
:第三个参数(动态类型)的数据部分的位置,以字节为单位。在这种情况下0xa0
。0x0000000000000000000000000000000000000000000000000000000000000004
:第一个参数的数据部分,它以元素中的字节数组的长度开始,在这种情况下是4。0x6461766500000000000000000000000000000000000000000000000000000000
:第一个参数的内容:UTF-8(在这种情况下等于ASCII)的编码"dave"
,在右边填充到32个字节。0x0000000000000000000000000000000000000000000000000000000000000003
:第三个参数的数据部分,它以元素中数组的长度开始,在这个例子中是3。0x0000000000000000000000000000000000000000000000000000000000000001
:第三个参数的第一个条目。0x0000000000000000000000000000000000000000000000000000000000000002
:第三个参数的第二个条目。0x0000000000000000000000000000000000000000000000000000000000000003
:第三个参数的第三个条目。
总共:
0xa5643bf20000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000464617665000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003
使用动态类型
此规范现在作为Solidity文档的一部分进行维护。
对f(uint,uint32[],bytes10,bytes)
具有值的签名的函数的调用(0x123, [0x456, 0x789], "1234567890", "Hello, world!")
按以下方式进行编码:
我们把前四个字节sha3("f(uint256,uint32[],bytes10,bytes)")
,即0x8be65246
。然后我们编码所有四个参数的头部分。对于静态类型uint256
和bytes10
,这些是直接我们想要传递的值,而对于动态类型uint32[]
和bytes
,我们使用在字节偏移到它们的数据区的开始,从值编码开始测量(即,不计数前四个字节包含函数签名的散列)。这些是:
0x0000000000000000000000000000000000000000000000000000000000000123
(0x123
填充到32个字节)0x0000000000000000000000000000000000000000000000000000000000000080
(第二个参数的数据部分的起始偏移,4 * 32个字节,正好是头部的大小)0x3132333435363738393000000000000000000000000000000000000000000000
("1234567890"
填充到右边的32个字节)0x00000000000000000000000000000000000000000000000000000000000000e0
(第四个参数的数据部分的起始偏移量=第一个动态参数的数据部分的起始偏移量+第一个动态参数的数据部分的大小= 4 * 32 + 3 * 32(见下文))
在此之后,第一个动态参数的数据部分[0x456, 0x789]
如下:
0x0000000000000000000000000000000000000000000000000000000000000002
(数组的元素个数,2)0x0000000000000000000000000000000000000000000000000000000000000456
(第一元素)0x0000000000000000000000000000000000000000000000000000000000000789
(第二元素)
最后,我们编码第二个动态参数的数据部分"Hello, world!"
:
0x000000000000000000000000000000000000000000000000000000000000000d
(元素数量(在这个例子中是字节数):13)0x48656c6c6f2c20776f726c642100000000000000000000000000000000000000
("Hello, world!"
填充到右边的32个字节)
总之,编码是(换行符之后的换行符,每个32字节为了清晰起见):
0x8be65246
0000000000000000000000000000000000000000000000000000000000000123
0000000000000000000000000000000000000000000000000000000000000080
3132333435363738393000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000e0
0000000000000000000000000000000000000000000000000000000000000002
0000000000000000000000000000000000000000000000000000000000000456
0000000000000000000000000000000000000000000000000000000000000789
000000000000000000000000000000000000000000000000000000000000000d
48656c6c6f2c20776f726c642100000000000000000000000000000000000000
活动
此规范现在作为Solidity文档的一部分进行维护。
事件是以太坊记录/事件监视协议的抽象。日志条目提供合同的地址,一系列最多四个主题和一些任意长度的二进制数据。事件利用现有的ABI函数来解释这个(连同一个接口规范)作为一个正确的类型结构。
给定一个事件名称和一系列的事件参数,我们将它们分成两个子系列:索引的和不是的。那些被编入索引的,可能数目最多为3的,与事件签名的Keccak散列一起使用,以形成日志条目的主题。那些没有索引的事件形成字节数组。
实际上,使用这个ABI的日志条目被描述为:
address
:合同地址(本质上由以太坊提供);topics[0]
:keccak(EVENT_NAME+"("+EVENT_ARGS.map(canonical_type_of).join(",")+")")
(canonical_type_of
就是简单地返回所述规范类型给定的参数,例如一个函数uint indexed foo
,它会返回uint256
)。如果该事件被声明为anonymous
在topics[0]
不产生;topics[n]
:EVENT_INDEXED_ARGS[n - 1]
(EVENT_INDEXED_ARGS
在一系列的EVENT_ARGS
被索引);data
:abi_serialise(EVENT_NON_INDEXED_ARGS)
(EVENT_NON_INDEXED_ARGS
是该系列的EVENT_ARGS
未索引,abi_serialise
用于从函数返回的一系列类型的值的ABI序列化的功能,如上文所述)。
JSON
此规范现在作为Solidity文档的一部分进行维护。
合约接口的JSON格式由一组函数和/或事件描述给出。函数描述是一个带有字段的JSON对象:
type
:"function"
,,"constructor"
或"fallback"
(未命名的“默认”功能);name
:函数的名字;inputs
:一个对象数组,每个对象都包含:name
:参数的名称;type
:参数的规范类型。
outputs
:类似于对象的数组,inputs
如果函数不返回任何东西,则可以省略;constant
:true
如果函数被指定为永不修改区块链状态 ;payable
:true
如果函数接受ether,则默认为false
。
type
可以省略,默认为"function"
。
构造函数和回退函数从来没有name
或outputs
。回退函数也没有inputs
。
发送非零以太币到非付款功能将抛出。不要这样做。
事件描述是一个JSON对象,具有相当类似的字段:
type
:总是"event"
name
:事件的名称;inputs
:一个对象数组,每个对象都包含:name
:参数的名称;type
:参数的规范类型。indexed
:true
如果该字段是日志主题的一部分,false
是否是其中的一个日志的数据段。
anonymous
:true
如果事件被声明为anonymous
。
例如,
contract Test {function Test(){ b = 0x12345678901234567890123456789012; }event Event(uint indexed a, bytes32 b);event Event2(uint indexed a, bytes32 b);function foo(uint a) { Event(a, b); }bytes32 b; }
会导致JSON:
[{ "type":"event", "inputs": [{"name":"a","type":"uint256","indexed":true},{"name":"b","type":"bytes32","indexed":false}], "name":"Event" }, { "type":"event", "inputs": [{"name":"a","type":"uint256","indexed":true},{"name":"b","type":"bytes32","indexed":false}], "name":"Event2" }, { "type":"function", "inputs": [{"name":"a","type":"uint256"}], "name":"foo", "outputs": [] }]
Javascript使用示例
此规范现在作为Solidity文档的一部分进行维护。
var Test = eth.contract( [{ "type":"event", "inputs": [{"name":"a","type":"uint256","indexed":true},{"name":"b","type":"bytes32","indexed":false}], "name":"Event" }, { "type":"event", "inputs": [{"name":"a","type":"uint256","indexed":true},{"name":"b","type":"bytes32","indexed":false}], "name":"Event2" }, { "type":"function", "inputs": [{"name":"a","type":"uint256"}], "name":"foo", "outputs": [] }]); var theTest = new Test(addrTest);// examples of usage: // every log entry ("event") coming from theTest (i.e. Event & Event2): var f0 = eth.filter(theTest); // just log entries ("events") of type "Event" coming from theTest: var f1 = eth.filter(theTest.Event); // also written as var f1 = theTest.Event(); // just log entries ("events") of type "Event" and "Event2" coming from theTest: var f2 = eth.filter([theTest.Event, theTest.Event2]); // just log entries ("events") of type "Event" coming from theTest with indexed parameter 'a' equal to 69: var f3 = eth.filter(theTest.Event, {'a': 69}); // also written as var f3 = theTest.Event({'a': 69}); // just log entries ("events") of type "Event" coming from theTest with indexed parameter 'a' equal to 69 or 42: var f4 = eth.filter(theTest.Event, {'a': [69, 42]}); // also written as var f4 = theTest.Event({'a': [69, 42]});// options may also be supplied as a second parameter with `earliest`, `latest`, `offset` and `max`, as defined for `eth.filter`. var options = { 'max': 100 }; var f4 = theTest.Event({'a': [69, 42]}, options);var trigger; f4.watch(trigger);// call foo to make an Event: theTest.foo(69);// would call trigger like: //trigger(theTest.Event, {'a': 69, 'b': '0x12345678901234567890123456789012'}, n); // where n is the block number that the event triggered in.
执行:
// e.g. f4 would be similar to: web3.eth.filter({'max': 100, 'address': theTest.address, 'topics': [ [69, 42] ]}); // except that the resultant data would need to be converted from the basic log entry format like: {'address': theTest.address,'topics': [web3.sha3("Event(uint256,bytes32)"), 0x00...0045 /* 69 in hex format */],'data': '0x12345678901234567890123456789012','number': n } // into data good for the trigger, specifically the three fields:Test.Event // derivable from the first topic{'a': 69, 'b': '0x12345678901234567890123456789012'} // derivable from the 'indexed' bool in the interface, the later 'topics' and the 'data'n // from the 'number'
活动结果:
[ {'event': Test.Event,'args': {'a': 69, 'b': '0x12345678901234567890123456789012'},'number': n},{ ...} ... ]
Ethereum Contract ABI相关推荐
- 【以太坊源码】交易(一)
交易是区块链中最基本也是最核心的一个概念,在以太坊中,交易更是重中之重,因为以太坊是一个智能合约平台,以太坊上的应用都是通过智能合约与区块链进行交互,而智能合约的执行是由交易触发的,没有交易,智能合约 ...
- 【区块链】以太坊Solidity编程:合约调用与web3.js
以太坊Solidity编程:合约调用与Web3.js 合约部署方法 合约的编译 使用浏览器编译器Remix 使用truffle编译,目前是最常用的编译方式 Solc或者Web3.js编译合约,使用相对 ...
- 区块链 以太坊 交易结构、执行、存储 解析 交易中为什么没有包含发送者地址这条数据
一. 交易的结构 1. Transaction结构 交易结构定义在 core/types/transaction.go 中: type Transaction struct {//交易数据data t ...
- web3@0.20.1 在依据abi创建智能合约的时候报错 TypeError: web3.eth.contract is not a function
前面的代码不变 var web3 = new Web3(new Web3.providers.HttpProvider("Http://localhost:8545")); var ...
- 使用Node.js部署智能合約(Smart Contract)
從智能合約原始檔.編譯.部署,一氣呵成 我想大部分的人應該都是為了寫智能合約(Smart Contract)而選擇使用Ethereum,在開發應用程式(Dapp)時,若能透過程式碼自動部署智能合約,就 ...
- The ultimate end-to-end tutorial to create and deploy a fully decentralized Dapp in ethereum
In this tutorial my objective is to walk you through the steps required to create a descentralized a ...
- Build a simple Ethereum + IPFS+ React.js DApp.
WHY ARE WE BUILDING THIS? It is prohibitively expensive to store a lot of data on the Ethereum block ...
- 智能合约Smart Contract技术详解
文章目录 合约编写 基本介绍 构造方法 ipfs mint 提现 白名单 合约 前端 部署 验证合约代码 前端和合约交互 准备工作 获取已经mint了的数量 mint 合约编写 建议读者先了解下sol ...
- Ethereum非同质化通证(NFT)的铸造与展示
Ethereum非同质化通证(NFT)的铸造与展示 前言 一.安装 Web3.js 二.创建 mint-nft.js 文件 三.获取合约应用程序二进制接口 四.使用IPFS为非同质化通证配置元数据 五 ...
最新文章
- SpringMVC中实现的token,防表单重复提交
- linux可以远程装机吗,linux 远程装机
- 快速排序之Java实现
- C++中 引用与取地址的区别
- Android中Application类用法
- Educational Codeforces Round 47 (Rated for Div. 2) :E. Intercity Travelling
- 配置cacti 监控squid
- BGP双线的真真假假
- SAP打印脱机请求和输出请求管理
- 将k8容器中文件下载到本地
- 《Redis入门指南(第 2 版)》读后感
- 经纬财富:宜昌炒白银和炒黄金有什么不同?
- java flv转mp3_java调用FFmpeg及mencoder转换视频为FLV并截图
- 机器学习实战(五) kaggle练习赛 泰坦尼克获救预测
- 月入3w+,6年经验测试开发工程师,见识到了真正意义上的测试天花板
- 【郭东白架构课 模块一:生存法则】05|法则二:研发人员的人性需求是如何影响架构活动成败的?
- 抖音html啥意思,用了这么久的抖音,你知道抖音到底是啥意思吗?
- Red Hat Enterprise Linux ISO 全镜像下载
- 调光LED RGB色准校准方案
- pytorch遇到Error loading “C:\Anaconda3\lib\site-packages\torch\lib\caffe2_detectron_ops_gpu.dll“
热门文章
- 基于第三方开发Android锁屏
- 解决WebView加载的网页被放大的问题
- MFC中主副屏窗口全屏最大化的几种方法
- Mac环境下brew安装、SVN安装
- uni-app 微信小程序支付/公众号支付/h5支付宝/h5微信/支付宝app支付/微信app支付
- 【c语言】my_strcat实现字符串连接
- 【精华】YOLO fastest/YOLOX/YOLO fastestv2/Nanodet/Nanodet Plus模型对比
- 怎么样用Python 读取oni 格式文件?
- python摄像头入侵_Python:通过摄像头实现的监控功能
- Theano、Lasagne、TensorFlow在Ubuntu14.04 64支持GPU的安装 py27