以太坊源碼(01):P2P網絡及節點發現機制


目錄

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(芯鏈)團隊整理。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM