国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

以太坊源碼分析—p2p節點發現與協議運行

xcc3641 / 612人閱讀

摘要:前言負責以太坊底層節點間的通信,主要包括底層節點發現和上層協議運行兩大部分。啟動了一個定時器,定期隨機選擇一個,向其中末尾的節點發送消息,如果對方回應了,則探活成功。

前言

p2p(peer to peer)負責以太坊底層節點間的通信,主要包括底層節點發現(discover)和上層協議運行兩大部分。

節點發現

節點發現功能主要涉及 Server Table udp 這幾個數據結構,它們有獨自的事件響應循環,節點發現功能便是它們互相協作完成的。其中,每個以太坊客戶端啟動后都會在本地運行一個Server,并將網絡拓撲中相鄰的節點視為Node,而TableNode的容器,udp則是負責維持底層的連接。這些結構的關系如下圖

Server
p2p/server.go
type Server struct {
    PrivateKey  *ecdsa.PrivateKey
    Protocols    []protocol
    StaticNodes[]  *discover.Node
    newTransport  func(net.Conn)  transport  
    ntab    disvocerTable    
    ourHandshake    *protoHandshake    

    addpeer    chan *conn
    ......
}

PrivateKey - 本節點的私鑰,用于與其他節點建立時的握手協商
Protocols - 支持的所有上層協議
StaticNodes - 預設的靜態Peer,節點啟動時會首先去向它們發起連接,建立鄰居關系
newTransport - 下層傳輸層實現,定義握手過程中的數據加密解密方式,默認的傳輸層實現是用newRLPX()創建的rlpx,這不是本文的重點
ntab - 典型實現是Table,所有peerNode的形式存放在Table
ourHandshake - 與其他節點建立連接時的握手信息,包含本地節點的版本號以及支持的上層協議
addpeer - 連接握手完成后,連接過程通過這個通道通知Server

Server.listenLoop()

Server的監聽循環,啟動底層監聽socket,當收到連接請求時,Accept后調用setupConn()開始連接建立過程

Server.run()

Server的主要事件處理和功能實現循環

進行主動的節點發現,詳見之后的節點發現部分

posthandshake channel 接收已經完成第一階段的連接,這些連接的身份已經被確認,但還需要驗證

addpeer channel 接收已經完成第二階段的連接,這些連接已經驗證,調用runPeer()運行本節點與Peer連接上的協議

Node

Node唯一表示網絡上的一個節點

p2p/discover/node.go
type Node struct {
    IP net.IP
    UDP, TCP uint16
    ID      NodeID
    sha    common.Hash
}

IP - IP地址
UDP/TCP - 連接使用的UDP/TCP端口號
ID - 以太坊網絡中唯一標識一個節點,本質上是一個橢圓曲線公鑰(PublicKey),與ServerPrivateKey對應。一個節點的IP地址不一定是固定的,但ID是唯一的。
sha - 用于節點間的距離計算


Table

Table主要用來管理與本節點與其他節點的連接的建立更新刪除

p2p/discover/table.go
type Table struct {
    bucket   [nBuckets]* bucket
    refreshReq    chan chan struct{}
    ......
}

bucket - 所有peer按與本節點的距離遠近放在不同的桶(bucket)中,詳見之后的節點維護
refreshReq - 更新Table請求通道

Table.loop()

Table的主要事件循環,主要負責控制refreshrevalidate過程。
refresh.C - 定時(30s)啟動Peer刷新過程的定時器
refreshReq - 接收其他線程投遞到Table刷新Peer連接的通知,當收到該通知時啟動更新,詳見之后的更新鄰居關系
revalidate.C - 定時重新檢查以連接節點的有效性的定時器,詳見之后的探活檢測

udp

udp負責節點間通信的底層消息控制,是Table運行的Kademlia協議的底層組件

type udp struct {
    conn  conn
    addpending chan *pending
    gotreply  chan reply
    *Table
}

conn - 底層監聽端口的連接
addpendingudp用來接收pending的channel。使用場景為:當我們向其他節點發送數據包后(packet)后可能會期待收到它的回復,pending用來記錄一次這種還沒有到來的回復。舉個例子,當我們發送ping包時,總是期待對方回復pong包。這時就可以將構造一個pending結構,其中包含期待接收的pong包的信息以及對應的callback函數,將這個pengding投遞到udp的這個channel。udp在收到匹配的pong后,執行預設的callback。
gotreply - udp用來接收其他節點回復的通道,配合上面的addpending,收到回復后,遍歷已有的pending鏈表,看是否有匹配的pending。
Table - 和Server中的ntab是同一個Table

