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