以太坊合同ABI

William Entriken 编辑此页面 

此规范现在作为Solidity文档的一部分进行维护。

功能

基本设计

我们假设应用程序二进制接口(ABI)是强类型的,在编译时和静态时是已知的。不会提供自检机制。我们断言,在编译是可调用的contract都具有接口定义。

本规范不涉及接口是动态的或者运行时的情况。如果这些情况变得重要,那么它们可以作为以太坊生态系统内的设施进行充分处理。

Function Selector

函数调用的调用数据的前四个字节指定要调用的函数。它是函数的Keccak(SHA-3)哈希签名中的第一个(左边的,高位的big-endian)四个字节。签名被定义为基本原型的规范表达式,即带有括号的参数类型列表的函数名称。参数类型由一个逗号分隔 - 不使用空格。

参数编码

编码的参数跟随, 从第五个字节开始。这种编码也用于其他地方,例如返回值和事件参数都以相同的方式编码,而不用四个字节来指定函数。

类型

存在以下基本类型:

  • uint<M>:无符号整数类型,M个0 < M <= 256,,M % 8 == 0。例如uint32uint8uint256
  • int<M>:二进制补码有符号整数类型的M0 < M <= 256,,M % 8 == 0
  • address:相当于uint160,除了假设的解释和语言类型。
  • uintint:同义词uint256int256分别(不被用于计算功能选择)。
  • bool:相当于uint8限制为值0和1
  • fixed<M>x<N>:有符号的定点小数的M比特,0 < M <= 256M % 8 ==0,和0 < N <= 80,其表示的值v作为v / (10 ** N)
  • ufixed<M>x<N>:无符号的变体fixed<M>x<N>
  • fixedufixed:同义词fixed128x19ufixed128x19分别(不被用于计算功能选择)。
  • bytes<M>M字节的二进制类型0 < M <= 32
  • function:相当于bytes24:一个地址,后跟一个功能选择器

以下(固定大小)数组类型存在:

  • <type>[M]:给定的固定长度类型的固定长度数组。

存在以下非固定大小类型:

  • bytes:动态大小的字节序列。
  • string:动态大小的unicode字符串假定为UTF-8编码。
  • <type>[]:给定的固定长度类型的可变长度数组。

编码的形式规范

此规范现在作为Solidity文档的一部分进行维护。

现在我们将正式指定编码,以便它具有以下属性,如果某些参数是嵌套数组,则这些属性特别有用:

属性:

  1. 访问数值所需的读取次数至多是参数数组结构中值的深度,即需要四次读取才能检索a_i[k][l][r]。在ABI的以前版本中,读数的数量与最坏情况下动态参数的总数成线性关系。

  2. 变量或数组元素的数据不与其他数据交错,并且是可重定位的,即它只使用相对“地址”

我们区分静态和动态类型。静态类型就地编码,动态类型在当前块之后的单独分配的位置进行编码。

定义:以下类型被称为“动态”:

  • bytes
  • string
  • T[] 为任何 T
  • T[k]任何动态T和任何k > 0

所有其他类型被称为“静态”。

定义: len(a)是二进制字符串中的字节数alen(a)假定的类型是uint256

我们将enc实际编码定义为ABI类型的值到二进制字符串的映射,这len(enc(X))取决于X当且仅当该类型X 是动态的值。

定义:对于任何ABI值X,我们递归定义enc(X),根据类型X

  • T[k]对于任何Tk

    enc(X) = head(X[0]) ... head(X[k-1]) tail(X[0]) ... tail(X[k-1])

    其中headtail被定义为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[]哪里Xk元素(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)),即XUTF-8编码,这个值被解释为bytes类型和进一步编码。请注意,此后续编码中使用的长度是utf-8编码字符串的字节数,而不是其字符数。

  • uint<M>enc(X)是大端编码X,用零字节填充到较高(左)侧,长度是32字节的倍数。

  • address:就像uint160这样

  • int<M>enc(X)是大端的二进制补码编码X,在高位(左侧)填充0xff负数X,正数为零X,字长为32字节的倍数。

  • bool:在这种uint8情况下,1用于true0用于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 的字节序列。

请注意,对于任何Xlen(enc(X))是32的倍数。

函数选择器和参数编码

总而言之,f使用参数调用函数a_1, ..., a_n被编码为

function_selector(f) enc([a_1, ..., a_n])

和返回值v_1, ..., v_kf被编码为

enc([v_1, ..., v_k])

其中的类型[a_1, ..., a_n][v_1, ..., v_k]被认为是固定长度的数组长度nk分别。请注意严格地说,它 [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与参数69true,我们将通过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。然后我们编码所有四个参数的头部分。对于静态类型uint256bytes10,这些是直接我们想要传递的值,而对于动态类型uint32[]bytes,我们使用在字节偏移到它们的数据区的开始,从值编码开始测量(即,不计数前四个字节包含函数签名的散列)。这些是:

  • 0x00000000000000000000000000000000000000000000000000000000000001230x123填充到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)。如果该事件被声明为anonymoustopics[0]不产生;
  • topics[n]EVENT_INDEXED_ARGS[n - 1]EVENT_INDEXED_ARGS在一系列的EVENT_ARGS被索引);
  • dataabi_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如果函数不返回任何东西,则可以省略;
  • constanttrue如果函数被指定为永不修改区块链状态 ;
  • payabletrue如果函数接受ether,则默认为false

