以太坊交易信息及event、input、logs、topics等概念机制

2023-11-02

一、交易信息获取

1.1 合约事件例子定义

举例,比如合约中事件如下:(以下内容均使用该事件例子)

event Transfer(address indexed from, address indexed to, uint256 value);
  • 事件名称:Transfer
  • 事件的参数:address, address, uint256
  • 注意:此事件的from和to参数前有indexed标记,value没有indexed标记

1.2 以太坊交易获取

当上述事件在合约中调用后,我们通过其交易hash获取交易信息。从以太坊得到一条交易信息的方式有两种:

  • eth_getTransactionByHash: :返回指定交易对应的交易信息
  • eth_getTransactionReceipt :返回指定交易对应的收据信息

eth_getTransactionByHash

返回的具体信息如下

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "blockHash": "0xb0d0e3b6c5e59b7b3e7e16701f6d6cb0c3c93487415b03839e88b3f7a241c528",
    "blockNumber": "0xd19505",
    "from": "0xb8262c6a2dcabd92a77df1d5bd074afd07fc5829",
    "gas": "0x10e3d",
    "gasPrice": "0x274daee580",
    "maxFeePerGas": "0x2d48ddd9f1",
    "maxPriorityFeePerGas": "0x6ccc91d0",
    "hash": "0xae2a33da8396a6bc40e874b0f32b9967113a3dbf071ab1290c44c62d86873d36",
    "input": "0xa9059cbb000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7000000000000000000000000000000000000000000000000000000016512c902",
    "nonce": "0x14",
    "to": "0xdac17f958d2ee523a2206206994597c13d831ec7",
    "transactionIndex": "0x71",
    "value": "0x0",
    "type": "0x2",
    "accessList": [],
    "chainId": "0x1",
    "v": "0x1",
    "r": "0xa1d7455286525df11602aab34e9e8ab21b092e2c7853a0d6beca0dfb2a78b2e8",
    "s": "0x75a485b8c378173a829b27a2e55312311fdb33c68ae65f4c74e5f9cc0a748e0d"
  }
}

web3调用中文文档:https://www.wenjiangs.com/doc/pr2nvcat

curl 调用:

curl -s -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"eth_getTransactionByHash","params":["0xae2a33da8396a6bc40e874b0f32b9967113a3dbf071ab1290c44c62d86873d36"],"id":1}' http://127.0.0.1:8545

eth_getTransactionReceipt

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "blockHash": "0xb0d0e3b6c5e59b7b3e7e16701f6d6cb0c3c93487415b03839e88b3f7a241c528",
    "blockNumber": "0xd19505",
    "contractAddress": null,
    "cumulativeGasUsed": "0x6c847e",
    "effectiveGasPrice": "0x274daee580",
    "from": "0xb8262c6a2dcabd92a77df1d5bd074afd07fc5829",
    "gasUsed": "0xa169",
    "logs": [
      {
        "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
        "topics": [
          "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
          "0x000000000000000000000000b8262c6a2dcabd92a77df1d5bd074afd07fc5829",
          "0x000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7"
        ],
        "data": "0x000000000000000000000000000000000000000000000000000000016512c902",
        "blockNumber": "0xd19505",
        "transactionHash": "0xae2a33da8396a6bc40e874b0f32b9967113a3dbf071ab1290c44c62d86873d36",
        "transactionIndex": "0x71",
        "blockHash": "0xb0d0e3b6c5e59b7b3e7e16701f6d6cb0c3c93487415b03839e88b3f7a241c528",
        "logIndex": "0xa0",
        "removed": false
      }
    ],
    "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000010000000000000000000000000000000000000000000000000000000008000000000080000000000000000000000000000000000000000000000000000000000000000000200000000000000010000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000080000000000000000000000000000000000000004000000002000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000200",
    "status": "0x1",
    "to": "0xdac17f958d2ee523a2206206994597c13d831ec7",
    "transactionHash": "0xae2a33da8396a6bc40e874b0f32b9967113a3dbf071ab1290c44c62d86873d36",
    "transactionIndex": "0x71",
    "type": "0x2"
  }
}

注意:getTransaction返回结果中包含input,而getTransactionReceipts返回结果中包含logs。

