def __get_eservice_client__(state, save_file, eservice_url) :

    try :
        contract = get_contract(state, save_file)
    except Exception as e :
        raise Exception('unable to load the contract')

    if eservice_url not in ['random', 'preferred'] :
        try :
            eservice_client = EnclaveServiceClient(eservice_url)
        except Exception as e :
            raise Exception('unable to connect to enclave service; {0}'.format(str(e)))

        if eservice_client.enclave_id not in contract.provisioned_enclaves :
            raise Exception('requested enclave not provisioned for the contract; %s', eservice_url)
    else :
        if eservice_url == 'preferred' :
            enclave_id = contract.extra_data.get('preferred-enclave', random.choice(contract.provisioned_enclaves))
        else :
            enclave_id = random.choice(contract.provisioned_enclaves)

        eservice_info = eservice_db.get_by_enclave_id(enclave_id)
        if eservice_info is None :
            raise Exception('attempt to use an unknown enclave; %s', enclave_id)

        try :
            eservice_client = EnclaveServiceClient(eservice_info.url)
        except Exception as e :
            raise Exception('unable to connect to enclave service; {0}'.format(str(e)))

    return eservice_client
Exemple #2
0
    def __init__(self, operation, request_originator_keys, contract, **kwargs):
        if not self.__ops__[operation]:
            raise ValueError('invalid operation')

        self.operation = operation
        self.contract_id = contract.contract_id
        self.creator_id = contract.creator_id
        self.enclave_service = kwargs.get('enclave_service')
        if self.enclave_service == 'random':
            enclave_id = random.choice(list(contract.enclave_map.keys()))
            try:  #use the eservice database to get the client
                einfo = eservice_db.get_by_enclave_id(enclave_id)
                self.enclave_service = einfo.client
            except Exception as e:
                raise Exception(
                    'failed to get enclave client using database: %s', str(e))

        self.encrypted_state_encryption_key = contract.get_state_encryption_key(
            self.enclave_service.enclave_id)
        self.originator_keys = request_originator_keys
        self.make_channel_keys()
        self.session_key = crypto.SKENC_GenerateKey()
        self.contract_code = contract.contract_code
        self.contract_state = contract.contract_state
        self.message = ContractMessage(self.originator_keys, self.channel_id,
                                       **kwargs)
        self.replication_params = contract.replication_params
        self.request_number = ContractRequest.__request_number__
        ContractRequest.__request_number__ += 1
    def __init__(self, request_originator_keys, contract, **kwargs) :
        self.contract_id = contract.contract_id
        self.creator_id = contract.creator_id
        self.enclave_service = kwargs.get('enclave_service')
        if self.enclave_service == 'random':
            enclave_id = random.choice(list(contract.enclave_map.keys()))
            try: #use the eservice database to get the client
                einfo = eservice_db.get_by_enclave_id(enclave_id)
                self.enclave_service = einfo.client
            except Exception as e:
                raise Exception('failed to get enclave client using database: %s', str(e))

        self.encrypted_state_encryption_key = contract.get_state_encryption_key(self.enclave_service.enclave_id)
        self.originator_keys = request_originator_keys
        self.make_channel_keys()
        self.session_key = crypto.SKENC_GenerateKey()

        self.replication_params = contract.replication_params
        self.request_number = ContractRequest.get_request_number()
Exemple #4
0
# -----------------------------------------------------------------
# logger.info('create and load the database from the provided URLs')
# -----------------------------------------------------------------
names = []
enclave_count = 0
for url in options.url:
    names.append('enclave_{0}'.format(enclave_count))
    eservice_db.add_by_url(ledger_config, url, name=names[enclave_count])
    enclave_count += 1

# -----------------------------------------------------------------
# logger.info('verify that the information in the database is consistent')
# -----------------------------------------------------------------
for e in names:
    einfo_by_name = eservice_db.get_by_name(e)
    einfo_by_enclave_id = eservice_db.get_by_enclave_id(
        einfo_by_name.client.enclave_id)

    # this can probably be simplified to just a comparison of
    # the two objects
    assert einfo_by_name.name == e
    assert einfo_by_enclave_id.name == e
    assert einfo_by_name.name == einfo_by_enclave_id.name
    assert einfo_by_name.enclave_id == einfo_by_enclave_id.enclave_id

# -----------------------------------------------------------------
# logger.info('verify that database can be saved and loaded')
# -----------------------------------------------------------------
initial_hash = compute_database_hash()
eservice_db.save_database(options.eservice_db, overwrite=True)

