def test_assets_consumed(publisher_ocean_instance, consumer_ocean_instance): ocn = publisher_ocean_instance acct = consumer_ocean_instance.main_account consumed_assets = len(ocn.assets.consumer_assets(acct.address)) asset = create_asset(publisher_ocean_instance) service = asset.get_service(service_type=ServiceTypes.ASSET_ACCESS) service_dict = service.as_dictionary() sa = ServiceAgreement.from_json(service_dict) keeper = ocn.keeper def grant_access(_, ocn_instance, agr_id, did, cons_address, account): ocn_instance.agreements.conditions.grant_access( agr_id, did, cons_address, account) agreement_id = consumer_ocean_instance.assets.order( asset.did, sa.index, acct) keeper.lock_reward_condition.subscribe_condition_fulfilled( agreement_id, 15, grant_access, (publisher_ocean_instance, agreement_id, asset.did, acct.address, publisher_ocean_instance.main_account), wait=True) keeper.access_secret_store_condition.subscribe_condition_fulfilled( agreement_id, 15, log_event(keeper.access_secret_store_condition.FULFILLED_EVENT), (), wait=True) assert ocn.agreements.is_access_granted(agreement_id, asset.did, acct.address) assert len(ocn.assets.consumer_assets(acct.address)) == consumed_assets + 1 publisher_ocean_instance.assets.retire(asset.did)
def test_agreement_hash(): """ 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. """ did = "did:op:0bc278fee025464f8012b811d1bce8e22094d0984e4e49139df5d5ff7a028bdf" template_id = '0x34219511357c43f4af90a4896b972a32809379bfbe8148eab3878e8406e75836' agreement_id = '0xf136d6fadecb48fdb2fc1fb420f5a5d1c32d22d9424e47ab9461556e058fefaa' ddo = get_ddo_sample() sa = ServiceAgreement.from_json( ddo.get_service(ServiceTypes.ASSET_ACCESS).as_dictionary()) assert did == ddo.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( 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 = '0xc1bc6cdb161b9d04d5b48bceba51b9092c4da8db08003b96b93647fbe86e330c' print('expected hash: ', expected) assert agreement_hash.hex() == expected, 'hash does not match.'
def _read_dict(self, dictionary): """Import a JSON dict into this DDO.""" values = copy.deepcopy(dictionary) self._did = values.pop('id') self._created = values.pop('created', None) if 'publicKey' in values: self._public_keys = [] for value in values.pop('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.pop('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.pop('service'): if isinstance(value, str): value = json.loads(value) if value['type'] == ServiceTypes.ASSET_ACCESS: service = ServiceAgreement.from_json(value) elif value['type'] == ServiceTypes.CLOUD_COMPUTE: service = ServiceAgreement.from_json(value) else: service = Service.from_json(value) self._services.append(service) if 'proof' in values: self._proof = values.pop('proof') self._other_values = values
def test_market_flow(): pub_wallet = get_publisher_wallet() publisher_ocean = get_publisher_ocean_instance() consumer_ocean = get_consumer_ocean_instance() # Register Asset asset = get_registered_ddo(publisher_ocean, pub_wallet) assert isinstance(asset, Asset) assert asset.data_token_address consumer_wallet = get_consumer_wallet() service = asset.get_service(service_type=ServiceTypes.ASSET_ACCESS) sa = ServiceAgreement.from_json(service.as_dictionary()) # Mint data tokens and assign to publisher dt = publisher_ocean.get_data_token(asset.data_token_address) mint_tokens_and_wait(dt, pub_wallet.address, pub_wallet) ###### # Give the consumer some datatokens so they can order the service try: tx_id = dt.transfer_tokens(consumer_wallet.address, 10, pub_wallet) dt.verify_transfer_tx(tx_id, pub_wallet.address, consumer_wallet.address) except (AssertionError, Exception) as e: print(e) raise ###### # Place order for the download service order_requirements = consumer_ocean.assets.order(asset.did, consumer_wallet.address, sa.index) ###### # Pay for the service _order_tx_id = consumer_ocean.assets.pay_for_service( order_requirements.amount, order_requirements.data_token_address, asset.did, service.index, '0xF9f2DB837b3db03Be72252fAeD2f6E0b73E428b9', consumer_wallet) ###### # Download the asset files asset_folder = consumer_ocean.assets.download( asset.did, sa.index, consumer_wallet, _order_tx_id, consumer_ocean.config.downloads_path) assert len(os.listdir(asset_folder)) > 1 orders = consumer_ocean.get_user_orders(consumer_wallet.address, asset.asset_id) assert orders, f'no orders found using the order history: datatoken {asset.asset_id}, consumer {consumer_wallet.address}' orders = consumer_ocean.get_user_orders( consumer_wallet.address, consumer_ocean.web3.toChecksumAddress(asset.asset_id)) assert orders, f'no orders found using the order history: datatoken {asset.asset_id}, consumer {consumer_wallet.address}' orders = consumer_ocean.get_user_orders(consumer_wallet.address) assert orders, f'no orders found using the order history: datatoken {asset.asset_id}, consumer {consumer_wallet.address}'
def test_market_flow(order_type): """Tests that an order is correctly placed on the market. The parameter implicit_none sends the payload with an empty key as the delegated consumer. The parameter explicit_none sends None as the delegated consumer, explicitly.""" pub_wallet = get_publisher_wallet() publisher_ocean = get_publisher_ocean_instance() consumer_ocean = get_consumer_ocean_instance() # Register Asset asset = get_registered_ddo(publisher_ocean, get_metadata(), pub_wallet) assert isinstance(asset, Asset) assert asset.data_token_address consumer_wallet = get_consumer_wallet() service = asset.get_service(service_type=ServiceTypes.ASSET_ACCESS) sa = ServiceAgreement.from_json(service.as_dictionary()) # Mint data tokens and assign to publisher dt = publisher_ocean.get_data_token(asset.data_token_address) mint_tokens_and_wait(dt, pub_wallet.address, pub_wallet) ###### # Give the consumer some datatokens so they can order the service try: tx_id = dt.transfer_tokens(consumer_wallet.address, 10.0, pub_wallet) dt.verify_transfer_tx(tx_id, pub_wallet.address, consumer_wallet.address) except (AssertionError, Exception) as e: print(e) raise ###### # Place order for the download service order_requirements = consumer_ocean.assets.order(asset.did, consumer_wallet.address, sa.index) ###### # Pay for the service args = [ order_requirements.amount, order_requirements.data_token_address, asset.did, service.index, "0xF9f2DB837b3db03Be72252fAeD2f6E0b73E428b9", consumer_wallet, ] if order_type == "explicit_none": args.append(None) _order_tx_id = consumer_ocean.assets.pay_for_service(*args) ###### # Download the asset files asset_folder = consumer_ocean.assets.download( asset.did, sa.index, consumer_wallet, _order_tx_id, consumer_ocean.config.downloads_path, ) assert len(os.listdir(asset_folder)) >= 1 if order_type == "explicit_none": # no need to continue, order worked return orders = consumer_ocean.get_user_orders(consumer_wallet.address, asset.asset_id) assert ( orders ), f"no orders found using the order history: datatoken {asset.asset_id}, consumer {consumer_wallet.address}" orders = consumer_ocean.get_user_orders( consumer_wallet.address, consumer_ocean.web3.toChecksumAddress(asset.asset_id)) assert ( orders ), f"no orders found using the order history: datatoken {asset.asset_id}, consumer {consumer_wallet.address}" orders = consumer_ocean.get_user_orders(consumer_wallet.address) assert ( orders ), f"no orders found using the order history: datatoken {asset.asset_id}, consumer {consumer_wallet.address}"
def test_payer_market_flow(): """Tests that an order can be placed for a delegated consumer, other than the payer.""" pub_wallet = get_publisher_wallet() publisher_ocean = get_publisher_ocean_instance() consumer_ocean = get_consumer_ocean_instance() another_consumer_ocean = get_another_consumer_ocean_instance( use_provider_mock=True) # Register Asset asset = get_registered_ddo(publisher_ocean, get_metadata(), pub_wallet) assert isinstance(asset, Asset) assert asset.data_token_address another_consumer_wallet = get_another_consumer_wallet() consumer_wallet = get_consumer_wallet() service = asset.get_service(service_type=ServiceTypes.ASSET_ACCESS) sa = ServiceAgreement.from_json(service.as_dictionary()) # Mint data tokens and assign to publisher dt = publisher_ocean.get_data_token(asset.data_token_address) mint_tokens_and_wait(dt, pub_wallet.address, pub_wallet) ###### # Give the consumer some datatokens so they can order the service try: tx_id = dt.transfer_tokens(consumer_wallet.address, 10.0, pub_wallet) dt.verify_transfer_tx(tx_id, pub_wallet.address, consumer_wallet.address) except (AssertionError, Exception) as e: print(e) raise ###### # Place order for the download service order_requirements = consumer_ocean.assets.order( asset.did, another_consumer_wallet.address, sa.index) ###### # Pay for the service and have another_consumer_wallet as consumer _order_tx_id = consumer_ocean.assets.pay_for_service( order_requirements.amount, order_requirements.data_token_address, asset.did, service.index, "0xF9f2DB837b3db03Be72252fAeD2f6E0b73E428b9", consumer_wallet, another_consumer_wallet.address, ) asset_folder = None assert asset_folder is None if asset_folder is None: # Download the asset files asset_folder = another_consumer_ocean.assets.download( asset.did, sa.index, another_consumer_wallet, _order_tx_id, another_consumer_ocean.config.downloads_path, ) assert len(os.listdir(asset_folder)) >= 1 orders = consumer_ocean.get_user_orders(consumer_wallet.address, asset.asset_id) assert ( orders ), f"no orders found using the order history: datatoken {asset.asset_id}, consumer {consumer_wallet.address}" orders = consumer_ocean.get_user_orders( consumer_wallet.address, consumer_ocean.web3.toChecksumAddress(asset.asset_id)) assert ( orders ), f"no orders found using the order history: datatoken {asset.asset_id}, consumer {consumer_wallet.address}" orders = consumer_ocean.get_user_orders(consumer_wallet.address) assert ( orders ), f"no orders found using the order history: datatoken {asset.asset_id}, consumer {consumer_wallet.address}"
def buy_asset(): """ Requires all ocean services running. """ setup_logging(default_level=logging.INFO) ConfigProvider.set_config(ExampleConfig.get_config()) config = ConfigProvider.get_config() providers = { 'duero': '0xfEF2d5e1670342b9EF22eeeDcb287EC526B48095', 'nile': '0x4aaab179035dc57b35e2ce066919048686f82972' } # make ocean instance ocn = Ocean() acc = get_account(1) if not acc: acc = ([acc for acc in ocn.accounts.list() if acc.password] or ocn.accounts.list())[0] Diagnostics.verify_contracts() metadata = example_metadata.metadata.copy() metadata['main']['dateCreated'] = get_timestamp() keeper = Keeper.get_instance() # Register ddo did = '' if did: ddo = ocn.assets.resolve(did) logging.info(f'using ddo: {did}') else: ddo = ocn.assets.create(metadata, acc, providers=[], use_secret_store=True) assert ddo is not None, f'Registering asset on-chain failed.' did = ddo.did logging.info(f'registered ddo: {did}') # ocn here will be used only to publish the asset. Handling the asset by the publisher # will be performed by the Brizo server running locally test_net = os.environ.get('TEST_NET', '') if test_net.startswith('nile'): provider = keeper.did_registry.to_checksum_address(providers['nile']) elif test_net.startswith('duero'): provider = keeper.did_registry.to_checksum_address(providers['duero']) else: provider = '0x068Ed00cF0441e4829D9784fCBe7b9e26D4BD8d0' # Wait for did registry event event = keeper.did_registry.subscribe_to_event( keeper.did_registry.DID_REGISTRY_EVENT_NAME, 30, event_filter={ '_did': Web3Provider.get_web3().toBytes(hexstr=ddo.asset_id), '_owner': acc.address}, wait=True ) if not event: logging.warning(f'Failed to get the did registry event for asset with did {did}.') assert keeper.did_registry.get_block_number_updated(ddo.asset_id) > 0, \ f'There is an issue in registering asset {did} on-chain.' keeper.did_registry.add_provider(ddo.asset_id, provider, acc) logging.info(f'is {provider} set as did provider: ' f'{keeper.did_registry.is_did_provider(ddo.asset_id, provider)}') _providers = keeper.did_registry.get_did_providers(ddo.asset_id) access_template_name = keeper.template_manager.SERVICE_TO_TEMPLATE_NAME['access'] template_id = keeper.template_manager.create_template_id(access_template_name) approved = keeper.template_manager.is_template_approved(template_id) print(f'agreement template approved: {approved}') template_data = keeper.template_manager.get_template(template_id) print(f'access agreement template: {template_data}') cons_ocn = Ocean() consumer_account = get_account(0) # sign agreement using the registered asset did above service = ddo.get_service(service_type=ServiceTypes.ASSET_ACCESS) # This will send the order request to Brizo which in turn will execute the agreement on-chain cons_ocn.accounts.request_tokens(consumer_account, 10) sa = ServiceAgreement.from_json(service.as_dictionary()) agreement_id = '' if not agreement_id: agreement_id = cons_ocn.assets.order( did, sa.index, consumer_account) logging.info('placed order: %s, %s', did, agreement_id) event = keeper.agreement_manager.subscribe_agreement_created( agreement_id, 60, None, (), wait=True ) assert event, "Agreement event is not found, check the keeper node's logs" logging.info(f'Got agreement event, next: lock reward condition') event = keeper.lock_reward_condition.subscribe_condition_fulfilled( agreement_id, 60, None, (), wait=True ) assert event, "Lock reward condition fulfilled event is not found, check the keeper node's logs" logging.info('Got lock reward event, next: wait for the access condition..') event = keeper.access_secret_store_condition.subscribe_condition_fulfilled( agreement_id, 15, None, (), wait=True ) logging.info(f'Got access event {event}') i = 0 while ocn.agreements.is_access_granted( agreement_id, did, consumer_account.address) is not True and i < 30: time.sleep(1) i += 1 assert ocn.agreements.is_access_granted(agreement_id, did, consumer_account.address) ocn.assets.consume( agreement_id, did, sa.index, consumer_account, config.downloads_path) logging.info('Success buying asset.') event = keeper.escrow_reward_condition.subscribe_condition_fulfilled( agreement_id, 30, None, (), wait=True ) assert event, 'no event for EscrowReward.Fulfilled' logging.info(f'got EscrowReward.FULFILLED event: {event}') logging.info('Done buy asset.')
def test_buy_asset(consumer_ocean_instance, publisher_ocean_instance): 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_ocean_instance, pub_acc) assert isinstance(ddo, DDO) # ocn here will be used only to publish the asset. Handling the asset by the publisher # will be performed by the Brizo server running locally cons_ocn = consumer_ocean_instance # restore the http client because we want the actual Brizo server to do the work # not the BrizoMock. # Brizo.set_http_client(requests) consumer_account = get_consumer_account() downloads_path_elements = len( os.listdir( consumer_ocean_instance._config.downloads_path)) if os.path.exists( consumer_ocean_instance._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_json(service.as_dictionary()) # This will send the consume request to Brizo which in turn will execute the agreement on-chain cons_ocn.accounts.request_tokens(consumer_account, 100) agreement_id = cons_ocn.assets.order(ddo.did, sa.index, consumer_account, auto_consume=False) event_wait_time = 10 event = keeper.escrow_access_secretstore_template.subscribe_agreement_created( agreement_id, event_wait_time, log_event( keeper.escrow_access_secretstore_template.AGREEMENT_CREATED_EVENT), (), wait=True) assert event, 'no event for EscrowAccessSecretStoreTemplate.AgreementCreated' event = keeper.lock_reward_condition.subscribe_condition_fulfilled( agreement_id, event_wait_time, log_event(keeper.lock_reward_condition.FULFILLED_EVENT), (), wait=True) assert event, 'no event for LockRewardCondition.Fulfilled' # give access publisher_ocean_instance.agreements.conditions.grant_access( agreement_id, ddo.did, consumer_account.address, pub_acc) event = keeper.access_secret_store_condition.subscribe_condition_fulfilled( agreement_id, event_wait_time, log_event(keeper.access_secret_store_condition.FULFILLED_EVENT), (), wait=True) assert event, 'no event for AccessSecretStoreCondition.Fulfilled' assert cons_ocn.agreements.is_access_granted(agreement_id, ddo.did, consumer_account.address) assert cons_ocn.assets.consume(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 consume only an specific file in passing the index. assert cons_ocn.assets.consume(agreement_id, ddo.did, sa.index, consumer_account, config.downloads_path, 2) assert len(os.listdir( config.downloads_path)) == downloads_path_elements + 1 with pytest.raises(AssertionError): cons_ocn.assets.consume(agreement_id, ddo.did, sa.index, consumer_account, config.downloads_path, -2) with pytest.raises(AssertionError): cons_ocn.assets.consume(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 try: cons_ocn.assets.consume(agreement_id, ddo.did, sa.index, pub_acc, config.downloads_path) except RPCError: print('hooray, secret store is working as expected.') publisher_ocean_instance.agreements.conditions.release_reward( agreement_id, sa.get_price(), pub_acc) event = keeper.escrow_reward_condition.subscribe_condition_fulfilled( agreement_id, event_wait_time + 20, log_event(keeper.escrow_reward_condition.FULFILLED_EVENT), (), wait=True) assert event, 'no event for EscrowReward.Fulfilled' assert w3.toHex(event.args['_agreementId']) == agreement_id
def start( self, input_datasets: list, consumer_wallet: Wallet, nonce: [int, None] = None, algorithm_did: [str, None] = None, algorithm_meta: [AlgorithmMetadata, None] = None, algorithm_tx_id: str = None, algorithm_data_token: str = None, output: dict = None, job_id: str = None, ): """ Start a remote compute job on the asset files. Files are identified by `did` after verifying that the provider service is active and transferring the number of data-tokens required for using this compute service. :param input_datasets: list of ComputeInput -- list of input datasets to the compute job. A dataset is represented with ComputeInput struct :param consumer_wallet: Wallet instance of the consumer ordering the service :param nonce: int value to use in the signature :param algorithm_did: str -- the asset did (of `algorithm` type) which consist of `did:op:` and the assetId hex str (without `0x` prefix) :param algorithm_meta: `AlgorithmMetadata` instance -- metadata about the algorithm being run if `algorithm` is being used. This is ignored when `algorithm_did` is specified. :param algorithm_tx_id: transaction hash of algorithm StartOrder tx (Required when using `algorithm_did`) :param algorithm_data_token: datatoken address of this algorithm (Required when using `algorithm_did`) :param output: dict object to be used in publishing mechanism, must define :param job_id: str identifier of a compute job that was previously started and stopped (if supported by the provider's backend) :return: str -- id of compute job being executed """ assert ( algorithm_did or algorithm_meta ), "either an algorithm did or an algorithm meta must be provided." for i in input_datasets: assert isinstance(i, ComputeInput) first_input = input_datasets[0] did = first_input.did order_tx_id = first_input.transfer_tx_id service_id = first_input.service_id output = OceanCompute.check_output_dict( output, consumer_wallet.address, data_provider=self._data_provider ) asset = resolve_asset(did, metadata_store_url=self._config.aquarius_url) _, service_endpoint = self._get_service_endpoint(did, asset) service = asset.get_service_by_index(service_id) sa = ServiceAgreement.from_json(service.as_dictionary()) assert ( ServiceTypes.CLOUD_COMPUTE == sa.type ), "service at serviceId is not of type compute service." signature = self._sign_message( consumer_wallet, f"{consumer_wallet.address}{did}", nonce=nonce, service_endpoint=sa.service_endpoint, ) job_info = self._data_provider.start_compute_job( did, service_endpoint, consumer_wallet.address, signature, sa.index, order_tx_id, algorithm_did, algorithm_meta, algorithm_tx_id, algorithm_data_token, output, input_datasets, job_id, ) return job_info["jobId"]