Skip to content
This repository has been archived by the owner on Sep 30, 2024. It is now read-only.

Commit

Permalink
Merge pull request #39 from nevermined-io/feature/multiple_rewards
Browse files Browse the repository at this point in the history
Implementation of multiple receivers for rewards distribution
  • Loading branch information
aaitor authored Feb 11, 2021
2 parents edc5fa9 + 91fd3e0 commit 7ff1a6f
Show file tree
Hide file tree
Showing 9 changed files with 68 additions and 32 deletions.
7 changes: 6 additions & 1 deletion examples/compute_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ def compute_example(verbose=False):
keeper = Keeper.get_instance()
provider = "0x068Ed00cF0441e4829D9784fCBe7b9e26D4BD8d0"

asset_rewards = {
"_amounts": ["10", "2"],
"_receivers": ["0x00Bd138aBD70e2F00903268F3Db08f2D25677C9e", "0x068ed00cf0441e4829d9784fcbe7b9e26d4bd8d0"]
}

# Setup accounts
acc = Account(
Web3.toChecksumAddress(PROVIDER_ADDRESS), PROVIDER_PASSWORD, PROVIDER_KEYFILE
Expand All @@ -70,7 +75,7 @@ def compute_example(verbose=False):
# Publish compute
example_metadata.compute_ddo["main"]["dateCreated"] = next(date_created)
ddo_compute = nevermined.assets.create_compute(
example_metadata.metadata, provider_acc, providers=[provider]
example_metadata.metadata, provider_acc, asset_rewards, providers=[provider]
)
assert ddo_compute is not None, "Creating compute asset on-chain failed."
print(
Expand Down
22 changes: 14 additions & 8 deletions nevermined_sdk_py/nevermined/assets.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def _get_secret_store(self, account):
def create(self, metadata, publisher_account,
service_descriptors=None, providers=None,
authorization_type=ServiceAuthorizationTypes.PSK_RSA, use_secret_store=False,
activity_id=None, attributes=None):
activity_id=None, attributes=None, asset_rewards={"_amounts": [], "_receivers": []}):
"""
Register an asset in both the keeper's DIDRegistry (on-chain) and in the Metadata store.
Expand All @@ -72,6 +72,7 @@ def create(self, metadata, publisher_account,
encrypting urls (Uses Gateway provider service if set to False)
:param activity_id: identifier of the activity creating the new entity
:param attributes: attributes associated with the action
:param asset_rewards: rewards distribution including the amounts and the receivers
:return: DDO instance
"""
assert isinstance(metadata, dict), f'Expected metadata of type dict, got {type(metadata)}'
Expand All @@ -87,7 +88,7 @@ def create(self, metadata, publisher_account,
ddo_service_endpoint)
if metadata_copy['main']['type'] == 'dataset' or metadata_copy['main'][
'type'] == 'algorithm':
access_service_attributes = self._build_access(metadata_copy, publisher_account)
access_service_attributes = self._build_access(metadata_copy, publisher_account, asset_rewards)
if not service_descriptors:
if authorization_type == ServiceAuthorizationTypes.PSK_RSA:
service_descriptors = [ServiceDescriptor.authorization_service_descriptor(
Expand Down Expand Up @@ -259,7 +260,7 @@ def create(self, metadata, publisher_account,
return None
return ddo

def create_compute(self, metadata, publisher_account,
def create_compute(self, metadata, publisher_account, asset_rewards={"_amounts": [], "_receivers": []},
service_descriptors=None, providers=None,
authorization_type=ServiceAuthorizationTypes.PSK_RSA, use_secret_store=False):
"""
Expand All @@ -268,6 +269,7 @@ def create_compute(self, metadata, publisher_account,
:param metadata: dict conforming to the Metadata accepted by Nevermined Protocol.
:param publisher_account: Account of the publisher registering this asset
:param asset_rewards: Asset rewards distribution including amounts and receivers
:param service_descriptors: list of ServiceDescriptor tuples of length 2.
The first item must be one of ServiceTypes and the second
item is a dict of parameters and values required by the service
Expand All @@ -284,7 +286,7 @@ def create_compute(self, metadata, publisher_account,
metadata_copy = copy.deepcopy(metadata)
gateway = GatewayProvider.get_gateway()

compute_service_attributes = self._build_compute(metadata_copy, publisher_account)
compute_service_attributes = self._build_compute(metadata_copy, publisher_account, asset_rewards)
service_descriptor = ServiceDescriptor.compute_service_descriptor(
compute_service_attributes, gateway.get_execute_endpoint(self._config))

Expand Down Expand Up @@ -623,23 +625,27 @@ def _build_authorization(authorization_type, public_key=None, threshold=None):
return authorization

@staticmethod
def _build_access(metadata, publisher_account):
def _build_access(metadata, publisher_account, asset_rewards):
return {"main": {
"name": "dataAssetAccessServiceAgreement",
"creator": publisher_account.address,
"price": metadata[MetadataMain.KEY]['price'],
"timeout": 3600,
"datePublished": metadata[MetadataMain.KEY]['dateCreated']
"datePublished": metadata[MetadataMain.KEY]['dateCreated'],
"_amounts": asset_rewards["_amounts"],
"_receivers": asset_rewards["_receivers"]
}}

def _build_compute(self, metadata, publisher_account):
def _build_compute(self, metadata, publisher_account, asset_rewards):
return {"main": {
"name": "dataAssetComputeServiceAgreement",
"creator": publisher_account.address,
"datePublished": metadata[MetadataMain.KEY]['dateCreated'],
"price": metadata[MetadataMain.KEY]['price'],
"timeout": 86400,
"provider": self._build_provider_config()
"provider": self._build_provider_config(),
"_amounts": asset_rewards["_amounts"],
"_receivers": asset_rewards["_receivers"]
}
}

Expand Down
26 changes: 14 additions & 12 deletions nevermined_sdk_py/nevermined/conditions.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from eth_utils import add_0x_prefix
from contracts_lib_py.web3_provider import Web3Provider
from common_utils_py.did import did_to_id
from common_utils_py.utils.utilities import to_checksum_addresses
from eth_utils import add_0x_prefix


class Conditions:
Expand Down Expand Up @@ -42,13 +42,14 @@ def grant_access(self, agreement_id, did, grantee_address, account):
receipt = self._keeper.access_secret_store_condition.get_tx_receipt(tx_hash)
return bool(receipt and receipt.status == 1)

def release_reward(self, agreement_id, amount, account):
def release_reward(self, agreement_id, amounts, receivers, account):
"""
Release reward condition.
:param agreement_id: id of the agreement, hex str
:param amount: Amount of tokens, int
:param account: Account
:param amounts: Amounts of tokens, int[]
:param receivers: Token receivers, str[]
:param account sending the transaction
:return:
"""
agreement_values = self._keeper.agreement_manager.get_agreement(agreement_id)
Expand All @@ -58,23 +59,24 @@ def release_reward(self, agreement_id, amount, account):
access_id, lock_id = agreement_values.condition_ids[:2]
tx_hash = self._keeper.escrow_reward_condition.fulfill(
agreement_id,
amount,
Web3Provider.get_web3().toChecksumAddress(owner),
consumer,
amounts,
to_checksum_addresses(receivers),
owner,
lock_id,
access_id,
account
)
receipt = self._keeper.escrow_reward_condition.get_tx_receipt(tx_hash)
return bool(receipt and receipt.status == 1)

def refund_reward(self, agreement_id, amount, account):
def refund_reward(self, agreement_id, amounts, receivers, account):
"""
Refund reaward condition.
:param agreement_id: id of the agreement, hex str
:param amount: Amount of tokens, int
:param account: Account
:param amounts: Amounts of tokens, int[]
:param receivers: Token receivers, str[]
:param account sending the transaction
:return:
"""
return self.release_reward(agreement_id, amount, account)
return self.release_reward(agreement_id, amounts, receivers, account)
8 changes: 4 additions & 4 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
'pyopenssl',
'PyJWT', # not jwt
'PyYAML==4.2b4',
'common-utils-py==0.4.2',
'contracts-lib-py==0.5.3',
'common-utils-py==0.4.6',
'contracts-lib-py==0.5.5',
'nevermined-secret-store==0.1.0',
'requests~=2.21.0',
'deprecated',
Expand Down Expand Up @@ -65,7 +65,7 @@
author="nevermined-io",
author_email='root@nevermined.io',
classifiers=[
'Development Status :: 2 - Pre-Alpha',
'Development Status :: 5 - Production/Stable',
'Intended Audience :: Developers',
'License :: OSI Approved :: Apache Software License',
'Natural Language :: English',
Expand All @@ -89,6 +89,6 @@
test_suite='tests',
tests_require=test_requirements,
url='https://github.com/nevermined-io/sdk-py',
version='0.7.0',
version='0.8.0',
zip_safe=False,
)
3 changes: 3 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from common_utils_py.agreements.service_types import ServiceTypes
from common_utils_py.did import DID
from common_utils_py.metadata.metadata import Metadata
from common_utils_py.utils.utilities import generate_prefixed_id
from contracts_lib_py.contract_handler import ContractHandler
from contracts_lib_py.web3_provider import Web3Provider

Expand Down Expand Up @@ -149,6 +150,8 @@ def setup_agreements_enviroment(ddo_sample):
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),
Expand Down
16 changes: 12 additions & 4 deletions tests/nevermined/test_agreements.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from common_utils_py.agreements.service_agreement import ServiceAgreement
from common_utils_py.agreements.service_types import ServiceTypes, ServiceTypesIndices
from common_utils_py.utils.utilities import to_checksum_addresses

from nevermined_sdk_py.gateway.gateway import Gateway
from nevermined_sdk_py.nevermined.keeper import NeverminedKeeper as Keeper
Expand Down Expand Up @@ -70,9 +71,12 @@ def test_sign_agreement(publisher_instance, consumer_instance, registered_ddo):
assert event, 'no event for AccessSecretStoreCondition.Fulfilled'

# Fulfill escrow_reward_condition
amounts = list(map(int, service_agreement.get_param_value_by_name('_amounts')))
receivers = to_checksum_addresses(service_agreement.get_param_value_by_name('_receivers'))

tx_hash = keeper.escrow_reward_condition.fulfill(
agreement_id, price, publisher_acc.address,
consumer_acc.address, lock_cond_id,
agreement_id, amounts, receivers,
publisher_acc.address, lock_cond_id,
access_cond_id, publisher_acc
)
keeper.escrow_reward_condition.get_tx_receipt(tx_hash)
Expand Down Expand Up @@ -161,9 +165,13 @@ def test_agreement_status(setup_agreements_enviroment, agreements):
"escrowReward": 1
}
}

amounts = list(map(int, service_agreement.get_param_value_by_name('_amounts')))
receivers = to_checksum_addresses(service_agreement.get_param_value_by_name('_receivers'))

tx_hash = keeper.escrow_reward_condition.fulfill(
agreement_id, price, publisher_acc.address,
consumer_acc.address, lock_cond_id,
agreement_id, amounts, to_checksum_addresses(receivers),
publisher_acc.address, lock_cond_id,
access_cond_id, publisher_acc
)
keeper.escrow_reward_condition.get_tx_receipt(tx_hash)
Expand Down
6 changes: 5 additions & 1 deletion tests/nevermined/test_assets.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,11 @@ def test_assets_workflow(publisher_instance, workflow_ddo):

def test_assets_compute(publisher_instance, metadata):
publisher = publisher_instance.main_account
ddo = publisher_instance.assets.create_compute(metadata, publisher)
asset_rewards = {
"_amounts": ["10", "2"],
"_receivers": ["0x00Bd138aBD70e2F00903268F3Db08f2D25677C9e", "0x068ed00cf0441e4829d9784fcbe7b9e26d4bd8d0"]
}
ddo = publisher_instance.assets.create_compute(metadata, publisher, asset_rewards=asset_rewards)
assert ddo
publisher_instance.assets.retire(ddo.did)

Expand Down
6 changes: 5 additions & 1 deletion tests/nevermined/test_buy_asset.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ def test_buy_asset(publisher_instance_no_init, consumer_instance_no_init):
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)

Expand All @@ -68,8 +69,11 @@ def test_buy_asset(publisher_instance_no_init, consumer_instance_no_init):
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, sa.get_price(), pub_acc)
agreement_id, amounts, receivers, pub_acc)

assert consumer_instance_no_init.assets.access(
agreement_id,
Expand Down
6 changes: 5 additions & 1 deletion tests/resources/helper_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,12 @@ def get_computing_ddo():

def get_registered_ddo(nevermined_instance, account):
metadata = get_metadata()
asset_rewards = {
"_amounts": ["10", "2"],
"_receivers": ["0x00Bd138aBD70e2F00903268F3Db08f2D25677C9e", "0x068ed00cf0441e4829d9784fcbe7b9e26d4bd8d0"]
}
metadata['main']['files'][0]['checksum'] = str(uuid.uuid4())
ddo = nevermined_instance.assets.create(metadata, account)
ddo = nevermined_instance.assets.create(metadata, account, asset_rewards=asset_rewards)
return ddo


Expand Down

0 comments on commit 7ff1a6f

Please sign in to comment.