diff --git a/src/commands/protocols/get/receiver/v1.0.0/v1-0-0-handle-get-request-command.js b/src/commands/protocols/get/receiver/v1.0.0/v1-0-0-handle-get-request-command.js
index 173b42767..14c7e09b6 100644
--- a/src/commands/protocols/get/receiver/v1.0.0/v1-0-0-handle-get-request-command.js
+++ b/src/commands/protocols/get/receiver/v1.0.0/v1-0-0-handle-get-request-command.js
@@ -149,7 +149,7 @@ class HandleGetRequestCommand extends HandleProtocolMessageCommand {
...(includeMetadata && metadata && { metadata }),
};
- if (assertion.length) {
+ if (assertion?.public?.length) {
await this.operationIdService.updateOperationIdStatus(
operationId,
blockchain,
@@ -157,7 +157,7 @@ class HandleGetRequestCommand extends HandleProtocolMessageCommand {
);
}
- return assertion.length
+ return assertion?.public?.length
? { messageType: NETWORK_MESSAGE_TYPES.RESPONSES.ACK, messageData: responseData }
: {
messageType: NETWORK_MESSAGE_TYPES.RESPONSES.NACK,
diff --git a/src/commands/protocols/get/sender/local-get-command.js b/src/commands/protocols/get/sender/local-get-command.js
index 0e501025f..3060c0f98 100644
--- a/src/commands/protocols/get/sender/local-get-command.js
+++ b/src/commands/protocols/get/sender/local-get-command.js
@@ -137,7 +137,7 @@ class LocalGetCommand extends Command {
assertion,
...(includeMetadata && metadata && { metadata }),
};
- if (assertion.length) {
+ if (assertion?.public?.length || assertion?.private?.length) {
await this.operationService.markOperationAsCompleted(
operationId,
blockchain,
diff --git a/src/commands/protocols/get/sender/v1.0.0/v1-0-0-get-request-command.js b/src/commands/protocols/get/sender/v1.0.0/v1-0-0-get-request-command.js
index 9a453f5e5..786001ab3 100644
--- a/src/commands/protocols/get/sender/v1.0.0/v1-0-0-get-request-command.js
+++ b/src/commands/protocols/get/sender/v1.0.0/v1-0-0-get-request-command.js
@@ -62,20 +62,30 @@ class GetRequestCommand extends ProtocolRequestCommand {
}
async handleAck(command, responseData) {
- if (responseData?.assertion) {
- // TODO: Add this validation
- try {
- await this.validationService.validateDatasetOnBlockchain(
- command.data.knowledgeCollectionId,
- responseData.assertion,
- command.data.blockchain,
- );
- } catch (e) {
- return this.handleNack(command, {
- errorMessage: e.message,
- });
- }
+ const { blockchain, contract, knowledgeCollectionId, knowledgeAssetId } = command.data;
+ if (responseData?.assertion?.public) {
+ // Only whole collection can be validated not particular KA
+ if (!knowledgeAssetId) {
+ try {
+ await this.validationService.validateDatasetOnBlockchain(
+ responseData.assertion.public,
+ blockchain,
+ contract,
+ knowledgeCollectionId,
+ );
+ // This is added as support when get starts supporting private for curated paranet
+ if (responseData.assertion?.private?.length)
+ await this.validationService.validatePrivateMerkleRoot(
+ responseData.assertion.public,
+ responseData.assertion.private,
+ );
+ } catch (e) {
+ return this.handleNack(command, {
+ errorMessage: e.message,
+ });
+ }
+ }
await this.operationService.processResponse(
command,
OPERATION_REQUEST_STATUS.COMPLETED,
diff --git a/src/commands/protocols/publish/sender/publish-validate-asset-blockchain-command.js b/src/commands/protocols/publish/sender/publish-validate-asset-blockchain-command.js
index c51f6247c..808629850 100644
--- a/src/commands/protocols/publish/sender/publish-validate-asset-blockchain-command.js
+++ b/src/commands/protocols/publish/sender/publish-validate-asset-blockchain-command.js
@@ -1,11 +1,11 @@
import ValidateAssetCommand from '../../../common/validate-asset-command.js';
-import Command from '../../../command.js';
-import { OPERATION_ID_STATUS, ZERO_BYTES32 } from '../../../../constants/constants.js';
+import { OPERATION_ID_STATUS } from '../../../../constants/constants.js';
class PublishValidateAssetBlockchainCommand extends ValidateAssetCommand {
constructor(ctx) {
super(ctx);
this.operationService = ctx.publishService;
+ this.validationService = ctx.validationService;
}
async handleError(operationId, blockchain, errorMessage, errorType) {
@@ -29,37 +29,17 @@ class PublishValidateAssetBlockchainCommand extends ValidateAssetCommand {
blockchain,
OPERATION_ID_STATUS.VALIDATE_ASSET_BLOCKCHAIN_START,
);
-
- const blockchainAssertionId =
- await this.blockchainModuleManager.getKnowledgeCollectionMerkleRoot(
- blockchain,
- contract,
- tokenId,
- );
- if (!blockchainAssertionId || blockchainAssertionId === ZERO_BYTES32) {
- return Command.retry();
- }
-
- const { dataset: cachedData } = await this.operationIdService.getCachedOperationIdData(
- operationId,
- );
const ual = this.ualService.deriveUAL(blockchain, contract, tokenId);
this.logger.debug(
`Validating asset's public assertion with id: ${datasetRoot} ual: ${ual}`,
);
- if (blockchainAssertionId !== datasetRoot) {
- await this.handleError(
- operationId,
- blockchain,
- `Invalid assertion id for asset ${ual}. Received value from blockchain: ${blockchainAssertionId}, received value from request: ${datasetRoot}`,
- this.errorType,
- true,
- );
- return Command.empty();
- }
-
- await this.validationService.validateDatasetRoot(cachedData, datasetRoot);
+ await this.validationService.validateDatasetRootOnBlockchain(
+ datasetRoot,
+ blockchain,
+ contract,
+ tokenId,
+ );
await this.operationIdService.updateOperationIdStatus(
operationId,
diff --git a/src/commands/protocols/publish/sender/publish-validate-asset-command.js b/src/commands/protocols/publish/sender/publish-validate-asset-command.js
index d6e1fa84c..bfdce4339 100644
--- a/src/commands/protocols/publish/sender/publish-validate-asset-command.js
+++ b/src/commands/protocols/publish/sender/publish-validate-asset-command.js
@@ -5,7 +5,6 @@ import {
ERROR_TYPE,
LOCAL_STORE_TYPES,
PARANET_ACCESS_POLICY,
- PRIVATE_ASSERTION_PREDICATE,
} from '../../../../constants/constants.js';
class PublishValidateAssetCommand extends ValidateAssetCommand {
@@ -62,18 +61,11 @@ class PublishValidateAssetCommand extends ValidateAssetCommand {
);
await this.validationService.validateDatasetRoot(cachedData.dataset.public, datasetRoot);
- const privateAssertionTriple = cachedData.dataset.public.find((triple) =>
- triple.includes(PRIVATE_ASSERTION_PREDICATE),
- );
-
- if (privateAssertionTriple) {
- const privateAssertionRoot = privateAssertionTriple.split(' ')[2].slice(1, -1);
-
- await this.validationService.validateDatasetRoot(
+ if (cachedData.dataset?.private?.length)
+ await this.validationService.validatePrivateMerkleRoot(
+ cachedData.dataset.public,
cachedData.dataset.private,
- privateAssertionRoot,
);
- }
this.operationIdService.emitChangeEvent(
OPERATION_ID_STATUS.PUBLISH.PUBLISH_VALIDATE_DATASET_ROOT_END,
diff --git a/src/modules/triple-store/implementation/ot-triple-store.js b/src/modules/triple-store/implementation/ot-triple-store.js
index 2051af4f3..66d90fb03 100644
--- a/src/modules/triple-store/implementation/ot-triple-store.js
+++ b/src/modules/triple-store/implementation/ot-triple-store.js
@@ -291,35 +291,56 @@ class OtTripleStore {
await this.queryVoid(repository, query);
}
- async getKnowledgeCollectionNamedGraphs(repository, ual, visibility, sort) {
- let visibilityFilter;
- switch (visibility) {
- case TRIPLES_VISIBILITY.PUBLIC:
- case TRIPLES_VISIBILITY.PRIVATE:
- visibilityFilter = `&& STRENDS(STR(?g), "${visibility}")`;
- break;
- case TRIPLES_VISIBILITY.ALL:
- visibilityFilter = '';
- break;
- default:
- throw new Error(`Unsupported visibility: ${visibility}`);
- }
- const query = `
- PREFIX schema: <${SCHEMA_CONTEXT}>
- CONSTRUCT { ?s ?p ?o . }
+ async getKnowledgeCollectionNamedGraphs(repository, ual, visibility) {
+ const assertion = {};
+ if (visibility === TRIPLES_VISIBILITY.PUBLIC || visibility === TRIPLES_VISIBILITY.ALL) {
+ const query = `
+ PREFIX schema:
+ CONSTRUCT {
+ ?s ?p ?o .
+ }
WHERE {
- GRAPH ?g {
+ {
+ SELECT ?s ?p ?o ?g
+ WHERE {
+ GRAPH ?g {
+ ?s ?p ?o .
+ }
+ FILTER (
+ STRSTARTS(STR(?g), "${ual}")
+ && STRENDS(STR(?g), "${TRIPLES_VISIBILITY.PUBLIC}")
+ )
+ }
+ ORDER BY ?g ?s ?p ?o
+ }
+ }`;
+ assertion.public = await this.construct(repository, query);
+ }
+ if (visibility === TRIPLES_VISIBILITY.PRIVATE || visibility === TRIPLES_VISIBILITY.ALL) {
+ const query = `
+ PREFIX schema:
+ CONSTRUCT {
?s ?p ?o .
}
- FILTER(
- STRSTARTS(STR(?g), "${ual}/")
- ${visibilityFilter}
- )
- }
- ${sort ? 'ORDER BY ?s' : ''}
- `;
+ WHERE {
+ {
+ SELECT ?s ?p ?o ?g
+ WHERE {
+ GRAPH ?g {
+ ?s ?p ?o .
+ }
+ FILTER (
+ STRSTARTS(STR(?g), "${ual}")
+ && STRENDS(STR(?g), "${TRIPLES_VISIBILITY.PRIVATE}")
+ )
+ }
+ ORDER BY ?g ?s ?p ?o
+ }
+ }`;
+ assertion.private = await this.construct(repository, query);
+ }
- return this.construct(repository, query);
+ return assertion;
}
async knowledgeCollectionNamedGraphsExist(repository, ual) {
diff --git a/src/service/triple-store-service.js b/src/service/triple-store-service.js
index 57fab6bfb..a45d654da 100644
--- a/src/service/triple-store-service.js
+++ b/src/service/triple-store-service.js
@@ -419,18 +419,24 @@ class TripleStoreService {
visibility,
);
}
+ if (nquads?.public) {
+ nquads.public = nquads.public.split('\n').filter((line) => line !== '');
+ }
+ if (nquads?.private) {
+ nquads.private = nquads.private.split('\n').filter((line) => line !== '');
+ }
- nquads = nquads.split('\n').filter((line) => line !== '');
+ const numberOfnquads = (nquads?.public?.length ?? 0) + (nquads?.private?.length ?? 0);
this.logger.debug(
`Assertion: ${ual} ${
- nquads.length ? '' : 'is not'
+ numberOfnquads ? '' : 'is not'
} found in the Triple Store's ${repository} repository.`,
);
if (nquads.length) {
this.logger.debug(
- `Number of n-quads retrieved from the Triple Store's ${repository} repository: ${nquads.length}.`,
+ `Number of n-quads retrieved from the Triple Store's ${repository} repository: ${numberOfnquads}.`,
);
}
diff --git a/src/service/validation-service.js b/src/service/validation-service.js
index 743d49c4b..286f483ca 100644
--- a/src/service/validation-service.js
+++ b/src/service/validation-service.js
@@ -1,4 +1,4 @@
-import { ZERO_ADDRESS } from '../constants/constants.js';
+import { ZERO_ADDRESS, PRIVATE_ASSERTION_PREDICATE } from '../constants/constants.js';
class ValidationService {
constructor(ctx) {
@@ -38,15 +38,43 @@ class ValidationService {
this.logger.info(`Assertion integrity validated! AssertionId: ${assertionId}`);
}
- async validateDatasetRootOnBlockchain(knowledgeCollectionId, assertionId, blockchain) {
- // TODO: call contract TO DO, dont return anything or return true
- return { knowledgeCollectionId, assertionId, blockchain };
+ async validateDatasetRootOnBlockchain(
+ knowledgeCollectionMerkleRoot,
+ blockchain,
+ assetStorageContractAddress,
+ knowledgeCollectionId,
+ ) {
+ const blockchainAssertionRoot =
+ await this.blockchainModuleManager.getKnowledgeCollectionLatestMerkleRoot(
+ blockchain,
+ assetStorageContractAddress,
+ knowledgeCollectionId,
+ );
+
+ if (knowledgeCollectionMerkleRoot !== blockchainAssertionRoot) {
+ throw new Error(
+ `Merkle Root validation failed. Merkle Root on chain: ${blockchainAssertionRoot}; Calculated Merkle Root: ${knowledgeCollectionMerkleRoot}`,
+ );
+ }
}
- async validateDatasetOnBlockchain(knowledgeCollectionId, assertion, blockchain) {
- const assertionId = await this.validationModuleManager.calculateRoot(assertion);
+ // Used to validate assertion node received through network get
+ async validateDatasetOnBlockchain(
+ assertion,
+ blockchain,
+ assetStorageContractAddress,
+ knowledgeCollectionId,
+ ) {
+ const knowledgeCollectionMerkleRoot = await this.validationModuleManager.calculateRoot(
+ assertion,
+ );
- await this.validateDatasetRootOnBlockchain(knowledgeCollectionId, assertionId, blockchain);
+ await this.validateDatasetRootOnBlockchain(
+ knowledgeCollectionMerkleRoot,
+ blockchain,
+ assetStorageContractAddress,
+ knowledgeCollectionId,
+ );
}
async validateDatasetRoot(dataset, datasetRoot) {
@@ -58,6 +86,22 @@ class ValidationService {
);
}
}
+
+ async validatePrivateMerkleRoot(publicAssertion, privateAssertion) {
+ const privateAssertionTriple = publicAssertion.find((triple) =>
+ triple.includes(PRIVATE_ASSERTION_PREDICATE),
+ );
+
+ if (privateAssertionTriple) {
+ const privateAssertionRoot = privateAssertionTriple.split(' ')[2].slice(1, -1);
+
+ await this.validateDatasetRoot(privateAssertion, privateAssertionRoot);
+ } else {
+ throw new Error(
+ `Merkle Root validation failed. Private Merkle Root not present in public assertion.`,
+ );
+ }
+ }
}
export default ValidationService;