def testNumberOfSetBitsNeverDecreases(self): n = 10 bf = BloomFilter(n, n) prev_cnt = 0 for i in range(n): bf.insert(str(i)) cnt = bf.count(True) self.assertTrue(cnt >= prev_cnt) prev_cnt = cnt
def testFalseNegativeNeverHappens(self): n = 10 inserted = [] bf = BloomFilter(n, n) for i in range(n): bf.insert(str(i)) inserted.append(i) for j in inserted: self.assertTrue(bf.query(j))
def get_dictionary_bloom(file_name): """ Get a dictionary as a Bloom filer data-structure from a text file. :param str file_name: name of the file storing the dictionary :return BloomFilter: dictionary """ bloom = BloomFilter() with open(file_name) as f: for line in f: bloom.insert(line.strip()) return bloom
def testInputIsFalsePositiveUntilInserted(self): n = 100 bf = BloomFilter(n / 2, n) fp = [False] * n inserted = [False] * n fp_cnt = 0 for i in range(n): bf.insert(str(i)) inserted[i] = True for j in range(n): if inserted[j]: continue # It was false positive before, it must continue # to be (since it was not inserted). if fp[j]: self.assertTrue(bf.query(j)) # Update false positives list elif bf.query(j): fp[j] = True fp_cnt += 1 # We're inserting more elements than the size of the array, so # there must be false positives. self.assertTrue(fp_cnt > 0)
def testInputIsFalsePositiveUntilInserted(self): n = 100 bf = BloomFilter(n/2, n) fp = [False]*n inserted = [False]*n fp_cnt = 0 for i in range(n): bf.insert(str(i)) inserted[i] = True for j in range(n): if inserted[j]: continue # It was false positive before, it must continue # to be (since it was not inserted). if fp[j]: self.assertTrue(bf.query(j)) # Update false positives list elif bf.query(j): fp[j] = True fp_cnt += 1 # We're inserting more elements than the size of the array, so # there must be false positives. self.assertTrue(fp_cnt > 0)
def bloom_filter_run(n, m, k=None): keys = range(n) # Random sampling without replacement random.shuffle(keys) probs = [] filter = BloomFilter(m, n, k) inserted = [False] * (n) for cnt, entry in enumerate(keys): filter.insert(str(entry)) inserted[entry] = True false_positives, total = 0, 0 # Compute false positives for probe in range(n): if not inserted[probe]: exists = filter.query(probe) if exists: false_positives += 1 total += 1 if total != 0: prob = false_positives * 1.0 / total probs.append(prob) return probs
class BitcoinClient(object): def __init__(self, addrs, params=MAINNET, user_agent="/pyBitcoin:0.1/", max_connections=10): self.addrs = addrs self.params = params self.user_agent = user_agent self.max_connections = max_connections self.peers = [] self.inventory = {} self.pending_txs = {} self.subscriptions = {} self.bloom_filter = BloomFilter(3, 0.01, random.getrandbits(32), BloomFilter.UPDATE_NONE) self.connect_to_peers() def connect_to_peers(self): if len(self.peers) < self.max_connections: shuffle(self.addrs) for i in range(self.max_connections - len(self.peers)): if len(self.addrs) > 0: addr = self.addrs.pop(0) peer = PeerFactory(self.params, self.user_agent, self.inventory, self.bloom_filter, self.on_peer_disconnected) reactor.connectTCP(addr[0], addr[1], peer) self.peers.append(peer) def on_peer_disconnected(self, peer): self.peers.remove(peer) self.connect_to_peers() def broadcast_tx(self, tx): """ Send the tx to half our peers, wait for half of the remainder to announce the tx before calling back True. """ def on_peer_anncounce(txid): self.pending_txs[txid][0] += 1 if self.pending_txs[txid][0] >= self.pending_txs[txid][1] / 2: if self.pending_txs[txid][3].active(): self.pending_txs[txid][3].cancel() self.pending_txs[txid][2].callback(True) d = defer.Deferred() self.inventory[bitcoin.txhash(tx)] = tx inv_packet = inv("TX", bitcoin.txhash(tx)) self.bloom_filter.insert(bitcoin.bin_txhash(tx)) self.pending_txs[bitcoin.txhash(tx)] = [ 0, len(self.peers) / 2, d, reactor.callLater(10, d.callback, False) ] for peer in self.peers[len(self.peers) / 2:]: peer.protocol.update_filter() peer.protocol.add_inv_callback(bitcoin.txhash(tx), on_peer_anncounce) for peer in self.peers[:len(self.peers) / 2]: peer.protocol.send_message(message(inv_packet, self.params)) return d def subscribe_address(self, address, callback): """ Listen for transactions on an address. Since we can't validate the transaction, we will only callback if a majority of our peers relay it. If less than a majority relay it, we will have to wait for block inclusion to callback. """ def on_peer_announce(tx): txhash = bitcoin.txhash(bitcoin.serialize(tx["tx"])) if txhash in self.subscriptions[address][0] and self.subscriptions[ address][0][txhash][0] != "complete": self.subscriptions[address][0][txhash][0] += 1 if self.subscriptions[address][0][txhash][ 0] >= self.subscriptions[address][0][txhash][1]: self.subscriptions[address][0][txhash][0] = "complete" self.subscriptions[address][1](tx["tx"]) elif txhash not in self.subscriptions[address][0]: self.subscriptions[address][0][txhash] = [ 1, len(self.peers) / 2 ] self.subscriptions[address] = [{}, callback] self.bloom_filter.insert(unhexlify(bitcoin.b58check_to_hex(address))) for peer in self.peers: peer.protocol.add_inv_callback(bitcoin.b58check_to_hex(address), on_peer_announce) peer.protocol.update_filter()
class BitcoinClient(object): def __init__(self, addrs, params=MAINNET, user_agent="/pyBitcoin:0.1/", max_connections=10): self.addrs = addrs self.params = params self.user_agent = user_agent self.max_connections = max_connections self.peers = [] self.inventory = {} self.pending_txs = {} self.subscriptions = {} self.bloom_filter = BloomFilter(3, 0.01, random.getrandbits(32), BloomFilter.UPDATE_NONE) self.connect_to_peers() def connect_to_peers(self): if len(self.peers) < self.max_connections: shuffle(self.addrs) for i in range(self.max_connections - len(self.peers)): if len(self.addrs) > 0: addr = self.addrs.pop(0) peer = PeerFactory(self.params, self.user_agent, self.inventory, self.bloom_filter, self.on_peer_disconnected) reactor.connectTCP(addr[0], addr[1], peer) self.peers.append(peer) def on_peer_disconnected(self, peer): self.peers.remove(peer) self.connect_to_peers() def broadcast_tx(self, tx): """ Send the tx to half our peers, wait for half of the remainder to announce the tx before calling back True. """ def on_peer_anncounce(txid): self.pending_txs[txid][0] += 1 if self.pending_txs[txid][0] >= self.pending_txs[txid][1] / 2: if self.pending_txs[txid][3].active(): self.pending_txs[txid][3].cancel() self.pending_txs[txid][2].callback(True) d = defer.Deferred() self.inventory[bitcoin.txhash(tx)] = tx inv_packet = inv("TX", bitcoin.txhash(tx)) self.bloom_filter.insert(bitcoin.bin_txhash(tx)) self.pending_txs[bitcoin.txhash(tx)] = [0, len(self.peers)/2, d, reactor.callLater(10, d.callback, False)] for peer in self.peers[len(self.peers)/2:]: peer.protocol.update_filter() peer.protocol.add_inv_callback(bitcoin.txhash(tx), on_peer_anncounce) for peer in self.peers[:len(self.peers)/2]: peer.protocol.send_message(message(inv_packet, self.params)) return d def subscribe_address(self, address, callback): """ Listen for transactions on an address. Since we can't validate the transaction, we will only callback if a majority of our peers relay it. If less than a majority relay it, we will have to wait for block inclusion to callback. """ def on_peer_announce(tx): txhash = bitcoin.txhash(bitcoin.serialize(tx["tx"])) if txhash in self.subscriptions[address][0] and self.subscriptions[address][0][txhash][0] != "complete": self.subscriptions[address][0][txhash][0] += 1 if self.subscriptions[address][0][txhash][0] >= self.subscriptions[address][0][txhash][1]: self.subscriptions[address][0][txhash][0] = "complete" self.subscriptions[address][1](tx["tx"]) elif txhash not in self.subscriptions[address][0]: self.subscriptions[address][0][txhash] = [1, len(self.peers)/2] self.subscriptions[address] = [{}, callback] self.bloom_filter.insert(unhexlify(bitcoin.b58check_to_hex(address))) for peer in self.peers: peer.protocol.add_inv_callback(bitcoin.b58check_to_hex(address), on_peer_announce) peer.protocol.update_filter()