以太坊虚拟机中的应用程序二进制接口(ABI)
智能合约是存储在区块链上并由以太坊虚拟机 (EVM) 执行的代码片段。 EVM 还提供了一个称为操作码的综合指令集,用于执行某些指令。操作码是类似于处理器指令集的低级代码。可以从以太坊黄皮书访问常见的以太坊操作码。整个程序以字节或二进制表示的形式编译并存储在以太坊区块链中作为地址的形式。对于以太坊和 EVM,合约只是在此字节序列上运行的单个程序。只有像 Solidity、Viper 或 Bamboo 这样的高级语言定义了从程序入口点到特定函数入口点的方式。当外部应用程序或另一个智能合约想要与区块链交互时,它需要了解一些智能合约的接口知识,例如识别方法及其参数的方法。以太坊应用程序二进制接口 (ABI) 促进了这一点。
它类似于应用程序接口 (API),它本质上是以人类可读形式或高级语言表示的代码接口。在 EVM 中,编译后的代码存储为二进制数据,人类可读的界面消失了,智能合约交互必须转换为 EVM 可以解释的二进制格式。 ABI 定义了方法和结构,您可以简单地使用这些方法和结构与该二进制合约进行交互(就像 API 那样),只是在较低的级别上。 ABI 向调用者指示需要编码的信息(函数签名和变量声明),以便虚拟机调用字节码(合同)可以理解。这个过程称为ABI 编码。
ABI 是两个程序模块之间的接口,其中之一主要是在机器代码级别。该接口是将数据编码/解码为机器代码或从机器代码中解码的默认方法。在以太坊中,基本上是如何编码语言以对 EVM 进行合同调用,或者如何从交易中读取数据。在大多数情况下,ABI 编码是由编译器中的工具(如 REMIX 或可以与区块链交互的钱包)自动执行的。 ABI 编码器需要对合约接口的描述,如函数名称和参数,通常以 JSON 形式提供。
ABI 编码示例
以太坊智能合约是部署在以太坊区块链上的字节码。合同中可能有多个功能。 ABI 是必需的,以便您可以指向要调用的特定函数调用,并保证该函数将以您期望的格式返回数据。
发送到合约的交易有效负载的前四个字节通常用于区分要调用合约中的哪个函数。
1) 合约 GeeksForGeeks具有一定的功能。让我们调用函数baz(...) 。
contract GeeksForGeeks {
function empty() {}
function baz(uint32 x, bool y) returns (bool r)
{ if(x>0)
r = true;
else
r =false;
}
function Ritu(bytes _name, bool _x) {}
}
使用参数 69 和 true 的函数调用 baz,我们总共将传递 68 个字节。
Method ID.
This is derived as the first 4 bytes of the Keccak-256 hash of the ASCII form of the signature baz(uint32,bool)
0xcdcd77c0
First parameter
uint32 value 69 padded to 32 bytes
0x0000000000000000000000000000000000000000000000000000000000000045:
Second parameter
boolean true, padded to 32 bytes
0x0000000000000000000000000000000000000000000000000000000000000001:
2) balanceOf是一个用来获取余额的函数。函数签名如下:
balanceOf(address)
计算此签名字符串的 keccak256 哈希值会产生:
0x70a08231b98ef4ca268c9cc3f6b4590e4bfec28280db06bb5d45e689f2a360be
取前四个字节为我们提供了以下函数选择器或方法 ID,如上所示:
0x70a08231
ABI 编码不是以太坊核心协议的一部分,因为交易中的有效载荷数据不需要具有任何结构,它只是一个字节序列。同样,以太坊虚拟机也只是将数据作为字节序列进行处理。例如,一个事务包含字节序列。如何将这些字节解释为结构化数据取决于程序和所使用的编程语言。为了让用不同编程语言编写的两个程序能够相互调用,这些语言的编译器应该以相同的方式实现数据的序列化和反序列化,即虽然它们应该实现它们不是被迫的ABI。
示例:在下面的示例中,创建了一个合约来存储一个数字并返回存储的数字。在示例下方,有两个输出:一个是 ABI 输出,第二个是代码执行的输出,即 Solidity 代码的简单部署和运行输出。
Solidity
// Solidity program to
// demonstrate abi encoding
pragma solidity >=0.4.22 <0.7.0;
// Creating a contract
contract Storage
{
// Declaring a state variable
uint256 number;
// Defining a function
// to store the number
function store(uint256 num) public
{
number = num;
}
// Defining a function to
// send back or return the
// stored number
function retrieve() public
view returns (uint256)
{
return number;
}
}
ABI 输出:
[
{
"inputs": [],
"name": "retrieve",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "num",
"type": "uint256"
}
],
"name": "store",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]
输出: