+-
在写智能合约的时候,之前我的习惯是把需要查询的数据记录在合约的event中,这些event的字段有些就是方法的入参。虽然以太坊log数据gas free相对较少,但积累起来就可观了。经过思考后,我给自己定了一些规则:
需要索引的字段,计算的中间结果,可以保留在event中 无后台的DApp可以在event中保留更多的字段 具有复杂功能(比如分账明细)的DApp,如需要多次查询大量数据,可以考虑使用后台来查询区块链。此时event中含有的函数入参就没有必要保留了,数据可以通过transaction的input字段恢复。拿我发送的一个transaction为例
{
hash: '0xcc1c866186ff39555936ea007a63ead761aef80d4301eb4e0081e8fc8f6fe18d',
nonce: 892,
blockHash: '0xbfff2fc0dd268dfce90417a3ea3b5da3a9e59703d8d4ec6a5be3ba2dce59b924',
blockNumber: 987,
transactionIndex: 0,
from: '0x40FB66078a2e688f83002930B7EbA981323d4bef',
to: '0x2C71AC97716A17E66D7E524Cfeb28B97A3728250',
value: '0',
gas: 5000000,
gasPrice: '10000000000',
input: '0x70a1495c00000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000003782dace9d900000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000056f70656e31000000000000000000000000000000000000000000000000000000',
v: '0x1b',
r: '0xbfbd3aef6c6777598847de0aa1ffcaf50470f785054771a54e2e274b89d1a633',
s: '0x27aea35dd4d462598ac909b55444ec0131c7977fe2ad244eaac0cc28b70e07f1'
}
可以看到很长的input字段,这个字段以0x70a1495c
开头,这其实就是函数签名,后面的数据则是按类型把数据拼接起来而已。我们再来看这个函数的abi
{
constant: false,
inputs: [
{ internalType: 'bytes', name: 'name', type: 'bytes' },
{ internalType: 'bool', name: 'isOpen', type: 'bool' },
{ internalType: 'bool', name: 'isCustom', type: 'bool' },
{ internalType: 'uint256', name: 'cusPrice', type: 'uint256' },
{ internalType: 'uint8', name: 'durationInYear', type: 'uint8' }
],
name: 'registerRoot',
outputs: [],
payable: false,
stateMutability: 'nonpayable',
type: 'function',
signature: '0x70a1495c'
}
可以看到signature也是0x70a1495c
这个签名是怎么生成的呢,其实很简单:web3.eth.abi.encodeFunctionSignature("registerRoot(bytes,bool,bool,uint256,uint8)")
就是一个短Hash,去掉0x70a1495c
后,我们把剩下数据解码:
web3.eth.abi.decodeParameters(["bytes","bool","bool","uint256","uint8"],"0x00000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000003782dace9d900000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000056f70656e31000000000000000000000000000000000000000000000000000000")
Result {
'0': '0x6f70656e31',
'1': true,
'2': true,
'3': '4000000000000000000',
'4': '1',
最后再拼上字段名称就可以了。
自己写了个解析函数,如下:
async function decodeParamsOfTransaction(txHash, func_abi){
var txData = await web3.eth.getTransaction(txHash);
var input = txData.input;
var types = func_abi.inputs.map(x=>x.internalType);
var _d = "0x"+input.replace(func_abi.signature,"");
var names = func_abi.inputs.map(x=>x.name);
var r = web3.eth.abi.decodeParameters(types, _d);
var dic = {}
for(var i=0; i<names.length; i++){
dic[names[i]] = r[i];
}
return dic
}
可得到例如下面的结果:
{
name: '0x6f70656e31',
isOpen: true,
isCustom: true,
cusPrice: '4000000000000000000',
durationInYear: '1'
}