以太坊原理解析

[以太坊源码分析][p2p网络04]:基于UDP的节点发现

2019-02-03  本文已影响0人  jea的笔记本

为什么要进行节点发现呢?

因为要加入一个p2p网络,并且与网络中的节点交互,需要知道这个p2p网络中的一些节点信息。节点发现,使本地节点得知其他节点的信息,进而加入到p2p网络中。节点发现就是一个寻找邻居节点的过程。

这里有一点跟去中心化违背的地方,就是节点第一次启动的时候,节点会与硬编码在以太坊源码中的bootnode进行连接,这个bootnode有一种中心化服务器的感觉,因为所有的节点加入几乎都先连接了它。然而,只有一个可以通信的节点,明显是不足够的。连接上bootnode后,获取bootnode部分的邻居节点,然后进行节点发现,获取更多的活跃的邻居节点。

以太坊的节点发现

Kademlia - wiki
kademlia
以太坊的节点发现基于类似的kademlia算法,源码中有两个版本,v4和v5。v4适用于全节点,通过discover.ListenUDP使用,v5适用于轻节点通过discv5.ListenUDP使用,这里主要介绍v4版本,较为简单的版本。

接下来是以太坊节点发现v4的源码分析部分,分为udp发现k桶刷新

0.索引

01.p2p服务开启节点发现
02.udp节点发现
03.k桶刷新

1.p2p服务开启节点发现

p2p.server.go中的Start方法中:

if !srv.NoDiscovery {
    cfg := discover.Config{
        PrivateKey:   srv.PrivateKey,
        AnnounceAddr: realaddr,
        NodeDBPath:   srv.NodeDatabase,
        NetRestrict:  srv.NetRestrict,
        Bootnodes:    srv.BootstrapNodes,
        Unhandled:    unhandled,
    }
    ntab, err := discover.ListenUDP(conn, cfg)
    if err != nil {
        return err
    }
    srv.ntab = ntab
}

2.udp节点发现

新建一个udp对象

首先要从newUDP方法看起,newUDP方法如下:

func newUDP(c conn, cfg Config) (*Table, *udp, error)
udp

源码中三个主要的过程:

udp消息有4种:

节点发现的过程

(假设节点A要进行节点发现,向节点B进行查询)

其中,节点B启动了loopreadloop两个单独的协程来处理节点A发送来的消息。

3.k桶刷新

以太坊的k桶设置:
alpha为3
nBuckets,k桶数量为17
bucketSize,k桶中最多存16个节点
maxReplacements,每个k桶的候选节点列表最多存10个节点

新建一个Table对象

newTable方法如下:

func newTable(t transport, self *enode.Node, db *enode.DB, bootnodes []*enode.Node)(*Table, error)
Table

主要介绍三个方法:

k桶刷新的过程

也就是go tab.loop()协程具体做了什么,如下:

loop
主要介绍三个协程:

4.总结

上一篇下一篇

猜你喜欢

热点阅读