Ejemplo n.º 1
0
def zmq_socket(ws):
    """
    Note: Currently unused
    This transfers data from ZMQ to a web socket.
    The idea was to do some pre-processing in Python
    before handing it to the WebSocket and consume it
    in the web interface.
    However from the documentation it's not very clear
    how the data provided in `EventList` is formatted.
    """
    LOGGER.debug("Entering ZMQ loop")
    while True:
        resp = socket.recv_multipart()[-1]

        msg = Message()
        msg.ParseFromString(resp)

        if msg.message_type == Message.CLIENT_EVENTS:
            events = EventList()
            events.ParseFromString(msg.content)
            LOGGER.debug("Received events")
            LOGGER.debug(events)
            # Eventually what we want to do here is ws.send(events)
            # But before we have to unpack and pre-process it.
        elif msg.message_type == Message.PING_REQUEST:
            LOGGER.debug("Received ping request")
            ws.send("ping request")
        else:
            LOGGER.warn("Unexpected message type '{}'".format(
                msg.message_type
            ))
Ejemplo n.º 2
0
    def run(self) -> None:
        if not self._is_active:
            LOGGER.error('Subscriber is inactive, Quitting...')
            return

        LOGGER.info('Starting the logging on {}'.format(self._event_log_file))

        with open(self._event_log_file, 'w+', newline='') as log_file:
            writer = csv.writer(log_file)
            writer.writerow(['time', 'events_received'])

            while self._is_active:

                LOGGER.debug('Waiting for events')

                message_future = self._stream.receive()

                event_list = EventList()
                event_list.ParseFromString(message_future.result().content)

                LOGGER.debug('Received {} event(s)'.format(
                    len(event_list.events)))

                writer.writerow([time.time(), len(event_list.events)])

                self.counter += len(event_list.events)
                if self.counter == self._expected_event_count:
                    self._is_active = False

        LOGGER.debug('Existing subscription loop')
Ejemplo n.º 3
0
    def start(self, known_ids=None):
        """Subscribes to state delta events, and then waits to receive deltas.
        Sends any events received to delta handlers.
        """
        if not known_ids:
            known_ids = [NULL_BLOCK_ID]

        self._stream.wait_for_ready()
        LOGGER.debug('Subscribing to state delta events')

        block_sub = EventSubscription(event_type='sawtooth/block-commit')
        delta_sub = EventSubscription(
            event_type='sawtooth/state-delta',
            filters=[
                EventFilter(key='address',
                            match_string='^{}.*'.format(NAMESPACE),
                            filter_type=EventFilter.REGEX_ANY)
            ])

        request = ClientEventsSubscribeRequest(
            last_known_block_ids=known_ids,
            subscriptions=[block_sub, delta_sub])
        response_future = self._stream.send(
            Message.CLIENT_EVENTS_SUBSCRIBE_REQUEST,
            request.SerializeToString())
        response = ClientEventsSubscribeResponse()
        response.ParseFromString(response_future.result().content)

        # Forked all the way back to genesis, restart with no known_ids
        if (response.status == ClientEventsSubscribeResponse.UNKNOWN_BLOCK
                and known_ids):
            return self.start()

        if response.status != ClientEventsSubscribeResponse.OK:
            raise RuntimeError('Subscription failed with status: {}'.format(
                ClientEventsSubscribeResponse.Status.Name(response.status)))

        self._is_active = True

        LOGGER.debug('Successfully subscribed to state delta events')
        while self._is_active:
            message_future = self._stream.receive()

            event_list = EventList()
            event_list.ParseFromString(message_future.result().content)
            for handler in self._event_handlers:
                handler(event_list.events)
Ejemplo n.º 4
0
 def _process(self, msg: Message) -> None:
     event_list = EventList()
     event_list.ParseFromString(msg.content)
     events = event_list.events
     raw_block = next(
         (e for e in events if e.event_type == "sawtooth/block-commit"), [])
     block = {b.key: b.value for b in raw_block.attributes}
     LOG.debug(f"Block: {block}")
     event = next(
         (e for e in events if e.event_type == "sawtooth/state-delta"),
         None)
     if event:
         state_changes = StateChangeList()
         state_changes.ParseFromString(event.data)
         changes = list(state_changes.state_changes)
         LOG.debug(f"Found {len(changes)} state changes")
         self._handle_changes(block, changes)
