Goosip協議
去中心化、容錯和最終一致性的算法
信息達到同步的最優時間:log(N)。
功能:
節點發現
數據廣播
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服務是處理消息的,每種類型的消息有不同的用途
消息類型
gossip服務使用不同模塊處理不同類型的消息。消息類型原型在/protos/message.proto中定義。gossip中傳播的消息以GossipMessage形式傳遞,具體的消息數據存放在GossipMessage中的Content成員中。
節點關系消息
與頻道成員身份、關系和存續相關的消息類型。
AliveMessage - alive消息
MembershipRequest - 成員關系請求消息
MembershipResponse -成員關系應答消息
pull機制消息
pull進來的可以是以塊數據為內容的消息,也可以是身份數據為內容的消息,下述4種消息中都有一個成員MsgType來表明這個消息中所攜帶的數據內容。從pull步驟上分為四種:
GossipHello - hello消息
DataDigest - 消息摘要
DataRequest - 摘要請求
DataUpdate - 摘要應答
state消息
和狀態有關的消息。這里的狀態指的是chain的數據狀態,如一個結點所存儲的塊數據是否一致,可以說這里所謂的狀態接近數據的意思。
StateInfo - 狀態消息
DataMessage - 數據消息(block)
TransactionMessage - 交易數據;
輔助類消息
這類消息不承擔具體傳送傳播數據的任務,而是輔助性的:
Empty - 空消息,用於結點間的Ping(來測試結點是否連通)和測試。
ConnEstablish - 用於gossip之間的握手,即任何時候一個peer想與另一個peer連接通信,都需要先發送這個消息以證明其身份。
gossip模塊
主要功能
gossip部分接口
type Gossip interface {
// Send sends a message to remote peers
Send(msg *proto.GossipMessage, peers ...*comm.RemotePeer)
// GetPeers returns the NetworkMembers considered alive
Peers() []discovery.NetworkMember
// PeersOfChannel returns the NetworkMembers considered alive
// and also subscribed to the channel given
PeersOfChannel(common.ChainID) []discovery.NetworkMember
// UpdateLedgerHeight updates the ledger height the peer
// publishes to other peers in the channel
UpdateLedgerHeight(height uint64, chainID common.ChainID)
// Gossip sends a message to other peers to the network
Gossip(msg *proto.GossipMessage)
// Accept returns a dedicated read-only channel for messages sent by other nodes that match a certain predicate.
// If passThrough is false, the messages are processed by the gossip layer beforehand.
// If passThrough is true, the gossip layer doesn't intervene and the messages
// can be used to send a reply back to the sender
Accept(acceptor common.MessageAcceptor, passThrough bool) (<-chan *proto.GossipMessage, <-chan proto.ReceivedMessage)
// JoinChan makes the Gossip instance join a channel
JoinChan(joinMsg api.JoinChannelMessage, chainID common.ChainID)
// LeaveChan makes the Gossip instance leave a channel.
// It still disseminates stateInfo message, but doesn't participate
// in block pulling anymore, and can't return anymore a list of peers
// in the channel.
LeaveChan(chainID common.ChainID)
// Stop stops the gossip component
Stop()
}
主要模塊
初始化和服務啟動
消息廣播
PeerA通過gossip協議廣播消息,PeerB為其中一個消息接收節點。
代碼應用框架
//初始化並加入通道‘A’
gossip = NewGossipInstance(15000, 1, 1000, isBoot)
gossip.JoinChan(&JoinChanMsg{}, common.ChainID("A"))
gossip.UpdateLedgerHeight(1, common.ChainID("A"))
acceptChan, _ := gossip.Accept(AcceptData, false) //AcceptData未消息選擇器
//通過gossip的方式來發送消息
gossip.Gossip(msg *pb.GossipMessage)
注:gossip發送消息后,對端節點接收到消息,會把過濾的消息坊到accetpChan通道中。
gossip pull機制
消息類型
pull機制主要涉及四種消息類型
GossipHello - hello消息
DataDigest - 消息摘要
DataRequest - 摘要請求
DataUpdate - 摘要應答
具體pull的內容包括: 未定義消息,塊消息,身份消息
初始化
pull機制的四個步驟
關鍵參數和函數
PullPeerNum //從PullPeerNum個節點pull數據
PullInterval //pull引擎每隔PullInterval開始一次pull同步
createBlockPuller: //創建pull.Mediator
- IngressDigFilter(大於本地高度的區塊)//用來過濾digest,返回自己要同步數據的摘要
- IdExtractor: seqNumFromMsg //要同步數據的唯一標識
注: IDExtractor是個接口,區塊數據用塊高標識;身份數據用證書或者公鑰相關數據表示