如何正確處理nonce

王一洋發表於2018-09-14

問題概述

以太坊系列(ETH&ETC)在傳送交易有三個對應的RPC介面,分別是ethsendTransaction、ethsendRawTransaction和personal_sendTransaction。這三個介面傳送(或構造傳送內容時)都需要一個引數nonce。官方文件對此引數的解釋是:整數型別,允許使用相同隨機數覆蓋自己傳送的處於pending狀態的交易。

官網解釋

僅從官網的解釋,我們無法獲取到更多的有效的資訊。但在真實生成中我們會發現如果傳錯nonce欄位值,通過RPC介面呼叫傳送的交易很大可能將不會被確認。如果通過console命令來操作一般不會出現此問題,因為節點已經幫我們處理了。

問題追蹤

如果繼續追蹤問題,會發現nonce傳遞錯誤的交易可以通過eth_getTransaction查詢得到相關資訊,但是它的blocknumber始終未null,也就說這邊交易始終未被確認。如果是在dev模式下,應該是很快就會被確認的。更進一步,通過txpool.content命令,會發現那筆交易一直處於queued佇列中,而未被消費。

原因解析

為了防止交易重播,ETH(ETC)節點要求每筆交易必須有一個nonce數值。每一個賬戶從同一個節點發起交易時,這個nonce值從0開始計數,傳送一筆nonce對應加1。當前面的nonce處理完成之後才會處理後面的nonce。注意這裡的前提條件是相同的地址在相同的節點傳送交易。 以下是nonce使用的幾條規則: ● 當nonce太小(小於之前已經有交易使用的nonce值),交易會被直接拒絕。 ● 當nonce太大,交易會一直處於佇列之中,這也就是導致我們上面描述的問題的原因; ● 當傳送一個比較大的nonce值,然後補齊開始nonce到那個值之間的nonce,那麼交易依舊可以被執行。 ● 當交易處於queue中時停止geth客戶端,那麼交易queue中的交易會被清除掉。

獲取nonce值

經過上面的解釋追蹤,我們已經瞭解到了nonce的基本使用規則。那麼,在實際應該用中我們如何保障nonce值的可靠性呢?這裡有兩個思路:

第一個思路就是由業務系統維護nonce值的遞增。如果交易傳送就出現問題,那麼該地址下一筆交易繼續使用這個nonce進行傳送交易。

第二個思路就是使用現有的api查詢當前地址已經傳送交易的nonce值,然後對其加1,再傳送交易。對應的API介面為:eth_getTransactionCount,此方法由兩個引數,第一個引數為需要查詢nonce的地址,第二個引數為block的狀態:latest、earliest和pending。一般情況使用pending就可以查詢獲得最新已使用的nonce。其他狀態大家可以自行驗證。

相關文章