udp.loop()

udp的處理循環,負責控制消息的向上遞交和收發控制

addpending 接收其他線程投遞來的pending需求

gotreply 接收udp.readLoop()投遞過來的pending的回復

udp.readLoop()

udp的底層接受數據包循環,負責接收其他節點的packet

接受其他節點發送的packet并解析,如果是回復包則投遞到udp.loop()


節點維護

以太坊使用Kademlia分布式路由存儲協議來進行網絡拓撲維護,了解該協議建議先閱讀易懂分布式。更權威的資料可以查看wiki。總的來說該協議:

使用UDP進行節點間消息通信,有 4 種消息

ping - 用于探測其他節點是否還存在

store - 接收者受到后,將信息中key/value對存儲在本節點

findnode - 接受者向發送者返回 k 個它知道的與目標結點距離最近的節點

findvalue - 和findnode 差不多,區別是如果接收者本地存在與目標結點對應的value,那么就回復這個值給發送者。

每個節點根據與鄰居節點距離之間的距離(NodeID的差距),分別放到不同的桶(bucket)中。

本文說的距離,均是指兩個節點NodeID的距離,計算方式可見p2p/discover/node.gologdist()方法

源碼中由Table結構保存所有bucketbucket結構如下

p2p/discover/table.go
type bucket struct {
    entries  []*Node
    replacemenets   []*Node
    ips  netutil.DistinctNetSet
}

entries 數組中保存經過bond的節點,并且其順序是越新bond通過了探活檢測(Revalidate)的節點位置越靠前。

replacemenets數組中保存候補節點,如果entries 數組數量滿了,之后的節點會被加入該數組

節點可以在entriesreplacements互相轉化,一個entries節點如果Validate失敗,那么它會被原本將一個原本在replacements數組的節點替換。

探活檢測(Revalidate)

有效性檢測就是利用ping消息進行探活操作。Table.loop()啟動了一個定時器(0~10s),定期隨機選擇一個bucket,向其entries中末尾的節點發送ping消息,如果對方回應了pong,則探活成功。

舉個栗子,假設某個bucket, entries最多保存2個節點,replacements最多保存4個節點。初始情況下entries=[A, B], replacements =  [C, D, E],如果此時節點F加入網絡,bond通過,由于entries已滿,只能加入到replacements =  [C, D, E, F]。 此時Revalidate定時器到期,則會對 B進行檢測,如果通過,則entries=[B, A],如果不通過,則將隨機選擇replacements中的一項(假設為D)替換B的位置,最終entries=[A, D],replacements =  [C, E, F]
更新鄰居關系

Table.loop()會定期(定時器超時)或不定期(收到refreshReq)地進行更新鄰居關系(發現新鄰居),兩者都調用doRefresh()方法,該方法對在網絡上查找離自身和三個隨機節點最近的若干個節點。

節點查找

Tablelookup()方法用來實現節點查找目標節點,它的實現就是Kademlia協議,通過節點間的接力,一步一步接近目標。

鄰居初始化

當一個節點啟動后,它會首先向配置的靜態節點發起連接,發起連接的過程稱為Dial,源碼中通過創建dialTask跟蹤這個過程

dialTask

dialTask表示一次向其他節點主動發起連接的任務

p2p/dial.go
type dialTask struct {
    flags    connFlag
    dest    *discover.Node
    ......
}

Server啟動時,會調用newDialState()根據預配置的StaticNodes初始化一批dialTask, 并在Server.run()方法中,啟動這些這些任務。

Dial過程需要知道目標節點(dest)的IP地址,如果不知道的話,就要先使用 recolve()解析出目標的IP地址,怎么解析?就是先要用借助Kademlia協議在網絡中查找目標節點。


當得到目標節點的IP后,下一步便是建立連接,這是通過dialTask.dial()建立連接

連接建立

連接建立的握手過程分為兩個階段,在在SetupConn()中實現
第一階段為ECDH密鑰建立:

sequenceDiagram
Note left of Dialer: Calc token
Note left of Dialer: Generate Random PrikeyNonce
Note left of Dialer: Sign
Dialer->>Receiver: AuthMsg
Note right of Receiver: Calc token
Note right of Receiver: Check Signature
Note right of Receiver: Generate Random PrikeyNonce
Receiver->>Dialer: AuthResp

第二階段為協議握手,互相交換支持的上層協議

sequenceDiagram
Dialer->>Receiver: protoHandshake
Receiver->>Dialer: protoHandshake

如果兩次握手都通過,dialTask將向Serveraddpeer通道發送peer的信息

