区块链开发教程 兄弟连区块链教程以太坊源码分析chain

              本文重点:区块链开发教程 兄弟连区块链教程以太坊源码分析chain

              chain_indexer索引chain_源码解析chain_indexer顾名思义,就是用来给区块链创建索引的功能。 之前在eth协议的时候,介绍过BloomIndexer的功能,其实BloomIndexer是chain_indexer的一个特殊的实现,可以理解为派生类,主要的功能其实实在chain_indexer这里面实现的。 虽说是派生类,但是chain_indexer其实就只被BloomIndexer使用。

              也就是给区块链的布隆过滤器创建了索引,以便快速的响应用户的日志搜索功能。 下面就来分析这部分的代码。 ###数据结构//ChainIndexerBackenddefinesthemethodsneededtoprocesschainsegmentsin////usedtocreatefilterbloomsorCHTs.//ChainIndexerBackend定义了处理区块链片段的方法,并把处理结果写入数据库。 这些可以用来创建布隆过滤器或者CHTs.//BloomIndexer其实就是实现了这个接口ChainIndexerBackend这里的CHTs不知道是什么东西。 typeChainIndexerBackendinterface{//Resetinitiatestheprocessingofanewchainsegment,potentiallyterminating//anypartiallycompletedoperations(incaseofareorg).//Reset方法用来初始化一个新的区块链片段,可能会终止任何没有完成的操作。

              Reset(sectionuint64)////willensureasequentialorderofheaders.//对区块链片段中的下一个区块头进行处理。 调用者将确保区块头的连续顺序。 Process(header*)//Commitfinalizesthesectionmetadataandstoresitintothedatabase.完成区块链片段的元数据并将其存储到数据库中。 Commit()error}//ChainIndexerdoesapost-processingjobforequallysizedsectionsofthe//canonicalchain(likeBlooomBitsandCHTstructures).AChainIndexeris//connectedtotheblockchainthroughtheeventsystembystartinga//ChainEventLoopinagoroutine.//ChainIndexer对区块链进行大小相等的片段进行处。 ChainIndexer在ChainEventLoop方法中通过事件系统与区块链通信,//FurtherchildChainIndexerscanbeaddedwhichusetheoutputoftheparent////afteranentiresectionhasbeenfinishedorincaseofrollbacksthatmight//affectalreadyfinishedsections.//更远可以添加使用父section索引器的输出的更多子链式索引器。

              这些子链式索引器只有在整个部分完成后或在可能影响已完成部分的回滚的情况下才接收新的头部通知。 typeChainIndexerstruct{//Chaindatabasetoindexthedatafrom区块链所在的数据库//Prefixedtable-viewofthedbtowriteindexmetadatainto索引存储的数据库backendChainIndexerBackend//Backgroundprocessorgeneratingtheindexdatacontent索引生成的后端。 children[]*ChainIndexer//Childindexerstocascadechainupdatesto子索引activeuint32//Flagwhethertheeventloopwasstartedupdatechanstruct{}//Notificationchannelthatheadersshouldbeprocessed接收到的headersquitchanchanerror//QuitchanneltoteardownrunninggoroutinessectionSizeuint64//Numberofblocksinasinglechainsegmenttoprocesssection的大小。

              默认是4096个区块为一个sectionconfirmsRequint64//Numberofconfirmationsbeforeprocessingacompletedsegment处理完成的段之前的确认次数storedSectionsuint64//Numberofsectionssuccessfullyindexedintothedatabase成功索引到数据库的部分数量knownSectionsuint64//Numberofsectionsknowntobecomplete(blockwise)已知完成的部分数量cascadedHeaduint64//Blocknumberofthelastcompletedsectioncascadedtosubindexers级联到子索引的最后一个完成部分的块号//Diskthrottlingtopreventaheavyupgradefromhoggingresources磁盘限制,以防止大量资源的大量升级}构造函数NewChainIndexer,这个方法是在eth/里面被调用的const(//bloomConfirmsisthenumberofconfirmationblocksbeforeabloomsectionis//consideredprobablyfinalanditsrotatedbitsarecalculated.//bloomConfirms用来表示确认区块数量,表示经过这么多区块之后,bloomsection被认为是已经不会更改了。

              bloomConfirms=256//bloomThrottlingisthetimetowaitbetweenprocessingtwoconsecutiveindex//\susefulduringchainupgradestopreventdiskoverload.//bloomThrottling是处理两个连续索引段之间的等待时间。

              在区块链升级过程中防止磁盘过载是很有用的。 bloomThrottling=100*)funcNewBloomIndexer(,sizeuint64)*{backend:=BloomIndexer{db:db,size:size,}//可以看到indexDb和chainDb实际是同一个数据库,但是indexDb的每个key前面附加了一个BloomBitsIndexPrefix的前缀。

              table:=(db,string())(db,table,backend,size,bloomConfirms,bloomThrottling,\bloombits\)}//NewChainIndexercreatesanewchainindexertodobackgroundprocessingon//chainsegmentsofagivensizeaftercertainnumberofconfirmationspassed.//(chainDb,,backendChainIndexerBackend,section,confirmuint64,,kindstring)*ChainIndexer{c:=ChainIndexer{chainDb:chainDb,indexDb:indexDb,backend:backend,update:make(chanstruct{},1),quit:make(chanchanerror),sectionSize:section,confirmsReq:confirm,throttling:throttling,log:(\type\,kind),}//()()returnc}loadValidSections,用来从数据库里面加载我们之前的处理信息,storedSections表示我们已经处理到哪里了。 //loadValidSectionsreadsthenumberofvalidsectionsfromtheindexdatabase//(c*ChainIndexer)loadValidSections(){data,_:=([]byte(\count\))iflen(data)==8{=(data[:])}}updateLoop,是主要的事件循环,用于调用backend来处理区块链section,这个需要注意的是,所有的主索引节点和所有的childindexer都会启动这个goroutine方法。

              func(c*ChainIndexer)updateLoop(){var()for{select{caseerrc:=-://Chainindexerterminating,{//如果当前以知的Section大于已经存储的Section//Periodicallyprintanupgradelogmessagetotheuser//每隔8秒打印一次日志信息。 (updated)8*{+1{updating=(\Upgradingchainindex\,\percentage\,*100/)}updated=()}//Cachethecurrentsectioncountandheadtoallowunlockingthemutexsection:={//section1代表section的下标是从0开始的。

              //sectionHead用来获取section的最后一个区块的hash值。

              oldHead=(section1)}//()//处理返回新的section的最后一个区块的hash值newHead,err:=(section,oldHead)iferr!=nil{(\Sectionprocessingfailed\,\error\,err)}()//Ifprocessingsucceededandnoreorgsocccurred,markthesectioncompletediferr==niloldHead==(section-1){(section,newHead)//更新数据库的状态(section+1)//更新数据库状态=={updating=(\Finishedupgradingchainindex\)}//cascadedHead是更新后的section的最后一个区块的高度//用法是什么?=*_,child:={(\Cascadingchainindexupdate\,\head\,)(,false)}}else{//如果处理失败,那么在有新的通知之前不会重试。

              //Ifprocessingfailed,don\(\Chainindexprocessingfailed\,\section\,section,\err\,err)=}}//Iftherearestillfurthersectionstoprocess,reschedule//如果还有section等待处理,那么等待throttling时间再处理。 避免磁盘过载。

              {(,func(){select{{}{}:default:}})}()}}}未完待续。