兄弟连Go语言+区块链技术培训以太坊源码分析49p2ptablego源码分析.docx
《兄弟连Go语言+区块链技术培训以太坊源码分析49p2ptablego源码分析.docx》由会员分享,可在线阅读,更多相关《兄弟连Go语言+区块链技术培训以太坊源码分析49p2ptablego源码分析.docx(19页珍藏版)》请在冰豆网上搜索。
![兄弟连Go语言+区块链技术培训以太坊源码分析49p2ptablego源码分析.docx](https://file1.bdocx.com/fileroot1/2022-10/28/8139f9da-ddae-41f5-b155-87a460b8960d/8139f9da-ddae-41f5-b155-87a460b8960d1.gif)
兄弟连Go语言+区块链技术培训以太坊源码分析49p2ptablego源码分析
兄弟连Go语言+区块链技术培训以太坊源码分析(49)p2p-table.go源码分析
table.go主要实现了p2p的Kademlia协议。
###Kademlia协议简介(建议阅读references里面的pdf文档)
Kademlia协议(以下简称Kad)是美国纽约大学的PetarP.Maymounkov和DavidMazieres.
在2002年发布的一项研究结果《Kademlia:
Apeerto-peerinformationsystembasedon
theXORmetric》。
简单的说,Kad是一种分布式哈希表(DHT)技术,不过和其他DHT实现技术比较,如
Chord、CAN、Pastry等,Kad通过独特的以异或算法(XOR)为距离度量基础,建立了一种
全新的DHT拓扑结构,相比于其他算法,大大提高了路由查询速度。
###table的结构和字段
const(
alpha=3//Kademliaconcurrencyfactor
bucketSize=16//Kademliabucketsize
hashBits=len(common.Hash{})*8
nBuckets=hashBits+1//Numberofbuckets
maxBondingPingPongs=16
maxFindnodeFailures=5
autoRefreshInterval=1*time.Hour
seedCount=30
seedMaxAge=5*24*time.Hour
)
typeTablestruct{
mutexsync.Mutex//protectsbuckets,theircontent,andnursery
buckets[nBuckets]*bucket//indexofknownnodesbydistance
nursery[]*Node//bootstrapnodes
db*nodeDB//databaseofknownnodes
refreshReqchanchanstruct{}
closeReqchanstruct{}
closedchanstruct{}
bondmusync.Mutex
bondingmap[NodeID]*bondproc
bondslotschanstruct{}//limitstotalnumberofactivebondingprocesses
nodeAddedHookfunc(*Node)//fortesting
nettransport
self*Node//metadataofthelocalnode
}
###初始化
funcnewTable(ttransport,ourIDNodeID,ourAddr*net.UDPAddr,nodeDBPathstring)(*Table,error){
//Ifnonodedatabasewasgiven,useanin-memoryone
//这个在之前的database.go里面有介绍。
打开leveldb。
如果path为空。
那么打开一个基于内存的db
db,err:
=newNodeDB(nodeDBPath,Version,ourID)
iferr!
=nil{
returnnil,err
}
tab:
=&Table{
net:
t,
db:
db,
self:
NewNode(ourID,ourAddr.IP,uint16(ourAddr.Port),uint16(ourAddr.Port)),
bonding:
make(map[NodeID]*bondproc),
bondslots:
make(chanstruct{},maxBondingPingPongs),
refreshReq:
make(chanchanstruct{}),
closeReq:
make(chanstruct{}),
closed:
make(chanstruct{}),
}
fori:
=0;i tab.bondslots<-struct{}{}
}
fori:
=rangetab.buckets{
tab.buckets[i]=new(bucket)
}
gotab.refreshLoop()
returntab,nil
}
上面的初始化启动了一个goroutinerefreshLoop(),这个函数主要完成以下的工作。
1. 每一个小时进行一次刷新工作(autoRefreshInterval)
2. 如果接收到refreshReq请求。
那么进行刷新工作。
3. 如果接收到关闭消息。
那么进行关闭。
所以函数主要的工作就是启动刷新工作。
doRefresh
//refreshLoopschedulesdoRefreshrunsandcoordinatesshutdown.
func(tab*Table)refreshLoop(){
var(
timer=time.NewTicker(autoRefreshInterval)
waiting[]chanstruct{}//accumulateswaitingcallerswhiledoRefreshruns
donechanstruct{}//wheredoRefreshreportscompletion
)
loop:
for{
select{
case<-timer.C:
ifdone==nil{
done=make(chanstruct{})
gotab.doRefresh(done)
}
casereq:
=<-tab.refreshReq:
waiting=append(waiting,req)
ifdone==nil{
done=make(chanstruct{})
gotab.doRefresh(done)
}
case<-done:
for_,ch:
=rangewaiting{
close(ch)
}
waiting=nil
done=nil
case<-tab.closeReq:
breakloop
}
}
if!
=nil{
.close()
}
ifdone!
=nil{
<-done
}
for_,ch:
=rangewaiting{
close(ch)
}
tab.db.close()
close(tab.closed)
}
doRefresh函数
//doRefreshperformsalookupforarandomtargettokeepbuckets
//full.seednodesareinsertedifthetableisempty(initial
//bootstrapordiscardedfaultypeers).
//doRefresh随机查找一个目标,以便保持buckets是满的。
如果table是空的,那么种子节点会插入。
(比如最开始的启动或者是删除错误的节点之后)
func(tab*Table)doRefresh(donechanstruct{}){
deferclose(done)
//TheKademliapaperspecifiesthatthebucketrefreshshould
//performalookupintheleastrecentlyusedbucket.Wecannot
//adheretothisbecausethefindnodetargetisa512bitvalue
//(nothash-sized)anditisnoteasilypossibletogeneratea
//sha3preimagethatfallsintoachosenbucket.
//Weperformalookupwitharandomtargetinstead.
//这里暂时没看懂
vartargetNodeID
rand.Read(target[:
])
result:
=tab.lookup(targ