以太坊源码分析(30)eth

阅读: 评论:0

以太坊源码分析(30)eth

以太坊源码分析(30)eth

## 以太坊的布隆过滤器
以太坊的区块头中包含了一个叫做logsBloom的区域。 这个区域存储了当前区块中所有的收据的日志的布隆过滤器,一共是2048个bit。也就是256个字节。
而我们的一个交易的收据包含了很多的日志记录。 每个日志记录包含了 合约的地址, 多个Topic。 而在我们的收据中也存在一个布隆过滤器,这个布隆过滤器记录了所有的日志记录的信息。
如果我们看黄皮书里面对日志记录的形式化定义。
O代表我们的日志记录,Oa代表logger的地址,Oto,Ot1代表日志的Topics, Od代表时间。
Oa是20个字节,Ot是32个字节,Od是很多字节
我们定义了一个布隆过滤器函数M,用来把一个日志对象转换成256字节的hash
M3:2045是一个特别的函数,用来设置2048个bit位中的三位为1。

对于任意的输入值,首先求他的KEC输出, 然后通过取KEC输出的 [0,1] [2,3],[4,5] 这几位的值 对2048取模, 得到三个值, 这三个值就是输出的2048中需要置位的下标。 也就是说对于任何一个输入,如果它对应的三个下标的值不都为1,那么它肯定不在这个区块中。 当如如果对应的三位都为1,也不能说明一定在这个区块中。 这就是布隆过滤器的特性。
收据中的布隆过滤器就是所有的日志的布隆过滤器输出的并集。
同时区块头中的logBloom,就是所有的收据的布隆过滤器的并集。
## ChainIndexer 和 BloomIndexer 最开始看到ChainIndexer,不是很明白是什么功能。 其实从名字中可以看到,是Chain的索引。 在 eth中我们有看到BloomIndexer,这个就是布隆过滤器的索引。
在我们的协议中提供了查找指定Log的功能。
用户可以通过传递下面的参数来查找指定的Log,开始的区块号,结束的区块号, 根据合约 Addresses指定的地址过滤,根据指定的Topics来过滤。
    // FilterCriteria represents a request to create a new filter.     type FilterCriteria struct {         FromBlock *big.Int         ToBlock *big.Int         Addresses []common.Address         Topics [][]common.Hash     }
如果开始和结束之间间隔很大,那么如果直接依次检索每个区块头的logBloom区域是比较低效的。 因为每个区块头都是分开存储的, 可能需要非常多的磁盘随机访问。
所以以太坊协议在本地维护了一套索引,用来加速这个过程。
大致原理是。 每4096个区块称为一个Section,一个Section里面的logBloom会存储在一起。对于每个Section, 用一个二维数据,A[ 2048][4096]来存储。 第一维2048代表了bloom过滤器的长度2048个字节。 第二维4096代表了一个Section里面的所有区块,每一个位置按照顺序代表了其中的一个区块。
- A[ 0][0]=blockchain[section*4096+0].logBloom[0], - A[ 0][1]=blockchain[section*4096+1].logBloom[0], - A[ 0][4096]=blockchain[section*4096+1].logBloom[0], - A[ 1][0]=blockchain[section*4096+0].logBloom[1], - A[ 1][1024]=blockchain[section*4096+1024].logBloom[1], - A[ 2047][1]=blockchain[section*4096+1].logBloom[2047],
如果Section填充完毕,那么会写成2048个KV。 ![ image]( picture/bloom_6.png)

## 代码分析
这个代码相对不是很独立,如果单独看这个代码,有点摸不着头脑的感觉, 因为它只是实现了一些接口,具体的处理逻辑并不在这里,而是在core里面。 不过这里我先结合之前讲到的信息分析一下。 后续更详细的逻辑在分析core的代码的时候再详细分析。
服务线程startBloomHandlers,这个方法是为了响应具体的查询请求, 给定指定的Section和bit来从levelDB里面查询然后返回出去。 单独看这里有点摸不着头脑。 这个方法的调用比较复杂。 涉及到core里面的很多逻辑。 这里先不细说了。 直到有这个方法就行了。
    type Retrieval struct {         Bit uint           //Bit的取值 0-2047 代表了想要获取哪一位的值         Sections []uint64       // 那些Section         Bitsets [][]byte       // 返回值 查询出来的结果。     }     // startBloomHandlers starts a batch of goroutines to accept bloom bit database     // retrievals from possibly a range of filters and serving the data to satisfy.     func (eth *Ethereum) startBloomHandlers() {         for i := 0; i < bloomServiceThreads; i++ {             go func() {                 for {                     select {                     case <-eth.shutdownChan:                         return                          case request := <-eth.bloomRequests: // request是一个通道                         task := <-request //从通道里面获取一个task                              task.Bitsets = make([][]byte, len(task.Sections))                         for i, section := range task.Sections {                             head := core.GetCanonicalHash(eth.chainDb, (section+1)*params.BloomBitsBlocks-1)                             blob, err := bitutil.DecompressBytes(core.GetBloomBits(eth.chainDb, task.Bit, section, head), int(params.BloomBitsBlocks)/8)                             if err != nil {                                 panic(err)                             }                             task.Bitsets[i] = blob                         }                         request <- task //通过request通道返回结果                     }                 }             }()         }     }

### 数据结构 BloomIndexer对象主要用户构建索引的过程,是core.ChainIndexer的一个接口实现,所以只实现了一些必须的接口。对于创建索引的逻辑还在core.ChainIndexer里面。

         // BloomIndexer implements a core.ChainIndexer, building up a rotated bloom bits index     // for the Ethereum header bloom filters, permitting blazing fast filtering.     type BloomIndexer struct {         size uint64 // section size to generate bloombits for              db ethdb.Database // database instance to write index data and metadata into         gen *bloombits.Generator // generator to rotate the bloom bits crating the bloom index              section uint64 // Section is the section number being processed currently 当前的section         head common.Hash // Head is the hash of the last header processed     }
    // NewBloomIndexer returns a chain indexer that generates bloom bits data for the     // canonical chain for fast logs filtering.     func NewBloomIndexer(db ethdb.Database, size uint64) *core.ChainIndexer {         backend := &BloomIndexer{             db: db,             size: size,         }         table := ethdb.NewTable(db, string(core.BloomBitsIndexPrefix))

本文发布于:2024-02-02 02:19:15,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170681461940760.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:以太   源码   eth
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23