def test_did(): assert DID.did().startswith(OCEAN_PREFIX) assert len(DID.did()) - len(OCEAN_PREFIX) == 64 assert DID.did() != DID.did(), '' _id = did_to_id(DID.did()) assert not _id.startswith( '0x'), 'id portion of did should not have a 0x prefix.'
def fulfill_access_secret_store_condition(event, agreement_id, did, service_agreement, consumer_address, publisher_account): """ Fulfill the access condition. :param event: AttributeDict with the event data. :param agreement_id: id of the agreement, hex str :param did: DID, str :param service_agreement: ServiceAgreement instance :param consumer_address: ethereum account address of consumer, hex str :param publisher_account: Account instance of the publisher """ logger.debug(f"release reward after event {event}.") name_to_parameter = { param.name: param for param in service_agreement.condition_by_name['accessSecretStore'].parameters } document_id = add_0x_prefix(name_to_parameter['_documentId'].value) asset_id = add_0x_prefix(did_to_id(did)) assert document_id == asset_id, f'document_id {document_id} <=> asset_id {asset_id} mismatch.' try: tx_hash = Keeper.get_instance().access_secret_store_condition.fulfill( agreement_id, document_id, consumer_address, publisher_account) process_tx_receipt( tx_hash, Keeper.get_instance().access_secret_store_condition. FULFILLED_EVENT, 'AccessSecretStoreCondition.Fulfilled') except Exception as e: # logger.error(f'Error when calling grantAccess condition function: {e}') raise e
def encrypt(ctx, plain_text): ocean, account = ctx.obj['ocean'], ctx.obj['account'] doc_id = did_to_id(DID.did()) encrypted_document = ocean.secret_store.encrypt(doc_id, plain_text, account) echo({ 'docId': doc_id, 'encryptedDocument': encrypted_document })
def download(service_agreement_id, service_definition_id, ddo, consumer_account, destination, brizo, secret_store): """ Download asset data files or result files from a compute job. :param service_agreement_id: Service agreement id, str :param service_definition_id: identifier of the service inside the asset DDO, str :param ddo: DDO :param consumer_account: Account instance of the consumer :param destination: Path, str :param brizo: Brizo instance :param secret_store: SecretStore instance :return: Asset folder path, str """ did = ddo.did encrypted_files = ddo.metadata['base']['encryptedFiles'] encrypted_files = (encrypted_files if isinstance(encrypted_files, str) else encrypted_files[0]) sa = ServiceAgreement.from_ddo(service_definition_id, ddo) consume_url = sa.consume_endpoint if not consume_url: logger.error( 'Consume asset failed, service definition is missing the "serviceEndpoint".' ) raise AssertionError( 'Consume asset failed, service definition is missing the "serviceEndpoint".' ) if ddo.get_service('Authorization'): secret_store_service = ddo.get_service( service_type=ServiceTypes.AUTHORIZATION) secret_store_url = secret_store_service.endpoints.consume secret_store.set_secret_store_url(secret_store_url) # decrypt the contentUrls decrypted_content_urls = json.loads( secret_store.decrypt_document(did_to_id(did), encrypted_files)) if isinstance(decrypted_content_urls, str): decrypted_content_urls = [decrypted_content_urls] logger.debug(f'got decrypted contentUrls: {decrypted_content_urls}') if not os.path.isabs(destination): destination = os.path.abspath(destination) if not os.path.exists(destination): os.mkdir(destination) asset_folder = os.path.join( destination, f'datafile.{did_to_id(did)}.{sa.service_definition_id}') if not os.path.exists(asset_folder): os.mkdir(asset_folder) brizo.consume_service(service_agreement_id, consume_url, consumer_account, decrypted_content_urls, asset_folder) return asset_folder
def get(did): register_values = Keeper.get_instance().did_registry.contract_concise\ .getDIDRegister(did_to_id(did)) response = [] if register_values and len(register_values) == 5: response = DIDRegisterValues(*register_values)._asdict() response['last_checksum'] = Web3Provider.get_web3()\ .toHex(response['last_checksum']) return response
def execute_service_agreement(self, did, service_index, service_agreement_id, service_agreement_signature, consumer_address, publisher_address): """ Execute the service agreement on-chain using keeper's ServiceAgreement contract. The on-chain executeAgreement method requires the following arguments: templateId, signature, consumer, hashes, timeouts, serviceAgreementId, did `agreement_message_hash` is necessary to verify the signature. The consumer `signature` includes the conditions timeouts and parameters value which is used on-chain to verify the values actually match the signed hashes. :param did: str representation fo the asset DID. Use this to retrieve the asset DDO. :param service_index: int identifies the specific service in the ddo to use in this agreement. :param service_agreement_id: 32 bytes identifier created by the consumer and will be used on-chain for the executed agreement. :param service_agreement_signature: str the signed agreement message hash which includes conditions and their parameters values and other details of the agreement. :param consumer_address: ethereum account address of consumer :param publisher_address: ethereum account address of publisher :return: """ assert consumer_address and self._web3.isChecksumAddress( consumer_address ), 'Invalid consumer address "%s"' % consumer_address assert publisher_address and self._web3.isChecksumAddress( publisher_address ), 'Invalid publisher address "%s"' % publisher_address assert publisher_address in self.accounts, 'Unrecognized publisher address %s' % publisher_address asset_id = did_to_id(did) ddo, service_agreement, service_def = self._get_ddo_and_service_agreement( did, service_index) content_urls = get_metadata_url(ddo) self.verify_service_agreement_signature(did, service_agreement_id, service_index, consumer_address, service_agreement_signature, ddo=ddo) # subscribe to events related to this service_agreement_id register_service_agreement(self._web3, self.keeper.contract_path, self.config.storage_path, self.main_account, service_agreement_id, did, service_def, 'publisher', service_index, service_agreement.get_price(), content_urls, None, 0) receipt = self.keeper.service_agreement.execute_service_agreement( service_agreement.template_id, service_agreement_signature, consumer_address, service_agreement.conditions_params_value_hashes, service_agreement.conditions_timeouts, service_agreement_id, asset_id, self.main_account) return receipt
def consume_service(self, service_agreement_id, did, service_index, consumer_account): ddo = self.resolve_did(did) metadata_service = ddo.get_service(service_type=ServiceTypes.METADATA) content_urls = metadata_service.get_values( )['metadata']['base']['contentUrls'] service = ddo.find_service_by_key_value( ServiceAgreement.SERVICE_DEFINITION_ID_KEY, service_index) sa = ServiceAgreement.from_service_dict(service.as_dictionary()) service_url = sa.service_endpoint if not service_url: print( 'Consume asset failed, service definition is missing the "serviceEndpoint".' ) raise AssertionError( 'Consume asset failed, service definition is missing the "serviceEndpoint".' ) # decrypt the contentUrls decrypted_content_urls = json.loads( self._decrypt_content_urls(did, content_urls)) if isinstance(decrypted_content_urls, str): decrypted_content_urls = [decrypted_content_urls] print('got decrypted contentUrls: ', decrypted_content_urls) asset_folder = 'datafile.%s.%s' % (did_to_id(did), service_index) asset_folder = os.path.join(self._downloads_path, asset_folder) if not os.path.exists(self._downloads_path): os.mkdir(self._downloads_path) if not os.path.exists(asset_folder): os.mkdir(asset_folder) for url in decrypted_content_urls: if url.startswith('"') or url.startswith("'"): url = url[1:-1] print('invoke consume endpoint for this url: %s' % url) consume_url = ( '%s?url=%s&serviceAgreementId=%s&consumerAddress=%s' % (service_url, url, service_agreement_id, consumer_account.address)) response = self._http_client.get(consume_url) if response.status_code == 200: download_url = response.url.split('?')[0] file_name = os.path.basename(download_url) with open(os.path.join(asset_folder, file_name), 'wb') as f: f.write(response.content) print('Saved downloaded file in "%s"' % f.name) else: print('consume failed: %s' % response.reason)
def build_access_service(did, price, purchase_endpoint, service_endpoint, timeout, template_id): param_map = { 'assetId': did_to_id(did), 'price': price, 'documentKeyId': did_to_id(did) } sla_template_path = get_sla_template_path() sla_template = ServiceAgreementTemplate.from_json_file( sla_template_path) sla_template.template_id = template_id conditions = sla_template.conditions[:] conditions_json_list = [] for cond in conditions: for param in cond.parameters: param.value = param_map[param.name] if cond.timeout > 0: cond.timeout = timeout conditions_json_list.append(cond) sa = ServiceAgreement(1, sla_template.template_id, sla_template.conditions, sla_template.service_agreement_contract) other_values = { ServiceAgreement.SERVICE_DEFINITION_ID_KEY: sa.sa_definition_id, ServiceAgreementTemplate.TEMPLATE_ID_KEY: sla_template.template_id, ServiceAgreement.SERVICE_CONTRACT_KEY: sa.service_agreement_contract, ServiceAgreement.SERVICE_CONDITIONS_KEY: conditions, 'purchaseEndpoint': purchase_endpoint } return Service(did, service_endpoint, ServiceTypes.ASSET_ACCESS, values=other_values)
def test_get_resolve_url(publisher_ocean_instance): ocean = publisher_ocean_instance register_account = ocean.main_account did_registry = keeper().did_registry did = DID.did() value_test = 'http://localhost:5000' did_resolver = DIDResolver(keeper().did_registry) did_registry.register(did, b'test', url=value_test, account=register_account) did_id = did_to_id(did) url = did_resolver.get_resolve_url(Web3.toBytes(hexstr=did_id)) assert url == value_test
def test_did_to_id(): did = DID.did() _id = did_to_id(did) assert _id is not None and len(_id) == 64, '' test_id = '%s' % secrets.token_hex(32) assert did_to_id(f'{OCEAN_PREFIX}{test_id}') == test_id assert did_to_id('did:op1:011') == '011' assert did_to_id('did:op:0') == '0' with pytest.raises(ValueError): did_to_id(OCEAN_PREFIX) assert did_to_id(f'{OCEAN_PREFIX}AB*&$#') == 'AB', ''
def grant_access(self, agreement_id, did, grantee_address, account): """ Grant access condition. :param agreement_id: id of the agreement, hex str :param did: DID, str :param grantee_address: Address, hex str :param account: Account :return: """ tx_hash = self._keeper.access_secret_store_condition.fulfill( agreement_id, add_0x_prefix(did_to_id(did)), grantee_address, account) return self._keeper.access_secret_store_condition.get_tx_receipt( tx_hash).status == 1
def _decrypt_content_urls(self, did, encrypted_data): result = None if self.config.secret_store_url and self.config.parity_url and self.main_account: consumer = self._secret_store_client(self.config.secret_store_url, self.config.parity_url, self.main_account.address, self.main_account.password) document_id = did_to_id(did) # :FIXME: -- modify the secret store lib to handle this. if document_id.startswith('0x'): document_id = document_id[2:] result = consumer.decrypt_document(document_id, encrypted_data) return result
def check_permissions(self, service_agreement_id, did, consumer_address): """ Verify on-chain that the `consumer_address` has permission to access the given `asset_did` according to the `service_agreement_id`. :param service_agreement_id: :param did: :param consumer_address: :return: bool True if user has permission """ agreement_consumer = self.keeper.service_agreement.get_service_agreement_consumer( service_agreement_id) if agreement_consumer != consumer_address: print('Invalid consumer address and/or service agreement id.') return False document_id = did_to_id(did) return self.keeper.access_conditions.check_permissions( consumer_address, document_id, self.main_account.address)
def _encrypt_metadata_content_urls(self, did, data): """ encrypt string data using the DID as an secret store id, if secret store is enabled then return the result from secret store encryption return None for no encryption performed """ result = None if self.config.secret_store_url and self.config.parity_url and self.main_account: publisher = self._secret_store_client(self.config.secret_store_url, self.config.parity_url, self.main_account.address, self.main_account.password) document_id = did_to_id(did) # :FIXME: -- modify the secret store lib to handle this. if document_id.startswith('0x'): document_id = document_id[2:] result = publisher.publish_document(document_id, data) return result
def build_access_service(did, price, purchase_endpoint, service_endpoint, timeout, template_id): """ Build the access service. :param did: DID, str :param price: Asset price, int :param purchase_endpoint: url of the service provider, str :param service_endpoint: identifier of the service inside the asset DDO, str :param timeout: amount of time in seconds before the agreement expires, int :param template_id: id of the template use to create the service, str :return: ServiceAgreement """ # TODO fill all the possible mappings param_map = { '_documentId': did_to_id(did), '_amount': price, '_rewardAddress': Keeper.get_instance().escrow_reward_condition.address, } sla_template_path = get_sla_template_path() sla_template = ServiceAgreementTemplate.from_json_file( sla_template_path) sla_template.template_id = template_id conditions = sla_template.conditions[:] for cond in conditions: for param in cond.parameters: param.value = param_map.get(param.name, '') if cond.timeout > 0: cond.timeout = timeout sla_template.set_conditions(conditions) sa = ServiceAgreement(1, sla_template, purchase_endpoint, service_endpoint, ServiceTypes.ASSET_ACCESS) sa.set_did(did) return sa
def refund_reward(event, agreement_id, did, service_agreement, price, consumer_account, publisher_address, condition_ids): """ Refund the reward to the publisher address. :param event: AttributeDict with the event data. :param agreement_id: id of the agreement, hex str :param did: DID, str :param service_agreement: ServiceAgreement instance :param price: Asset price, int :param consumer_account: Account instance of the consumer :param publisher_address: ethereum account address of publisher, hex str :param condition_ids: is a list of bytes32 content-addressed Condition IDs, bytes32 """ logger.debug(f"trigger refund after event {event}.") access_id, lock_id = condition_ids[:2] name_to_parameter = { param.name: param for param in service_agreement.condition_by_name['escrowReward'].parameters } document_id = add_0x_prefix(name_to_parameter['_documentId'].value) asset_id = add_0x_prefix(did_to_id(did)) assert document_id == asset_id, f'document_id {document_id} <=> asset_id {asset_id} mismatch.' assert price == service_agreement.get_price(), 'price mismatch.' # logger.info(f'About to do grantAccess: account {account.address}, # saId {service_agreement_id}, ' # f'documentKeyId {document_key_id}') try: tx_hash = Keeper.get_instance().escrow_reward_condition.fulfill( agreement_id, price, publisher_address, consumer_account.address, lock_id, access_id, consumer_account) process_tx_receipt( tx_hash, Keeper.get_instance().escrow_reward_condition.FULFILLED_EVENT, 'EscrowReward.Fulfilled') except Exception as e: # logger.error(f'Error when doing escrow_reward_condition.fulfills: {e}') raise e
def test_publish(client, publisher_ocean_instance): ocn = publisher_ocean_instance endpoint = BaseURLs.ASSETS_URL + '/publish' did = DID.did() asset_id = did_to_id(did) account = get_provider_account(ocn) test_urls = ['url 0', 'url 1', 'url 2'] urls_json = json.dumps(test_urls) signature = Keeper.get_instance().sign_hash(asset_id, account) address = Web3Provider.get_web3().personal.ecRecover(asset_id, signature) assert address.lower() == account.address.lower() payload = { 'documentId': asset_id, 'signedDocumentId': signature, 'document': urls_json, 'publisherAddress': account.address } post_response = client.post(endpoint, data=json.dumps(payload), content_type='application/json') encrypted_url = post_response.data.decode('utf-8') assert encrypted_url.startswith('0x')
def decrypt(ocn, account, did): ddo = ocn.assets.resolve(did) encrypted_files = ddo.metadata['base']['encryptedFiles'] encrypted_files = (encrypted_files if isinstance(encrypted_files, str) else encrypted_files[0]) secret_store = ocn.assets._get_secret_store(account) if ddo.get_service('Authorization'): secret_store_service = ddo.get_service( service_type=ServiceTypes.AUTHORIZATION) secret_store_url = secret_store_service.endpoints.service secret_store.set_secret_store_url(secret_store_url) # decrypt the contentUrls try: decrypted_content_urls = json.loads( secret_store.decrypt_document(did_to_id(did), encrypted_files)) except RPCError: decrypted_content_urls = encrypted_files if isinstance(decrypted_content_urls, str): decrypted_content_urls = [decrypted_content_urls] return decrypted_content_urls
def assets_get_providers(did): response = Keeper.get_instance().did_registry\ .get_did_providers(did_to_id(did)) echo(response)
def test_check_permissions_not_registered_did(): consumer_account = get_consumer_account(ConfigProvider.get_config()) assert not access_secret_store_condition.check_permissions( did_to_id(DID.did()), consumer_account.address)
def test_get_resolve_multiple_urls(publisher_ocean_instance): ocean = publisher_ocean_instance register_account = ocean.main_account did_registry = keeper().did_registry did = DID.did() did2 = DID.did() did3 = DID.did() did4 = DID.did() did5 = DID.did() did6 = DID.did() did7 = DID.did() did8 = DID.did() did9 = DID.did() did10 = DID.did() value_test = 'http://localhost:5000' value_test2 = 'http://localhost:5001' value_test3 = 'http://localhost:5002' value_test4 = 'http://localhost:5003' value_test5 = 'http://localhost:5004' value_test6 = 'http://localhost:5005' value_test7 = 'http://localhost:5006' value_test8 = 'http://localhost:5007' value_test9 = 'http://localhost:5008' value_test10 = 'http://localhost:5009' did_resolver = DIDResolver(keeper().did_registry) did_registry.register(did, b'test', url=value_test, account=register_account) did_registry.register(did2, b'test', url=value_test2, account=register_account) did_registry.register(did3, b'test', url=value_test3, account=register_account) did_registry.register(did4, b'test', url=value_test4, account=register_account) did_registry.register(did5, b'test', url=value_test5, account=register_account) did_registry.register(did6, b'test', url=value_test6, account=register_account) did_registry.register(did7, b'test', url=value_test7, account=register_account) did_registry.register(did8, b'test', url=value_test8, account=register_account) did_registry.register(did9, b'test', url=value_test9, account=register_account) did_registry.register(did10, b'test', url=value_test10, account=register_account) did_id = did_to_id(did) did_id2 = did_to_id(did2) did_id3 = did_to_id(did3) did_id4 = did_to_id(did4) did_id5 = did_to_id(did5) did_id6 = did_to_id(did6) did_id7 = did_to_id(did7) did_id8 = did_to_id(did8) did_id9 = did_to_id(did9) did_id10 = did_to_id(did10) url = did_resolver.get_resolve_url(Web3.toBytes(hexstr=did_id)) url2 = did_resolver.get_resolve_url(Web3.toBytes(hexstr=did_id2)) url3 = did_resolver.get_resolve_url(Web3.toBytes(hexstr=did_id3)) url4 = did_resolver.get_resolve_url(Web3.toBytes(hexstr=did_id4)) url5 = did_resolver.get_resolve_url(Web3.toBytes(hexstr=did_id5)) url6 = did_resolver.get_resolve_url(Web3.toBytes(hexstr=did_id6)) url7 = did_resolver.get_resolve_url(Web3.toBytes(hexstr=did_id7)) url8 = did_resolver.get_resolve_url(Web3.toBytes(hexstr=did_id8)) url9 = did_resolver.get_resolve_url(Web3.toBytes(hexstr=did_id9)) url10 = did_resolver.get_resolve_url(Web3.toBytes(hexstr=did_id10)) assert url == value_test assert url2 == value_test2 assert url3 == value_test3 assert url4 == value_test4 assert url5 == value_test5 assert url6 == value_test6 assert url7 == value_test7 assert url8 == value_test8 assert url9 == value_test9 assert url10 == value_test10
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
def assets_get_owner(did): response = Keeper.get_instance().did_registry\ .get_did_owner(did_to_id(did)) echo(response)
def asset_id(self): """The asset id part of the DID""" return add_0x_prefix(did_to_id(self._did))
def add_providers(account, did, provider): if provider == 'me': provider = account.address did_registry = Keeper.get_instance().did_registry return did_registry.add_provider(did_to_id(did), provider, account)
def assign_did_from_ddo(self): """ #TODO: This is a temporary hack, need to clearly define how DID is assigned! :return: """ self.asset_id = did_to_id(self._ddo.did)