我在使用go调用合约的时候常常遇到下面几个问题
问题1:
nonce too low
关于nonce太低的问题。
这里普及以下nonce的知识。
以太坊会给每个账户维护一个nonce,每次这个账户进行交易的时候他的nonce会自动加1.合约账户也一样。当出现上面提到的错误的时候是因为在发起一笔交易的时候你的当前操作的外部账户nonce小于或者等于上一笔交易的nonce所以才出现这个问题。
最好的方法就是过一段时间读取一下当前以太坊的当前账户的nonce,并且还要在本地自己维护一个nonce,每当我们发起一笔交易后本地的nonce自增1.然后下一笔交易的时候我们可以确保nonce正确。并且我们可以固定多少次交易后再次从以太坊获取最新nonce确保nonce正确.
//查询当前账户nonce //第一个是连接连接网络的对象。第二个参数是要查询的账户的地址
func QueryNonce(cli *ethclient.Client, Accounts string) (uint64, error) {
fromAccDef := accounts.Account{Address: common.HexToAddress(Accounts)}
Nonce, err := cli.PendingNonceAt(context.Background(), fromAccDef.Address)
if err != nil {
fmt.Println("获取nonce失败:", err)
return 0, err
}
fmt.Println("读取Nonce成功")
return Nonce, nil
}
这里再附上通过RPC请求获取账户nonce的方法
//rpc请求获取nonce
func QueryNonceRpc(_Rpc *rpc.Client, _Account string) int {
var nonce string
_Rpc.Call(&nonce, "eth_getTransactionCount", "0x"+_Account, "pending")
n, _ := strconv.ParseUint(nonce[2:], 16, 32)
return int(n)
}
上面的pending代表返回的nonce包含了当前队列中还未确认的nonce.
共三个可选参数 :latest 代表最新确认的交易的nonce ,earliest最早的交易nonce(说实话我也不知道这个返回的nonce是什么),pending 返回已经发送但是未被确认的nonce.
当交易频率较高的时候推荐使用pending参数.如果使用latest可能会导致nonce重复或者过小