Ejemplo n.º 5
0
def _create_event_payload(event_type, attributes):
    return EventList(events=[
        Event(event_type=Events.REMME_BATCH_DELTA.value,
              attributes=[
                  Event.Attribute(key=attr_k, value=attr_v)
                  for attr_k, attr_v in attributes.items()
              ])
    ])
Ejemplo n.º 6
0
    def listen_to_event(self):
        self._stream.wait_for_ready()
        # Step 1: Construct a Subscription
        block_sub = EventSubscription(event_type='sawtooth/block-commit')

        # Step 2: Submit the Event Subscription
        request = ClientEventsSubscribeRequest(subscriptions=[block_sub])

        response_future = self._stream.send(
            Message.CLIENT_EVENTS_SUBSCRIBE_REQUEST,
            request.SerializeToString())

        response = ClientEventsSubscribeResponse()
        response.ParseFromString(response_future.result().content)

        # Listen for events in an infinite loop
        LOGGER.warning("Listening to events.")
        while True:
            msg = self._stream.receive()
            event_list = EventList()
            event_list.ParseFromString(msg.result().content)
            for handler in self._event_handlers:
                handler(event_list.events)
Ejemplo n.º 7
0
async def _process_msg(request, msg):
    LOGGER.debug(f'Message type: {msg.message_type}')

    if msg.message_type != Message.CLIENT_EVENTS:
        LOGGER.debug(f'Skip unexpected msg type {msg.message_type}')
        return

    evt_resp = EventList()
    evt_resp.ParseFromString(msg.content)

    ws = request.ws
    subsevt = request.rpc._subsevt.get(ws, {})

    for proto_data in evt_resp.events:
        evt = message_to_dict(proto_data)
        LOGGER.debug(f'Dicted response evt: {evt}')

        event_type = evt['event_type']

        evt_names = SAWTOOTH_TO_REMME_EVENT.get(event_type)
        if not evt_names:
            LOGGER.debug(f'Evt names for type "{event_type}" '
                         'not configured')
            continue

        for evt_name in evt_names:
            evt_tr = EVENT_HANDLERS[evt_name]

            # Check if evt_name is subscribed
            if evt_name not in subsevt:
                LOGGER.debug('No active ws connection '
                             f'for evt "{evt_name}"')
                continue

            # Check if ws has stored hashes
            if ws not in request.rpc._evthashes:
                LOGGER.warning(f'Connection {ws} not found')
                del subsevt[evt_name]
                continue

            # get response of updated state
            LOGGER.debug(f'Got evt data: {evt}')
            updated_state = evt_tr.parse_evt(evt)
            if not updated_state:
                LOGGER.debug('Skiping evt with no state update')
                continue

            validated_data = subsevt[evt_name]['validated_data']
            LOGGER.debug(f'Loaded validated data: {validated_data}')
            msg_id = subsevt[evt_name]['msg_id']

            response = evt_tr.prepare_response(updated_state, validated_data)
            if asyncio.iscoroutine(response):
                response = await response

            if not response:
                LOGGER.debug('Skiping evt with empty response')
                continue

            LOGGER.debug(f'Got response: {response}')
            evthash = evt_tr.prepare_evt_hash(response)
            LOGGER.debug(f'Evt hash calculated: {evthash}')

            # Check if we already have sent update
            if evthash in request.rpc._evthashes[ws]:
                LOGGER.debug(f'Connection {ws} already '
                             'received this notification')
                continue

            result = encode_result(msg_id, {
                'event_type': evt_name,
                'attributes': response
            })
            await request.rpc._ws_send_str(request, result)

            request.rpc._evthashes[ws].add(evthash)
