def create(self, metadata, publisher_account, service_descriptors=None, providers=None, authorization_type=ServiceAuthorizationTypes.PSK_RSA, use_secret_store=False, activity_id=None, attributes=None, asset_rewards={"_amounts": [], "_receivers": []}, cap=None, royalties=None, mint=0): """ Register an asset in both the keeper's DIDRegistry (on-chain) and in the Metadata store. :param metadata: dict conforming to the Metadata accepted by Nevermined 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 authorization_type: str indicate the authorization type that is going to be used to encrypt the urls. SecretStore, PSK-RSA and PSK-ECDSA are supported. :param use_secret_store: bool indicate whether to use the secret store directly for encrypting urls (Uses Gateway provider service if set to False) :param activity_id: identifier of the activity creating the new entity :param attributes: attributes associated with the action :param asset_rewards: rewards distribution including the amounts and the receivers :param cap: max cap of nfts that can be minted for the asset :param royalties: royalties in the secondary market going to the original creator :param mint: number of nfts to mint just after registration of the asset :return: DDO instance """ assert isinstance(metadata, dict), f'Expected metadata of type dict, got {type(metadata)}' # copy metadata so we don't change the original metadata_copy = copy.deepcopy(metadata) # Create a DDO object ddo = DDO() gateway = GatewayProvider.get_gateway() ddo_service_endpoint = self._get_metadata_provider().get_service_endpoint() metadata_service_desc = ServiceDescriptor.metadata_service_descriptor(metadata_copy, ddo_service_endpoint) if metadata_copy['main']['type'] == 'dataset' or metadata_copy['main'][ 'type'] == 'algorithm': access_service_attributes = self._build_access(metadata_copy, publisher_account, asset_rewards) if not service_descriptors: if authorization_type == ServiceAuthorizationTypes.PSK_RSA: service_descriptors = [ServiceDescriptor.authorization_service_descriptor( self._build_authorization(authorization_type, public_key=gateway.get_rsa_public_key(self._config)), gateway.get_access_endpoint(self._config) )] elif authorization_type == ServiceAuthorizationTypes.PSK_ECDSA: service_descriptors = [ServiceDescriptor.authorization_service_descriptor( self._build_authorization(authorization_type, public_key=gateway.get_ecdsa_public_key(self._config)), gateway.get_access_endpoint(self._config) )] else: service_descriptors = [ServiceDescriptor.authorization_service_descriptor( self._build_authorization(authorization_type, threshold=0), self._config.secret_store_url )] service_descriptors += [ServiceDescriptor.access_service_descriptor( access_service_attributes, gateway.get_access_endpoint(self._config) )] else: service_types = set(map(lambda x: x[0], service_descriptors)) if ServiceTypes.AUTHORIZATION not in service_types: if authorization_type == ServiceAuthorizationTypes.PSK_RSA: service_descriptors += [ServiceDescriptor.authorization_service_descriptor( self._build_authorization(authorization_type, public_key=gateway.get_rsa_public_key(self._config)), gateway.get_access_endpoint(self._config) )] elif authorization_type == ServiceAuthorizationTypes.PSK_ECDSA: service_descriptors += [ServiceDescriptor.authorization_service_descriptor( self._build_authorization(authorization_type, public_key=gateway.get_ecdsa_public_key(self._config)), gateway.get_access_endpoint(self._config) )] else: service_descriptors += [ServiceDescriptor.authorization_service_descriptor( self._build_authorization(authorization_type, threshold=0), self._config.secret_store_url )] else: service_descriptors += [ServiceDescriptor.access_service_descriptor( access_service_attributes, gateway.get_access_endpoint(self._config) )] else: if not service_descriptors: service_descriptors = [] else: service_descriptors += [] logger.info('registering a workflow.') # Add all services to ddo service_descriptors = [metadata_service_desc] + service_descriptors services = ServiceFactory.build_services(service_descriptors) checksums = dict() for service in services: checksums[str(service.index)] = checksum(service.main) # Adding proof to the ddo. ddo.add_proof(checksums, publisher_account) # Generating the did and adding to the ddo. did_seed = checksum(ddo.proof['checksum']) asset_id = self._keeper.did_registry.hash_did(did_seed, publisher_account.address) ddo._did = DID.did(asset_id) did = ddo._did logger.debug(f'Generating new did: {did}') # Check if it's already registered first! if did in self._get_metadata_provider().list_assets(): raise DIDAlreadyExist( f'Asset id {did} is already registered to another asset.') for service in services: if service.type == ServiceTypes.ASSET_ACCESS: access_service = ServiceFactory.complete_access_service( did, gateway.get_access_endpoint(self._config), access_service_attributes, self._keeper.access_template.address, self._keeper.escrow_payment_condition.address, service.type ) ddo.add_service(access_service) elif service.type == ServiceTypes.NFT_ACCESS: access_service = ServiceFactory.complete_access_service( did, gateway.get_nft_access_endpoint(self._config), self._build_nft_access(metadata_copy, publisher_account, asset_rewards, service.main['_numberNfts']), self._keeper.nft_access_template.address, self._keeper.escrow_payment_condition.address, service.type ) ddo.add_service(access_service) elif service.type == ServiceTypes.NFT_SALES: nft_sales_service = ServiceFactory.complete_nft_sales_service( did, gateway.get_access_endpoint(self._config), service.attributes, self._keeper.nft_sales_template.address, self._keeper.escrow_payment_condition.address, service.type ) ddo.add_service(nft_sales_service) elif service.type == ServiceTypes.METADATA: ddo_service_endpoint = service.service_endpoint.replace('{did}', did) service.set_service_endpoint(ddo_service_endpoint) ddo.add_service(service) elif service.type == ServiceTypes.CLOUD_COMPUTE: compute_service = ServiceFactory.complete_compute_service( did, service.service_endpoint, service.attributes, self._keeper.compute_execution_condition.address, self._keeper.escrow_payment_condition.address ) ddo.add_service(compute_service) else: ddo.add_service(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'] in ['dataset', 'algorithm']: 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 = gateway.get_encrypt_endpoint(self._config) files_encrypted = gateway.encrypt_files_dict( metadata_copy['main']['files'], encrypt_endpoint, ddo.asset_id, authorization_type) 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 if mint > 0 or royalties is not None or cap is not None: registered_on_chain = self._keeper.did_registry.register_mintable_did( did_seed, checksum=Web3Provider.get_web3().toBytes(hexstr=ddo.asset_id), url=ddo_service_endpoint, account=publisher_account, cap=cap, royalties=royalties, providers=providers, activity_id=activity_id, attributes=attributes ) if mint > 0: self._keeper.did_registry.mint(ddo.asset_id, mint, account=publisher_account) else: registered_on_chain = self._keeper.did_registry.register( did_seed, checksum=Web3Provider.get_web3().toBytes(hexstr=ddo.asset_id), url=ddo_service_endpoint, account=publisher_account, cap=cap, royalties=royalties, providers=providers, activity_id=activity_id, attributes=attributes ) 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 response = self._get_metadata_provider().publish_asset_ddo(ddo) logger.info('Asset/ddo published successfully in Metadata.') 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 Metadata failed: {str(e)}') if not response: return None return ddo
def register_ddo(metadata, account, providers, auth_service, additional_service_descriptors, royalties=None, cap=None, mint=0): keeper = keeper_instance() metadata_api = Metadata('http://172.17.0.1:5000') ddo = DDO() ddo_service_endpoint = metadata_api.get_service_endpoint() metadata_service_desc = ServiceDescriptor.metadata_service_descriptor( metadata, ddo_service_endpoint) authorization_service_attributes = { "main": { "service": auth_service, "publicKey": "0xd7" } } service_descriptors = [ ServiceDescriptor.authorization_service_descriptor( authorization_service_attributes, 'http://localhost:12001') ] service_descriptors += [metadata_service_desc] service_descriptors += additional_service_descriptors services = ServiceFactory.build_services(service_descriptors) checksums = dict() for service in services: try: checksums[str(service.index)] = checksum(service.main) except Exception as e: pass # Adding proof to the ddo. ddo.add_proof(checksums, account) did_seed = checksum(ddo.proof['checksum']) asset_id = keeper.did_registry.hash_did(did_seed, account.address) ddo._did = DID.did(asset_id) did = ddo._did for service in services: if service.type == ServiceTypes.ASSET_ACCESS or service.type == ServiceTypes.NFT_ACCESS or service.type == ServiceTypes.ASSET_ACCESS_PROOF: access_service = ServiceFactory.complete_access_service( did, service.service_endpoint, service.attributes, keeper.access_template.address, keeper.escrow_payment_condition.address, service.type) ddo.add_service(access_service) elif service.type == ServiceTypes.CLOUD_COMPUTE: compute_service = ServiceFactory.complete_compute_service( did, service.service_endpoint, service.attributes, keeper.compute_execution_condition.address, keeper.escrow_payment_condition.address) ddo.add_service(compute_service) elif service.type == ServiceTypes.NFT_SALES: nft_sales_service = ServiceFactory.complete_nft_sales_service( did, service.service_endpoint, service.attributes, keeper.nft_sales_template.address, keeper.escrow_payment_condition.address, service.type) ddo.add_service(nft_sales_service) else: ddo.add_service(service) ddo.proof['signatureValue'] = keeper.sign_hash(did_to_id_bytes(did), account) ddo.add_public_key(did, account.address) ddo.add_authentication(did, PUBLIC_KEY_TYPE_RSA) try: _oldddo = metadata_api.get_asset_ddo(ddo.did) if _oldddo: metadata_api.retire_asset_ddo(ddo.did) except ValueError: pass if 'files' in metadata['main']: if auth_service == ServiceAuthorizationTypes.SECRET_STORE: encrypted_files = do_secret_store_encrypt( remove_0x_prefix(ddo.asset_id), json.dumps(metadata['main']['files']), account, get_config()) elif auth_service == ServiceAuthorizationTypes.PSK_RSA: encrypted_files, public_key = rsa_encryption_from_file( json.dumps(metadata['main']['files']), get_rsa_public_key_file()) else: encrypted_files, public_key = ecdsa_encryption_from_file( json.dumps(metadata['main']['files']), get_provider_key_file(), get_provider_password()) _files = metadata['main']['files'] # only assign if the encryption worked if encrypted_files: index = 0 for file in metadata['main']['files']: file['index'] = index index = index + 1 del file['url'] metadata['encryptedFiles'] = encrypted_files ddo_with_did = DDO(did, json_text=ddo.as_text().replace('/{did}', '/' + did)) ddo_service_endpoint = ddo_service_endpoint.replace('/{did}', '/' + did) if mint > 0 or royalties is not None or cap is not None: keeper.did_registry.register_mintable_did( did_seed, checksum=web3().toBytes(hexstr=ddo.asset_id), url=ddo_service_endpoint, cap=cap, royalties=royalties, account=account, providers=providers) if mint > 0: keeper.did_registry.mint(ddo.asset_id, mint, account=account) else: keeper_instance().did_registry.register( did_seed, checksum=web3().toBytes(hexstr=ddo.asset_id), url=ddo_service_endpoint, account=account, providers=providers) metadata_api.publish_asset_ddo(ddo_with_did) return ddo_with_did