Exemple #1
0
def test_compute_not_an_algo(client):
    pub_wallet = get_publisher_wallet()
    cons_wallet = get_consumer_wallet()

    (
        _,
        did,
        tx_id,
        sa,
        data_token,
        _,
        alg_data_token,
        _,
        alg_tx_id,
    ) = build_and_send_ddo_with_compute_service(
        client, asset_type="allow_all_published")

    nonce = get_nonce(client, cons_wallet.address)
    # prepare consumer signature on did
    msg = f"{cons_wallet.address}{did}{str(nonce)}"
    _hash = add_ethereum_prefix_and_hash_msg(msg)
    signature = Web3Helper.sign_hash(_hash, cons_wallet)

    # Start the compute job
    payload = dict({
        "signature":
        signature,
        "documentId":
        did,
        "serviceId":
        sa.index,
        "serviceType":
        sa.type,
        "consumerAddress":
        cons_wallet.address,
        "transferTxId":
        tx_id,
        "dataToken":
        data_token,
        "output":
        build_stage_output_dict(dict(), sa.service_endpoint,
                                cons_wallet.address, pub_wallet),
        "algorithmDid":
        did,  # intentionally, should not be an algo did
        "algorithmDataToken":
        alg_data_token,
        "algorithmTransferTxId":
        alg_tx_id,
    })

    # Start compute with valid signature
    payload["signature"] = signature
    compute_endpoint = BaseURLs.ASSETS_URL + "/compute"
    response = client.post(compute_endpoint,
                           data=json.dumps(payload),
                           content_type="application/json")
    assert response.status == "400 BAD REQUEST"
    error = response.get_json()["error"]
    assert "is not a valid algorithm" in error
def test_compute_norawalgo_allowed(client):
    pub_wallet = get_publisher_wallet()
    cons_wallet = get_consumer_wallet()

    # publish a dataset asset
    dataset_ddo_w_compute_service = get_dataset_ddo_with_compute_service_no_rawalgo(client, pub_wallet)
    did = dataset_ddo_w_compute_service.did
    ddo = dataset_ddo_w_compute_service
    data_token = dataset_ddo_w_compute_service.data_token_address
    dt_contract = DataToken(data_token)
    mint_tokens_and_wait(dt_contract, cons_wallet, pub_wallet)

    # CHECKPOINT 1
    algorithm_meta = {
        "rawcode": "console.log('Hello world'!)",
        "format": 'docker-image',
        "version": '0.1',
        "container": {
            "entrypoint": 'node $ALGO',
            "image": 'node',
            "tag": '10'
        }
    }
    # prepare parameter values for the compute endpoint
    # signature, documentId, consumerAddress, and algorithmDid or algorithmMeta

    sa = ServiceAgreement.from_ddo(ServiceTypes.CLOUD_COMPUTE, dataset_ddo_w_compute_service)
    tx_id = send_order(client, ddo, dt_contract, sa, cons_wallet)
    nonce = get_nonce(client, cons_wallet.address)

    # prepare consumer signature on did
    msg = f'{cons_wallet.address}{did}{nonce}'
    _hash = add_ethereum_prefix_and_hash_msg(msg)
    signature = Web3Helper.sign_hash(_hash, cons_wallet)

    # Start the compute job
    payload = dict({
        'signature': signature,
        'documentId': did,
        'serviceId': sa.index,
        'serviceType': sa.type,
        'consumerAddress': cons_wallet.address,
        'transferTxId': tx_id,
        'dataToken': data_token,
        'output': build_stage_output_dict(dict(), dataset_ddo_w_compute_service, cons_wallet.address, pub_wallet),
        'algorithmDid': '',
        'algorithmMeta': algorithm_meta,
        'algorithmDataToken': ''
    })

    compute_endpoint = BaseURLs.ASSETS_URL + '/compute'
    response = client.post(
        compute_endpoint,
        data=json.dumps(payload),
        content_type='application/json'
    )
    assert response.status == '400 BAD REQUEST', f'start compute job failed: {response.status} , { response.data}'
