def get_consumer_ocean_instance(init_tokens=True, use_ss_mock=True, use_brizo_mock=False):
    ocn = Ocean()
    account = get_consumer_account()
    ocn.main_account = account
    if init_tokens:
        init_ocn_tokens(ocn, ocn.main_account)
    if use_ss_mock:
        SecretStoreProvider.set_secret_store_class(SecretStoreMock)
    if use_brizo_mock:
        BrizoProvider.set_brizo_class(BrizoMock)

    return ocn
Exemple #2
0
def test_initialize_and_consume(client, publisher_ocean_instance, consumer_ocean_instance):
    print(publisher_ocean_instance.accounts)
    pub_ocn, cons_ocn = publisher_ocean_instance, consumer_ocean_instance
    consumer_account = cons_ocn.main_account
    publisher_account = pub_ocn.main_account
    asset_price = 10

    # Register asset
    ddo = get_registered_ddo(pub_ocn, publisher_account)

    print("did: %s" % ddo.did)

    service_definition_id = \
        ddo.get_service(service_type=ServiceTypes.ASSET_ACCESS).get_values()[
            'serviceDefinitionId']

    agreement_id = ServiceAgreement.create_new_agreement_id()
    service_def = ddo.find_service_by_id(service_definition_id).as_dictionary()

    service_agreement = ServiceAgreement.from_ddo(service_definition_id, ddo)
    service_agreement.validate_conditions()
    agreement_hash = service_agreement.get_service_agreement_hash(agreement_id)
    cons_ocn.main_account.unlock()

    signature = consumer_account.sign_hash(agreement_hash)

    sa = service_agreement

    cons_ocn.main_account.unlock()
    cons_ocn._approve_token_transfer(service_agreement.get_price(), consumer_account)
    cons_ocn._http_client = client
    # subscribe to events
    register_service_agreement(cons_ocn.config.storage_path,
                               cons_ocn.main_account,
                               agreement_id,
                               ddo.did,
                               service_def,
                               'consumer',
                               service_definition_id,
                               service_agreement.get_price(),
                               get_metadata_url(ddo),
                               cons_ocn.consume_service,
                               0)

    request_payload = BrizoProvider.get_brizo().prepare_purchase_payload(ddo.did, agreement_id,
                                                                         service_definition_id,
                                                                         signature,
                                                                         consumer_account.address)
    initialize = client.post(
        sa.purchase_endpoint,
        data=request_payload,
        content_type='application/json'
    )
    print(initialize.status_code)
    assert initialize.status_code == 201
    assert pub_ocn.keeper.service_agreement.get_agreement_status(agreement_id) is False, ''
    # wait a bit until all service agreement events are processed
    time.sleep(15)
    assert pub_ocn.keeper.service_agreement.get_agreement_status(agreement_id) is True, ''
    print('Service agreement executed and fulfilled, all good.')
    def _process_service_descriptors(self, service_descriptors, metadata,
                                     account):
        brizo = BrizoProvider.get_brizo()
        ddo_service_endpoint = self._get_aquarius().get_service_endpoint()

        service_type_to_descriptor = {sd[0]: sd for sd in service_descriptors}
        _service_descriptors = []
        metadata_service_desc = service_type_to_descriptor.pop(
            ServiceTypes.METADATA,
            ServiceDescriptor.metadata_service_descriptor(
                metadata, ddo_service_endpoint))
        auth_service_desc = service_type_to_descriptor.pop(
            ServiceTypes.AUTHORIZATION,
            ServiceDescriptor.authorization_service_descriptor(
                self._config.secret_store_url))
        _service_descriptors = [metadata_service_desc, auth_service_desc]

        # Always dafault to creating a ServiceTypes.ASSET_ACCESS service if no services are specified
        access_service_descriptor = service_type_to_descriptor.pop(
            ServiceTypes.ASSET_ACCESS,
            ServiceDescriptor.access_service_descriptor(
                self._build_access_service(metadata, account),
                brizo.get_consume_endpoint(self._config),
                self._keeper.escrow_access_secretstore_template.address))
        compute_service_descriptor = service_type_to_descriptor.pop(
            ServiceTypes.CLOUD_COMPUTE, None)

        if access_service_descriptor:
            _service_descriptors.append(access_service_descriptor)
        if compute_service_descriptor:
            _service_descriptors.append(compute_service_descriptor)

        _service_descriptors.extend(service_type_to_descriptor.values())
        return ServiceFactory.build_services(_service_descriptors)
    def consume(self,
                service_agreement_id,
                did,
                service_index,
                consumer_account,
                destination,
                index=None):
        """
        Consume the asset data.

        Using the service endpoint defined in the ddo's service pointed to by service_definition_id.
        Consumer's permissions is checked implicitly by the secret-store during decryption
        of the contentUrls.
        The service endpoint is expected to also verify the consumer's permissions to consume this
        asset.
        This method downloads and saves the asset datafiles to disk.

        :param service_agreement_id: str
        :param did: DID, str
        :param service_index: identifier of the service inside the asset DDO, str
        :param consumer_account: Account instance of the consumer
        :param destination: str path
        :param index: Index of the document that is going to be downloaded, int
        :return: str path to saved files
        """
        ddo = self.resolve(did)
        if index is not None:
            assert isinstance(index,
                              int), logger.error('index has to be an integer.')
            assert index >= 0, logger.error(
                'index has to be 0 or a positive integer.')
        return self._asset_consumer.download(
            service_agreement_id, service_index, ddo, consumer_account,
            destination, BrizoProvider.get_brizo(),
            self._get_secret_store(consumer_account), index)
