Example #1
0
    def start_wo_submitted_event_listener(self, handler_func):
        """
        Start event listener is blockchain specific
        and it is implemented using blockchain provided sdk
        @param handler_func is event handler function
        """

        # TODO: After creating APIs for event listening
        # This is also generalized
        # Start an event listener that listens for events from the proxy
        # blockchain, extracts request payload from there and make a request
        # to avalon-listener
        def workorder_event_handler_func(event, account, contract):
            """
            The function retrieves pertinent information
            from the event received and makes call to handler_func
            """
            try:
                work_order_request = json.loads(
                    event["args"]["workOrderRequest"])
            except Exception as err:
                logging.exception(
                    "Exception while parsing json {}".format(err))
            work_order_id = work_order_request["workOrderId"]
            worker_id = work_order_request["workerId"]
            requester_id = work_order_request["requesterId"]
            work_order_params = event["args"]["workOrderRequest"]
            handler_func(work_order_id, worker_id, requester_id,
                         work_order_params)

        w3 = BlockchainInterface(self._config)

        contract = self._wo_evt
        # Listening only for workOrderSubmitted event now
        listener = w3.newListener(contract, "workOrderSubmitted")

        try:
            daemon = EventProcessor(self._config)
            asyncio.get_event_loop().run_until_complete(
                daemon.start(
                    listener,
                    workorder_event_handler_func,
                    account=None,
                    contract=contract,
                ))
        except KeyboardInterrupt:
            asyncio.get_event_loop().run_until_complete(daemon.stop())
Example #2
0
    def work_order_get_result(self, work_order_id, id=None):
        """
        Query blockchain to get a work order result.
        This function starts an event handler for handling the
        workOrderCompleted event from the Ethereum blockchain.

        Parameters:
        work_order_id Work Order ID that was sent in the
                      corresponding work_order_submit request
        id            Optional JSON RPC request ID

        Returns:
        Tuple containing work order status, worker id, work order request,
        work order response, and error code.
        None on error.
        """
        logging.info("About to start Ethereum event handler")

        # Start an event listener that listens for events from the proxy
        # blockchain, extracts response payload from there and passes it
        # on to the requestor

        w3 = BlockchainInterface(self._config)

        contract = self.__contract_instance_evt
        # Listening only for workOrderCompleted event now
        listener = w3.newListener(contract, "workOrderCompleted")

        try:
            daemon = EventProcessor(self._config)
            # Wait for the workOrderCompleted event after starting the
            # listener and handler
            event = asyncio.get_event_loop()\
                .run_until_complete(daemon.get_event_synchronously(
                    listener, is_wo_id_in_event, wo_id=work_order_id))

            # Get the first element as this is a list of one event
            # obtained from gather() in ethereum_listener
            work_order_response = event[0]["args"]["workOrderResponse"]

            return json.loads(work_order_response)
        except KeyboardInterrupt:
            asyncio.get_event_loop().run_until_complete(daemon.stop())
Example #3
0
    def start(self):
        logging.info("Ethereum Connector service started")

        # Fetch first worker details from shared KV (via direct API)
        # and add the worker to block chain.
        # TODO: Fetch all workers from shared KV and block chain
        # and do 2-way sync.
        jrpc_worker_registry = JRPCWorkerRegistryImpl(self._config)
        worker_ids_onchain = self._lookup_workers_onchain()
        self.__worker_ids = self._lookup_workers_in_kv_storage(
            jrpc_worker_registry)

        self._add_update_worker_to_chain(worker_ids_onchain,
                                         jrpc_worker_registry)

        # Start an event listener that listens for events from the proxy
        # blockchain, extracts request payload from there and make a request
        # to avalon-listener

        w3 = BlockchainInterface(self._config)

        contract = self._work_order_contract_instance_evt
        # Listening only for workOrderSubmitted event now
        listener = w3.newListener(contract, "workOrderSubmitted")

        try:
            daemon = EventProcessor(self._config)
            asyncio.get_event_loop().run_until_complete(
                daemon.start(
                    listener,
                    self.handleEvent,
                    account=None,
                    contract=contract,
                ))
        except KeyboardInterrupt:
            asyncio.get_event_loop().run_until_complete(daemon.stop())
    def work_order_get_result(self, work_order_id, id=None):
        """
        Query blockchain to get a work order result.
        This function starts an event handler for handling the
        workOrderCompleted event from the Ethereum blockchain.

        Parameters:
        work_order_id Work Order ID that was sent in the
                      corresponding work_order_submit request
        id            Optional JSON RPC request ID

        Returns:
        Tuple containing work order status, worker id, work order request,
        work order response, and error code.
        None on error.
        """
        # Call the contract to get the result from blockchain
        # If we get the result from chain then return
        # Otherwise start the event listener to get work order
        # completed event.
        if (self.__contract_instance is not None):
            try:
                # workOrderGet returns tuple containing work order
                # result params as defined in EEA spec 6.10.5
                _, _, _, work_order_res, _ = \
                    self.__contract_instance.functions.workOrderGet(
                        work_order_id).call()
                if len(work_order_res) > 0:
                    return json.loads(work_order_res)
                else:
                    logging.warn("Work order seems to be not computed yet, "
                                 "going to listen for workOrderCompleted "
                                 "event")
            except Exception as e:
                logging.error("Failed to call contract {}".format(e))
                return None
        else:
            logging.error("Work order contract instance is not initialized")
            return None

        # Start an event listener that listens for events from the proxy
        # blockchain, extracts response payload from there and passes it
        # on to the requestor

        w3 = BlockchainInterface(self._config)

        contract = self.__contract_instance_evt
        # Listening only for workOrderCompleted event now
        listener = w3.newListener(contract, "workOrderCompleted")

        daemon = EventProcessor(self._config)
        # Wait for the workOrderCompleted event after starting the
        # listener and handler
        try:
            event = asyncio.get_event_loop().run_until_complete(
                asyncio.wait_for(
                    daemon.get_event_synchronously(listener,
                                                   is_wo_id_in_event,
                                                   wo_id=work_order_id),
                    timeout=self.WORK_ORDER_GET_RESULT_TIMEOUT,
                ))
            # Get the first element as this is a list of one event
            # obtained from gather() in ethereum_listener
            work_order_response = event[0]["args"]["workOrderResponse"]

            return json.loads(work_order_response)
        except asyncio.TimeoutError:
            logging.error("Work order get result timed out."
                          " Either work order id is invalid or"
                          " Work order execution not completed yet")
        except Exception as e:
            logging.error("Exception occurred while listening"
                          " to an event: {}".format(e))
        finally:
            asyncio.get_event_loop().run_until_complete(daemon.stop())
        return None