所以我自己想到了这一点 - 我为 geth 创建了一个自定义 JavaScript 跟踪器,该跟踪器在第三个参数中传递给 geth 到 debug_traceCall (请参阅链接提供的 API 参考):
{
data: [],
fault: function (log) {
},
step: function (log) {
var topicCount = (log.op.toString().match(/LOG(d)/) || [])[1];
if (topicCount) {
var res = {
address: log.contract.getAddress(),
data: log.memory.slice(parseInt(log.stack.peek(0)), parseInt(log.stack.peek(0)) + parseInt(log.stack.peek(1))),
};
for (var i = 0; i < topicCount; i++)
res['topic' + i.toString()] = log.stack.peek(i + 2);
this.data.push(res);
}
},
result: function () {
return this.data;
}
}
该跟踪器由 geth 为跟踪中的每个操作执行。基本上它的作用:
- 检查这是否是
LOG0、LOG1、LOG2、LOG3 或LOG4 EVM 操作码之一
- 从当前合约中提取合约地址
- 提取默认
topic0 和后续主题(如果有)
- 从内存中提取额外的事件数据(注意:stack[0]是偏移量,stack[1]是数据大小)
将跟踪器传递给 geth 如下所示:
res = await ethersProvider.send('debug_traceCall', [{
from: tx.from,
to: tx.to,
gas: BigNumber.from(tx.gas)._hex.replace('0x0', '0x'),
gasPrice: BigNumber.from(tx.gasPrice)._hex.replace('0x0', '0x'),
value: BigNumber.from(tx.value)._hex.replace('0x0', '0x'),
data: tx.input
}, "latest", {
tracer: "{
" +
" data: [],
" +
" fault: function (log) {
" +
" },
" +
" step: function (log) {
" +
" var topicCount = (log.op.toString().match(/LOG(\d)/) || [])[1];
" +
" if (topicCount) {
" +
" var res = {
" +
" address: log.contract.getAddress(),
" +
" data: log.memory.slice(parseInt(log.stack.peek(0)), parseInt(log.stack.peek(0)) + parseInt(log.stack.peek(1))),
" +
" };
" +
" for (var i = 0; i < topicCount; i++)
" +
" res['topic' + i.toString()] = log.stack.peek(i + 2);
" +
" this.data.push(res);
" +
" }
" +
" },
" +
" result: function () {
" +
" return this.data;
" +
" }
" +
"}",
enableMemory: true,
enableReturnData: true,
disableStorage: true
}])