def get_consumer_ocean_instance(init_tokens=True,
                                use_ss_mock=True,
                                use_brizo_mock=True):
    ocn = make_ocean_instance(CONSUMER_INDEX)
    account = get_consumer_account(ConfigProvider.get_config())
    if account.address in ocn.accounts.accounts_addresses:
        ocn.main_account = account
    else:
        ocn.main_account = ocn.accounts.list()[1]

    if init_tokens:
        init_ocn_tokens(ocn, ocn.main_account)
    if use_ss_mock:
        SecretStoreProvider.set_secret_store_class(SecretStoreMock)
    if use_brizo_mock:
        BrizoProvider.set_brizo_class(BrizoMock)

    return ocn
Exemple #6
0
    def send(self,
             did,
             agreement_id,
             service_index,
             signature,
             consumer_account,
             auto_consume=False):
        """
        Send a signed service agreement to the publisher Brizo instance to
        consume/access the service.

        :param did: str representation fo the asset DID. Use this to retrieve the asset DDO.
        :param agreement_id: 32 bytes identifier created by the consumer and will be used
         on-chain for the executed agreement.
        :param service_index: int identifies the specific service in
         the ddo to use in this agreement.
        :param signature: str the signed agreement message hash which includes
         conditions and their parameters values and other details of the agreement.
        :param consumer_account: Account instance of the consumer
        :param auto_consume: boolean tells this function wether to automatically trigger
            consuming the asset upon receiving access permission
        :raises OceanInitializeServiceAgreementError: on failure
        :return: bool
        """
        asset = self._asset_resolver.resolve(did)
        service_agreement = asset.get_service_by_index(service_index)
        # subscribe to events related to this agreement_id before sending the request.
        logger.debug(
            f'Registering service agreement with id: {agreement_id}, auto-consume {auto_consume}'
        )
        # TODO: refactor this to use same code in `create`

        publisher_address = self._keeper.did_registry.get_did_owner(
            asset.asset_id)
        condition_ids = service_agreement.generate_agreement_condition_ids(
            agreement_id, asset.asset_id, consumer_account.address,
            publisher_address, self._keeper)
        from_block = Web3Provider.get_web3().eth.blockNumber
        self._process_consumer_agreement_events(
            agreement_id, did, service_agreement, consumer_account,
            condition_ids, publisher_address, from_block, auto_consume)

        return BrizoProvider.get_brizo().initialize_service_agreement(
            did, agreement_id, service_index, signature,
            consumer_account.address, service_agreement.endpoints.purchase)
    def execute(self, agreement_id, did, index, consumer_account,
                workflow_did):
        """

        :param agreement_id:representation of `bytes32` id, hexstr
        :param did: computing service did, str
        :param index: id of the service within the asset DDO, str
        :param consumer_account: Account instance of the consumer ordering the service
        :param workflow_did: the asset did (of `workflow` type) which consist of `did:op:` and
        the assetId hex str (without `0x` prefix), str
        :return: local path on the file system where the asset data files are downloaded, str
        """
        workflow_ddo = self.resolve(workflow_did)
        compute_ddo = self.resolve(did)
        if index is not None:
            assert isinstance(index,
                              int), logger.error('index has to be an integer.')
            assert index >= 0, logger.error(
                'index has to be 0 or a positive integer.')
        return self._asset_executor.execute(agreement_id, compute_ddo,
                                            workflow_ddo, consumer_account,
                                            BrizoProvider.get_brizo(), index)
