P2P網絡數據交互

1. 發送交易數據SendTransactions

事件觸發交易廣播txBroadcastLoop

本地發送了一個交易,或者是接收到別人發來的交易信息。 txpool會產生一條消息,消息被傳遞到txCh通道。而後被goroutine txBroadcastLoop()處理, 發送給其餘不知道這個交易的peer。緩存

ProtocolManager在Start的時候,訂閱TxPreEvent並啓動txBroadcastLoop協程監聽事件。併發

當監聽到事件後,調用BroadcastTx進行廣播,廣播按照委員及候選委員,接入節點,輕節點逐層廣播。app

發送交易以前,會把tx.Hash放到peer的knownTxs中:函數

新鏈接創建txsyncLoop

txsyncLoop負責每一個新鏈接的初始事務同步。 當新的peer出現時,咱們轉發全部當前待處理的事務。oop

在txsyncLoop函數中定義了一個send函數來廣播交易信息:區塊鏈

2. 發送區塊哈希值SendNewBlockHashes

廣播挖礦區塊 NewMinedBlockEvent

ProtocolManager在Start的時候,訂閱NewMinedBlockEvent並啓動 minedBroadcastLoop()協程監聽事件。fetch

監聽到事件後,開始廣播區塊信息。編碼

先根據BroadcastBlock輸入的參數propagate決定是否廣播區塊,當propagate爲true時,廣播區塊信息。以後開始廣播區塊哈希。spa

廣播時,先把hash放到knownBlocks裏面,在廣播區塊和區塊哈希協程

基於塊通知的同步Fetcher

Fetcher Start函數中啓動協程:

Fetcher模塊的queue裏面緩存了已經完成fetch的block,等待按照順序插入到本地的區塊鏈中。優先級別就是他們的區塊號,這樣區塊數小的排在最前面。最後調用insert方法把給定的區塊插入本地的區塊鏈。

在insert函數中,有兩處廣播:一是若是區塊頭經過驗證,那麼立刻對區塊進行廣播;二是若是插入成功, 那麼廣播區塊,第二個參數爲false,那麼只會對區塊的hash進行廣播。

定時同步syncer

syncer中會定時的同BestPeer()來同步信息: 當有新的Peer增長的時候 會同步, 這個時候可能觸發區塊廣播; 定時觸發 10秒一次。

3. 發送區塊內容SendNewBlock

參照SendNewBlockHashes的處理流程。

4. 發送區塊頭信息SendBlockHeaders

在經過握手後runPeer時,會運行protocol的run函數,接着調用startProtocols函數,進而進入NewProtocolManager的時候定義的Run,每個SubProtocols都有一個Run。

這個run方法首先建立了一個peer對象,而後調用了handle方法來處理這個peer。注意,這裏的peer區別於p2p中的peer,可是它包含p2p的peer。

在handle最後,循環調用handleMsg, 這個方法很長,主要是處理接收到各類消息以後的應對措施。

對於GetBlockHeadersMsg的消息處理,結果調用SendBlockHeaders返回給對端:

首先解碼msg,解析出getBlockHeadersData結構體。

查找方式:

從Hash指定的開始朝創世區塊移動,也就是反向移動。

從Hash指定的開始正向移動。

經過Number反向查找。

經過Number正向查找。

查找結果發給對端:

5. 發送區塊體信息SendBlockBodies

沒有用到。

6. RLP編碼發送區塊體信息SendBlockBodiesRLP

調用流程參考「4 發送區塊頭信息SendBlockHeaders」。

收到GetBlockBodiesMsg,解析msg信息,組織bodies併發送給對端。

7. 發送節點信息SendNodeData

調用流程參考「4 發送區塊頭信息SendBlockHeaders」。

GetNodeDataMsg對應的協議版本要大於等於eth63。

8. RLP編碼發送節點信息SendReceiptsRLP

調用流程參考「4 發送區塊頭信息SendBlockHeaders」。

9. 請求一個區塊頭RequestOneHeader

調用流程參考「4 發送區塊頭信息SendBlockHeaders」。

10. 經過Hash請求區塊頭RequestHeadersByHash

首先,在協議初始化的時候,調用protocolManager.Start

以後啓動syncer(), syncer中會定時的同BestPeer()來同步信息: 當有新的Peer增長的時候 會同步; 定時觸發 10秒一次同步。

​)

pm.synchronise會調用中 Downloader中的同步函數。 Synchronise試圖和一個peer來同步,若是同步過程當中遇到一些錯誤,那麼會刪除掉Peer。而後會被重試。

最後,在syncWithPeer中會啓動幾個fetcher 分別負責header,bodies,receipts處理。spawnSync給每一個fetcher啓動一個goroutine, 而後阻塞的等待fetcher出錯。

在fetchHeight中,會發出RequestHeadersByHash請求。

fetchHeaders方法用來獲取header。 而後根據獲取的header去獲取body和receipt等信息。fetchHeaders不斷的重複這樣的操做,發送header請求,等待全部的返回,直到完成全部的header請求。

11. 經過Number請求區塊頭RequestHeadersByNumber

調用流程參考「10 經過Hash請求區塊頭RequestHeadersByHash」。

12. 請求區塊體RequestBodies

調用流程參考「10 經過Hash請求區塊頭RequestHeadersByHash」。

13. 請求收據RequestReceipts

調用流程參考「10 經過Hash請求區塊頭RequestHeadersByHash」。

14. 請求節點信息RequestNodeData

在建立Downloader的時候,會同時啓動協程 startFetcher,進而啓動runStateSync。

15. 握手Handshake

head是當前的區塊頭,genesis是創世區塊的信息,只有創世區塊相同才能握手成功。若是接收到任何一個錯誤(發送,接收),或者是超時,那麼就斷開鏈接,握手失敗。

readStatus,檢查對端返回的各類狀況。

相關文章
相關標籤/搜索