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

同一钱包多交易Nonce冲突求助:Telegram NFT Mint Bot异常排查

同一钱包并发Mint NFT的Nonce问题解决思路

问题根源分析

  • 用w3.eth.getTransactionCount("wallet")默认只返回已确认交易的nonce,并发场景下多个请求会拿到相同值,提交重复交易触发ALREADY_EXISTS错误。
  • 用普通本地计数器的话,若pending交易未确认就递增计数器,会导致nonce不连续;如果尝试替换pending交易但gas未提高,就会触发could not replace existing tx错误。

具体解决方案

  1. 结合Pending状态的Nonce+本地计数器

    • 初始化时用w3.eth.getTransactionCount("wallet", "pending")获取包含pending交易的最新nonce,作为本地计数器初始值。
    • 每次提交交易前,先同步节点的pending nonce,避免本地计数器因交易失败等情况落后。
    • 提交成功后手动递增本地计数器,确保后续交易nonce正确。
  2. 加锁控制并发

    • 因为多用户同时调用,必须给nonce的获取、同步、递增操作加锁,同一时间只允许一个请求操作nonce,彻底避免重复nonce问题。Python中可以用threading.Lock()(同步场景)或asyncio.Lock()(异步场景)实现。
  3. 动态Gas价格处理交易替换

    • 若遇到需要替换pending交易的情况,新交易的gas价格(maxPriorityFeePerGas和maxFeePerGas)必须比旧交易高至少10%,节点才会接受替换。可以基于当前节点gas价格动态调整,比如乘以1.1。
  4. 交易状态跟踪与重试

    • 记录每笔交易的nonce和哈希,定期检查状态:
      • 若交易确认,正常推进计数器;
      • 若交易失败,回滚本地计数器或重新同步pending nonce;
      • 若交易长时间pending,提高gas价格重试。

代码示例

import threading
from web3 import Web3

w3 = Web3(Web3.HTTPProvider("你的节点URL"))
wallet_addr = "你的钱包地址"
nonce_lock = threading.Lock()
local_nonce = w3.eth.getTransactionCount(wallet_addr, "pending")

def mint_nft():
    global local_nonce
    with nonce_lock:
        # 同步节点最新的pending nonce
        pending_nonce = w3.eth.getTransactionCount(wallet_addr, "pending")
        if pending_nonce > local_nonce:
            local_nonce = pending_nonce
        
        # 构建Mint交易
        tx_params = {
            "to": "NFT合约地址",
            "value": w3.to_wei("0.01", "ether"),  # 替换成Mint所需ETH
            "gas": 200000,  # 根据合约调整gas上限
            "maxPriorityFeePerGas": w3.to_wei("2", "gwei"),
            "maxFeePerGas": w3.to_wei("20", "gwei"),
            "nonce": local_nonce,
            "chainId": 1  # 替换成对应链的ID,比如BSC是56
        }

        # 签名并发送交易
        try:
            signed_tx = w3.eth.account.sign_transaction(tx_params, private_key="你的私钥")
            tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
            local_nonce += 1
            print(f"交易提交成功: {tx_hash.hex()}")
            return tx_hash
        except ValueError as e:
            err_msg = str(e)
            if "ALREADY_EXISTS" in err_msg:
                # 更新本地nonce并重试
                local_nonce = w3.eth.getTransactionCount(wallet_addr, "pending")
                print(f"更新本地nonce至: {local_nonce},重试交易")
                return mint_nft()
            elif "could not replace existing tx" in err_msg:
                # 提高gas价格重试
                tx_params["maxPriorityFeePerGas"] = w3.to_wei("2.2", "gwei")
                tx_params["maxFeePerGas"] = w3.to_wei("22", "gwei")
                signed_tx = w3.eth.account.sign_transaction(tx_params, private_key="你的私钥")
                tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
                local_nonce += 1
                print(f"提高Gas后交易成功: {tx_hash.hex()}")
                return tx_hash
            else:
                # 其他错误抛出
                raise e

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 18:15:06