Example #1
0
def main(args=None):

    parser = argparse.ArgumentParser()
    parser.add_argument(
        "-c", "--config",
        help="The config file containing the Fabric network information",
        type=str)
    parser.add_argument(
        "-u", "--uri",
        help="Direct API listener endpoint",
        default="http://avalon-listener:1947",
        type=str)

    options = parser.parse_args(args)

    config = _parse_config_file(options.config)
    if config is None:
        logging.error("\n Error in parsing config file: {}\n".format(
            options.config
        ))
        sys.exit(-1)

    # Http JSON RPC listener uri
    uri = options.uri
    if uri:
        config["tcf"]["json_rpc_uri"] = uri

    fabric_worker = FabricWorkerRegistryImpl(config)
    fabric_work_order = FabricWorkOrderImpl(config)

    nest_asyncio.apply()
    fabric_connector_svc = FabricConnector(
        config, None,
        fabric_worker, fabric_work_order, None)
    fabric_connector_svc.start()
 def create_work_order_instance(self, blockchain_type, config):
     # create work order instance for direct/proxy model
     if blockchain_type == 'fabric':
         return FabricWorkOrderImpl(config)
     elif blockchain_type == 'ethereum':
         return EthereumWorkOrderImpl(config)
     else:
         return JRPCWorkOrderImpl(config)
def _create_work_order_instance(blockchain_type, config):
    # create work order instance for direct/proxy model
    if constants.proxy_mode and blockchain_type == 'fabric':
        return FabricWorkOrderImpl(config)
    elif constants.proxy_mode and blockchain_type == 'ethereum':
        return EthereumWorkOrderProxyImpl(config)
    else:
        logger.info("Direct SDK code path\n")
        return JRPCWorkOrderImpl(config)
 def __init__(self, config, blockchain_type):
     super().__init__()
     self._config = config
     if blockchain_type.lower() == 'fabric':
         self._worker_instance = FabricWorkerRegistryImpl(self._config)
         self._work_order_instance = FabricWorkOrderImpl(self._config)
     elif blockchain_type.lower() == 'ethereum':
         self._worker_instance = EthereumWorkerRegistryImpl(self._config)
         self._work_order_instance = EthereumWorkOrderProxyImpl(
             self._config)
     else:
         logging.error("Invalid blockchain type")
Example #5
0
 def __init__(self, listener_url):
     tcf_home = environ.get("TCF_HOME", "../../../")
     config_file = tcf_home + "/sdk/avalon_sdk/tcf_connector.toml"
     if not path.isfile(config_file):
         raise FileNotFoundError("File not found at path: {0}".format(
             path.realpath(config_file)))
     try:
         with open(config_file) as fd:
             self.__config = toml.load(fd)
     except IOError as e:
         if e.errno != errno.ENOENT:
             raise Exception("Could not open config file: %s", e)
     self.__config['tcf']['json_rpc_uri'] = listener_url
     self.__fabric_worker = FabricWorkerRegistryImpl(self.__config)
     self.__fabric_work_order = FabricWorkOrderImpl(self.__config)
     self.__jrpc_worker = JRPCWorkerRegistryImpl(self.__config)
     self.__jrpc_work_order = JRPCWorkOrderImpl(self.__config)
     # List of active available worker ids in Avalon
     self.__worker_ids = []
     # Wait time in sec
     self.WAIT_TIME = 31536000
     nest_asyncio.apply()
