dkg 8.0.0a3__py3-none-any.whl → 8.0.2__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.
- dkg/__init__.py +1 -1
- dkg/assertion.py +2 -2
- dkg/clients/__init__.py +4 -0
- dkg/clients/async_dkg.py +109 -0
- dkg/{main.py → clients/dkg.py} +42 -21
- dkg/constants.py +117 -6
- dkg/data/interfaces/AskStorage.json +366 -0
- dkg/data/interfaces/Chronos.json +202 -0
- dkg/data/interfaces/Hub.json +294 -2
- dkg/data/interfaces/IdentityStorage.json +58 -0
- dkg/data/interfaces/{ContentAsset.json → KnowledgeCollection.json} +256 -343
- dkg/data/interfaces/KnowledgeCollectionStorage.json +2312 -0
- dkg/data/interfaces/Paranet.json +30 -214
- dkg/data/interfaces/ParanetIncentivesPoolFactory.json +18 -2
- dkg/data/interfaces/ParanetKnowledgeMinersRegistry.json +20 -4
- dkg/data/interfaces/{ParanetNeurowebIncentivesPool.json → ParanetNeuroIncentivesPool.json} +7 -7
- dkg/data/interfaces/ParanetsRegistry.json +102 -32
- dkg/data/interfaces/Token.json +146 -17
- dkg/managers/__init__.py +0 -0
- dkg/managers/async_manager.py +69 -0
- dkg/{manager.py → managers/manager.py} +5 -3
- dkg/method.py +5 -2
- dkg/modules/__init__.py +0 -0
- dkg/modules/asset/__init__.py +0 -0
- dkg/modules/asset/asset.py +739 -0
- dkg/modules/asset/async_asset.py +753 -0
- dkg/modules/async_module.py +66 -0
- dkg/modules/graph/__init__.py +0 -0
- dkg/modules/graph/async_graph.py +112 -0
- dkg/modules/graph/graph.py +87 -0
- dkg/{module.py → modules/module.py} +1 -1
- dkg/modules/network/__init__.py +0 -0
- dkg/{network.py → modules/network/network.py} +4 -4
- dkg/modules/node/__init__.py +0 -0
- dkg/modules/node/async_node.py +39 -0
- dkg/{node.py → modules/node/node.py} +2 -2
- dkg/modules/paranet/__init__.py +0 -0
- dkg/{paranet.py → modules/paranet/paranet.py} +2 -6
- dkg/providers/__init__.py +9 -2
- dkg/providers/blockchain/__init__.py +4 -0
- dkg/providers/blockchain/async_blockchain.py +245 -0
- dkg/providers/blockchain/base_blockchain.py +102 -0
- dkg/providers/{blockchain.py → blockchain/blockchain.py} +15 -96
- dkg/providers/node/__init__.py +4 -0
- dkg/providers/node/async_node_http.py +72 -0
- dkg/providers/node/base_node_http.py +25 -0
- dkg/providers/{node_http.py → node/node_http.py} +12 -10
- dkg/services/__init__.py +0 -0
- dkg/services/blockchain_services/__init__.py +0 -0
- dkg/services/blockchain_services/async_blockchain_service.py +180 -0
- dkg/services/blockchain_services/blockchain_service.py +174 -0
- dkg/services/input_service.py +181 -0
- dkg/services/node_services/__init__.py +0 -0
- dkg/services/node_services/async_node_service.py +184 -0
- dkg/services/node_services/node_service.py +167 -0
- dkg/types/__init__.py +11 -11
- dkg/utils/blockchain_request.py +76 -50
- dkg/utils/knowledge_asset_tools.py +5 -0
- dkg/utils/knowledge_collection_tools.py +248 -0
- dkg/utils/node_request.py +60 -14
- dkg/utils/rdf.py +9 -3
- {dkg-8.0.0a3.dist-info → dkg-8.0.2.dist-info}/METADATA +28 -19
- dkg-8.0.2.dist-info/RECORD +82 -0
- {dkg-8.0.0a3.dist-info → dkg-8.0.2.dist-info}/WHEEL +1 -1
- dkg/asset.py +0 -912
- dkg/data/interfaces/AssertionStorage.json +0 -229
- dkg/data/interfaces/ContentAssetStorage.json +0 -706
- dkg/data/interfaces/ServiceAgreementStorageProxy.json +0 -1314
- dkg/graph.py +0 -63
- dkg-8.0.0a3.dist-info/RECORD +0 -52
- {dkg-8.0.0a3.dist-info → dkg-8.0.2.dist-info}/LICENSE +0 -0
- {dkg-8.0.0a3.dist-info → dkg-8.0.2.dist-info}/NOTICE +0 -0
dkg/asset.py
DELETED
@@ -1,912 +0,0 @@
|
|
1
|
-
# Licensed to the Apache Software Foundation (ASF) under one
|
2
|
-
# or more contributor license agreements. See the NOTICE file
|
3
|
-
# distributed with this work for additional information
|
4
|
-
# regarding copyright ownership. The ASF licenses this file
|
5
|
-
# to you under the Apache License, Version 2.0 (the
|
6
|
-
# "License"); you may not use this file except in compliance
|
7
|
-
# with the License. You may obtain a copy of the License at
|
8
|
-
|
9
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
-
|
11
|
-
# Unless required by applicable law or agreed to in writing,
|
12
|
-
# software distributed under the License is distributed on an
|
13
|
-
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
14
|
-
# KIND, either express or implied. See the License for the
|
15
|
-
# specific language governing permissions and limitations
|
16
|
-
# under the License.
|
17
|
-
|
18
|
-
import json
|
19
|
-
import math
|
20
|
-
import re
|
21
|
-
from typing import Literal, Type
|
22
|
-
|
23
|
-
from pyld import jsonld
|
24
|
-
from web3 import Web3
|
25
|
-
from web3.constants import ADDRESS_ZERO, HASH_ZERO
|
26
|
-
from web3.exceptions import ContractLogicError
|
27
|
-
from web3.types import TxReceipt
|
28
|
-
|
29
|
-
from dkg.constants import (
|
30
|
-
DEFAULT_HASH_FUNCTION_ID,
|
31
|
-
DEFAULT_PROXIMITY_SCORE_FUNCTIONS_PAIR_IDS,
|
32
|
-
PRIVATE_ASSERTION_PREDICATE,
|
33
|
-
PRIVATE_CURRENT_REPOSITORY,
|
34
|
-
PRIVATE_HISTORICAL_REPOSITORY,
|
35
|
-
)
|
36
|
-
from dkg.dataclasses import (
|
37
|
-
BidSuggestionRange,
|
38
|
-
KnowledgeAssetContentVisibility,
|
39
|
-
KnowledgeAssetEnumStates,
|
40
|
-
NodeResponseDict,
|
41
|
-
)
|
42
|
-
from dkg.exceptions import (
|
43
|
-
DatasetOutputFormatNotSupported,
|
44
|
-
InvalidKnowledgeAsset,
|
45
|
-
InvalidStateOption,
|
46
|
-
InvalidTokenAmount,
|
47
|
-
MissingKnowledgeAssetState,
|
48
|
-
OperationNotFinished,
|
49
|
-
)
|
50
|
-
from dkg.manager import DefaultRequestManager
|
51
|
-
from dkg.method import Method
|
52
|
-
from dkg.module import Module
|
53
|
-
from dkg.types import JSONLD, UAL, Address, AgreementData, HexStr, Wei
|
54
|
-
from dkg.utils.blockchain_request import BlockchainRequest
|
55
|
-
from dkg.utils.decorators import retry
|
56
|
-
from dkg.utils.merkle import MerkleTree, hash_assertion_with_indexes
|
57
|
-
from dkg.utils.metadata import (
|
58
|
-
generate_agreement_id,
|
59
|
-
generate_assertion_metadata,
|
60
|
-
generate_keyword,
|
61
|
-
)
|
62
|
-
from dkg.utils.node_request import (
|
63
|
-
NodeRequest,
|
64
|
-
OperationStatus,
|
65
|
-
StoreTypes,
|
66
|
-
validate_operation_status,
|
67
|
-
)
|
68
|
-
from dkg.utils.rdf import format_content, normalize_dataset
|
69
|
-
from dkg.utils.ual import format_ual, parse_ual
|
70
|
-
|
71
|
-
|
72
|
-
class KnowledgeAsset(Module):
|
73
|
-
def __init__(self, manager: DefaultRequestManager):
|
74
|
-
self.manager = manager
|
75
|
-
|
76
|
-
_owner = Method(BlockchainRequest.owner_of)
|
77
|
-
|
78
|
-
def is_valid_ual(self, ual: UAL) -> bool:
|
79
|
-
if not ual or not isinstance(ual, str):
|
80
|
-
raise ValueError("UAL must be a non-empty string.")
|
81
|
-
|
82
|
-
parts = ual.split("/")
|
83
|
-
if len(parts) != 3:
|
84
|
-
raise ValueError("UAL format is incorrect.")
|
85
|
-
|
86
|
-
prefixes = parts[0].split(":")
|
87
|
-
prefixes_number = len(prefixes)
|
88
|
-
if prefixes_number != 3 and prefixes_number != 4:
|
89
|
-
raise ValueError("Prefix format in UAL is incorrect.")
|
90
|
-
|
91
|
-
if prefixes[0] != "did":
|
92
|
-
raise ValueError(
|
93
|
-
f"Invalid DID prefix. Expected: 'did'. Received: '{prefixes[0]}'."
|
94
|
-
)
|
95
|
-
|
96
|
-
if prefixes[1] != "dkg":
|
97
|
-
raise ValueError(
|
98
|
-
f"Invalid DKG prefix. Expected: 'dkg'. Received: '{prefixes[1]}'."
|
99
|
-
)
|
100
|
-
|
101
|
-
if prefixes[2] != (
|
102
|
-
blockchain_name := (
|
103
|
-
self.manager.blockchain_provider.blockchain_id.split(":")[0]
|
104
|
-
)
|
105
|
-
):
|
106
|
-
raise ValueError(
|
107
|
-
"Invalid blockchain name in the UAL prefix. "
|
108
|
-
f"Expected: '{blockchain_name}'. Received: '${prefixes[2]}'."
|
109
|
-
)
|
110
|
-
|
111
|
-
if prefixes_number == 4:
|
112
|
-
chain_id = self.manager.blockchain_provider.blockchain_id.split(":")[1]
|
113
|
-
|
114
|
-
if int(prefixes[3]) != int(chain_id):
|
115
|
-
raise ValueError(
|
116
|
-
"Chain ID in UAL does not match the blockchain. "
|
117
|
-
f"Expected: '${chain_id}'. Received: '${prefixes[3]}'."
|
118
|
-
)
|
119
|
-
|
120
|
-
contract_address = self.manager.blockchain_provider.contracts[
|
121
|
-
"ContentAssetStorage"
|
122
|
-
].address
|
123
|
-
|
124
|
-
if parts[1].lower() != contract_address.lower():
|
125
|
-
raise ValueError(
|
126
|
-
"Contract address in UAL does not match. "
|
127
|
-
f"Expected: '${contract_address.lower()}'. "
|
128
|
-
f"Received: '${parts[1].lower()}'."
|
129
|
-
)
|
130
|
-
|
131
|
-
try:
|
132
|
-
owner = self._owner(int(parts[2]))
|
133
|
-
|
134
|
-
if not owner or owner == ADDRESS_ZERO:
|
135
|
-
raise ValueError("Token does not exist or has no owner.")
|
136
|
-
|
137
|
-
return True
|
138
|
-
except Exception as err:
|
139
|
-
raise ValueError(f"Error fetching asset owner: {err}")
|
140
|
-
|
141
|
-
_get_contract_address = Method(BlockchainRequest.get_contract_address)
|
142
|
-
_get_current_allowance = Method(BlockchainRequest.allowance)
|
143
|
-
|
144
|
-
def get_current_allowance(self, spender: Address | None = None) -> Wei:
|
145
|
-
if spender is None:
|
146
|
-
spender = self._get_contract_address("ServiceAgreementV1")
|
147
|
-
|
148
|
-
return int(
|
149
|
-
self._get_current_allowance(
|
150
|
-
self.manager.blockchain_provider.account.address, spender
|
151
|
-
)
|
152
|
-
)
|
153
|
-
|
154
|
-
_increase_allowance = Method(BlockchainRequest.increase_allowance)
|
155
|
-
_decrease_allowance = Method(BlockchainRequest.decrease_allowance)
|
156
|
-
|
157
|
-
def set_allowance(self, token_amount: Wei, spender: Address | None = None) -> Wei:
|
158
|
-
if spender is None:
|
159
|
-
spender = self._get_contract_address("ServiceAgreementV1")
|
160
|
-
|
161
|
-
current_allowance = self.get_current_allowance(spender)
|
162
|
-
|
163
|
-
allowance_difference = token_amount - current_allowance
|
164
|
-
|
165
|
-
if allowance_difference > 0:
|
166
|
-
self._increase_allowance(spender, allowance_difference)
|
167
|
-
elif allowance_difference < 0:
|
168
|
-
self._decrease_allowance(spender, -allowance_difference)
|
169
|
-
|
170
|
-
return allowance_difference
|
171
|
-
|
172
|
-
def increase_allowance(
|
173
|
-
self, token_amount: Wei, spender: Address | None = None
|
174
|
-
) -> Wei:
|
175
|
-
if spender is None:
|
176
|
-
spender = self._get_contract_address("ServiceAgreementV1")
|
177
|
-
|
178
|
-
self._increase_allowance(spender, token_amount)
|
179
|
-
|
180
|
-
return token_amount
|
181
|
-
|
182
|
-
def decrease_allowance(
|
183
|
-
self, token_amount: Wei, spender: Address | None = None
|
184
|
-
) -> Wei:
|
185
|
-
if spender is None:
|
186
|
-
spender = self._get_contract_address("ServiceAgreementV1")
|
187
|
-
|
188
|
-
current_allowance = self.get_current_allowance(spender)
|
189
|
-
subtracted_value = min(token_amount, current_allowance)
|
190
|
-
|
191
|
-
self._decrease_allowance(spender, subtracted_value)
|
192
|
-
|
193
|
-
return subtracted_value
|
194
|
-
|
195
|
-
_chain_id = Method(BlockchainRequest.chain_id)
|
196
|
-
|
197
|
-
_get_asset_storage_address = Method(BlockchainRequest.get_asset_storage_address)
|
198
|
-
_create = Method(BlockchainRequest.create_asset)
|
199
|
-
_mint_paranet_knowledge_asset = Method(BlockchainRequest.mint_knowledge_asset)
|
200
|
-
|
201
|
-
_get_bid_suggestion = Method(NodeRequest.bid_suggestion)
|
202
|
-
_local_store = Method(NodeRequest.local_store)
|
203
|
-
_publish = Method(NodeRequest.publish)
|
204
|
-
|
205
|
-
def create(
|
206
|
-
self,
|
207
|
-
content: dict[Literal["public", "private"], JSONLD],
|
208
|
-
epochs_number: int,
|
209
|
-
token_amount: Wei | None = None,
|
210
|
-
immutable: bool = False,
|
211
|
-
content_type: Literal["JSON-LD", "N-Quads"] = "JSON-LD",
|
212
|
-
paranet_ual: UAL | None = None,
|
213
|
-
) -> dict[str, UAL | HexStr | dict[str, dict[str, str] | TxReceipt]]:
|
214
|
-
blockchain_id = self.manager.blockchain_provider.blockchain_id
|
215
|
-
assertions = format_content(content, content_type)
|
216
|
-
|
217
|
-
public_assertion_id = MerkleTree(
|
218
|
-
hash_assertion_with_indexes(assertions["public"]),
|
219
|
-
sort_pairs=True,
|
220
|
-
).root
|
221
|
-
public_assertion_metadata = generate_assertion_metadata(assertions["public"])
|
222
|
-
|
223
|
-
content_asset_storage_address = self._get_asset_storage_address(
|
224
|
-
"ContentAssetStorage"
|
225
|
-
)
|
226
|
-
|
227
|
-
if token_amount is None:
|
228
|
-
token_amount = int(
|
229
|
-
self._get_bid_suggestion(
|
230
|
-
blockchain_id,
|
231
|
-
epochs_number,
|
232
|
-
public_assertion_metadata["size"],
|
233
|
-
content_asset_storage_address,
|
234
|
-
public_assertion_id,
|
235
|
-
DEFAULT_HASH_FUNCTION_ID,
|
236
|
-
token_amount or BidSuggestionRange.LOW,
|
237
|
-
)["bidSuggestion"]
|
238
|
-
)
|
239
|
-
|
240
|
-
current_allowance = self.get_current_allowance()
|
241
|
-
if is_allowance_increased := current_allowance < token_amount:
|
242
|
-
self.increase_allowance(token_amount)
|
243
|
-
|
244
|
-
result = {"publicAssertionId": public_assertion_id, "operation": {}}
|
245
|
-
|
246
|
-
try:
|
247
|
-
if paranet_ual is None:
|
248
|
-
receipt: TxReceipt = self._create(
|
249
|
-
{
|
250
|
-
"assertionId": Web3.to_bytes(hexstr=public_assertion_id),
|
251
|
-
"size": public_assertion_metadata["size"],
|
252
|
-
"triplesNumber": public_assertion_metadata["triples_number"],
|
253
|
-
"chunksNumber": public_assertion_metadata["chunks_number"],
|
254
|
-
"tokenAmount": token_amount,
|
255
|
-
"epochsNumber": epochs_number,
|
256
|
-
"scoreFunctionId": DEFAULT_PROXIMITY_SCORE_FUNCTIONS_PAIR_IDS[
|
257
|
-
self.manager.blockchain_provider.environment
|
258
|
-
][blockchain_id],
|
259
|
-
"immutable_": immutable,
|
260
|
-
}
|
261
|
-
)
|
262
|
-
else:
|
263
|
-
parsed_paranet_ual = parse_ual(paranet_ual)
|
264
|
-
paranet_knowledge_asset_storage, paranet_knowledge_asset_token_id = (
|
265
|
-
parsed_paranet_ual["contract_address"],
|
266
|
-
parsed_paranet_ual["token_id"],
|
267
|
-
)
|
268
|
-
|
269
|
-
receipt: TxReceipt = self._mint_paranet_knowledge_asset(
|
270
|
-
paranet_knowledge_asset_storage,
|
271
|
-
paranet_knowledge_asset_token_id,
|
272
|
-
{
|
273
|
-
"assertionId": Web3.to_bytes(hexstr=public_assertion_id),
|
274
|
-
"size": public_assertion_metadata["size"],
|
275
|
-
"triplesNumber": public_assertion_metadata["triples_number"],
|
276
|
-
"chunksNumber": public_assertion_metadata["chunks_number"],
|
277
|
-
"tokenAmount": token_amount,
|
278
|
-
"epochsNumber": epochs_number,
|
279
|
-
"scoreFunctionId": DEFAULT_PROXIMITY_SCORE_FUNCTIONS_PAIR_IDS[
|
280
|
-
self.manager.blockchain_provider.environment
|
281
|
-
][blockchain_id],
|
282
|
-
"immutable_": immutable,
|
283
|
-
},
|
284
|
-
)
|
285
|
-
|
286
|
-
result["paranetId"] = Web3.to_hex(
|
287
|
-
Web3.solidity_keccak(
|
288
|
-
["address", "uint256"],
|
289
|
-
[
|
290
|
-
paranet_knowledge_asset_storage,
|
291
|
-
paranet_knowledge_asset_token_id,
|
292
|
-
],
|
293
|
-
)
|
294
|
-
)
|
295
|
-
except ContractLogicError as err:
|
296
|
-
if is_allowance_increased:
|
297
|
-
self.decrease_allowance(token_amount)
|
298
|
-
raise err
|
299
|
-
|
300
|
-
events = self.manager.blockchain_provider.decode_logs_event(
|
301
|
-
receipt,
|
302
|
-
"ContentAsset",
|
303
|
-
"AssetMinted",
|
304
|
-
)
|
305
|
-
token_id = events[0].args["tokenId"]
|
306
|
-
|
307
|
-
result["UAL"] = format_ual(
|
308
|
-
blockchain_id, content_asset_storage_address, token_id
|
309
|
-
)
|
310
|
-
result["operation"]["mintKnowledgeAsset"] = json.loads(Web3.to_json(receipt))
|
311
|
-
|
312
|
-
assertions_list = [
|
313
|
-
{
|
314
|
-
"blockchain": blockchain_id,
|
315
|
-
"contract": content_asset_storage_address,
|
316
|
-
"tokenId": token_id,
|
317
|
-
"assertionId": public_assertion_id,
|
318
|
-
"assertion": assertions["public"],
|
319
|
-
"storeType": StoreTypes.TRIPLE,
|
320
|
-
}
|
321
|
-
]
|
322
|
-
|
323
|
-
if content.get("private", None):
|
324
|
-
assertions_list.append(
|
325
|
-
{
|
326
|
-
"blockchain": blockchain_id,
|
327
|
-
"contract": content_asset_storage_address,
|
328
|
-
"tokenId": token_id,
|
329
|
-
"assertionId": MerkleTree(
|
330
|
-
hash_assertion_with_indexes(assertions["private"]),
|
331
|
-
sort_pairs=True,
|
332
|
-
).root,
|
333
|
-
"assertion": assertions["private"],
|
334
|
-
"storeType": StoreTypes.TRIPLE,
|
335
|
-
}
|
336
|
-
)
|
337
|
-
|
338
|
-
operation_id = self._publish(
|
339
|
-
public_assertion_id,
|
340
|
-
assertions["public"],
|
341
|
-
blockchain_id,
|
342
|
-
content_asset_storage_address,
|
343
|
-
token_id,
|
344
|
-
DEFAULT_HASH_FUNCTION_ID,
|
345
|
-
)["operationId"]
|
346
|
-
operation_result = self.get_operation_result(operation_id, "publish")
|
347
|
-
|
348
|
-
result["operation"]["publish"] = {
|
349
|
-
"operationId": operation_id,
|
350
|
-
"status": operation_result["status"],
|
351
|
-
}
|
352
|
-
|
353
|
-
if operation_result["status"] == OperationStatus.COMPLETED:
|
354
|
-
operation_id = self._local_store(assertions_list)["operationId"]
|
355
|
-
operation_result = self.get_operation_result(operation_id, "local-store")
|
356
|
-
|
357
|
-
result["operation"]["localStore"] = {
|
358
|
-
"operationId": operation_id,
|
359
|
-
"status": operation_result["status"],
|
360
|
-
}
|
361
|
-
|
362
|
-
return result
|
363
|
-
|
364
|
-
|
365
|
-
def local_store(
|
366
|
-
self,
|
367
|
-
content: dict[Literal["public", "private"], JSONLD],
|
368
|
-
epochs_number: int,
|
369
|
-
token_amount: Wei | None = None,
|
370
|
-
immutable: bool = False,
|
371
|
-
content_type: Literal["JSON-LD", "N-Quads"] = "JSON-LD",
|
372
|
-
paranet_ual: UAL | None = None,
|
373
|
-
) -> dict[str, UAL | HexStr | dict[str, dict[str, str] | TxReceipt]]:
|
374
|
-
blockchain_id = self.manager.blockchain_provider.blockchain_id
|
375
|
-
assertions = format_content(content, content_type)
|
376
|
-
|
377
|
-
public_assertion_id = MerkleTree(
|
378
|
-
hash_assertion_with_indexes(assertions["public"]),
|
379
|
-
sort_pairs=True,
|
380
|
-
).root
|
381
|
-
public_assertion_metadata = generate_assertion_metadata(assertions["public"])
|
382
|
-
|
383
|
-
content_asset_storage_address = self._get_asset_storage_address(
|
384
|
-
"ContentAssetStorage"
|
385
|
-
)
|
386
|
-
|
387
|
-
if token_amount is None:
|
388
|
-
token_amount = int(
|
389
|
-
self._get_bid_suggestion(
|
390
|
-
blockchain_id,
|
391
|
-
epochs_number,
|
392
|
-
public_assertion_metadata["size"],
|
393
|
-
content_asset_storage_address,
|
394
|
-
public_assertion_id,
|
395
|
-
DEFAULT_HASH_FUNCTION_ID,
|
396
|
-
token_amount or BidSuggestionRange.LOW,
|
397
|
-
)["bidSuggestion"]
|
398
|
-
)
|
399
|
-
|
400
|
-
current_allowance = self.get_current_allowance()
|
401
|
-
if is_allowance_increased := current_allowance < token_amount:
|
402
|
-
self.increase_allowance(token_amount)
|
403
|
-
|
404
|
-
result = {"publicAssertionId": public_assertion_id, "operation": {}}
|
405
|
-
|
406
|
-
try:
|
407
|
-
receipt: TxReceipt = self._create(
|
408
|
-
{
|
409
|
-
"assertionId": Web3.to_bytes(hexstr=public_assertion_id),
|
410
|
-
"size": public_assertion_metadata["size"],
|
411
|
-
"triplesNumber": public_assertion_metadata["triples_number"],
|
412
|
-
"chunksNumber": public_assertion_metadata["chunks_number"],
|
413
|
-
"tokenAmount": token_amount,
|
414
|
-
"epochsNumber": epochs_number,
|
415
|
-
"scoreFunctionId": DEFAULT_PROXIMITY_SCORE_FUNCTIONS_PAIR_IDS[
|
416
|
-
self.manager.blockchain_provider.environment
|
417
|
-
][blockchain_id],
|
418
|
-
"immutable_": immutable,
|
419
|
-
}
|
420
|
-
)
|
421
|
-
except ContractLogicError as err:
|
422
|
-
if is_allowance_increased:
|
423
|
-
self.decrease_allowance(token_amount)
|
424
|
-
raise err
|
425
|
-
|
426
|
-
events = self.manager.blockchain_provider.decode_logs_event(
|
427
|
-
receipt,
|
428
|
-
"ContentAsset",
|
429
|
-
"AssetMinted",
|
430
|
-
)
|
431
|
-
token_id = events[0].args["tokenId"]
|
432
|
-
|
433
|
-
result["UAL"] = format_ual(
|
434
|
-
blockchain_id, content_asset_storage_address, token_id
|
435
|
-
)
|
436
|
-
result["operation"]["mintKnowledgeAsset"] = json.loads(Web3.to_json(receipt))
|
437
|
-
|
438
|
-
assertions_list = [
|
439
|
-
{
|
440
|
-
"blockchain": blockchain_id,
|
441
|
-
"contract": content_asset_storage_address,
|
442
|
-
"tokenId": token_id,
|
443
|
-
"assertionId": public_assertion_id,
|
444
|
-
"assertion": assertions["public"],
|
445
|
-
"storeType": StoreTypes.TRIPLE_PARANET,
|
446
|
-
"paranetUAL": paranet_ual,
|
447
|
-
}
|
448
|
-
]
|
449
|
-
|
450
|
-
if content.get("private", None):
|
451
|
-
assertions_list.append(
|
452
|
-
{
|
453
|
-
"blockchain": blockchain_id,
|
454
|
-
"contract": content_asset_storage_address,
|
455
|
-
"tokenId": token_id,
|
456
|
-
"assertionId": MerkleTree(
|
457
|
-
hash_assertion_with_indexes(assertions["private"]),
|
458
|
-
sort_pairs=True,
|
459
|
-
).root,
|
460
|
-
"assertion": assertions["private"],
|
461
|
-
"storeType": StoreTypes.TRIPLE_PARANET,
|
462
|
-
"paranetUAL": paranet_ual,
|
463
|
-
}
|
464
|
-
)
|
465
|
-
|
466
|
-
operation_id = self._local_store(assertions_list)["operationId"]
|
467
|
-
operation_result = self.get_operation_result(operation_id, "local-store")
|
468
|
-
|
469
|
-
result["operation"]["localStore"] = {
|
470
|
-
"operationId": operation_id,
|
471
|
-
"status": operation_result["status"],
|
472
|
-
}
|
473
|
-
|
474
|
-
if operation_result["status"] == OperationStatus.COMPLETED:
|
475
|
-
parsed_paranet_ual = parse_ual(paranet_ual)
|
476
|
-
paranet_knowledge_asset_storage, paranet_knowledge_asset_token_id = (
|
477
|
-
parsed_paranet_ual["contract_address"],
|
478
|
-
parsed_paranet_ual["token_id"],
|
479
|
-
)
|
480
|
-
|
481
|
-
receipt: TxReceipt = self._submit_knowledge_asset(
|
482
|
-
paranet_knowledge_asset_storage,
|
483
|
-
paranet_knowledge_asset_token_id,
|
484
|
-
content_asset_storage_address,
|
485
|
-
token_id,
|
486
|
-
)
|
487
|
-
|
488
|
-
result["operation"]["submitToParanet"] = json.loads(Web3.to_json(receipt))
|
489
|
-
|
490
|
-
return result
|
491
|
-
|
492
|
-
|
493
|
-
_submit_knowledge_asset = Method(BlockchainRequest.submit_knowledge_asset)
|
494
|
-
|
495
|
-
def submit_to_paranet(
|
496
|
-
self, ual: UAL, paranet_ual: UAL
|
497
|
-
) -> dict[str, UAL | Address | TxReceipt]:
|
498
|
-
parsed_ual = parse_ual(ual)
|
499
|
-
knowledge_asset_storage, knowledge_asset_token_id = (
|
500
|
-
parsed_ual["contract_address"],
|
501
|
-
parsed_ual["token_id"],
|
502
|
-
)
|
503
|
-
|
504
|
-
parsed_paranet_ual = parse_ual(paranet_ual)
|
505
|
-
paranet_knowledge_asset_storage, paranet_knowledge_asset_token_id = (
|
506
|
-
parsed_paranet_ual["contract_address"],
|
507
|
-
parsed_paranet_ual["token_id"],
|
508
|
-
)
|
509
|
-
|
510
|
-
receipt: TxReceipt = self._submit_knowledge_asset(
|
511
|
-
paranet_knowledge_asset_storage,
|
512
|
-
paranet_knowledge_asset_token_id,
|
513
|
-
knowledge_asset_storage,
|
514
|
-
knowledge_asset_token_id,
|
515
|
-
)
|
516
|
-
|
517
|
-
return {
|
518
|
-
"UAL": ual,
|
519
|
-
"paranetUAL": paranet_ual,
|
520
|
-
"paranetId": Web3.to_hex(
|
521
|
-
Web3.solidity_keccak(
|
522
|
-
["address", "uint256"],
|
523
|
-
[knowledge_asset_storage, knowledge_asset_token_id],
|
524
|
-
)
|
525
|
-
),
|
526
|
-
"operation": json.loads(Web3.to_json(receipt)),
|
527
|
-
}
|
528
|
-
|
529
|
-
_transfer = Method(BlockchainRequest.transfer_asset)
|
530
|
-
|
531
|
-
def transfer(
|
532
|
-
self,
|
533
|
-
ual: UAL,
|
534
|
-
new_owner: Address,
|
535
|
-
) -> dict[str, UAL | Address | TxReceipt]:
|
536
|
-
token_id = parse_ual(ual)["token_id"]
|
537
|
-
|
538
|
-
receipt: TxReceipt = self._transfer(
|
539
|
-
self.manager.blockchain_provider.account,
|
540
|
-
new_owner,
|
541
|
-
token_id,
|
542
|
-
)
|
543
|
-
|
544
|
-
return {
|
545
|
-
"UAL": ual,
|
546
|
-
"owner": new_owner,
|
547
|
-
"operation": json.loads(Web3.to_json(receipt)),
|
548
|
-
}
|
549
|
-
|
550
|
-
_burn_asset = Method(BlockchainRequest.burn_asset)
|
551
|
-
|
552
|
-
def burn(self, ual: UAL) -> dict[str, UAL | TxReceipt]:
|
553
|
-
token_id = parse_ual(ual)["token_id"]
|
554
|
-
|
555
|
-
receipt: TxReceipt = self._burn_asset(token_id)
|
556
|
-
|
557
|
-
return {"UAL": ual, "operation": json.loads(Web3.to_json(receipt))}
|
558
|
-
|
559
|
-
_get_assertion_ids = Method(BlockchainRequest.get_assertion_ids)
|
560
|
-
_get_latest_assertion_id = Method(BlockchainRequest.get_latest_assertion_id)
|
561
|
-
_get_unfinalized_state = Method(BlockchainRequest.get_unfinalized_state)
|
562
|
-
|
563
|
-
_get = Method(NodeRequest.get)
|
564
|
-
_query = Method(NodeRequest.query)
|
565
|
-
|
566
|
-
def get(
|
567
|
-
self,
|
568
|
-
ual: UAL,
|
569
|
-
state: str | HexStr | int = KnowledgeAssetEnumStates.LATEST,
|
570
|
-
content_visibility: str = KnowledgeAssetContentVisibility.ALL,
|
571
|
-
output_format: Literal["JSON-LD", "N-Quads"] = "JSON-LD",
|
572
|
-
validate: bool = True,
|
573
|
-
) -> dict[str, UAL | HexStr | list[JSONLD] | dict[str, str]]:
|
574
|
-
state = (
|
575
|
-
state.upper()
|
576
|
-
if (isinstance(state, str) and not re.match(r"^0x[a-fA-F0-9]{64}$", state))
|
577
|
-
else state
|
578
|
-
)
|
579
|
-
content_visibility = content_visibility.upper()
|
580
|
-
output_format = output_format.upper()
|
581
|
-
|
582
|
-
token_id = parse_ual(ual)["token_id"]
|
583
|
-
|
584
|
-
def handle_latest_finalized_state(token_id: int) -> tuple[HexStr, bool]:
|
585
|
-
return Web3.to_hex(self._get_latest_assertion_id(token_id)), True
|
586
|
-
|
587
|
-
is_state_finalized = False
|
588
|
-
|
589
|
-
match state:
|
590
|
-
case KnowledgeAssetEnumStates.LATEST | KnowledgeAssetEnumStates.LATEST_FINALIZED:
|
591
|
-
public_assertion_id, is_state_finalized = handle_latest_finalized_state(
|
592
|
-
token_id
|
593
|
-
)
|
594
|
-
|
595
|
-
case _ if isinstance(state, int):
|
596
|
-
assertion_ids = [
|
597
|
-
Web3.to_hex(assertion_id)
|
598
|
-
for assertion_id in self._get_assertion_ids(token_id)
|
599
|
-
]
|
600
|
-
if 0 <= state < (states_number := len(assertion_ids)):
|
601
|
-
public_assertion_id = assertion_ids[state]
|
602
|
-
|
603
|
-
if state == states_number - 1:
|
604
|
-
is_state_finalized = True
|
605
|
-
else:
|
606
|
-
raise InvalidStateOption(f"State index {state} is out of range.")
|
607
|
-
|
608
|
-
case _ if isinstance(state, str) and re.match(
|
609
|
-
r"^0x[a-fA-F0-9]{64}$", state
|
610
|
-
):
|
611
|
-
assertion_ids = [
|
612
|
-
Web3.to_hex(assertion_id)
|
613
|
-
for assertion_id in self._get_assertion_ids(token_id)
|
614
|
-
]
|
615
|
-
|
616
|
-
if state in assertion_ids:
|
617
|
-
public_assertion_id = state
|
618
|
-
|
619
|
-
if state == assertion_ids[-1]:
|
620
|
-
is_state_finalized = True
|
621
|
-
else:
|
622
|
-
raise InvalidStateOption(
|
623
|
-
f"Given state hash: {state} is not a part of the KA."
|
624
|
-
)
|
625
|
-
|
626
|
-
case _:
|
627
|
-
raise InvalidStateOption(f"Invalid state option: {state}.")
|
628
|
-
|
629
|
-
get_public_operation_id: NodeResponseDict = self._get(
|
630
|
-
ual, public_assertion_id, hashFunctionId=1
|
631
|
-
)["operationId"]
|
632
|
-
|
633
|
-
get_public_operation_result = self.get_operation_result(
|
634
|
-
get_public_operation_id, "get"
|
635
|
-
)
|
636
|
-
public_assertion = get_public_operation_result["data"].get("assertion", None)
|
637
|
-
|
638
|
-
if public_assertion is None:
|
639
|
-
raise MissingKnowledgeAssetState("Unable to find state on the network!")
|
640
|
-
|
641
|
-
if validate:
|
642
|
-
root = MerkleTree(
|
643
|
-
hash_assertion_with_indexes(public_assertion), sort_pairs=True
|
644
|
-
).root
|
645
|
-
if root != public_assertion_id:
|
646
|
-
raise InvalidKnowledgeAsset(
|
647
|
-
f"State: {public_assertion_id}. " f"Merkle Tree Root: {root}"
|
648
|
-
)
|
649
|
-
|
650
|
-
result = {"operation": {}}
|
651
|
-
if content_visibility != KnowledgeAssetContentVisibility.PRIVATE:
|
652
|
-
formatted_public_assertion = public_assertion
|
653
|
-
|
654
|
-
match output_format:
|
655
|
-
case "NQUADS" | "N-QUADS":
|
656
|
-
formatted_public_assertion: list[JSONLD] = jsonld.from_rdf(
|
657
|
-
"\n".join(public_assertion),
|
658
|
-
{"algorithm": "URDNA2015", "format": "application/n-quads"},
|
659
|
-
)
|
660
|
-
case "JSONLD" | "JSON-LD":
|
661
|
-
formatted_public_assertion = "\n".join(public_assertion)
|
662
|
-
|
663
|
-
case _:
|
664
|
-
raise DatasetOutputFormatNotSupported(
|
665
|
-
f"{output_format} isn't supported!"
|
666
|
-
)
|
667
|
-
|
668
|
-
if content_visibility == KnowledgeAssetContentVisibility.PUBLIC:
|
669
|
-
result = {
|
670
|
-
**result,
|
671
|
-
"asertion": formatted_public_assertion,
|
672
|
-
"assertionId": public_assertion_id,
|
673
|
-
}
|
674
|
-
else:
|
675
|
-
result["public"] = {
|
676
|
-
"assertion": formatted_public_assertion,
|
677
|
-
"assertionId": public_assertion_id,
|
678
|
-
}
|
679
|
-
|
680
|
-
result["operation"]["publicGet"] = {
|
681
|
-
"operationId": get_public_operation_id,
|
682
|
-
"status": get_public_operation_result["status"],
|
683
|
-
}
|
684
|
-
|
685
|
-
if content_visibility != KnowledgeAssetContentVisibility.PUBLIC:
|
686
|
-
private_assertion_link_triples = list(
|
687
|
-
filter(
|
688
|
-
lambda element: PRIVATE_ASSERTION_PREDICATE in element,
|
689
|
-
public_assertion,
|
690
|
-
)
|
691
|
-
)
|
692
|
-
|
693
|
-
if private_assertion_link_triples:
|
694
|
-
private_assertion_id = re.search(
|
695
|
-
r'"(.*?)"', private_assertion_link_triples[0]
|
696
|
-
).group(1)
|
697
|
-
|
698
|
-
private_assertion = get_public_operation_result["data"].get(
|
699
|
-
"privateAssertion", None
|
700
|
-
)
|
701
|
-
|
702
|
-
query_private_operation_id: NodeResponseDict | None = None
|
703
|
-
if private_assertion is None:
|
704
|
-
query = f"""
|
705
|
-
CONSTRUCT {{ ?s ?p ?o }}
|
706
|
-
WHERE {{
|
707
|
-
{{
|
708
|
-
GRAPH <assertion:{private_assertion_id}>
|
709
|
-
{{
|
710
|
-
?s ?p ?o .
|
711
|
-
}}
|
712
|
-
}}
|
713
|
-
}}
|
714
|
-
"""
|
715
|
-
|
716
|
-
query_private_operation_id = self._query(
|
717
|
-
query,
|
718
|
-
"CONSTRUCT",
|
719
|
-
PRIVATE_CURRENT_REPOSITORY
|
720
|
-
if is_state_finalized
|
721
|
-
else PRIVATE_HISTORICAL_REPOSITORY,
|
722
|
-
)["operationId"]
|
723
|
-
|
724
|
-
query_private_operation_result = self.get_operation_result(
|
725
|
-
query_private_operation_id, "query"
|
726
|
-
)
|
727
|
-
|
728
|
-
private_assertion = normalize_dataset(
|
729
|
-
query_private_operation_result["data"],
|
730
|
-
"N-Quads",
|
731
|
-
)
|
732
|
-
|
733
|
-
if validate:
|
734
|
-
root = MerkleTree(
|
735
|
-
hash_assertion_with_indexes(private_assertion),
|
736
|
-
sort_pairs=True,
|
737
|
-
).root
|
738
|
-
if root != private_assertion_id:
|
739
|
-
raise InvalidKnowledgeAsset(
|
740
|
-
f"State: {private_assertion_id}. "
|
741
|
-
f"Merkle Tree Root: {root}"
|
742
|
-
)
|
743
|
-
|
744
|
-
match output_format:
|
745
|
-
case "NQUADS" | "N-QUADS":
|
746
|
-
formatted_private_assertion: list[JSONLD] = jsonld.from_rdf(
|
747
|
-
"\n".join(private_assertion),
|
748
|
-
{
|
749
|
-
"algorithm": "URDNA2015",
|
750
|
-
"format": "application/n-quads",
|
751
|
-
},
|
752
|
-
)
|
753
|
-
case "JSONLD" | "JSON-LD":
|
754
|
-
formatted_private_assertion = "\n".join(private_assertion)
|
755
|
-
|
756
|
-
case _:
|
757
|
-
raise DatasetOutputFormatNotSupported(
|
758
|
-
f"{output_format} isn't supported!"
|
759
|
-
)
|
760
|
-
|
761
|
-
if content_visibility == KnowledgeAssetContentVisibility:
|
762
|
-
result = {
|
763
|
-
**result,
|
764
|
-
"assertion": formatted_private_assertion,
|
765
|
-
"assertionId": private_assertion_id,
|
766
|
-
}
|
767
|
-
else:
|
768
|
-
result["private"] = {
|
769
|
-
"assertion": formatted_private_assertion,
|
770
|
-
"assertionId": private_assertion_id,
|
771
|
-
}
|
772
|
-
|
773
|
-
if query_private_operation_id is not None:
|
774
|
-
result["operation"]["queryPrivate"] = {
|
775
|
-
"operationId": query_private_operation_id,
|
776
|
-
"status": query_private_operation_result["status"],
|
777
|
-
}
|
778
|
-
|
779
|
-
return result
|
780
|
-
|
781
|
-
_extend_storing_period = Method(BlockchainRequest.extend_asset_storing_period)
|
782
|
-
|
783
|
-
def extend_storing_period(
|
784
|
-
self,
|
785
|
-
ual: UAL,
|
786
|
-
additional_epochs: int,
|
787
|
-
token_amount: Wei | None = None,
|
788
|
-
) -> dict[str, UAL | TxReceipt]:
|
789
|
-
parsed_ual = parse_ual(ual)
|
790
|
-
blockchain_id, content_asset_storage_address, token_id = (
|
791
|
-
parsed_ual["blockchain"],
|
792
|
-
parsed_ual["contract_address"],
|
793
|
-
parsed_ual["token_id"],
|
794
|
-
)
|
795
|
-
|
796
|
-
if token_amount is None:
|
797
|
-
latest_finalized_state = self._get_latest_assertion_id(token_id)
|
798
|
-
latest_finalized_state_size = self._get_assertion_size(
|
799
|
-
latest_finalized_state
|
800
|
-
)
|
801
|
-
|
802
|
-
token_amount = int(
|
803
|
-
self._get_bid_suggestion(
|
804
|
-
blockchain_id,
|
805
|
-
additional_epochs,
|
806
|
-
latest_finalized_state_size,
|
807
|
-
content_asset_storage_address,
|
808
|
-
latest_finalized_state,
|
809
|
-
DEFAULT_HASH_FUNCTION_ID,
|
810
|
-
token_amount or BidSuggestionRange.LOW,
|
811
|
-
)["bidSuggestion"]
|
812
|
-
)
|
813
|
-
|
814
|
-
receipt: TxReceipt = self._extend_storing_period(
|
815
|
-
token_id, additional_epochs, token_amount
|
816
|
-
)
|
817
|
-
|
818
|
-
return {
|
819
|
-
"UAL": ual,
|
820
|
-
"operation": json.loads(Web3.to_json(receipt)),
|
821
|
-
}
|
822
|
-
|
823
|
-
_get_block = Method(BlockchainRequest.get_block)
|
824
|
-
|
825
|
-
_get_service_agreement_data = Method(BlockchainRequest.get_service_agreement_data)
|
826
|
-
_get_assertion_size = Method(BlockchainRequest.get_assertion_size)
|
827
|
-
_add_tokens = Method(BlockchainRequest.increase_asset_token_amount)
|
828
|
-
|
829
|
-
def add_tokens(
|
830
|
-
self,
|
831
|
-
ual: UAL,
|
832
|
-
token_amount: Wei | None = None,
|
833
|
-
) -> dict[str, UAL | TxReceipt]:
|
834
|
-
parsed_ual = parse_ual(ual)
|
835
|
-
blockchain_id, content_asset_storage_address, token_id = (
|
836
|
-
parsed_ual["blockchain"],
|
837
|
-
parsed_ual["contract_address"],
|
838
|
-
parsed_ual["token_id"],
|
839
|
-
)
|
840
|
-
|
841
|
-
if token_amount is None:
|
842
|
-
agreement_id = self.get_agreement_id(
|
843
|
-
content_asset_storage_address, token_id
|
844
|
-
)
|
845
|
-
# TODO: Dynamic types for namedtuples?
|
846
|
-
agreement_data: Type[AgreementData] = self._get_service_agreement_data(
|
847
|
-
agreement_id
|
848
|
-
)
|
849
|
-
|
850
|
-
timestamp_now = self._get_block("latest")["timestamp"]
|
851
|
-
current_epoch = math.floor(
|
852
|
-
(timestamp_now - agreement_data.startTime) / agreement_data.epochLength
|
853
|
-
)
|
854
|
-
epochs_left = agreement_data.epochsNumber - current_epoch
|
855
|
-
|
856
|
-
latest_finalized_state = self._get_latest_assertion_id(token_id)
|
857
|
-
latest_finalized_state_size = self._get_assertion_size(
|
858
|
-
latest_finalized_state
|
859
|
-
)
|
860
|
-
|
861
|
-
token_amount = int(
|
862
|
-
self._get_bid_suggestion(
|
863
|
-
blockchain_id,
|
864
|
-
epochs_left,
|
865
|
-
latest_finalized_state_size,
|
866
|
-
content_asset_storage_address,
|
867
|
-
latest_finalized_state,
|
868
|
-
DEFAULT_HASH_FUNCTION_ID,
|
869
|
-
token_amount or BidSuggestionRange.LOW,
|
870
|
-
)["bidSuggestion"]
|
871
|
-
) - sum(agreement_data.tokensInfo)
|
872
|
-
|
873
|
-
if token_amount <= 0:
|
874
|
-
raise InvalidTokenAmount(
|
875
|
-
"Token amount is bigger than default suggested amount, "
|
876
|
-
"please specify exact token_amount if you still want to add "
|
877
|
-
"more tokens!"
|
878
|
-
)
|
879
|
-
|
880
|
-
receipt: TxReceipt = self._add_tokens(token_id, token_amount)
|
881
|
-
|
882
|
-
return {
|
883
|
-
"UAL": ual,
|
884
|
-
"operation": json.loads(Web3.to_json(receipt)),
|
885
|
-
}
|
886
|
-
|
887
|
-
def get_owner(self, ual: UAL) -> Address:
|
888
|
-
token_id = parse_ual(ual)["token_id"]
|
889
|
-
|
890
|
-
return self._owner(token_id)
|
891
|
-
|
892
|
-
_get_assertion_id_by_index = Method(BlockchainRequest.get_assertion_id_by_index)
|
893
|
-
|
894
|
-
def get_agreement_id(self, contract_address: Address, token_id: int) -> HexStr:
|
895
|
-
first_assertion_id = self._get_assertion_id_by_index(token_id, 0)
|
896
|
-
keyword = generate_keyword(contract_address, first_assertion_id)
|
897
|
-
return generate_agreement_id(contract_address, token_id, keyword)
|
898
|
-
|
899
|
-
_get_operation_result = Method(NodeRequest.get_operation_result)
|
900
|
-
|
901
|
-
@retry(catch=OperationNotFinished, max_retries=5, base_delay=1, backoff=2)
|
902
|
-
def get_operation_result(
|
903
|
-
self, operation_id: str, operation: str
|
904
|
-
) -> NodeResponseDict:
|
905
|
-
operation_result = self._get_operation_result(
|
906
|
-
operation_id=operation_id,
|
907
|
-
operation=operation,
|
908
|
-
)
|
909
|
-
|
910
|
-
validate_operation_status(operation_result)
|
911
|
-
|
912
|
-
return operation_result
|