@tevm/utils
Version:
A custom implementation of ethereumjs blockchain
105 lines (93 loc) • 2.92 kB
text/typescript
// This is adapted from @ethereumjs/vm package not the @ethereumjs/util package
import { DefensiveNullCheckError, InvalidBytesSizeError } from '@tevm/errors'
import { hexToBytes, keccak256 } from './viem.js'
const zeros = (bytes: number): Uint8Array => {
return new Uint8Array(bytes)
}
const BYTE_SIZE = 256
/**
* A simple Bloom filter implementation originally from ethereumjs
*/
export class Bloom {
bitvector: Uint8Array
/**
* Represents a Bloom filter.
* @throws {InvalidBytesSizeError} If the byte size of the bitvector is not 256.
*/
constructor(bitvector?: Uint8Array) {
if (!bitvector) {
this.bitvector = zeros(BYTE_SIZE)
} else {
if (bitvector.length !== BYTE_SIZE) throw new InvalidBytesSizeError(BYTE_SIZE, bitvector.length)
this.bitvector = bitvector
}
}
/**
* Adds an element to a bit vector of a 64 byte bloom filter.
* @param e - The element to add
* @throws {never}
*/
add(e: Uint8Array) {
const eBytes = hexToBytes(keccak256(e))
const mask = 2047 // binary 11111111111
for (let i = 0; i < 3; i++) {
const first2bytes = new DataView(eBytes.buffer).getUint16(i * 2)
const loc = mask & first2bytes
const byteLoc = loc >> 3
const bitLoc = 1 << (loc % 8)
let item = this.bitvector[BYTE_SIZE - byteLoc - 1]
if (item === undefined) {
throw new DefensiveNullCheckError('item is not defined. There is a bug in the implementation')
}
item |= bitLoc
this.bitvector[BYTE_SIZE - byteLoc - 1] = item
}
}
/**
* Checks if an element is in the bloom.
* @param e - The element to check
* @throws {never}
*/
check(e: Uint8Array): boolean {
const eBytes = hexToBytes(keccak256(e))
const mask = 2047 // binary 11111111111
let match = true
for (let i = 0; i < 3 && match; i++) {
const first2bytes = new DataView(eBytes.buffer).getUint16(i * 2)
const loc = mask & first2bytes
const byteLoc = loc >> 3
const bitLoc = 1 << (loc % 8)
const item = this.bitvector[BYTE_SIZE - byteLoc - 1]
if (item === undefined) {
throw new DefensiveNullCheckError('item is not defined. There is a bug in the implementation')
}
match = (item & bitLoc) !== 0
}
return Boolean(match)
}
/**
* Checks if multiple topics are in a bloom.
* @returns `true` if every topic is in the bloom
* @throws {never}
*/
multiCheck(topics: Uint8Array[]): boolean {
return topics.every((t: Uint8Array) => this.check(t))
}
/**
* Bitwise or blooms together.
* @throws {never}
*/
or(bloom: Bloom) {
for (let i = 0; i <= BYTE_SIZE; i++) {
const a = this.bitvector[i]
const b = bloom.bitvector[i]
if (a === undefined) {
throw new DefensiveNullCheckError('a is not defined. Please open an issue in the tevm github repo')
}
if (b === undefined) {
throw new DefensiveNullCheckError('b is not defined. Please open an issue in the tevm github repo')
}
this.bitvector[i] = a | b
}
}
}