You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

async函数循环处理区块交易未等条件完成就执行save触发MongoDB重复键错误

跨区块交易事件处理重复写入问题解决

问题根因

你当前的代码存在两个核心逻辑错误导致跨区块事件处理异常:

  1. Web3.js的getPastEvents方法混用了回调和async/await语法:当你给getPastEvents传入第三个回调参数时,该方法不会返回Promise,你写的await contract.getPastEvents(...)不会等待回调内的异步校验、写入逻辑执行完成,就会直接往下执行ticker.save()和currentBlock++进入下一个区块的处理。
  2. 数据库写入没有做幂等处理,同一个交易哈希在不同区块的事件处理流程中都尝试插入,触发MongoDB的唯一索引重复报错。

修复方案

1. 统一使用Promise写法处理事件查询

去掉getPastEvents的回调参数,直接用await获取事件结果后同步处理,确保当前区块的所有事件全部处理完成再进入后续流程:

// 原回调写法替换为以下代码
const events = await contract.getPastEvents(
  'allEvents',
  { fromBlock: currentBlock, toBlock: currentBlock }
);
if (events && events.length > 0) {
  function Raw(address, data, eventSignature, topics) {
    this.address = address;
    this.data = data;
    this.eventSignature = eventSignature;
    this.topics = topics;
  }
  // 其余你原来写在回调里的事件处理、交易匹配、写入逻辑全部放到这里
}

2. 新增数据库写入幂等逻辑

交易写入时优先用upsert操作,避免重复键报错:

// 替换原来的insert逻辑
await TransactionModel.updateOne(
  { transactionHash: targetHash }, // 唯一键筛选条件
  {
    $set: {
      // 你要写入的交易字段
    },
    // 可以用$addToSet新增跨区块的事件列表,避免覆盖已有事件
    $addToSet: { events: newEvent }
  },
  { upsert: true } // 不存在则插入,存在则更新
);

3. 调整区块流转逻辑

确保所有合约的当前区块事件全部处理完成后,再更新lastFetchedBlock和保存ticker,再进入下一个区块循环。

内容的提问来源于stack exchange,提问作者committer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 08:06:00