Exemple #3
0
def test_compute_diff_provider(client):
    pub_wallet = get_publisher_wallet()
    cons_wallet = get_consumer_wallet()

    (
        _,
        did,
        tx_id,
        sa,
        data_token,
        alg_ddo,
        alg_data_token,
        _,
        alg_tx_id,
    ) = build_and_send_ddo_with_compute_service(client, alg_diff=True)

    nonce = get_nonce(client, cons_wallet.address)
    # prepare consumer signature on did
    msg = f"{cons_wallet.address}{did}{str(nonce)}"
    _hash = add_ethereum_prefix_and_hash_msg(msg)
    signature = Web3Helper.sign_hash(_hash, cons_wallet)

    # Start the compute job
    payload = dict({
        "signature":
        signature,
        "documentId":
        did,
        "serviceId":
        sa.index,
        "serviceType":
        sa.type,
        "consumerAddress":
        cons_wallet.address,
        "transferTxId":
        tx_id,
        "dataToken":
        data_token,
        "output":
        build_stage_output_dict(dict(), sa.service_endpoint,
                                cons_wallet.address, pub_wallet),
        "algorithmDid":
        alg_ddo.did,
        "algorithmDataToken":
        alg_data_token,
        "algorithmTransferTxId":
        alg_tx_id,
    })

    compute_endpoint = BaseURLs.ASSETS_URL + "/compute"
    response = client.post(compute_endpoint,
                           data=json.dumps(payload),
                           content_type="application/json")

    assert response.status == "200 OK", f"start compute job failed: {response.data}"
def test_compute_specific_algo_dids(client):
    pub_wallet = get_publisher_wallet()
    cons_wallet = get_consumer_wallet()

    # publish a dataset asset
    dataset_ddo_w_compute_service = get_dataset_ddo_with_compute_service_specific_algo_dids(client, pub_wallet)
    did = dataset_ddo_w_compute_service.did
    ddo = dataset_ddo_w_compute_service
    data_token = dataset_ddo_w_compute_service.as_dictionary()['dataToken']
    dt_contract = DataToken(data_token)
    mint_tokens_and_wait(dt_contract, cons_wallet, pub_wallet)

    # publish an algorithm asset (asset with metadata of type `algorithm`)
    alg_ddo = get_algorithm_ddo(client, cons_wallet)
    alg_data_token = alg_ddo.as_dictionary()['dataToken']
    alg_dt_contract = DataToken(alg_data_token)
    mint_tokens_and_wait(alg_dt_contract, pub_wallet, cons_wallet)
    # CHECKPOINT 1

    sa = ServiceAgreement.from_ddo(ServiceTypes.CLOUD_COMPUTE, dataset_ddo_w_compute_service)
    tx_id = send_order(client, ddo, dt_contract, sa, cons_wallet)
    nonce = get_nonce(client, cons_wallet.address)

    # prepare consumer signature on did
    msg = f'{cons_wallet.address}{did}{nonce}'
    _hash = add_ethereum_prefix_and_hash_msg(msg)
    signature = Web3Helper.sign_hash(_hash, cons_wallet)

    # Start the compute job
    payload = dict({
        'signature': signature,
        'documentId': did,
        'serviceId': sa.index,
        'serviceType': sa.type,
        'consumerAddress': cons_wallet.address,
        'transferTxId': tx_id,
        'dataToken': data_token,
        'output': build_stage_output_dict(dict(), dataset_ddo_w_compute_service, cons_wallet.address, pub_wallet),
        'algorithmDid': alg_ddo.did,
        'algorithmMeta': {},
        'algorithmDataToken': alg_data_token
    })

    compute_endpoint = BaseURLs.ASSETS_URL + '/compute'
    response = client.post(
        compute_endpoint,
        data=json.dumps(payload),
        content_type='application/json'
    )
    assert response.status == '400 BAD REQUEST', f'start compute job failed: {response.status} , { response.data}'
Exemple #5
0
    def validate_output(self):
        """Validates output dictionary after stage build."""
        output_def = decode_from_data(self.data, "output", dec_type="dict")

        if output_def == -1:
            self.error = "Output is invalid or can not be decoded."
            return False

        self.validated_output_dict = build_stage_output_dict(
            output_def,
            self.service_endpoint,
            self.consumer_address,
            self.provider_wallet,
        )

        return True
