兄弟连Go语言+区块链技术培训以太坊源码分析35ethfetcher源码分析.docx

上传人:b****6 文档编号:4561789 上传时间:2022-12-06 格式:DOCX 页数:21 大小:24.23KB
下载 相关 举报
兄弟连Go语言+区块链技术培训以太坊源码分析35ethfetcher源码分析.docx_第1页
第1页 / 共21页
兄弟连Go语言+区块链技术培训以太坊源码分析35ethfetcher源码分析.docx_第2页
第2页 / 共21页
兄弟连Go语言+区块链技术培训以太坊源码分析35ethfetcher源码分析.docx_第3页
第3页 / 共21页
兄弟连Go语言+区块链技术培训以太坊源码分析35ethfetcher源码分析.docx_第4页
第4页 / 共21页
兄弟连Go语言+区块链技术培训以太坊源码分析35ethfetcher源码分析.docx_第5页
第5页 / 共21页
点击查看更多>>
下载资源
资源描述

兄弟连Go语言+区块链技术培训以太坊源码分析35ethfetcher源码分析.docx

《兄弟连Go语言+区块链技术培训以太坊源码分析35ethfetcher源码分析.docx》由会员分享,可在线阅读,更多相关《兄弟连Go语言+区块链技术培训以太坊源码分析35ethfetcher源码分析.docx(21页珍藏版)》请在冰豆网上搜索。

兄弟连Go语言+区块链技术培训以太坊源码分析35ethfetcher源码分析.docx

兄弟连Go语言+区块链技术培训以太坊源码分析35ethfetcher源码分析

兄弟连Go语言+区块链技术培训以太坊源码分析(35)eth-fetcher源码分析

fetcher包含基于块通知的同步。

当我们接收到NewBlockHashesMsg消息得时候,我们只收到了很多Block的hash值。

需要通过hash值来同步区块,然后更新本地区块链。

fetcher就提供了这样的功能。

