abi编码函数
什么是abi
应用程序二进制接口,以太坊的调用合约时的接口说明
ABI是两个程序模块之间的接口,主要是用于将数据编码或解码为源代码所表示的代码。
以太坊中主要用于solidity合约的函数调用,以及反向编码读取数据的中的方法
solidityABI编码函数
- abi.encode(…) returns (bytes):计算参数的 ABI 编码。
- 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 字节(高位在左的大端序)(译注:这里的“高位在左的大端序“,指最高位字节存储在最低位地址上的一种串行化编码方式,即高位字节在左)。 这种签名被定义为基础原型的规范表达,基础原型即是函数名称加上由括号括起来的参数类型列表,参数类型间由一个逗号分隔开,且没有空格。
简单来说,函数选择器就是通过函数名来参数来标识函数,可以用于不同合约之间的函数调用
1.合约中函数调用截取调用数据的前四个字节(0x之后),就是将函数名以及参数类型进行签名处理(Keccak–Sha3),
- 执行set(21)函数 可以得到结果:
60fe47b1 set(uint256) -这便是获取到函数签名散列截取到的前四个字节(一个字节对应16进制2个字符) - 传入参数为21 对于16进制为15
- 函数最终结果: 0x60fe47b10000000000000000000000000000000000000000000000000000000000000015
合约函数名与函数参数,每个参数最终要被补全为32个字节
solidityABI编码函数实现:
contract testABI {
uint storedData;
function set(uint x) public {
storedData = x;
}
function abiEncode() public view returns (bytes memory) {
abi.encode(1); // 计算1的ABI编码
return abi.encodeWithSignature("set(uint256)", 1); //计算函数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" }
]
``
abiDetail:
- constant – 如果函数改变区块链状态为true,反之false;
- type: 调用参数类型: string,function,callback,contsructor
- name: 调用参数名称
- payable: 是否支持ether
- stateMutability:(状态可变性) - pure - view - payable - nonpayable
- outputs: 调用输出值
- input:{
- name: 参数名称
- type: 参数类型
}
abi.encode 与abi.encodePacked
-
对函数打包处理,但是处理方式不一样,对于小于32字节类型的参数,前者会将所有参数自动补全到32个字节,后者不会自动补全
-
uint默认是uint256,验证时并不存在补全字节这个问题
contract TestDifference {
function testUint(
uint8 _num1,
uint32 _num2
)
public view returns (bytes memory, bytes memory) {
return (
abi.encode(_num1),
abi.encodePacked(_num2)
);
}
function testBytes() public view returns (bytes memory, bytes memory) {
bytes memory _bts ="Hello,world!";
return (abi.encodePacked(_bts),abi.encode(_bts));
}
}
关于使用abi.encodeWithSignature(string signature, …) returns (bytes)
主要应用场景: 函数调用
contract Contract {
MyContract contract1 = new MyContract();
function getSelector() public view returns (bytes4, bytes4) {
return (contract1.function1.selector, contract1.getBalance.selector);
}
function callGetValue(uint _x) public view returns (uint) {
bytes4 selector = contract1.getValue.selector;
bytes memory data = abi.encodeWithSelector(selector, _x);
(bool success, bytes memory returnedData) = address(contract1).staticcall(data);
require(success);
return abi.decode(returnedData, (uint256));
}
}
contract MyContract {
function function1() public {}
function getBalance(address _address) public view returns (uint256){}
function getValue (uint _value) public pure returns (uint) {
return _value;
}
}
来源:CSDN
作者:带着星星
链接:https://blog.csdn.net/qq_35434814/article/details/104682616