def computeStart():
    """Call the execution of a workflow.

    ---
    tags:
      - services
    consumes:
      - application/json
    parameters:
      - name: signature
        in: query
        description: Signature of (consumerAddress+jobId+documentId) to verify the consumer of
            this asset/compute job. The signature uses ethereum based signing method
            (see https://github.com/ethereum/EIPs/pull/683)
        type: string
      - name: consumerAddress
        in: query
        description: The consumer ethereum address.
        required: true
        type: string

      - name: algorithmDid
        in: query
        description: The DID of the algorithm Asset to be executed
        required: false
        type: string
      - name: algorithmMeta
        in: query
        description: json object that define the algorithm attributes and url or raw code
        required: false
        type: json string
      - name: output
        in: query
        description: json object that define the output section
        required: true
        type: json string
    responses:
      200:
        description: Call to the operator-service was successful.
      400:
        description: One of the required attributes is missing.
      401:
        description: Consumer signature is invalid or failed verification
      500:
        description: General server error
    """
    data = get_request_data(request)

    try:
        asset, service, did, consumer_address, token_address = process_consume_request(  # noqa
            data,
            'compute_start_job',
            additional_params=["transferTxId", "output"],
            require_signature=False)
        service_id = data.get('serviceId')
        service_type = data.get('serviceType')
        signature = data.get('signature')
        tx_id = data.get("transferTxId")

        # Verify that  the number of required tokens has been
        # transferred to the provider's wallet.

        _tx, _order_log, _transfer_log = validate_order(
            consumer_address, token_address, float(service.get_cost()), tx_id,
            add_0x_prefix(did_to_id(did)) if did.startswith('did:') else did,
            service_id)
        validate_transfer_not_used_for_other_service(did, service_id, tx_id,
                                                     consumer_address,
                                                     token_address)
        record_consume_request(did, service_id, tx_id, consumer_address,
                               token_address, service.get_cost())

        algorithm_did = data.get('algorithmDid')
        algorithm_token_address = data.get('algorithmDataToken')
        algorithm_meta = data.get('algorithmMeta')
        algorithm_tx_id = data.get('algorithmTransferTxId')
        output_def = data.get('output', dict())

        assert service_type == ServiceTypes.CLOUD_COMPUTE

        # Validate algorithm choice
        if not (algorithm_meta or algorithm_did):
            msg = f'Need an `algorithmMeta` or `algorithmDid` to run, otherwise don\'t bother.'  # noqa
            logger.error(msg, exc_info=1)
            return jsonify(error=msg), 400

        # algorithmDid also requires algorithmDataToken
        # and algorithmTransferTxId
        if algorithm_did:
            if not (algorithm_token_address and algorithm_tx_id):
                msg = (
                    f'Using `algorithmDid` requires the `algorithmDataToken` and '  # noqa
                    f'`algorithmTransferTxId` values in the request payload. '
                    f'algorithmDataToken is the DataToken address for the algorithm asset. '  # noqa
                    f'algorithmTransferTxId is the transaction id (hash) of transferring '  # noqa
                    f'data tokens from consumer wallet to this providers wallet.'
                )
                logger.error(msg, exc_info=1)
                return jsonify(error=msg), 400

        # Consumer signature
        original_msg = f'{consumer_address}{did}'
        verify_signature(consumer_address, signature, original_msg,
                         user_nonce.get_nonce(consumer_address))

        ########################
        # Valid service?
        if service is None:
            return jsonify(
                error=f'This DID has no compute service {did}.'), 400

        #########################
        # Check privacy
        privacy_options = service.main.get('privacy', {})
        if (algorithm_meta
                and privacy_options.get('allowRawAlgorithm', True) is False):
            return jsonify(
                error=f'cannot run raw algorithm on this did {did}.'), 400

        trusted_algorithms = privacy_options.get('trustedAlgorithms', [])
        if (algorithm_did and trusted_algorithms
                and algorithm_did not in trusted_algorithms):
            return jsonify(
                error=f'cannot run raw algorithm on this did {did}.'), 400

        #########################
        # Validate ALGORITHM meta
        if algorithm_meta:
            algorithm_meta = json.loads(algorithm_meta) if isinstance(
                algorithm_meta, str) else algorithm_meta

        algorithm_dict = build_stage_algorithm_dict(
            consumer_address, algorithm_did, algorithm_token_address,
            algorithm_tx_id, algorithm_meta, provider_wallet)
        error_msg, status_code = validate_algorithm_dict(
            algorithm_dict, algorithm_did)
        if error_msg:
            return jsonify(error=error_msg), status_code

        #########################
        # INPUT
        asset_urls = get_asset_download_urls(
            asset, provider_wallet, config_file=app.config['CONFIG_FILE'])
        if not asset_urls:
            return jsonify(error=f'cannot get url(s) in input did {did}.'), 400

        input_dict = dict({'index': 0, 'id': did, 'url': asset_urls})

        #########################
        # OUTPUT
        if output_def:
            output_def = json.loads(output_def) if isinstance(
                output_def, str) else output_def
        output_dict = build_stage_output_dict(output_def, asset,
                                              consumer_address,
                                              provider_wallet)

        #########################
        # STAGE
        stage = build_stage_dict(input_dict, algorithm_dict, output_dict)

        #########################
        # WORKFLOW
        workflow = dict({'stages': list([stage])})

        # workflow is ready, push it to operator
        logger.info('Sending: %s', workflow)

        msg_to_sign = f'{provider_wallet.address}{did}'
        msg_hash = add_ethereum_prefix_and_hash_msg(msg_to_sign)
        payload = {
            'workflow': workflow,
            'providerSignature': Web3Helper.sign_hash(msg_hash,
                                                      provider_wallet),
            'documentId': did,
            'agreementId': tx_id,
            'owner': consumer_address,
            'providerAddress': provider_wallet.address
        }
        response = requests_session.post(
            get_compute_endpoint(),
            data=json.dumps(payload),
            headers={'content-type': 'application/json'})
        user_nonce.increment_nonce(consumer_address)
        return Response(response.content,
                        response.status_code,
                        headers={'content-type': 'application/json'})

    except InvalidSignatureError as e:
        msg = f'Consumer signature failed verification: {e}'
        logger.error(msg, exc_info=1)
        return jsonify(error=msg), 401

    except (ValueError, KeyError, Exception) as e:
        logger.error(f'Error- {str(e)}', exc_info=1)
        return jsonify(error=f'Error : {str(e)}'), 500
