使用Golang调用智能合约方法时如何确认交易状态
Golang 等待链上交易确认、查询交易最终状态实现方案
核心逻辑说明
- 你调用
Mint方法拿到的transaction实例,仅代表交易已经在本地完成签名、提交到RPC节点的交易池,此时交易并未完成上链,和JS版本里拿到transactionHash时的状态一致 - JS里
await等待交易返回的效果,本质是SDK封装了后台轮询逻辑:持续向节点查询交易对应收据,直到交易被打包进区块、达到设定的区块确认数阈值后,才返回最终结果 - 交易最终状态以交易收据的
Status字段为准:值为1代表交易执行成功,值为0代表交易执行失败(触发合约回滚、Gas不足等)
通用等待交易确认实现
直接封装可复用的轮询等待函数,内置超时控制、确认数计算逻辑:
import ( "context" "fmt" "math/big" "time" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" ) // WaitTxConfirm 等待交易上链完成确认 // 参数: RPC客户端实例、交易哈希、要求的最小确认区块数、轮询查询间隔 // 返回: 交易执行收据、错误信息 func WaitTxConfirm(client *ethclient.Client, txHash common.Hash, minConfirm int64, pollInterval time.Duration) (*types.Receipt, error) { // 设置总超时时间,避免交易长期卡在交易池导致程序无限阻塞,可根据链类型调整 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) defer cancel() ticker := time.NewTicker(pollInterval) defer ticker.Stop() for { select { case <-ctx.Done(): return nil, fmt.Errorf("wait tx %s confirm timeout", txHash.Hex()) case <-ticker.C: // 查询交易收据,返回NotFound说明交易还在交易池排队,继续下一轮查询 receipt, err := client.TransactionReceipt(ctx, txHash) if err != nil { if err == ethereum.NotFound { continue } return nil, err } // 查询当前链上最新区块高度 latestHeader, err := client.HeaderByNumber(ctx, nil) if err != nil { return nil, err } latestBlockNum := latestHeader.Number.Int64() txBlockNum := receipt.BlockNumber.Int64() // 计算当前交易的区块确认数 curConfirm := latestBlockNum - txBlockNum if curConfirm >= minConfirm { return receipt, nil } } } }
原有Mint逻辑改造示例
把等待逻辑接入你现有的Mint代码即可实现和JS版本一致的等待效果:
// 初始化RPC客户端,替换为你实际使用的节点RPC地址 client, err := ethclient.Dial("你的节点RPC地址") if err != nil { panic(fmt.Sprintf("connect rpc failed: %v", err)) } // 原有Mint发交易逻辑 transaction, err := erc721.Mint(trx, common.HexToAddress("my account"), big.NewInt(int64(i))) if err != nil { fmt.Println("send mint tx failed: ", err) return } txHash := transaction.Hash() fmt.Println("tx submitted, hash: ", txHash.String()) // 等待交易确认:私链/测试链可设1个确认,公链建议设6~12个确认避免链重组,轮询间隔建议2秒左右 receipt, err := WaitTxConfirm(client, txHash, 1, 2*time.Second) if err != nil { fmt.Println("wait tx confirm failed: ", err) return } // 判断最终交易状态 if receipt.Status == types.ReceiptStatusSuccessful { fmt.Printf("mint success, packed in block %d\n", receipt.BlockNumber.Uint64()) } else { fmt.Printf("mint failed on chain, packed in block %d\n", receipt.BlockNumber.Uint64()) }
注意事项
- 确认数阈值根据链类型调整:以太坊主网等公链建议设置6~12个确认,规避链重组导致的交易回滚风险;私有链、测试链无重组风险时可设为1,缩短等待时间
- 轮询间隔不要设置过短,避免给RPC节点造成过大请求压力,公链建议25秒,私链可设为500ms1秒
- 不要拿到交易哈希就判定交易成功,也不要查到收据就判定交易成功,必须校验收据的
Status字段,交易执行失败时同样会被打包进区块生成收据 - 总超时时间可根据实际场景调整,如果发的是低Gas交易可能需要更长等待时间,避免正常排队的交易被误判超时
内容的提问来源于stack exchange,提问作者Mr.c
相关产品推荐
相关产品推荐

