以太坊源碼分析:交易緩衝池txpool

區塊鏈就是何交易打交道,咱們今天就介紹下,交易處理過程當中的一個重要組成部分:txpool。這篇文章主要從功能角度介紹,經過這篇文章會了解:緩存

  1. txpool的在交易中的位置和做用。
  2. txpool的功能,核心組成部分queued和pending。
  3. txpool如何實現它的功能。
  4. txpool源碼的重要關注點。

以太坊內部有個重要的內部功能是txpool,從字面意思就能看出來,交易池就是存放交易的池子。它在以太坊中的位置以下圖,只要有新交易,不管是本節點建立的,仍是其餘peer節點廣播來的,都會先加入到交易池裏,在打包區塊的時候,就從這個池子裏提取,區塊產生以後,共識區塊,交易上鍊。less

txpool主圖

txpool有4個功能:函數

  1. 做爲存放交易的緩衝區,大量交易到來時,先存起來
  2. 爲打包區塊服務,合適交易會被打包到區塊
  3. 清理交易
  4. 當交易的數量多於緩衝區大小時,過濾/懲罰發送大量交易的帳戶(攻擊者)

咱們來一張稍微詳細點的模塊交互圖,看txpool怎麼實現上面4個功能的。oop

txpool模塊交互

緩存功能的設計

txpool中的交易分爲queued和pending 2種,其中queued存放將來的、當前沒法執行的交易。以太坊使用nonce值決定某個帳戶的交易順序,多條交易值nonce值必須連續,若是和過去的交易不連續,則沒法執行,咱們不妨使用nonce值,標記交易的號碼,nonce爲10的交易,稱爲第10號交易。舉個例子,當前帳戶的nonce是10,txpool中有該帳戶的第100號交易,但txpool中沒有第11~99號交易,這些交易的缺失,形成第100號交易沒法執行,因此第100號交易就是將來的交易、不可執行的交易,存放在queue中。性能

pending存放可執行的交易。好比咱們把上面的11~99號交易補全了,那麼11~100號交易均可以進入到pending,由於這些交易都是連續的,均可以打包進區塊。區塊鏈

當節點收到交易(本地節點發起的或peer廣播來的)時,會先存放到queued,txpool在某些狀況下,把queued中可執行的交易,轉移到pending中。spa

爲區塊打包服務

這是txpool最核心的功能,worker在打包區塊的時候,會獲取全部的pending交易,但這些交易還存在txpool中,worker只是讀取出來,至於txpool什麼時候刪除交易,稍後從txpool清理交易的角度單獨在看。設計

清理交易

txpool清理交易有如下幾種條件,符合任意如下1條的,都是無效交易,會被從pending或者queued中移除code

  1. 交易的nonce值已經低於帳戶在當前高度上的nonce值,表明交易已過時,交易已經上鍊就屬於這種狀況
  2. 交易的GasLimit大於區塊的GasLimit,區塊容不下交易
  3. 帳戶的餘額已不足以支持該交易要消耗的費用
  4. 交易的數量超過了queued和pending的緩衝區大小,須要進行清理

交易清理主要有3個場景事件

  1. txpool訂閱了ChainHeadEvent事件,該事件表明主鏈上有新區塊產生,txpool會根據最新的區塊,檢查每一個帳號的交易,有些無效的會被刪除,有些因爲區塊回滾會從pending移動到queued,而後把queued中可執行的交易移動到pending,爲下一輪區塊打包組號準備。
  2. queued交易移動到pending被稱爲「提高」(promote),這個過程當中,一樣會檢查交易,當交易不符合以上條件時,就會被直接從queued中刪除。
  3. 刪除停留在queued中超過3小時的交易,3小時這個超時時間是能夠經過geth的啓動參數調整的。txpool記錄了某個帳戶交易進入pending的時間,若是這個時間超過了3小時,表明該帳號的交易遲遲不能被主鏈打包,既然沒法被主連接受,就刪除掉在queued中原本就沒法執行的交易。

懲罰惡意帳號

這也是txpool很重要的一個屬性,能夠防止惡意帳戶以發起大量垃圾交易。防止惡意用戶形成:

  1. 佔用txpool空間
  2. 浪費節點大量內存和CPU
  3. 下降打包性能

只有當交易的總數量超過緩衝區大小時,txpool纔會認爲有惡意帳戶發起大量交易。pending和queued緩衝區大小不一樣,但處理策略相似:

  1. pending的緩衝區容量是4096,當pending的交易數量多於此時,就會運行檢查,每一個帳號的交易數量是否多於16,把這些帳號蒐集出來,進行循環依次清理,什麼意思呢?就是每輪只刪除(移動到queued)這些帳號的每一個帳號1條交易,而後看數量是否降下來了,不知足再進行下一輪,直到知足。
  2. queued的緩衝區容量是1024,超過以後清理策略和pending差很少,但這裏但是真刪除了。

該部分功能未抽象成單獨的函數,而是在promoteExecutables()中,就是在每次把queued交易轉移到pending後執行的。

本地交易的特權,txpool雖然對交易有諸多限制,但若是交易是本節點的帳號發起的,以上數量限制等都對他無效。因此,若是你用本節點帳號不停的發送交易,並不會被認爲是攻擊者,你用txpool.status命令,能夠查看到交易的數量,確定能夠大於4096,我曾達到過60000+。

重點關注的源碼

txpool的主要設計上面就講完了,若是你想把txpool的代碼閱讀一番,我建議你重點關注一下這些函數和變量,按圖索驥能就徹底掌握txpool的實現。

  • TxPoolConfig:txpool的配置參數
  • chainHeadCh:txpool訂閱了新區塊事件
  • pending:pending的交易,每一個帳號都有一個交易列表
  • queue:queued的交易,每一個帳號都有一個交易列表
  • loop:txpool的事件處理函數
  • addTx:添加1條交易的源頭,你能找到相似的函數
  • promoteExecutables:queued交易移動到pending
  • reset:根據當前區塊的最新高度,重置txpool中的交易

仔細閱讀一遍,你會發現txpool會涉及多個鎖(TxPool.mu, TxPool.all, TxPool.priced.all),因此當txpool中的交易不少時,它的性能是很低的,這也會影響到區塊的打包。

  1. 若是這篇文章對你有幫助,請點個贊/喜歡,鼓勵我持續分享,感謝。
  2. 個人文章列表,點此可查看
  3. 若是喜歡本文,隨意轉載,但請保留此原文連接

一塊兒學Golang-分享有料的Go語言技術

相關文章
相關標籤/搜索