dkg 1.1.2__py3-none-any.whl → 8.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. dkg/asset.py +589 -683
  2. dkg/constants.py +102 -40
  3. dkg/data/interfaces/AskStorage.json +366 -0
  4. dkg/data/interfaces/Chronos.json +202 -0
  5. dkg/data/interfaces/Hub.json +294 -2
  6. dkg/data/interfaces/IdentityStorage.json +400 -0
  7. dkg/data/interfaces/KnowledgeCollection.json +610 -0
  8. dkg/data/interfaces/KnowledgeCollectionStorage.json +2312 -0
  9. dkg/data/interfaces/Paranet.json +656 -135
  10. dkg/data/interfaces/ParanetIncentivesPoolFactory.json +18 -7
  11. dkg/data/interfaces/ParanetKnowledgeMinersRegistry.json +20 -4
  12. dkg/data/interfaces/{ParanetNeurowebIncentivesPool.json → ParanetNeuroIncentivesPool.json} +27 -58
  13. dkg/data/interfaces/ParanetsRegistry.json +844 -36
  14. dkg/data/interfaces/Token.json +146 -17
  15. dkg/dataclasses.py +13 -4
  16. dkg/exceptions.py +1 -0
  17. dkg/graph.py +55 -24
  18. dkg/main.py +18 -2
  19. dkg/network.py +2 -2
  20. dkg/node.py +7 -0
  21. dkg/paranet.py +356 -111
  22. dkg/providers/blockchain.py +23 -24
  23. dkg/providers/node_http.py +6 -13
  24. dkg/services/input_service.py +183 -0
  25. dkg/services/node_service.py +164 -0
  26. dkg/types/__init__.py +15 -3
  27. dkg/types/general.py +15 -8
  28. dkg/utils/blockchain_request.py +188 -64
  29. dkg/utils/knowledge_asset_tools.py +5 -0
  30. dkg/utils/knowledge_collection_tools.py +236 -0
  31. dkg/utils/merkle.py +1 -1
  32. dkg/utils/node_request.py +33 -33
  33. dkg/utils/rdf.py +10 -6
  34. dkg/utils/string_transformations.py +1 -0
  35. {dkg-1.1.2.dist-info → dkg-8.0.0.dist-info}/METADATA +36 -26
  36. dkg-8.0.0.dist-info/RECORD +56 -0
  37. {dkg-1.1.2.dist-info → dkg-8.0.0.dist-info}/WHEEL +1 -1
  38. dkg/data/interfaces/AssertionStorage.json +0 -229
  39. dkg/data/interfaces/ContentAsset.json +0 -801
  40. dkg/data/interfaces/ContentAssetStorage.json +0 -782
  41. dkg/data/interfaces/ServiceAgreementStorageProxy.json +0 -1314
  42. dkg/data/interfaces/UnfinalizedStateStorage.json +0 -171
  43. dkg-1.1.2.dist-info/RECORD +0 -52
  44. {dkg-1.1.2.dist-info → dkg-8.0.0.dist-info}/LICENSE +0 -0
  45. {dkg-1.1.2.dist-info → dkg-8.0.0.dist-info}/NOTICE +0 -0
@@ -17,13 +17,14 @@
17
17
 
18
18
  import json
19
19
  import os
20
+ from dotenv import load_dotenv
20
21
  from collections import namedtuple
21
22
  from functools import wraps
22
23
  from pathlib import Path
23
24
  from typing import Any, Type
24
25
 
25
26
  import requests
