1. 程式人生 > >以太坊原始碼P2P網路及節點發現機制

以太坊原始碼P2P網路及節點發現機制

http://www.cnblogs.com/blockchain/p/7943962.html

目錄

1 分散式網路介紹

1.1 Kad網介紹

1.2 Kad網路節點距離

1.3 K桶

1.4 Kad通訊協議

2 鄰居節點

2.1 NodeTable類主要成員

2.2 鄰居節點發現方法

2.3 鄰居節點網路拓撲及重新整理機制。

1 分散式網路介紹

以太坊底層分散式網路即P2P網路,使用了經典的Kademlia網路,簡稱kad。


1.1 Kad網介紹

Kademlia在2002年由美國紐約大學的PetarP.Manmounkov和DavidMazieres提出,是一種分散式散列表(DHT)技術,以異或運算為距離度量基礎,已經在BitTorrent、BitComet、Emule等軟體中得到應用。

1.2 Kad網路節點距離               

以太坊網路節點距離計算方法:

  • Node1:節點1 NodeId

  • Node2:節點2 NodeId

1.3 K桶

Kad的路由表是通過稱為K桶的資料構造而成,K桶記錄了節點NodeId,distance,endpoint,ip等資訊。以太坊K桶按照與target節點距離進行排序,共256個K桶,每個K桶包含16個節點。

圖1.1

1.4 Kad通訊協議

    以太坊Kad網路中節點間通訊基於UDP,主要由以下幾個命令構成,若兩個節點間PING-PONG握手通過,則認為相應節點線上。

Kad通訊協議,基於UDP

序號

分類

功能描述

構成

1

PING

探測一個節點,判斷其是否線上

struct PingNode

{

         h256  version = 0x3;

         Endpoint  from;

         Endpoint  to;

         uint32_t  timestamp;

};

2

PONG

PING命令響應

struct Pong
{
                       Endpoint to;
                       h256 echo;
                       uint32_t timestamp;
};

3

FINDNODE

向節點查詢某個與目標節點ID距離接近的節點

struct FindNeighbours
{
                       NodeId target;                 uint32_t timestamp;
};

4

NEIGHBORS

FIND_NODE命令響應,傳送與目標節點ID距離接近的K桶中的節點

struct Neighbours
{
                       list nodes: struct Neighbour
                       {
                                    inline Endpoint endpoint;
                                      NodeId node;
                       };
                       uint32_t timestamp;
};

2 鄰居節點

2.1 NodeTable類主要成員

C++版本以太坊原始碼中,NodeTable是以太坊 P2P網路的關鍵類,所有與鄰居節點相關的資料和方法均由NodeTable類實現。

序號

成員名稱

說明

備註

1

m_node

本節點,包含NodeId、endpoint、ip等

2

m_state

K桶,包含鄰居節點的NodeId、distance、endpoint、ip

3

m_nodes

已知的節點資訊,但並沒有加入到K桶

序號

函式名

路徑

功能

1

NodeTable::NodeTable(ba::io_service&  _io, KeyPair const& _alias, NodeIPEndpoint const& _endpoint, bool  _enabled)

cpp-ethereum

/libp2p/NodeTable.cpp

NodeTable類建構函式,初始化K桶,發起鄰居節點發現過程

2

void  NodeTable::doDiscovery()

Cpp-ethereum

/libp2p/NodeTable.cpp

具體發現函式

3

shared_ptr<NodeEntry>  NodeTable::addNode(Node const& _node, NodeRelation _relation)

cpp-ethereum

/libp2p/NodeTable.cpp

將節點加入m_nodes,併發起ping握手

4

void  NodeTable::doDiscover(NodeID _node, unsigned _round,  shared_ptr<set<shared_ptr<NodeEntry>>> _tried)

cpp-ethereum

/libp2p/NodeTable.cpp

底層發現函式,從k桶中選出節點,傳送FINDNODE命令

5

vector<shared_ptr<NodeEntry>>  NodeTable::nearestNodeEntries(NodeID _target)

cpp-ethereum

/libp2p/NodeTable.cpp

從K桶中選出節點

6

void  NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from,  bytesConstRef _packet)

cpp-ethereum

/libp2p/NodeTable.cpp

Kad協議處理

7

void  NodeTable::noteActiveNode(Public const& _pubk, bi::udp::endpoint  const& _endpoint)

cpp-ethereum

/libp2p/NodeTable.cpp

將新節點加入到K桶

2.2 鄰居節點發現方法

     鄰居節點是指加入到K桶,並通過PING-PONG握手的節點。

圖2.1

鄰居節點發現流程說明:

  1. 系統第一次啟動隨機生成本機節點NodeId,記為LocalId,生成後將固定不變,本地節點記為local-eth。

  2. 系統讀取公共節點資訊,ping-pong握手完成後,將其寫入K桶。

  3. 系統每隔7200ms重新整理一次K桶。

  4. 重新整理K桶流程如下:

a.      隨機生成目標節點Id,記為TargetId,從1開始記錄發現次數和重新整理時間。

b.      計算TargetId與LocalId的距離,記為Dlt

c.      K桶中節點的NodeId記為KadId,計算KadId與TargetId的距離,記為Dkt

d.      找出K桶中Dlt大於Dkt的節點,記為k桶節點,向k桶節點發送FindNODE命令,FindNODE命令包含TargetId

e.      K桶節點收到FindNODE命令後,同樣執行b-d的過程,將從K桶中找到的節點使用Neighbours命令發回給本機節點。

f.       本機節點收到Neighbours後,將收到的節點寫入到K桶中。

g.      若搜尋次數不超過8次,重新整理時間不超過600ms,則返回到b步驟迴圈執行。

2.3 鄰居節點網路拓撲及重新整理機制。

圖2.2

1 TargetId為隨機生成的虛擬節點ID。

2 以太坊Kad網路與傳統Kad網路的區別:

  1. 以太坊節點在發現鄰居節點的8次迴圈中,所查詢的節點均在距離上向隨機生成的TargetId收斂。

  2. 傳統Kad網路發現節點時,在距離上向節點本身收斂。

本文由HPB(芯鏈)團隊整理。