github.com/amazechain/amc@v0.1.3/internal/avm/types/bloom9.go (about)

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