数据结构

    //announceisthehashnotificationoftheavailabilityofanewblockinthe

    //network.

    //announce是一个hash通知,表示网络上有合适的新区块出现。

    typeannouncestruct{

        hashcommon.Hash//Hashoftheblockbeingannounced//新区块的hash值

        numberuint64//Numberoftheblockbeingannounced(0=unknown|oldprotocol)区块的高度值,

        header*types.Header//Headeroftheblockpartiallyreassembled(newprotocol)    重新组装的区块头

        timetime.Time//Timestampoftheannouncement

    

        originstring//Identifierofthepeeroriginatingthenotification

    

        fetchHeaderheaderRequesterFn//Fetcherfunctiontoretrievetheheaderofanannouncedblock获取区块头的函数指针,里面包含了peer的信息。

就是说找谁要这个区块头

        fetchBodiesbodyRequesterFn//Fetcherfunctiontoretrievethebodyofanannouncedblock获取区块体的函数指针

    }

    

    //headerFilterTaskrepresentsabatchofheadersneedingfetcherfiltering.

    typeheaderFilterTaskstruct{

        peerstring//Thesourcepeerofblockheaders

        headers[]*types.Header//Collectionofheaderstofilter

        timetime.Time//Arrivaltimeoftheheaders

    }

    

    //headerFilterTaskrepresentsabatchofblockbodies(transactionsanduncles)

    //needingfetcherfiltering.

    typebodyFilterTaskstruct{

        peerstring//Thesourcepeerofblockbodies

        transactions[][]*types.Transaction//Collectionoftransactionsperblockbodies

        uncles[][]*types.Header//Collectionofunclesperblockbodies

        timetime.Time//Arrivaltimeoftheblocks'contents

    }

    

    //injectrepresentsaschedulesimportoperation.

    //当节点收到NewBlockMsg的消息时候,会插入一个区块

    typeinjectstruct{

        originstring

        block*types.Block

    }

    

    //Fetcherisresponsibleforaccumulatingblockannouncementsfromvariouspeers

    //andschedulingthemforretrieval.

    typeFetcherstruct{

        //Variouseventchannels

        notifychan*announce   //announce的通道,

        injectchan*inject     //inject的通道

    

        blockFilterchanchan[]*types.Block   //通道的通道?

        headerFilterchanchan*headerFilterTask

        bodyFilterchanchan*bodyFilterTask

    

        donechancommon.Hash

        quitchanstruct{}

    

        //Announcestates

        announcesmap[string]int//Perpeerannouncecountstopreventmemoryexhaustionkey是peer的名字,value是announce的count,为了避免内存占用太大。

        announcedmap[common.Hash][]*announce//Announcedblocks,scheduledforfetching等待调度fetching的announce

        fetchingmap[common.Hash]*announce//Announcedblocks,currentlyfetching正在fetching的announce

        fetchedmap[common.Hash][]*announce//Blockswithheadersfetched,scheduledforbodyretrieval//已经获取区块头的,等待获取区块body

        completingmap[common.Hash]*announce//Blockswithheaders,currentlybody-completing//头和体都已经获取完成的announce

    

        //Blockcache

        queue*prque.Prque//Queuecontainingtheimportoperations(blocknumbersorted)//包含了import操作的队列(按照区块号排列)

        queuesmap[string]int//Perpeerblockcountstopreventmemoryexhaustionkey是peer,value是block数量。

避免内存消耗太多。

        queuedmap[common.Hash]*inject//Setofalreadyqueuedblocks(todedupimports)已经放入队列的区块。

为了去重。

    

        //Callbacks依赖了一些回调函数。

        getBlockblockRetrievalFn//Retrievesablockfromthelocalchain

        verifyHeaderheaderVerifierFn//Checksifablock'sheadershaveavalidproofofwork

        broadcastBlockblockBroadcasterFn//Broadcastsablocktoconnectedpeers

        chainHeightchainHeightFn//Retrievesthecurrentchain'sheight

        insertChainchainInsertFn//Injectsabatchofblocksintothechain

        dropPeerpeerDropFn//Dropsapeerformisbehaving

    

        //Testinghooks仅供测试使用。

        announceChangeHookfunc(common.Hash,bool)//Methodtocalluponaddingordeletingahashfromtheannouncelist

        queueChangeHookfunc(common.Hash,bool)//Methodtocalluponaddingordeletingablockfromtheimportqueue

        fetchingHookfunc([]common.Hash)//Methodtocalluponstartingablock(eth/61)orheader(eth/62)fetch

        completingHookfunc([]common.Hash)//Methodtocalluponstartingablockbodyfetch(eth/62)

        importedHookfunc(*types.Block)//Methodtocalluponsuccessfulblockimport(botheth/61andeth/62)

    }

启动fetcher,直接启动了一个goroutine来处理。

这个函数有点长。

后续再分析。

    //Startbootsuptheannouncementbasedsynchroniser,acceptingandprocessing

    //hashnotificationsandblockfetchesuntilterminationrequested.

    func(f*Fetcher)Start(){

        gof.loop()

    }

loop函数函数太长。

我先帖一个省略版本的出来。

fetcher通过四个map(announced,fetching,fetched,completing)记录了announce的状态(等待fetch,正在fetch,fetch完头等待fetchbody,fetch完成)。

