4.3 合约编码方法和工具
合约的调用和查询,传入的参数是根据合约ABICode编码后函数和函数参数的data。详细可参考solidity - Application Binary Interface Specification
下面介绍几种方式取得合约ABICode方法调用时对应的编码data。
4.3.1 使用remix调用合约获取data
在使用remix执行合约方法时,每次交易都有对应的交易详情,可以在控制台看到交易信息里的函数调用的input,以及对应的decodeInput和decodeOutput。
input就是调用函数时向区块链环境发送的JSON里的data。对应开放平台,在使用合约调用时,传入的data可以直接使用remix的data。
4.3.2 使用ethers.js实现编码和解码
ethers.js是一个以太坊的js依赖包。里面提供了根据ABICode编码函数名的方法和编码参数的静态方法。
例:
//HelloWorld.sol
pragma solidity^0.4.23;
contract HelloWorld {
address public owner;
string public info;
constructor(address _owner) public {
owner = _owner;
}
function saySomething(string _str) public returns(string) {
info = _str;
return info;
}
}
//编码function saySomething函数的 abi
var ethers = require('ethers')
var abi = [
{
"constant": false,
"inputs": [
{
"name": "_str",
"type": "string"
}
],
"name": "saySomething",
"outputs": [
{
"name": "",
"type": "string"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"name": "_owner",
"type": "address"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"constant": true,
"inputs": [],
"name": "info",
"outputs": [
{
"name": "",
"type": "string"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "owner",
"outputs": [
{
"name": "",
"type": "address"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
}
];
var interface = new ethers.Interface(abi)
var abiInstance = interface.functions[abi[0].name] // abi[0]即saySomething function的abi
return abiInstance.sighash // 0xfe6b3783
获取函数参数编码data的方法:
使用ethers.utils.ABICoder的encode方法,如
// 编码 function saySomething 的输入参数 'Hello World'的data
var abiCoder = new ethers.utils.AbiCoder()
return abiCoder.encode(['string'], ['Hello World'])
//0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b48656c6c6f20576f726c64000000000000000000000000000000000000000000
实际调用函数的input即为:函数saySomething encode
的前八位 + 函数输入参数的encode。结果为
0xfe6b37830000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b48656c6c6f20576f726c64000000000000000000000000000000000000000000
可对比上面使用remix调用方法时的input值,两者结果一致。
合约执行结束后,info值被设置为 “Hello World”。下面请求constant方法(同8.3 Demo合约查询),根据结果解析info值。
curl -k -X POST --data '{"jsonrpc":"2.0","method":"eth_call","params":[{"from":"0x7eff122b94897ea5b0e2a9abf47b86337fafebdc","to":"0xd5b0df861803a07f330868104eec92ebdcce4c79","data":"0x370158ea"}, "latest"],"id":1}' https://sandbox-blockchain.xunlei.com/call
{"jsonrpc":"2.0","id":1,"result":"0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b48656c6c6f20576f726c64000000000000000000000000000000000000000000"}
var ethers = require('ethers')
var outputTypes = ['string']
var response = "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b48656c6c6f20576f726c64000000000000000000000000000000000000000000"
var abiCoder = new ethers.utils.AbiCoder()
abiCoder.decode(outputTypes, response)
// [ 'Hello World' ]
decode结果根据传入的outputTypes数组长度,解析对应的参数。