【Ethereum 智能合约开发笔记】深入 Ethereum 智能合约 ABI

虚拟猫咪合约 ABI

开发 DApp 时要呼叫在区块链上的 Ethereum 智能合约,就需要智能合约的 ABI。本篇希望更多了解 ABI,像是为什么需要 ABI?如何解读 Ethereum 的智能合约 ABI?以及如何取得智能合约的 ABI?

ABI(Application Binary Interface)

如果理解 API 就很容易了解 ABI。简单来说,API 是程式间互动的介面。这个介面包含程式提供外界存取的 functions、variables 等。ABI 也是程式间互动的介面,但程式是被编译后的 binary code。所以同样的介面,但传递是 binary 格式的资料。所以 ABI 就要描述如何 decode/encode 程式间传递的 binary 资料。下图以 Linux 为例,描述 Linux 中 API、ABI 和程式的关系。


编译和部署智能合约

话说在 Ethereum 智能合约可以被大家使用前,必须先被部署到区块链上。从智能合约的原始码到使用智能合约,大概包含几个步骤:

  1. 撰写智能合约的原始码(一般是用 Solidity 写)
  2. 编译智能合约的原始码成可在 EVM 上执行的 bytecode(binary code)。同时可以透过编译取得智能合约的 ABI
  3. 部署智能合约,实际上是把 bytecode 储存在链上(透过一个 transaction),并取得一个专属这个合约的地址
  4. 如果要写个程式呼叫这个智能合约,就要把资料发送到这个合约的地址(一样透过一个 transaction)。Ethereum 节点会根据输入的资料,选择要执行合约中的哪一个 function 和要输入的参数

而要如何知道这个智能合约提供哪些 function 以及应该要传入什么样的参数呢?这些资讯就是记录在智能合约的 ABI。


Ethereum 智能合约 ABI

Ethereum 智能合约 ABI 用一个 array 表示,其中会包含数个用 JSON 格式表示的 FunctionEvent。根据最新的 Solidity 文件:

Function

共有 7 个栏位:

  • name:a string,function 名称
  • type:a string,"function", "constructor", or "fallback"
  • inputs:an array,function 输入的参数,包含:
    • name:a string,参数名称
    • type:a string,参数的 data type(e.g. uint256)
    • components:an array,如果输入的参数是 tuple(struct) type 才会有这个栏位。描述 struct 中包含的资料型态
  • outputs:an array,function 的回传值,和 inputs 使用相同表示方式。如果没有回传值可忽略,值为 []
  • payabletrue,如果 function 可收 Ether,预设为 false
  • constanttrue,如果 function 不会改写区块链的状态,反之为 false
  • stateMutability:a string,其值可能为以下其中之一:"pure"(不会读和写区块链状态)、"view"(会读区块链状态,但不会改写区块链状态)、"payable" and "nonpayable"(会改写区块链状态,且如可收 Ether 为 "payable",反之为 "nonpayable")

仔细看会发现 payableconstant 这两个栏位所描述的内容,似乎已包含在 stateMutability 中。

事实的确是这样,在 Solidity v0.4.16 中把 constant 这个修饰 function 的 key words 分成 view(neither reads from nor writes to the state)和 pure(does not modify the state),并从 v0.4.17 开始 Type Checker 会强制检查。constant 改为只用来修饰不能被修改的 variable。并在 ABI 中加入 stateMutability 这个栏位统一表示,payableconstant 目前保留是为了向后兼容。这个更新详细的内容和讨论可参考:Introduce a real constant keyword and rename the current behaviour #992

Event

共有 4 个栏位:

  • name: a string,event 的名称
  • type: a string,always "event"
  • inputs: an array,输入的参数,包含:
    • name: a string,参数名称
    • type: a string,参数的 data type(e.g. uint256)
    • components: an array,如果输入的参数是 tuple(struct) type 才会有这个栏位。描述 struct 中包含的资料型态
    • indexed: true,如果这个参数被宣告为 indexed(被存在 log 的 topics 中),反之为 false(储存在 log 的 data 中)
  • anonymous: true,如果 event 被宣告为 anonymous

更新智能合约状态需要发送 transaction,transaction 需要等待验证,所以更新合约状态是非同步的,无法马上取得回传值。使用 Event 可以在状态更新成功后,将相关资讯记录到 Log,并让监听这个 Event 的 DApp 或任何使用介面收到通知。每一笔 transaction 都有对应的 Log。

所以简单来说,Event 可用来:1. 取得 function 更新合约状态后的回传值 2. 也可作为合约另外的储存空间。

Event 的参数分为:有 indexed,和其他没有 indexed 的。有 indexed 的参数可以使用 filter,例如同一个 Event,我可以选择只监听从特定 address 发出来的交易。每笔 Log 的资料同样分为两部分:Topics(长度最多为 4 的 array) 和 Data。有 indexed 的参数会储存在 Log 的 Topics,其他的存在 Data。如果宣告为 anonymous,就不会产生以下范例中的 Topics[0],其值为 Event signature 的 hash,作为这个 Event 的 ID。

event Set(address indexed _from, uint value)

要详细了解 Solidity Event 可参考 Solidity的event事件(二十一)|入门系列Solidity的event的支持指引(二十二)|入门系列

用一个简单的智能合约举例

这个智能合约包含:

  • data:一个可改写的 state variable,会自动产生一个只能读取的 data() function
  • set():一个改写 data 值的 function
  • Set():一个在每次更新 data 纪录 log 的 event

智能合约 Source Code:

pragma solidity ^0.4.20;

contract SimpleStorage {
    uint public data;
    
    event Set(address indexed _from, uint value);
    
    function set(uint x) public {
        data = x;
        Set(msg.sender, x);
    }
}

智能合约 ABI:

[{
        "constant": true,
        "inputs": [],
        "name": "data",
        "outputs": [{"name": "","type": "uint256"}],
        "payable": false,
        "stateMutabㄒility": "view",
        "type": "function"
    },
    {
        "anonymous": false,
        "inputs": [{"indexed": true,"name": "_from","type": "address"},{"indexed": false,"name": "value","type": "uint256"}],
        "name": "Set",
        "type": "event"
    },
    {
        "constant": false,
        "inputs": [{"name": "x","type": "uint256"}],
        "name": "set",
        "outputs": [],
        "payable": false,
        "stateMutability": "nonpayable",
        "type": "function"
}]

取得 Ethereum 智能合约 ABI

Solidity Compiler

可以用 Solidity Compiler 取得合约 ABI,我使用 JavaScript 版本的 Compiler 为例。

安装:

npm install solc -g

取得合约 ABI:

solcjs simpleStorage.sol --abi

会产生一个 simpleStorage_sol_SimpleStorage.abi 档案,里面就是合约 ABI 内容。

也可以取得合约 binary code:

solcjs your_contract.sol --bin

Remix

同样使用 Solidity Compiler,也可以用 Remix。在合约的 Details 可以看到完整的 ABI。可以在 Settings 中指定 Compiler 版本。

Remix

Etherscan

许多知名合约会把合约 source code 放上 Etherscan 做验证,可以同时看到合约 ABI。

Etherscan

另外有提供 API 可以取得经验证的合约 ABI。


References

相关套件

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,761评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,953评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,998评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,248评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,130评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,145评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,550评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,236评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,510评论 1 291
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,601评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,376评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,247评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,613评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,911评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,191评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,532评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,739评论 2 335