Fabric 1.0原始碼分析(15)gossip(流言演算法)

尹成發表於2018-05-20
# Fabric 1.0原始碼筆記 之 gossip(流言演算法)

## 1、gossip概述

gossip,翻譯為流言蜚語,即為一種可最終達到一致的演算法。最終一致的另外的含義就是,不保證同時達到一致。
gossip中有三種基本的操作:
* push - A節點將資料(key,value,version)及對應的版本號推送給B節點,B節點更新A中比自己新的資料
* pull - A僅將資料key,version推送給B,B將本地比A新的資料(Key,value,version)推送給A,A更新本地
* push/pull - 與pull類似,只是多了一步,A再將本地比B新的資料推送給B,B更新本地

gossip在Fabric中作用:
* 管理組織內節點和通道資訊,並加測節點是否線上或離線。
* 廣播資料,使組織內相同channel的節點同步相同資料。
* 管理新加入的節點,並同步資料到新節點。

gossip程式碼,分佈在gossip、peer/gossip目錄下,目錄結構如下:

* gossip目錄:
    * service目錄,GossipService介面定義及實現。
    * integration目錄,NewGossipComponent工具函式。
    * gossip目錄,Gossip介面定義及實現。
    * comm目錄,GossipServer介面實現。
    * state目錄,GossipStateProvider介面定義及實現(狀態複製)。
    * api目錄:訊息加密服務介面定義。
        * crypto.go,MessageCryptoService介面定義。
        * channel.go,SecurityAdvisor介面定義。
* peer/gossip目錄:
    * mcs.go,MessageCryptoService介面實現,即mspMessageCryptoService結構體及方法。
    * sa.go,SecurityAdvisor介面實現,即mspSecurityAdvisor結構體及方法。
    
