前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >以太坊合约 ABI 和 EVM 字节码

以太坊合约 ABI 和 EVM 字节码

作者头像
Tiny熊
发布2022-05-25 10:32:50
1.4K0
发布2022-05-25 10:32:50
举报
文章被收录于专栏:深入浅出区块链技术

本文作者:影无双[1]

本文从理论和命令行实践解释以太坊合约 ABI 和 EVM 字节码

介绍

本文解释以太坊中的合约 ABI[2] 和 EVM[3] 字节码。由于以太坊使用 EVM(Ethereum Virtual Machine - 以太坊虚拟机)作为系统的核心,因此用高级语言编写的智能合约代码需要编译成 EVM 字节码和合约 ABI 才能运行。在与智能合约交互时,有必要先了解它们。

你将了解到

  • 了解合约 ABI 和 EVM 字节码是什么,以及它们的关系。
  • 如何使用solc命令行生成合约 ABI 和 EVM 字节码

不包括:

  • 合约 ABI 规范的详细信息(编码/解码)。
  • 如何编写智能合约
  • 以太坊和区块链的基本解释

希望读者已经具备以太坊和区块链的基本知识。

字节码和 ABI

由于以太坊使用 EVM 作为网络的核心组件,因此用高级语言编写的智能合约代码需要编译成 EVM 字节码才能运行。EVM 字节码是 EVM 上的可执行代码,合约 ABI 是与 EVM 字节码交互的接口。例如,如果你想用你的 JavaScript 代码调用智能合约中的函数,ABI 扮演着你的 JavaScript 代码和 EVM 字节码彼此交互的中介角色。下图显示了合约 ABI、EVM 字节码和外部组件(dApp 和网络)的架构 。左边是编译过程,右边是交互。

Ethernaut Lvl 0 Walkthrough: ABIs, Web3, and how to abuse them[4]

EVM 字节码(Bytecode)

EVM 字节码是一种低级编程语言,它是从高级编程语言(如 solidity)编译而来的。EVM 是虚拟机,介于操作系统和应用层之间,以减少对操作系统的依赖。多亏了 EVM,以太坊智能合约几乎可以在任何计算机上运行。如果你是 Java 开发者,可以把它类比为 JVM(Java 虚拟机),它们有相同的机制。EVM 字节码如下所示。它不是人类可读的,而是机器可读的。

6080604052348015600f57600080fd5b5060878061001e6000396000f3fe6080604052348015600f57600080fd5b50600436

1060285760003560e01c8063037a417c14602d575b600080fd5b60336049565b6040518082815260200191505060405180910

390f35b6000600190509056fea265627a7a7230582050d33093e20eb388eec760ca84ba30ec42dadbdeb8edf5cd8b261e89b8

d4279264736f6c634300050a0032

在 Remix IDE 上编译时,你会看到如下四个字段。它们代表了字节码的更多细节,例如linkReferenceopcodessource Mapobject是一个 EVM 字节码。

linkReference: 当前智能合约有依赖的其他智能合约地址object: 当前智能合约字节码opcodes: 操作码,是人类可读的低级指令sourceMap: 源映射,用于将每个合约指令与生成它的源码部分相对应

合约 ABI

在计算机科学中,ABI(Application Binary Interface)是两个程序模块之间的接口;通常是在操作系统和用户程序之间。在以太坊中,合约 ABI 是一个接口,它定义了如何调用智能合约中的函数并取回数据的标准方案。合约 ABI 为外部使用而设计,实现应用程序到合约和合约到合约的交互。例如,如果你想从 dApp 调用智能合约函数,就可以通过合约 ABI 调用。合约 ABI 用如下的 JSON 格式表示:

代码语言:javascript
复制
[
   {
      "constant":true,
      "inputs":[
      ],
      "name":"testFunc",
      "outputs":[
         {
            "name":"",
            "type":"int256"
         }
      ],
      "payable":false,
      "stateMutability":"pure",
      "type":"function"
   }
]

合约 ABI 定义函数名称和参数数据类型,用于对 EVM 的合约调用进行编码并从交易中读取数据。关于如何编码和解码合约 ABI 有一个明确的规范。下面是一个用函数来描述编码的例子:

代码语言:javascript
复制
function withdraw(uint withdraw_amount) public {}

首先,withdraw函数将用 keccak256 编码,前 4 个字节会用作选择器。选择器用来标识调用哪个函数。

代码语言:javascript
复制
// Encode function with keccak256.
> web3.utils.sha3(“withdraw(uint256)”)
0x2e1a7d4d13322e7b96f9a57413e1525c250fb7a9021cf91d1540d5b69f16a49f
// Extract first 4 bytes.
0x2c1a7d4d

接下来,参数将以十六进制编码,并附加到有 32 字节填充的已编码的withdraw函数。

