[eos21]协议-网络协议-part2
2.3.2 dispatch manager(调度管理器)
Dispatch Manager维护节点接收到的块和交易的状态。
状态包含识别块或交易的基本信息,在块状态和交易状态列表中维护:
块状态列表:节点为接收到的所有块管理的块状态列表。
交易状态列表:节点管理的所有接收交易的交易状态列表。
这使得快速定位某个节点是否有给定的块和交易成为可能。
从概念来看,这就是维护所有收到的块的节点,不知道为啥叫调度管理器,而不是状态管理器?
解答:通读全文后,能基本知道答案了。因为可以根据块和交易的状态列表,才能决定从哪些节点获取相应的块数据。因此叫做调度。
题外话:再一次证明这种“低效”的阅读方式的好处,就是印象深刻,有备份,能前呼后应。
2.3.2.1 block state

块状态标识块自身信息和块所来自的节点信息。have_block应该表示自己是否有这个块的完整信息。
2.3.2.2 交易状态

其中,block_num表示当这个交易被收到时候,当前节点的head block num。如果lib追上hb,那么,这个交易就会被抛弃。
用于定时清理自己收到的交易。
除此之外,交易还会通过过期时间被移除。
2.3.2.3 状态回收
随着lib不断向前推进,在lib之前的所有块都被认为是不可逆状态的。因此这些块的状态会从块状态列表中清除。
类似,交易状态也会根据过期时间从交易状态列表中移除。
块和交易状态数量级比较轻,状态会不断变化,因此是在内存中维护的。
但是,块的实际完整数据被临时存储在Fork DB中,交易的完整数据存储在各种为应用交易(applied)或非应用交易(unapplied)的队列中。
2.3.3 连接列表
连接列表包括每个节点的连接状态。
维护p2p协议版本,块和交易的状态,上一次握手信息,node id等信息。
连接状态包含以下信息:
Info requested: 其他节点是否向自己请求信息
Socket state: tcp 连接状态
Node ID: 节点的身份id
Last Handshake Received: 从其他节点收到的上次握手信息
Last Handshake Sent: 发给对方的上次握手信息
Handshake Sent Count: 发给对方的握手信息次数
Syncing: 是否正在和其他节点同步
Protocol Version: net plugin的网络协议版本
2.4 net serializer
net serializer有两个主要作用:
序列化要做网络传输的对象和消息
序列化需要做加密哈希的对象和消息
第一种情况,对端需要做反序列化。
第二种情况,需要序列化对象实例中的特定字段来生成其内容的加密哈希。
为特定对象类型(操作、交易、块等)生成的大多数id都包含来自对象实例的相关字段的加密散列。
3 操作模式
从操作角度来说,相对于其他节点,自身节点处于以下三种状态:
in-sync 模式:没有需要同步的块,和其他节点保持信息一致
lib catch-up模式:节点要求lib块,因为lib块落后于其他节点
hb catch-up模式:节点要求hb块,因为hb块落后于其他节点
如前文所说,操作模式存储在sync manager中,sync manager是net plugin中的四个模块之一。
随着不断同步信息,节点会不断在追赶模式和同步模式之间切换。
3.1 块ID
块ID是一个块的唯一标识。块ID依赖于块头和块号。即blockid=func(head,blocknum)。
eosio通过块id区分两个块是否一样,这在和其他节点同步块是非常重要。
块头包含交易和操作的merkle tree的root hash,因此,可以认为块id依赖其所有的交易和操作。
块id的前32位其实就是块号。这很容易看出来。如下图:

其中,块号110118560的16进制就是69046a0。
3.2 in-sync模式
在该模式下,节点的hb(head block)与其他节点的hb一致,这意味着节点状态一样。
当节点处于该模式时,它不会向其他节点请求更多的块,而是继续执行其他功能:
验证交易,如果无效则将其删除;如果有效,将它们转发给其他对等点。
验证块,如果数据块无效则将其删除;如果有效,且收到对等节点的请求,将它们转发给其他对等点。
因此,这种模式用带宽交换延迟,这对于验证依赖于TaPoS(transaction as proof of stake)的交易特别有用,因为处理开销更低。
注意,如果交易有效且未过期,总是会被转发。而,块只有在有效且被对等节点请求时才会被转发。
这减少了网络开销。
3.3 catch-up模式
如果hb落后于对等节点的hb或者lib,则处于catch-up模式。
会执行以下两个步骤:
将节点的lib从最近的公共祖先+ 1同步到对等节点的lib。
将节点的hb从最近的共同祖先+ 1同步到对等节点的hb。
因此,先更新节点的LIB,然后更新节点的hb。
3.3.1 lib catch-up模式
如下图所示:

节点从对等节点同步块,将91和92(lib)追加到自己的块90之后。
注意:节点将自己的91n,92n,93n组成的临时分支抛弃掉。因为对端节点的92和自己的92n并不一样,不是一个分支,92已经是lib,所以就要舍弃自己本地分支。同步之后,节点上的lib和hb是同一个节点。
3.3.2 head catch-up模式
如下图:

流程:拿到对端的hb信息(此处应该只是块的元信息,而不是完整信息),然后从自己的hb和对端的hb往前回溯,回溯到最近的一个公共节点,上例中是93,93n和93p是同一个块。
根据最长链原则,95p变成了hb。
3.3.3 块获取(block retrieval)
在共同的祖先被找到之后,一个同步请求信息(sync request message)就会被发给对端节点,以获取需要的块信息。请求信息会指定起止块号。
为了有效利用带宽,会从不同的节点获取需要的块信息,而不仅仅是一个节点。之所以能做到这一点,就是因为dispatch manager中的块和交易状态列表。块状态信息中有这个块被哪些节点维护。
3.4 模式切换
节点和对端节点都会受到新的块,将块推送的自己的local chain中。
依赖于哪个链先长,会发生下列之一的情况:
节点发送catch-up请求信息给对端节点,包括自己的hb信息
节点发送catch-up通知信息,以通知对端节点需要同步信息
第一种情况下,节点从in-sync切换到catch-up模式。
第二种情况下,在收到通知信息之后,节点切换到catch-up模式。
实际情况下,in-sync模式是很短暂的。在一个忙碌的eosio区块链中,节点大部分时间处于catchup模式,用来验证交易和同步块信息。