[IPFS挖矿教程] Filecoin技术架构分析之六:协议层hello握手协议

[复制链接]
12794 |0
发表于 2019-4-23 12:00:05 | 显示全部楼层 |阅读模式
目录6 filecoin源码协议层分析之hello握手协议
6.3.1 数据结构
6.3.2 方法
6.3.3 函数
6.3.4 实例化及业务逻辑
6.1 目的
6.2 源码信息
6.3 源码分析
6.1 目的处理节点上线后的区块同步握手。
6.2 源码信息version
master分支 619b0eb1(2019年3月2日)
package
hello
location
protocol/hello
node/node.go
6.3 源码分析6.3.1 数据结构定义协议名称
//Protocolisthelibp2pprotocolidentifierforthehelloprotocol.constprotocol="/fil/hello/1.0.0"
定义hello协议消息体结构
TipSet切片
TipSet高度
创世区块cid
//Messageisthedatastructureofasinglemessageinthehelloprotocol.typeMessagestruct{
HeaviestTipSetCids[]cid.Cid
HeaviestTipSetHeightuint64
GenesisHashcid.Cid
}
同步回调函数类型定义
typesyncCallbackfunc(frompeer.ID,cids[]cid.Cid,heightuint64)
获取Tipset函数类型定义
typegetTipSetFuncfunc()types.TipSet
Handler结构体,当连接到其他节点的时候,其一,会发送包含本节点信息的hello 消息给对端节点; 其二, 对端也会回复一个包含对端节点信息的消息体过来。
host 对应libp2p上的主机
创世区块cid
区块同步回调函数
获取TipSet的函数
//Handlerimplementsthe'Hello'protocolhandler.Uponconnectingtoanew//node,wesendthemamessagecontainingsomeinformationaboutthestateof//ourchain,andreceivethesameinformationfromthem.Thisisusedto//initiateachainsyncanddetectconnectionstoforks.typeHandlerstruct{
hosthost.Host
genesiscid.Cid//chainSyncCBiscalledwhennewpeerstellusabouttheirchain
chainSyncCBsyncCallback//getHeaviestTipSetisusedtoretrievethecurrentheaviesttipset
//forfillingoutourhellomessages.
getHeaviestTipSetgetTipSetFunc
}
错误的创世区块
//ErrBadGenesisistheerrorreturnedwhenamissmatchingenesisblockshappens.varErrBadGenesis=fmt.Errorf("badgenesisblock")
以上基本是作为hello客户端的一些定义,以下作为hello服务端的一些定义
//NewpeerconnectionnotificationstypehelloNotifyHandler// 连接超时时间consthelloTimeout=time.Second*10
6.3.2 方法6.3.2.1 Handler 方法流函数处理,接收远端节点的hello消息
func(h*Handler)handleNewStream(snet.Stream){
defers.Close()//nolint:errcheck
//获取远端节点实例
from:=s.Conn().RemotePeer()varhelloMessage//读取流信息到hello结构体中
iferr:=cbu.NewMsgReader(s).ReadMsg(&hello);err!=nil{
log.Warningf("badhellomessagefrompeer%s:%s",from,err)return
}//调用processHelloMessage方法对接收到的消息进行处理
switcherr:=h.processHelloMessage(from,&hello);err{//如果创世区块不一样,关闭流连接退出,不予处理
caseErrBadGenesis:
log.Warningf("genesiscid:%sdoesnotmatch:%s,disconnectingfrompeer:%s",&hello.GenesisHash,h.genesis,from)
s.Conn().Close()//nolint:errcheck
return
casenil://ok,noop
default:
log.Error(err)
}
}
处理hello消息
func(h*Handler)processHelloMessage(frompeer.ID,msg*Message)error{//如果创世区块不一样,报错
if!msg.GenesisHash.Equals(h.genesis){returnErrBadGenesis
}//调用区块同步方法
//此回调函数实在node包实例化hello协议的时候中定义的
h.chainSyncCB(from,msg.HeaviestTipSetCids,msg.HeaviestTipSetHeight)returnnil
}
响应远端节点的连接,回复hello消息体
func(h*Handler)getOurHelloMessage()*Message{
heaviest:=h.getHeaviestTipSet()
height,err:=heaviest.Height()iferr!=nil{
panic("somehowheaviesttipsetisempty")
}return&Message{
GenesisHash:h.genesis,
HeaviestTipSetCids:heaviest.ToSortedCidSet().ToSlice(),
HeaviestTipSetHeight:height,
}
}
func(h*Handler)sayHello(ctxcontext.Context,ppeer.ID)error{
s,err:=h.host.NewStream(ctx,p,protocol)iferr!=nil{returnerr
}
defers.Close()//nolint:errcheck
//获取本节点的hello消息体
msg:=h.getOurHelloMessage()//向远端节点发送消息体
returncbu.NewMsgWriter(s).WriteMsg(&msg)
}
6.3.2.2 helloNotify方法hello方法,返回一个handler实例
func(hn*helloNotify)hello()*Handler{return(*Handler)(hn)
}
helloNotify实现了libp2p-net/interface.go中的Notifiee接口
func(hn*helloNotify)Connected(nnet.Network,cnet.Conn){gofunc(){
ctx,cancel:=context.WithTimeout(context.Background(),helloTimeout)
defercancel()
p:=c.RemotePeer()//有其他节点连接的时候调用sayHello,发送hello消息体
iferr:=hn.hello().sayHello(ctx,p);err!=nil{log.Warningf("failedtosendhellohandshaketopeer%s:%s",p,err)
}
}()
}
func(hn*helloNotify)Listen(nnet.Network,ama.Multiaddr){}
func(hn*helloNotify)ListenClose(nnet.Network,ama.Multiaddr){}
func(hn*helloNotify)Disconnected(nnet.Network,cnet.Conn){}
func(hn*helloNotify)OpenedStream(nnet.Network,snet.Stream){}
func(hn*helloNotify)ClosedStream(nnet.Network,snet.Stream){}
6.3.3 函数创建hello实例
//Newcreatesanewinstanceofthehelloprotocolandregistersitto//thegivenhost,withtheprovidedcallbacks.funcNew(hhost.Host,gencid.Cid,syncCallbacksyncCallback,getHeaviestTipSetgetTipSetFunc)*Handler{
hello:=&Handler{
host:h,
genesis:gen,
chainSyncCB:syncCallback,
getHeaviestTipSet:getHeaviestTipSet,
}//设置流处理回调函数
h.SetStreamHandler(protocol,hello.handleNewStream)//注册网络状态改变通知回调函数
//registerforconnectionnotifications
h.Network().Notify((*helloNotify)(hello))returnhello
}//上文中的helloNotify实现了libp2p-net/interface.go中的Notifiee接口//Notifieeisaninterfaceforanobjectwishingtoreceive//notificationsfromaNetwork.typeNotifieeinterface{
Listen(Network,ma.Multiaddr)//calledwhennetworkstartslisteningonanaddr
ListenClose(Network,ma.Multiaddr)//calledwhennetworkstopslisteningonanaddr
Connected(Network,Conn)//calledwhenaconnectionopened
Disconnected(Network,Conn)//calledwhenaconnectionclosed
OpenedStream(Network,Stream)//calledwhenastreamopened
ClosedStream(Network,Stream)//calledwhenastreamclosed
//TODO
//PeerConnected(Network,peer.ID)//calledwhenapeerconnected
//PeerDisconnected(Network,peer.ID)//calledwhenapeerdisconnected}
6.3.4 实例化及业务逻辑location: node/node.go
Node节点中定义了hello服务
typeNodestruct{
......
HelloSvc*hello.Handler
......
}
启动hello服务
//Startbootsupthenode.func(node*Node)Start(ctxcontext.Context)error{
......//Startup'hello'handshakeservice
//定义区块同步的回调函数
syncCallBack:=func(pidlibp2ppeer.ID,cids[]cid.Cid,heightuint64){//TODOitispossiblethesyncerinterfaceshouldbemodifiedto
//makeuseoftheadditionalcontextnotusedhere(fromaddr+height).
//Tokeepthingssimplefornowthisinfoisnotused.
//触发调用会启动同步区块的动作
err:=node.Syncer.HandleNewBlocks(context.Background(),cids)iferr!=nil{log.Infof("errorhandlingblocks:%s",types.NewSortedCidSet(cids...).String())
}
}//实例化hello服务
node.HelloSvc=hello.New(node.Host(),node.ChainReader.GenesisCid(),syncCallBack,node.ChainReader.Head)
......
}

gs2c5zkewgk.png

gs2c5zkewgk.png
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表