def __init__(self,mongodbutil): self.itemArray = [] self.mongodbutil = mongodbutil originalBloom = self.readBloomValueFromFile() if originalBloom == '' : self.bloomFilter = BloomFilter() else: #self.bloomFilter = BloomFilter(int.from_bytes(originalBloom, byteorder='big')) self.bloomFilter = BloomFilter(int(originalBloom)) self.urlExist = False
def test_casting_to_integer(): bloom = BloomFilter() assert int(bloom) == 0 bloom.add(b'value 1') bloom.add(b'value 2') assert int( bloom ) == 1090215279796298345343057319992441901006450066263950115824040002588950485497113027143927523755823134941133023716890165043342811041924870874305880232180990464248298835944719578227183672673286106858273952584661686762419935928160959430409028732374024192153399763277382459194254234587232383494962731940352290891816707697788111127980409605093135659121120897102645250001200507634146244124778321795865777525978540960830042468420173693965828992647991129039043403835835590424035347457188427354145120006479590726476620907513681178254852999008485376
def __init__(self, status_code: bytes, gas_used: int, logs: Iterable[Log], bloom: int = None) -> None: if bloom is None: bloomables = itertools.chain.from_iterable(log.bloomables for log in logs) bloom = int(BloomFilter.from_iterable(bloomables)) super(Receipt, self).__init__( status_code=status_code, gas_used=gas_used, bloom=bloom, logs=logs, ) for log_idx, log in enumerate(self.logs): if log.address not in self.bloom_filter: raise ValidationError( "The address from the log entry at position {0} is not " "present in the provided bloom filter.".format(log_idx)) for topic_idx, topic in enumerate(log.topics): if int32.serialize(topic) not in self.bloom_filter: raise ValidationError( "The topic at position {0} from the log entry at " "position {1} is not present in the provided bloom " "filter.".format(topic_idx, log_idx))
def __init__(self, header: BlockHeader, transactions: Iterable[BaseTransaction] = None, xmessage_sent: Iterable[StretchXMessage] = None, xmessage_received: Iterable[StretchXMessageReceived] = None, uncles: Iterable[BlockHeader] = None) -> None: if transactions is None: transactions = [] if xmessage_sent is None: xmessage_sent = [] if xmessage_received is None: xmessage_received = [] if uncles is None: uncles = [] self.bloom_filter = BloomFilter(header.bloom) rlp.Serializable.__init__( self, header=header, transactions=transactions, xmessage_sent=xmessage_sent, xmessage_received=xmessage_received, uncles=uncles, )
def add_receipt_to_header(self, old_header: BlockHeaderAPI, receipt: ReceiptAPI) -> BlockHeaderAPI: return old_header.copy( bloom=int(BloomFilter(old_header.bloom) | receipt.bloom), gas_used=receipt.gas_used, state_root=self.state.make_state_root(), )
def add_transaction(self, transaction, computation, block): """ Add a transaction to the given block and return `trie_data` to store the transaction data in chaindb in VM layer. Update the bloom_filter, transaction trie and receipt trie roots, bloom_filter, bloom, and used_gas of the block. :param transaction: the executed transaction :param computation: the Computation object with executed result :param block: the Block which the transaction is added in :type transaction: Transaction :type computation: Computation :type block: Block :return: the block and the trie_data :rtype: (Block, dict[bytes, bytes]) """ receipt = self.make_receipt(transaction, computation) self.gas_used = receipt.gas_used new_header = block.header.copy( bloom=int(BloomFilter(block.header.bloom) | receipt.bloom), gas_used=receipt.gas_used, state_root=self.state_root, ) new_block = block.copy( header=new_header, transactions=tuple(block.transactions) + (transaction, ), ) return new_block, receipt
def add_receipt_to_header(self, old_header: BlockHeaderAPI, receipt: ReceiptAPI) -> BlockHeaderAPI: # Skip merkelizing the account data and persisting it to disk on every transaction. # Starting in Byzantium, this is no longer necessary, because the state root isn't # in the receipt anymore. return old_header.copy( bloom=int(BloomFilter(old_header.bloom) | receipt.bloom), gas_used=receipt.gas_used, )
async def poll_zeroex_logs_loop(self): while True: try: new_blocks: List[ AttributeDict] = await self._new_blocks_queue.get() for block in new_blocks: block_bloom_filter = BloomFilter( int.from_bytes(block["logsBloom"], byteorder='big')) if FILL_EVENT_TOPIC in block_bloom_filter: # Potentially a Fill for an order hash we are interested in order_hashes: List[str] = [] for order_hash in self._watch_order_hashes: if bytes.fromhex(order_hash) in block_bloom_filter: order_hashes.append("0x" + order_hash) if len(order_hashes) > 0: fill_entries = await self._get_logs({ 'topics': [ "0x6869791f0a34781b29882982cc39e882768cf2c96995c2a110c577c53bc932d5", None, None, order_hashes ], 'blockhash': block["hash"].hex() }) for fill_entry in fill_entries: event_data: AttributeDict = get_event_data( ABICodec(registry), self._event_abi, fill_entry) event_data_tx_hash: HexBytes = event_data[ "transactionHash"] # Skip any duplicates if event_data_tx_hash not in self._event_cache: await self._handle_event_data(event_data) # Mark all of these as processed now, since each tx may contain multiple Fill logs for fill_entry in fill_entries: event_data_tx_hash: HexBytes = fill_entry[ "transactionHash"] if event_data_tx_hash not in self._event_cache: self._event_cache.add(event_data_tx_hash) except asyncio.CancelledError: raise except asyncio.TimeoutError: continue except Exception: self.logger().network( "Unknown error trying to fetch new events for ZeroEx fills.", exc_info=True, app_warning_msg= "Unknown error trying to fetch new events for ZeroEx fills. " "Check wallet network connection")
def __init__(self, header, transactions=None, uncles=None): if transactions is None: transactions = [] if uncles is None: uncles = [] self.bloom_filter = BloomFilter(header.bloom) super().__init__( header=header, transactions=transactions, uncles=uncles, )
def test_bloom_filter_extend_method(log_entries): bloom = BloomFilter() for address, topics in log_entries: bloom.extend([address]) bloom.extend(topics) check_bloom(bloom, log_entries)
def test_casting_to_binary(): bloom = BloomFilter() assert bin(bloom) == '0b0' bloom.add(b'value 1') bloom.add(b'value 2') assert bin(bloom) == ( '0b1000000000000000000000000000000000000000000000000000000000000' '000000000000000000000000000000000000000000000000000100000000000' '000000000000000000000000000000000000000000000000000000000000000' '000000000000000000000000000000000000000000000000000000000000000' '000000000000000000000000000000000000000000000000000000000000000' '000000000000000000000000000000000000000000000000000000000000000' '010000000000000000000000000000000000000000000000000000000000000' '000000000000000000000000000000000000000000000000000000000000000' '000000000000000000000000000000000000000000000000000000000000000' '000000000000000000000000000000000000000000000000000000000000000' '000000000000000000000000000000000000000000000000000000000000000' '000000000000000000000000000000000000000000000000000000000000000' '000000000000000000000000000000000000000000000000000000000000000' '000000000000000000000000000000000000000000000000000000000000000' '000000000000000000010000000000000000000000000001000000000000000' '000000000000000000000000000000000000000000000000000000000000000' '000000000000000000000000000000000000000000000000000000000000000' '000000000000000000000000000000000000000000000000000000000000000' '000000000000000000000000000000000000000000000000000000000000000' '000000000000000000000000000000000000000000000000000000000000000' '000000000000000000000000000000000000000000000000000000000000000' '000000000000000000000000000000000000000000000000000000000000000' '000000000000000000000000000000000000000000000000000000000000000' '000000000000000000000000000000000000000000000000000000000000000' '000000000100000000000000000000000000000000000000000000000000000' '000000000000000000000000000000000000000000000000000000000000000' '000000000000000000000000000000000000000000000000000000000000000' '000000000000000000000000000000000000000000000000000000000000000' '00000000000000000000000')
def test_bloom_filter_add_method(log_entries): bloom = BloomFilter() for address, topics in log_entries: bloom.add(address) for topic in topics: bloom.add(topic) check_bloom(bloom, log_entries)
def __init__(self, header, chaindb, transactions=None, uncles=None): self.chaindb = chaindb if transactions is None: transactions = [] if uncles is None: uncles = [] self.bloom_filter = BloomFilter(header.bloom) super(FrontierBlock, self).__init__( header=header, transactions=transactions, uncles=uncles, )
def __init__(self, state_root: bytes, gas_used: int, logs: Iterable[Log], bloom: int=None) -> None: if bloom is None: bloomables = itertools.chain.from_iterable(log.bloomables for log in logs) bloom = int(BloomFilter.from_iterable(bloomables)) super().__init__( state_root=state_root, gas_used=gas_used, bloom=bloom, logs=logs, )
def __init__(self, header: BlockHeader, transactions: Iterable[BaseTransaction] = None, uncles: Iterable[BlockHeader] = None) -> None: if transactions is None: transactions = [] if uncles is None: uncles = [] self.bloom_filter = BloomFilter(header.bloom) super().__init__( header=header, transactions=transactions, uncles=uncles, )
def __init__(self, header: BlockHeaderAPI, transactions: Sequence[SignedTransactionAPI] = None, uncles: Sequence[BlockHeaderAPI] = None) -> None: if transactions is None: transactions = [] if uncles is None: uncles = [] self.bloom_filter = BloomFilter(header.bloom) super().__init__( header=header, transactions=transactions, uncles=uncles, )
def apply_transaction(self, transaction): """ Apply the transaction to the current block. This is a wrapper around :func:`~evm.vm.state.State.apply_transaction` with some extra orchestration logic. """ state_root, computation = self.state.apply_transaction(transaction) receipt = self.make_receipt(transaction, computation, self.state) # TODO: remove this mutation. self.state.gas_used = receipt.gas_used new_header = self.block.header.copy( bloom=int(BloomFilter(self.block.header.bloom) | receipt.bloom), gas_used=receipt.gas_used, state_root=state_root, ) return new_header, receipt, computation
def __init__(self, header, db, transactions=None, uncles=None): self.db = db if transactions is None: transactions = [] if uncles is None: uncles = [] self.bloom_filter = BloomFilter(header.bloom) self.transaction_db = Trie(db=self.db, root_hash=header.transaction_root) self.receipt_db = Trie(db=self.db, root_hash=header.receipt_root) super(FrontierBlock, self).__init__( header=header, transactions=transactions, uncles=uncles, )
def apply_transaction(self, header, transaction): """ Apply the transaction to the current block. This is a wrapper around :func:`~evm.vm.state.State.apply_transaction` with some extra orchestration logic. :param header: header of the block before application :param transaction: to apply """ self.validate_transaction_against_header(header, transaction) state_root, computation = self.state.apply_transaction(transaction) receipt = self.make_receipt(header, transaction, computation, self.state) new_header = header.copy( bloom=int(BloomFilter(header.bloom) | receipt.bloom), gas_used=receipt.gas_used, state_root=state_root, ) return new_header, receipt, computation
def apply_transaction(self, transaction): """ Apply the transaction to the vm in the current block. """ state_root, computation = self.state.apply_transaction(transaction) receipt = self.make_receipt(transaction, computation, self.state) # TODO: remove this mutation. self.state.gas_used = receipt.gas_used new_header = self.block.header.copy( bloom=int(BloomFilter(self.block.header.bloom) | receipt.bloom), gas_used=receipt.gas_used, state_root=state_root, ) self.block = self.block.copy( header=new_header, transactions=tuple(self.block.transactions) + (transaction,), ) return self.block, receipt, computation
def __init__(self, header, transactions=None, receive_transactions=None, reward_bundle=None): if transactions is None: transactions = [] if receive_transactions is None: receive_transactions = [] if reward_bundle is None: reward_bundle = StakeRewardBundle() self.bloom_filter = BloomFilter(header.bloom) super(HeliosTestnetBlock, self).__init__( header=header, transactions=transactions, receive_transactions=receive_transactions, reward_bundle=reward_bundle, )
def apply_send_transaction( self, header: BlockHeader, transaction: BaseTransaction, caller_chain_address: Address, validate: bool = True ) -> Tuple[BlockHeader, Receipt, BaseComputation]: """ Apply the transaction to the current block. This is a wrapper around :func:`~hvm.vm.state.State.apply_transaction` with some extra orchestration logic. :param header: header of the block before application :param transaction: to apply """ #caller_chain_address = header.sender #this is a send transaction send_transaction = transaction receive_transaction = None if validate: self.validate_transaction_against_header( header, send_transaction=send_transaction) computation, _ = self.state.apply_transaction( send_transaction=send_transaction, caller_chain_address=caller_chain_address, receive_transaction=receive_transaction, validate=validate) if validate: receipt = self.make_receipt(header, computation, send_transaction) new_header = header.copy( bloom=int(BloomFilter(header.bloom) | receipt.bloom), gas_used=receipt.gas_used, ) return new_header, receipt, computation else: return None, None, computation
def get_deposit_transactions_from_block(self, height: int) -> List[Deposit]: try: ret_deposit_txs = [] n_chain_lastest_height = self.myweb3.eth.blockNumber block_info = self.myweb3.eth.getBlock(BlockNumber(height), full_transactions=True) included_contracts = [] erc20_transfer_event = unhexlify(ERC20_TRANSFER_EVENT_HASH) n = int(hexlify(block_info.logsBloom).decode('latin1'), 16) bloom_filter = BloomFilter(n) # 测试合约地址是否存在 if erc20_transfer_event in bloom_filter: # 检查 transfer事件是否存在 for contract_addr in ERC20_CONTRACTS_LIST: con_addr = contract_addr.replace( '0x', '').lower() # 如果包含'0x'则去掉 '0x' con_addr_bytes = unhexlify(con_addr) if con_addr_bytes in bloom_filter: included_contracts.append(con_addr) del bloom_filter for tx_data in block_info["transactions"]: # 如果是创建合约, to是 null 或者是 挖矿交易 if tx_data['to'] is None: self.logger.info('tx_data["to"] is None') continue #因redis区分大小写, 所以统一使用小写进行redis匹配 to_addr = str(tx_data['to']).lower() from_addr = str(tx_data['from']).lower() # if str(to_addr).lower() == '0xa1f5c76f14b3aeb1fd615f569c67993e8d890112': # self.logger.info('-------------') if self.is_in_address_cache(address=to_addr): # 普通的ETH充币 # 普通的ETH转账 deposit_address = self.session.query(Address)\ .filter(Address.address == to_addr)\ .first() if deposit_address is None: self.logger.warning( f'not found address {to_addr} in databases!') continue deposit_tx = Deposit() deposit_tx.tx_hash = to_hex(tx_data["hash"]) deposit_tx.token_name = 'ETH' deposit_tx.notify_status = 0 deposit_tx.memo = None deposit_tx.pro_id = deposit_address.pro_id deposit_tx.from_addr = from_addr # tx_data['from'] deposit_tx.to_addr = to_addr #tx_data['to'] deposit_tx.amount = RoundDown( Web3.fromWei(tx_data["value"], 'ether')) deposit_tx.block_time = datetime.fromtimestamp( int(block_info.timestamp)), deposit_tx.tx_confirmations = n_chain_lastest_height - block_info[ 'number'] deposit_tx.block_height = block_info["number"] self.logger.info(f"found ETH deposit tx:{deposit_tx}") ret_deposit_txs.append(deposit_tx) self.refresh_deposit_address_balance(address=to_addr) continue # ETH归集 if self.is_in_address_cache(address=from_addr): self.refresh_deposit_address_balance(address=from_addr) pass # 继续判断是否包含 ERC20代币交易 if 0 == len(included_contracts): continue # 获取关心的ERC20代币转账 erc20_deposit_tx = self._get_erc20_token_deposit( tx_data, block_info, n_chain_lastest_height) if erc20_deposit_tx is not None: ret_deposit_txs.append(erc20_deposit_tx) self.logger.info( f"found ETH deposit tx:{erc20_deposit_tx}") pass return ret_deposit_txs except Exception as e: # traceback.print_exc() self.logger.error( f"get_deposit_transactions_from_block({height}) error:{e}") time.sleep(2) raise e pass
from eth_bloom import BloomFilter b = BloomFilter() print(b'a value' in b) print(type(b)) b.add(b'a value') a = int(b) print(bin(b)) print(b'a value' in b) print(int(b)) print(len(bin(b))) c = BloomFilter(bin(b)) print(b'a value' in b) url = 'http://163.com' print(bytes(url.encode('utf-8')) in b) b.add(bytes(url.encode('utf-8'))) print(bytes(url.encode('utf-8')) in b)
class Sinanews(object): def __init__(self,mongodbutil): self.itemArray = [] self.mongodbutil = mongodbutil originalBloom = self.readBloomValueFromFile() if originalBloom == '' : self.bloomFilter = BloomFilter() else: #self.bloomFilter = BloomFilter(int.from_bytes(originalBloom, byteorder='big')) self.bloomFilter = BloomFilter(int(originalBloom)) self.urlExist = False def get_page(self,code,url): self.itemArray = [] res = requests.get(url,timeout=10) res.encoding = "gbk" res.raise_for_status() if res.status_code == 200 : contentSoup = bs4.BeautifulSoup(res.text,'lxml') elems = contentSoup.select('#js_ggzx > li,.li_point > ul > li,.col02_22 > ul > li') for elem in elems: json = {} json['code'] = code ele = elem.select('span') json['date'] = ele[0].getText()[1:-1] s = json['date'] ele = elem.select('a') json['title'] = ele[len(ele)-1].getText() print("date:{},title:{}".format(s,json['title'])) json['href'] = ele[len(ele)-1].attrs['href'] ret,content = self.get_content(json['href']) if ret != -1 : time.sleep(4 * random.random()) if ret == 0 : json['content'] = content self.itemArray.append(json) def get_content(self,url): content = '' ret = -1 self.urlExist = bytes(url.encode('utf-8')) in self.bloomFilter if self.urlExist: print('This url:{} has existed'.format(url)) return ret, content else: self.bloomFilter.add(bytes(url.encode('utf-8'))) header = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36'} res = requests.get(url,headers=header,timeout=10) res.encoding = "utf-8" try: res.raise_for_status() except Exception as err: print(err) if res.status_code == 200: soup = bs4.BeautifulSoup(res.text,'lxml') elems = soup.select('#artibody,.entry-content') if len(elems) > 0 : content = elems[0].getText() ret = 0 return ret, content def get_item_array(self): return self.itemArray def writeBloomValueToFile(self): file = open(''.join((self.path(),'/bloom.txt')),'w+') file.write(str(self.bloomFilter.__int__())) file.close() def readBloomValueFromFile(self): file = None content = '' try: file = open(''.join((self.path(),'/bloom.txt')),'r') content = file.read() print(content) file.close() except Exception as err: print(err) return content # def addUrl(self,url): # self.urlExist = bytes(url.encode('utf-8')) in self.bloomFilter # if self.urlExist: # print('This url:{} has existed'.format(url)) # else: # self.bloomFilter.add(bytes(url.encode('utf-8'))) def path(self): return os.path.dirname(__file__)
def bloom_filter(self) -> BloomFilter: return BloomFilter(self.bloom)
import json from eth_bloom import BloomFilter data = json.load(open('data/addr_stats.json')) b = BloomFilter() for addr in data.keys(): b.add(bytes(addr.encode())) print(int(b)) print(bin(b))
def test_bloom_filter_from_iterable_method(log_entries): bloomables = itertools.chain.from_iterable( itertools.chain([address], topics) for address, topics in log_entries) bloom = BloomFilter.from_iterable(bloomables) check_bloom(bloom, log_entries)
def apply_receive_transaction( self, header: BlockHeader, receive_transaction: BaseReceiveTransaction, caller_chain_address: Address, validate: bool = True ) -> Tuple[Optional[BlockHeader], Optional[Receipt], BaseComputation, Optional[BaseReceiveTransaction]]: """ Apply the transaction to the current block. This is a wrapper around :func:`~hvm.vm.state.State.apply_transaction` with some extra orchestration logic. :param header: header of the block before application :param transaction: to apply """ # Lets make sure we have this receivable transaction in the account receivable_tx_key = self.state.account_db.get_receivable_transaction( caller_chain_address, receive_transaction.send_transaction_hash) # Very first thing, check to see if this transaction has been received before: try: block_hash, index, is_receive = self.chaindb.get_transaction_index( receive_transaction.hash) if self.chaindb.is_in_canonical_chain(block_hash): raise ValidationError( 'Tried to import a receive transaction that has already been received in the canonical chain' ) except TransactionNotFound: pass if receivable_tx_key is None: # There is no receivable transaction that matches this one. # now check to see if the block is in the canonical chain, but didnt have the transaction in it try: block_hash, index, is_receive = self.chaindb.get_transaction_index( receive_transaction.send_transaction_hash) if block_hash == receive_transaction.sender_block_hash: raise ValidationError( 'Receive transaction is invalid. We do have the send transaction and send block, but it has already been received.' ) else: raise ValidationError( 'Receive transaction is invalid. We have already imported this transaction, but it was from another block.' ) except TransactionNotFound: if self.chaindb.is_in_canonical_chain( receive_transaction.sender_block_hash): raise ValidationError( 'Receive transaction is invalid. We have the sender block, but it didn\'t contain the send transaction' ) if self.chaindb.exists(receive_transaction.send_transaction_hash): self.logger.debug( "The missing receivable transaction exists in the db but not canonical chain." ) if self.chaindb.is_in_canonical_chain( receive_transaction.sender_block_hash): self.logger.debug( "The sender block of the missing receivable transaction is in the canonical chain. This must means the tx is in there, but wasnt saved to canonical transactions..." ) raise ReceivableTransactionNotFound( "caller_chain_address = {}, send_transaction_hash = {}, sender_block_hash = {}" .format( encode_hex(caller_chain_address), encode_hex(receive_transaction.send_transaction_hash), encode_hex(receive_transaction.sender_block_hash), )) else: #now lets get all of the relevant transactions in this chain try: if receive_transaction.is_refund: #this is a refund transaction. We need to load the receive_transaction containing the refund and the send_transaction refund_transaction = receive_transaction block_hash, index, is_receive = self.chaindb.get_transaction_index( refund_transaction.send_transaction_hash) if block_hash != refund_transaction.sender_block_hash: raise ValidationError( "The sender_block_hash of this refund transaction doesn't match the block of the receive transaction" ) if not is_receive: raise ValidationError( "This refund transaction references a send transaction. This is not allowed." ) receive_transaction = self.chaindb.get_receive_transaction_by_index_and_block_hash( block_hash, index, self.get_receive_transaction_class(), ) else: refund_transaction = None block_hash, index, is_receive = self.chaindb.get_transaction_index( receive_transaction.send_transaction_hash) if block_hash != receive_transaction.sender_block_hash: raise ValidationError( "The sender_block_hash of this receive transaction doesn't match the block of the send transaction" ) if is_receive: raise ValidationError( "This receive transaction references another receive transaction. This is not allowed." ) send_transaction = self.chaindb.get_transaction_by_index_and_block_hash( block_hash, index, self.get_transaction_class(), ) except TransactionNotFound: raise ReceivableTransactionNotFound() # we assume past this point that, if it is a receive transaction, the send transaction exists in account computation, processed_transaction = self.state.apply_transaction( send_transaction=send_transaction, caller_chain_address=caller_chain_address, receive_transaction=receive_transaction, refund_transaction=refund_transaction, validate=validate) if validate: receipt = self.make_receipt(header, computation, send_transaction, receive_transaction, refund_transaction) new_header = header.copy( bloom=int(BloomFilter(header.bloom) | receipt.bloom), gas_used=receipt.gas_used, ) return new_header, receipt, computation, processed_transaction else: return None, None, computation, processed_transaction
def test_combining_filters(): b1 = BloomFilter() b2 = BloomFilter() b1.add(b'a') b1.add(b'b') b1.add(b'c') b2.add(b'd') b2.add(b'e') b2.add(b'f') b1.add(b'common') b2.add(b'common') assert b'a' in b1 assert b'b' in b1 assert b'c' in b1 assert b'a' not in b2 assert b'b' not in b2 assert b'c' not in b2 assert b'd' in b2 assert b'e' in b2 assert b'f' in b2 assert b'd' not in b1 assert b'e' not in b1 assert b'f' not in b1 assert b'common' in b1 assert b'common' in b2 b3 = b1 | b2 assert b'a' in b3 assert b'b' in b3 assert b'c' in b3 assert b'd' in b3 assert b'e' in b3 assert b'f' in b3 assert b'common' in b3 b4 = b1 + b2 assert b'a' in b4 assert b'b' in b4 assert b'c' in b4 assert b'd' in b4 assert b'e' in b4 assert b'f' in b4 assert b'common' in b4 b5 = BloomFilter(int(b1)) b5 |= b2 assert b'a' in b5 assert b'b' in b5 assert b'c' in b5 assert b'd' in b5 assert b'e' in b5 assert b'f' in b5 assert b'common' in b5 b6 = BloomFilter(int(b1)) b6 += b2 assert b'a' in b6 assert b'b' in b6 assert b'c' in b6 assert b'd' in b6 assert b'e' in b6 assert b'f' in b6 assert b'common' in b6