def test_agreement_hash(ddo_sample): """ This test verifies generating agreement hash using fixed inputs and ddo example. This will make it easier to compare the hash generated from different languages. """ w3 = Web3 did = "did:nv:0c184915b07b44c888d468be85a9b28253e80070e5294b1aaed81c2f0264e430" template_id = w3.toChecksumAddress( "0x00bd138abd70e2f00903268f3db08f2d25677c9e") agreement_id = '0xf136d6fadecb48fdb2fc1fb420f5a5d1c32d22d9424e47ab9461556e058fefaa' sa = ServiceAgreement.from_service_dict( ddo_sample.get_service(ServiceTypes.ASSET_ACCESS).as_dictionary()) sa.service_agreement_template.set_template_id(template_id) assert template_id == sa.template_id, '' assert did == ddo_sample.did # Don't generate condition ids, use fixed ids so we get consistent hash # (access_id, lock_id, escrow_id) = sa.generate_agreement_condition_ids( # agreement_id, ddo.asset_id, consumer, publisher, keeper) access_id = '0x2d7c1d60dc0c3f52aa9bd71ffdbe434a0e58435571e64c893bc9646fea7f6ec1' lock_id = '0x1e265c434c14e668695dda1555088f0ea4356f596bdecb8058812e7dcba9ee73' escrow_id = '0xe487fa6d435c2f09ef14b65b34521302f1532ac82ba8f6c86116acd8566e2da3' print(f'condition ids: \n' f'{access_id} \n' f'{lock_id} \n' f'{escrow_id}') agreement_hash = ServiceAgreement.generate_service_agreement_hash( sa.template_id, (access_id, lock_id, escrow_id), sa.conditions_timelocks, sa.conditions_timeouts, agreement_id, generate_multi_value_hash) print('agreement hash: ', agreement_hash.hex()) expected = '0x96732b390dacec0f19ad304ac176b3407968a0184d01b3262687fd23a3f0995e' print('expected hash: ', expected) assert agreement_hash.hex() == expected, 'hash does not match.'
def test_nft_access(client, provider_account, consumer_account): keeper = keeper_instance() ddo = get_nft_ddo(provider_account, providers=[provider_account.address]) asset_id = ddo.asset_id nft_amounts = 1 keeper.nft_upgradeable.transfer_nft(asset_id, consumer_account.address, nft_amounts, provider_account) assert keeper.nft_upgradeable.balance(consumer_account.address, asset_id) >= nft_amounts nft_access_service_agreement = ServiceAgreement.from_ddo( ServiceTypes.NFT_ACCESS, ddo) agreement_id = ServiceAgreement.create_new_agreement_id() (nft_access_cond_id, nft_holder_cond_id ) = nft_access_service_agreement.generate_agreement_condition_ids( agreement_id, asset_id, consumer_account.address, keeper) print('NFT_ACCESS_DID: ' + asset_id) keeper.nft_access_template.create_agreement( agreement_id, asset_id, [nft_holder_cond_id, nft_access_cond_id], nft_access_service_agreement.conditions_timelocks, nft_access_service_agreement.conditions_timeouts, consumer_account.address, consumer_account) event = keeper.nft_access_template.subscribe_agreement_created( agreement_id, 15, None, (), wait=True, from_block=0) assert event, "Agreement event is not found, check the keeper node's logs" # generate the grant token grant_token = generate_access_grant_token(consumer_account, agreement_id, ddo.did, uri="/nft-access") # request access token response = client.post("/api/v1/gateway/services/oauth/token", data={ "grant_type": NeverminedJWTBearerGrant.GRANT_TYPE, "assertion": grant_token }) access_token = response.get_json()["access_token"] index = 0 endpoint = BaseURLs.ASSETS_URL + '/nft-access/%s/%d' % (agreement_id, index) response = client.get(endpoint, headers={"Authorization": f"Bearer {access_token}"}) assert response.status == '200 OK' assert len( keeper.did_registry.get_provenance_method_events( 'USED', did_bytes=did_to_id_bytes(ddo.did))) >= 1
def access(service_agreement_id, service_index, ddo, consumer_account, destination, gateway, secret_store, config, index=None): """ Download asset data files or result files from a compute job. :param service_agreement_id: Service agreement id, str :param service_index: 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 gateway: Gateway instance :param secret_store: SecretStore instance :param config: Sdk configuration instance :param index: Index of the document that is going to be downloaded, int :return: Asset folder path, str """ did = ddo.did sa = ServiceAgreement.from_ddo(ServiceTypes.ASSET_ACCESS, ddo) consume_url = sa.service_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(ServiceTypes.AUTHORIZATION): secret_store_service = ddo.get_service( service_type=ServiceTypes.AUTHORIZATION) secret_store_url = secret_store_service.service_endpoint secret_store.set_secret_store_url(secret_store_url) asset_folder = create_asset_folder(did, service_index, destination) 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.') assert index < len(ddo.metadata['main']['files']), logger.error( 'index can not be bigger than the number of files') if index is not None: gateway.access_service(did, service_agreement_id, consume_url, consumer_account, asset_folder, config, index) else: for i, _file in enumerate(ddo.metadata['main']['files']): gateway.access_service(did, service_agreement_id, consume_url, consumer_account, asset_folder, config, i) return asset_folder
def test_assets_consumed(publisher_instance, consumer_instance, ddo_sample): acct = consumer_instance.main_account consumed_assets = len(publisher_instance.assets.consumer_assets(acct.address)) asset = create_asset(publisher_instance, ddo_sample) service = asset.get_service(service_type=ServiceTypes.ASSET_ACCESS) service_dict = service.as_dictionary() sa = ServiceAgreement.from_service_dict(service_dict) keeper = publisher_instance.keeper def grant_access(event, instance, agr_id, did, cons_address, account): instance.agreements.conditions.grant_access( agr_id, add_0x_prefix(did_to_id(did)), cons_address, account) agreement_id = consumer_instance.assets.order( asset.did, sa.index, acct, acct) keeper.lock_payment_condition.subscribe_condition_fulfilled( agreement_id, 15, grant_access, (publisher_instance, agreement_id, asset.did, acct.address, publisher_instance.main_account), wait=True ) keeper.access_condition.subscribe_condition_fulfilled( agreement_id, 15, log_event(keeper.access_condition.FULFILLED_EVENT), (), wait=True ) assert publisher_instance.agreements.is_access_granted(agreement_id, asset.did, acct.address) assert len(publisher_instance.assets.consumer_assets(acct.address)) == consumed_assets + 1 publisher_instance.assets.retire(asset.did)
def test_consume(client, provider_account, consumer_account): endpoint = BaseURLs.ASSETS_URL + '/consume' for method in constants.ConfigSections.DECRYPTION_METHODS: print('Testing Consume with Authorization Method: ' + method) ddo = get_registered_ddo(provider_account, providers=[provider_account.address], auth_service=method) # initialize an agreement agreement_id = place_order(provider_account, ddo, consumer_account, ServiceTypes.ASSET_ACCESS) payload = dict({ 'serviceAgreementId': agreement_id, 'consumerAddress': consumer_account.address }) print('Provider: ' + provider_account.address) print('Consumer: ' + consumer_account.address) keeper = keeper_instance() agr_id_hash = add_ethereum_prefix_and_hash_msg(agreement_id) signature = keeper.sign_hash(agr_id_hash, consumer_account) index = 0 event = keeper.access_template.subscribe_agreement_created( agreement_id, 15, None, (), wait=True, from_block=0) assert event, "Agreement event is not found, check the keeper node's logs" consumer_balance = keeper.token.get_token_balance( consumer_account.address) if consumer_balance < 50: keeper.dispenser.request_tokens(50 - consumer_balance, consumer_account) sa = ServiceAgreement.from_ddo(ServiceTypes.ASSET_ACCESS, ddo) lock_payment(agreement_id, ddo.asset_id, sa, amounts, receivers, consumer_account) event = keeper.lock_payment_condition.subscribe_condition_fulfilled( agreement_id, 15, None, (), wait=True, from_block=0) assert event, "Lock reward condition fulfilled event is not found, check the keeper " \ "node's logs" grant_access(agreement_id, ddo, consumer_account, provider_account) event = keeper.access_condition.subscribe_condition_fulfilled( agreement_id, 15, None, (), wait=True, from_block=0) assert event or keeper.access_condition.check_permissions( ddo.asset_id, consumer_account.address ), f'Failed to get access permission: agreement_id={agreement_id}, ' \ f'did={ddo.did}, consumer={consumer_account.address}' # Consume using url index and signature (let the gateway do the decryption) payload['signature'] = signature payload['index'] = index request_url = endpoint + '?' + '&'.join( [f'{k}={v}' for k, v in payload.items()]) response = client.get(request_url) assert response.status == '200 OK'
def setup_nft_sales_agreements_environment(): consumer_acc = get_consumer_account() publisher_acc = get_publisher_account() keeper = Keeper.get_instance() ddo = get_ddo_nft_sample() did_seed = generate_prefixed_id() asset_id = keeper.did_registry.hash_did(did_seed, publisher_acc.address) ddo._did = DID.did(asset_id) keeper.did_registry.register_mintable_did( did_seed, checksum=Web3Provider.get_web3().toBytes(hexstr=ddo.asset_id), url='http://172.17.0.1:5000', cap=10, royalties=10, account=publisher_acc, providers=None) keeper.did_registry.mint(ddo.asset_id, 10, account=publisher_acc) service_agreement = ServiceAgreement.from_ddo(ServiceTypes.NFT_SALES, ddo) agreement_id = ServiceAgreement.create_new_agreement_id() price = service_agreement.get_price() (access_cond_id, lock_cond_id, escrow_cond_id) = service_agreement.generate_agreement_condition_ids( agreement_id, asset_id, consumer_acc.address, keeper) nft_access_service_agreement = ServiceAgreement.from_ddo( ServiceTypes.NFT_ACCESS, ddo) nft_access_agreement_id = ServiceAgreement.create_new_agreement_id() (nft_access_cond_id, nft_holder_cond_id ) = nft_access_service_agreement.generate_agreement_condition_ids( nft_access_agreement_id, asset_id, consumer_acc.address, keeper) return (keeper, ddo, publisher_acc, consumer_acc, agreement_id, nft_access_agreement_id, asset_id, price, service_agreement, nft_access_service_agreement, (lock_cond_id, access_cond_id, escrow_cond_id), (nft_access_cond_id, nft_holder_cond_id))
def order(self, did, index, consumer_account, account): agreement_id = ServiceAgreement.create_new_agreement_id() logger.debug(f'about to request create agreement: {agreement_id}') self._agreements.create( did, index, agreement_id, consumer_account.address, account ) return agreement_id
def prepare(self, did, consumer_account, service_index): """ :param did: str representation fo the asset DID. Use this to retrieve the asset DDO. :param consumer_account: Account instance of the consumer :param service_index: int identifies the specific service in the ddo to use in this agreement. :return: tuple (agreement_id: str, signature: hex str) """ agreement_id = ServiceAgreement.create_new_agreement_id() signature = self._sign(agreement_id, did, consumer_account, service_index) return agreement_id, signature
def validate_nft_access(self, agreement_id, did, consumer_address): keeper = keeper_instance() asset = DIDResolver(keeper.did_registry).resolve(did) # check which nft access service type is on the ddo service_type = ServiceTypes.NFT_ACCESS if asset.get_service(ServiceTypes.NFT721_ACCESS) is not None: service_type = ServiceTypes.NFT721_ACCESS sa = ServiceAgreement.from_ddo(service_type, asset) return self._validate_nft_access(agreement_id, did, consumer_address, sa, service_type)
def test_store_and_retrieve_service(metadata_instance, json_service): agreement_id = ServiceAgreement.create_new_agreement_id() service = Service.from_json(json_service) # store the service agreement result = metadata_instance.store_service_agreement(agreement_id, service) assert result is True result = metadata_instance.get_service_agreement(agreement_id) assert result.type == service.type assert result.index == service.index assert result.service_endpoint == service.service_endpoint assert result.attributes == service.attributes
def place_order(provider_account, ddo, consumer_account, service_type=ServiceTypes.ASSET_ACCESS): keeper = keeper_instance() agreement_id = ServiceAgreement.create_new_agreement_id() if service_type == ServiceTypes.ASSET_ACCESS: agreement_template = keeper.access_template elif service_type == ServiceTypes.ASSET_ACCESS_PROOF: agreement_template = keeper.access_proof_template elif service_type == ServiceTypes.NFT_SALES: agreement_template = keeper.nft_sales_template elif service_type == ServiceTypes.CLOUD_COMPUTE: agreement_template = keeper.escrow_compute_execution_template else: raise NotImplementedError( "The agreement template could not be created.") publisher_address = provider_account.address service_agreement = ServiceAgreement.from_ddo(service_type, ddo) if service_type == ServiceTypes.ASSET_ACCESS_PROOF: consumer_pub = get_buyer_public_key() condition_ids = service_agreement.generate_agreement_condition_ids( agreement_id, ddo.asset_id, consumer_pub, keeper) else: condition_ids = service_agreement.generate_agreement_condition_ids( agreement_id, ddo.asset_id, consumer_account.address, keeper) time_locks = service_agreement.conditions_timelocks time_outs = service_agreement.conditions_timeouts agreement_template.create_agreement(agreement_id, ddo.asset_id, condition_ids, time_locks, time_outs, consumer_account.address, consumer_account) return agreement_id
def complete_access_service(did, service_endpoint, attributes, template_id, reward_contract_address=None, service_type=ServiceTypes.ASSET_ACCESS): """ Build the access service. :param did: DID, str :param service_endpoint: identifier of the service inside the asset DDO, str :param template_id: id of the template use to create the service, str :param reward_contract_address: hex str ethereum address of deployed reward condition smart contract :return: ServiceAgreement """ param_map = { '_documentId': did_to_id(did), '_amount': attributes['main']['price'] } if reward_contract_address is not None: param_map['_rewardAddress'] = reward_contract_address try: param_map['_did'] = did_to_id(did) param_map['_amounts'] = attributes['main']['_amounts'] param_map['_receivers'] = attributes['main']['_receivers'] param_map['_tokenAddress'] = attributes['main']['_tokenAddress'] param_map['_numberNfts'] = attributes['main']['_numberNfts'] except KeyError as e: logger.error(f'Error mapping field {e}') sla_template_dict = get_sla_template(service_type) sla_template = ServiceAgreementTemplate(template_id, service_type, attributes['main']['creator'], sla_template_dict) 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 = attributes['main']['timeout'] sla_template.set_conditions(conditions) sa = ServiceAgreement(attributes, sla_template, service_endpoint, service_type) return sa
def _validate_nft_access(self, agreement_id, did, consumer_address, service_agreement, service_type): keeper = keeper_instance() asset = DIDResolver(keeper.did_registry).resolve(did) asset_id = asset.asset_id sa_name = service_agreement.main['name'] erc721_address = service_agreement.get_param_value_by_name('_contractAddress') access_granted = False if agreement_id is None or agreement_id == '0x': if sa_name == 'nftAccessAgreement': access_granted = is_nft_holder(keeper, asset_id, service_agreement.get_number_nfts(), consumer_address) elif sa_name == 'nft721AccessAgreement': access_granted = is_nft721_holder(keeper, asset_id, consumer_address, erc721_address) else: agreement = keeper.agreement_manager.get_agreement(agreement_id) cond_ids = agreement.condition_ids access_cond_id = cond_ids[1] ddo = DIDResolver(keeper.did_registry).resolve(did) nft_access_service_agreement = ServiceAgreement.from_ddo(service_type, ddo) (nft_access_cond_id, nft_holder_cond_id) = nft_access_service_agreement.generate_agreement_condition_ids(agreement_id, asset_id, consumer_address, keeper) if [nft_holder_cond_id, nft_access_cond_id] != cond_ids: raise InvalidClientError(f"ServiceAgreement {agreement_id} doesn't match ddo") if not is_nft_access_condition_fulfilled( agreement_id, access_cond_id, consumer_address, keeper): # If not granted, verification of agreement and conditions and fulfill # access_granted = is_nft_holder(keeper, asset_id, sa.get_number_nfts(), consumer_address) access_granted = fulfill_nft_holder_and_access_condition( keeper, agreement_id, cond_ids, asset_id, service_agreement.get_number_nfts(), consumer_address, self.provider_account ) if not access_granted: msg = ('Checking access permissions failed. Either consumer address does not have ' 'permission to consume this NFT or consumer address and/or service ' 'agreement ' 'id is invalid.') logger.warning(msg) raise InvalidClientError(msg)
def _read_dict(self, dictionary): """Import a JSON dict into this DDO.""" values = dictionary self._did = values['id'] self._created = values.get('created', None) if 'publicKey' in values: self._public_keys = [] for value in values['publicKey']: if isinstance(value, str): value = json.loads(value) self._public_keys.append( DDO.create_public_key_from_json(value)) if 'authentication' in values: self._authentications = [] for value in values['authentication']: if isinstance(value, str): value = json.loads(value) self._authentications.append( DDO.create_authentication_from_json(value)) if 'service' in values: self._services = [] for value in values['service']: if isinstance(value, str): value = json.loads(value) if value['type'] == ServiceTypes.ASSET_ACCESS: service = ServiceAgreement.from_service_dict(value) elif value['type'] == ServiceTypes.ASSET_ACCESS_PROOF: service = ServiceAgreement.from_service_dict(value) elif value['type'] == ServiceTypes.CLOUD_COMPUTE: service = ServiceAgreement.from_service_dict(value) elif value['type'] == ServiceTypes.NFT_SALES: service = ServiceAgreement.from_service_dict(value) else: service = Service.from_json(value) self._services.append(service) if 'proof' in values: self._proof = values['proof']
def test_access_endpoint_bad_signature(client, provider_account, consumer_account): # The provider_account will place the order and consumer_account # will try to request access to it # order access keeper = keeper_instance() ddo = get_registered_ddo(provider_account, providers=[provider_account.address]) agreement_id = place_order(provider_account, ddo, provider_account) event = keeper.access_template.subscribe_agreement_created(agreement_id, 15, None, (), wait=True, from_block=0) assert event, "Agreement event is not found, check the keeper node's logs" consumer_balance = keeper.token.get_token_balance(consumer_account.address) if consumer_balance < 50: keeper.dispenser.request_tokens(50 - consumer_balance, consumer_account) sa = ServiceAgreement.from_ddo(ServiceTypes.ASSET_ACCESS, ddo) lock_payment(agreement_id, ddo.asset_id, sa, amounts, receivers, consumer_account) event = keeper.lock_payment_condition.subscribe_condition_fulfilled( agreement_id, 15, None, (), wait=True, from_block=0) assert event, "Lock reward condition fulfilled event is not found, check the keeper node's logs" # create jwt bearer grant jwk = account_to_jwk(consumer_account) assertion = NeverminedJWTBearerGrant.sign(jwk, issuer=consumer_account.address, audience=BaseURLs.ASSETS_URL + '/access', subject=agreement_id, claims={"did": ddo.did}, header={"alg": "ES256K"}) response = client.post("/api/v1/gateway/services/oauth/token", data={ "grant_type": NeverminedJWTBearerGrant.GRANT_TYPE, "assertion": assertion }) assert response.status_code == 400 assert response.get_json()["error"] == "invalid_client"
def setup_did_sales_agreements_environment(): consumer_acc = get_consumer_account() publisher_acc = get_publisher_account() keeper = Keeper.get_instance() ddo = get_ddo_did_sales_sample() did_seed = generate_prefixed_id() asset_id = keeper.did_registry.hash_did(did_seed, publisher_acc.address) ddo._did = DID.did(asset_id) keeper.did_registry.register( did_seed, checksum=Web3Provider.get_web3().toBytes(hexstr=ddo.asset_id), url='metadata:5000', account=publisher_acc, providers=None) service_agreement = ServiceAgreement.from_ddo(ServiceTypes.DID_SALES, ddo) agreement_id = ServiceAgreement.create_new_agreement_id() price = service_agreement.get_price() (access_cond_id, lock_cond_id, escrow_cond_id) = service_agreement.generate_agreement_condition_ids( agreement_id, asset_id, consumer_acc.address, keeper) return ( keeper, ddo, publisher_acc, consumer_acc, agreement_id, asset_id, price, service_agreement, (lock_cond_id, access_cond_id, escrow_cond_id), )
def setup_agreements_environment(ddo_sample): consumer_acc = get_consumer_account() publisher_acc = get_publisher_account() keeper = Keeper.get_instance() ddo = ddo_sample ddo._did = DID.did({"0": generate_prefixed_id()}) keeper.did_registry.register( ddo.asset_id, checksum=Web3Provider.get_web3().toBytes(hexstr=ddo.asset_id), url='localhost:5000', account=publisher_acc, providers=None ) registered_ddo = ddo asset_id = registered_ddo.asset_id service_agreement = ServiceAgreement.from_ddo(ServiceTypes.ASSET_ACCESS, ddo) agreement_id = ServiceAgreement.create_new_agreement_id() price = service_agreement.get_price() access_cond_id, lock_cond_id, escrow_cond_id = \ service_agreement.generate_agreement_condition_ids( agreement_id, asset_id, consumer_acc.address, publisher_acc.address, keeper ) return ( keeper, publisher_acc, consumer_acc, agreement_id, asset_id, price, service_agreement, (lock_cond_id, access_cond_id, escrow_cond_id), )
def test_execute_endpoint(client, provider_account, consumer_account): ddo_compute = get_registered_compute_ddo( provider_account, providers=[provider_account.address]) ddo_algorithm = get_registered_algorithm_ddo( consumer_account, providers=[provider_account.address]) ddo_workflow = get_registered_workflow_ddo( consumer_account, ddo_compute.did, ddo_algorithm.did, providers=[provider_account.address]) # initialize agreement agreement_id = place_order(provider_account, ddo_compute, consumer_account, service_type=ServiceTypes.CLOUD_COMPUTE) sa = ServiceAgreement.from_ddo(ServiceTypes.CLOUD_COMPUTE, ddo_compute) lock_payment(agreement_id, ddo_compute.asset_id, sa, amounts, receivers, consumer_account) keeper = keeper_instance() event = keeper.lock_payment_condition.subscribe_condition_fulfilled( agreement_id, 60, None, (), wait=True) assert event is not None, "Reward condition is not found" # create jwt bearer grant jwk = account_to_jwk(consumer_account) assertion = NeverminedJWTBearerGrant.sign(jwk, issuer=consumer_account.address, subject=agreement_id, audience=BaseURLs.ASSETS_URL + '/execute', claims={"did": ddo_workflow.did}, header={"alg": "ES256K"}) response = client.post("/api/v1/gateway/services/oauth/token", data={ "grant_type": NeverminedJWTBearerGrant.GRANT_TYPE, "assertion": assertion }) assert response.status_code == 200 # use jwt access token to execute the compute access_token = response.get_json()["access_token"] response = client.post(f"/api/v1/gateway/services/execute/{agreement_id}", headers={"Authorization": f"Bearer {access_token}"}) assert response.status_code == 200
def test_agreement(): template_id = Web3.toChecksumAddress('0x' + ('f' * 40)) agreement_id = '0x' + ('e' * 64) access_id = '0x' + ('a' * 64) lock_id = '0x' + ('b' * 64) escrow_id = '0x' + ('c' * 64) signature = ServiceAgreement.generate_service_agreement_hash( template_id, [access_id, lock_id, escrow_id], [0, 0, 0], [0, 0, 0], agreement_id, generate_multi_value_hash) print({signature}) assert (signature == Web3.toBytes( hexstr= "0x67901517c18a3d23e05806fff7f04235cc8ae3b1f82345b8bfb3e4b02b5800c7") ), "The signature is not correct."
def test_compute_logs(publisher_instance_no_init, consumer_instance_no_init, metadata, algorithm_ddo, workflow_ddo): consumer = publisher_instance_no_init.main_account publisher = consumer_instance_no_init.main_account # publish compute ddo_computing = publisher_instance_no_init.assets.create_compute( metadata, publisher) # publish algorithm metadata = algorithm_ddo['service'][0] ddo_algorithm = consumer_instance_no_init.assets.create( metadata['attributes'], consumer) metadata = workflow_ddo['service'][0] metadata['attributes']['main']['workflow']['stages'][0]['input'][0][ 'id'] = ddo_computing.did metadata['attributes']['main']['workflow']['stages'][0]['transformation'][ 'id'] = ddo_algorithm.did workflow_ddo = consumer_instance_no_init.assets.create( metadata['attributes'], publisher) assert workflow_ddo # order compute asset service = ddo_computing.get_service( service_type=ServiceTypes.CLOUD_COMPUTE) sa = ServiceAgreement.from_service_dict(service.as_dictionary()) agreement_id = consumer_instance_no_init.assets.order( ddo_computing.did, sa.index, consumer, consumer) keeper = Keeper.get_instance() event = keeper.lock_payment_condition.subscribe_condition_fulfilled( agreement_id, 60, None, (), wait=True) assert event is not None, "Reward condition is not found" # execute workflow execution_id = consumer_instance_no_init.assets.execute( agreement_id, ddo_computing.did, sa.index, consumer, workflow_ddo.did) # get logs logs = consumer_instance_no_init.assets.compute_logs( agreement_id, execution_id, consumer) assert logs publisher_instance_no_init.assets.retire(ddo_computing.did) publisher_instance_no_init.assets.retire(ddo_algorithm.did) publisher_instance_no_init.assets.retire(workflow_ddo.did)
def execute(agreement_id, compute_ddo, workflow_ddo, consumer_account, gateway, index, config): """ :param agreement_id: :param workflow_ddo: :param consumer_account: :param index: :return: the id of the compute job """ service_endpoint = ServiceAgreement.from_ddo( ServiceTypes.CLOUD_COMPUTE, compute_ddo).service_endpoint response = gateway.execute_compute_service(agreement_id, service_endpoint, consumer_account, workflow_ddo, config) return response.json()["workflowId"]
def complete_compute_service(did, service_endpoint, attributes, template_id, reward_contract_address): """ Build the access service. :param did: DID, str :param service_endpoint: identifier of the service inside the asset DDO, str :param template_id: id of the template use to create the service, str :param reward_contract_address: hex str ethereum address of deployed reward condition smart contract :return: ServiceAgreement """ param_map = { '_documentId': did_to_id(did), '_amount': attributes['main']['price'], '_rewardAddress': reward_contract_address } try: param_map['_amounts'] = attributes['main']['_amounts'] param_map['_receivers'] = attributes['main']['_receivers'] except KeyError: pass sla_template_dict = get_sla_template(ServiceTypes.CLOUD_COMPUTE) sla_template = ServiceAgreementTemplate(template_id, ServiceTypes.CLOUD_COMPUTE, attributes['main']['creator'], sla_template_dict) 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 = attributes['main']['timeout'] sla_template.set_conditions(conditions) sa = ServiceAgreement(attributes, sla_template, service_endpoint, ServiceTypes.CLOUD_COMPUTE) return sa
def test_nfts_flow(publisher_instance_no_init, consumer_instance_no_init): config = ExampleConfig.get_config() ConfigProvider.set_config(config) keeper = Keeper.get_instance() pub_acc = get_publisher_account() # Register ddo ddo = get_registered_ddo_nft(publisher_instance_no_init, pub_acc) asset_id = ddo.asset_id nft_amounts = 1 assert isinstance(ddo, DDO) consumer_account = get_consumer_account() consumer_instance_no_init.accounts.request_tokens(consumer_account, 100) service_sales = ddo.get_service(service_type=ServiceTypes.NFT_SALES) sa_sales = ServiceAgreement.from_service_dict( service_sales.as_dictionary()) amounts = sa_sales.get_amounts_int() receivers = sa_sales.get_receivers() number_nfts = sa_sales.get_number_nfts() token_address = keeper.token.address sales_agreement_id = consumer_instance_no_init.assets.order( ddo.did, sa_sales.index, consumer_account, consumer_account) sales_agreement = keeper.agreement_manager.get_agreement( sales_agreement_id) assert sales_agreement.did == asset_id, '' lock_cond_id = sales_agreement.condition_ids[0] access_cond_id = sales_agreement.condition_ids[1] escrow_cond_id = sales_agreement.condition_ids[2] # transfer the nft keeper.transfer_nft_condition.fulfill(sales_agreement_id, asset_id, consumer_account.address, nft_amounts, lock_cond_id, pub_acc) # escrow payment keeper.escrow_payment_condition.fulfill( sales_agreement_id, asset_id, amounts, receivers, keeper.escrow_payment_condition.address, token_address, lock_cond_id, access_cond_id, pub_acc) assert keeper.condition_manager.get_condition_state(lock_cond_id) == 2, '' assert keeper.condition_manager.get_condition_state( access_cond_id) == 2, '' assert keeper.condition_manager.get_condition_state( escrow_cond_id) == 2, '' assert keeper.did_registry.balance(consumer_account.address, asset_id) >= number_nfts # CHECK ACCESS CREATING THE AGREEMENT nft_access_service_agreement = ServiceAgreement.from_ddo( ServiceTypes.NFT_ACCESS, ddo) sa_access = ddo.get_service(service_type=ServiceTypes.NFT_ACCESS) nft_access_agreement_id = consumer_instance_no_init.assets.order( ddo.did, sa_access.index, consumer_account, consumer_account) event = keeper.nft_access_template.subscribe_agreement_created( nft_access_agreement_id, 10, log_event(keeper.nft_access_template.AGREEMENT_CREATED_EVENT), (), wait=True) assert event, 'no event for AgreementCreated ' time.sleep(3) keeper.nft_holder_condition.fulfill(nft_access_agreement_id, asset_id, consumer_account.address, number_nfts, consumer_account) time.sleep(3) keeper.nft_access_condition.fulfill(nft_access_agreement_id, asset_id, consumer_account.address, pub_acc) time.sleep(3) access_agreement = keeper.agreement_manager.get_agreement( nft_access_agreement_id) assert access_agreement.did == asset_id, '' nft_holder_cond_id = access_agreement.condition_ids[0] nft_access_cond_id = access_agreement.condition_ids[1] assert keeper.condition_manager.get_condition_state( nft_access_cond_id) == 2, '' assert keeper.condition_manager.get_condition_state( nft_holder_cond_id) == 2, '' # AND HERE TESTING WITHOUT CREATING THE AGREEMENT service_access = ddo.get_service(service_type=ServiceTypes.NFT_ACCESS) no_agreement_id = '0x' assert consumer_instance_no_init.assets.access( no_agreement_id, ddo.did, service_access.index, consumer_account, config.downloads_path, service_type=ServiceTypes.NFT_ACCESS) # AND HERE CHECKING CREATING AN AGREEMENT FIRST nft_access_service_agreement = ServiceAgreement.from_ddo( ServiceTypes.NFT_ACCESS, ddo) nft_access_agreement_id = ServiceAgreement.create_new_agreement_id() (nft_access_cond_id, nft_holder_cond_id ) = nft_access_service_agreement.generate_agreement_condition_ids( nft_access_agreement_id, asset_id, consumer_account.address, keeper) keeper.nft_access_template.create_agreement( nft_access_agreement_id, asset_id, [nft_holder_cond_id, nft_access_cond_id], nft_access_service_agreement.conditions_timelocks, nft_access_service_agreement.conditions_timeouts, consumer_account.address, pub_acc) event = keeper.nft_access_template.subscribe_agreement_created( nft_access_agreement_id, 10, log_event(keeper.nft_access_template.AGREEMENT_CREATED_EVENT), (), wait=True) assert event, 'no event for AgreementCreated ' # This is because in this test the gateway is executed using the same account than the consumer keeper.did_registry.add_provider(asset_id, consumer_account.address, pub_acc) time.sleep(3) assert consumer_instance_no_init.assets.access( nft_access_agreement_id, ddo.did, service_access.index, consumer_account, config.downloads_path, index=0, service_type=ServiceTypes.NFT_ACCESS)
def test_access_proof(client, provider_account, consumer_account): for method in constants.ConfigSections.DECRYPTION_METHODS: ddo = get_proof_ddo(provider_account, providers=[provider_account.address], auth_service=method) # initialize an agreement agreement_id = place_order(provider_account, ddo, consumer_account, ServiceTypes.ASSET_ACCESS_PROOF) print(ddo.did) keeper = keeper_instance() index = 0 event = keeper.access_proof_template.subscribe_agreement_created( agreement_id, 15, None, (), wait=True, from_block=0) assert event, "Agreement event is not found, check the keeper node's logs" consumer_balance = keeper.token.get_token_balance( consumer_account.address) if consumer_balance < 50: keeper.dispenser.request_tokens(50 - consumer_balance, consumer_account) sa = ServiceAgreement.from_ddo(ServiceTypes.ASSET_ACCESS_PROOF, ddo) lock_payment(agreement_id, ddo.asset_id, sa, amounts, receivers, consumer_account) event = keeper.lock_payment_condition.subscribe_condition_fulfilled( agreement_id, 15, None, (), wait=True, from_block=0) assert event, "Lock reward condition fulfilled event is not found, check the keeper node's logs" # Consume using url index # generate the grant token grant_token = generate_access_proof_grant_token( consumer_account, agreement_id, ddo.did, get_buyer_secret_key(), "/access-proof") # request access token response = client.post("/api/v1/gateway/services/oauth/token", data={ "grant_type": NeverminedJWTBearerGrant.GRANT_TYPE, "assertion": grant_token }) access_token = response.get_json()["access_token"] agreement = keeper.agreement_manager.get_agreement(agreement_id) cond_ids = agreement.condition_ids assert keeper.condition_manager.get_condition_state( cond_ids[0]) == ConditionState.Fulfilled.value assert keeper.condition_manager.get_condition_state( cond_ids[1]) == ConditionState.Fulfilled.value assert keeper.condition_manager.get_condition_state( cond_ids[2]) == ConditionState.Fulfilled.value endpoint = BaseURLs.ASSETS_URL + '/access-proof/%s/%d' % (agreement_id, index) response = client.get( endpoint, headers={"Authorization": f"Bearer {access_token}"}) assert response.status == '200 OK' assert len( keeper.did_registry.get_provenance_method_events( 'USED', did_bytes=did_to_id_bytes(ddo.did))) == 1
def test_sign_agreement(publisher_instance, consumer_instance, registered_ddo): # point consumer_instance's Gateway mock to the publisher's nevermined instance Gateway.set_http_client( GatewayMock(publisher_instance, publisher_instance.main_account)) consumer_acc = consumer_instance.main_account keeper = Keeper.get_instance() publisher_acc = publisher_instance.main_account did = registered_ddo.did asset_id = registered_ddo.asset_id ddo = consumer_instance.assets.resolve(did) service_agreement = ServiceAgreement.from_ddo(ServiceTypes.ASSET_ACCESS, ddo) price = service_agreement.get_price() # Give consumer some tokens keeper.dispenser.request_vodkas(price * 2, consumer_acc) agreement_id, signature = consumer_instance.agreements.prepare( did, consumer_acc, ServiceTypesIndices.DEFAULT_ACCESS_INDEX) success = publisher_instance.agreements.create( did, ServiceTypesIndices.DEFAULT_ACCESS_INDEX, agreement_id, consumer_acc.address, publisher_acc) assert success, 'createAgreement failed.' # Verify condition types (condition contracts) agreement_values = keeper.agreement_manager.get_agreement(agreement_id) assert agreement_values.did == asset_id, '' cond_types = keeper.access_template.get_condition_types() for i, cond_id in enumerate(agreement_values.condition_ids): cond = keeper.condition_manager.get_condition(cond_id) assert cond.type_ref == cond_types[i] access_cond_id, lock_cond_id, escrow_cond_id = agreement_values.condition_ids # Fulfill lock_payment_condition is done automatically when create agreement is done correctly assert 2 == keeper.condition_manager.get_condition_state(lock_cond_id), '' assert 1 == keeper.condition_manager.get_condition_state( access_cond_id), '' assert 1 == keeper.condition_manager.get_condition_state( escrow_cond_id), '' # Fulfill access_condition tx_hash = keeper.access_condition.fulfill(agreement_id, asset_id, consumer_acc.address, publisher_acc) keeper.access_condition.get_tx_receipt(tx_hash) assert 2 == keeper.condition_manager.get_condition_state( access_cond_id), '' event = keeper.access_condition.subscribe_condition_fulfilled( agreement_id, 10, log_event(keeper.access_condition.FULFILLED_EVENT), (), wait=True) assert event, 'no event for AccessSecretStoreCondition.Fulfilled' # Fulfill escrow_payment_condition amounts = service_agreement.get_amounts_int() receivers = service_agreement.get_receivers() tx_hash = keeper.escrow_payment_condition.fulfill( agreement_id, asset_id, amounts, receivers, keeper.escrow_payment_condition.address, lock_cond_id, access_cond_id, publisher_acc) keeper.escrow_payment_condition.get_tx_receipt(tx_hash) assert 2 == keeper.condition_manager.get_condition_state( escrow_cond_id), '' event = keeper.escrow_payment_condition.subscribe_condition_fulfilled( agreement_id, 10, log_event(keeper.escrow_payment_condition.FULFILLED_EVENT), (), wait=True) assert event, 'no event for EscrowReward.Fulfilled' publisher_instance.assets.retire(did)
def create(self, did, index, agreement_id, consumer_address, account): """ 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 values which is usedon-chain to verify that the values actually match the signed hashes. :param did: str representation fo the asset DID. Use this to retrieve the asset DDO. :param index: str identifies the specific service in the ddo to use in this agreement. :param agreement_id: 32 bytes identifier created by the consumer and will be used on-chain for the executed agreement. conditions and their parameters values and other details of the agreement. :param consumer_address: ethereum account address of consumer, hex str :param account: Account instance creating the agreement. Can be either the consumer, publisher or provider :return: dict the `executeAgreement` transaction receipt """ assert consumer_address and Web3Provider.get_web3().isChecksumAddress( consumer_address), f'Invalid consumer address {consumer_address}' assert account.address in self._keeper.accounts, \ f'Unrecognized account address {account.address}' payment_involved = True asset = self._asset_resolver.resolve(did) asset_id = asset.asset_id service = asset.get_service_by_index(index) if service.type == ServiceTypes.ASSET_ACCESS: agreement_template = self._keeper.access_template template_address = self._keeper.access_template.address elif service.type == ServiceTypes.CLOUD_COMPUTE: agreement_template = self._keeper.escrow_compute_execution_template template_address = self._keeper.escrow_compute_execution_template.address elif service.type == ServiceTypes.NFT_SALES: agreement_template = self._keeper.nft_sales_template template_address = self._keeper.nft_sales_template.address elif service.type == ServiceTypes.NFT_ACCESS: payment_involved = False agreement_template = self._keeper.nft_access_template template_address = self._keeper.nft_access_template.address else: raise Exception('The agreement could not be created. Review the index of your service.') agreement_template_approved = self._keeper.template_manager.is_template_approved(template_address) if not agreement_template_approved: msg = (f'The Service Agreement Template contract at address ' f'{template_address} is not ' f'approved and cannot be used for creating service agreements.') logger.warning(msg) raise InvalidAgreementTemplate(msg) if agreement_template.get_agreement_consumer(agreement_id) != ZERO_ADDRESS: raise ServiceAgreementExists( f'Service agreement {agreement_id} already exists, cannot reuse ' f'the same agreement id.') service_agreement = ServiceAgreement.from_service_index(index, asset) token_address = check_token_address( self._keeper, service_agreement.get_param_value_by_name('_tokenAddress')) publisher_address = Web3Provider.get_web3().toChecksumAddress(asset.publisher) condition_ids = service_agreement.generate_agreement_condition_ids( agreement_id, asset_id, consumer_address, self._keeper, token_address=token_address) time_locks = service_agreement.conditions_timelocks time_outs = service_agreement.conditions_timeouts if payment_involved and service_agreement.get_price() > self._keeper.token.get_token_balance(consumer_address): return Exception( f'The consumer balance is ' f'{self._keeper.token.get_token_balance(consumer_address)}. ' f'This balance is lower that the asset price {service_agreement.get_price()}.') if service.type == ServiceTypes.NFT_SALES: conditions_ordered = [condition_ids[1], condition_ids[0], condition_ids[2]] elif service.type == ServiceTypes.NFT_ACCESS: conditions_ordered = [condition_ids[1], condition_ids[0]] else: conditions_ordered = condition_ids success = agreement_template.create_agreement( agreement_id, asset_id, conditions_ordered, time_locks, time_outs, consumer_address, account ) if success: if payment_involved: self.conditions.lock_payment( agreement_id, asset_id, service_agreement.get_amounts_int(), service_agreement.get_receivers(), token_address, account) return self._is_condition_fulfilled(agreement_id, 'lockReward') return True return False
def demo(): """The Nevermined Federated Learning demo. This demo showcases the nevermined Federated Learning capabilities. FLow: 1. Setup nevermined 2. Setup accounts 3. Publish compute to the data assets 4. Publish algorithm 5. Publish workflows 6. Order computations 7. Execute workflows """ print("Setting up...\n") date_created = dates_generator() # 1. Setup nevermined nevermined = Nevermined(Config("config.ini")) keeper = Keeper.get_instance() provider = "0x068Ed00cF0441e4829D9784fCBe7b9e26D4BD8d0" # 2. Setup accounts acc = Account(Web3.toChecksumAddress(PARITY_ADDRESS), PARITY_PASSWORD, PARITY_KEYFILE) nevermined.accounts.request_tokens(acc, 100) provider_data0 = acc provider_data1 = acc provider_coordinator = acc consumer = acc # 3. Publish compute to the data with open("resources/metadata/metadata0.json") as f: metadata_data0 = json.load(f) metadata_data0["main"]["dateCreated"] = next(date_created) with open("resources/metadata/metadata1.json") as f: metadata_data1 = json.load(f) metadata_data1["main"]["dateCreated"] = next(date_created) ddo_compute0 = nevermined.assets.create_compute( metadata_data0, provider_data0, providers=[provider], ) assert ddo_compute0 is not None, "Creating asset compute0 on-chain failed" print( f"[DATA_PROVIDER0 --> NEVERMINED] Publishing compute to the data asset for asset0: {ddo_compute0.did}" ) ddo_compute1 = nevermined.assets.create_compute( metadata_data1, provider_data1, providers=[provider], ) assert ddo_compute1 is not None, "Creating asset compute1 on-chain failed" print( f"[DATA_PROVIDER1 --> NEVERMINED] Publishing compute to the data asset for asset1: {ddo_compute1.did}" ) with open("resources/metadata/metadata_compute_coordinator.json") as f: metadata_compute_coordinator = json.load(f) metadata_compute_coordinator["main"]["dateCreated"] = next( date_created) ddo_compute_coordinator = nevermined.assets.create_compute( metadata_compute_coordinator, provider_coordinator, providers=[provider], ) assert (ddo_compute_coordinator is not None), "Creating asset compute_coordinator on-chain failed" print( f"[COORDINATOR_PROVIDER --> NEVERMINED] Publishing coordinator compute asset: {ddo_compute_coordinator.did}" ) # 4. Publish algorithm with open("resources/metadata/metadata_transformation.json") as f: metadata_transformation = json.load(f) metadata_transformation["main"]["dateCreated"] = next(date_created) ddo_transformation = nevermined.assets.create( metadata_transformation, consumer, providers=[provider], ) assert (ddo_transformation is not None), "Creating asset transformation on-chain failed" print( f"[DATA_SCIENTIST --> NEVERMINED] Publishing algorithm asset: {ddo_transformation.did}" ) # 5. Publish the workflows with open("resources/metadata/metadata_workflow.json") as f: metadata_workflow = json.load(f) with open("resources/metadata/metadata_workflow_coordinator.json") as f: metadata_workflow_coordinator = json.load(f) metadata_workflow0 = copy.deepcopy(metadata_workflow) metadata_workflow0["main"]["workflow"]["stages"][0]["input"][0][ "id"] = ddo_compute0.did metadata_workflow0["main"]["workflow"]["stages"][0]["transformation"][ "id"] = ddo_transformation.did metadata_workflow1 = copy.deepcopy(metadata_workflow) metadata_workflow1["main"]["workflow"]["stages"][0]["input"][0][ "id"] = ddo_compute1.did metadata_workflow1["main"]["workflow"]["stages"][0]["transformation"][ "id"] = ddo_transformation.did metadata_workflow_coordinator["main"]["dateCreated"] = next(date_created) ddo_workflow0 = nevermined.assets.create( metadata_workflow0, consumer, providers=[provider], ) assert ddo_workflow0 is not None, "Creating asset workflow0 on-chain failed" print( f"[DATA_SCIENTIST --> NEVERMINED] Publishing compute workflow for asset0: {ddo_workflow0.did}" ) ddo_workflow1 = nevermined.assets.create( metadata_workflow1, consumer, providers=[provider], ) assert ddo_workflow1 is not None, "Creating asset workflow1 on-chain failed" print( f"[DATA_SCIENTIST --> NEVERMINED] Publishing compute workflow for asset1: {ddo_workflow1.did}" ) ddo_workflow_coordinator = nevermined.assets.create( metadata_workflow_coordinator, consumer, providers=[provider], ) assert (ddo_workflow_coordinator is not None), "Creating asset workflow_coordinator on-chain failed" print( f"[DATA_SCIENTIST --> NEVERMINED] Publishing compute workflow for coordinator: {ddo_workflow_coordinator.did}" ) # 6. Order computations service0 = ddo_compute0.get_service( service_type=ServiceTypes.CLOUD_COMPUTE) service_agreement0 = ServiceAgreement.from_service_dict( service0.as_dictionary()) agreement_id0 = nevermined.assets.order(ddo_compute0.did, service_agreement0.index, consumer, consumer) print( f"[DATA_SCIENTIST --> DATA_PROVIDER0] Requesting an agreement for compute to the data for asset0: {agreement_id0}" ) event = keeper.lock_reward_condition.subscribe_condition_fulfilled( agreement_id0, 60, None, (), wait=True) assert event is not None, "Reward condition is not found" event = keeper.compute_execution_condition.subscribe_condition_fulfilled( agreement_id0, 60, None, (), wait=True) assert event is not None, "Execution condition not found" service1 = ddo_compute1.get_service( service_type=ServiceTypes.CLOUD_COMPUTE) service_agreement1 = ServiceAgreement.from_service_dict( service1.as_dictionary()) agreement_id1 = nevermined.assets.order(ddo_compute1.did, service_agreement1.index, consumer, consumer) print( f"[DATA_SCIENTIST --> DATA_PROVIDER1] Requesting an agreement for compute to the data for asset1: {agreement_id1}" ) event = keeper.lock_reward_condition.subscribe_condition_fulfilled( agreement_id1, 60, None, (), wait=True) assert event is not None, "Reward condition is not found" event = keeper.compute_execution_condition.subscribe_condition_fulfilled( agreement_id1, 60, None, (), wait=True) assert event is not None, "Execution condition not found" service_coordinator = ddo_compute_coordinator.get_service( service_type=ServiceTypes.CLOUD_COMPUTE) service_agreement_coordinator = ServiceAgreement.from_service_dict( service_coordinator.as_dictionary()) agreement_id_coordinator = nevermined.assets.order( ddo_compute_coordinator.did, service_agreement_coordinator.index, consumer, consumer) print( f"[DATA_SCIENTIST --> COORDINATOR_PROVIDER] Requesting an agreement for coordinator compute: {agreement_id_coordinator}" ) event = keeper.lock_reward_condition.subscribe_condition_fulfilled( agreement_id_coordinator, 60, None, (), wait=True) assert event is not None, "Reward condition is not found" event = keeper.compute_execution_condition.subscribe_condition_fulfilled( agreement_id_coordinator, 60, None, (), wait=True) assert event is not None, "Execution condition not found" # 7. Execute workflows compute_coordinator_id = nevermined.assets.execute( agreement_id_coordinator, ddo_compute_coordinator.did, service_agreement_coordinator.index, consumer, ddo_workflow_coordinator.did, ) print( f"[DATA_SCIENTIST --> COORDINATOR_PROVIDER] Requesting execution for coordinator compute: {compute_coordinator_id}" ) compute_asset0_id = nevermined.assets.execute( agreement_id0, ddo_compute0.did, service_agreement0.index, consumer, ddo_workflow0.did, ) print( f"[DATA_SCIENTIST --> DATA_PROVIDER0] Requesting execution for compute to data for asset0: {compute_asset0_id}" ) compute_asset1_id = nevermined.assets.execute( agreement_id1, ddo_compute1.did, service_agreement1.index, consumer, ddo_workflow1.did, ) print( f"[DATA_SCIENTIST --> DATA_PROVIDER1] Requesting execution for compute to data for asset1: {compute_asset1_id}" ) jobs = [ (agreement_id_coordinator, compute_coordinator_id), (agreement_id0, compute_asset0_id), (agreement_id1, compute_asset1_id), ] return jobs
def nft_transfer(): """Allows the provider transfer and release the rewards. swagger_from_file: docs/nft_transfer.yml """ required_attributes = [ 'agreementId', 'nftHolder', 'nftReceiver', 'nftAmount' ] data = request.json msg, status = check_required_attributes(required_attributes, data, 'nft-transfer') if msg: return msg, status agreement_id = data.get('agreementId') nft_holder_address = data.get('nftHolder') nft_receiver_address = data.get('nftReceiver') nft_amount = data.get('nftAmount') keeper = keeper_instance() agreement = keeper.agreement_manager.get_agreement(agreement_id) did = id_to_did(agreement.did) ddo = DIDResolver(keeper.did_registry).resolve(did) try: ServiceAgreement.from_ddo(ServiceTypes.NFT_SALES, ddo) except ValueError as e: logger.error('nft-sales service not found on ddo for %s', did) return str(e), 400 (lock_payment_condition_id, nft_transfer_condition_id, escrow_payment_condition_id) = agreement.condition_ids if not is_nft_holder(keeper, agreement.did, nft_amount, nft_holder_address): msg = f'Holder {nft_holder_address} does not have enough NFTs to transfer' logger.warning(msg) return msg, 406 if not is_lock_payment_condition_fulfilled(lock_payment_condition_id, keeper): msg = f'lockPayment condition for agreement_id={agreement_id} is not fulfilled' logger.warning(msg) return msg, 402 if not is_nft_transfer_approved(nft_holder_address, get_provider_account().address, keeper): msg = f'Gateway ({get_provider_account().address}) is not approved to transfer nfts from {nft_holder_address}' logger.warning(msg) return msg, 405 # fulfill transferNFT condition if not is_nft_transfer_condition_fulfilled(nft_transfer_condition_id, keeper): logger.debug('NFTTransfer condition not fulfilled') result = fulfill_for_delegate_nft_transfer_condition( agreement_id, agreement.did, Web3.toChecksumAddress(nft_holder_address), Web3.toChecksumAddress(nft_receiver_address), nft_amount, lock_payment_condition_id, keeper) if result is False: msg = f'There was an error fulfilling the NFTTransfer condition for agreement_id={agreement_id}' logger.error(msg) return msg, 500 # fulfill escrowPayment condition if not is_escrow_payment_condition_fulfilled(escrow_payment_condition_id, keeper): logger.debug('EscrowPayment condition not fulfilled') result = fulfill_escrow_payment_condition( keeper, agreement_id, [ nft_transfer_condition_id, lock_payment_condition_id, escrow_payment_condition_id ], ddo, get_provider_account(), service_type=ServiceTypes.NFT_SALES) if result is False: msg = f'There was an error fulfilling the EscrowPayment condition for agreement_id={agreement_id}' logger.error(msg) return msg, 500 return 'success', 200
def test_buy_asset(publisher_instance_no_init, consumer_instance_no_init): config = ExampleConfig.get_config() ConfigProvider.set_config(config) keeper = Keeper.get_instance() # :TODO: enable the actual SecretStore # SecretStoreProvider.set_secret_store_class(SecretStore) w3 = Web3Provider.get_web3() pub_acc = get_publisher_account() # Register ddo ddo = get_registered_ddo(publisher_instance_no_init, pub_acc) assert isinstance(ddo, DDO) # nevermined here will be used only to publish the asset. Handling the asset by the publisher # will be performed by the Gateway server running locally # restore the http client because we want the actual Gateway server to do the work # not the GatewayMock. # Gateway.set_http_client(requests) consumer_account = get_consumer_account() downloads_path_elements = len( os.listdir(consumer_instance_no_init._config.downloads_path)) if os.path.exists( consumer_instance_no_init._config.downloads_path) else 0 # sign agreement using the registered asset did above service = ddo.get_service(service_type=ServiceTypes.ASSET_ACCESS) sa = ServiceAgreement.from_service_dict(service.as_dictionary()) # This will send the access request to Gateway which in turn will execute the agreement on-chain consumer_instance_no_init.accounts.request_tokens(consumer_account, 100) agreement_id = consumer_instance_no_init.assets.order( ddo.did, sa.index, consumer_account, consumer_account) event_wait_time = 10 event = keeper.lock_payment_condition.subscribe_condition_fulfilled( agreement_id, event_wait_time, log_event(keeper.lock_payment_condition.FULFILLED_EVENT), (), wait=True ) assert event, 'no event for LockRewardCondition.Fulfilled' # give access publisher_instance_no_init.agreements.conditions.grant_access( agreement_id, ddo.asset_id, consumer_account.address, pub_acc) event = keeper.access_condition.subscribe_condition_fulfilled( agreement_id, event_wait_time, log_event(keeper.access_condition.FULFILLED_EVENT), (), wait=True ) assert event, 'no event for AccessSecretStoreCondition.Fulfilled' assert consumer_instance_no_init.agreements.is_access_granted(agreement_id, ddo.did, consumer_account.address) amounts = list(map(int, service.get_param_value_by_name('_amounts'))) receivers = service.get_param_value_by_name('_receivers') publisher_instance_no_init.agreements.conditions.release_reward( agreement_id, ddo.asset_id, amounts, receivers, pub_acc) assert consumer_instance_no_init.assets.access( agreement_id, ddo.did, sa.index, consumer_account, config.downloads_path) assert len(os.listdir(config.downloads_path)) == downloads_path_elements + 1 # Check that we can access only an specific file in passing the index. assert consumer_instance_no_init.assets.access( agreement_id, ddo.did, sa.index, consumer_account, config.downloads_path, 1 ) assert len(os.listdir(config.downloads_path)) == downloads_path_elements + 1 with pytest.raises(AssertionError): consumer_instance_no_init.assets.access( agreement_id, ddo.did, sa.index, consumer_account, config.downloads_path, -2 ) with pytest.raises(AssertionError): consumer_instance_no_init.assets.access( agreement_id, ddo.did, sa.index, consumer_account, config.downloads_path, 3 ) # decrypt the contentUrls using the publisher account instead of consumer account. # if the secret store is working and ACL check is enabled, this should fail # since SecretStore decrypt will fail the checkPermissions check and the gateway will return # an http error code back with pytest.raises(ValueError) as e: consumer_instance_no_init.assets.access( agreement_id, ddo.did, sa.index, pub_acc, config.downloads_path ) print(e)
def test_buy_asset_no_secret_store(publisher_instance_gateway, consumer_instance_gateway): config = ExampleConfig.get_config() ConfigProvider.set_config(config) keeper = Keeper.get_instance() w3 = Web3Provider.get_web3() pub_acc = get_publisher_account() for method in [ServiceAuthorizationTypes.SECRET_STORE, ServiceAuthorizationTypes.PSK_ECDSA, ServiceAuthorizationTypes.PSK_RSA]: # Register ddo ddo = get_registered_with_psk(publisher_instance_gateway, pub_acc, auth_method=method) assert isinstance(ddo, DDO) # nevermined here will be used only to publish the asset. Handling the asset by the publisher # will be performed by the Gateway server running locally # restore the http client because we want the actual Gateway server to do the work # not the GatewayMock. # Gateway.set_http_client(requests) consumer_account = get_consumer_account() downloads_path_elements = len( os.listdir(consumer_instance_gateway._config.downloads_path)) if os.path.exists( consumer_instance_gateway._config.downloads_path) else 0 # sign agreement using the registered asset did above service = ddo.get_service(service_type=ServiceTypes.ASSET_ACCESS) sa = ServiceAgreement.from_service_dict(service.as_dictionary()) # This will send the access request to Gateway which in turn will execute the agreement on-chain consumer_instance_gateway.accounts.request_tokens(consumer_account, 100) agreement_id = consumer_instance_gateway.assets.order( ddo.did, sa.index, consumer_account, consumer_account) event_wait_time = 10 event = keeper.access_template.subscribe_agreement_created( agreement_id, event_wait_time, log_event(keeper.access_template.AGREEMENT_CREATED_EVENT), (), wait=True ) assert event, 'no event for EscrowAccessSecretStoreTemplate.AgreementCreated' event = keeper.lock_payment_condition.subscribe_condition_fulfilled( agreement_id, event_wait_time, log_event(keeper.lock_payment_condition.FULFILLED_EVENT), (), wait=True ) assert event, 'no event for LockRewardCondition.Fulfilled' # give access publisher_instance_gateway.agreements.conditions.grant_access( agreement_id, ddo.asset_id, consumer_account.address, pub_acc) event = keeper.access_condition.subscribe_condition_fulfilled( agreement_id, event_wait_time, log_event(keeper.access_condition.FULFILLED_EVENT), (), wait=True ) assert event, 'no event for AccessSecretStoreCondition.Fulfilled' assert consumer_instance_gateway.agreements.is_access_granted(agreement_id, ddo.did, consumer_account.address) publisher_instance_gateway.agreements.conditions.release_reward( agreement_id, ddo.asset_id, sa.get_amounts_int(), sa.get_receivers(), pub_acc) assert consumer_instance_gateway.assets.access( agreement_id, ddo.did, sa.index, consumer_account, config.downloads_path) assert len(os.listdir(config.downloads_path)) == downloads_path_elements + 1 with pytest.raises(AssertionError): consumer_instance_gateway.assets.access( agreement_id, ddo.did, sa.index, consumer_account, config.downloads_path, -2 ) with pytest.raises(AssertionError): consumer_instance_gateway.assets.access( agreement_id, ddo.did, sa.index, consumer_account, config.downloads_path, 3 )