深入理解以太坊交易處理機制
前言
一級標題"前言"、"前言"去中心化"一級標題"前言"區塊鍊是一個以"去信任化
賬本
一級標題

基本概念
一級標題
的區塊鏈自然少不了記賬,而交易自然而然的成為了重中之重。知道創宇區塊鏈安全實驗室將從源代碼視角對以太坊交易池數據結構、交易費用設置、交易構建、交易入池、交易簽名、交易驗證等邏輯設計進行簡要淺析,並通過對以太坊交易安全機制設計來研究公鏈安全機制設計。
一級標題
基本概念
交易流程示意圖大致如下所示:首先由用戶通過網絡發起交易請求,並使用自己的私鑰對交易進行簽名,之後進行交易廣播,進而將交易添加到交易池中,礦工從交易池中獲取交易信息,然後將其進行打包並生成區塊,之後通過進行共識出塊,最後向全網廣播交易區塊。
交易池的數據來源:
一級標題

遠程同步,通過廣播同步的形式,將其他以太坊節點的交易數據同步至本地節點。
交易池的數據去向:由miner(礦工) 獲取並驗證,用於挖礦,挖礦成功後寫進區塊被廣播,交易被寫入規範鏈後會從交易池中進行刪除,如果交易被寫進分叉則交易池中的交易不會減少,之後等待重新打包。

數據結構
一級標題
二級標題

二級標題

02 交易池配置

二級標題
二級標題


初始化池


02 交易池配置

二級標題

03 交易檢索數量

初始化池

交易池的初始化通過NewTxPool 來實現,具體代碼如下所示:

在這里首先調用sanitize 函數對配置參數進行校驗,以規避設置不合理的gas prices。


之後使用默認配置初始化一個交易池( txpool ):

之後初始化本地賬戶並將配置的本地賬戶地址加到交易池:


之後創建更加gasprices 排序的交易:

具體實現代碼如下所示:

reset 具體實現如下:


scheduleReorgLoop 具體實現代碼如下所示,該函數主要用於reset 和promoteExecutable 的執行計劃。
一級標題

之後訂閱相關交易事件並開啟主循環:
一級標題
主循環loop 具體實現代碼如下,它是txPool 的一個goroutine,也是主要的事件循環,它主要用於等待和響應外部區塊鏈事件以及各種報告和交易驅逐事件 :
一級標題
構建交易
交易有用戶發起,使得資產從一方轉移至另一方,即所謂的價值轉移,我們最直觀的交易構建就是通過錢包來進行轉賬,在這裡我們直接以eth_sendTransaction 這一個RPC 為例進行分析交易的構建流程,eth_sendTransaction 請求示例如下:
參數示例:
from: DATA,20 字節- 發送交易的源地址

to: DATA,20 字節- 交易的目標地址,當創建新合約時可選

gas: QUANTITY - 交易執行可用gas 量,可選整數,默認值90000,未用gas 將返還

gasPrice: QUANTITY - gas 價格,可選,默認值:待定(To-Be-Determined)"value: QUANTITY - 交易發送的金額,可選整數"data: DATA - 合約的編譯帶啊或被調用方法的簽名及編碼參數


nonce: QUANTITY - nonce,可選,可以使用同一個nonce 來實現掛起的交易的重寫

響應示例:"下面我們來跟踪一下eth_sendTransaction 這一個RPC 的執行過程,在這里首先檢索賬戶是否存在,之後檢查Nonce 是否為空,緊接著調用SingTx 進行簽名操作,之後調用SubmitTransaction 來提交交易:"SignTx 實現代碼如下所示,在這裡會繼續調用SignTx 進行簽名操作,這裡不再深入,後續的

會進行纖細分析:

這一個分析單元模塊:
一級標題

交易入池


一級標題

之後檢查接受地址是否為空,如果為空則創建一個地址(一般在合約創建時出現),之後打印一份完整的TX 詳細信息的日誌便於後續手動調查分析,之後返回交易的hash 值:

一級標題

交易入池



我們知道交易的來源有兩個方面:一個方面是本地提交的,另一個方面是遠程提交的,這兩個的具體實現代碼分別為AddLocals 和AddRemotes,這兩個函數在添加交易到交易池時都是通過調用addTxs 來實現的:

addTxs 代碼如下所示:

首先會對交易進行過濾,檢查是否是一個已知的交易(即添加過或廣播過的),之後調用send 函數校驗通過secp256k1 橢圓曲線從簽名(v,r,s) 派生的地址,如果派生失敗或簽名不正確,則返回錯誤 :

