以太坊交易中的Nonce詳解

nonce在區(qū)塊鏈中是一個(gè)非常重要的概念,從比特幣到以太坊都有nonce的身影勉躺。

在比特幣中癌瘾,nonce主要用于調(diào)整pow挖礦的難度,而在以太坊中饵溅,除了調(diào)整挖礦難度外妨退,在外部賬戶的每筆交易中也都存在一個(gè)nonce。這個(gè)nonce是一個(gè)連續(xù)的整數(shù)蜕企,在每個(gè)賬戶發(fā)送交易時(shí)所產(chǎn)生咬荷,其主要設(shè)計(jì)目的是為防止雙花。

web3中的sendTransaction方法轻掩,官方文檔是這樣寫的:

https://web3js.readthedocs.io/en/1.0/web3-eth.html#sendtransaction

image.png

可以看到幸乒,在構(gòu)建交易時(shí),有一個(gè)可選的nonce參數(shù)放典,可以覆蓋在交易池中的逝变,pending列表中相同nonce的交易。

接下來我會(huì)在Geth搭建的私有鏈來進(jìn)行以下實(shí)驗(yàn)奋构,來看看不同情況下nonce對(duì)應(yīng)的交易會(huì)怎樣:

  • 相同nonce下的兩筆交易
  • 不連續(xù)nonce下的交易
  • 不具體指定nonce的交易

說明:使用Geth搭建私有鏈詳見:http://www.reibang.com/p/4c3efd23a427

首先下方命令看到地址0xfa8d4ded7fe1fec96c1b10443bea261195f233bb的總交易數(shù)是2壳影,也就是說,nonce數(shù)值已累加到1(nonce值從0開始)弥臼,新的交易nonce值將是2宴咧。

> eth.getTransactionCount("0xfa8d4ded7fe1fec96c1b10443bea261195f233bb")
2

接下來指定nonce為2,創(chuàng)建一筆交易径缅,如下可看到掺栅,交易成功,并被打包到了1980區(qū)塊中纳猪。

> web3.eth.sendTransaction({from: "0xfa8d4ded7fe1fec96c1b10443bea261195f233bb", to: "0xf3756e74c9c409fdf4fa6d44c492fbb1edf36f53", value: "1000000000000000000", nonce: "2"})
"0x8a16b9a887928125071469332425896d33a1fa8c4e5a5deb50545f637ea1bf5d"

> eth.getTransaction("0x8a16b9a887928125071469332425896d33a1fa8c4e5a5deb50545f637ea1bf5d")
{
  blockHash: "0x9ba0aad04c9b52ef9bc543d274ce1718e32e9fdbf4bff7f88904f14c03f41855",
  blockNumber: 1980,
  from: "0xfa8d4ded7fe1fec96c1b10443bea261195f233bb",
  gas: 90000,
  gasPrice: 1000000000,
  hash: "0x8a16b9a887928125071469332425896d33a1fa8c4e5a5deb50545f637ea1bf5d",
  input: "0x",
  nonce: 2,
  r: "0xd530dc31288ff48f796763ce398a21cca9e9ab640f80890478b259dc247709e0",
  s: "0x275aa77f51cb157e2088e90cc3859bd2e53dbcc5bf752a5380a8736796a2a383",
  to: "0xf3756e74c9c409fdf4fa6d44c492fbb1edf36f53",
  transactionIndex: 0,
  v: "0x557",
  value: 1000000000000000000
}

如果此時(shí)我在發(fā)送一筆交易氧卧,并指定nonce還是2,運(yùn)行結(jié)果如下所示氏堤。

會(huì)看到此時(shí)交易報(bào)錯(cuò)沙绝,提示“nonce too low”

> web3.eth.sendTransaction({from: "0xfa8d4ded7fe1fec96c1b10443bea261195f233bb", to: "0xf3756e74c9c409fdf4fa6d44c492fbb1edf36f53", value: "1000000000000000000", nonce: "2"})
Error: nonce too low
    at web3.js:3143:20
    at web3.js:6347:15
    at web3.js:5081:36
    at <anonymous>:1:1