Exemple #7
0
def test_compute_norawalgo_allowed(client):
    pub_wallet = get_publisher_wallet()
    cons_wallet = get_consumer_wallet()

    # publish a dataset asset
    dataset_ddo_w_compute_service = comp_ds_no_rawalgo(client, pub_wallet)
    did = dataset_ddo_w_compute_service.did
    ddo = dataset_ddo_w_compute_service

    data_token = dataset_ddo_w_compute_service.data_token_address
    dt_contract = DataToken(data_token)
    mint_tokens_and_wait(dt_contract, cons_wallet, pub_wallet)

    # CHECKPOINT 1
    algorithm_meta = {
        "rawcode": "console.log('Hello world'!)",
        "format": "docker-image",
        "version": "0.1",
        "container": {
            "entrypoint": "node $ALGO",
            "image": "node",
            "tag": "10"
        },
    }
    # prepare parameter values for the compute endpoint
    # signature, documentId, consumerAddress, and algorithmDid or algorithmMeta

    sa = ServiceAgreement.from_ddo(ServiceTypes.CLOUD_COMPUTE,
                                   dataset_ddo_w_compute_service)
    tx_id = send_order(client, ddo, dt_contract, sa, cons_wallet)
    nonce = get_nonce(client, cons_wallet.address)

    # prepare consumer signature on did
    msg = f"{cons_wallet.address}{did}{nonce}"
    _hash = add_ethereum_prefix_and_hash_msg(msg)
    signature = Web3Helper.sign_hash(_hash, cons_wallet)

    # Start the compute job
    payload = dict({
        "signature":
        signature,
        "documentId":
        did,
        "serviceId":
        sa.index,
        "serviceType":
        sa.type,
        "consumerAddress":
        cons_wallet.address,
        "transferTxId":
        tx_id,
        "dataToken":
        data_token,
        "output":
        build_stage_output_dict(dict(), sa.service_endpoint,
                                cons_wallet.address, pub_wallet),
        "algorithmMeta":
        algorithm_meta,
        "algorithmDataToken":
        "",
    })

    compute_endpoint = BaseURLs.ASSETS_URL + "/compute"
    response = client.post(compute_endpoint,
                           data=json.dumps(payload),
                           content_type="application/json")
    assert (response.status == "400 BAD REQUEST"
            ), f"start compute job failed: {response.status} , {response.data}"