Exemple #8
0
    def consume(self, service_agreement_id, did, service_definition_id,
                consumer_account, destination):
        """
        Consume the asset data.

        Using the service endpoint defined in the ddo's service pointed to by service_definition_id.
        Consumer's permissions is checked implicitly by the secret-store during decryption
        of the contentUrls.
        The service endpoint is expected to also verify the consumer's permissions to consume this
        asset.
        This method downloads and saves the asset datafiles to disk.

        :param service_agreement_id: str
        :param did: DID, str
        :param service_definition_id: identifier of the service inside the asset DDO, str
        :param consumer_account: Account instance of the consumer
        :param destination: str path
        :return: str path to saved files
        """
        ddo = self.resolve(did)
        return self._asset_consumer.download(
            service_agreement_id, service_definition_id, ddo, consumer_account,
            destination, BrizoProvider.get_brizo(),
            self._get_secret_store(consumer_account))
    def create(self,
               metadata,
               publisher_account,
               service_descriptors=None,
               providers=None,
               use_secret_store=True):
        """
        Register an asset in both the keeper's DIDRegistry (on-chain) and in the Metadata store (
        Aquarius).

        :param metadata: dict conforming to the Metadata accepted by Ocean Protocol.
        :param publisher_account: Account of the publisher registering this asset
        :param service_descriptors: list of ServiceDescriptor tuples of length 2.
            The first item must be one of ServiceTypes and the second
            item is a dict of parameters and values required by the service
        :param providers: list of addresses of providers of this asset (a provider is
            an ethereum account that is authorized to provide asset services)
        :param use_secret_store: bool indicate whether to use the secret store directly for
            encrypting urls (Uses Brizo provider service if set to False)
        :return: DDO instance
        """
        assert isinstance(
            metadata,
            dict), f'Expected metadata of type dict, got {type(metadata)}'
        assert service_descriptors is None or isinstance(service_descriptors, list), \
            f'bad type of `service_descriptors` {type(service_descriptors)}'
        # if not metadata or not Metadata.validate(metadata):
        #     raise OceanInvalidMetadata('Metadata seems invalid. Please make sure'
        #                                ' the required metadata values are filled in.')

        # copy metadata so we don't change the original
        metadata_copy = copy.deepcopy(metadata)
        asset_type = metadata_copy['main']['type']
        assert asset_type in (
            'dataset',
            'algorithm'), f'Invalid/unsupported asset type {asset_type}'

        service_descriptors = service_descriptors or []
        brizo = BrizoProvider.get_brizo()

        services = self._process_service_descriptors(service_descriptors,
                                                     metadata_copy,
                                                     publisher_account)
        stype_to_service = {s.type: s for s in services}
        checksum_dict = dict()
        for service in services:
            checksum_dict[str(service.index)] = checksum(service.main)

        # Create a DDO object
        ddo = DDO()
        # Adding proof to the ddo.
        ddo.add_proof(checksum_dict, publisher_account)

        # Generating the did and adding to the ddo.
        did = ddo.assign_did(DID.did(ddo.proof['checksum']))
        logger.debug(f'Generating new did: {did}')
        # Check if it's already registered first!
        if did in self._get_aquarius().list_assets():
            raise OceanDIDAlreadyExist(
                f'Asset id {did} is already registered to another asset.')

        md_service = stype_to_service[ServiceTypes.METADATA]
        ddo_service_endpoint = md_service.service_endpoint
        if '{did}' in ddo_service_endpoint:
            ddo_service_endpoint = ddo_service_endpoint.replace('{did}', did)
            md_service.set_service_endpoint(ddo_service_endpoint)

        # Populate the ddo services
        ddo.add_service(md_service)
        ddo.add_service(stype_to_service[ServiceTypes.AUTHORIZATION])
        access_service = stype_to_service.get(ServiceTypes.ASSET_ACCESS, None)
        compute_service = stype_to_service.get(ServiceTypes.CLOUD_COMPUTE,
                                               None)

        if access_service:
            access_service.init_conditions_values(
                did, {
                    cname: c.address
                    for cname, c in
                    self._keeper.contract_name_to_instance.items()
                })
            ddo.add_service(access_service)
        if compute_service:
            compute_service.init_conditions_values(
                did, {
                    cname: c.address
                    for cname, c in
                    self._keeper.contract_name_to_instance.items()
                })
            ddo.add_service(compute_service)

        ddo.proof['signatureValue'] = self._keeper.sign_hash(
            add_ethereum_prefix_and_hash_msg(did_to_id_bytes(did)),
            publisher_account)

        # Add public key and authentication
        ddo.add_public_key(did, publisher_account.address)

        ddo.add_authentication(did, PUBLIC_KEY_TYPE_RSA)

        # Setup metadata service
        # First compute files_encrypted
        if metadata_copy['main']['type'] == 'dataset':
            assert metadata_copy['main']['files'], \
                'files is required in the metadata main attributes.'
            logger.debug('Encrypting content urls in the metadata.')
            if not use_secret_store:
                encrypt_endpoint = brizo.get_encrypt_endpoint(self._config)
                files_encrypted = brizo.encrypt_files_dict(
                    metadata_copy['main']['files'], encrypt_endpoint,
                    ddo.asset_id, publisher_account.address,
                    self._keeper.sign_hash(
                        add_ethereum_prefix_and_hash_msg(ddo.asset_id),
                        publisher_account))
            else:
                files_encrypted = self._get_secret_store(publisher_account) \
                    .encrypt_document(
                    did_to_id(did),
                    json.dumps(metadata_copy['main']['files']),
                )

            # only assign if the encryption worked
            if files_encrypted:
                logger.debug(
                    f'Content urls encrypted successfully {files_encrypted}')
                index = 0
                for file in metadata_copy['main']['files']:
                    file['index'] = index
                    index = index + 1
                    del file['url']
                metadata_copy['encryptedFiles'] = files_encrypted
            else:
                raise AssertionError('Encrypting the files failed.')

        # DDO url and `Metadata` service

        logger.debug(f'Generated ddo and services, DID is {ddo.did},'
                     f' metadata service @{ddo_service_endpoint}.')
        response = None

        # register on-chain
        registered_on_chain = self._keeper.did_registry.register(
            ddo.asset_id,
            checksum=Web3Provider.get_web3().toBytes(hexstr=ddo.asset_id),
            url=ddo_service_endpoint,
            account=publisher_account,
            providers=providers)
        if registered_on_chain is False:
            logger.warning(f'Registering {did} on-chain failed.')
            return None
        logger.info(f'Successfully registered DDO (DID={did}) on chain.')
        try:
            # publish the new ddo in ocean-db/Aquarius
            response = self._get_aquarius().publish_asset_ddo(ddo)
            logger.info('Asset/ddo published successfully in aquarius.')
        except ValueError as ve:
            raise ValueError(
                f'Invalid value to publish in the metadata: {str(ve)}')
        except Exception as e:
            logger.error(f'Publish asset in aquarius failed: {str(e)}')
        if not response:
            return None
        return ddo
