Exemple #1
0
def LocalMain(config, message):
    # ---------- check the integrity of the configuration ----------
    try:
        ledger_config = config['Sawtooth']
        contract_config = config['Contract']
        service_config = config['Service']
        key_config = config['Key']
    except KeyError as ke:
        logger.error('missing configuration section %s', str(ke))
        sys.exit(-1)

    # ---------- load the contract information file ----------
    try:
        save_file = contract_config['SaveFile']
        data_directory = contract_config['DataDirectory']
        logger.info('load contract from %s', save_file)

        contract = Contract.read_from_file(ledger_config,
                                           save_file,
                                           data_dir=data_directory)
    except KeyError as ke:
        logger.error('missing configuration parameter %s', str(ke))
        sys.exit(-1)
    except Exception as e:
        logger.error('failed to load the contract; %s', str(e))
        sys.exit(-1)

    # ---------- load the invoker's keys ----------
    try:
        keyfile = key_config['FileName']
        keypath = key_config['SearchPath']
        contract_invoker_keys = ServiceKeys.read_from_file(keyfile, keypath)
    except KeyError as ke:
        logger.error('missing configuration parameter %s', str(ke))
        sys.exit(-1)
    except Exception as e:
        logger.error('unable to load client keys; %s', str(e))
        sys.exit(-1)

    # ---------- set up the enclave service ----------
    try:
        enclave_url = service_config['PreferredEnclaveService']
        enclave_client = EnclaveServiceClient(enclave_url)
    except KeyError as ke:
        logger.error('missing configuration parameter %s', str(ke))
        sys.exit(-1)
    except Exception as e:
        logger.error('unable to connect to enclave service; %s', str(e))
        sys.exit(-1)

    try:
        # this is just a sanity check to make sure the selected enclave
        # has actually been provisioned
        contract.get_state_encryption_key(enclave_client.enclave_id)
    except KeyError as ke:
        logger.error('selected enclave is not provisioned')
        sys.exit(-1)

    # ---------- process incoming messages ----------
    if message:
        mlist = MessageIterator(message)
    else:
        mlist = InputIterator(config.get('Identity', '') + "> ")

    for msg in mlist:
        if not msg:
            continue

        logger.info('send message <%s> to contract', msg)

        try:
            update_request = contract.create_update_request(
                contract_invoker_keys, enclave_client, msg)
            update_response = update_request.evaluate()
            if update_response.status:
                print(update_response.result)
            else:
                print('ERROR: {}'.format(update_response.result))
                # continue if this is an interactive session, fail
                # if we are processing command line messages
                if message:
                    sys.exit(-1)
                else:
                    continue
        except Exception as e:
            logger.error('enclave failed to evaluation expression; %s', str(e))
            sys.exit(-1)

        try:
            logger.debug("sending to ledger")
            txnid = update_response.submit_update_transaction(ledger_config)
        except Exception as e:
            logger.error('failed to save the new state; %s', str(e))
            sys.exit(-1)

        contract.set_state(update_response.encrypted_state)
        contract.contract_state.save_to_cache(data_dir=data_directory)

    sys.exit(0)
Exemple #2
0
def LocalMain(commands, config):
    # ---------- load the contract ----------
    try:
        ledger_config = config['Sawtooth']
        contract_config = config['Contract']
        service_config = config['Service']
        key_config = config['Key']
    except KeyError as ke:
        logger.error('missing configuration section %s', str(ke))
        sys.exit(-1)

    # ---------- load the invoker's keys ----------
    try:
        keyfile = key_config['FileName']
        keypath = key_config['SearchPath']
        client_keys = ServiceKeys.read_from_file(keyfile, keypath)
    except KeyError as ke:
        logger.error('missing configuration parameter %s', str(ke))
        sys.exit(-1)
    except Exception as e:
        logger.error('unable to load client keys; %s', str(e))
        sys.exit(-1)

    # ---------- read the contract source code ----------
    try:
        contract_name = contract_config['Name']
        data_directory = contract_config['DataDirectory']
        save_file = contract_config['SaveFile']
        source_file = contract_config['SourceFile']
        source_path = contract_config['SourceSearchPath']
        contract_code = ContractCode.create_from_scheme_file(
            contract_name, source_file, source_path)
    except KeyError as ke:
        logger.error('missing configuration parameter %s', str(ke))
        sys.exit(-1)
    except Exception as e:
        logger.error('unable to load contract source; %s', str(e))
        sys.exit(-1)

    logger.info('Loaded contract data for %s', contract_name)

    # ---------- set up the enclave clients ----------
    try:
        enclaveclients = []
        for url in service_config['EnclaveServiceURLs']:
            enclaveclients.append(EnclaveServiceClient(url))
    except Exception as e:
        logger.error('unable to setup enclave services; %s', str(e))
        sys.exit(-1)

    # ---------- set up the provisioning service clients ----------
    # This is a dictionary of provisioning service public key : client pairs
    try:
        provclients = []
        for url in service_config['ProvisioningServiceURLs']:
            provclients.append(ProvisioningServiceClient(url))
    except Exception as e:
        logger.error('unable to setup provisioning services; %s', str(e))
        sys.exit(-1)

    logger.debug("All enclaveclients: %s", enclaveclients)
    logger.debug("All provclients: %s", provclients)

    # process the commands to create & register the contract
    if 'register' in commands:
        try:
            provisioning_service_keys = [pc.identity for pc in provclients]
            contract_id = register_contract(ledger_config, client_keys,
                                            contract_code,
                                            provisioning_service_keys)

            logger.info('Registered contract %s with id %s', contract_name,
                        contract_id)
            contract_state = ContractState.create_new_state(contract_id)
            contract = Contract(contract_code, contract_state, contract_id,
                                client_keys.identity)
            contract.save_to_file(save_file, data_dir=data_directory)
        except Exception as e:
            logger.error('failed to register the contract; %s', str(e))
            sys.exit(-1)
    else:
        # need to read the contract from the contract file
        contract = Contract.read_from_file(ledger_config, contract_name,
                                           data_directory)

    if 'addenclave' in commands:
        encrypted_state_encryption_keys = AddEnclaveSecrets(
            ledger_config, contract.contract_id, client_keys, enclaveclients,
            provclients)

        for enclave_id in encrypted_state_encryption_keys:
            encrypted_key = encrypted_state_encryption_keys[enclave_id]
            contract.set_state_encryption_key(enclave_id, encrypted_key)

        contract.save_to_file(save_file, data_dir=data_directory)
        logger.info(
            'Successfully added enclave secrets to ledger for contract %s',
            contract_code.name)

    if 'create' in commands:
        CreateContract(ledger_config, client_keys, enclaveclients, contract)

        contract.contract_state.save_to_cache(data_dir=data_directory)
        contract.save_to_file(save_file, data_dir=data_directory)

    print('export CONTRACTID={0}'.format(contract.contract_id))
 def client(self):
     if self.__eservice_client__ is None:
         self.__eservice_client__ = EnclaveServiceClient(self.url)
     return self.__eservice_client__
