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的介绍.

    // NetworkStack is used to retrieve network info and send messages
    type NetworkStack interface {
      Communicator
      Inquirer
    }
  • 作为consensus/pbft.communicator接口的一部分. 该接口定义在consensus/pbft/broadcast.go.

    type communicator interface {
      consensus.Communicator
      consensus.Inquirer
    }

    可以看到, 事实上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

type Communicator interface {
    Broadcast(msg *pb.Message, peerType pb.PeerEndpoint_Type) error
    Unicast(msg *pb.Message, receiverHandle *pb.PeerID) error
}

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

Usage

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

    // NetworkStack is used to retrieve network info and send messages
    type NetworkStack interface {
      Communicator
      Inquirer
    }
  • 作为consensus/pbft.communicator接口的一部分. 该接口定义在consensus/pbft/broadcast.go.

    type communicator interface {
      consensus.Communicator
      consensus.Inquirer
    }

    虽然此处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

type NetworkStack interface {
    Communicator
    Inquirer
}

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

Usage

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

Implement

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

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

engine.helper = NewHelper(coord)

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

// Helper contains the reference to the peer's MessageHandlerCoordinator
type Helper struct {
    consenter    consensus.Consenter
    coordinator  peer.MessageHandlerCoordinator
    secOn        bool
    valid        bool // Whether we believe the state is up to date
    secHelper    crypto.Peer
    curBatch     []*pb.Transaction       // TODO, remove after issue 579
    curBatchErrs []*pb.TransactionResult // TODO, remove after issue 579
    persist.Helper

    executor consensus.Executor
}

对于func GetNetworkInfo():

// GetNetworkInfo returns the PeerEndpoints of the current validator and the entire validating network
func (h *Helper) GetNetworkInfo() (self *pb.PeerEndpoint, network []*pb.PeerEndpoint, err error) {
    ep, err := h.coordinator.GetPeerEndpoint()
    if err != nil {
        return self, network, fmt.Errorf("Couldn't retrieve own endpoint: %v", err)
    }
    self = ep

    peersMsg, err := h.coordinator.GetPeers()
    if err != nil {
        return self, network, fmt.Errorf("Couldn't retrieve list of peers: %v", err)
    }
    peers := peersMsg.GetPeers()
    for _, endpoint := range peers {
        if endpoint.Type == pb.PeerEndpoint_VALIDATOR {
            network = append(network, endpoint)
        }
    }
    network = append(network, self)

    return
}

可以看到其实是通过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?