一. 以太坊中的Bloom filter 的使用
以太坊中,通过eth_getTransactionReceipt方法获取交易收据。
eth_getTransactionReceipt 得到的结果如下:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"blockHash": "0x04099d9fff6403bf6518ccc94a1d4ed19e5e00f61a1fa43b1ef528e97a8c2ad4",
"blockNumber": "0x260",
"contractAddress": "0xdbd3c12200b337791eaa7acf28fce3ab96dedab9",
"cumulativeGasUsed": "0x408a89",
"from": "0x385df4353966d91fbad2d287c46d4e89c4934c7e",
"gasUsed": "0x408a89",
"logs": [
{
"address": "0xdbd3c12200b337791eaa7acf28fce3ab96dedab9",
"topics": [
"0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0",
"0x0000000000000000000000000000000000000000000000000000000000000000",
"0x000000000000000000000000385df4353966d91fbad2d287c46d4e89c4934c7e"
],
"data": "0x",
"blockNumber": "0x260",
"transactionHash": "0x7462fc45f454ccdac2fc166ae05f91e800c5d2bfa5a65d3a6c3732eefdbc94d9",
"transactionIndex": "0x0",
"blockHash": "0x04099d9fff6403bf6518ccc94a1d4ed19e5e00f61a1fa43b1ef528e97a8c2ad4",
"logIndex": "0x0",
"removed": false
}
],
"logsBloom": "0x00000000000000000000200000000800000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000400000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000080000000040000000000000000000000000000000000040",
"status": "0x1",
"to": null,
"transactionHash": "0x7462fc45f454ccdac2fc166ae05f91e800c5d2bfa5a65d3a6c3732eefdbc94d9",
"transactionIndex": "0x0"
}
}
在reciept中会为日志数据生成一个Bloom过滤器,在func (pre *Prestate) Apply 方法中:
CreateBloom方法:
// CreateBloom creates a bloom filter out of the give Receipts (+Logs)
func CreateBloom(receipts Receipts) Bloom {
buf := make([]byte, 6)
var bin Bloom
for _, receipt := range receipts {
for _, log := range receipt.Logs {
bin.add(log.Address.Bytes(), buf)
for _, b := range log.Topics {
bin.add(b[:], buf)
}
}
}
return bin
}
那么,bloom的作用是什么呢?
布隆过滤器并不是以太坊的专属,Bloom Filter是1970年由布隆提出的,特点是非常节省空间的概率数据结构,运行速度快,占用内存小,缺点是有一定的误判率。
很多场景中,都存在判断一个元素是否存在的需求,比较熟知的方法是采用 HashMap的数据结构,使用put方法存储数据,然后通过取值或者判断存在等方式来确定,在区块链中,在链式结构存储了大量数据以后,采用这种方式需要大量查询,就会非常耗费资源,检索的速度会越来越慢。所以以太坊使用了bloom过滤器来快速查询日志。
我们来看一下以太坊中Bloom:
// Bloom represents a 2048 bit bloom filter.
type Bloom [BloomByteLength]byte
它实际上是一个很长的二进制向量和一系列随机映射函数组成,主要用于判断一个元素是否在一个集合中。
需要注意的是,以太坊的bloom过滤器适合大量数据中高效判断元素是否存在,但是并不存储数据本身,仅存储hash结果取模运算后的位标记。过滤结果如果是存在于,实际情况不一定存在,但是判断结果为不存在时,则一定不存在,基于这个特点,以太坊中的判断逻辑是,根据bloom和过滤的参数判定是否存在,不存在则直接返回。
// blockLogs returns the logs matching the filter criteria within a single block.
func (f *Filter) blockLo