26
- from dkg.constants import BLOCKCHAINS, DEFAULT_GAS_PRICE_GWEI
27
+ from dkg.constants import BLOCKCHAINS
27
28
  from dkg.exceptions import (
28
29
  AccountMissing,
29
30
  EnvironmentNotSupported,
@@ -32,12 +33,13 @@ from dkg.exceptions import (
32
33
  )
33
34
  from dkg.types import URI, Address, DataHexStr, Environment, Wei
34
35
  from eth_account.signers.local import LocalAccount
36
+ from eth_typing import ABI, ABIFunction
35
37
  from web3 import Web3
36
38
  from web3.contract import Contract
37
39
  from web3.contract.contract import ContractFunction
38
40
  from web3.logs import DISCARD
39
- from web3.middleware import construct_sign_and_send_raw_middleware
40
- from web3.types import ABI, ABIFunction, TxReceipt
41
+ from web3.middleware import SignAndSendRawMiddlewareBuilder
42
+ from web3.types import TxReceipt
41
43
 
42
44
 
43
45
  class BlockchainProvider:
@@ -48,7 +50,6 @@ class BlockchainProvider:
48
50
  environment: Environment,
49
51
  blockchain_id: str,
50
52
  rpc_uri: URI | None = None,
51
- private_key: DataHexStr | None = None,
52
53
  gas_price: Wei | None = None,
53
54
  verify: bool = True,
54
55
  ):
@@ -105,11 +106,9 @@ class BlockchainProvider:
105
106
  }
106
107
  self._init_contracts()
107
108
 
108
- if (
109
- private_key is not None
110
- or (private_key_env := os.environ.get("PRIVATE_KEY", None)) is not None
111
- ):
112
- self.set_account(private_key or private_key_env)
109
+ load_dotenv()
110
+ if private_key := os.environ.get("PRIVATE_KEY"):
111
+ self.set_account(private_key)
113
112
 
114
113
  def make_json_rpc_request(self, endpoint: str, args: dict[str, Any] = {}) -> Any:
115
114
  web3_method = getattr(self.w3.eth, endpoint)
@@ -181,13 +180,15 @@ class BlockchainProvider:
181
180
  "account."
182
181
  )
183
182
 
184
- gas_price = self.gas_price or gas_price or self._get_network_gas_price()
185
-
186
183
  options = {
187
- "gasPrice": gas_price,
188
184
  "gas": gas_limit or contract_function(**args).estimate_gas(),
189
185
  }
190
186
 
187
+ gas_price = self.gas_price or gas_price or self._get_network_gas_price()
188
+
189
+ if gas_price is not None:
190
+ options["gasPrice"] = gas_price
191
+
191
192
  tx_hash = contract_function(**args).transact(options)
192
193
  tx_receipt = self.w3.eth.wait_for_transaction_receipt(tx_hash)
193
194
 
@@ -204,8 +205,9 @@ class BlockchainProvider:
204
205
 
205
206
  def set_account(self, private_key: DataHexStr):
206
207
  self.account: LocalAccount = self.w3.eth.account.from_key(private_key)
207
- self.w3.middleware_onion.add(
208
- construct_sign_and_send_raw_middleware(self.account)
208
+ self.w3.middleware_onion.inject(
209
+ SignAndSendRawMiddlewareBuilder.build(private_key),
210
+ layer=0,
209
211
  )
210
212
  self.w3.eth.default_account = self.account.address
211
213
 
@@ -213,12 +215,6 @@ class BlockchainProvider:
213
215
  if self.environment == "development":
214
216
  return None
215
217
 
216
- blockchain_name, _ = self.blockchain_id.split(":")
217
-
218
- default_gas_price = self.w3.to_wei(
219
- DEFAULT_GAS_PRICE_GWEI[blockchain_name], "gwei"
220
- )
221
-
222
218
  def fetch_gas_price(oracle_url: str) -> Wei | None:
223
219
  try:
224
220
  response = requests.get(oracle_url)
@@ -244,7 +240,7 @@ class BlockchainProvider:
244
240
  if gas_price is not None:
245
241
  return gas_price
246
242
 
247
- return default_gas_price
243
+ return None
248
244
 
249
245
  def _init_contracts(self):
250
246
  for contract in self.abi.keys():
@@ -262,11 +258,14 @@ class BlockchainProvider:
262
258
  ):