Exemple #8
0
def test_compute(client):
    pub_wallet = get_publisher_wallet()
    cons_wallet = get_consumer_wallet()

    (
        _,
        did,
        tx_id,
        sa,
        data_token,
        alg_ddo,
        alg_data_token,
        _,
        alg_tx_id,
    ) = build_and_send_ddo_with_compute_service(client)

    nonce = get_nonce(client, cons_wallet.address)
    # prepare consumer signature on did
    msg = f"{cons_wallet.address}{did}{str(nonce)}"
    _hash = add_ethereum_prefix_and_hash_msg(msg)
    signature = Web3Helper.sign_hash(_hash, cons_wallet)

    # Start the compute job
    payload = dict({
        "signature":
        signature,
        "documentId":
        did,
        "serviceId":
        sa.index,
        "serviceType":
        sa.type,
        "consumerAddress":
        cons_wallet.address,
        "transferTxId":
        tx_id,
        "dataToken":
        data_token,
        "output":
        build_stage_output_dict(dict(), sa.service_endpoint,
                                cons_wallet.address, pub_wallet),
        "algorithmDid":
        alg_ddo.did,
        "algorithmDataToken":
        alg_data_token,
        "algorithmTransferTxId":
        alg_tx_id,
    })

    # Start compute using invalid signature (withOUT nonce), should fail
    msg = f"{cons_wallet.address}{did}"
    _hash = add_ethereum_prefix_and_hash_msg(msg)
    payload["signature"] = Web3Helper.sign_hash(_hash, cons_wallet)
    compute_endpoint = BaseURLs.ASSETS_URL + "/compute"
    response = client.post(compute_endpoint,
                           data=json.dumps(payload),
                           content_type="application/json")

    assert response.status_code == 400, f"{response.data}"

    # Start compute with valid signature
    payload["signature"] = signature
    response = client.post(compute_endpoint,
                           data=json.dumps(payload),
                           content_type="application/json")
    assert response.status == "200 OK", f"start compute job failed: {response.data}"
    job_info = response.json[0]
    print(f"got response from starting compute job: {job_info}")
    job_id = job_info.get("jobId", "")

    nonce = get_nonce(client, cons_wallet.address)
    msg = f"{cons_wallet.address}{job_id}{did}{nonce}"
    _hash = add_ethereum_prefix_and_hash_msg(msg)
    signature = Web3Helper.sign_hash(_hash, cons_wallet)

    payload = dict({
        "signature": signature,
        "documentId": did,
        "consumerAddress": cons_wallet.address,
        "jobId": job_id,
    })

    job_info = get_compute_job_info(client, compute_endpoint, payload)
    assert job_info, f"Failed to get job info for jobId {job_id}"
    print(f"got info for compute job {job_id}: {job_info}")
    assert job_info["statusText"] in get_possible_compute_job_status_text()

    # get compute job status without signature should return limited status info
    payload.pop("signature")
    job_info = get_compute_job_info(client, compute_endpoint, payload)
    assert job_info, f"Failed to get job status without signature: payload={payload}"
    assert "owner" not in job_info, "owner should not be in this status response"
    assert (
        "resultsUrl"
        not in job_info), "resultsUrl should not be in this status response"
    assert ("algorithmLogUrl" not in job_info
            ), "algorithmLogUrl should not be in this status response"
    assert (
        "resultsDid"
        not in job_info), "resultsDid should not be in this status response"

    payload["signature"] = ""
    job_info = get_compute_job_info(client, compute_endpoint, payload)
    assert job_info, f"Failed to get job status without signature: payload={payload}"
    assert "owner" not in job_info, "owner should not be in this status response"
    assert (
        "resultsUrl"
        not in job_info), "resultsUrl should not be in this status response"
    assert ("algorithmLogUrl" not in job_info
            ), "algorithmLogUrl should not be in this status response"
    assert (
        "resultsDid"
        not in job_info), "resultsDid should not be in this status response"