Ejemplo n.º 8
0
    def subscribe(self, event_name: str, is_write_to_file=False, file_name='certificate.pem'):
        subscription = EventSubscription(event_type="ca_1/{}".format(event_name))

        # Setup a connection to the validator
        ctx = zmq.Context()
        socket = ctx.socket(zmq.DEALER)
        socket.connect('tcp://127.0.0.1:4004')

        # Construct the request
        request = ClientEventsSubscribeRequest(
            subscriptions=[subscription]).SerializeToString()

        # Construct the message wrapper
        correlation_id = "123"  # This must be unique for all in-process requests
        msg = Message(
            correlation_id=correlation_id,
            message_type=Message.CLIENT_EVENTS_SUBSCRIBE_REQUEST,
            content=request)

        # Send the request
        socket.send_multipart([msg.SerializeToString()])

        # Receive the response
        resp = socket.recv_multipart()[-1]

        # Parse the message wrapper
        msg = Message()
        msg.ParseFromString(resp)

        # Validate the response type
        if msg.message_type != Message.CLIENT_EVENTS_SUBSCRIBE_RESPONSE:
            print("Unexpected message type")
            return

        # Parse the response
        response = ClientEventsSubscribeResponse()
        response.ParseFromString(msg.content)

        # Validate the response status
        if response.status != ClientEventsSubscribeResponse.OK:
            print("Subscription failed: {}".format(response.response_message))
            return

        resp = socket.recv_multipart()[-1]

        # Parse the message wrapper
        msg = Message()
        msg.ParseFromString(resp)

        # Validate the response type
        if msg.message_type != Message.CLIENT_EVENTS:
            print("Unexpected message type")
            return

        # Parse the response
        events = EventList()
        events.ParseFromString(msg.content)

        for event in events.events:
            if event.data is not None:
                if is_write_to_file:
                    write_to_file(file_name, event.data)
                else:
                    print(event.data)

        # Construct the request
        request = ClientEventsUnsubscribeRequest().SerializeToString()

        # Construct the message wrapper
        correlation_id = "124"  # This must be unique for all in-process requests
        msg = Message(
            correlation_id=correlation_id,
            message_type=Message.CLIENT_EVENTS_UNSUBSCRIBE_REQUEST,
            content=request)

        # Send the request
        socket.send_multipart([msg.SerializeToString()])

        # Receive the response
        resp = socket.recv_multipart()[-1]

        # Parse the message wrapper
        msg = Message()
        msg.ParseFromString(resp)

        # Validate the response type
        if msg.message_type != Message.CLIENT_EVENTS_UNSUBSCRIBE_RESPONSE:
            print("Unexpected message type")

        # Parse the response
        response = ClientEventsUnsubscribeResponse()
        response.ParseFromString(msg.content)

        # Validate the response status
        if response.status != ClientEventsUnsubscribeResponse.OK:
            print("Unsubscription failed: {}".format(response.response_message))

        # Close the connection to the validator
        socket.close()
