什么是abi

ABI-Application Binary Interface,应用二进制接口说明。
ABI可以简单理解成区块链外部与合约进行交互以及合约和合约之间进行交互的一种标准方式。数据会根据其类型按照这份手册中说明的方法进行编码。这种编码并不是可以自描述的,而是需要一种特定的概要(schema)来进行解码。在以太坊中主要用于solidity合约的函数调用,以及反向编码读取数据的中的方法。

solidityABI编码函数

abi.encodePacked(…) returns (bytes):计算参数的紧密打包编码
abi. encodeWithSelector(bytes4 selector, …) returns (bytes): 计算函数选择器和参数的 ABI 编码
abi.encodeWithSignature(string signature, …) returns (bytes): 等价于* abi.encodeWithSelector(bytes4(keccak256(signature), …)

solidityABI编码函数 实现细节

一个函数调用数据的前 4 字节,指定了要调用的函数。这就是某个函数签名的 Keccak(SHA-3)哈希的前 4 字节(高位在左的大端序)(译注:这里的“高位在左的大端序“,指最高位字节存储在最低位地址上的一种串行化编码方式,即高位字节在左)。 这种签名被定义为基础原型的规范表达,基础原型即是函数名称加上由括号括起来的参数类型列表,参数类型间由一个逗号分隔开,且没有空格。

简单来说,函数选择器就是通过函数名来参数来标识函数,可以用于不同合约之间的函数调用。
合约中函数调用截取调用数据的前四个字节(0x之后),就是将函数名以及参数类型进行签名处理(Keccak–Sha3)。

solidityABI编码函数实现:

    uint storedData;

    function set(uint x) public {
        storedData = x;
    }

    function abiEncode(uint x) public view returns (bytes memory) {
        abi.encode(x);  // 计算1的ABI编码
        return abi.encodeWithSignature("set(uint256)", x); //计算函数set(uint256) 及参数1 的ABI 编码
    }
}

remix部署合约之后,调用abiEncode()将会产生如下数据输出:
abi.encode(21)
0x60fe47b10000000000000000000000000000000000000000000000000000000000000015
其中60fe47b1便是对应的set()函数的签名处理:

 {
 	"constant": false,
 	"inputs": [
 		{
 			"internalType": "uint256",
 			"name": "value",
 			"type": "uint256"
 		}
 	],
 	"name": "set",
 	"outputs": [],
 	"payable": false,
 	"stateMutability": "nonpayable",
 	"type": "function"
 }
]

传入参数为21 对于16进制为15,合约函数名与函数参数,每个参数最终要被补全为32个字节。
** abiDetail: **

type: 调用参数类型: string,function,callback,contsructor
name: 调用参数名称
payable: 是否支持ether
stateMutability:(状态可变性) - pure - view - payable - nonpayable
outputs: 调用输出值
input:{
name: 参数名称
type: 参数类型
}

abi.encode 与abi.encodePacked

对函数打包处理,但是处理方式不一样,对于小于32字节类型的参数,前者会将所有参数自动补全到32个字节,后者不会自动补全。

      bytes memory _bts ="Hello,world!";
    return (abi.encodePacked(_bts),abi.encode(_bts));
  }
}
output:
0:
bytes: 0x48656c6c6f2c776f726c6421
1:
bytes: 0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000c48656c6c6f2c776f726c64210000000000000000000000000000000000000000

关于使用abi.encodeWithSignature(string signature, …) returns (bytes)

主要应用场景: 函数调用:

    uint storedData;

    function set(uint x) public {
        storedData = x;
    }

    function abiEncode() public constant returns (bytes) {
        abi.encode(1);  // 计算1的ABI编码
        return abi.encodeWithSignature("set(uint256)", 1); //计算函数set(uint256) 及参数1 的ABI 编码
    }
}

Web3 ABI 编码函数

另一个web3提供相应的API,例如使用web3计算函数选择器的方式如下:
web3.eth.abi.encodeFunctionSignature('myMethod(uint256,string)');