同一钱包多交易Nonce冲突求助:Telegram NFT Mint Bot异常排查
同一钱包并发Mint NFT的Nonce问题解决思路
问题根源分析
- 用
w3.eth.getTransactionCount("wallet")默认只返回已确认交易的nonce,并发场景下多个请求会拿到相同值,提交重复交易触发ALREADY_EXISTS错误。 - 用普通本地计数器的话,若pending交易未确认就递增计数器,会导致nonce不连续;如果尝试替换pending交易但gas未提高,就会触发
could not replace existing tx错误。
具体解决方案
结合Pending状态的Nonce+本地计数器
- 初始化时用
w3.eth.getTransactionCount("wallet", "pending")获取包含pending交易的最新nonce,作为本地计数器初始值。 - 每次提交交易前,先同步节点的pending nonce,避免本地计数器因交易失败等情况落后。
- 提交成功后手动递增本地计数器,确保后续交易nonce正确。
- 初始化时用
加锁控制并发
- 因为多用户同时调用,必须给nonce的获取、同步、递增操作加锁,同一时间只允许一个请求操作nonce,彻底避免重复nonce问题。Python中可以用
threading.Lock()(同步场景)或asyncio.Lock()(异步场景)实现。
- 因为多用户同时调用,必须给nonce的获取、同步、递增操作加锁,同一时间只允许一个请求操作nonce,彻底避免重复nonce问题。Python中可以用
动态Gas价格处理交易替换
- 若遇到需要替换pending交易的情况,新交易的gas价格(
maxPriorityFeePerGas和maxFeePerGas)必须比旧交易高至少10%,节点才会接受替换。可以基于当前节点gas价格动态调整,比如乘以1.1。
- 若遇到需要替换pending交易的情况,新交易的gas价格(
交易状态跟踪与重试
- 记录每笔交易的nonce和哈希,定期检查状态:
- 若交易确认,正常推进计数器;
- 若交易失败,回滚本地计数器或重新同步pending nonce;
- 若交易长时间pending,提高gas价格重试。
- 记录每笔交易的nonce和哈希,定期检查状态:
代码示例
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
相关产品推荐
相关产品推荐

