Section2.3.2 network

Inquirer

Inquirer is used to retrieve info about the validating network

type Inquirer interface {
    GetNetworkInfo() (self *pb.PeerEndpoint, network []*pb.PeerEndpoint, err error)
    GetNetworkHandles() (self *pb.PeerID, network []*pb.PeerID, err error)
}

Inquirer用来获取网络信息. 会返回整个网络上的节点信息. 第一个函数返回PeerEndpoint包含了节点的物理位置和PeerID等, 而第二个函数则仅仅返回PeerID. 两种结构是定义在protos/fabric.pb.go中的. PeerEndpoint.Address是由ip和端口组成的字符串.

type PeerID struct {
    Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
}
...
type PeerEndpoint struct {
    ID      *PeerID           `protobuf:"bytes,1,opt,name=ID,json=iD" json:"ID,omitempty"`
    Address string            `protobuf:"bytes,2,opt,name=address" json:"address,omitempty"`
    Type    PeerEndpoint_Type `protobuf:"varint,3,opt,name=type,enum=protos.PeerEndpoint_Type" json:"type,omitempty"`
    PkiID   []byte            `protobuf:"bytes,4,opt,name=pkiID,proto3" json:"pkiID,omitempty"`
}

Usage

  • 作为consensus.NetworkStack接口的一部分. 具体见下文对NetworkStack的介绍.

  • 作为consensus/pbft.communicator接口的一部分. 该接口定义在consensus/pbft/broadcast.go.

    可以看到, 事实上communicatorNetworkStack其实是完全一样的接口, 只不过communicator定义在pbft内部, 仅限pbft内部使用. communicator是作为pbft.broadcaster的成员变量来使用的, 但事实上, broadcaster仅使用了communicator的单播函数, 而这一部分是由consensus.Communicator定义的(pbft内部根据0~n-1的序号标记外部节点, 所以不需要Inquirer). 故而, consensus.Inquirer在此处其实并没有用处. 完全可以删除. 所以, 实质上, Inquirer也是只作为NetworkStack的一部分被用到.

Implement

Inquirer的引用情况可以看出, Inquirer的引用都是通过NetworkStack实现功能的. 所以具体实现也是通过NetworkStack. 将在下面描述.

Summary

Inquirer虽然有两处引用, 但是在communicator中, Inquirer部分完全没有被用到, 所以其实它只作为NetworkStack的一部分被实际用到了. 该接口其实也是完全可以并到NetworkStack中, 单列只是为了区别功能.

Communicator

Communicator is used to send messages to other validators

顾名思义, 该接口定义了广播和单播的函数用于发送消息. 注意到这里的参数, 这里的receiverHandle等都是peer层的, 不是pbft层使用的节点标记, 因此该接口不会直接被pbft内部使用.

Usage

  • 作为consensus.NetworkStack接口的一部分. 具体见下文对NetworkStack的介绍.

  • 作为consensus/pbft.communicator接口的一部分. 该接口定义在consensus/pbft/broadcast.go.

    虽然此处communicator是由两个接口合并定义的, 但是, 正如前文所述, 这里面并没有使用Inquirer. 所以可以认为pbft内定义的communicator就是consensus.Communicator. communicator作为broadcaster的成员变量被使用. 由于pbft使用的节点标记就是一个数字, broadcaster内通过调用func getValidatorHandle()获得网络层的handle, 然后通过communicator内的函数发送消息.

    (对于fabric来说, 其pbft层的handle和网络层的对应很简单, 只是通过字符串操作来并加上前缀就能把pbft层的数字转化成网络层的handle)

Implement

同样, 对于Usage#1的实现, 将会在下面NetworkStack中进行描述. 对于Usage#2, 可以追溯到是在obcBatch初始化是赋给pbft的, 可以看到, 实际上是把一个consensus.Stack接口的数据当作consensus.Communicator中交给pbft. Stack是在consensus中定义的一个包括了NetworkStack的接口, 实际实现的数据类型为helper.Helper. 这里我们不会也不马上描述Helper对接口的实现, 但也等到下面介绍Stack再一块介绍. 而是选择在下一部分NetworkStack介绍完网络部分的接口.

Summary

该接口主要负责向节点分发消息, 节点handle是采用的网络层的handle, 该接口单独使用只有一处, 是在pbft内, 经过pbft内节点handle向网络层的handle转化后, 该接口会根据handle向网络层发送消息. 虽然这里只是单独使用Communicator, 在程序中却是直接用最高级的接口Stack来初始化, Stack包括了NetworkStack也就当然包括Communicator, 因此我们在NetworkStack中再讨论其实现.

NetworkStack

NetworkStack is used to retrieve network info and send messages

NetworkStack只是前面两个接口的综合.

Usage

NetworkStack没有被直接使用的地方, 只是在作为Stack的一部分被使用. 所以对于其使用情况, 将会在Stack的描述中涉及.

Implement

由于外部没有对NetworkStack接口的单独使用, 也就没有了任何结构体特意去实现NetworkStack. 所以我们这里将会讨论Stack接口里对于NetworkStack部分的实现.

对于Stack, 我们可以追溯到它是由Helper来实现的. Helper是在Engine初始化过程中初始化的:

其结构体定义在fabric/consensus/helper/helper.go.

对于func GetNetworkInfo():

可以看到其实是通过Helper的成员变量coordinator来获得自身的节点信息和网络信息, 解析后返回结果. func GetNetworkHandles()是依赖func GetNetworkInfo()的, 内部是通过先调用func GetNetworkInfo()然后把结果进行处理后返回, 而对于func Broadcast()func Unicast()则是直接调用的coordinator的对应函数. 因此, Helper其实是对coordinator的一个封装.

coordinator是定义在core/peer/peer.go中的MessageHandlerCoordinator, 已经属于peer层内部, 其内部机制不再深究.

Summary

NetworkStack只是作为Stack的一部分被使用, 并没有单独实现NetworkStack接口的结构体. 对于Stack, 由Helper来实现, HelperNetworkStack部分的实现是依赖于core/peer中定义的MessageHandlerCoordinator. 该参数在程序启动时会初始化.

Last updated

Was this helpful?