二、input解析

2.1 input内容解析

input=0x则为非合约调用,否则为合约方法调用。

以合约方法function transfer(address to, uint tokens) 为例;

input数据分为3个部分:

  • 第一部分: 4 字节,是方法名的哈希

例如:a9059cbb,具体可参见:以太坊智能合约各方法对应的签名编码

  • 第二部分: 32字节,以太坊地址,目前以太坊地址是20个字节,高位补0
例如:000000000000000000000000abcabcabcabcabcabcabcabcabcabcabcabcabca
  • 第三部分:32字节,是需要传输的代币数量,这里是1*10^18 GNT
例如:0000000000000000000000000000000000000000000000000de0b6b3a7640000

所有这些加在一起就是交易数据:

a9059cbb000000000000000000000000abcabcabcabcabcabcabcabcabcabcabcabcabca0000000000000000000000000000000000000000000000000de0b6b3a7640000

2.2 input处理逻辑

如下为处理input的逻辑(web3.js):

if(transanctionInput=='0x'){
        // 非合约调用
    return;
}else{
    retJson['function'] = {'funcName':null,'inputs':null,'outputs':null,'exeResult':null};
    var funcArr = mxxContractABI.filter(function (per) {
        return per.signature == funcHash ;
    });
    if(funcArr!==null&&funcArr.length>0){   // 得到方法名
        if(funcArr[0].hasOwnProperty("name") && funcArr[0].name!==null){
            retJson['function']['funcName'] = funcArr[0].name;
        }
        if(funcArr[0].hasOwnProperty("inputs") && funcArr[0].inputs!==null){
            funcArr[0].inputs.map(function (res) {  // 得到方法inputs(输入)
                inputs.push(res.type);
            });
            retJson['function']['inputs'] = inputs;
        }
        if(funcArr[0].hasOwnProperty("outputs")&& funcArr[0].outputs!==null){
            funcArr[0].outputs.map(function (res) {// 得到方法outputs(输出)
                outputs.push(res.type);
            });
            retJson['function']['outputs']= outputs;
        }
 
    }
    status = transanctionReceipt.status;
    if(status == '0x1'){
        //执行成功
        retJson['function']['exeResult'] = 'Successfully Executed';
    }else {
        retJson['function']['exeResult'] = 'Failed Executed';
    }

三、logs解析

智能合约通过【事件】来产生【日志】,日志存储的Gas费用要比合约的存储便宜很多(日志每个字节花费8个Gas,而合约存储是每32个字节20000个Gas)。想要通过合约向用户返回数据,则需将数据以事件的形式传给用户,用户拿到transactionReceipt后解析log,log.args.x拿到数据。Input只能拿到调用合约以及function的信息,而不能拿到function运行后内部产生的事件(事件不一定和function拥有相同名称和参数)。

3.1 logs解析代码

logs解析步骤代码(web3.js)

web3SolidityEvent = require('./node_modules/truffle-contract/node_modules/web3/lib/web3/event.js');
var transferErc20Json = {
    "anonymous": false,
    "inputs": [{
        "indexed": true,
        "name": "from",
        "type": "address"
    }, {
        "indexed": true,
        "name": "to",
        "type": "address"
    }, {
        "indexed": false,
        "name": "value",
        "type": "uint256"
    }],
    "name": "Transfer",
    "type": "event",
    "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
};
var transferEvent = new web3SolidityEvent(null, config.transferErc20Json, null);
async function processReceiptLogs(transactionReceipt){
        let ethErc20LogRecord = null;
        let logs = transactionReceipt.logs;
 
        for (let i = 0; i < logs.length; i++) {
            let isContractExists = await redis.contractExists(logs[i].address);
 
            if (isContractExists === true) {//判断redis中是否存在
 
//是否是ERC-20 transfer事件,用topics来判断
                if(logs[i].topics[0] === transferErc20Json.signature){ 
 
                    var log = await transferEvent.decode(logs[i]);
                    logger.debug(prefixOfLogger +'--'+'transferEvent decode result:',log);
                    ethErc20LogRecord = {
                        txHash: log.transactionHash,
                        logIndex: log.logIndex,
                        contractAddress: log.address,
                        fromAddress: log.args.from ,
                        toAddress: log.args.to,
                        value: log.args.value.div(Math.pow(10, 18)).toString(),
                        data: log.args.data,
                        blockNumber: log.blockNumber,
                        removed: log.removed
                    };
                    db.setCreateAndUpdateTime(ethErc20LogRecord);
                    let createLogRecord = await tables.EthErc20Log.create(ethErc20LogRecord);
 
                }
            }
}
  1. 取出transactionReceipt中logs;

  2. 取出logs中一条log;

  3. 使用event.js得到transferEvent,然后用transferEvent的decode方法解析log;

若是公链转币,以太坊转账,则交易回执转logs为空。

若是执行合约的事件,则logs不为空,故ERC-20代币转账,会执行合约Transfer方法,产生logs

四、topics

4.1 概念

Topics[]是一个数组

  • Topics[0] :指向特定的事件,是事件的签名,如ERC-20 Transfer方法:
sha3('Transfer(address,address,uint256)') => 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
  • Topics[1] :是address类型的from参数补齐64位结果(合约交易中真正的from地址)

  • Topics[2] :是address类型to参数补齐64位的结果(合约交易中真正的to地址)

由于value没有indexed标记,因此放在data中,将value的值转化为16进制并补齐64位

4.2 indexed

Transfer事件的第一个和第二个参数被标记为indexed, 因此他们的值被放在 topics array 中. 由于value参数没有标记为indexed, 所以value值被放在data字段. 如果事件中有多个字段未标记为indexed, 那么他们的值都会被记录在data字段中。

事件规则

  • topic[0] : keccak(“Transfer(address,address,uint256)”),对事件的字符做keccak散列运算

  • topic[1] : address类型from参数补齐64位

  • topic[2] : address类型to参数补齐64位

data: 没有indexed标记的value的值转化为16进制,并补齐64位

注意:

事件中的参数类型需要写成完整的,如Transfer(address,address,uint)就不行,需要将uint改为uint256。

五、合约交易关键字段解释

{
  "jsonrpc": "2.0",   //RPC版本号,2.0
  "id": 1,      //RPC请求编号
  "result": {  //调用结果,为交易收据,主要包含如下字段:
    "blockHash": "0xb0d0e3b6c5e59b7b3e7e16701f6d6cb0c3c93487415b03839e88b3f7a241c528",  // 区块哈希
    "blockNumber": "0xd19505",   // 区块高度
    "contractAddress": null,    //合约地址
    "cumulativeGasUsed": "0x6c847e",  //当前交易执行后累计花费的gas总值
    "effectiveGasPrice": "0x274daee580",  //当前交易预计使用的gas总值
    "from": "0xb8262c6a2dcabd92a77df1d5bd074afd07fc5829",   //当前交易发送者的地址
    "gasUsed": "0xa169",    //执行当前这个交易单独花费的gas
    "logs": [   //这个交易产生的日志对象数组
      {
        "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",   //当前交易被调用的合约地址
        "topics": [
          "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",  //keccak(Transfer(address,address,uint256)), //合约事件签名哈希值,对事件的字符做keccak散列运算
          "0x000000000000000000000000b8262c6a2dcabd92a77df1d5bd074afd07fc5829",  //当前交易from的地址
          "0x000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7"   //当前交易to的地址
        ], 
        "data": "0x000000000000000000000000000000000000000000000000000000016512c902",     //包含日志的非索引参数
        "blockNumber": "0xd19505",    // 区块高度
        "transactionHash": "0xae2a33da8396a6bc40e874b0f32b9967113a3dbf071ab1290c44c62d86873d36",   //交易的哈希值,32字节
        "transactionIndex": "0x71"   //交易在区块里面的序号,当交易为pending时为空
        "blockHash": "0xb0d0e3b6c5e59b7b3e7e16701f6d6cb0c3c93487415b03839e88b3f7a241c528",
        "logIndex": "0xa0",    //块中日志索引位置的整数,当交易为pending时日志为空。
        "removed": false   //当由于链重组而删除日志时,为True。 如果它是一个有效的日志则为False。  
      }
    ],
    //bloom过滤器,当交易为pending时日志为空
    "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000010000000000000000000000000000000000000000000000000000000008000000000080000000000000000000000000000000000000000000000000000000000000000000200000000000000010000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000080000000000000000000000000000000000000004000000002000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000200",
    "status": "0x1",   //交易事务状态,1(成功)或0(失败)
    "to": "0xdac17f958d2ee523a2206206994597c13d831ec7",   //当前交易被调用的合约地址
    "transactionHash": "0xae2a33da8396a6bc40e874b0f32b9967113a3dbf071ab1290c44c62d86873d36",  //交易的哈希值,32字节
    "transactionIndex": "0x71",  //交易在区块里面的序号,当交易为pending时为空
    "type": "0x2"  
  }
}

getTransactionReceipt返回信息字段详情可参考:https://infura.io/docs/ethereum/json-rpc/eth-getTransactionReceipt


以上,就是今天分享的全部内容了。

希望大家通过以上方式可以解决自己的实际需求,解决自己目前所遇到的问题。

如果在查看过程中有任何疑问,可以扫描下面的二维码,添加我的个人微信,备注:地区-职业方向-昵称,欢迎来撩,加入区块链技术交流群,与更多的区块链技术大佬学习交流。
在这里插入图片描述
原创不易,码字不易。 觉得这篇文章对你有点用的话,麻烦你为本文点个赞,留言或转发一下,因为这将是我输出更多优质文章的动力,感谢!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

以太坊交易信息及event、input、logs、topics等概念机制 的相关文章

  • 工作和生活中,如何用项目管理思维解决复杂的事情?

    在工作和生活中 许多事情都可以采用项目思维方式来解决 当我们逐渐将工作和生活中的各种事务以项目的方式来处理和推进时 我们可能并没有意识到 实际上我们正在运用项目管理思维 项目管理思维能帮助我们在面对繁杂事务时 理清思路 考虑周全 明确行动

随机推荐

  • 《程序员的自我修养—链接、装载与库》

    程序员的自我修养 链接 装载与库 读书笔记 本文为记录笔记 大部分内容为书中的摘抄 作者微博 MTK 蛙蛙鱼 写作时间 2013年11月18日 更新时间 2014年02月18日 编译和链接 2 1 被隐藏了的过程 预编译 cpp or gc
  • 蓝桥BASIC-18 矩形面积交 思路分析

    问题描述 平面上有两个矩形 它们的边平行于直角坐标系的X轴或Y轴 对于每个矩形 我们给出它的一对相对顶点的坐标 请你编程算出两个矩形的交的面积 输入格式 输入仅包含两行 每行描述一个矩形 在每行中 给出矩形的一对相对顶点的坐标 每个点的坐标
  • Qt开发上位机软件建立经典蓝牙通讯

    Qt开发上位机软件建立经典蓝牙通讯 之前做了一个具有经典蓝牙通讯功能的Windows上位机软件 在网上学习了相关博客以及参考了官方经典蓝牙例程之后 总结出了使用Qt建立经典蓝牙通讯的步骤 附带相关源码 作为分享 开发环境 我使用的Qt版本是
  • ESP32 LVGL开发一 移植与例程

    简介 LVGL 轻量级和通用图形库 是一个免费和开源的图形库 提供UI通信元素的构建接口与较低资源实现的源码 适用于快速开发UI图形交互页面的应用 官方已经适配了ESP32硬件平台 库版本为v7 11 开箱即用 如有异议 欢迎留言指正 特性
  • java进制转换及算法

    本文主要讲各个进制转换的方法 进制转换 前言 一 说明 1 作用 2 本质 3 方法 4 场景 二 实例 1 字符串与16进制的互转 2 16进制字符串与byte数组互转 3 字符串与指定格式的byte数组互转 4 字符串与16进制互转 5
  • PC-Lint c/c++ 代码检查工具

    概述 PC Lint是GIMPEL SOFTWARE公司的一个产品 它是一个历史悠久 功能异常强劲的静态代码检测工具 它的使用历史可以追溯到计算机编程的远古时代 30多年以前 经过这么多年的发展 它不但能够监测出许多语法逻辑上的隐患 而且也
  • Linux - Ubuntu下安装node.js的方法

    1 Putty连接 安装Putty连接到Ubuntu 输入密码验证后进入Putty命令行控制台 1 1 查看Ubuntu版本 sudo uname m 如果显示i686 你安装了32位操作系统 如果显示 x86 64 你安装了64位操作系统
  • Redis的高级特性一览

    更多内容 欢迎关注微信公众号 全菜工程师小辉 公众号回复关键词 领取免费学习资料 应用场景 缓存系统 用于缓解数据库的高并发压力 计数器 使用Redis原子操作 用于社交网络的转发数 评论数 粉丝数 关注数等 排行榜 使用zset数据结构
  • ag-grid表格如何使用?

    1 自定义标题 tableHeaderCustom vue
  • 证件照片如何换背景底色,3个免费制作证件照的方法,简单易学

    在日常生活中 我们经常需要用到证件照 比如 找工作需要简历上附带有证件照 还有办理学生证 身份证也需要提交证件照 不同的平台有时候提交的要求 背景底色 大小等 也不一样 如果你不想每次都重拍 那么可以用一些工具 软件 在原来的照片上修改 也
  • smb协议详解和samba服务的配置

    理论部分 samba 基于smb协议使网络上的计算机能共享文件 samba的核心是smbd和nmbd两个守护进程 smbd 管理samba服务器上的共享目录 nmbd 进行netbios名解析 使客户端能浏览服务器的共享资源 协议端口 sm
  • 堆的用法总结

    堆 heaps 不是容器 而是一种特别的数据组织方式 堆一般用来保存序列容器 堆很重要 很多不同的计算机进程中都使用了它们 为了弄明白堆是什么 首先需要明白树是什么 因此首先说明树这种数据结构是什么 树是分层排列的元素或节点 每个节点有一个
  • Hive架构及基础知识

    1 用户接口 Client CLI hive shell JDBC ODBC java 访问 hive WEBUI 浏览器访问 hive 2 元数据 Metastore 元数据包括 表名 表所属的数据库 默认是 default 表的拥有者
  • C++多态学习(二)完整定义:什么是多态?

    多态分为静多态和动多态 1 静多态 函数重载 是一种多态现象 通过命名倾轧在编译阶段决定 故称为静多态 2 动多态 动多态 不是在编译器阶段决定 而是在运行阶段决定 故称为动多态 动多态形成的条件如下 1 父类中有虚函数 2 子类overr
  • SpringBoot使用@Async实现多线程异步

    SpringBoot使用 Async实现多线程异步 一 什么是异步 说明 在同步操作中 我们执行到添加数据库的时候 我们必须等待这个方法彻底执行完才能执行 修改数据 完成后 发送短信 完成后 发送消息 等操作 如果插入数据库这个动作执行时间
  • 全新防火墙6.0 单条PPPOE(ADSL)上网配置

    一 组网需求 外网接口使用ADSL拨号 内网为192 168 1 0 24网段 实现基本上网功能 二 网络拓扑 三 配置要点 1 配置接口 wan1口 接ADSL的接口 务必勾选 从服务器重新获得网关 这样ADSL拨号成功后设备会自动生成默
  • 软件工程面试——数据库

    数据库实体的关系 数据库中的实体关系指的是不同实体之间的相互依赖和联系 实体关系是数据库设计中非常重要的一个概念 它是用于描述不同实体之间的关系 连接和交互方式的 在数据库中 一个实体通常指的是一个对象或者一个概念 比如一个人 一个订单或者
  • powerdesigner如何生成数据库表

    1 建立逻辑数据模型 2 构建基础模板 3 转为PDM 4 生成sql文件 数据库设计的步骤是什么
  • C++11新关键字noexcept、override、final把我们的心意告诉编译器

    noexcept告诉编译器不抛异常 异常时一定要处理的 如果一个函数出现异常 它内部不对该异常做处理 异常会一直往上传递 给函数的调用者 到最后一直没有被处理 程序就会终止 调用std terminate 它默认调用std abort vo
  • 以太坊交易信息及event、input、logs、topics等概念机制

    文章目录 一 交易信息获取 1 1 合约事件例子定义 1 2 以太坊交易获取 二 input解析 2 1 input内容解析 2 2 input处理逻辑 三 logs解析 3 1 logs解析代码 四 topics 4 1 概念 4 2 i