GossipServer更詳細內容,參考:[Fabric 1.0原始碼筆記 之 gossip(流言演算法) #GossipServer(Gossip服務端)](GossipServer.md)

## 2、GossipService介面定義及實現

### 2.1、GossipService介面定義

```go
type GossipService interface {
    gossip.Gossip
    NewConfigEventer() ConfigProcessor
    InitializeChannel(chainID string, committer committer.Committer, endpoints []string)
    GetBlock(chainID string, index uint64) *common.Block
    AddPayload(chainID string, payload *proto.Payload) error
}
//程式碼在gossip/service/gossip_service.go
```

補充gossip.Gossip:

```go
type Gossip interface {
    Send(msg *proto.GossipMessage, peers ...*comm.RemotePeer)
    Peers() []discovery.NetworkMember
    PeersOfChannel(common.ChainID) []discovery.NetworkMember
    UpdateMetadata(metadata []byte)
    UpdateChannelMetadata(metadata []byte, chainID common.ChainID)
    Gossip(msg *proto.GossipMessage)
    Accept(acceptor common.MessageAcceptor, passThrough bool) (<-chan *proto.GossipMessage, <-chan proto.ReceivedMessage)
    JoinChan(joinMsg api.JoinChannelMessage, chainID common.ChainID)
    SuspectPeers(s api.PeerSuspector)
    Stop()
}
//程式碼在gossip/gossip/gossip.go
```

### 2.2、GossipService介面實現

GossipService介面實現,即gossipServiceImpl結構體及方法。

```go
type gossipSvc gossip.Gossip

type gossipServiceImpl struct {
    gossipSvc
    chains map[string]state.GossipStateProvider //鏈
    leaderElection map[string]election.LeaderElectionService //選舉服務
    deliveryService deliverclient.DeliverService
    deliveryFactory DeliveryServiceFactory
    lock sync.RWMutex
    idMapper identity.Mapper
    mcs api.MessageCryptoService
    peerIdentity []byte
    secAdv api.SecurityAdvisor
}

//初始化Gossip Service,調取InitGossipServiceCustomDeliveryFactory()
func InitGossipService(peerIdentity []byte, endpoint string, s *grpc.Server, mcs api.MessageCryptoService,secAdv api.SecurityAdvisor, secureDialOpts api.PeerSecureDialOpts, bootPeers ...string) error
//初始化Gossip Service
func InitGossipServiceCustomDeliveryFactory(peerIdentity []byte, endpoint string, s *grpc.Server,factory DeliveryServiceFactory, mcs api.MessageCryptoService, secAdv api.SecurityAdvisor,secureDialOpts api.PeerSecureDialOpts, bootPeers ...string) error
//獲取gossipServiceInstance
func GetGossipService() GossipService
//調取 newConfigEventer(g)
func (g *gossipServiceImpl) NewConfigEventer() ConfigProcessor
//初始化通道
func (g *gossipServiceImpl) InitializeChannel(chainID string, committer committer.Committer, endpoints []string)
func (g *gossipServiceImpl) configUpdated(config Config)
func (g *gossipServiceImpl) GetBlock(chainID string, index uint64) *common.Block
func (g *gossipServiceImpl) AddPayload(chainID string, payload *proto.Payload) error
//停止gossip服務
func (g *gossipServiceImpl) Stop()
func (g *gossipServiceImpl) newLeaderElectionComponent(chainID string, callback func(bool)) election.LeaderElectionService
func (g *gossipServiceImpl) amIinChannel(myOrg string, config Config) bool
func (g *gossipServiceImpl) onStatusChangeFactory(chainID string, committer blocksprovider.LedgerInfo) func(bool)
func orgListFromConfig(config Config) []string
//程式碼在gossip/service/gossip_service.go
```

#### 2.2.1、func InitGossipService(peerIdentity []byte, endpoint string, s *grpc.Server, mcs api.MessageCryptoService,secAdv api.SecurityAdvisor, secureDialOpts api.PeerSecureDialOpts, bootPeers ...string) error

```go
func InitGossipService(peerIdentity []byte, endpoint string, s *grpc.Server, mcs api.MessageCryptoService,
    secAdv api.SecurityAdvisor, secureDialOpts api.PeerSecureDialOpts, bootPeers ...string) error {
    util.GetLogger(util.LoggingElectionModule, "")
    return InitGossipServiceCustomDeliveryFactory(peerIdentity, endpoint, s, &deliveryFactoryImpl{},
        mcs, secAdv, secureDialOpts, bootPeers...)
}

func InitGossipServiceCustomDeliveryFactory(peerIdentity []byte, endpoint string, s *grpc.Server,
    factory DeliveryServiceFactory, mcs api.MessageCryptoService, secAdv api.SecurityAdvisor,
    secureDialOpts api.PeerSecureDialOpts, bootPeers ...string) error {
    var err error
    var gossip gossip.Gossip
    once.Do(func() {
        //peer.gossip.endpoint,本節點在組織內的gossip id,或者使用peerEndpoint.Address
        if overrideEndpoint := viper.GetString("peer.gossip.endpoint"); overrideEndpoint != "" {
            endpoint = overrideEndpoint
        }
        idMapper := identity.NewIdentityMapper(mcs, peerIdentity)
        gossip, err = integration.NewGossipComponent(peerIdentity, endpoint, s, secAdv,
            mcs, idMapper, secureDialOpts, bootPeers...)
        gossipServiceInstance = &gossipServiceImpl{
            mcs: mcs,
            gossipSvc: gossip,
            chains: make(map[string]state.GossipStateProvider),
            leaderElection: make(map[string]election.LeaderElectionService),
            deliveryFactory: factory,
            idMapper: idMapper,
            peerIdentity: peerIdentity,
            secAdv: secAdv,
        }
    })
    return err
}

//程式碼在gossip/service/gossip_service.go
```

#### 2.2.2、func (g *gossipServiceImpl) Stop()

```go
func (g *gossipServiceImpl) Stop() {
    g.lock.Lock()
    defer g.lock.Unlock()
    for _, ch := range g.chains {
        logger.Info("Stopping chain", ch)
        ch.Stop()
    }

    for chainID, electionService := range g.leaderElection {
        logger.Infof("Stopping leader election for %s", chainID)
        electionService.Stop()
    }
    g.gossipSvc.Stop()
    if g.deliveryService != nil {
        g.deliveryService.Stop()
    }
}
//程式碼在gossip/service/gossip_service.go
```

#### 2.2.3、func (g *gossipServiceImpl) InitializeChannel(chainID string, committer committer.Committer, endpoints []string)

```go
func (g *gossipServiceImpl) InitializeChannel(chainID string, committer committer.Committer, endpoints []string) {
    g.lock.Lock()
    defer g.lock.Unlock()

    //構造GossipStateProviderImpl,並啟動goroutine處理從orderer或其他節點接收的block
    g.chains[chainID] = state.NewGossipStateProvider(chainID, g, committer, g.mcs)
    if g.deliveryService == nil {
        var err error
        g.deliveryService, err = g.deliveryFactory.Service(gossipServiceInstance, endpoints, g.mcs)
    }
    if g.deliveryService != nil {
        //如下兩者只可以二選一
        leaderElection := viper.GetBool("peer.gossip.useLeaderElection") //是否動態選舉代表節點
        isStaticOrgLeader := viper.GetBool("peer.gossip.orgLeader") //是否指定本節點為組織代表節點

        if leaderElection {
            //選舉代表節點
            g.leaderElection[chainID] = g.newLeaderElectionComponent(chainID, g.onStatusChangeFactory(chainID, committer))
        } else if isStaticOrgLeader {
            //如果指定本節點為代表節點,則啟動Deliver client
            g.deliveryService.StartDeliverForChannel(chainID, committer, func() {})
        }
}

//程式碼在gossip/service/gossip_service.go
```

#### 2.2.4、func (g *gossipServiceImpl) AddPayload(chainID string, payload *proto.Payload) error

```go
func (g *gossipServiceImpl) AddPayload(chainID string, payload *proto.Payload) error {
    g.lock.RLock()
    defer g.lock.RUnlock()
    return g.chains[chainID].AddPayload(payload)
}
//程式碼在gossip/service/gossip_service.go
```

## 3、NewGossipComponent工具函式

```go
func NewGossipComponent(peerIdentity []byte, endpoint string, s *grpc.Server,
    secAdv api.SecurityAdvisor, cryptSvc api.MessageCryptoService, idMapper identity.Mapper,
    secureDialOpts api.PeerSecureDialOpts, bootPeers ...string) (gossip.Gossip, error) {

    //peer.gossip.externalEndpoint為節點被組織外節點感知時的地址
    externalEndpoint := viper.GetString("peer.gossip.externalEndpoint")

    //endpoint,取自peer.address,即節點對外服務的地址
    //bootPeers取自peer.gossip.bootstrap,即啟動節點後所進行gossip連線的初始節點,可為多個
    conf, err := newConfig(endpoint, externalEndpoint, bootPeers...)
    gossipInstance := gossip.NewGossipService(conf, s, secAdv, cryptSvc, idMapper,
        peerIdentity, secureDialOpts)

    return gossipInstance, nil
}

func newConfig(selfEndpoint string, externalEndpoint string, bootPeers ...string) (*gossip.Config, error) {
    _, p, err := net.SplitHostPort(selfEndpoint)
    port, err := strconv.ParseInt(p, 10, 64) //節點對外服務的埠

    var cert *tls.Certificate
    if viper.GetBool("peer.tls.enabled") {
        certTmp, err := tls.LoadX509KeyPair(config.GetPath("peer.tls.cert.file"), config.GetPath("peer.tls.key.file"))
        cert = &certTmp
    }

    return &gossip.Config{
        BindPort: int(port),
        BootstrapPeers: bootPeers,
        ID: selfEndpoint,
        MaxBlockCountToStore: util.GetIntOrDefault("peer.gossip.maxBlockCountToStore", 100),
        MaxPropagationBurstLatency: util.GetDurationOrDefault("peer.gossip.maxPropagationBurstLatency", 10*time.Millisecond),
        MaxPropagationBurstSize: util.GetIntOrDefault("peer.gossip.maxPropagationBurstSize", 10),
        PropagateIterations: util.GetIntOrDefault("peer.gossip.propagateIterations", 1),
        PropagatePeerNum: util.GetIntOrDefault("peer.gossip.propagatePeerNum", 3),
        PullInterval: util.GetDurationOrDefault("peer.gossip.pullInterval", 4*time.Second),
        PullPeerNum: util.GetIntOrDefault("peer.gossip.pullPeerNum", 3),
        InternalEndpoint: selfEndpoint,
        ExternalEndpoint: externalEndpoint,
        PublishCertPeriod: util.GetDurationOrDefault("peer.gossip.publishCertPeriod", 10*time.Second),
        RequestStateInfoInterval: util.GetDurationOrDefault("peer.gossip.requestStateInfoInterval", 4*time.Second),
        PublishStateInfoInterval: util.GetDurationOrDefault("peer.gossip.publishStateInfoInterval", 4*time.Second),
        SkipBlockVerification: viper.GetBool("peer.gossip.skipBlockVerification"),
        TLSServerCert: cert,
    }, nil
}
//程式碼在gossip/integration/integration.go
```

## 4、Gossip介面定義及實現

### 4.1、Gossip介面定義

```go
type Gossip interface {
    //向節點傳送訊息
    Send(msg *proto.GossipMessage, peers ...*comm.RemotePeer)
    //返回活的節點
    Peers() []discovery.NetworkMember
    //返回指定通道的活的節點
    PeersOfChannel(common.ChainID) []discovery.NetworkMember
    //更新metadata
    UpdateMetadata(metadata []byte)
    //更新通道metadata
    UpdateChannelMetadata(metadata []byte, chainID common.ChainID)
    //向網路內其他節點傳送資料
    Gossip(msg *proto.GossipMessage)
    Accept(acceptor common.MessageAcceptor, passThrough bool) (<-chan *proto.GossipMessage, <-chan proto.ReceivedMessage)
    //加入通道
    JoinChan(joinMsg api.JoinChannelMessage, chainID common.ChainID)
    //驗證可疑節點身份,並關閉無效連結
    SuspectPeers(s api.PeerSuspector)
    //停止Gossip服務
    Stop()
}
//程式碼在gossip/gossip/gossip.go
```

### 4.2、Config結構體定義

```go
type Config struct {
    BindPort int //繫結的埠,僅用於測試
    ID string //本例項id,即對外開放的節點地址
    BootstrapPeers []string //啟動時要連結的節點
    PropagateIterations int //取自peer.gossip.propagateIterations,訊息轉發的次數,預設為1
    PropagatePeerNum int //取自peer.gossip.propagatePeerNum,訊息推送給節點的個數,預設為3
    MaxBlockCountToStore int //取自peer.gossip.maxBlockCountToStore,儲存到記憶體中的區塊個數上限,預設100
    MaxPropagationBurstSize int //取自peer.gossip.maxPropagationBurstSize,儲存的最大訊息個數,超過則轉發給其他節點,預設為10
    MaxPropagationBurstLatency time.Duration //取自peer.gossip.maxPropagationBurstLatency,儲存訊息的最大時間,超過則轉發給其他節點,預設為10毫秒

    PullInterval time.Duration //取自peer.gossip.pullInterval,拉取訊息的時間間隔,預設為4秒
    PullPeerNum int //取自peer.gossip.pullPeerNum,從指定個數的節點拉取資訊,預設3個

    SkipBlockVerification bool //取自peer.gossip.skipBlockVerification,是否不對區塊訊息進行校驗,預設false即需校驗
    PublishCertPeriod time.Duration //取自peer.gossip.publishCertPeriod,包括在訊息中的啟動證書的時間,預設10s
    PublishStateInfoInterval time.Duration //取自peer.gossip.publishStateInfoInterval,向其他節點推送狀態資訊的時間間隔,預設4s
    RequestStateInfoInterval time.Duration //取自peer.gossip.requestStateInfoInterval,從其他節點拉取狀態資訊的時間間隔,預設4s
    TLSServerCert *tls.Certificate //本節點TLS 證書

    InternalEndpoint string //本節點在組織內使用的地址
    ExternalEndpoint string //本節點對外部組織公佈的地址
}
//程式碼在gossip/gossip/gossip.go
```

### 4.3、Gossip介面實現

Gossip介面介面實現,即gossipServiceImpl結構體及方法。

#### 4.3.1、gossipServiceImpl結構體及方法

```go
type gossipServiceImpl struct {
    selfIdentity api.PeerIdentityType
    includeIdentityPeriod time.Time
    certStore *certStore
    idMapper identity.Mapper
    presumedDead chan common.PKIidType
    disc discovery.Discovery
    comm comm.Comm
    incTime time.Time
    selfOrg api.OrgIdentityType
    *comm.ChannelDeMultiplexer
    logger *logging.Logger
    stopSignal *sync.WaitGroup
    conf *Config
    toDieChan chan struct{}
    stopFlag int32
    emitter batchingEmitter
    discAdapter *discoveryAdapter
    secAdvisor api.SecurityAdvisor
    chanState *channelState
    disSecAdap *discoverySecurityAdapter
    mcs api.MessageCryptoService
    stateInfoMsgStore msgstore.MessageStore
}

func NewGossipService(conf *Config, s *grpc.Server, secAdvisor api.SecurityAdvisor,
func NewGossipServiceWithServer(conf *Config, secAdvisor api.SecurityAdvisor, mcs api.MessageCryptoService,
func (g *gossipServiceImpl) JoinChan(joinMsg api.JoinChannelMessage, chainID common.ChainID)
func (g *gossipServiceImpl) SuspectPeers(isSuspected api.PeerSuspector)
func (g *gossipServiceImpl) Gossip(msg *proto.GossipMessage)
func (g *gossipServiceImpl) Send(msg *proto.GossipMessage, peers ...*comm.RemotePeer)
func (g *gossipServiceImpl) Peers() []discovery.NetworkMember
func (g *gossipServiceImpl) PeersOfChannel(channel common.ChainID) []discovery.NetworkMember
func (g *gossipServiceImpl) Stop()
func (g *gossipServiceImpl) UpdateMetadata(md []byte)
func (g *gossipServiceImpl) UpdateChannelMetadata(md []byte, chainID common.ChainID)
func (g *gossipServiceImpl) Accept(acceptor common.MessageAcceptor, passThrough bool) (<-chan *proto.GossipMessage, <-chan proto.ReceivedMessage)

func (g *gossipServiceImpl) newStateInfoMsgStore() msgstore.MessageStore
func (g *gossipServiceImpl) selfNetworkMember() discovery.NetworkMember
func newChannelState(g *gossipServiceImpl) *channelState
func createCommWithoutServer(s *grpc.Server, cert *tls.Certificate, idStore identity.Mapper,
func createCommWithServer(port int, idStore identity.Mapper, identity api.PeerIdentityType,
func (g *gossipServiceImpl) toDie() bool
func (g *gossipServiceImpl) periodicalIdentityValidationAndExpiration()
func (g *gossipServiceImpl) periodicalIdentityValidation(suspectFunc api.PeerSuspector, interval time.Duration)
func (g *gossipServiceImpl) learnAnchorPeers(orgOfAnchorPeers api.OrgIdentityType, anchorPeers []api.AnchorPeer)
func (g *gossipServiceImpl) handlePresumedDead()
func (g *gossipServiceImpl) syncDiscovery()
func (g *gossipServiceImpl) start()
func (g *gossipServiceImpl) acceptMessages(incMsgs <-chan proto.ReceivedMessage)
func (g *gossipServiceImpl) handleMessage(m proto.ReceivedMessage)
func (g *gossipServiceImpl) forwardDiscoveryMsg(msg proto.ReceivedMessage)
func (g *gossipServiceImpl) validateMsg(msg proto.ReceivedMessage) bool
func (g *gossipServiceImpl) sendGossipBatch(a []interface{})
func (g *gossipServiceImpl) gossipBatch(msgs []*proto.SignedGossipMessage)
func (g *gossipServiceImpl) sendAndFilterSecrets(msg *proto.SignedGossipMessage, peers ...*comm.RemotePeer)
func (g *gossipServiceImpl) gossipInChan(messages []*proto.SignedGossipMessage, chanRoutingFactory channelRoutingFilterFactory)
func selectOnlyDiscoveryMessages(m interface{}) bool
func (g *gossipServiceImpl) newDiscoverySecurityAdapter() *discoverySecurityAdapter
func (sa *discoverySecurityAdapter) ValidateAliveMsg(m *proto.SignedGossipMessage) bool
func (sa *discoverySecurityAdapter) SignMessage(m *proto.GossipMessage, internalEndpoint string) *proto.Envelope
func (sa *discoverySecurityAdapter) validateAliveMsgSignature(m *proto.SignedGossipMessage, identity api.PeerIdentityType) bool
func (g *gossipServiceImpl) createCertStorePuller() pull.Mediator
func (g *gossipServiceImpl) sameOrgOrOurOrgPullFilter(msg proto.ReceivedMessage) func(string) bool
func (g *gossipServiceImpl) connect2BootstrapPeers()
func (g *gossipServiceImpl) createStateInfoMsg(metadata []byte, chainID common.ChainID) (*proto.SignedGossipMessage, error)
func (g *gossipServiceImpl) hasExternalEndpoint(PKIID common.PKIidType) bool
func (g *gossipServiceImpl) isInMyorg(member discovery.NetworkMember) bool
func (g *gossipServiceImpl) getOrgOfPeer(PKIID common.PKIidType) api.OrgIdentityType
func (g *gossipServiceImpl) validateLeadershipMessage(msg *proto.SignedGossipMessage) error
func (g *gossipServiceImpl) validateStateInfoMsg(msg *proto.SignedGossipMessage) error
func (g *gossipServiceImpl) disclosurePolicy(remotePeer *discovery.NetworkMember) (discovery.Sieve, discovery.EnvelopeFilter)
func (g *gossipServiceImpl) peersByOriginOrgPolicy(peer discovery.NetworkMember) filter.RoutingFilter
func partitionMessages(pred common.MessageAcceptor, a []*proto.SignedGossipMessage) ([]*proto.SignedGossipMessage, []*proto.SignedGossipMessage)
func extractChannels(a []*proto.SignedGossipMessage) []common.ChainID

func (g *gossipServiceImpl) newDiscoveryAdapter() *discoveryAdapter
func (da *discoveryAdapter) close()
func (da *discoveryAdapter) toDie() bool
func (da *discoveryAdapter) Gossip(msg *proto.SignedGossipMessage)
func (da *discoveryAdapter) SendToPeer(peer *discovery.NetworkMember, msg *proto.SignedGossipMessage)
func (da *discoveryAdapter) Ping(peer *discovery.NetworkMember) bool
func (da *discoveryAdapter) Accept() <-chan *proto.SignedGossipMessage
func (da *discoveryAdapter) PresumedDead() <-chan common.PKIidType
func (da *discoveryAdapter) CloseConn(peer *discovery.NetworkMember)
//程式碼在gossip/gossip/gossip_impl.go
```

#### 4.3.2、func NewGossipService(conf *Config, s *grpc.Server, secAdvisor api.SecurityAdvisor,mcs api.MessageCryptoService, idMapper identity.Mapper, selfIdentity api.PeerIdentityType,secureDialOpts api.PeerSecureDialOpts) Gossip

建立附加到grpc.Server上的Gossip例項。

```go
func NewGossipService(conf *Config, s *grpc.Server, secAdvisor api.SecurityAdvisor,
    mcs api.MessageCryptoService, idMapper identity.Mapper, selfIdentity api.PeerIdentityType,
    secureDialOpts api.PeerSecureDialOpts) Gossip {

    var c comm.Comm
    var err error

    lgr := util.GetLogger(util.LoggingGossipModule, conf.ID)
    if s == nil { 建立並啟動gRPC Server,以及註冊GossipServer例項
        c, err = createCommWithServer(conf.BindPort, idMapper, selfIdentity, secureDialOpts)
    } else { //將GossipServer例項註冊至peerServer
        c, err = createCommWithoutServer(s, conf.TLSServerCert, idMapper, selfIdentity, secureDialOpts)
    }

    g := &gossipServiceImpl{
        selfOrg: secAdvisor.OrgByPeerIdentity(selfIdentity),
        secAdvisor: secAdvisor,
        selfIdentity: selfIdentity,
        presumedDead: make(chan common.PKIidType, presumedDeadChanSize),
        idMapper: idMapper,
        disc: nil,
        mcs: mcs,
        comm: c,
        conf: conf,
        ChannelDeMultiplexer: comm.NewChannelDemultiplexer(),
        logger: lgr,
        toDieChan: make(chan struct{}, 1),
        stopFlag: int32(0),
        stopSignal: &sync.WaitGroup{},
        includeIdentityPeriod: time.Now().Add(conf.PublishCertPeriod),
    }
    g.stateInfoMsgStore = g.newStateInfoMsgStore()
    g.chanState = newChannelState(g)
    g.emitter = newBatchingEmitter(conf.PropagateIterations,
        conf.MaxPropagationBurstSize, conf.MaxPropagationBurstLatency,
        g.sendGossipBatch)
    g.discAdapter = g.newDiscoveryAdapter()
    g.disSecAdap = g.newDiscoverySecurityAdapter()
    g.disc = discovery.NewDiscoveryService(g.selfNetworkMember(), g.discAdapter, g.disSecAdap, g.disclosurePolicy)
    g.certStore = newCertStore(g.createCertStorePuller(), idMapper, selfIdentity, mcs)

    go g.start()
    go g.periodicalIdentityValidationAndExpiration()
    go g.connect2BootstrapPeers()
    return g
}
//程式碼在gossip/gossip/gossip_impl.go
```

#### 4.3.3、go g.start()

```go
func (g *gossipServiceImpl) start() {
    go g.syncDiscovery()
    go g.handlePresumedDead()

    msgSelector := func(msg interface{}) bool {
        gMsg, isGossipMsg := msg.(proto.ReceivedMessage)
        if !isGossipMsg {
            return false
        }
        isConn := gMsg.GetGossipMessage().GetConn() != nil
        isEmpty := gMsg.GetGossipMessage().GetEmpty() != nil
        return !(isConn || isEmpty)
    }

    incMsgs := g.comm.Accept(msgSelector)
    go g.acceptMessages(incMsgs)
}
//程式碼在gossip/gossip/gossip_impl.go
```

go g.acceptMessages(incMsgs)程式碼如下:

```go
func (g *gossipServiceImpl) acceptMessages(incMsgs <-chan proto.ReceivedMessage) {
    defer g.logger.Debug("Exiting")
    g.stopSignal.Add(1)
    defer g.stopSignal.Done()
    for {
        select {
        case s := <-g.toDieChan:
            g.toDieChan <- s
            return
        case msg := <-incMsgs:
            g.handleMessage(msg) //此處會調取gc.HandleMessage(m),處理轉發訊息
        }
    }
}
//程式碼在gossip/gossip/gossip_impl.go
```

gc.HandleMessage(m)程式碼如下:

```go
func (gc *gossipChannel) HandleMessage(msg proto.ReceivedMessage) {
    m := msg.GetGossipMessage()
    orgID := gc.GetOrgOfPeer(msg.GetConnectionInfo().ID)
    if m.IsDataMsg() || m.IsStateInfoMsg() {
        added := false

        if m.IsDataMsg() {
            added = gc.blockMsgStore.Add(msg.GetGossipMessage())
        } else {
            added = gc.stateInfoMsgStore.Add(msg.GetGossipMessage())
        }

        if added {
            gc.Gossip(msg.GetGossipMessage()) //轉發給其他節點,最終會呼叫func (g *gossipServiceImpl) gossipBatch(msgs []*proto.SignedGossipMessage)實現批量分發
            gc.DeMultiplex(m)
            if m.IsDataMsg() {
                gc.blocksPuller.Add(msg.GetGossipMessage())
            }
        }
        return
    }
    //...
}
//程式碼在gossip/gossip/channel/channel.go
```

func (g *gossipServiceImpl) gossipBatch(msgs []*proto.SignedGossipMessage)程式碼如下:

```go
func (g *gossipServiceImpl) gossipBatch(msgs []*proto.SignedGossipMessage) {
    var blocks []*proto.SignedGossipMessage
    var stateInfoMsgs []*proto.SignedGossipMessage
    var orgMsgs []*proto.SignedGossipMessage
    var leadershipMsgs []*proto.SignedGossipMessage

    isABlock := func(o interface{}) bool {
        return o.(*proto.SignedGossipMessage).IsDataMsg()
    }
    isAStateInfoMsg := func(o interface{}) bool {
        return o.(*proto.SignedGossipMessage).IsStateInfoMsg()
    }
    isOrgRestricted := func(o interface{}) bool {
        return aliveMsgsWithNoEndpointAndInOurOrg(o) || o.(*proto.SignedGossipMessage).IsOrgRestricted()
    }
    isLeadershipMsg := func(o interface{}) bool {
        return o.(*proto.SignedGossipMessage).IsLeadershipMsg()
    }

    // Gossip blocks
    blocks, msgs = partitionMessages(isABlock, msgs)
    g.gossipInChan(blocks, func(gc channel.GossipChannel) filter.RoutingFilter {
        return filter.CombineRoutingFilters(gc.EligibleForChannel, gc.IsMemberInChan, g.isInMyorg)
    })

    // Gossip Leadership messages
    leadershipMsgs, msgs = partitionMessages(isLeadershipMsg, msgs)
    g.gossipInChan(leadershipMsgs, func(gc channel.GossipChannel) filter.RoutingFilter {
        return filter.CombineRoutingFilters(gc.EligibleForChannel, gc.IsMemberInChan, g.isInMyorg)
    })

    // Gossip StateInfo messages
    stateInfoMsgs, msgs = partitionMessages(isAStateInfoMsg, msgs)
    for _, stateInfMsg := range stateInfoMsgs {
        peerSelector := g.isInMyorg
        gc := g.chanState.lookupChannelForGossipMsg(stateInfMsg.GossipMessage)
        if gc != nil && g.hasExternalEndpoint(stateInfMsg.GossipMessage.GetStateInfo().PkiId) {
            peerSelector = gc.IsMemberInChan
        }

        peers2Send := filter.SelectPeers(g.conf.PropagatePeerNum, g.disc.GetMembership(), peerSelector)
        g.comm.Send(stateInfMsg, peers2Send...)
    }

    // Gossip messages restricted to our org
    orgMsgs, msgs = partitionMessages(isOrgRestricted, msgs)
    peers2Send := filter.SelectPeers(g.conf.PropagatePeerNum, g.disc.GetMembership(), g.isInMyorg)
    for _, msg := range orgMsgs {
        g.comm.Send(msg, peers2Send...)
    }

    // Finally, gossip the remaining messages
    for _, msg := range msgs {
        selectByOriginOrg := g.peersByOriginOrgPolicy(discovery.NetworkMember{PKIid: msg.GetAliveMsg().Membership.PkiId})
        peers2Send := filter.SelectPeers(g.conf.PropagatePeerNum, g.disc.GetMembership(), selectByOriginOrg)
        g.sendAndFilterSecrets(msg, peers2Send...)
    }
}
//程式碼在gossip/gossip/gossip_impl.go
```

## 5、GossipStateProvider介面定義及實現(狀態複製)

### 5.1、GossipStateProvider介面定義

通過狀態複製填充缺少的塊,以及傳送請求從其他節點獲取缺少的塊

```go
type GossipStateProvider interface {
    //按索引獲取塊
    GetBlock(index uint64) *common.Block
    //新增塊
    AddPayload(payload *proto.Payload) error
    //終止狀態複製
    Stop()
}
//程式碼在gossip/state/state.go
```

### 5.2、GossipStateProvider介面實現

```go
type GossipStateProviderImpl struct {
    mcs api.MessageCryptoService //訊息加密服務
    chainID string //Chain id
    gossip GossipAdapter //gossiping service
    gossipChan <-chan *proto.GossipMessage
    commChan <-chan proto.ReceivedMessage
    payloads PayloadsBuffer //Payloads佇列快取
    committer committer.Committer
    stateResponseCh chan proto.ReceivedMessage
    stateRequestCh chan proto.ReceivedMessage
    stopCh chan struct{}
    done sync.WaitGroup
    once sync.Once
    stateTransferActive int32
}

func (s *GossipStateProviderImpl) GetBlock(index uint64) *common.Block
func (s *GossipStateProviderImpl) AddPayload(payload *proto.Payload) error
func (s *GossipStateProviderImpl) Stop()

func NewGossipStateProvider(chainID string, g GossipAdapter, committer committer.Committer, mcs api.MessageCryptoService) GossipStateProvider
func (s *GossipStateProviderImpl) listen()
func (s *GossipStateProviderImpl) directMessage(msg proto.ReceivedMessage)
func (s *GossipStateProviderImpl) processStateRequests()
func (s *GossipStateProviderImpl) handleStateRequest(msg proto.ReceivedMessage)
func (s *GossipStateProviderImpl) handleStateResponse(msg proto.ReceivedMessage) (uint64, error)
func (s *GossipStateProviderImpl) queueNewMessage(msg *proto.GossipMessage)
func (s *GossipStateProviderImpl) deliverPayloads()
func (s *GossipStateProviderImpl) antiEntropy()
func (s *GossipStateProviderImpl) maxAvailableLedgerHeight() uint64
func (s *GossipStateProviderImpl) requestBlocksInRange(start uint64, end uint64)
func (s *GossipStateProviderImpl) stateRequestMessage(beginSeq uint64, endSeq uint64) *proto.GossipMessage
func (s *GossipStateProviderImpl) selectPeerToRequestFrom(height uint64) (*comm.RemotePeer, error)
func (s *GossipStateProviderImpl) filterPeers(predicate func(peer discovery.NetworkMember) bool) []*comm.RemotePeer
func (s *GossipStateProviderImpl) hasRequiredHeight(height uint64) func(peer discovery.NetworkMember) bool
func (s *GossipStateProviderImpl) addPayload(payload *proto.Payload, blockingMode bool) error
func (s *GossipStateProviderImpl) commitBlock(block *common.Block) error

//程式碼在gossip/state/state.go
```

#### 5.2.1、func (s *GossipStateProviderImpl) AddPayload(payload *proto.Payload) error

```go
func (s *GossipStateProviderImpl) AddPayload(payload *proto.Payload) error {
    blockingMode := blocking
    if viper.GetBool("peer.gossip.nonBlockingCommitMode") { //非阻塞提交模式
        blockingMode = false
    }
    return s.addPayload(payload, blockingMode)
}
//程式碼在gossip/state/state.go
```

s.addPayload(payload, blockingMode)程式碼如下:

```go
func (s *GossipStateProviderImpl) addPayload(payload *proto.Payload, blockingMode bool) error {
    height, err := s.committer.LedgerHeight()
    return s.payloads.Push(payload) //加入快取
}
//程式碼在gossip/state/state.go
```

#### 5.2.2、func NewGossipStateProvider(chainID string, g GossipAdapter, committer committer.Committer, mcs api.MessageCryptoService) GossipStateProvider

```go
func NewGossipStateProvider(chainID string, g GossipAdapter, committer committer.Committer, mcs api.MessageCryptoService) GossipStateProvider {
    logger := util.GetLogger(util.LoggingStateModule, "")

    gossipChan, _ := g.Accept(func(message interface{}) bool {
        return message.(*proto.GossipMessage).IsDataMsg() &&
            bytes.Equal(message.(*proto.GossipMessage).Channel, []byte(chainID))
    }, false)

    remoteStateMsgFilter := func(message interface{}) bool {
        receivedMsg := message.(proto.ReceivedMessage)
        msg := receivedMsg.GetGossipMessage()
        connInfo := receivedMsg.GetConnectionInfo()
        authErr := mcs.VerifyByChannel(msg.Channel, connInfo.Identity, connInfo.Auth.Signature, connInfo.Auth.SignedData)
        return true
    }

    _, commChan := g.Accept(remoteStateMsgFilter, true)

    height, err := committer.LedgerHeight()

    s := &GossipStateProviderImpl{
        mcs: mcs,
        chainID: chainID,
        gossip: g,
        gossipChan: gossipChan,
        commChan: commChan,
        payloads: NewPayloadsBuffer(height),
        committer: committer,
        stateResponseCh: make(chan proto.ReceivedMessage, defChannelBufferSize),
        stateRequestCh: make(chan proto.ReceivedMessage, defChannelBufferSize),
        stopCh: make(chan struct{}, 1),
        stateTransferActive: 0,
        once: sync.Once{},
    }

    nodeMetastate := NewNodeMetastate(height - 1)
    b, err := nodeMetastate.Bytes()
    s.done.Add(4)

    go s.listen()
    go s.deliverPayloads() //處理從orderer獲取的塊
    go s.antiEntropy() //處理缺失塊
    go s.processStateRequests() //處理狀態請求訊息
    return s
}
//程式碼在gossip/state/state.go
```

#### 5.2.3、func (s *GossipStateProviderImpl) deliverPayloads()

```go
func (s *GossipStateProviderImpl) deliverPayloads() {
    defer s.done.Done()

    for {
        select {
        case <-s.payloads.Ready():
            for payload := s.payloads.Pop(); payload != nil; payload = s.payloads.Pop() {
                rawBlock := &common.Block{}
                err := pb.Unmarshal(payload.Data, rawBlock)
                err := s.commitBlock(rawBlock)
            }
        case <-s.stopCh:
            s.stopCh <- struct{}{}
            logger.Debug("State provider has been stoped, finishing to push new blocks.")
            return
        }
    }
}

func (s *GossipStateProviderImpl) commitBlock(block *common.Block) error {
    err := s.committer.Commit(block)
    nodeMetastate := NewNodeMetastate(block.Header.Number)
    b, err := nodeMetastate.Bytes()
    return nil
}
//程式碼在gossip/state/state.go
```

#### 5.2.4、func (s *GossipStateProviderImpl) antiEntropy()

定時獲取當前高度和節點中最大高度的差值

```go
func (s *GossipStateProviderImpl) antiEntropy() {
    defer s.done.Done()

    for {
        select {
        case <-s.stopCh:
            s.stopCh <- struct{}{}
            return
        case <-time.After(defAntiEntropyInterval):
            current, err := s.committer.LedgerHeight()
            max := s.maxAvailableLedgerHeight() //最大高度
            s.requestBlocksInRange(uint64(current), uint64(max))
        }
    }
}
//程式碼在gossip/state/state.go
```

s.requestBlocksInRange(uint64(current), uint64(max))程式碼如下:

```go
func (s *GossipStateProviderImpl) requestBlocksInRange(start uint64, end uint64) {
    atomic.StoreInt32(&s.stateTransferActive, 1)
    defer atomic.StoreInt32(&s.stateTransferActive, 0)

    for prev := start; prev <= end; {
        next := min(end, prev+defAntiEntropyBatchSize) //一批最大10個
        gossipMsg := s.stateRequestMessage(prev, next) //構造GossipMessage_StateRequest

        responseReceived := false
        tryCounts := 0

        for !responseReceived {
            peer, err := s.selectPeerToRequestFrom(next) //確定peer
            s.gossip.Send(gossipMsg, peer)
            tryCounts++
            select {
            case msg := <-s.stateResponseCh:
                if msg.GetGossipMessage().Nonce != gossipMsg.Nonce {
                    continue
                }
                index, err := s.handleStateResponse(msg)
                prev = index + 1
                responseReceived = true
            case <-time.After(defAntiEntropyStateResponseTimeout):
            case <-s.stopCh:
                s.stopCh <- struct{}{}
                return
            }
        }
    }
}
//程式碼在gossip/state/state.go
```

index, err := s.handleStateResponse(msg)程式碼如下:

```go
func (s *GossipStateProviderImpl) handleStateResponse(msg proto.ReceivedMessage) (uint64, error) {
    max := uint64(0)
    response := msg.GetGossipMessage().GetStateResponse()
    for _, payload := range response.GetPayloads() {
        err := s.mcs.VerifyBlock(common2.ChainID(s.chainID), payload.SeqNum, payload.Data)
        err := s.addPayload(payload, blocking) //存入本地
    }
    return max, nil
}
//程式碼在gossip/state/state.go
```

committer更詳細內容,參考:[Fabric 1.0原始碼筆記 之 Peer #committer(提交者)](../peer/committer.md)

#### 5.2.5、func (s *GossipStateProviderImpl) listen()

```go
func (s *GossipStateProviderImpl) listen() {
    defer s.done.Done()

    for {
        select {
        case msg := <-s.gossipChan:
            //處理從通道中其他節點分發的訊息
            go s.queueNewMessage(msg)
        case msg := <-s.commChan:
            logger.Debug("Direct message ", msg)
            go s.directMessage(msg)
        case <-s.stopCh:
            s.stopCh <- struct{}{}
            return
        }
    }
}
//程式碼在gossip/state/state.go
```

go s.queueNewMessage(msg)程式碼如下:

```go
func (s *GossipStateProviderImpl) queueNewMessage(msg *proto.GossipMessage) {
    dataMsg := msg.GetDataMsg()
    if dataMsg != nil {
        err := s.addPayload(dataMsg.GetPayload(), nonBlocking) //寫入本地
    }
}
//程式碼在gossip/state/state.go
```
    
## 10、MessageCryptoService介面及實現

MessageCryptoService介面定義:訊息加密服務。

```go
type MessageCryptoService interface {
    //獲取Peer身份的PKI ID(Public Key Infrastructure,公鑰基礎設施)
    GetPKIidOfCert(peerIdentity PeerIdentityType) common.PKIidType
    //校驗塊簽名
    VerifyBlock(chainID common.ChainID, seqNum uint64, signedBlock []byte) error
    //使用Peer的簽名金鑰對訊息簽名
    Sign(msg []byte) ([]byte, error)
    //校驗簽名是否為有效簽名
    Verify(peerIdentity PeerIdentityType, signature, message []byte) error
    //在特定通道下校驗簽名是否為有效簽名
    VerifyByChannel(chainID common.ChainID, peerIdentity PeerIdentityType, signature, message []byte) error
    //校驗Peer身份
    ValidateIdentity(peerIdentity PeerIdentityType) error
}
//程式碼在gossip/api/crypto.go
```

MessageCryptoService介面實現,即mspMessageCryptoService結構體及方法:

```go
type mspMessageCryptoService struct {
    channelPolicyManagerGetter policies.ChannelPolicyManagerGetter //通道策略管理器,type ChannelPolicyManagerGetter interface
    localSigner crypto.LocalSigner //本地簽名者,type LocalSigner interface
    deserializer mgmt.DeserializersManager //反序列化管理器,type DeserializersManager interface
}

//構造mspMessageCryptoService
func NewMCS(channelPolicyManagerGetter policies.ChannelPolicyManagerGetter, localSigner crypto.LocalSigner, deserializer mgmt.DeserializersManager) api.MessageCryptoService
//調取s.getValidatedIdentity(peerIdentity)
func (s *mspMessageCryptoService) ValidateIdentity(peerIdentity api.PeerIdentityType) error
func (s *mspMessageCryptoService) GetPKIidOfCert(peerIdentity api.PeerIdentityType) common.PKIidType
func (s *mspMessageCryptoService) VerifyBlock(chainID common.ChainID, seqNum uint64, signedBlock []byte) error
func (s *mspMessageCryptoService) Sign(msg []byte) ([]byte, error)
func (s *mspMessageCryptoService) Verify(peerIdentity api.PeerIdentityType, signature, message []byte) error
func (s *mspMessageCryptoService) VerifyByChannel(chainID common.ChainID, peerIdentity api.PeerIdentityType, signature, message []byte) error
func (s *mspMessageCryptoService) getValidatedIdentity(peerIdentity api.PeerIdentityType) (msp.Identity, common.ChainID, error)
//程式碼在peer/gossip/mcs.go
```

## 20、本文使用的網路內容

* [hyperledger fabric 程式碼分析之 gossip 協議](https://zhuanlan.zhihu.com/p/27989809)
* [fabric原始碼解析14——peer的gossip服務之初始化](http://blog.csdn.net/idsuf698987/article/details/77898724)






網址:http://www.qukuailianxueyuan.io/



欲領取造幣技術與全套虛擬機器資料

區塊鏈技術交流QQ群:756146052  備註:CSDN

尹成學院微信:備註:CSDN





網址:http://www.qukuailianxueyuan.io/



欲領取造幣技術與全套虛擬機器資料

區塊鏈技術交流QQ群:756146052  備註:CSDN

尹成學院微信:備註:CSDN

相關文章