按照nonce的規(guī)則,接下來的新交易nonce值應(yīng)該是3,我現(xiàn)在跳過3闪檬,直接指定nonce值為4星著,會(huì)發(fā)生什么,如下所示粗悯。

> web3.eth.sendTransaction({from: "0xfa8d4ded7fe1fec96c1b10443bea261195f233bb", to: "0xf3756e74c9c409fdf4fa6d44c492fbb1edf36f53", value: "1000000000000000000", nonce:"4"})
"0xcbd473fb1bcc396dfd98e2f1807dea5b78c77f713592c134e7249b3786025d6a"

可以看到虚循,返回了交易hash,我們查看該筆交易样傍,發(fā)現(xiàn)blockNumber為null横缔,并沒有加入到區(qū)塊中,如下所示:

> eth.getTransaction("0xcbd473fb1bcc396dfd98e2f1807dea5b78c77f713592c134e7249b3786025d6a")
{
  blockHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
  blockNumber: null,
  from: "0xfa8d4ded7fe1fec96c1b10443bea261195f233bb",
  gas: 90000,
  gasPrice: 1000000000,
  hash: "0xcbd473fb1bcc396dfd98e2f1807dea5b78c77f713592c134e7249b3786025d6a",
  input: "0x",
  nonce: 4,
  r: "0x657ceabd6907d50d1af9046ea58352d0804cc3812b290ff103bc32514bc491c5",
  s: "0x2bc6b80ef7de0ed9a737ba78f404f825d58ab345c446019fbd67644c2f2b2a36",
  to: "0xf3756e74c9c409fdf4fa6d44c492fbb1edf36f53",
  transactionIndex: 0,
  v: "0x558",
  value: 1000000000000000000
}

暫未被加入到區(qū)塊中的交易铭乾,會(huì)被放入到交易池中(txpool)剪廉,交易池里會(huì)維護(hù)兩個(gè)列表,一個(gè)是待被打包的pending列表炕檩,一個(gè)是當(dāng)前無法執(zhí)行的交易queued列表。

從下方請(qǐng)求可看到0xcbd473fb1bcc396dfd98e2f1807dea5b78c77f713592c134e7249b3786025d6a交易被放到了queued列表中捌斧。這是由于交易池中沒有找到地址0xfa8d4DEd7fE1feC96c1B10443bEa261195f233Bb為3的nonce笛质。

