Skip to content

Commit

Permalink
entries: Add support for verification of registry entries
Browse files Browse the repository at this point in the history
Signed-off-by: Shreevatsa N <[email protected]>
  • Loading branch information
vatsa287 committed Nov 6, 2024
1 parent ad58a07 commit 6d2dcd9
Show file tree
Hide file tree
Showing 3 changed files with 293 additions and 4 deletions.
15 changes: 15 additions & 0 deletions demo/src/dedi/registry-entries-tx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,21 @@ async function main() {
);

console.log('\n✅ Registry Entry reinstated!', registryEntryReinstate);

console.log(`\n❄️ Registry Entry verification `)

const verificationResult = await Cord.Entries.verifyAgainstInputProperties(
registryEntry,
updateEntryDigest,
`did:cord:3${authorIdentity.address}`,
registry.uri
)

if (verificationResult.isValid) {
console.log(`✅ Verification successful! "${registryEntry}" 🎉`)
} else {
console.log(`🚫 Verification failed! - "${verificationResult.message}" 🚫`)
}
}

main()
Expand Down
155 changes: 155 additions & 0 deletions packages/entries/src/Entries.chain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
*/
import {
SDKErrors,
DecoderUtils,
} from '@cord.network/utils';


Expand All @@ -49,10 +50,15 @@ import {
CordKeyringPair,
Option,
RegistryAuthorizationUri,
IRegistryEntryChainStorage,
RegistryUri,
DidUri
} from '@cord.network/types';

import { Chain } from '@cord.network/network';

import { encodeAddress } from '@polkadot/util-crypto';

import { ConfigService } from '@cord.network/config'

import type {
Expand All @@ -62,6 +68,7 @@ import type {
import {
uriToIdentifier,
uriToEntryIdAndDigest,
identifierToUri,
} from '@cord.network/identifier'

export async function isRegistryEntryStored(
Expand Down Expand Up @@ -340,3 +347,151 @@ export async function dispatchReinstateEntryToChain(
)
}
}


/**
* Decodes the registry entry details from the blockchain state.
* This function takes an optional encoded entry and an identifier,
* then extracts and formats the relevant properties into a structured object.
*
* @param {Option<PalletEntriesRegistryEntryDetails>} encoded -
* The optional encoded data from the blockchain representing the registry entry details.
* It may contain the entry details or be `None`.
*
* @param {string} identifier -
* The identifier used to generate the URI for the registry entry.
*
* @returns {IRegistryEntryChainStorage | null}
* - Returns an object containing the decoded registry entry details structured as `IRegistryEntryChainStorage`.
* - If the encoded data is `None`, returns `null`.
*
* @example
* // Example Usage:
* const encodedEntryDetails = ... // fetched from the blockchain
* const identifier = "someIdentifier";
*
* const registryEntry = decodeRegistryEntryDetailsFromChain(encodedEntryDetails, identifier);
* console.log(registryEntry); // Outputs the decoded registry entry details.
*
*/
export function decodeRegistryEntryDetailsFromChain(
encoded: Option<PalletEntriesRegistryEntryDetails>,
identifier: string
): IRegistryEntryChainStorage | null {
if (encoded.isNone) {
return null;
}

const chainRegistryEntry = encoded.unwrap();

/*
* Below code block encodes the data from the chain present in raw
* to its respective formats.
*/
const registryEntry: IRegistryEntryChainStorage = {
uri: identifierToUri(identifier) as EntryUri,
digest: chainRegistryEntry.digest.toHex(),
revoked: chainRegistryEntry.revoked.valueOf(),
creatorUri: `did:cord:3${encodeAddress(chainRegistryEntry.creator, 29)}` as DidUri,
registryUri: identifierToUri(
DecoderUtils.hexToString(chainRegistryEntry.registryId.toString())
) as RegistryUri
};

console.log("chainRegistryEntry after", registryEntry);

return registryEntry;
}


/**
* Retrieves the details of a registry entry from the blockchain using the provided identifier.
* This asynchronous function queries the blockchain for the registry entry associated with
* the specified identifier and decodes the details into a structured format.
*
* @param {string} identifier -
* The identifier used to query the registry entry from the blockchain.
*
* @returns {Promise<IRegistryEntryChainStorage | null>}
* - Returns a promise that resolves to an object containing the decoded registry entry details
* structured as `IRegistryEntryChainStorage`.
* - If no entry is found, it throws an error.
*
* @throws {SDKErrors.CordFetchError}
* Throws an error if there is no registry entry associated with the provided identifier.
*
* @example
* // Example Usage:
* const identifier = "someIdentifier";
*
* try {
* const entryDetails = await getDetailsfromChain(identifier);
* console.log(entryDetails); // Outputs the registry entry details.
* } catch (error) {
* console.error(error.message); // Handle the error accordingly.
* }
*
*/
export async function getDetailsfromChain(
identifier: string
): Promise<IRegistryEntryChainStorage | null> {
const api = ConfigService.get('api');
const registryEntryId = uriToIdentifier(identifier);

const registryEntry = await api.query.entries.registryEntries(registryEntryId);

const decodedDetails = decodeRegistryEntryDetailsFromChain(registryEntry, identifier);

if (!decodedDetails) {
throw new SDKErrors.CordFetchError(
`There is no registry entry with the provided ID "${registryEntryId}" present on the chain.`
);
}

return decodedDetails;
}


/**
* Fetches the registry entry details from the blockchain using the specified entry URI.
* This asynchronous function converts the entry URI into its corresponding identifier,
* retrieves the details of the registry entry from the blockchain, and returns them in a
* structured format.
*
* @param {EntryUri} registryEntryUri -
* The URI of the registry entry for which details are to be fetched.
*
* @returns {Promise<IRegistryEntryChainStorage>}
* - Returns a promise that resolves to an object containing the decoded registry entry details
* structured as `IRegistryEntryChainStorage`.
*
* @throws {SDKErrors.CordFetchError}
* Throws an error if no registry entry is found associated with the provided URI.
*
* @example
* // Example Usage:
* const registryEntryUri = "someEntryUri";
*
* try {
* const entryDetails = await fetchRegistryEntryDetailsFromChain(registryEntryUri);
* console.log(entryDetails); // Outputs the registry entry details.
* } catch (error) {
* console.error(error.message); // Handle the error accordingly.
* }
*
*/
export async function fetchRegistryEntryDetailsFromChain(
registryEntryUri: EntryUri
): Promise<IRegistryEntryChainStorage> {
const registryEntryObj = uriToEntryIdAndDigest(registryEntryUri);

const entryDetails = await getDetailsfromChain(registryEntryObj.identifier);

if (!entryDetails) {
throw new SDKErrors.CordFetchError(
`There is no registry entry with the provided ID "${registryEntryObj.identifier}" present on the chain.`
);
}

return entryDetails;
}
127 changes: 123 additions & 4 deletions packages/entries/src/Entries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,21 +47,25 @@ import {
blake2AsHex,
} from "@cord.network/types";

import { SDKErrors } from '@cord.network/utils';

import { DataUtils } from '@cord.network/utils'

import {
SDKErrors,
DataUtils,
} from '@cord.network/utils';
fetchRegistryEntryDetailsFromChain
} from "./Entries.chain";