Example #6
0
class FabricConnector():
    """
    Fabric blockchain connector
    """
    def __init__(self, listener_url):
        tcf_home = environ.get("TCF_HOME", "../../../")
        config_file = tcf_home + "/sdk/avalon_sdk/tcf_connector.toml"
        if not path.isfile(config_file):
            raise FileNotFoundError("File not found at path: {0}".format(
                path.realpath(config_file)))
        try:
            with open(config_file) as fd:
                self.__config = toml.load(fd)
        except IOError as e:
            if e.errno != errno.ENOENT:
                raise Exception("Could not open config file: %s", e)
        self.__config['tcf']['json_rpc_uri'] = listener_url
        self.__fabric_worker = FabricWorkerRegistryImpl(self.__config)
        self.__fabric_work_order = FabricWorkOrderImpl(self.__config)
        self.__jrpc_worker = JRPCWorkerRegistryImpl(self.__config)
        self.__jrpc_work_order = JRPCWorkOrderImpl(self.__config)
        # List of active available worker ids in Avalon
        self.__worker_ids = []
        # Wait time in sec
        self.WAIT_TIME = 31536000
        nest_asyncio.apply()

    def start(self):
        self.sync_worker()
        loop = asyncio.get_event_loop()
        tasks = self.get_work_order_event_handler_tasks()
        loop.run_until_complete(
            asyncio.wait(tasks, return_when=asyncio.ALL_COMPLETED))
        loop.close()

    def sync_worker(self):
        """
        Check for existing worker and update worker to fabric blockchain
        """
        # Get all TEE Intel SGX based workers ids from the Fabric blockchain
        worker_ids_onchain = self._lookup_workers_onchain()
        # Get all Intel SGX TEE based worker ids from shared kv
        self.__worker_ids = self._lookup_workers_in_kv_storage()
        # If worker id exists in shared kv then update details of
        # worker to with details field.
        # otherwise add worker to blockchain
        # Update all worker which are not in shared kv and
        # present in blockchain to Decommissioned status
        self._add_update_worker_to_chain(worker_ids_onchain, self.__worker_ids)

    def get_work_order_event_handler_tasks(self):
        """
        Sync work order with blockchain
        1. listen to work order submit event
        2. Submit work order request to listener
        3. Wait for a work order result
        4. Update work order result to fabric
        """
        event_handler = self.__fabric_work_order.\
            get_work_order_submitted_event_handler(
                self.workorder_event_handler_func
            )
        if event_handler:
            tasks = [
                event_handler.start_event_handling(),
                event_handler.stop_event_handling(int(self.WAIT_TIME))
            ]
            return tasks
        else:
            logging.info("get work order submitted event handler failed")
            return None

    def workorder_event_handler_func(self, event, block_num, txn_id, status):
        logging.info("Event payload: {}\n Block number: {}\n"
                     "Transaction id: {}\n Status {}".format(
                         event, block_num, txn_id, status))
        jrpc_req_id = 301
        # Add workorder id to work order list
        payload_string = event['payload'].decode("utf-8")
        work_order_req = json.loads(payload_string)
        work_order_id = work_order_req['workOrderId']
        # Submit the work order to listener if worker id from the event
        # matches with available worker ids
        if work_order_req['workerId'] in self.__worker_ids:
            logging.info("Submitting to work order to listener")
            response = self.__jrpc_work_order.work_order_submit(
                work_order_req['workOrderId'],
                work_order_req['workerId'],
                work_order_req['requesterId'],
                work_order_req["workOrderRequest"],
                id=jrpc_req_id)
            logging.info("Work order submit response {}".format(response))
            if response and 'error' in response and \
                    response['error']['code'] == \
                            WorkOrderStatus.PENDING.value:
                # get the work order result
                jrpc_req_id += 1
                work_order_result = \
                    self.__jrpc_work_order.work_order_get_result(
                        work_order_req['workOrderId'],
                        jrpc_req_id
                    )
                logging.info(
                    "Work order get result {}".format(work_order_result))
            # With Synchronous work order processing work order submit
            # return result
            elif response and 'result' in response:
                work_order_result = response
            else:
                logging.info("work_order_submit is failed")
                work_order_result = None
            if work_order_result:
                logging.info("Commit work order result to blockchain")
                # call to chain code to store result to blockchain
                status = self.__fabric_work_order.work_order_complete(
                    work_order_id, json.dumps(work_order_result))
                if status == ContractResponse.SUCCESS:
                    # remove the entry from work order list
                    logging.info(
                        "Chaincode invoke call work_order_complete success")
                else:
                    logging.info(
                        "Chaincode invoke call work_order_complete failed")

    def _lookup_workers_in_kv_storage(self):
        """
        Retrieves the worker ids from shared kv using
        worker_lookup direct API.
        Returns list of worker ids
        """
        jrpc_req_id = random.randint(0, 100000)

        worker_lookup_result = self.__jrpc_worker.worker_lookup(
            worker_type=WorkerType.TEE_SGX, id=jrpc_req_id)
        logging.info("\nWorker lookup response from kv storage : {}\n".format(
            json.dumps(worker_lookup_result, indent=4)))
        if "result" in worker_lookup_result and \
                "ids" in worker_lookup_result["result"].keys():
            if worker_lookup_result["result"]["totalCount"] != 0:
                return worker_lookup_result["result"]["ids"]
            else:
                logging.error("No workers found in kv storage")
        else:
            logging.error("Failed to lookup worker in kv storage")
        return []

    def _retrieve_worker_details_from_kv_storage(self, worker_id):
        """
        Retrieve worker details from shared kv using
        direct json rpc API
        Returns the worker details in json string format
        """
        jrpc_req_id = random.randint(0, 100000)
        worker_info = self.__jrpc_worker.worker_retrieve(
            worker_id, jrpc_req_id)
        logging.info("Worker retrieve response from kv storage: {}".format(
            json.dumps(worker_info, indent=4)))

        if "error" in worker_info:
            logging.error("Unable to retrieve worker details from kv storage")
            return ""
        else:
            return worker_info["result"]

    def _lookup_workers_onchain(self):
        """
        Lookup all workers on chain to sync up with kv storage
        Return list of worker ids
        """
        worker_lookup_result = self.__fabric_worker.worker_lookup(
            worker_type=WorkerType.TEE_SGX)
        logging.info("Worker lookup response from blockchain: {}\n".format(
            json.dumps(worker_lookup_result, indent=4)))
        if worker_lookup_result and worker_lookup_result[0] > 0:
            return worker_lookup_result[2]
        else:
            logging.info("No workers found in fabric blockchain")
            return []

    def _add_update_worker_to_chain(self, wids_onchain, wids_kv):
        """
        This function adds/updates a worker in the fabric blockchain
        """
        for wid in wids_kv:
            worker_info = self._retrieve_worker_details_from_kv_storage(wid)
            worker_id = wid
            worker_type = WorkerType(worker_info["workerType"])
            org_id = worker_info["organizationId"]
            app_type_id = worker_info["applicationTypeId"]
            details = json.dumps(worker_info["details"])

            result = None
            if wid in wids_onchain:
                logging.info(
                    "Updating worker {} on fabric blockchain".format(wid))
                result = self.__fabric_worker.worker_update(worker_id, details)
            else:
                logging.info(
                    "Adding new worker {} to fabric blockchain".format(wid))
                result = self.__fabric_worker.worker_register(
                    worker_id, worker_type, org_id, [app_type_id], details)
            if result != ContractResponse.SUCCESS:
                logging.error("Error while adding/updating worker to fabric" +
                              " blockchain")

        for wid in wids_onchain:
            # Mark all stale workers on blockchain as decommissioned
            if wid not in wids_kv:
                worker = self.__fabric_worker.worker_retrieve(wid)
                # worker_retrieve returns tuple and first element
                # denotes status of worker.
                worker_status_onchain = worker[0]
                # If worker is not already decommissioned,
                # mark it decommissioned
                # as it is no longer available in the kv storage
                if worker_status_onchain != WorkerStatus.DECOMMISSIONED.value:
                    update_status = self.__fabric_worker.worker_set_status(
                        wid, WorkerStatus.DECOMMISSIONED)
                    if update_status == ContractResponse.SUCCESS:
                        logging.info("Marked worker " + wid +
                                     " as decommissioned on" +
                                     " fabric blockchain")
                    else:
                        logging.info("Update worker " + wid + " is failed")