> web3.txpool.content.queued
{
  0xfa8d4DEd7fE1feC96c1B10443bEa261195f233Bb: {
    4: {
      blockHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
      blockNumber: null,
      from: "0xfa8d4ded7fe1fec96c1b10443bea261195f233bb",
      gas: "0x15f90",
      gasPrice: "0x3b9aca00",
      hash: "0xcbd473fb1bcc396dfd98e2f1807dea5b78c77f713592c134e7249b3786025d6a",
      input: "0x",
      nonce: "0x4",
      r: "0x657ceabd6907d50d1af9046ea58352d0804cc3812b290ff103bc32514bc491c5",
      s: "0x2bc6b80ef7de0ed9a737ba78f404f825d58ab345c446019fbd67644c2f2b2a36",
      to: "0xf3756e74c9c409fdf4fa6d44c492fbb1edf36f53",
      transactionIndex: "0x0",
      v: "0x558",
      value: "0xde0b6b3a7640000"
    }
}

新建一筆交易,設(shè)置nonce為3捞蚂,如下所示妇押。

會(huì)看到提交交易后,queued列表中nonce為4的交易也被移出姓迅,同時(shí)待打包的pending列表中敲霍,有了nonce值為3和4的交易信息。挖礦后丁存,這兩筆交易將會(huì)被寫入到區(qū)塊中肩杈。

> web3.eth.sendTransaction({from: "0xfa8d4ded7fe1fec96c1b10443bea261195f233bb", to: "0xf3756e74c9c409fdf4fa6d44c492fbb1edf36f53", value: "1000000000000000000", nonce:"3"})
"0xf9ed5af220997d8278e075ed87b391e6a28354b0c45726bb41ebae22fe5817b1"

> web3.txpool.content.pending

{
  0xfa8d4DEd7fE1feC96c1B10443bEa261195f233Bb: {
    3: {
      blockHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
      blockNumber: null,
      from: "0xfa8d4ded7fe1fec96c1b10443bea261195f233bb",
      gas: "0x15f90",
      gasPrice: "0x3b9aca00",
      hash: "0xf9ed5af220997d8278e075ed87b391e6a28354b0c45726bb41ebae22fe5817b1",
      input: "0x",
      nonce: "0x7",
      r: "0x258f9f382c3cd8c595cd610ad7df09cc5b0d6b7a6cd68a67a0d151a1d72d8c72",
      s: "0x7c4fe98cbeb967f8a6d7ebb4c848c264521ddf98fc992f99571d4e2380e50a9a",
      to: "0xf3756e74c9c409fdf4fa6d44c492fbb1edf36f53",
      transactionIndex: "0x0",
      v: "0x557",
      value: "0xde0b6b3a7640000"
    },
    4: {
      blockHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
      blockNumber: null,
      from: "0xfa8d4ded7fe1fec96c1b10443bea261195f233bb",
      gas: "0x15f90",
      gasPrice: "0x3b9aca00",
      hash: "0xcbd473fb1bcc396dfd98e2f1807dea5b78c77f713592c134e7249b3786025d6a",
      input: "0x",
      nonce: "0x7",
      r: "0x258f9f382c3cd8c595cd610ad7df09cc5b0d6b7a6cd68a67a0d151a1d72d8c72",
      s: "0x7c4fe98cbeb967f8a6d7ebb4c848c264521ddf98fc992f99571d4e2380e50a9a",
      to: "0xf3756e74c9c409fdf4fa6d44c492fbb1edf36f53",
      transactionIndex: "0x0",
      v: "0x557",
      value: "0xde0b6b3a7640000"
    },
  }
}

總結(jié)一下:

  1. 以太坊中有兩種nonce,一種是在區(qū)塊中的nonce解寝,主要是調(diào)整挖礦難度扩然;一種是每筆交易中nonce。
  2. 每個(gè)外部賬戶(私鑰控制的賬戶)都有一個(gè)nonce值聋伦,從0開始連續(xù)累加夫偶,每累加一次,代表一筆交易觉增。
  3. 某一地址的某一交易的nonce值如果大于當(dāng)前的nonce兵拢,該交易會(huì)被放到交易池的queued列表中,直到缺失的nonce被提交到交易池中逾礁。
  4. 地址的nonce值是一個(gè)連續(xù)的整數(shù)说铃,起設(shè)計(jì)的主要目的是防止雙花。
  5. 在發(fā)生一筆交易時(shí),如果不指定nonce值時(shí)截汪,節(jié)點(diǎn)會(huì)根據(jù)當(dāng)前交易池的交易自動(dòng)計(jì)算該筆交易的nonce疾牲。有可能會(huì)出現(xiàn)節(jié)點(diǎn)A和節(jié)點(diǎn)B計(jì)算的nonce值不一樣的情況。

參考代碼:

https://github.com/ethereum/go-ethereum/blob/86e77900c53ebce3309099a39cbca38eb4d62fdf/core/tx_pool.go

一筆交易調(diào)用add(ctx context.Context, tx *types.Transaction)方法將交易信息加入到交易池的pending列表中衙解,需要對(duì)交易信息進(jìn)行驗(yàn)證阳柔,驗(yàn)證方法是validateTx,如下所示:

// validateTx checks whether a transaction is valid according to the consensus
// rules and adheres to some heuristic limits of the local node (price and size).
func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
    // Heuristic limit, reject transactions over 32KB to prevent DOS attacks
    if tx.Size() > 32*1024 {
        return ErrOversizedData
    }
    ...
    // Ensure the transaction adheres to nonce ordering
    if pool.currentState.GetNonce(from) > tx.Nonce() {
        return ErrNonceTooLow
    }
    ...
}

