github.com/snowblossomcoin/go-ethereum@v1.9.25/core/types/bloom9.go (about)

     1  // Copyright 2014 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package types
    18  
    19  import (
    20  	"encoding/binary"
    21  	"fmt"
    22  	"math/big"
    23  
    24  	"github.com/ethereum/go-ethereum/common/hexutil"
    25  	"github.com/ethereum/go-ethereum/crypto"
    26  )
    27  
    28  type bytesBacked interface {
    29  	Bytes() []byte
    30  }
    31  
    32  const (
    33  	// BloomByteLength represents the number of bytes used in a header log bloom.
    34  	BloomByteLength = 256
    35  
    36  	// BloomBitLength represents the number of bits used in a header log bloom.
    37  	BloomBitLength = 8 * BloomByteLength
    38  )
    39  
    40  // Bloom represents a 2048 bit bloom filter.
    41  type Bloom [BloomByteLength]byte
    42  
    43  // BytesToBloom converts a byte slice to a bloom filter.
    44  // It panics if b is not of suitable size.
    45  func BytesToBloom(b []byte) Bloom {
    46  	var bloom Bloom
    47  	bloom.SetBytes(b)
    48  	return bloom
    49  }
    50  
    51  // SetBytes sets the content of b to the given bytes.
    52  // It panics if d is not of suitable size.
    53  func (b *Bloom) SetBytes(d []byte) {
    54  	if len(b) < len(d) {
    55  		panic(fmt.Sprintf("bloom bytes too big %d %d", len(b), len(d)))
    56  	}
    57  	copy(b[BloomByteLength-len(d):], d)
    58  }
    59  
    60  // Add adds d to the filter. Future calls of Test(d) will return true.
    61  func (b *Bloom) Add(d []byte) {
    62  	b.add(d, make([]byte, 6))
    63  }
    64  
    65  // add is internal version of Add, which takes a scratch buffer for reuse (needs to be at least 6 bytes)
    66  func (b *Bloom) add(d []byte, buf []byte) {
    67  	i1, v1, i2, v2, i3, v3 := bloomValues(d, buf)
    68  	b[i1] |= v1
    69  	b[i2] |= v2
    70  	b[i3] |= v3
    71  }
    72  
    73  // Big converts b to a big integer.
    74  // Note: Converting a bloom filter to a big.Int and then calling GetBytes
    75  // does not return the same bytes, since big.Int will trim leading zeroes
    76  func (b Bloom) Big() *big.Int {
    77  	return new(big.Int).SetBytes(b[:])
    78  }
    79  
    80  // Bytes returns the backing byte slice of the bloom
    81  func (b Bloom) Bytes() []byte {
    82  	return b[:]
    83  }
    84  
    85  // Test checks if the given topic is present in the bloom filter
    86  func (b Bloom) Test(topic []byte) bool {
    87  	i1, v1, i2, v2, i3, v3 := bloomValues(topic, make([]byte, 6))
    88  	return v1 == v1&b[i1] &&
    89  		v2 == v2&b[i2] &&
    90  		v3 == v3&b[i3]
    91  }
    92  
    93  // MarshalText encodes b as a hex string with 0x prefix.
    94  func (b Bloom) MarshalText() ([]byte, error) {
    95  	return hexutil.Bytes(b[:]).MarshalText()
    96  }
    97  
    98  // UnmarshalText b as a hex string with 0x prefix.
    99  func (b *Bloom) UnmarshalText(input []byte) error {
   100  	return hexutil.UnmarshalFixedText("Bloom", input, b[:])
   101  }
   102  
   103  // CreateBloom creates a bloom filter out of the give Receipts (+Logs)
   104  func CreateBloom(receipts Receipts) Bloom {
   105  	buf := make([]byte, 6)
   106  	var bin Bloom
   107  	for _, receipt := range receipts {
   108  		for _, log := range receipt.Logs {
   109  			bin.add(log.Address.Bytes(), buf)
   110  			for _, b := range log.Topics {
   111  				bin.add(b[:], buf)
   112  			}
   113  		}
   114  	}
   115  	return bin
   116  }
   117  
   118  // LogsBloom returns the bloom bytes for the given logs
   119  func LogsBloom(logs []*Log) []byte {
   120  	buf := make([]byte, 6)
   121  	var bin Bloom
   122  	for _, log := range logs {
   123  		bin.add(log.Address.Bytes(), buf)
   124  		for _, b := range log.Topics {
   125  			bin.add(b[:], buf)
   126  		}
   127  	}
   128  	return bin[:]
   129  }
   130  
   131  // Bloom9 returns the bloom filter for the given data
   132  func Bloom9(data []byte) []byte {
   133  	var b Bloom
   134  	b.SetBytes(data)
   135  	return b.Bytes()
   136  }
   137  
   138  // bloomValues returns the bytes (index-value pairs) to set for the given data
   139  func bloomValues(data []byte, hashbuf []byte) (uint, byte, uint, byte, uint, byte) {
   140  	sha := hasherPool.Get().(crypto.KeccakState)
   141  	sha.Reset()
   142  	sha.Write(data)
   143  	sha.Read(hashbuf)
   144  	hasherPool.Put(sha)
   145  	// The actual bits to flip
   146  	v1 := byte(1 << (hashbuf[1] & 0x7))
   147  	v2 := byte(1 << (hashbuf[3] & 0x7))
   148  	v3 := byte(1 << (hashbuf[5] & 0x7))
   149  	// The indices for the bytes to OR in
   150  	i1 := BloomByteLength - uint((binary.BigEndian.Uint16(hashbuf)&0x7ff)>>3) - 1
   151  	i2 := BloomByteLength - uint((binary.BigEndian.Uint16(hashbuf[2:])&0x7ff)>>3) - 1
   152  	i3 := BloomByteLength - uint((binary.BigEndian.Uint16(hashbuf[4:])&0x7ff)>>3) - 1
   153  
   154  	return i1, v1, i2, v2, i3, v3
   155  }
   156  
   157  // BloomLookup is a convenience-method to check presence int he bloom filter
   158  func BloomLookup(bin Bloom, topic bytesBacked) bool {
   159  	return bin.Test(topic.Bytes())
   160  }