代码语言:javascript
复制
// Convert from ETH to Wei.
> withdraw_amount = web3.utils.toWei(“0.01", “ether”);
10000000000000000
// Convert Wei with hexdecimal.
> withdraw_amount_hex = web3.toHex(withdraw_mount);
0x2386f26fc10000
// Left padding.
> withdraw_amount_padleft = web3.utils.leftPad(withdraw_amount_hex, 32);
0x0000000000000000002386f26fc10000
// Append to selector(encoded function).
“0x2c1a7d4d” + withdraw_amount_padleft
// Final encoded ABI.
0x2c1a7d4d0x0000000000000000002386f26fc10000

数据调用withdraw函数并请求0.01作为参数。如果您想了解 ABI 编码/解码规范的详细信息,请参阅合约 ABI 规范[5]

实际上,与合约交互,你可以像下面这样使用 web3.js。首先是与合约 ABI 签订合约,接下来是用 EVM 字节码创建一个实例。这个代码是 Solidity REMIX 在编译成功时生成的。

代码语言:javascript
复制
var samplecontractContract = web3.eth.contract([{"constant":true,"inputs":[],"name":"testFunc","outputs":[{"name":"","type":"int256"}],"payable":false,"stateMutability":"pure","type":"function"}]);
var samplecontract = samplecontractContract.new(
   {
     from: web3.eth.accounts[0],
     data: '0x6080604052348015600f57600080fd5b50607e8061001e6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063037a417c14602d575b600080fd5b60336049565b6040518082815260200191505060405180910390f35b6000600190509056fea165627a7a72305820e710d7394e9965c17ead6bb53757a23caee28d75a0a02b483638015a49dac6070029',
     gas: '4700000'
   }, function (e, contract){
    console.log(e, contract);
    if (typeof contract.address !== 'undefined') {
         console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash);
    }
 })

solc命令

我们看看如何用solc命令生成合约 ABI 和 EVM 字节码。solc命令是最常用的编译器之一。用 npm 包管理器安装它:

安装

代码语言:javascript
复制
$ npm install -g solc

下面是示例源代码,文件名为SampleToken.sol

代码语言:javascript
复制
pragma solidity ^0.5.8;

contract  SampleContract {

    function testFunc() public pure returns (int) {
        return 1;
    }
}

输出 EVM 字节码

代码语言:javascript
复制
$ solc --bin SampleToken.sol
> ======= SampleContract.sol:SampleContract =======
Binary:
6080604052348015600f57600080fd5b5060878061001e6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063037a417c14602d575b600080fd5b60336049565b6040518082815260200191505060405180910390f35b6000600190509056fea265627a7a7230582050d33093e20eb388eec760ca84ba30ec42dadbdeb8edf5cd8b261e89b8d4279264736f6c634300050a0032

输出合约 ABI

代码语言:javascript
复制
$ sold —abi SampleToken.sol
> ======= SampleContract.sol:SampleContract =======
Contract JSON ABI
[{"constant":true,"inputs":[],"name":"testFunc","outputs":[{"name":"","type":"int256"}],"payable":false,"stateMutability":"pure","type":"function"}]

如果要输出到特定目录,可以使用-o选项进行设置(不能设置输出文件名)。

代码语言:javascript
复制
$ mkdir build
$ solc --abi -o build SampleToken.sol

重新编译时,设置--overwrite选项。

代码语言:javascript
复制
$ solc --abi -o build —overwrite SampleToken.sol

帮助

代码语言:javascript
复制
$ solc --help

结论

本文解释了合约 ABI 和 EVM 字节码。EVM 字节码是从高级编程语言编译来的源代码,合约 ABI 是与 EVM 字节码交互的接口。它们都可以用solc命令行编译,solc命令行主要用于以太坊开发。希望这篇文章能帮助你实际理解合约 ABI 和 EVM 字节码。如果您有任何问题或意见,随时欢迎。谢谢。

参考

Solidity 字节码和操作码基础知识[6]

什么是 ABI,为什么需要用它与合约交互?[7]

calldata 关键字作为 solidity v0.5.0 函数中的参数?[8]

Solidity 源映射[9]

原文链接:https://medium.com/@eiki1212/explaining-ethereum-contract-abi-evm-bytecode-6afa6e917c3b

参考资料

[1]

影无双: https://learnblockchain.cn/people/58

[2]

ABI: https://learnblockchain.cn/2018/08/09/understand-abi

[3]

EVM: https://learnblockchain.cn/2019/10/05/evm-data

[4]

Ethernaut Lvl 0 Walkthrough: ABIs, Web3, and how to abuse them: https://hackernoon.com/ethernaut-lvl-0-walkthrough-abis-web3-and-how-to-abuse-them-d92a8842d71b

[5]

合约 ABI 规范: https://solidity.readthedocs.io/en/latest/abi-spec.html

[6]

Solidity 字节码和操作码基础知识: /@blockchain101/solidity-bytecode-and-opcode-basics-672e9b1a88c2

[7]

什么是 ABI,为什么需要用它与合约交互?: https://ethereum.stackexchange.com/questions/234/what-is-an-abi-and-why-is-it-needed-to-interact-with-contracts

[8]

calldata 关键字作为 solidity v0.5.0 函数中的参数?: https://ethereum.stackexchange.com/questions/63247/calldata-keyword-as-parameter-in-solidity-v0-5-0-function

[9]

Solidity 源映射: https://blog.diatomic.software/solidity-source-mapping/

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-04-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 深入浅出区块链技术 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 介绍
  • 你将了解到
  • 字节码和 ABI
  • EVM 字节码(Bytecode)
  • 合约 ABI
  • solc命令
  • 结论
  • 参考
    • 参考资料
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档