sequenceDiagram
participant Server.run()
participant dialTask
participant Remote Node
dialTask->>Remote Node:EncHandshake
Remote Node->>dialTask:EncHandshake
dialTask->>Server.run(): posthandshake
dialTask->>Remote Node:ProtoHandshake
Remote Node->>dialTask:ProtoHandshake
dialTask->>Server.run(): addpeer
Note over Server.run(): go runPeer()
協議運行

協議運行并不單單指某個特定的協議,準確地說應該是若干個獨立的協議同時在兩個節點間運行。在p2p節點發現提到過,節點間建立連接的時候會經過兩次握手,其中的第二次握手,節點間會交換自身所支持的協議。最終兩個節點間生效的協議為兩個節點支持的協議的交集

功能主要涉及 Peer protoRW 這幾個數據結構,其關系如圖

Peer

rw - 節點間連接的底層信息,比如使用的socket以及對端節點支持的協議(capabilities)

running - 節點間生效運行的協議簇

Peer.run()負責連接建立后啟動運行上層協議,它自身運行在一個獨立的go routine,具有自己的事件處理循環,除此之外,它還會額外創建2+ngo routine, 其中2包括一個用于保活的pingLoop() go routine和一個用于接收協議數據的readLoop() go routine ,而 n 為運行于其上的n個協議的go routine,即每個協議調用自己的Run()方法運行在自己多帶帶的go routine

protoRW

Run 每種協議自身的運行入口,以新的go routine形式啟動.

總結

p2p主要由底層節點發現和上層協議運行兩部分組成,節點發現負責管理以太坊網絡中各個節點間的連接建立,更新和刪除,Server是p2p功能的入口,Table負責記錄peer節點信息, udp負責底層通信。而在底層的基礎上,節點間可以運行多個獨立的協議。

以太坊使用Kademlia分布式路由存儲協議來進行網絡拓撲維護,將不同距離的peer節點放在不同的bucket中。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/24380.html

相關文章

  • 以太源碼分析—Whisper

    摘要:前言是以太坊中一項非常有趣的技術,它是一個基于身份的通信系統,被設計用于之間少量數據通信。協議運行在以太坊協議框架之上,所有運行協議的節點以下簡稱節點組成一個網絡。 [TOC] 前言 Whisper是以太坊中一項非常有趣的技術,它是一個基于身份的通信系統,被設計用于Dapp之間少量數據通信。Whisper協議運行在以太坊p2p協議框架之上,所有運行Whisper協議的節點(以下簡稱節點...

    Doyle 評論0 收藏0
  • 區塊鏈中的P2P

    摘要:為什么區塊鏈會選擇作為網絡基礎上面介紹的時候說過,他是無中心服務器的,中心服務器就意味著,當受到攻擊的時候,中心服務器一旦宕機,整個網絡和服務就會出現問題。區塊鏈的核心是去中心化,這和網絡的觀念不約而同,所以選擇的理由也就很充分。 區塊鏈中P2P介紹 p2p是什么 為什么區塊鏈需要P2P 比特幣、以太坊、超級賬本和EOS的P2P對比 P2P是什么 P2P作為區塊鏈網絡中去中心化...

    jkyin 評論0 收藏0
  • 區塊鏈技術學習指引

    摘要:引言給迷失在如何學習區塊鏈技術的同學一個指引,區塊鏈技術是隨比特幣誕生,因此要搞明白區塊鏈技術,應該先了解下比特幣。但區塊鏈技術不單應用于比特幣,還有非常多的現實應用場景,想做區塊鏈應用開發,可進一步閱讀以太坊系列。 本文始發于深入淺出區塊鏈社區, 原文:區塊鏈技術學習指引 原文已更新,請讀者前往原文閱讀 本章的文章越來越多,本文是一個索引帖,方便找到自己感興趣的文章,你也可以使用左側...

    Cristic 評論0 收藏0
  • 基于以太的視頻直播平臺 Livepeer白皮書中文概覽

    摘要:說明的視頻片段分發現在沒做出什么成果作者還提了一句,協議有望成為直播內容的傳播協議。仿佛也沒能掩飾住不知道怎么分發視頻片段的尷尬說了這么多,看了代碼發現視頻片段還是通過分發總結最終將建立一個可擴展的,即用即付的直播網絡 Background Livepeer旨在構建帶有激勵機制的視頻直播分布式網絡 Blockchain 以太坊 智能合約和交易基于Ethereum以太坊網絡 DP...

    Eric 評論0 收藏0

發表評論

0條評論

xcc3641

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<