263
259
  self.contracts[contract] = self.w3.eth.contract(
264
260
  address=(
265
- self.contracts["Hub"].functions.getContractAddress(contract).call()
266
- if not contract.endswith("AssetStorage")
267
- else self.contracts["Hub"]
261
+ self.contracts["Hub"]
268
262
  .functions.getAssetStorageAddress(contract)
269
263
  .call()
264
+ if contract.endswith("AssetStorage")
265
+ or contract.endswith("CollectionStorage")
266
+ else self.contracts["Hub"]
267
+ .functions.getContractAddress(contract)
268
+ .call()
270
269
  ),
271
270
  abi=self.abi[contract],
272
271
  decode_tuples=True,
@@ -28,15 +28,11 @@ class NodeHTTPProvider:
28
28
  def __init__(
29
29
  self,
30
30
  endpoint_uri: URI | str,
31
+ api_version: str = "v1",
31
32
  auth_token: str | None = None,
32
- api_version: str = "v0",
33
33
  ):
34
- self.endpoint_uri = URI(endpoint_uri)
35
- self.auth_token = auth_token
36
- self.api_version = api_version
37
-
38
- def get_full_url(self, path: str) -> str:
39
- return f"{self.endpoint_uri}/{self.api_version}/{path}"
34
+ self.url = f"{URI(endpoint_uri)}/{api_version}"
35
+ self.headers = {"Authorization": f"Bearer {auth_token}"} if auth_token else {}
40
36
 
41
37
  def make_request(
42
38
  self,
@@ -45,16 +41,13 @@ class NodeHTTPProvider:
45
41
  params: dict[str, Any] = {},
46
42
  data: dict[str, Any] = {},
47
43
  ) -> NodeResponseDict:
48
- url = self.get_full_url(path)
49
- headers = (
50
- {"Authorization": f"Bearer {self.auth_token}"} if self.auth_token else {}
51
- )
44
+ url = f"{self.url}/{path}"
52
45
 
53
46
  try:
54
47
  if method == HTTPRequestMethod.GET:
55
- response = requests.get(url, params=params, headers=headers)
48
+ response = requests.get(url, params=params, headers=self.headers)
56
49
  elif method == HTTPRequestMethod.POST:
57
- response = requests.post(url, json=data, headers=headers)
50
+ response = requests.post(url, json=data, headers=self.headers)
58
51
  else:
59
52
  raise HTTPRequestMethodNotSupported(
60
53
  f"{method.name} method isn't supported"
@@ -0,0 +1,183 @@
1
+ from dkg.constants import (
2
+ DefaultParameters,
3
+ ZERO_ADDRESS,
4
+ DEFAULT_PROXIMITY_SCORE_FUNCTIONS_PAIR_IDS,
5
+ )
6
+
7
+
8
+ class InputService:
9
+ def __init__(self, manager, config):
10
+ self.manager = manager
11
+ self.config = config
12
+
13
+ def get_asset_get_arguments(self, options):
14
+ return {
15
+ "max_number_of_retries": self.get_max_number_of_retries(options),
16
+ "frequency": self.get_frequency(options),
17
+ "state": self.get_state(options),
18
+ "include_metadata": self.get_include_metadata(options),
19
+ "content_type": self.get_content_type(options),
20
+ "validate": self.get_validate(options),
21
+ "output_format": self.get_output_format(options),
22
+ "hash_function_id": self.get_hash_function_id(options),
23
+ "paranet_ual": self.get_paranet_ual(options),
24
+ "subject_ual": self.get_subject_ual(options),
25
+ }
26
+
27
+ def get_asset_create_arguments(self, options):
28
+ return {
29
+ "max_number_of_retries": self.get_max_number_of_retries(options),
30
+ "frequency": self.get_frequency(options),
31
+ "epochs_num": self.get_epochs_num(options),
32
+ "hash_function_id": self.get_hash_function_id(options),
33
+ "score_function_id": self.get_score_function_id(options),
34
+ "immutable": self.get_immutable(options),
35
+ "token_amount": self.get_token_amount(options),
36
+ "payer": self.get_payer(options),
37
+ "minimum_number_of_finalization_confirmations": self.get_minimum_number_of_finalization_confirmations(
38
+ options
39
+ ),
40
+ "minimum_number_of_node_replications": self.get_minimum_number_of_node_replications(
41
+ options
42
+ ),
43
+ }
44
+
45
+ def get_query_arguments(self, options):
46
+ return {
47
+ "max_number_of_retries": self.get_max_number_of_retries(options),
48
+ "frequency": self.get_frequency(options),
49
+ "paranet_ual": self.get_paranet_ual(options),
50
+ "repository": self.get_repository(options),
51
+ }
52
+
53
+ def get_publish_finality_arguments(self, options):
54
+ return {
55
+ "max_number_of_retries": self.get_max_number_of_retries(options),
56
+ "frequency": self.get_frequency(options),
57
+ "minimum_number_of_finalization_confirmations": self.get_minimum_number_of_finalization_confirmations(
58
+ options
59
+ ),
60
+ }
61
+
62
+ def get_max_number_of_retries(self, options):
63
+ return (
64
+ options.get("max_number_of_retries")
65
+ or self.config.get("max_number_of_retries")
66
+ or DefaultParameters.MAX_NUMBER_OF_RETRIES.value
67
+ )
68
+
69
+ def get_frequency(self, options):
70
+ return (
71
+ options.get("frequency")
72
+ or self.config.get("frequency")
73
+ or DefaultParameters.FREQUENCY.value
74
+ )
75
+
76
+ def get_state(self, options):
77
+ return (
78
+ options.get("state")
79
+ or self.config.get("state")
80
+ or DefaultParameters.STATE.value
81
+ )
82
+
83
+ def get_include_metadata(self, options):
84
+ return (
85
+ options.get("include_metadata")
86
+ or self.config.get("include_metadata")
87
+ or DefaultParameters.INCLUDE_METADATA.value
88
+ )
89
+
90
+ def get_content_type(self, options):
91
+ return (
92
+ options.get("content_type")
93
+ or self.config.get("content_type")
94
+ or DefaultParameters.CONTENT_TYPE.value
95
+ )
96
+
97
+ def get_validate(self, options):
98
+ return (
99
+ options.get("validate")
100
+ or self.config.get("validate")
101
+ or DefaultParameters.VALIDATE.value
102
+ )
103
+
104
+ def get_output_format(self, options):
105
+ return (
106
+ options.get("output_format")
107
+ or self.config.get("output_format")
108
+ or DefaultParameters.OUTPUT_FORMAT.value
109
+ )
110
+
111
+ def get_hash_function_id(self, options):
112
+ return (
113
+ options.get("hash_function_id")
114
+ or self.config.get("hash_function_id")
115
+ or DefaultParameters.HASH_FUNCTION_ID.value
116
+ )
117
+
118
+ def get_paranet_ual(self, options):
119
+ return (
120
+ options.get("paranet_ual")
121
+ or self.config.get("paranet_ual")
122
+ or DefaultParameters.PARANET_UAL.value
123
+ )
124
+
125
+ def get_subject_ual(self, options):
126
+ return (
127
+ options.get("subject_ual")
128
+ or self.config.get("subject_ual")
129
+ or DefaultParameters.GET_SUBJECT_UAL.value
130
+ )
131
+
132
+ def get_epochs_num(self, options):
133
+ return options.get("epochs_num") or self.config.get("epochs_num") or None
134
+
135
+ def get_immutable(self, options):
136
+ return (
137
+ options.get("immutable")
138
+ or self.config.get("immutable")
139
+ or DefaultParameters.IMMUTABLE.value
140
+ )
141
+
142
+ def get_token_amount(self, options):
143
+ return options.get("token_amount") or self.config.get("token_amount") or None
144
+
145
+ def get_payer(self, options):
146
+ return options.get("payer") or self.config.get("payer") or ZERO_ADDRESS
147
+
148
+ def get_minimum_number_of_finalization_confirmations(self, options):
149
+ return (
150
+ options.get("minimum_number_of_finalization_confirmations")
151
+ or self.config.get("minimum_number_of_finalization_confirmations")
152
+ or DefaultParameters.MIN_NUMBER_OF_FINALIZATION_CONFIRMATION.value
153
+ or None
154
+ )
155
+
156
+ def get_minimum_number_of_node_replications(self, options):
157
+ return (
158
+ options.get("minimum_number_of_node_replications")
159
+ or self.config.get("minimum_number_of_node_replications")
160
+ or None
161
+ )
162
+
163
+ def get_score_function_id(self, options):
164
+ environment = (
165
+ options.get("environment")
166
+ or self.config.get("environment")
167
+ or self.manager.blockchain_provider.environment
168
+ or DefaultParameters.ENVIRONMENT.value
169
+ )
170
+ blockchain_name = (
171
+ options.get("blockchain")
172
+ or self.config.get("blockchain")
173
+ or self.manager.blockchain_provider.blockchain_id
174
+ )
175
+
176
+ return DEFAULT_PROXIMITY_SCORE_FUNCTIONS_PAIR_IDS[environment][blockchain_name]
177
+
178
+ def get_repository(self, options):
179
+ return (
180
+ options.get("repository")
181
+ or self.config.get("repository")
182
+ or DefaultParameters.REPOSITORY.value
183
+ )
@@ -0,0 +1,164 @@
1
+ from dkg.manager import DefaultRequestManager
2
+ from dkg.method import Method
3
+ from dkg.module import Module
4
+ import time
5
+ from dkg.utils.decorators import retry
6
+ from dkg.exceptions import (
7
+ OperationNotFinished,
8
+ )
9
+ from dkg.utils.node_request import (
10
+ NodeRequest,
11
+ validate_operation_status,
12
+ )
13
+
14
+
15
+ class NodeService(Module):
16
+ def __init__(self, manager: DefaultRequestManager):
17
+ self.manager = manager
18
+
19
+ _get_operation_result = Method(NodeRequest.get_operation_result)
20
+ _finality_status = Method(NodeRequest.finality_status)
21
+ _ask = Method(NodeRequest.ask)
22
+ _publish = Method(NodeRequest.publish)
23
+ _get = Method(NodeRequest.get)
24
+ _query = Method(NodeRequest.query)
25
+
26
+ def get_operation_result(
27
+ self, operation_id: str, operation: str, max_retries: int, frequency: int
28
+ ):
29
+ @retry(
30
+ catch=OperationNotFinished,
31
+ max_retries=max_retries,
32
+ base_delay=frequency,
33
+ backoff=1,
34
+ )
35
+ def retry_get_operation_result():
36
+ operation_result = self._get_operation_result(
37
+ operation_id=operation_id,
38
+ operation=operation,
39
+ )
40
+ validate_operation_status(operation_result)
41
+
42
+ return operation_result
43
+
44
+ return retry_get_operation_result()
45
+
46
+ def finality_status(
47
+ self,
48
+ ual: str,
49
+ required_confirmations: int,
50
+ max_number_of_retries: int,
51
+ frequency: int,
52
+ ):
53
+ retries = 0
54
+ finality = 0
55
+
56
+ while finality < required_confirmations and retries <= max_number_of_retries:
57
+ if retries > max_number_of_retries:
58
+ raise Exception(
59
+ f"Unable to achieve required confirmations. "
60
+ f"Max number of retries ({max_number_of_retries}) reached."
61
+ )
62
+
63
+ if retries > 0:
64
+ time.sleep(frequency)
65
+
66
+ retries += 1
67
+
68
+ try:
69
+ try:
70
+ response = self._finality_status(ual=ual)
71
+ except Exception as e:
72
+ response = None
73
+ print(f"failed: {e}")
74
+
75
+ if response is not None:
76
+ finality = response.get("finality", 0)
77
+ if finality >= required_confirmations:
78
+ break
79
+
80
+ except Exception:
81
+ finality = 0
82
+
83
+ return finality
84
+
85
+ def ask(self, ual, required_confirmations, max_number_of_retries, frequency):
86
+ ask = 0
87
+ retries = 0
88
+
89
+ while ask < required_confirmations and retries < max_number_of_retries:
90
+ if retries > max_number_of_retries:
91
+ raise Exception(
92
+ f"Unable to achieve required confirmations. "
93
+ f"Max number of retries ({max_number_of_retries}) reached."
94
+ )
95
+
96
+ if retries > 0:
97
+ time.sleep(frequency)
98
+
99
+ retries += 1
100
+
101
+ try:
102
+ try:
103
+ response = self._ask(
104
+ ual=ual, minimumNumberOfNodeReplications=required_confirmations
105
+ )
106
+ except Exception as e:
107
+ response = None
108
+ print(f"failed: {e}")
109
+
110
+ if response is not None:
111
+ number_of_confirmations = response.json().get(
112
+ "numberOfConfirmations", 0
113
+ )
114
+ if number_of_confirmations >= required_confirmations:
115
+ ask = number_of_confirmations
116
+
117
+ except Exception as e:
118
+ ask = 0
119
+ print(f"Retry {retries + 1}/{max_number_of_retries} failed: {e}")
120
+
121
+ return ask
122
+
123
+ def publish(
124
+ self,
125
+ dataset_root,
126
+ dataset,
127
+ blockchain_id,
128
+ hash_function_id,
129
+ minimum_number_of_node_replications,
130
+ ):
131
+ return self._publish(
132
+ dataset_root,
133
+ dataset,
134
+ blockchain_id,
135
+ hash_function_id,
136
+ minimum_number_of_node_replications,
137
+ )
138
+
139
+ def get(
140
+ self,
141
+ ual_with_state,
142
+ content_type,
143
+ include_metadata,
144
+ hash_function_id,
145
+ paranet_ual,
146
+ subject_ual,
147
+ ):
148
+ return self._get(
149
+ ual_with_state,
150
+ content_type,
151
+ include_metadata,
152
+ hash_function_id,
153
+ paranet_ual,
154
+ subject_ual,
155
+ )
156
+
157
+ def query(
158
+ self,
159
+ query,
160
+ query_type,
161
+ repository,
162
+ paranet_ual,
163
+ ):
164
+ return self._query(query, query_type, repository, paranet_ual)
dkg/types/__init__.py CHANGED
@@ -1,6 +1,18 @@
1
- from .general import AutoStrEnum, AutoStrEnumCapitalize, AutoStrEnumUpperCase # NOQA: F401
2
- from .blockchain import (ABI, ABIElement, ABIError, ABIEvent, # NOQA: F401
3
- ABIFunction, ABIParameter, AgreementData, Environment)
1
+ from .general import (
2
+ AutoStrEnum, # NOQA: F401
3
+ AutoStrEnumCapitalize, # NOQA: F401
4
+ AutoStrEnumUpperCase, # NOQA: F401
5
+ )
6
+ from .blockchain import (
7
+ ABI, # NOQA: F401
8
+ ABIElement, # NOQA: F401
9
+ ABIError, # NOQA: F401
10
+ ABIEvent, # NOQA: F401
11
+ ABIFunction, # NOQA: F401
12
+ ABIParameter, # NOQA: F401
13
+ AgreementData, # NOQA: F401
14
+ Environment, # NOQA: F401
15
+ )
4
16
  from .dkg_node import UAL # NOQA: F401
5
17
  from .encoding import BytesLike, DataHexStr, HexStr # NOQA: F401
6
18
  from .evm import Address, ChecksumAddress, Wei # NOQA: F401
dkg/types/general.py CHANGED
@@ -17,28 +17,35 @@
17
17
 
18
18
  from enum import Enum
19
19
 
20
+
20
21
  class AutoStrEnum(str, Enum):
21
22
  @staticmethod
22
- def _generate_next_value_(name: str, start: int, count: int, last_values: list) -> str:
23
+ def _generate_next_value_(
24
+ name: str, start: int, count: int, last_values: list
25
+ ) -> str:
23
26
  return name.lower()
24
-
27
+
25
28
  def __str__(self):
26
29
  return str(self.value)
27
-
30
+
28
31
 
29
32
  class AutoStrEnumCapitalize(str, Enum):
30
33
  @staticmethod
31
- def _generate_next_value_(name: str, start: int, count: int, last_values: list) -> str:
34
+ def _generate_next_value_(
35
+ name: str, start: int, count: int, last_values: list
36
+ ) -> str:
32
37
  return name.capitalize()
33
-
38
+
34
39
  def __str__(self):
35
40
  return str(self.value)
36
41
 
37
42
 
38
43
  class AutoStrEnumUpperCase(str, Enum):
39
44
  @staticmethod
40
- def _generate_next_value_(name: str, start: int, count: int, last_values: list) -> str:
45
+ def _generate_next_value_(
46
+ name: str, start: int, count: int, last_values: list
47
+ ) -> str:
41
48
  return name
42
-
49
+
43
50
  def __str__(self):
44
- return str(self.value)
51
+ return str(self.value)