def test_broadcast_events(self): """Test that broadcast_events works with a single subscriber to the sawtooth/block-commit event type and that the subscriber does not receive events until it is enabled. """ mock_service = Mock() mock_block_store = Mock() mock_receipt_store = Mock() event_broadcaster = EventBroadcaster(mock_service, mock_block_store, mock_receipt_store) block = create_block() event_broadcaster.chain_update(block, []) mock_service.send.assert_not_called() event_broadcaster.add_subscriber("test_conn_id", [create_block_commit_subscription()], []) event_broadcaster.chain_update(block, []) mock_service.send.assert_not_called() event_broadcaster.enable_subscriber("test_conn_id") event_broadcaster.chain_update(block, []) event_list = events_pb2.EventList( events=BlockEventExtractor(block).extract( [create_block_commit_subscription()])).SerializeToString() mock_service.send.assert_called_with( validator_pb2.Message.CLIENT_EVENTS, event_list, connection_id="test_conn_id")
def chain_update(self, block, receipts): """ Handles both "sawtooth/block-commit" Events and "settings/update" Events. For "sawtooth/block-commit", the last_block_num is updated or a fork is detected. For "settings/update", the corresponding cache entry will be updated. """ block_events = BlockEventExtractor(block).extract( [EventSubscription(event_type="sawtooth/block-commit")]) receipt_events = ReceiptEventExtractor(receipts).extract( [EventSubscription(event_type="settings/update")]) LOGGER.debug('SettingsObserver: chain_update receipt_events=%s', receipt_events) values = {} topology_update = False for event in receipt_events: if event.event_type == "settings/update": updated = event.attributes[0].value if updated not in values: if updated == 'bgx.consensus.pbft.nodes': topology_update = True values[updated] = True self._handle_txn_commit(event, updated) for event in block_events: forked = self._handle_block_commit(event) if forked: return topology_update return topology_update
def test_catchup_subscriber(self): """Test that catch subscriber handles the case of: - no blocks (i.e. the genesis block has not been produced or received - a block that has some receipts exists and sends results """ mock_service = Mock() mock_block_store = MagicMock() mock_block_store.chain_head = None mock_block_store.get_predecessor_iter.return_value = [] mock_receipt_store = Mock() event_broadcaster = EventBroadcaster(mock_service, mock_block_store, mock_receipt_store) event_broadcaster.add_subscriber( "test_conn_id", [create_block_commit_subscription()], []) event_broadcaster.catchup_subscriber("test_conn_id") mock_service.send.assert_not_called() block = create_block() mock_block_store.chain_head = block mock_block_store.get_predecessor_iter.return_value = [block] mock_block_store.__getitem__.return_value = block event_broadcaster.catchup_subscriber("test_conn_id") event_list = events_pb2.EventList( events=BlockEventExtractor(block).extract( [create_block_commit_subscription()])).SerializeToString() mock_service.send.assert_called_with( validator_pb2.Message.CLIENT_EVENTS, event_list, connection_id="test_conn_id", one_way=True)
def do_block_event_extractor(): block_header = BlockHeader(block_num=85, state_root_hash="0987654321fedcba", previous_block_id="0000000000000000") block = BlockWrapper( Block(header_signature="abcdef1234567890", header=block_header.SerializeToString())) extractor = BlockEventExtractor(block) events = extractor.extract( [EventSubscription(event_type="sawtooth/block-commit")]) assert events == [ Event(event_type="sawtooth/block-commit", attributes=[ Event.Attribute(key="block_id", value="abcdef1234567890"), Event.Attribute(key="block_num", value="85"), Event.Attribute(key="state_root_hash", value="0987654321fedcba"), Event.Attribute(key="previous_block_id", value="0000000000000000") ]) ]
def get_events_for_block(self, blkw, subscriptions): receipts = [] for batch in blkw.block.batches: for txn in batch.transactions: try: receipts.append( self._receipt_store.get(txn.header_signature)) except KeyError: LOGGER.warning( "Transaction id %s not found in receipt store " " while looking" " up events for block id %s", txn.header_signature[:10], blkw.identifier[:10]) block_event_extractor = BlockEventExtractor(blkw) receipt_event_extractor = ReceiptEventExtractor(receipts=receipts) events = [] events.extend(block_event_extractor.extract(subscriptions)) events.extend(receipt_event_extractor.extract(subscriptions)) return events
def test_block_event_extractor(self): """Test that a sawtooth/block-commit event is generated correctly.""" block_header = BlockHeader( block_num=85, state_root_hash="0987654321fedcba", previous_block_id="0000000000000000") block = BlockWrapper(Block( header_signature="abcdef1234567890", header=block_header.SerializeToString())) extractor = BlockEventExtractor(block) events = extractor.extract([EventSubscription( event_type="sawtooth/block-commit")]) self.assertEqual(events, [ Event( event_type="sawtooth/block-commit", attributes=[ Event.Attribute(key="block_id", value="abcdef1234567890"), Event.Attribute(key="block_num", value="85"), Event.Attribute( key="state_root_hash", value="0987654321fedcba"), Event.Attribute( key="previous_block_id", value="0000000000000000")])])
def get_events_for_block(self, blkw, subscriptions): receipts = [] for batch in blkw.block.batches: for txn in batch.transactions: try: receipts.append(self._receipt_store.get( txn.header_signature)) except KeyError: LOGGER.warning( "Transaction id %s not found in receipt store " " while looking" " up events for block id %s", txn.header_signature[:10], blkw.identifier[:10]) block_event_extractor = BlockEventExtractor(blkw) receipt_event_extractor = ReceiptEventExtractor(receipts=receipts) events = [] events.extend(block_event_extractor.extract(subscriptions)) events.extend(receipt_event_extractor.extract(subscriptions)) return events
def test_block_event_extractor(self): """Test that a sawtooth/block-commit event is generated correctly.""" block_header = BlockHeader(block_num=85, state_root_hash="0987654321fedcba", previous_block_id="0000000000000000") block = BlockWrapper( Block(header_signature="abcdef1234567890", header=block_header.SerializeToString())) extractor = BlockEventExtractor(block) events = extractor.extract( [EventSubscription(event_type="sawtooth/block-commit")]) self.assertEqual(events, [ Event(event_type="sawtooth/block-commit", attributes=[ Event.Attribute(key="block_id", value="abcdef1234567890"), Event.Attribute(key="block_num", value="85"), Event.Attribute(key="state_root_hash", value="0987654321fedcba"), Event.Attribute(key="previous_block_id", value="0000000000000000") ]) ])
def chain_update(self, block, receipts): extractors = [ BlockEventExtractor(block), ReceiptEventExtractor(receipts), ] subscriptions = [] for subscriber in self._subscribers.values(): for subscription in subscriber.subscriptions: if subscription not in subscriptions: subscriptions.append(subscription) events = [] for extractor in extractors: extracted_events = extractor.extract(subscriptions) if extracted_events: events.extend(extracted_events) if events: self.broadcast_events(events)
def chain_update(self, block, receipts): """ Handles both "block_commit" Events and "identity_update" Events. For "block_commit", the last_block_num is updated or a fork is detected. For "identity_update", the corresponding cache entry will be updated. """ block_events = BlockEventExtractor(block).extract( [EventSubscription(event_type="block_commit")]) receipt_events = ReceiptEventExtractor(receipts).extract( [EventSubscription(event_type="identity_update")]) for event in block_events: forked = self._handle_block_commit(event) if forked: return for event in receipt_events: if event.event_type == "identity_update": self._handle_txn_commit(event)
def get_events_for_block_ids(self, block_ids, subscriptions): """Get a list of events associated with all the block ids. Args: block_ids (list of str): The block ids to search for events that match each subscription. subscriptions (list of EventSubscriptions): EventFilter and event type to filter events. Returns (list of Events): The Events associated which each block id. Raises: KeyError A block id isn't found within the block store. """ events = [] extractors = [] for block_id in block_ids: blk_w = self._block_store[block_id] extractors.append(BlockEventExtractor(blk_w)) receipts = [] for batch in blk_w.block.batches: for txn in batch.transactions: try: receipts.append( self._receipt_store.get(txn.header_signature)) except KeyError: LOGGER.warning( "Transaction id %s not found in receipt store " " while looking" " up events for block id %s", txn.header_signature[:10], block_id[:10]) extractors.append(ReceiptEventExtractor(receipts=receipts)) for extractor in extractors: events.extend(extractor.extract(subscriptions)) return events