之後將交易添加到交易池中去(注意: 這裡有事務鎖)

addTxsLocked 的具體實現如下所示,它會將有效的交易進行排隊處理,同時調用pool.add 函數將交易添加到交易隊列中去:

add 函數的具體實現如下所示:


在這裡會首先檢查當前的交易是否已經知曉(即被廣播過或者添加到池子裡過),如果已知曉則直接丟棄:

之後鑑別交易是本地提交還是遠程提交,並調用函數validateTx 來驗證交易,如果驗證不通過則直接丟棄:
之後檢查交易池是否滿了,如果滿了則放棄交易隊列中定價過低的交易,GlobalSlots 和GlobalQueue 為pending 和queue 的最大容量:


之後判斷當前交易在pending 隊列中是否存在nonce 值相同的交易,如果存在則判斷當前交易所設置的gasprice 是否超過設置的PriceBump 百分比,超過則替換覆蓋已存在的交易,否則報錯返回替換交易Gasprice 過低,並且把它扔到queue 隊列中( enqueueTx ):

之後調用enqueueTx 將添加到交易隊列中去,同時檢查from 賬戶是否為本地地址,如果是則添加到交易池本地地址中去:

enqueueTx 代碼如下所示,該函數主要將新的交易插入到交易隊列中去:

在sign 中使用ECDSA (橢圓曲線加密算法) 進行簽名,之後返回簽名的結果:

交易驗證
一級標題
交易驗證
一級標題
交易驗證
一級標題
交易驗證時整個交易環節最重要的一環,對於用戶來說,交易驗證時保證用戶財產安全的重要手段,而對於整個以太坊來說,交易驗證時保證以太坊穩定運行和持續發展的重要方式,交易驗證主要出現在以下幾個場景中:


節點收到其他節點廣播的交易時,節點需要先驗證交易是否合法,合法的交易才會加入節點的交易池;
一級標題


節點收到其他節點同步到的區塊是,也需要驗證區塊中包含的交易。

一級標題

交易驗證由validateTx 函數來完成,其邏輯代碼如下所示,在這裡會檢查eip2718 是否開啟以及交易的類型,之後檢查交易的size、交易轉賬的額度、交易的gas、交易簽名的正確性、確保交易遵循Nonce 順序、交易人資產是否足夠、確保交易的gas price 幣基本的交易費用要高:

一級標題

交易升級

交易升級主要是指將交易放入pending 列表中去,該方法與add 方法的不同之處在於add 函數是將獲得到的新交易插入pending,而PromoteExecutables 是將把給定的賬號地址列表中可以執行的交易從queue 列表中插入pending 中,並檢查失效的交易,然後發送交易池更新事件,其實現代碼如下所示:

在這里通過一個for 循環來迭代所有的賬戶併升級交易,在這里首先將所有queue 中nonce 低於賬戶當前nonce 的交易刪除:
之後將所有queue 中消費大於賬戶所持餘額或者gas 大於最大gas 限制的交易移除:
之後將所有可執行的交易從queue 裡面添加到pending 裡面,在這裡會調用promoteTx 方法將隊列中的交易( Txs ) 放入pending:
promoteTx 實現代碼如下所示,該函數首先將交易插入到pending 隊列中去,如果舊交易更好(交易Gasprice 大於或等於原交易價值的110% 為標準,具體跟pricebump 設定有關係) 則刪除當前這個交易,如果當前交易相較於舊的交易更好則刪除舊的交易,之後更新列表:
之後回到promoteExecutables 函數中,如果非本地賬戶queue 小於限制( AccountQueue ) 則進行移除操作:
交易降級


分叉導致pending 最前一個交易的nonce 值與狀態的nonce 值不等。
一級標題



池子重置
一級標題



一級標題

我們可以通過reset 來重置交易池,該方法具體代碼如下所示:
一級標題"如果舊頭不為null 則開始進行重組,此時如果舊鏈的頭區塊大於新鏈的頭區塊高度時則舊鏈先後回退並回收所有回退的交易,如果新鏈的頭區塊大於舊鏈的頭區塊則新鏈後退並回收交易,當新鍊和舊鏈的到達同一高度時則同時回退直到找到共同的父節點,之後找出所有存儲在discard 裡面但是不在included 裡面的值,之後將這些交易重新插入到pool 裡面:"一級標題
文末小結
參考鏈接:
https://blog.csdn.net/lj900911/article/details/84825739
https://blog.csdn.net/pulong074

