写点什么

简述以太坊 P2P 网络之 UDP

作者:devpoint
  • 2021 年 11 月 25 日
  • 本文字数:1126 字

    阅读完需:约 4 分钟

简述以太坊P2P网络之UDP

个人认为以太坊是区块链项目中带来技术重新认识和学习的不错的项目,特别是在 P2P 网络这一块。本文将介绍 P2P 网络中负责节点之间的通信连接和服务发现,本文的内容主要是对代码层级的理解,可能存在对其理解的错误,欢迎指点。包括以下两个方面:


  • 种子节点初始化,节点发现

  • 节点连接及相互通信

pending一种延迟处理逻辑,提供一个回调机制

  • 当某一个操作发起异步请求时,就使用pending结构封装一个闭包,当收到异步回复后从 pending 列表取出这个闭包,执行回调,因此在这个回调里可以完成数据包校验等后处理,如 findnode 操作将更新 k 桶的操作暂存,再获取到异步回复后执行这个闭包完成 k 桶更新

  • 提供多个回复接收功能,一个 RPC 请求可能会对应多个回复包,比如 findnode 对应多个 neigbours 回复包,此时可以提供多个pending进行逐个包校验

种子节点初始化及节点发现

这部分的逻辑的实现主要在p2p/discover/table.go中,在 udp 中newUDP方法调用newTable开始种子节点及节点的发现。


  • newTable:执行该函数会传入Bootnodes信息,配置信息在params/bootnodes.go中,为初始连接节点,服务启动后就从这些节点开始进行节点的发现和扩散。关键执行方法

  • tab.setFallbackNodes:验证bootnodes信息,将节点信息赋值给tab.nursery

  • tab.seedRand:设置随机seed

  • tab.loadSeedNodes:将bootnodes加入路由表

  • tab.loop:创建goroutine发现节点并进行连接

  • tab.doRefresh:创建goroutine刷新所有节点(30 分钟),并进行连接

  • tab.lookup:查找距离自己最近的节点

  • tab.closest:获取距离target最近的16个节点

  • tab.findnode:向最近的节点发起findnode请求,并增加处理neighborsPacket闭包的pending,具体实现为udp.go中的findnode,对于超过 24 小时没有接收到ping包的节点重新发送ping;对端节点接收到findnode请求后,查找附近的 16 个节点,并发送neighborsPacket


--


  • findnode-neighbors 时序图


由于 UDP 有最大报文数限制,所以能够发送的邻近节点数目是有限的,需要拆包发送



节点连接及相互通信

P2P 服务的启动位于p2p/server.go 中的Start()


建立一个 UDP 连接服务discover.ListenUDP这个方法的关键实现是初始化三个通道,2 个goroutine


  • 三个通道

  • closing:关闭 udp

  • gotreply:消息回复

  • addpendingpending消息处理

  • 2 个 goroutine

  • udp.loop():主要监听t.gotreplyt.addpending

  • t.addpending:接收并增加一个闭包

  • t.gotreply:接收回复遍历,执行callback通知errC通道

  • udp.readLoop():读取 UDP 数据包,执行t.handlePacket进行数据包处理

  • t.handlePacket:执行decodePacket对数据包进行解码,然后调用相应数据包的handle方法

网络传输四种数据包
  • 数据包类型


const (  pingPacket = iota + 1 // zero is 'reserved'  pongPacket  findnodePacket  neighborsPacket)
复制代码


  • 数据包结构



  • ping-pong 时序图



发布于: 23 小时前阅读数: 7
用户头像

devpoint

关注

细节的追求者 2011.11.12 加入

专注前端开发,用技术创造价值!

评论

发布
暂无评论
简述以太坊P2P网络之UDP