In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-27 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >
Share
Shulou(Shulou.com)06/01 Report--
这篇文章主要讲解了"BlockKeeper的逻辑是什么",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"BlockKeeper的逻辑是什么"吧!
我们要发送什么样的数据请求,才能让比原节点把它持有的区块数据发给我?找到发送请求的代码
首先我们先要在代码中定位到,比原到底是在什么时候来向对方节点发送请求的。
在前一篇讲的是如何建立连接并验证身份,那么发出数据请求的操作,一定在上次的代码之后。按照这个思路,我们在SyncManager类中Switch启动之后,找到了一个叫BlockKeeper的类,相关的操作是在它里面完成的。
下面是老规矩,还是从启动开始,但是会更简化一些:
cmd/bytomd/main.go#L54
func main() { cmd := cli.PrepareBaseCmd(commands.RootCmd, "TM", os.ExpandEnv(config.DefaultDataDir())) cmd.Execute()}
cmd/bytomd/commands/run_node.go#L41
func runNode(cmd *cobra.Command, args []string) error { n := node.NewNode(config) if _, err := n.Start(); err != nil { // ...}
node/node.go#L169
func (n *Node) OnStart() error { // ... n.syncManager.Start() // ...}
netsync/handle.go#L141
func (sm *SyncManager) Start() { go sm.netStart() // ... go sm.syncer()}
注意sm.netStart(),我们在一篇中建立连接并验证身份的操作,就是在它里面完成的。而这次的这个问题,是在下面的sm.syncer()中完成的。
另外注意,由于这两个函数调用都使用了goroutine,所以它们是同时进行的。
sm.syncer()的代码如下:
netsync/sync.go#L46
func (sm *SyncManager) syncer() { sm.fetcher.Start() defer sm.fetcher.Stop() // ... for { select { case sm.chain.BestBlockHeight() { // ... sm.blockKeeper.BlockRequestWorker(peer.Key, bestHeight) }}
可以看到,首先是从众多的peers中,找到最合适的那个。什么叫Best呢?看一下BestPeer()的定义:
netsync/peer.go#L266
func (ps *peerSet) BestPeer() (*p2p.Peer, uint64) { // ... for _, p := range ps.peers { if bestPeer == nil || p.height > bestHeight { bestPeer, bestHeight = p.swPeer, p.height } } return bestPeer, bestHeight}
其实就是持有区块链数据最长的那个。
找到了BestPeer之后,就调用sm.blockKeeper.BlockRequestWorker(peer.Key, bestHeight)方法,从这里,正式进入BlockKeeper -- 也就是本文的主角 -- 的世界。
BlockKeeper
blockKeeper.BlockRequestWorker的逻辑比较复杂,它包含了:
根据自己持有的区块数据来计算需要同步的数据
向前面找到的最佳节点发送数据请求
拿到对方发过来的区块数据
对数据进行处理
广播新状态
处理各种出错情况,等等
由于本文中只关注"发送请求",所以一些与之关系不大的逻辑我会忽略掉,留待以后再讲。
在"发送请求"这里,实际也包含了两种情形,一种简单的,一种复杂的:
简单的:假设不存在分叉,则直接检查本地高度最高的区块,然后请求下一个区块
复杂的:考虑分叉的情况,则当前本地的区块可能就存在分叉,那么到底应该请求哪个区块,就需要慎重考虑
由于第2种情况对于本文来说过于复杂(因为需要深刻理解比原链中分叉的处理逻辑),所以在本文中将把问题简化,只考虑第1种。而分叉的处理,将放在以后讲解。
下面是把blockKeeper.BlockRequestWorker中的代码简化成了只包含第1种情况:
netsync/block_keeper.go#L72
func (bk *blockKeeper) BlockRequestWorker(peerID string, maxPeerHeight uint64) error { num := bk.chain.BestBlockHeight() + 1 reqNum := uint64(0) reqNum = num // ... bkPeer, ok := bk.peers.Peer(peerID) swPeer := bkPeer.getPeer() // ... block, err := bk.BlockRequest(peerID, reqNum) // ...}
在这种情况下,我们可以认为bk.chain.BestBlockHeight()中的Best,指的是本地持有的不带分叉的区块链高度最高的那个。(需要提醒的是,如果存在分叉情况,则Best不一定是高度最高的那个)
那么我们就可以直接向最佳peer请求下一个高度的区块,它是通过bk.BlockRequest(peerID, reqNum)实现的:
netsync/block_keeper.go#L152
func (bk *blockKeeper) BlockRequest(peerID string, height uint64) (*types.Block, error) { var block *types.Block if err := bk.blockRequest(peerID, height); err != nil { return nil, errReqBlock } // ... for { select { case pendingResponse :=
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.