crate::ix!();
#[derive(Clone,Default,Serialize,Deserialize)]
pub struct BloomFilter {
data: Vec<u8>,
n_hash_funcs: u32,
n_tweak: u32,
n_flags: u8,
}
impl BloomFilter {
pub fn new(
n_elements: u32,
n_fp_rate: f64,
n_tweak_in: u32,
n_flags_in: u8) -> Self {
let cap: usize = {
let n = n_elements as f64;
let lr = n_fp_rate.log10();
let m0 = -1.0 / LN2SQUARED * n * lr;
let m1 = MAX_BLOOM_FILTER_SIZE * 8;
let res = min(m0 as u32, m1 as u32) / 8;
res.try_into().unwrap()
};
let n_hash_funcs = {
let n = n_elements;
let cap8 = cap * 8;
let nln2 = ((n as f64) * LN2) as usize;
let m0 = (cap8 / nln2) as u32;
min(m0, MAX_HASH_FUNCS)
};
let n_tweak = n_tweak_in;
let n_flags = n_flags_in;
Self {
data: Vec::with_capacity(cap),
n_hash_funcs,
n_tweak,
n_flags,
}
}
#[inline] pub fn hash(&self,
n_hash_num: u32,
data_to_hash: &[u8]) -> u32 {
let x = murmur_hash3(
n_hash_num * 0xFBA4C795 + self.n_tweak,
data_to_hash
);
let modulus: u32 = (self.data.len() * 8).try_into().unwrap();
x % modulus
}
pub fn insert_key(&mut self, key: &[u8]) {
if self.data.is_empty() {
return;
}
for i in 0..self.n_hash_funcs {
let n_index: u32 = self.hash(i,key);
let pos: usize = (n_index >> 3).try_into().unwrap();
self.data[pos] |= (1 << (7 & n_index));
}
}
pub fn insert_outpoint(&mut self, outpoint: &OutPoint) {
let mut stream: DataStream
= DataStream::new(SER_NETWORK, PROTOCOL_VERSION);
stream.stream(outpoint);
self.insert_key(stream.as_slice());
}
pub fn contains_key(&self, key: &[u8]) -> bool {
if self.data.is_empty() {
return true;
}
for i in 0..self.n_hash_funcs {
let n_index: u32 = self.hash(i,key);
let pos: usize = (n_index >> 3).try_into().unwrap();
if (self.data[pos] & (1 << (7 & n_index))) == 0 {
return false;
}
}
true
}
pub fn contains_outpoint(&self, outpoint: &OutPoint) -> bool {
let mut stream: DataStream
= DataStream::new(
SER_NETWORK.try_into().unwrap(),
PROTOCOL_VERSION
);
stream.stream(&outpoint);
self.contains_key(stream.as_slice())
}
pub fn is_within_size_constraints(&self) -> bool {
return
self.data.len() <= MAX_BLOOM_FILTER_SIZE
&& self.n_hash_funcs <= MAX_HASH_FUNCS;
}
pub fn is_relevant_and_update(&mut self, tx: &Transaction) -> bool {
let mut found: bool = false;
if self.data.is_empty() {
return true;
}
let hash: &u256 = tx.get_hash();
if self.contains_key(hash.as_slice()) {
found = true;
}
for i in 0..tx.vout.len() {
let txout: &TxOut = &tx.vout[i];
let pubkey: &Script = &txout.script_pub_key;
let mut pc = pubkey.iter().peekable();
let mut data = Vec::<u8>::default();
let mut some_peek: bool = pc.peek().is_some();
while some_peek {
let mut opcode = OpcodeType::default();
if !pubkey.get_op(
&mut pc,
&mut opcode,
Some(&mut data)
) {
break;
}
if data.len() != 0 && self.contains_key(&data) {
found = true;
if (self.n_flags & BloomFlags::BLOOM_UPDATE_MASK as u8) == BloomFlags::BLOOM_UPDATE_ALL as u8 {
self.insert_outpoint(&OutPoint::new(hash,i.try_into().unwrap()));
} else {
if (self.n_flags & BloomFlags::BLOOM_UPDATE_MASK as u8) == BloomFlags::BLOOM_UPDATE_P2PUBKEY_ONLY as u8 {
let mut solutions = Vec::<Vec::<u8>>::default();
let ty: TxoutType = solver(&pubkey,&mut solutions);
if ty == TxoutType::PUBKEY || ty == TxoutType::MULTISIG {
self.insert_outpoint(&OutPoint::new(hash,i.try_into().unwrap()));
}
}
}
break;
}
some_peek = pc.peek().is_some();
}
}
if found {
return true;
}
for txin in tx.vin.iter() {
if self.contains_outpoint(&txin.prevout) {
return true;
}
let mut data = Vec::<u8>::default();
let mut pc = txin.script_sig.iter().peekable();
while pc.peek() != None {
let mut opcode = OpcodeType::default();
let op = txin.script_sig.get_op(
&mut pc,
&mut opcode,
Some(&mut data)
);
if !op {
break;
}
if data.len() != 0 && self.contains_key(data.as_slice()) {
return true;
}
}
}
false
}
}