github.com/baptiste-b-pegasys/quorum/v22@v22.4.2/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  // Quorum
    74  // OrBloom executes an Or operation on the bloom
    75  func (b *Bloom) OrBloom(bl []byte) {
    76  	bin := new(big.Int).SetBytes(b[:])
    77  	input := new(big.Int).SetBytes(bl[:])
    78  	bin.Or(bin, input)
    79  	b.SetBytes(bin.Bytes())
    80  }
    81  
    82  // Big converts b to a big integer.
    83  // Note: Converting a bloom filter to a big.Int and then calling GetBytes
    84  // does not return the same bytes, since big.Int will trim leading zeroes
    85  func (b Bloom) Big() *big.Int {
    86  	return new(big.Int).SetBytes(b[:])
    87  }
    88  
    89  // Bytes returns the backing byte slice of the bloom
    90  func (b Bloom) Bytes() []byte {
    91  	return b[:]
    92  }
    93  
    94  // Test checks if the given topic is present in the bloom filter
    95  func (b Bloom) Test(topic []byte) bool {
    96  	i1, v1, i2, v2, i3, v3 := bloomValues(topic, make([]byte, 6))
    97  	return v1 == v1&b[i1] &&
    98  		v2 == v2&b[i2] &&
    99  		v3 == v3&b[i3]
   100  }
   101  
   102  // MarshalText encodes b as a hex string with 0x prefix.
   103  func (b Bloom) MarshalText() ([]byte, error) {
   104  	return hexutil.Bytes(b[:]).MarshalText()
   105  }
   106  
   107  // UnmarshalText b as a hex string with 0x prefix.
   108  func (b *Bloom) UnmarshalText(input []byte) error {
   109  	return hexutil.UnmarshalFixedText("Bloom", input, b[:])
   110  }
   111  
   112  // CreateBloom creates a bloom filter out of the give Receipts (+Logs)
   113  func CreateBloom(receipts Receipts) Bloom {
   114  	buf := make([]byte, 6)
   115  	var bin Bloom
   116  	for _, receipt := range receipts {
   117  		for _, log := range receipt.Logs {
   118  			bin.add(log.Address.Bytes(), buf)
   119  			for _, b := range log.Topics {
   120  				bin.add(b[:], buf)
   121  			}
   122  		}
   123  	}
   124  	return bin
   125  }
   126  
   127  // LogsBloom returns the bloom bytes for the given logs
   128  func LogsBloom(logs []*Log) []byte {
   129  	buf := make([]byte, 6)
   130  	var bin Bloom
   131  	for _, log := range logs {
   132  		bin.add(log.Address.Bytes(), buf)
   133  		for _, b := range log.Topics {
   134  			bin.add(b[:], buf)
   135  		}
   136  	}
   137  	return bin[:]
   138  }
   139  
   140  // Bloom9 returns the bloom filter for the given data
   141  func Bloom9(data []byte) []byte {
   142  	var b Bloom
   143  	b.SetBytes(data)
   144  	return b.Bytes()
   145  }
   146  
   147  // bloomValues returns the bytes (index-value pairs) to set for the given data
   148  func bloomValues(data []byte, hashbuf []byte) (uint, byte, uint, byte, uint, byte) {
   149  	sha := hasherPool.Get().(crypto.KeccakState)
   150  	sha.Reset()
   151  	sha.Write(data)
   152  	sha.Read(hashbuf)
   153  	hasherPool.Put(sha)
   154  	// The actual bits to flip
   155  	v1 := byte(1 << (hashbuf[1] & 0x7))
   156  	v2 := byte(1 << (hashbuf[3] & 0x7))
   157  	v3 := byte(1 << (hashbuf[5] & 0x7))
   158  	// The indices for the bytes to OR in
   159  	i1 := BloomByteLength - uint((binary.BigEndian.Uint16(hashbuf)&0x7ff)>>3) - 1
   160  	i2 := BloomByteLength - uint((binary.BigEndian.Uint16(hashbuf[2:])&0x7ff)>>3) - 1
   161  	i3 := BloomByteLength - uint((binary.BigEndian.Uint16(hashbuf[4:])&0x7ff)>>3) - 1
   162  
   163  	return i1, v1, i2, v2, i3, v3
   164  }
   165  
   166  // BloomLookup is a convenience-method to check presence int he bloom filter
   167  func BloomLookup(bin Bloom, topic bytesBacked) bool {
   168  	return bin.Test(topic.Bytes())
   169  }