def test_compute(client):

    pub_wallet = get_publisher_wallet()
    cons_wallet = get_consumer_wallet()

    # publish a dataset asset
    dataset_ddo_w_compute_service = get_dataset_ddo_with_compute_service(client, pub_wallet)
    did = dataset_ddo_w_compute_service.did
    ddo = dataset_ddo_w_compute_service
    data_token = dataset_ddo_w_compute_service.data_token_address
    dt_contract = DataToken(data_token)
    mint_tokens_and_wait(dt_contract, cons_wallet, pub_wallet)

    # publish an algorithm asset (asset with metadata of type `algorithm`)
    alg_ddo = get_algorithm_ddo(client, cons_wallet)
    alg_data_token = alg_ddo.as_dictionary()['dataToken']
    alg_dt_contract = DataToken(alg_data_token)
    mint_tokens_and_wait(alg_dt_contract, cons_wallet, cons_wallet)

    sa = ServiceAgreement.from_ddo(ServiceTypes.CLOUD_COMPUTE, dataset_ddo_w_compute_service)
    tx_id = send_order(client, ddo, dt_contract, sa, cons_wallet)

    alg_service = ServiceAgreement.from_ddo(ServiceTypes.ASSET_ACCESS, alg_ddo)
    alg_tx_id = send_order(client, alg_ddo, alg_dt_contract, alg_service, cons_wallet)

    nonce = get_nonce(client, cons_wallet.address)
    # prepare consumer signature on did
    msg = f'{cons_wallet.address}{did}{str(nonce)}'
    _hash = add_ethereum_prefix_and_hash_msg(msg)
    signature = Web3Helper.sign_hash(_hash, cons_wallet)

    # Start the compute job
    payload = dict({
        'signature': signature,
        'documentId': did,
        'serviceId': sa.index,
        'serviceType': sa.type,
        'consumerAddress': cons_wallet.address,
        'transferTxId': tx_id,
        'dataToken': data_token,
        'output': build_stage_output_dict(dict(), dataset_ddo_w_compute_service, cons_wallet.address, pub_wallet),
        'algorithmDid': alg_ddo.did,
        'algorithmMeta': {},
        'algorithmDataToken': alg_data_token,
        'algorithmTransferTxId': alg_tx_id
    })

    # Start compute using invalid signature (withOUT nonce), should fail
    msg = f'{cons_wallet.address}{did}'
    _hash = add_ethereum_prefix_and_hash_msg(msg)
    payload['signature'] = Web3Helper.sign_hash(_hash, cons_wallet)
    compute_endpoint = BaseURLs.ASSETS_URL + '/compute'
    response = client.post(
        compute_endpoint,
        data=json.dumps(payload),
        content_type='application/json'
    )

    assert response.status_code == 401, f'{response.data}'

    # Start compute with valid signature
    payload['signature'] = signature
    response = client.post(
        compute_endpoint,
        data=json.dumps(payload),
        content_type='application/json'
    )
    assert response.status == '200 OK', f'start compute job failed: {response.data}'
    job_info = response.json[0]
    print(f'got response from starting compute job: {job_info}')
    job_id = job_info.get('jobId', '')

    nonce = get_nonce(client, cons_wallet.address)
    msg = f'{cons_wallet.address}{job_id}{did}{nonce}'
    _hash = add_ethereum_prefix_and_hash_msg(msg)
    signature = Web3Helper.sign_hash(_hash, cons_wallet)

    payload = dict({
        'signature': signature,
        'documentId': did,
        'consumerAddress': cons_wallet.address,
        'jobId': job_id,
    })

    job_info = get_compute_job_info(client, compute_endpoint, payload)
    assert job_info, f'Failed to get job info for jobId {job_id}'
    print(f'got info for compute job {job_id}: {job_info}')
    assert job_info['statusText'] in get_possible_compute_job_status_text()

    # get compute job status without signature should return limited status info
    payload.pop('signature')
    job_info = get_compute_job_info(client, compute_endpoint, payload)
    assert job_info, f'Failed to get job status without signature: payload={payload}'
    assert 'owner' not in job_info, 'owner should not be in this status response'
    assert 'resultsUrl' not in job_info, 'resultsUrl should not be in this status response'
    assert 'algorithmLogUrl' not in job_info, 'algorithmLogUrl should not be in this status response'
    assert 'resultsDid' not in job_info, 'resultsDid should not be in this status response'

    payload['signature'] = ''
    job_info = get_compute_job_info(client, compute_endpoint, payload)
    assert job_info, f'Failed to get job status without signature: payload={payload}'
    assert 'owner' not in job_info, 'owner should not be in this status response'
    assert 'resultsUrl' not in job_info, 'resultsUrl should not be in this status response'
    assert 'algorithmLogUrl' not in job_info, 'algorithmLogUrl should not be in this status response'
    assert 'resultsDid' not in job_info, 'resultsDid should not be in this status response'
