主页 > imtoken交易所在哪里 > 以太坊合约 ABI 和 EVM 字节码

以太坊合约 ABI 和 EVM 字节码

imtoken交易所在哪里 2023-06-18 08:00:23

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

介绍

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

您将学习

不包括:

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

字节码和 ABI

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

以太坊合约地址和帐户地址_以太坊合约地址查询_以太坊做合约

Ethernaut Lvl 0 演练:ABI、Web3 以及如何滥用它们[4]

EVM字节码(Bytecode)

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

6080604052348015600f57600080fd5b5060878061001e6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063037a417c14602d575b600080fd5b60336049565b6040518082815260200191505060405180910390f35b6000600190509056fea265627a7a7230582050d33093e20eb388eec760ca84ba30ec42dadbdeb8edf5cd8b261e89b8d4279264736f6c634300050a0032

在 Remix IDE 上编译时,您会看到以下四个字段。 它们表示字节码的更多细节,例如 linkReference、opcodes 和 source Map。 object 是一个 EVM 字节码。

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

合约ABI

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

[
   {
      "constant":true,
      "inputs":[
      ],
      "name":"testFunc",
      "outputs":[
         {
            "name":"",
            "type":"int256"
         }
      ],
      "payable":false,
      "stateMutability":"pure",
      "type":"function"
   }
]

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

function withdraw(uint withdraw_amountpublic {}

首先,withdraw 函数将使用 keccak256 进行编码,前 4 个字节将用作选择器。 选择器用于标识要调用的函数。

// Encode function with keccak256.
> web3.utils.sha3(“withdraw(uint256)”)
0x2e1a7d4d13322e7b96f9a57413e1525c250fb7a9021cf91d1540d5b69f16a49f
// Extract first 4 bytes.
0x2c1a7d4d

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

// 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在编译成功时生成的。

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 包管理器安装它:

安装

$ npm install -g solc

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

pragma solidity ^0.5.8;

contract  SampleContract {

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

输出 EVM 字节码

$ solc --bin SampleToken.sol
> ======= SampleContract.sol:SampleContract =======
Binary:
6080604052348015600f57600080fd5b5060878061001e6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063037a417c14602d575b600080fd5b60336049565b6040518082815260200191505060405180910390f35b6000600190509056fea265627a7a7230582050d33093e20eb388eec760ca84ba30ec42dadbdeb8edf5cd8b261e89b8d4279264736f6c634300050a0032

出口合同ABI

$ 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选项设置(输出文件名不能设置)。

$ mkdir build
$ solc --abi -o build SampleToken.sol

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

$ solc --abi -o build —overwrite SampleToken.sol

帮助

$ solc --help

综上所述

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

参考

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

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

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

Solidity 源地图[9]

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

参考文献[1]

影子武士:

[2]

阿比:

[3]

虚拟机:

[4]

Ethernaut Lvl 0 演练:ABI、Web3 以及如何滥用它们:

[5]

合约ABI规范:

[6]

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

[7]

什么是 ABI,为什么需要它来与合约交互? :

[8]

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

[9]

Solidity 源地图:

以太坊合约地址和帐户地址_以太坊做合约_以太坊合约地址查询