import {
uriToIdentifier,
updateRegistryEntryUri,
buildRegistryEntryUri,
checkIdentifier,
identifierToUri,
uriToEntryIdAndDigest
} from '@cord.network/identifier';

import { ConfigService } from '@cord.network/config';


/**
* Generates a URI for a registry entry based on its digest, registry URI, and creator's address.
*
Expand Down Expand Up @@ -375,3 +379,118 @@ export async function updateEntriesProperties(

return registryEntryObj
}


/**
* Verifies the input properties of a registry entry URI against its corresponding chain state details.
* This function ensures that the provided digest, creator URI, and registry URI match the data retrieved
* from the blockchain. It also checks if the entry is revoked or if the URIs are mismatched.
*
* @param {EntryUri} registryEntryUri - The element's URI to be verified against the chain's registry entry.
* It should be of the form `entry:cord:IdDigest:Digest`.
* @param {HexString} digest - The expected digest (hash) associated with the registry entry.
* @param {DidUri} [creatorUri] - (Optional) The expected DID of the creator of the registry entry.
* @param {RegistryUri} [registryUri] - (Optional) The expected registry URI associated with the registry entry.
*
* @returns {Promise<{ isValid: boolean; message: string }>}
* - A result object containing:
* - `isValid`: A boolean indicating whether the verification was successful.
* - `message`: A message describing the outcome of the verification.
*
* @throws {Error} - If an unexpected error occurs during the verification process.
*
* @example
* // Example Usage:
* const registryEntryUri = "cord:3xyz123" as EntryUri;
* const digest = "0xabcdef..." as HexString;
* const creatorUri = "did:cord:3F7HsGqJPyz..." as DidUri;
* const registryUri = "cord:registry:xyz" as RegistryUri;
*
* const result = await verifyAgainstInputProperties(
* registryEntryUri,
* digest,
* creatorUri,
* registryUri
* );
*
* console.log(result.isValid); // true or false
* console.log(result.message); // 'Digest properties provided are valid and match...'
*
*/
export async function verifyAgainstInputProperties(
registryEntryUri: EntryUri,
digest: HexString,
creatorUri?: DidUri,
registryUri?: RegistryUri,
): Promise<{ isValid: boolean; message: string }> {
try {
const registryEntryStatus = await fetchRegistryEntryDetailsFromChain(registryEntryUri);
const registryEntryObj = uriToEntryIdAndDigest(registryEntryUri);
const entryUri = identifierToUri(registryEntryObj.identifier);

if (!registryEntryStatus) {
return {
isValid: false,
message: `Registry Entry details for "${digest}" not found.`,
}
}

console.log("uri", entryUri, "digest", digest, "creatorUri", creatorUri, "registryUri", registryUri);

if (digest !== registryEntryStatus.digest) {
return {
isValid: false,
message: 'Digest does not match with Registry Entry Digest.',
}
}

if (registryEntryStatus?.revoked) {
return {
isValid: false,
message: `Registry Entry "${registryEntryUri}" Revoked.`,
}
}

if (entryUri !== registryEntryStatus.uri) {
return {
isValid: false,
message: 'Registry Entry and Chain Entry URI details does not match.',
}
}

if (creatorUri) {
if (creatorUri !== registryEntryStatus.creatorUri) {
return {
isValid: false,
message: 'Registry Entry and Digest creator does not match.',
}
}
}

if (registryUri) {
if (registryUri !== registryEntryStatus.registryUri) {
return {
isValid: false,
message: 'Registry Entry and Chain Registry URI does not match.',
}
}
}

return {
isValid: true,
message:
'Digest properties provided are valid and matches the registry entry details.',
}
} catch (error) {
if (error instanceof Error) {
return {
isValid: false,
message: `Error verifying properties: ${error}`,
}
}
return {
isValid: false,
message: 'An unknown error occurred while verifying the properties.',
}
}
}

0 comments on commit 6d2dcd9

Please sign in to comment.