Exemple #10
0
def test_fails(client):
    provider_wallet = get_provider_wallet()
    consumer_address = get_consumer_wallet().address
    pub_wallet = get_publisher_wallet()

    (
        dataset,
        did,
        tx_id,
        sa,
        _,
        alg_ddo,
        alg_data_token,
        _,
        alg_tx_id,
    ) = build_and_send_ddo_with_compute_service(client)

    # output key is invalid
    data = {
        "documentId": did,
        "transferTxId": tx_id,
        "serviceId": sa.index,
        "output": "this can not be decoded",
        "algorithmDid": alg_ddo.did,
        "algorithmDataToken": alg_data_token,
        "algorithmTransferTxId": alg_tx_id,
    }

    validator = WorkflowValidator(consumer_address, provider_wallet, data)
    assert validator.validate() is False
    assert validator.error == "Output is invalid or can not be decoded."

    # algorithmDid is not actually an algorithm
    data = {
        "documentId":
        did,
        "transferTxId":
        tx_id,
        "serviceId":
        sa.index,
        "output":
        build_stage_output_dict(dict(), sa.service_endpoint, consumer_address,
                                pub_wallet),
        "algorithmDid":
        did,
        "algorithmDataToken":
        alg_data_token,
        "algorithmTransferTxId":
        alg_tx_id,
    }

    validator = WorkflowValidator(consumer_address, provider_wallet, data)
    assert validator.validate() is False
    assert validator.error == f"DID {did} is not a valid algorithm"

    valid_output = build_stage_output_dict(dict(), sa.service_endpoint,
                                           consumer_address, pub_wallet)

    # algorithmMeta doesn't contain 'url' or 'rawcode'
    data = {
        "documentId": did,
        "transferTxId": tx_id,
        "serviceId": sa.index,
        "output": valid_output,
        "algorithmMeta": {},
    }

    validator = WorkflowValidator(consumer_address, provider_wallet, data)
    assert validator.validate() is False
    assert (
        validator.error ==
        "algorithmMeta must define one of `url` or `rawcode` or `remote`, but all seem missing."
    )

    # algorithmMeta container is empty
    data = {
        "documentId": did,
        "transferTxId": tx_id,
        "serviceId": sa.index,
        "output": valid_output,
        "algorithmMeta": {
            "rawcode": "console.log('Hello world'!)",
            "format": "docker-image",
            "version": "0.1",
            "container": {},
        },
    }

    validator = WorkflowValidator(consumer_address, provider_wallet, data)
    assert validator.validate() is False
    assert (
        validator.error ==
        "algorithm `container` must specify values for all of entrypoint, image and tag."
    )

    # algorithmMeta container is missing image
    data = {
        "documentId": did,
        "transferTxId": tx_id,
        "serviceId": sa.index,
        "output": valid_output,
        "algorithmMeta": {
            "rawcode": "console.log('Hello world'!)",
            "format": "docker-image",
            "version": "0.1",
            "container": {
                "entrypoint": "node $ALGO",
                "tag": "10"
            },
        },
    }

    validator = WorkflowValidator(consumer_address, provider_wallet, data)
    assert validator.validate() is False
    assert (
        validator.error ==
        "algorithm `container` must specify values for all of entrypoint, image and tag."
    )

    # Additional Input validations ###
    data = {
        "documentId": did,
        "transferTxId": tx_id,
        "serviceId": sa.index,
        "output": valid_output,
        "algorithmDid": alg_ddo.did,
        "algorithmDataToken": alg_data_token,
        "algorithmTransferTxId": alg_tx_id,
        "additionalInputs": "",
    }

    validator = WorkflowValidator(consumer_address, provider_wallet, data)
    assert validator.validate() is True

    # additional input is invalid
    data = {
        "documentId": did,
        "transferTxId": tx_id,
        "serviceId": sa.index,
        "output": valid_output,
        "algorithmDid": alg_ddo.did,
        "algorithmDataToken": alg_data_token,
        "algorithmTransferTxId": alg_tx_id,
        "additionalInputs": "i can not be decoded in json!",
    }

    validator = WorkflowValidator(consumer_address, provider_wallet, data)
    assert validator.validate() is False
    assert validator.error == "Additional input is invalid or can not be decoded."

    # Missing did in additional input
    data = {
        "documentId": did,
        "transferTxId": tx_id,
        "serviceId": sa.index,
        "output": valid_output,
        "algorithmDid": alg_ddo.did,
        "algorithmDataToken": alg_data_token,
        "algorithmTransferTxId": alg_tx_id,
        "additionalInputs": [{
            "transferTxId": tx_id,
            "serviceId": sa.index
        }],
    }

    validator = WorkflowValidator(consumer_address, provider_wallet, data)
    assert validator.validate() is False
    assert validator.error == "Error in input at index 1: No documentId in input item."

    # Did is not valid
    data = {
        "documentId":
        did,
        "transferTxId":
        tx_id,
        "serviceId":
        sa.index,
        "output":
        valid_output,
        "algorithmDid":
        alg_ddo.did,
        "algorithmDataToken":
        alg_data_token,
        "algorithmTransferTxId":
        alg_tx_id,
        "additionalInputs": [{
            "documentId": "i am not a did",
            "transferTxId": tx_id,
            "serviceId": sa.index,
        }],
    }

    validator = WorkflowValidator(consumer_address, provider_wallet, data)
    assert validator.validate() is False
    assert (
        validator.error ==
        "Error in input at index 1: Asset for did i am not a did not found.")

    # Service is not compute, nor access
    other_service = [
        s for s in dataset.services if s.type not in
        [ServiceTypes.CLOUD_COMPUTE, ServiceTypes.ASSET_ACCESS]
    ][0]
    data = {
        "documentId":
        did,
        "transferTxId":
        tx_id,
        "serviceId":
        sa.index,
        "output":
        valid_output,
        "algorithmDid":
        alg_ddo.did,
        "algorithmDataToken":
        alg_data_token,
        "algorithmTransferTxId":
        alg_tx_id,
        "additionalInputs": [{
            "documentId": did,
            "transferTxId": tx_id,
            "serviceId": other_service.index
        }],
    }

    validator = WorkflowValidator(consumer_address, provider_wallet, data)
    assert validator.validate() is False
    assert (
        validator.error ==
        "Error in input at index 1: Services in input can only be access or compute."
    )

    # Additional input has other trusted algs
    (
        _,
        trust_did,
        trust_tx_id,
        trust_sa,
        _,
        _,
        _,
        _,
        _,
    ) = build_and_send_ddo_with_compute_service(
        client, asset_type="specific_algo_dids")

    data = {
        "documentId":
        did,
        "transferTxId":
        tx_id,
        "serviceId":
        sa.index,
        "output":
        valid_output,
        "algorithmDid":
        alg_ddo.did,
        "algorithmDataToken":
        alg_data_token,
        "algorithmTransferTxId":
        alg_tx_id,
        "additionalInputs": [{
            "documentId": trust_did,
            "transferTxId": trust_tx_id,
            "serviceId": trust_sa.index,
        }],
    }

    validator = WorkflowValidator(consumer_address, provider_wallet, data)
    assert validator.validate() is False
    assert (
        validator.error ==
        f"Error in input at index 1: this algorithm did {alg_ddo.did} is not trusted."
    )
