Ethereum/Core API/eth_getLogs

eth_getLogs

eth_getLogs 方法返回与给定过滤器对象匹配的所有日志数组,允许开发者直接查询历史事件数据,而无需先创建过滤器。这是检索区块链事件数据最强大和最常用的方法之一,对 dApp 开发和区块链数据分析至关重要。

使用场景

  • 跟踪钱包的代币转账历史
  • 在 dApp 中构建用户活动时间线
  • 监控协议事件进行分析
  • 分析 DEX 上的历史交易活动
  • 审计合约交互和治理投票
  • 为更快的应用程序访问索引区块链数据
  • 从事件中重建状态以进行合约验证
  • 为用户相关的合约事件创建通知
  • 通过异常事件检测安全事件
  • 生成全面的交易收据

方法详情

此方法接受带有日志返回条件的过滤器对象,是最查询密集的 RPC 调用之一。

参数:

日志过滤器选项对象

开始搜索的区块号/标签

搜索至的区块号/标签

过滤日志的合约地址

主题过滤器数组(事件签名和索引参数)

获取日志的区块哈希(fromBlock/toBlock 的替代方案)

返回值:

与过滤条件匹配的日志对象数组

此日志来源的地址

索引日志参数数组(最多 4 个主题)

非索引日志数据(十六进制编码)

包含此日志的区块号(十六进制)

创建此日志的交易哈希

交易在区块中的索引

包含此日志的区块哈希

此日志在区块中的索引位置

此日志是否因链重组而被移除

响应示例

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x00000000000000000000000068b3465833fb72a70ecdf485e0e4c7bd8665fc45",
        "0x00000000000000000000000027182842e098f60e3d576794a5bffb0777e025d3"
      ],
      "data": "0x000000000000000000000000000000000000000000000043e1f92f1839951800",
      "blockNumber": "0x10d4f40",
      "transactionHash": "0x7d5b3f1d5b32c2b6da53acaace3894412f3b1ec2384a9b8e6c1a52325e880db2",
      "transactionIndex": "0xc1",
      "blockHash": "0xe2ccfc7b29eb6cad4bd3e55a00275a3b05d2d5f984ef63683f115e92d213d5b2",
      "logIndex": "0x5a",
      "removed": false
    }
  ]
}

理解日志对象

返回的每个日志对象包含:

  • address:生成事件的合约地址
  • topics:0-4 个 32 字节主题数组(索引参数)
    • 第一个主题通常是事件签名哈希(事件签名的 keccak256)
    • 后续主题是索引事件参数(每个限制为 32 字节)
  • data:包含非索引事件参数(十六进制字符串)
  • blockNumber:创建日志的区块号
  • transactionHash:生成日志的交易哈希
  • transactionIndex:交易在区块中的索引位置
  • blockHash:创建日志的区块哈希
  • logIndex:日志在区块中的索引位置
  • removed:如果由于链重组而移除日志,则为 true

主题过滤深入解析

topics 参数提供强大的过滤功能:

  1. 简单主题匹配

    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    

    这匹配所有 ERC-20 Transfer 事件。

  2. 位置特定匹配(位置之间的 AND 逻辑):

    "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      "0x000000000000000000000000abc123..."
    ]
    

    这匹配来自特定地址的 Transfer 事件。

  3. 位置内 OR 逻辑

    "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      ["0x000000000000000000000000abc123...", "0x000000000000000000000000def456..."]
    ]
    

    这匹配来自两个地址之一的 Transfer 事件。

  4. 使用 null 跳过位置

    "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      null,
      "0x000000000000000000000000xyz789..."
    ]
    

    这匹配发送到特定地址的 Transfer 事件(忽略 FROM 字段)。

常见使用模式

以下是常见用例的完整示例:

// 1. 获取特定代币的所有 ERC-20 转账事件
async function getTokenTransfers(tokenAddress, fromBlock = '0x0', toBlock = 'latest') {
  // Transfer 事件签名:keccak256("Transfer(address,address,uint256)")
  const transferEventSignature = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  return await provider.send('eth_getLogs', [{
    address: tokenAddress,
    topics: [transferEventSignature],
    fromBlock,
    toBlock
  }]);
}

// 2. 获取特定钱包地址的转入或转出交易
async function getUserTransfers(tokenAddress, userAddress, fromBlock = '0x0', toBlock = 'latest') {
  const transferEventSignature = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';
  const paddedAddress = userAddress.replace('0x', '0x000000000000000000000000');

  // 主题数组匹配用户作为发送者或接收者的事件
  return await provider.send('eth_getLogs', [{
    address: tokenAddress,
    topics: [
      transferEventSignature,
      [paddedAddress, null],  // 从用户(或)
      [paddedAddress, null]   // 到用户(或)
    ],
    fromBlock,
    toBlock
  }]);
}

// 3. 跟踪 NFT 铸造事件
async function getNFTMints(nftAddress, fromBlock = '0x0', toBlock = 'latest') {
  // 从 0x0 地址的 Transfer 事件是铸造
  const transferEventSignature = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';
  const zeroAddress = '0x0000000000000000000000000000000000000000000000000000000000000000';

  return await provider.send('eth_getLogs', [{
    address: nftAddress,
    topics: [
      transferEventSignature,
      zeroAddress  // From 地址是零地址(铸造)
    ],
    fromBlock,
    toBlock
  }]);
}

// 4. ERC-20 Transfer 事件的完整解码器
function decodeTransferEvent(log) {
  // 从主题解析索引参数
  const from = '0x' + log.topics[1].substring(26);
  const to = '0x' + log.topics[2].substring(26);

  // 从数据字段解析金额
  const amount = BigInt(log.data);

  return {
    from,
    to,
    amount,
    blockNumber: parseInt(log.blockNumber, 16),
    txHash: log.transactionHash
  };
}

性能考虑

高效使用 eth_getLogs

  • 区块范围限制:大多数提供商限制每次请求的区块范围(例如,2000-10000 个区块)

  • 分页策略:对于大型查询,按区块范围分页:

    async function paginatedLogs(filter, maxBlocksPerPage = 2000) {
      const fromBlock = parseInt(filter.fromBlock === 'earliest' ? '0x0' : filter.fromBlock, 16);
      const latestBlock = parseInt(await provider.send('eth_blockNumber', []), 16);
      const toBlock = filter.toBlock === 'latest' ? latestBlock : parseInt(filter.toBlock, 16);
    
      let allLogs = [];
      for (let i = fromBlock; i <= toBlock; i += maxBlocksPerPage) {
        const pageToBlock = Math.min(i + maxBlocksPerPage - 1, toBlock);
        const pageFilter = {
          ...filter,
          fromBlock: '0x' + i.toString(16),
          toBlock: '0x' + pageToBlock.toString(16)
        };
    
        const logs = await provider.send('eth_getLogs', [pageFilter]);
        allLogs = allLogs.concat(logs);
      }
    
      return allLogs;
    }
    
  • 主题特异性:更具体的主题过滤器可减少数据传输和处理时间

  • 地址过滤:查询单个合约比多个合约更高效

  • 提供商优化:一些提供商如 Infura 有专门的日志查询端点

  • 速率限制:此方法通常有更严格的速率限制,可能计为多个请求

  • 缓存:考虑缓存经常访问的历史数据结果

  • 存档节点:某些查询可能需要存档节点而非全节点

常见事件签名

以下是用于过滤的常用事件签名:

  • ERC-20 Transfer: 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
  • ERC-20 Approval: 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925
  • ERC-721 Transfer: 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef(与 ERC-20 相同)
  • Uniswap V2 Swap: 0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822
  • ERC-1155 TransferSingle: 0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62
  • ERC-1155 TransferBatch: 0x4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb

另请参阅

帮助我们变得更好!
分享此页面并帮助我们为您创建更好的产品。