Exemple #10
0
    def create(self,
               metadata,
               publisher_account,
               service_descriptors=None,
               providers=None,
               use_secret_store=True):
        """
        Register an asset in both the keeper's DIDRegistry (on-chain) and in the Metadata store (
        Aquarius).

        :param metadata: dict conforming to the Metadata accepted by Ocean Protocol.
        :param publisher_account: Account of the publisher registering this asset
        :param service_descriptors: list of ServiceDescriptor tuples of length 2.
            The first item must be one of ServiceTypes and the second
            item is a dict of parameters and values required by the service
        :param providers: list of addresses of providers of this asset (a provider is
            an ethereum account that is authorized to provide asset services)
        :return: DDO instance
        """
        assert isinstance(
            metadata,
            dict), f'Expected metadata of type dict, got {type(metadata)}'
        if not metadata or not Metadata.validate(metadata):
            raise OceanInvalidMetadata(
                'Metadata seems invalid. Please make sure'
                ' the required metadata values are filled in.')

        # copy metadata so we don't change the original
        metadata_copy = copy.deepcopy(metadata)

        # Create a DDO object
        did = DID.did()
        logger.debug(f'Generating new did: {did}')
        # Check if it's already registered first!
        if did in self._get_aquarius().list_assets():
            raise OceanDIDAlreadyExist(
                f'Asset id {did} is already registered to another asset.')

        ddo = DDO(did)

        # Add public key and authentication
        ddo.add_public_key(did, publisher_account.address)
        ddo.add_authentication(did, PUBLIC_KEY_TYPE_RSA)

        priv_key = ddo.get_private_key()

        # Setup metadata service
        # First replace `files` with encrypted `files`
        assert metadata_copy['base'][
            'files'], 'files is required in the metadata base attributes.'
        assert Metadata.validate(metadata), 'metadata seems invalid.'
        logger.debug('Encrypting content urls in the metadata.')
        brizo = BrizoProvider.get_brizo()
        if not use_secret_store:
            encrypt_endpoint = brizo.get_encrypt_endpoint(self._config)
            files_encrypted = brizo.encrypt_files_dict(
                metadata_copy['base']['files'], encrypt_endpoint, ddo.asset_id,
                publisher_account.address,
                self._keeper.sign_hash(ddo.asset_id, publisher_account))
        else:
            files_encrypted = self._get_secret_store(publisher_account) \
                .encrypt_document(
                did_to_id(did),
                json.dumps(metadata_copy['base']['files']),
            )

        metadata_copy['base']['checksum'] = ddo.generate_checksum(
            did, metadata)
        ddo.add_proof(metadata_copy['base']['checksum'],
                      publisher_account.address,
                      private_key=priv_key)

        # only assign if the encryption worked
        if files_encrypted:
            logger.info(
                f'Content urls encrypted successfully {files_encrypted}')
            index = 0
            for file in metadata_copy['base']['files']:
                file['index'] = index
                index = index + 1
                del file['url']
            metadata_copy['base']['encryptedFiles'] = files_encrypted
        else:
            raise AssertionError(
                'Encrypting the files failed. Make sure the secret store is'
                ' setup properly in your config file.')

        # DDO url and `Metadata` service
        ddo_service_endpoint = self._get_aquarius().get_service_endpoint(did)
        metadata_service_desc = ServiceDescriptor.metadata_service_descriptor(
            metadata_copy, ddo_service_endpoint)
        if not service_descriptors:
            service_descriptors = [
                ServiceDescriptor.authorization_service_descriptor(
                    self._config.secret_store_url)
            ]
            brizo = BrizoProvider.get_brizo()
            service_descriptors += [
                ServiceDescriptor.access_service_descriptor(
                    metadata[MetadataBase.KEY]['price'],
                    brizo.get_purchase_endpoint(self._config),
                    brizo.get_service_endpoint(self._config), 3600,
                    self._keeper.escrow_access_secretstore_template.address)
            ]
        else:
            service_types = set(map(lambda x: x[0], service_descriptors))
            if ServiceTypes.AUTHORIZATION not in service_types:
                service_descriptors += [
                    ServiceDescriptor.authorization_service_descriptor(
                        self._config.secret_store_url)
                ]
            else:
                brizo = BrizoProvider.get_brizo()
                service_descriptors += [
                    ServiceDescriptor.access_service_descriptor(
                        metadata[MetadataBase.KEY]['price'],
                        brizo.get_purchase_endpoint(self._config),
                        brizo.get_service_endpoint(self._config), 3600, self.
                        _keeper.escrow_access_secretstore_template.address)
                ]

        # Add all services to ddo
        service_descriptors = service_descriptors + [metadata_service_desc]
        for service in ServiceFactory.build_services(did, service_descriptors):
            ddo.add_service(service)

        logger.debug(
            f'Generated ddo and services, DID is {ddo.did},'
            f' metadata service @{ddo_service_endpoint}, '
            f'`Access` service purchase @{ddo.services[0].endpoints.service}.')
        response = None
        try:
            # publish the new ddo in ocean-db/Aquarius
            response = self._get_aquarius().publish_asset_ddo(ddo)
            logger.debug('Asset/ddo published successfully in aquarius.')
        except ValueError as ve:
            raise ValueError(
                f'Invalid value to publish in the metadata: {str(ve)}')
        except Exception as e:
            logger.error(f'Publish asset in aquarius failed: {str(e)}')

        if not response:
            return None

        # register on-chain
        self._keeper.did_registry.register(
            did,
            checksum=Web3Provider.get_web3().sha3(
                text=metadata_copy['base']['checksum']),
            url=ddo_service_endpoint,
            account=publisher_account,
            providers=providers)
        logger.info(f'DDO with DID {did} successfully registered on chain.')
        return ddo