#load db freshly and check
Exemple #5
0
def send_to_contract(state,
                     save_file,
                     message,
                     eservice_url=None,
                     quiet=False,
                     wait=False,
                     commit=True):

    # ---------- load the invoker's keys ----------
    try:
        keyfile = state.get(['Key', 'FileName'])
        keypath = state.get(['Key', 'SearchPath'])
        client_keys = ServiceKeys.read_from_file(keyfile, keypath)
    except Exception as e:
        raise Exception('unable to load client keys; {0}'.format(str(e)))

    # ---------- read the contract ----------
    try:
        contract = get_contract(state, save_file)
    except Exception as e:
        raise Exception('unable to load the contract')

    # ---------- set up the enclave service ----------
    if eservice_url is None:
        eservice_url = 'preferred'

    if eservice_url not in ['random', 'preferred']:
        try:
            eservice_client = EnclaveServiceClient(eservice_url)
        except Exception as e:
            raise Exception('unable to connect to enclave service; {0}'.format(
                str(e)))

        if eservice_client.enclave_id not in contract.provisioned_enclaves:
            raise Exception(
                'requested enclave not provisioned for the contract; %s',
                eservice_url)
    else:
        if eservice_url == 'preferred':
            enclave_id = contract.extra_data.get(
                'preferred-enclave',
                random.choice(contract.provisioned_enclaves))
        else:
            enclave_id = random.choice(contract.provisioned_enclaves)

        eservice_info = eservice_db.get_by_enclave_id(enclave_id)
        if eservice_info is None:
            raise Exception('attempt to use an unknown enclave; %s',
                            enclave_id)

        try:
            eservice_client = EnclaveServiceClient(eservice_info.url)
        except Exception as e:
            raise Exception('unable to connect to enclave service; {0}'.format(
                str(e)))

    # ---------- send the message to the enclave service ----------
    try:
        update_request = contract.create_update_request(
            client_keys, message, eservice_client)
        update_response = update_request.evaluate()
    except Exception as e:
        raise Exception('enclave failed to evaluate expression; {0}'.format(
            str(e)))

    if not update_response.status:
        # not sure if this should throw an exception which would
        # terminate the script or if it should just return an
        # empty string that can be tested for later
        # if not quiet :
        #     print("FAILED: {0}".format(update_response.invocation_response))
        # return ''
        raise ValueError(update_response.invocation_response)

    if not quiet:
        print(update_response.invocation_response)

    data_directory = state.get(['Contract', 'DataDirectory'])
    ledger_config = state.get(['Ledger'])

    if update_response.state_changed and commit:

        contract.set_state(update_response.raw_state)

        # asynchronously submit the commit task: (a commit task replicates
        # change-set and submits the corresponding transaction)
        try:
            update_response.commit_asynchronously(ledger_config)
        except Exception as e:
            raise Exception('failed to submit commit: %s', str(e))

        # wait for the commit to finish.
        # TDB:
        # 1. make wait_for_commit a separate shell command.
        # 2. Add a provision to specify commit dependencies as input to send command.
        # 3. Return commit_id after send command back to shell so as to use as input
        #    commit_dependency in a future send command
        try:
            txn_id = update_response.wait_for_commit()
            if txn_id is None:
                raise Exception(
                    "Did not receive txn id for the send operation")
        except Exception as e:
            raise Exception("Error while waiting for commit: %s", str(e))

        try:
            contract.contract_state.save_to_cache(data_dir=data_directory)
        except Exception as e:
            logger.exception('failed to save the new state in the cache')

    return update_response.invocation_response
def __replication_worker__(service_id, pending_tasks_queue,
                           condition_variable_for_setup):
    """ Worker thread that replicates to a specific storage service"""
    # set up the service client
    try:
        einfo = service_db.get_by_enclave_id(service_id)
        service_client = einfo.client
        init_sucess = True
    except:
        logger.info("Failed to set up service client for service id %s",
                    str(service_id))
        # mark the service as unusable
        __services_to_ignore__.add(service_id)
        #exit the thread
        init_sucess = False

    # notify the manager that init was attempted
    condition_variable_for_setup.acquire()
    condition_variable_for_setup.notify()
    condition_variable_for_setup.release()

    # exit the thread if init failed
    if not init_sucess:
        return

    try:
        while True:

            # wait for a new task, task is the response object
            try:
                response = pending_tasks_queue.get(timeout=1.0)
            except:
                # check for termination signal
                if __stop_service__:
                    logger.info(
                        "Exiting Replication worker thread for service at %s",
                        str(service_client.ServiceURL))
                    break
                else:
                    continue

            #check if the task is already complete. If so go to the next one
            replication_request = response.replication_request
            if replication_request.is_completed:
                continue

            # replicate now!
            block_data_list = ContractState.block_data_generator(replication_request.contract_id, \
                replication_request.blocks_to_replicate, replication_request.data_dir)
            expiration = replication_request.availability_duration
            request_id = response.commit_id[2]
            try:
                fail_task = False
                response_from_replication = service_client.store_blocks(
                    block_data_list, expiration)
                if response_from_replication is None:
                    fail_task = True
                    logger.info(
                        "No response from storage service %s for replication request %d",
                        str(service_client.ServiceURL), request_id)
            except Exception as e:
                fail_task = True
                logger.info(
                    "Replication request %d got an exception from %s: %s",
                    request_id, str(service_client.ServiceURL), str(e))

            # update the set of services where replication is completed
            replication_request.update_set_of_services_where_replicated(
                service_id, fail_task)

            # check if the overall task can be marked as successful or failed:
            if len(replication_request.successful_services
                   ) >= replication_request.num_provable_replicas:
                replication_request.mark_as_completed(
                    response.call_back_after_replication)
            elif len(replication_request.unsuccessful_services) > len(
                    replication_request.service_ids
            ) - replication_request.num_provable_replicas:
                replication_request.mark_as_failed()

            # Finally, if the task failed, mark the service as unreliable
            # (this may be a bit harsh, we will refine this later based on the nature of the failure)
            if fail_task:
                __services_to_ignore__.add(service_id)
                logger.info(
                    "Ignoring service at %s for rest of replication attempts",
                    str(service_client.ServiceURL))
                #exit the thread
                break

    except Exception as e:
        logger.info("Replication Worker exception %s", str(e))