Exemple #4
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 command_create(state, bindings, pargs):
    """controller command to create a contract
    """

    parser = argparse.ArgumentParser(prog='create')
    parser.add_argument('-c',
                        '--contract-class',
                        help='Name of the contract class',
                        required=True,
                        type=str)
    parser.add_argument('-s',
                        '--contract-source',
                        help='File that contains contract source code',
                        required=True,
                        type=str)
    parser.add_argument('-f',
                        '--save-file',
                        help='File where contract data is stored',
                        type=str)
    parser.add_argument('--symbol', help='binding symbol for result', type=str)
    options = parser.parse_args(pargs)

    contract_class = options.contract_class
    contract_source = options.contract_source

    contract_file = "{0}.pdo".format(contract_class)
    if options.save_file:
        contract_file = options.save_file

    # ---------- 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 source code ----------
    try:
        source_path = state.get(['Contract', 'SourceSearchPath'])
        contract_code = ContractCode.create_from_scheme_file(
            contract_class, contract_source, source_path)
    except Exception as e:
        raise Exception('unable to load contract source; {0}'.format(str(e)))

    logger.info('Loaded contract code for %s', contract_class)

    # ---------- set up the enclave clients ----------
    try:
        eservice_urls = state.get(['Service', 'EnclaveServiceURLs'], [])
        if len(eservice_urls) == 0:
            raise Exception('no enclave services specified')

        enclaveclients = []
        for url in eservice_urls:
            enclaveclients.append(EnclaveServiceClient(url))
    except Exception as e:
        raise Exception('unable to contact enclave services; {0}'.format(
            str(e)))

    # ---------- set up the provisioning service clients ----------
    # This is a dictionary of provisioning service public key : client pairs
    try:
        pservice_urls = state.get(['Service', 'ProvisioningServiceURLs'])
        if len(pservice_urls) == 0:
            raise Exception('no provisioning services specified')

        provclients = []
        for url in pservice_urls:
            provclients.append(ProvisioningServiceClient(url))
    except Exception as e:
        raise Exception('unable to contact provisioning services; {0}'.format(
            str(e)))

    # ---------- register contract ----------
    data_directory = state.get(['Contract', 'DataDirectory'])
    ledger_config = state.get(['Sawtooth'])

    try:
        provisioning_service_keys = [pc.identity for pc in provclients]
        contract_id = register_contract(ledger_config, client_keys,
                                        contract_code,
                                        provisioning_service_keys)

        logger.info('Registered contract with class %s and id %s',
                    contract_class, contract_id)
        contract_state = ContractState.create_new_state(contract_id)
        contract = Contract(contract_code, contract_state, contract_id,
                            client_keys.identity)
        contract.save_to_file(contract_file, data_dir=data_directory)
    except Exception as e:
        raise Exception('failed to register the contract; {0}'.format(str(e)))

    # provision the encryption keys to all of the enclaves
    try:
        encrypted_state_encryption_keys = __add_enclave_secrets(
            ledger_config, contract.contract_id, client_keys, enclaveclients,
            provclients)

        for enclave_id in encrypted_state_encryption_keys:
            encrypted_key = encrypted_state_encryption_keys[enclave_id]
            contract.set_state_encryption_key(enclave_id, encrypted_key)

        contract.save_to_file(contract_file, data_dir=data_directory)
    except Exception as e:
        raise Exception('failed to provisioning the enclaves; {0}'.format(
            str(e)))

    # create the initial contract state
    try:
        __create_contract(ledger_config, client_keys, enclaveclients, contract)

        contract.contract_state.save_to_cache(data_dir=data_directory)
        contract.save_to_file(contract_file, data_dir=data_directory)
    except Exception as e:
        raise Exception(
            'failed to create the initial contract state; {0}'.format(str(e)))

    if contract_id and options.symbol:
        bindings.bind(options.symbol, contract_id)