使用GetNonce方法獲取當(dāng)前地址在交易池中的nonce值,如果當(dāng)前交易的nonce比交易池中的nonce值小蚓峦,就會(huì)報(bào)“nonce too low”的錯(cuò)誤舌剂。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市暑椰,隨后出現(xiàn)的幾起案子霍转,更是在濱河造成了極大的恐慌,老刑警劉巖一汽,帶你破解...
    沈念sama閱讀 216,470評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件避消,死亡現(xiàn)場離奇詭異,居然都是意外死亡召夹,警方通過查閱死者的電腦和手機(jī)岩喷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來监憎,“玉大人纱意,你說我怎么就攤上這事【ɡ” “怎么了偷霉?”我有些...
    開封第一講書人閱讀 162,577評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長褐筛。 經(jīng)常有香客問我类少,道長,這世上最難降的妖魔是什么死讹? 我笑而不...
    開封第一講書人閱讀 58,176評(píng)論 1 292
  • 正文 為了忘掉前任瞒滴,我火速辦了婚禮,結(jié)果婚禮上赞警,老公的妹妹穿的比我還像新娘妓忍。我一直安慰自己,他們只是感情好愧旦,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,189評(píng)論 6 388
  • 文/花漫 我一把揭開白布世剖。 她就那樣靜靜地躺著,像睡著了一般笤虫。 火紅的嫁衣襯著肌膚如雪旁瘫。 梳的紋絲不亂的頭發(fā)上祖凫,一...
    開封第一講書人閱讀 51,155評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音酬凳,去河邊找鬼惠况。 笑死,一個(gè)胖子當(dāng)著我的面吹牛宁仔,可吹牛的內(nèi)容都是我干的稠屠。 我是一名探鬼主播,決...
    沈念sama閱讀 40,041評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼翎苫,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼服猪!你這毒婦竟也來了熙侍?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,903評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤揪惦,失蹤者是張志新(化名)和其女友劉穎攒磨,沒想到半個(gè)月后造挽,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體十偶,經(jīng)...
    沈念sama閱讀 45,319評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蚂会,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,539評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了作岖。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片漫雷。...
    茶點(diǎn)故事閱讀 39,703評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖鳍咱,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情与柑,我是刑警寧澤谤辜,帶...
    沈念sama閱讀 35,417評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站价捧,受9級(jí)特大地震影響丑念,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜结蟋,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,013評(píng)論 3 325
  • 文/蒙蒙 一脯倚、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧嵌屎,春花似錦推正、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至尼夺,卻和暖如春尊残,著一層夾襖步出監(jiān)牢的瞬間炒瘸,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評(píng)論 1 269
  • 我被黑心中介騙來泰國打工寝衫, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留顷扩,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,711評(píng)論 2 368
  • 正文 我出身青樓慰毅,卻偏偏與公主長得像隘截,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子事富,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,601評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • 問題起源 在使用同一個(gè)地址連續(xù)發(fā)送交易時(shí)技俐,每筆交易往往不可能立即到賬, 當(dāng)前交易還未到賬的情況下统台,下一筆交易無論是...
    糙米薏仁湯閱讀 5,135評(píng)論 1 6
  • 原文地址 https://mbinary.coding.me/introduction-to-bitcoin.ht...
    mbinary閱讀 5,139評(píng)論 0 4
  • 8.1 簡介 挖礦是增加比特幣貨幣供應(yīng)的一個(gè)過程雕擂。挖礦同時(shí)還保護(hù)著比特幣系統(tǒng)的安全,防止欺詐交易贱勃,避免“雙重支付”...
    冉冉升起的沙丁魚閱讀 1,617評(píng)論 0 1
  • 長相普通的宋念念21歲了井赌,仍然單著,但是她有喜歡的人了贵扰。而她喜歡的人就是她多年的好友丁杭仇穗,他不算帥,但180的身高...
    徐漾閱讀 378評(píng)論 0 5
  • 等你 天晴的日子 我在陽光下等你 下雨的時(shí)候 我在云層里等你 我站成了一棵樹 一半在風(fēng)中 一半在土里 等你 從晨曦...
    鳴鷗閱讀 375評(píng)論 11 5