Exemple #11
0
def test_passes(client):
    provider_wallet = get_provider_wallet()
    consumer_address = get_consumer_wallet().address
    pub_wallet = get_publisher_wallet()

    (
        _,
        did,
        tx_id,
        sa,
        _,
        alg_ddo,
        alg_data_token,
        _,
        alg_tx_id,
    ) = build_and_send_ddo_with_compute_service(client)

    data = {
        "documentId":
        did,
        "serviceId":
        sa.index,
        "transferTxId":
        tx_id,
        "output":
        build_stage_output_dict(dict(), sa.service_endpoint, consumer_address,
                                pub_wallet),
        "algorithmDid":
        alg_ddo.did,
        "algorithmDataToken":
        alg_data_token,
        "algorithmTransferTxId":
        alg_tx_id,
    }

    validator = WorkflowValidator(consumer_address, provider_wallet, data)
    assert validator.validate() is True

    data = {
        "documentId":
        did,
        "serviceId":
        sa.index,
        "transferTxId":
        tx_id,
        "output":
        build_stage_output_dict(dict(), sa.service_endpoint, consumer_address,
                                pub_wallet),
        "algorithmMeta": {
            "rawcode": "console.log('Hello world'!)",
            "format": "docker-image",
            "version": "0.1",
            "container": {
                "entrypoint": "node $ALGO",
                "image": "node",
                "tag": "10"
            },
        },
    }
    validator = WorkflowValidator(consumer_address, provider_wallet, data)
    assert validator.validate() is True