Ejemplo n.º 9
0
def subscribe_event():
    """
     A custom management command to store block information of each block data by event subscription.
     this command is calling from docker-compose file
    """
    logger.info("event function start..")
    # Setup a connection to the validator
    ctx = zmq.Context()
    socket = ctx.socket(zmq.DEALER)
    socket.connect(validator_url)

    # -------------------------------#
    # Submit the Event Subscription  #
    # -------------------------------#

    # subscribe both both "block commit" and "state-delta" event
    block_sub = EventSubscription(event_type='sawtooth/block-commit')
    delta_sub = EventSubscription(
        event_type='sawtooth/state-delta',
        filters=[
            EventFilter(key='address',
                        match_string='^{}.*'.format(NAMESPACE),
                        filter_type=EventFilter.REGEX_ANY)
        ])

    # Construct the request
    request = ClientEventsSubscribeRequest(
        subscriptions=[block_sub, delta_sub]).SerializeToString()

    # Construct the message wrapper
    correlation_id = "123"  # This must be unique for all in-process requests
    msg = Message(correlation_id=correlation_id,
                  message_type=Message.CLIENT_EVENTS_SUBSCRIBE_REQUEST,
                  content=request)

    # Send the request
    socket.send_multipart([msg.SerializeToString()])

    #
    # -------------------------------#
    #     Receive the response       #
    # -------------------------------#

    resp = socket.recv_multipart()[-1]

    # Parse the message wrapper
    msg = Message()
    msg.ParseFromString(resp)

    # Validate the response type
    if msg.message_type != Message.CLIENT_EVENTS_SUBSCRIBE_RESPONSE:
        logger.error("Unexpected message type")
        return

    # Parse the response
    response = ClientEventsSubscribeResponse()
    response.ParseFromString(msg.content)

    # Validate the response status
    if response.status != ClientEventsSubscribeResponse.OK:
        return

    while True:
        resp = socket.recv_multipart()[-1]

        # Parse the message wrapper
        msg = Message()
        msg.ParseFromString(resp)

        # Validate the response type
        if msg.message_type != Message.CLIENT_EVENTS:
            return

        # Parse the response
        events = EventList()
        events.ParseFromString(msg.content)
        block_info = {"address": []}
        event_data = MessageToDict(events)
        events_list = event_data["events"]
        for event in events_list:
            attributes = event["attributes"]

            for attr in attributes:
                key = attr["key"]
                value = attr["value"]
                if key == 'address':
                    block_info["address"].append(value)
                else:
                    block_info[key] = value

        address_list = block_info["address"]
        for address in address_list:
            BlockInfo.objects.create(
                block_num=block_info["block_num"],
                block_id=block_info["block_id"],
                state_root_hash=block_info["state_root_hash"],
                previous_block_id=block_info["previous_block_id"],
                address=address,
            )
            logger.info("blockinfo subscription created..")
Ejemplo n.º 10
0
    async def check_event(self):
        LOGGER.info(f"Checking for new events...")
        if self.last_block_num is None:
            LOGGER.debug(f"Last block number not ready!")
            return

        try:
            msg = self._event_queue[Message.CLIENT_EVENTS].get_nowait()
        except asyncio.QueueEmpty:
            LOGGER.debug("No message prepared yet")
            return

        LOGGER.info(f"message type {msg.message_type}")

        # Validate the response type
        if msg.message_type != Message.CLIENT_EVENTS:
            LOGGER.error("Unexpected message type")
            return

        # Parse the response
        event_list = EventList()
        event_list.ParseFromString(msg.content)

        web_socks_to_notify = {}
        LOGGER.debug(
            f"Received the following events list: {event_list.events}")
        block_num = None
        block_id = None
        is_event_catch_up = False
        for event in event_list.events:
            # assumed to be the first one in the list
            if event.event_type == SAWTOOTH_BLOCK_COMMIT_EVENT_TYPE:
                block_num = int(
                    get_value_from_key(event.attributes, "block_num"))
                block_id = get_value_from_key(event.attributes, "block_id")
                is_event_catch_up = block_num <= self.last_block_num
                self.last_block_num = max(self.last_block_num, block_num)
            else:
                event_response = {}
                event_response['type'] = event.event_type
                event_response['transaction_id'], event_response[
                    'data'] = process_event(event.event_type, event.attributes)

                event = self._events[event_response['type']]
                for web_sock in event:
                    if web_sock.closed:
                        await self._handle_unsubscribe(web_sock)
                        continue

                    if is_event_catch_up and not event[web_sock]['is_catch_up']:
                        continue

                    if web_sock not in web_socks_to_notify:
                        web_socks_to_notify[web_sock] = []

                    web_socks_to_notify[web_sock] += [event_response]
                    if self.last_block_num == block_num:
                        self._events[event_response['type']][web_sock][
                            'is_catch_up'] = False

        for web_sock, events in web_socks_to_notify.items():
            await self._ws_send_message(
                web_sock, {
                    Entity.EVENTS.value: events,
                    "block_num": block_num,
                    "block_id": block_id,
                    "last_known_block_num": self.last_block_num
                })