loop其实通过定时器和各种消息来对各种map里面的announce进行状态转换。

    //Loopisthemainfetcherloop,checkingandprocessingvariousnotification

    //events.

    func(f*Fetcher)loop(){

        //Iteratetheblockfetchinguntilaquitisrequested

        fetchTimer:

=time.NewTimer(0)//fetch的定时器。

        completeTimer:

=time.NewTimer(0)//compelte的定时器。

    

        for{

            //Cleanupanyexpiredblockfetches

            //如果fetching的时间超过5秒,那么放弃掉这个fetching

            forhash,announce:

=rangef.fetching{

                iftime.Since(announce.time)>fetchTimeout{

                    f.forgetHash(hash)

                }

            }

            //Importanyqueuedblocksthatcouldpotentiallyfit

            //这个fetcher.queue里面缓存了已经完成fetch的block等待按照顺序插入到本地的区块链中

            //fetcher.queue是一个优先级队列。

优先级别就是他们的区块号的负数,这样区块数小的排在最前面。

            height:

=f.chainHeight()

            for!

f.queue.Empty(){//

                op:

=f.queue.PopItem().(*inject)

                iff.queueChangeHook!

=nil{

                    f.queueChangeHook(op.block.Hash(),false)

                }

                //Iftoohighupthechainorphase,continuelater

                number:

=op.block.NumberU64()

                ifnumber>height+1{//当前的区块的高度太高,还不能import

                    f.queue.Push(op,-float32(op.block.NumberU64()))

                    iff.queueChangeHook!

=nil{

                        f.queueChangeHook(op.block.Hash(),true)

                    }

                    break

                }

                //Otherwiseiffreshandstillunknown,tryandimport

                hash:

=op.block.Hash()

                ifnumber+maxUncleDist

=nil{

                    //区块的高度太低低于当前的height-maxUncleDist

                    //或者区块已经被import了

                    f.forgetBlock(hash)

                    continue

                }

                //插入区块

                f.insert(op.origin,op.block)

            }

            //Waitforanoutsideeventtooccur

            select{

            case<-f.quit:

                //Fetcherterminating,abortalloperations

                return

    

            casenotification:

=<-f.notify:

//在接收到NewBlockHashesMsg的时候,对于本地区块链还没有的区块的hash值会调用fetcher的Notify方法发送到notify通道。

                ...

    

            caseop:

=<-f.inject:

//在接收到NewBlockMsg的时候会调用fetcher的Enqueue方法,这个方法会把当前接收到的区块发送到inject通道。

                ...

                f.enqueue(op.origin,op.block)

    

            casehash:

=<-f.done:

//当完成一个区块的import的时候会发送该区块的hash值到done通道。

                ...

    

            case<-fetchTimer.C:

//fetchTimer定时器,定期对需要fetch的区块头进行fetch

                ...

    

            case<-completeTimer.C:

//completeTimer定时器定期对需要fetch的区块体进行fetch

                ...

    

            casefilter:

=<-f.headerFilter:

//当接收到BlockHeadersMsg的消息的时候(接收到一些区块头),会把这些消息投递到headerFilter队列。

这边会把属于fetcher请求的数据留下,其他的会返回出来,给其他系统使用。

                ...

    

            casefilter:

=<-f.bodyFilter:

//当接收到BlockBodiesMsg消息的时候,会把这些消息投递给bodyFilter队列。

这边会把属于fetcher请求的数据留下,其他的会返回出来,给其他系统使用。

                ...

            }

        }

    }

###区块头的过滤流程

####FilterHeaders请求

FilterHeaders方法在接收到BlockHeadersMsg的时候被调用。

这个方法首先投递了一个channelfilter到headerFilter。

然后往filter投递了一个headerFilterTask的任务。

然后阻塞等待filter队列返回消息。

    //FilterHeadersextractsalltheheadersthatwereexplicitlyrequestedbythefetcher,

    //returningthosethatshouldbehandleddifferently.

    func(f*Fetcher)FilterHeaders(peerstring,headers[]*types.Header,timetime.Time)[]*types.Header{

        log.Trace("Filteringheaders","peer",peer,"headers",len(headers))

    

        //Sendthefilterchanneltothefetcher

        filter:

=make(chan*headerFilterTask)

    

        select{

        casef.headerFilter<-filter:

        case<-f.quit:

            returnnil

        }

        //Requestthefilteringoftheheaderlist

        select{

        casefilter<-&headerFilterTask{peer:

peer,headers:

headers,time:

time}:

        case<-f.quit:

            returnnil

        }

        //Retrievetheheadersremainingafterfiltering

        select{

        casetask:

=<-filter:

            returntask.headers

        case<-f.quit:

            returnnil

        }

    }

####headerFilter的处理

这个处理在loop()的goroutine中。

    casefilter:

=<-f.headerFilter:

                //Headersarrivedfromaremotepeer.Extractthosethatwereexplicitly

                //requestedbythefetcher,andreturneverythingelsesoit'sdelivered

                //tootherpartsofthesystem.

                vartask*headerFilterTask

                select{

                casetask=<-filter:

                case<-f.quit:

                    return

                }

                headerFilter

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高中教育 > 高中教育

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1