type可以省略,默认为"function"

构造函数和回退函数从来没有nameoutputs。回退函数也没有inputs

发送非零以太币到非付款功能将抛出。不要这样做。

事件描述是一个JSON对象,具有相当类似的字段:

  • type:总是 "event"
  • name:事件的名称;
  • inputs:一个对象数组,每个对象都包含:
    • name:参数的名称;
    • type:参数的规范类型。
    • indexedtrue如果该字段是日志主题的一部分,false是否是其中的一个日志的数据段。
  • anonymoustrue如果事件被声明为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相关推荐

  1. 【以太坊源码】交易(一)

    交易是区块链中最基本也是最核心的一个概念,在以太坊中,交易更是重中之重,因为以太坊是一个智能合约平台,以太坊上的应用都是通过智能合约与区块链进行交互,而智能合约的执行是由交易触发的,没有交易,智能合约 ...

  2. 【区块链】以太坊Solidity编程:合约调用与web3.js

    以太坊Solidity编程:合约调用与Web3.js 合约部署方法 合约的编译 使用浏览器编译器Remix 使用truffle编译,目前是最常用的编译方式 Solc或者Web3.js编译合约,使用相对 ...

  3. 区块链 以太坊 交易结构、执行、存储 解析 交易中为什么没有包含发送者地址这条数据

    一. 交易的结构 1. Transaction结构 交易结构定义在 core/types/transaction.go 中: type Transaction struct {//交易数据data t ...

  4. 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 ...

  5. 使用Node.js部署智能合約(Smart Contract)

    從智能合約原始檔.編譯.部署,一氣呵成 我想大部分的人應該都是為了寫智能合約(Smart Contract)而選擇使用Ethereum,在開發應用程式(Dapp)時,若能透過程式碼自動部署智能合約,就 ...

  6. 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 ...

  7. 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 ...

  8. 智能合约Smart Contract技术详解

    文章目录 合约编写 基本介绍 构造方法 ipfs mint 提现 白名单 合约 前端 部署 验证合约代码 前端和合约交互 准备工作 获取已经mint了的数量 mint 合约编写 建议读者先了解下sol ...

  9. Ethereum非同质化通证(NFT)的铸造与展示

    Ethereum非同质化通证(NFT)的铸造与展示 前言 一.安装 Web3.js 二.创建 mint-nft.js 文件 三.获取合约应用程序二进制接口 四.使用IPFS为非同质化通证配置元数据 五 ...

最新文章

  1. SpringMVC中实现的token,防表单重复提交
  2. linux可以远程装机吗,linux 远程装机
  3. 快速排序之Java实现
  4. C++中 引用与取地址的区别
  5. Android中Application类用法
  6. Educational Codeforces Round 47 (Rated for Div. 2) :E. Intercity Travelling
  7. 配置cacti 监控squid
  8. BGP双线的真真假假
  9. SAP打印脱机请求和输出请求管理
  10. 将k8容器中文件下载到本地
  11. 《Redis入门指南(第 2 版)》读后感
  12. 经纬财富:宜昌炒白银和炒黄金有什么不同?
  13. java flv转mp3_java调用FFmpeg及mencoder转换视频为FLV并截图
  14. 机器学习实战(五) kaggle练习赛 泰坦尼克获救预测
  15. 月入3w+,6年经验测试开发工程师,见识到了真正意义上的测试天花板
  16. 【郭东白架构课 模块一:生存法则】05|法则二:研发人员的人性需求是如何影响架构活动成败的?
  17. 抖音html啥意思,用了这么久的抖音,你知道抖音到底是啥意思吗?
  18. Red Hat Enterprise Linux ISO 全镜像下载
  19. 调光LED RGB色准校准方案
  20. pytorch遇到Error loading “C:\Anaconda3\lib\site-packages\torch\lib\caffe2_detectron_ops_gpu.dll“

热门文章

  1. 基于第三方开发Android锁屏
  2. 解决WebView加载的网页被放大的问题
  3. MFC中主副屏窗口全屏最大化的几种方法
  4. Mac环境下brew安装、SVN安装
  5. uni-app 微信小程序支付/公众号支付/h5支付宝/h5微信/支付宝app支付/微信app支付
  6. 【c语言】my_strcat实现字符串连接
  7. 【精华】YOLO fastest/YOLOX/YOLO fastestv2/Nanodet/Nanodet Plus模型对比
  8. 怎么样用Python 读取oni 格式文件?
  9. python摄像头入侵_Python:通过摄像头实现的监控功能
  10. Theano、Lasagne、TensorFlow在Ubuntu14.04 64支持GPU的安装 py27