Web3.js发起多笔交易遇Nonce错误,如何处理及追踪Nonce值?
解决Nonce不匹配问题及追踪方法
问题原因
你同时发起两笔交易时,两次web3.eth.getTransactionCount调用几乎同步执行,拿到的是同一个账户nonce值。当第一笔交易提交后,账户nonce已更新,但第二笔仍使用旧值,最终触发nonce不匹配错误。
解决方案
1. 串行执行交易(最可靠)
等第一笔交易确认后再发起第二笔,确保每次获取的nonce都是最新状态:
async function executeTransactions() { // 获取初始nonce let txCount = await web3.eth.getTransactionCount(ENV.account); // 第一笔认证交易 const authTx = { nonce: web3.utils.toHex(txCount), gasLimit: web3.utils.toHex(800000), gasPrice: web3.utils.toHex(web3.utils.toWei('10', 'gwei')), to: ENV.contractAddress, data: contract.methods.auth(ENV.deviceName, ENV.serialNumber).encodeABI() }; const authRaw = txToRaw(authTx); // 修正你代码里的笔误toToRaw为txToRaw await new Promise((resolve, reject) => { web3.eth.sendSignedTransaction(authRaw, (err, txHash) => { if (err) return reject(err); console.log("认证交易哈希:", txHash); console.log("认证成功!"); resolve(); }); }); // 第二笔创建证明交易,nonce手动+1 txCount += 1; const createTx = { nonce: web3.utils.toHex(txCount), gasLimit: web3.utils.toHex(800000), gasPrice: web3.utils.toHex(web3.utils.toWei('10', 'gwei')), to: ENV.contractAddress, data: contract.methods.createAbstract( "2022", web3.utils.utf8ToHex(ENV.serialNumber), contexts.ipfsHash, web3.utils.utf8ToHex(soilData), "xx" ).encodeABI() }; const createRaw = txToRaw(createTx); await new Promise((resolve, reject) => { web3.eth.sendSignedTransaction(createRaw, (err, txHash) => { if (err) return reject(err); console.log("创建证明交易哈希:", txHash); console.log("创建证明成功!"); resolve(); }); }); } executeTransactions().catch(err => console.error("交易失败:", err));
2. 手动维护nonce值
若不需要等待第一笔交易确认(适合链上确认慢的场景,Ganache中慎用),可先获取一次nonce再手动递增:
web3.eth.getTransactionCount(ENV.account).then((txCount) => { // 第一笔交易使用初始nonce const authTx = { nonce: web3.utils.toHex(txCount), gasLimit: web3.utils.toHex(800000), gasPrice: web3.utils.toHex(web3.utils.toWei('10', 'gwei')), to: ENV.contractAddress, data: contract.methods.auth(ENV.deviceName, ENV.serialNumber).encodeABI() }; const authRaw = txToRaw(authTx); web3.eth.sendSignedTransaction(authRaw, (err, txHash) => { if (err) console.error("认证错误:", err); else console.log("认证成功,哈希:", txHash); }); // 第二笔交易直接使用nonce+1 const createTx = { nonce: web3.utils.toHex(txCount + 1), gasLimit: web3.utils.toHex(800000), gasPrice: web3.utils.toHex(web3.utils.toWei('10', 'gwei')), to: ENV.contractAddress, data: contract.methods.createAbstract( "2022", web3.utils.utf8ToHex(ENV.serialNumber), contexts.ipfsHash, web3.utils.utf8ToHex(soilData), "xx" ).encodeABI() }; const createRaw = txToRaw(createTx); web3.eth.sendSignedTransaction(createRaw, (err, txHash) => { if (err) console.error("创建证明错误:", err); else console.log("创建证明成功,哈希:", txHash); }); });
Nonce追踪方法
- 已确认交易的nonce:执行
web3.eth.getTransactionCount(ENV.account),返回账户已完成交易的数量,即下一笔交易的基础nonce。 - 包含pending交易的nonce:执行
web3.eth.getTransactionCount(ENV.account, 'pending'),返回包含未确认交易在内的总nonce值(Ganache交易确认快,需在交易提交后稍等再调用才能拿到正确值)。 - Ganache界面查看:打开Ganache客户端,找到对应账户,直接查看交易记录和当前账户的nonce值,直观追踪。
关于pending参数无效的说明
Ganache作为本地测试链,交易确认速度极快,并行调用getTransactionCount时,第一笔交易可能还未进入pending池,两次调用会拿到同一个已确认的nonce值,因此pending参数无法解决并行交易的冲突问题,串行执行是最可靠的方案。
内容的提问来源于stack exchange,提问作者a_lucky_guy
相关产品推荐
相关产品推荐

