diff --git a/config/config.json b/config/config.json index a7e8345980..fed029d00b 100644 --- a/config/config.json +++ b/config/config.json @@ -743,7 +743,7 @@ "enabled": false, "package": "./blockchain/implementation/gnosis/gnosis-service.js", "config": { - "hubContractAddress": "", + "hubContractAddress": "0xbEF14fc04F870c2dD65c13Df4faB6ba01A9c746b", "gasPriceOracleLink": "https://api.gnosisscan.io/api?module=proxy&action=eth_gasPrice", "rpcEndpoints": ["https://rpc.gnosischain.com/"] } diff --git a/installer/installer.sh b/installer/installer.sh index dda03af907..6861d7f059 100755 --- a/installer/installer.sh +++ b/installer/installer.sh @@ -253,60 +253,67 @@ install_node() { # Change directory to ot-node/current cd $OTNODE_DIR - #request node env - read -p "Please select node environment: (Default: Mainnet) [T]estnet [M]ainnet [E]xit " choice + # Request node env with strict input validation + while true; do + read -p "Please select node environment: (Default: Mainnet) [T]estnet [M]ainnet [E]xit " choice case "$choice" in - [tT]* ) nodeEnv="testnet";; - [eE]* ) text_color $RED"Installer stopped by user"; exit;; - * ) nodeEnv="mainnet";; + [tT]* ) nodeEnv="testnet"; break;; + [mM]* ) nodeEnv="mainnet"; break;; + [eE]* ) text_color $RED "Installer stopped by user"; exit;; + * ) text_color $RED "Invalid choice. Please enter either [T]estnet, [M]ainnet, or [E]xit."; continue;; esac + done echo "NODE_ENV=$nodeEnv" >> $OTNODE_DIR/.env - #blockchains=("otp" "polygon") - #for ((i = 0; i < ${#blockchains[@]}; ++i)); - #do - # read -p "Do you want to connect your node to blockchain: ${blockchains[$i]} ? [Y]Yes [N]No [E]Exit: " choice - # case "$choice" in - # [Yy]* ) - - # read -p "Enter your substrate operational wallet address: " SUBSTRATE_OPERATIONAL_WALLET - # echo "Substrate operational wallet address: $SUBSTRATE_OPERATIONAL_WALLET" - - # read -p "Enter your substrate operational wallet private key: " SUBSTRATE_OPERATIONAL_PRIVATE_KEY - # echo "Substrate operational wallet private key: $SUBSTRATE_OPERATIONAL_PRIVATE_KEY" - - read -p "Enter your EVM operational wallet address: " EVM_OPERATIONAL_WALLET - text_color $GREEN "EVM operational wallet address: $EVM_OPERATIONAL_WALLET" + # Blockchains prompt based on the selected environment + if [ "$nodeEnv" == "mainnet" ]; then + blockchain_prompt=("OriginTrail Parachain") + elif [ "$nodeEnv" == "testnet" ]; then + blockchain_prompt=("OriginTrail Parachain") + fi - read -p "Enter your EVM operational wallet private key: " EVM_OPERATIONAL_PRIVATE_KEY - text_color $GREEN "EVM operational wallet private key: $EVM_OPERATIONAL_PRIVATE_KEY" + # Ask user which blockchain to connect to with strict input validation + while true; do + read -p "Please select the blockchain you want to connect your node to: + 1. ${blockchain_prompt[0]} + Your choice: " blockchain_choice + + case "$blockchain_choice" in + [1]* ) blockchain="${blockchain_prompt[0]}"; break;; + [eE]* ) text_color $RED "Installer stopped by user"; exit;; + * ) text_color $RED "Invalid choice. Please enter a valid number."; continue;; + esac + done - # read -p "Enter your substrate management wallet address: " SUBSTRATE_MANAGEMENT_WALLET - # echo "Substrate management wallet address: $SUBSTRATE_MANAGEMENT_WALLET" + # Case statement to handle blockchain-specific configurations + case "$blockchain" in + "OriginTrail Parachain") + # Input wallets for the selected blockchain + read -p "Enter your EVM operational wallet address for $blockchain: " EVM_OPERATIONAL_WALLET + text_color $GREEN "EVM operational wallet address for $blockchain: $EVM_OPERATIONAL_WALLET" - # read -p "Enter your substrate management wallet private key: " SUBSTRATE_MANAGEMENT_WALLET_PRIVATE_KEY - # echo "Substrate management wallet private key: $SUBSTRATE_MANAGEMENT_WALLET_PRIVATE_KEY" + read -p "Enter your EVM operational wallet private key for $blockchain: " EVM_OPERATIONAL_PRIVATE_KEY + text_color $GREEN "EVM operational wallet private key for $blockchain: $EVM_OPERATIONAL_PRIVATE_KEY" - read -p "Enter your EVM management wallet address: " EVM_MANAGEMENT_WALLET - text_color $GREEN "EVM management wallet address: $EVM_MANAGEMENT_WALLET" + read -p "Enter your EVM management wallet address for $blockchain: " EVM_MANAGEMENT_WALLET + text_color $GREEN "EVM management wallet address for $blockchain: $EVM_MANAGEMENT_WALLET" - read -p "Enter your profile shares token name: " SHARES_TOKEN_NAME - text_color $GREEN "Profile shares token name: $SHARES_TOKEN_NAME" + read -p "Enter your profile shares token name for $blockchain: " SHARES_TOKEN_NAME + text_color $GREEN "Profile shares token name for $blockchain: $SHARES_TOKEN_NAME" - read -p "Enter your profile shares token symbol: " SHARES_TOKEN_SYMBOL - text_color $GREEN "Profile shares token name: $SHARES_TOKEN_SYMBOL" - # ;; - # [Nn]* ) ;; - # [Ee]* ) echo "Installer stopped by user"; exit;; - # * ) ((--i));echo "Please make a valid choice and try again.";; - #esac - #done + read -p "Enter your profile shares token symbol for $blockchain: " SHARES_TOKEN_SYMBOL + text_color $GREEN "Profile shares token symbol for $blockchain: $SHARES_TOKEN_SYMBOL" + ;; + * ) + text_color $RED "Invalid blockchain choice. Exiting installer." + exit;; + esac - perform_step npm ci --omit=dev --ignore-scripts "Executing npm install" + perform_step npm ci --omit=dev --ignore-scripts "Executing npm install" - CONFIG_DIR=$OTNODE_DIR/.. - perform_step touch $CONFIG_DIR/.origintrail_noderc "Configuring node config file" - perform_step $(jq --null-input --arg tripleStore "$tripleStore" '{"logLevel": "trace", "auth": {"ipWhitelist": ["::1", "127.0.0.1"]}}' > $CONFIG_DIR/.origintrail_noderc) "Adding loglevel and auth values to node config file" + CONFIG_DIR=$OTNODE_DIR/.. + perform_step touch $CONFIG_DIR/.origintrail_noderc "Configuring node config file" + perform_step $(jq --null-input --arg tripleStore "$tripleStore" '{"logLevel": "trace", "auth": {"ipWhitelist": ["::1", "127.0.0.1"]}}' > $CONFIG_DIR/.origintrail_noderc) "Adding loglevel and auth values to node config file" perform_step $(jq --arg tripleStore "$tripleStore" --arg tripleStoreUrl "$tripleStoreUrl" '.modules.tripleStore.implementation[$tripleStore] |= { @@ -343,16 +350,38 @@ install_node() { perform_step mv $CONFIG_DIR/origintrail_noderc_tmp $CONFIG_DIR/.origintrail_noderc "Adding node wallets to node config file 2/2" - perform_step $(jq --arg blockchain "otp" --arg evmOperationalWallet "$EVM_OPERATIONAL_WALLET" --arg evmOperationalWalletPrivateKey "$EVM_OPERATIONAL_PRIVATE_KEY" --arg evmManagementWallet "$EVM_MANAGEMENT_WALLET" --arg evmManagementWallet "$SHARES_TOKEN_NAME" --arg evmManagementWallet "$SHARES_TOKEN_SYMBOL" --arg sharesTokenName "$SHARES_TOKEN_NAME" --arg sharesTokenSymbol "$SHARES_TOKEN_SYMBOL" '.modules.blockchain.implementation[$blockchain].config |= - { - "evmOperationalWalletPublicKey": $evmOperationalWallet, - "evmOperationalWalletPrivateKey": $evmOperationalWalletPrivateKey, - "evmManagementWalletPublicKey": $evmManagementWallet, - "sharesTokenName": $sharesTokenName, - "sharesTokenSymbol": $sharesTokenSymbol - } + .' $CONFIG_DIR/.origintrail_noderc > $CONFIG_DIR/origintrail_noderc_tmp) "Adding node wallets to node config file 1/2" + # Set blockchain IDs based on the environment + if [ "$nodeEnv" == "mainnet" ]; then + otp_blockchain_id=2043 + else + otp_blockchain_id=20430 + fi - perform_step mv $CONFIG_DIR/origintrail_noderc_tmp $CONFIG_DIR/.origintrail_noderc "Adding node wallets to node config file 2/2" + + + # Single blockchain selected + if [ "$blockchain" = "OriginTrail Parachain" ]; then + blockchain="otp" + blockchain_id="$otp_blockchain_id" + fi + + blockchain_arg="$blockchain:$blockchain_id" + + perform_step $(jq --arg blockchain_arg "$blockchain_arg" --arg EVM_OPERATIONAL_WALLET "$EVM_OPERATIONAL_WALLET" --arg EVM_OPERATIONAL_PRIVATE_KEY "$EVM_OPERATIONAL_PRIVATE_KEY" --arg EVM_MANAGEMENT_WALLET "$EVM_MANAGEMENT_WALLET" --arg SHARES_TOKEN_NAME "$SHARES_TOKEN_NAME" --arg SHARES_TOKEN_SYMBOL "$SHARES_TOKEN_SYMBOL" ' + .modules.blockchain.implementation += { + ($blockchain_arg): { + "enabled": true, + "config": { + "evmOperationalWalletPublicKey": $EVM_OPERATIONAL_WALLET, + "evmOperationalWalletPrivateKey": $EVM_OPERATIONAL_PRIVATE_KEY, + "evmManagementWalletPublicKey": $EVM_MANAGEMENT_WALLET, + "sharesTokenName": $SHARES_TOKEN_NAME, + "sharesTokenSymbol": $SHARES_TOKEN_SYMBOL + } + } + }' "$CONFIG_DIR/.origintrail_noderc" > "$CONFIG_DIR/origintrail_noderc_tmp") "Adding node wallets to node config file 1/2" + + perform_step mv $CONFIG_DIR/origintrail_noderc_tmp $CONFIG_DIR/.origintrail_noderc "Adding node wallets to node config file 2/2" perform_step cp $OTNODE_DIR/installer/data/otnode.service /lib/systemd/system/ "Copying otnode service file" @@ -449,6 +478,9 @@ install_node header_color $BGREEN"INSTALLATION COMPLETE !" +rm -r /root/ot-node-6-release-testnet +journalctl -u otnode --output cat -fn 200 + text_color $GREEN " New aliases added: otnode-restart @@ -466,5 +498,3 @@ If the logs do not show and the screen hangs, press ctrl+c to exit the installat " read -p "Press enter to continue..." - -journalctl -u otnode --output cat -fn 200 diff --git a/ot-node.js b/ot-node.js index 3595e5495d..e2e59b0224 100644 --- a/ot-node.js +++ b/ot-node.js @@ -28,14 +28,6 @@ class OTNode { await this.checkForUpdate(); await this.removeUpdateFile(); - await MigrationExecutor.executeTripleStoreUserConfigurationMigration( - this.logger, - this.config, - ); - await MigrationExecutor.executeTelemetryModuleUserConfigurationMigration( - this.logger, - this.config, - ); await MigrationExecutor.executeUalExtensionUserConfigurationMigration( this.logger, this.config, @@ -57,43 +49,6 @@ class OTNode { await this.initializeModules(); - await MigrationExecutor.executePullShardingTableMigration( - this.container, - this.logger, - this.config, - ); - await MigrationExecutor.executePrivateAssetsMetadataMigration( - this.container, - this.logger, - this.config, - ); - await MigrationExecutor.executeRemoveAgreementStartEndTimeMigration( - this.container, - this.logger, - this.config, - ); - await MigrationExecutor.executeMarkOldBlockchainEventsAsProcessedMigration( - this.container, - this.logger, - this.config, - ); - await MigrationExecutor.executeTripleStoreMetadataMigration( - this.container, - this.logger, - this.config, - ); - await MigrationExecutor.executeServiceAgreementsMetadataMigration( - this.container, - this.logger, - this.config, - ); - await MigrationExecutor.executeRemoveOldEpochCommandsMigration( - this.container, - this.logger, - this.config, - ); - await MigrationExecutor.executePendingStorageMigration(this.logger, this.config); - await this.createProfiles(); await this.initializeCommandExecutor(); diff --git a/package-lock.json b/package-lock.json index 96ed40c12e..43c41e49d3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "origintrail_node", - "version": "6.1.0", + "version": "6.1.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "origintrail_node", - "version": "6.1.0", + "version": "6.1.1", "license": "ISC", "dependencies": { "@comunica/query-sparql": "^2.4.3", diff --git a/package.json b/package.json index 04b8a57868..7ddcc1b845 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "origintrail_node", - "version": "6.1.0", + "version": "6.1.1", "description": "OTNode V6", "main": "index.js", "type": "module", diff --git a/src/constants/constants.js b/src/constants/constants.js index ea9f47e221..052f17df4c 100644 --- a/src/constants/constants.js +++ b/src/constants/constants.js @@ -554,6 +554,8 @@ export const CONTRACTS = { HUB_CONTRACT: 'HubContract', COMMIT_MANAGER_V1_U1_CONTRACT: 'CommitManagerV1U1Contract', SERVICE_AGREEMENT_V1_CONTRACT: 'ServiceAgreementV1Contract', + PARAMETERS_STORAGE_CONTRACT: 'ParametersStorageContract', + IDENTITY_STORAGE_CONTRACT: 'IdentityStorageContract', }; export const CONTRACT_EVENTS = { @@ -563,6 +565,7 @@ export const CONTRACT_EVENTS = { PROFILE: ['AskUpdated'], COMMIT_MANAGER_V1: ['StateFinalized'], SERVICE_AGREEMENT_V1: ['ServiceAgreementV1Extended', 'ServiceAgreementV1Terminated'], + PARAMETERS_STORAGE: ['ParameterChanged'], }; export const NODE_ENVIRONMENTS = { @@ -586,3 +589,30 @@ export const BLOCK_TIME_MILLIS = { }; export const TRANSACTION_CONFIRMATIONS = 1; + +export const CACHE_DATA_TYPES = { + NUMBER: 'number', +}; + +/** + * CACHED_FUNCTIONS: + * ContractName: { + * functionName: returnType + * } + * @type {{IdentityStorageContract: [{name: string, type: string}], ParametersStorageContract: *}} + */ +export const CACHED_FUNCTIONS = { + ParametersStorageContract: { + r0: CACHE_DATA_TYPES.NUMBER, + r1: CACHE_DATA_TYPES.NUMBER, + r2: CACHE_DATA_TYPES.NUMBER, + finalizationCommitsNumber: CACHE_DATA_TYPES.NUMBER, + updateCommitWindowDuration: CACHE_DATA_TYPES.NUMBER, + commitWindowDurationPerc: CACHE_DATA_TYPES.NUMBER, + proofWindowDurationPerc: CACHE_DATA_TYPES.NUMBER, + epochLength: CACHE_DATA_TYPES.NUMBER, + }, + IdentityStorageContract: { + getIdentityId: CACHE_DATA_TYPES.NUMBER, + }, +}; diff --git a/src/controllers/http-api/v0/bid-suggestion-http-api-controller-v0.js b/src/controllers/http-api/v0/bid-suggestion-http-api-controller-v0.js index e41932c32b..4d711228fa 100644 --- a/src/controllers/http-api/v0/bid-suggestion-http-api-controller-v0.js +++ b/src/controllers/http-api/v0/bid-suggestion-http-api-controller-v0.js @@ -9,11 +9,15 @@ class BidSuggestionController extends BaseController { } async handleRequest(req, res) { - if ((await this.repositoryModuleManager.getPeersCount(req.query.blockchain)) === 0) - this.returnResponse(res, 400, { - code: 400, - message: 'Empty Sharding Table', + if ((await this.repositoryModuleManager.getPeersCount(req.query.blockchain)) === 0) { + const message = `Unable to get bid suggestion. Empty sharding table for blockchain id: ${req.query.blockchain}`; + this.logger.error(message); + this.returnResponse(res, 406, { + code: 406, + message, }); + return; + } // Uncomment when switch to ethers.js // if ( @@ -45,17 +49,24 @@ class BidSuggestionController extends BaseController { firstAssertionId, hashFunctionId, } = req.query; - - this.returnResponse(res, 200, { - bidSuggestion: await this.shardingTableService.getBidSuggestion( + try { + const bidSuggestion = await this.shardingTableService.getBidSuggestion( blockchain, epochsNumber, assertionSize, contentAssetStorageAddress, firstAssertionId, hashFunctionId, - ), - }); + ); + + this.returnResponse(res, 200, { bidSuggestion }); + } catch (error) { + this.logger.error(`Unable to get bid suggestion. Error: ${error}`); + this.returnResponse(res, 500, { + code: 500, + message: 'Unable to calculate bid suggestion', + }); + } } } diff --git a/src/migration/ual-extension-triple-store-migration.js b/src/migration/ual-extension-triple-store-migration.js index 32821b6973..4709c6133b 100644 --- a/src/migration/ual-extension-triple-store-migration.js +++ b/src/migration/ual-extension-triple-store-migration.js @@ -1,3 +1,4 @@ +/* eslint-disable no-await-in-loop */ import BaseMigration from './base-migration.js'; import { TRIPLE_STORE_REPOSITORIES } from '../constants/constants.js'; @@ -22,181 +23,57 @@ class UalExtensionTripleStoreMigration extends BaseMigration { const chunkSize = 10000; - const totalSubjectsQuery = ` - SELECT (COUNT(*) AS ?totalObjects) - WHERE { - GRAPH { - ?s ?p ?o . - FILTER (STRSTARTS(STR(?s), "did:dkg:${oldBlockchainId}/")) - } - }`; - - const totalObjectsQuery = ` - SELECT (COUNT(*) AS ?totalObjects) - WHERE { - ?s ?p ?o . - FILTER(STRENDS(STR(?p), "blockchain") && STRENDS(STR(?o), "${oldBlockchainId}")) - } - - `; - const updateSubjectQuery = ` - WITH - DELETE { - ?s ?p ?o - } - INSERT { - ?newSubject ?p ?o - } - WHERE { - { - SELECT ?s ?p ?o (IRI(REPLACE(STR(?s), "${oldBlockchainId}", "${newBlockchainId}")) AS ?newSubject) - WHERE { - ?s ?p ?o . - FILTER (STRSTARTS(STR(?s), "did:dkg:${oldBlockchainId}/")) - } - LIMIT ${chunkSize} - } - } - `; - const updateObjectQuery = ` - WITH - DELETE { - ?s ?p ?o - } - INSERT { - ?s ?p "${newBlockchainId}" . - } - WHERE { - SELECT ?s ?p ?o - WHERE { - ?s ?p ?o . - FILTER(STRENDS(STR(?p), "blockchain") && STRENDS(STR(?o), "${oldBlockchainId}")) - } - LIMIT ${chunkSize} - } - `; for (const repository in TRIPLE_STORE_REPOSITORIES) { - // eslint-disable-next-line no-await-in-loop - const totalSubjectsResult = await this.tripleStoreService.select( - TRIPLE_STORE_REPOSITORIES[repository], - totalSubjectsQuery, - ); - const totalSubjects = parseInt( - totalSubjectsResult[0].totalObjects.match( - /"(\d+)"\^\^http:\/\/www.w3.org\/2001\/XMLSchema#integer/, - )[1], - 10, - ); - this.logger.debug( - `Total number of triple store subjects that will be updated: ${totalSubjects} in repositroy: ${repository}.`, - ); - let offsetSubject = 0; - if (totalSubjects !== 0) { - do { - // eslint-disable-next-line no-await-in-loop - await this.tripleStoreService.queryVoid( - TRIPLE_STORE_REPOSITORIES[repository], - updateSubjectQuery, - ); + const getUalListQuery = ` + PREFIX schema: + SELECT DISTINCT ?subject ?object + WHERE { + ?subject schema:assertion ?object . + }`; - offsetSubject += chunkSize; - this.logger.debug( - `Number of subjects updated: ${offsetSubject} in repository ${repository}`, - ); - } while (offsetSubject < totalSubjects); - this.logger.debug( - `Finalised triple store subject update in repository: ${repository}.`, - ); - } - // eslint-disable-next-line no-await-in-loop - const totalObjectsResult = await this.tripleStoreService.select( + const ualList = await this.tripleStoreService.select( TRIPLE_STORE_REPOSITORIES[repository], - totalObjectsQuery, + getUalListQuery, ); - const totalObjects = parseInt( - totalObjectsResult[0].totalObjects.match( - /"(\d+)"\^\^http:\/\/www.w3.org\/2001\/XMLSchema#integer/, - )[1], - 10, - ); - let offsetObject = 0; - this.logger.debug( - `Total number of triple store object that will be updated: ${totalObjects} in repositroy: ${repository}.`, + + this.logger.info( + `Ual extension triple store migration: found ${ualList.length} distinct UALs in ${repository}`, ); - if (totalObjects !== 0) { - do { - // eslint-disable-next-line no-await-in-loop - await this.tripleStoreService.queryVoid( - TRIPLE_STORE_REPOSITORIES[repository], - updateObjectQuery, - ); + const subjectsSet = new Set(ualList.map((item) => item.subject)); + const newTriples = []; + for (const { subject: ual, object: assertionId } of ualList) { + if (assertionId.startsWith('assertion:')) { + let newUal; + if (ual.includes(newBlockchainId)) { + newUal = ual.replace(newBlockchainId, oldBlockchainId); + } else { + newUal = ual.replace(oldBlockchainId, newBlockchainId); + } + if (!subjectsSet.has(newUal)) { + newTriples.push(`<${newUal}> schema:assertion <${assertionId}>`); + } + } + } - offsetObject += chunkSize; - this.logger.debug( - `Number of objects updated: ${offsetObject} in repository ${repository}`, - ); - } while (offsetObject < totalObjects); - this.logger.debug( - `Finalised triple store object update in repository: ${repository}.`, + while (newTriples.length) { + const triplesForInsert = newTriples.splice(0, chunkSize); + const insertQuery = ` + PREFIX schema: + INSERT DATA { + GRAPH { + ${triplesForInsert.join(' .\n')} + } + }`; + await this.tripleStoreService.queryVoid( + TRIPLE_STORE_REPOSITORIES[repository], + insertQuery, + ); + this.logger.info( + `Inserted ${triplesForInsert.length} triples, left for insert: ${newTriples.length} repository: ${repository}`, ); } + this.logger.info(`Finished processing of UALs in repository: ${repository}`); } - // for (const repository in TRIPLE_STORE_REPOSITORIES) { - // const countOldSujbectQuerry = `SELECT (COUNT(*) AS ?count) - // WHERE { - // ?s ?p ?o . - // FILTER (STRSTARTS(STR(?s), "did:dkg:otp/")) - // }`; - // // eslint-disable-next-line no-await-in-loop - // const countOldSujbectResult = await this.tripleStoreModuleManager.select( - // this.repositoryImplementations[repository], - // TRIPLE_STORE_REPOSITORIES[repository], - // countOldSujbectQuerry, - // ); - // const countNewSujbectQuerry = `SELECT (COUNT(*) AS ?count) - // WHERE { - // ?s ?p ?o . - // FILTER (STRSTARTS(STR(?s), "did:dkg:otp:2160/")) - // }`; - // // eslint-disable-next-line no-await-in-loop - // const countNewSujbectQuerryResult = await this.tripleStoreModuleManager.select( - // this.repositoryImplementations[repository], - // TRIPLE_STORE_REPOSITORIES[repository], - // countNewSujbectQuerry, - // ); - // - // const countOldObjectsQuery = `SELECT (COUNT(*) AS ?count) - // WHERE { - // ?s ?p ?o . - // FILTER(STRENDS(STR(?p), "blockchain") && STRENDS(STR(?o), "otp")) - // }`; - // // eslint-disable-next-line no-await-in-loop - // const countOldObjectsQueryResult = await this.tripleStoreModuleManager.select( - // this.repositoryImplementations[repository], - // TRIPLE_STORE_REPOSITORIES[repository], - // countOldObjectsQuery, - // ); - // const countNewObjectQuery = `SELECT (COUNT(*) AS ?count) - // WHERE { - // ?s ?p ?o . - // FILTER(STRENDS(STR(?p), "blockchain") && STRENDS(STR(?o), "otp:2160")) - // }`; - // // eslint-disable-next-line no-await-in-loop - // const countNewObjectQueryResult = await this.tripleStoreModuleManager.select( - // this.repositoryImplementations[repository], - // TRIPLE_STORE_REPOSITORIES[repository], - // countNewObjectQuery, - // ); - // this.logger.debug( - // `Report for UAL extentsion triple store migragrion on repository: ${repository}. Old subject count: ${JSON.stringify( - // countOldSujbectResult, - // )}. New subject count: ${JSON.stringify( - // countNewSujbectQuerryResult, - // )}. Old object count: ${JSON.stringify( - // countOldObjectsQueryResult, - // )}. New object count: ${JSON.stringify(countNewObjectQueryResult)}.`, - // ); - // } } getOldBlockchainId() { diff --git a/src/modules/blockchain/blockchain-module-manager.js b/src/modules/blockchain/blockchain-module-manager.js index d7b8b98c19..dfce41cee5 100644 --- a/src/modules/blockchain/blockchain-module-manager.js +++ b/src/modules/blockchain/blockchain-module-manager.js @@ -26,6 +26,14 @@ class BlockchainModuleManager extends BaseModuleManager { ]); } + setContractCallCache(blockchain, contractName, functionName, value) { + return this.callImplementationFunction(blockchain, 'setContractCallCache', [ + contractName, + functionName, + value, + ]); + } + getPrivateKey(blockchain) { return this.callImplementationFunction(blockchain, 'getPrivateKey'); } @@ -38,20 +46,12 @@ class BlockchainModuleManager extends BaseModuleManager { return this.callImplementationFunction(blockchain, 'getManagementKey'); } - async isHubContract(blockchain, contractAddress) { - return this.callImplementationFunction(blockchain, 'isHubContract', [contractAddress]); - } - async isAssetStorageContract(blockchain, contractAddress) { return this.callImplementationFunction(blockchain, 'isAssetStorageContract', [ contractAddress, ]); } - async getNodeStake(blockchain, identityId) { - return this.callImplementationFunction(blockchain, 'getNodeStake', [identityId]); - } - async getBlockNumber(blockchain) { return this.callImplementationFunction(blockchain, 'getBlockNumber'); } @@ -112,13 +112,6 @@ class BlockchainModuleManager extends BaseModuleManager { ]); } - async getAssertionIdsLength(blockchain, assetContractAddress, tokenId) { - return this.callImplementationFunction(blockchain, 'getAssertionIdsLength', [ - assetContractAddress, - tokenId, - ]); - } - async getKnowledgeAssetOwner(blockchain, assetContractAddress, tokenId) { return this.callImplementationFunction(blockchain, 'getKnowledgeAssetOwner', [ assetContractAddress, @@ -130,10 +123,6 @@ class BlockchainModuleManager extends BaseModuleManager { return this.callImplementationFunction(blockchain, 'getUnfinalizedState', [tokenId]); } - async getAssertionIssuer(blockchain, assertionId) { - return this.callImplementationFunction(blockchain, 'getAssertionIssuer', [assertionId]); - } - async getShardingTableHead(blockchain) { return this.callImplementationFunction(blockchain, 'getShardingTableHead'); } @@ -373,20 +362,6 @@ class BlockchainModuleManager extends BaseModuleManager { return this.callImplementationFunction(blockchain, 'isHashFunction', [hashFunctionId]); } - async isScoreFunction(blockchain, scoreFunctionId) { - return this.callImplementationFunction(blockchain, 'isScoreFunction', [scoreFunctionId]); - } - - async callScoreFunction(blockchain, scoreFunctionId, hashFunctionId, peerId, keyword, stake) { - return this.callImplementationFunction(blockchain, 'callScoreFunction', [ - scoreFunctionId, - hashFunctionId, - peerId, - keyword, - stake, - ]); - } - async getLog2PLDSFParams(blockchain) { return this.callImplementationFunction(blockchain, 'getLog2PLDSFParams'); } diff --git a/src/modules/blockchain/implementation/web3-service.js b/src/modules/blockchain/implementation/web3-service.js index 4e41f9b2cd..78c257f741 100644 --- a/src/modules/blockchain/implementation/web3-service.js +++ b/src/modules/blockchain/implementation/web3-service.js @@ -19,6 +19,9 @@ import { HTTP_RPC_PROVIDER_PRIORITY, FALLBACK_PROVIDER_QUORUM, RPC_PROVIDER_STALL_TIMEOUT, + CACHED_FUNCTIONS, + CACHE_DATA_TYPES, + CONTRACTS, } from '../../../constants/constants.js'; const require = createRequire(import.meta.url); @@ -51,6 +54,7 @@ const ABIs = { const SCORING_FUNCTIONS = { 1: 'Log2PLDSF', }; +const contractCallCache = {}; class Web3Service { async initialize(config, logger) { @@ -280,6 +284,32 @@ class Web3Service { } } + setContractCallCache(contractName, functionName, value) { + if (CACHED_FUNCTIONS[contractName]?.[functionName]) { + const type = CACHED_FUNCTIONS[contractName][functionName]; + if (!contractCallCache[contractName]) { + contractCallCache[contractName] = {}; + } + switch (type) { + case CACHE_DATA_TYPES.NUMBER: + contractCallCache[contractName][functionName] = Number(value); + break; + default: + contractCallCache[contractName][functionName] = value; + } + } + } + + getContractCallCache(contractName, functionName) { + if ( + CACHED_FUNCTIONS[contractName]?.[functionName] && + contractCallCache[contractName]?.[functionName] + ) { + return contractCallCache[contractName][functionName]; + } + return null; + } + initializeContract(contractName, contractAddress) { if (ABIs[contractName] != null) { this[`${contractName}Contract`] = new ethers.Contract( @@ -343,16 +373,13 @@ class Web3Service { } async getIdentityId() { - if (this.config.identityId) { - return this.config.identityId; - } const identityId = await this.callContractFunction( this.IdentityStorageContract, 'getIdentityId', [this.getPublicKey()], + CONTRACTS.IDENTITY_STORAGE_CONTRACT, ); - this.config.identityId = Number(identityId); - return this.config.identityId; + return Number(identityId); } async identityIdExists() { @@ -415,32 +442,30 @@ class Web3Service { } } - async callContractFunction(contractInstance, functionName, args) { - let result; - while (result === undefined) { - try { + async callContractFunction(contractInstance, functionName, args, contractName = null) { + let result = this.getContractCallCache(contractName, functionName); + try { + if (!result) { // eslint-disable-next-line no-await-in-loop result = await contractInstance[functionName](...args); - } catch (error) { - const decodedErrorData = this._decodeErrorData(error, contractInstance.interface); + this.setContractCallCache(contractName, functionName, result); + } + } catch (error) { + const decodedErrorData = this._decodeErrorData(error, contractInstance.interface); - const functionFragment = contractInstance.interface.getFunction( - error.transaction.data.slice(0, 10), - ); - const inputs = functionFragment.inputs - .map((input, i) => { - const argName = input.name; - const argValue = this._formatArgument(args[i]); - return `${argName}=${argValue}`; - }) - .join(', '); + const functionFragment = contractInstance.interface.getFunction( + error.transaction.data.slice(0, 10), + ); + const inputs = functionFragment.inputs + .map((input, i) => { + const argName = input.name; + const argValue = this._formatArgument(args[i]); + return `${argName}=${argValue}`; + }) + .join(', '); - throw new Error( - `Call ${functionName}(${inputs}) failed, reason: ${decodedErrorData}`, - ); - } + throw new Error(`Call ${functionName}(${inputs}) failed, reason: ${decodedErrorData}`); } - return result; } @@ -737,22 +762,12 @@ class Web3Service { return timestamp < timestampThirtyDaysInPast; } - async isHubContract(contractAddress) { - return this.callContractFunction(this.HubContract, 'isContract(address)', [ - contractAddress, - ]); - } - async isAssetStorageContract(contractAddress) { return this.callContractFunction(this.HubContract, 'isAssetStorage(address)', [ contractAddress, ]); } - async getNodeStake(identityId) { - return this.callContractFunction(this.StakingStorageContract, 'totalStakes', [identityId]); - } - async getAssertionIdByIndex(assetContractAddress, tokenId, index) { const assetStorageContractInstance = this.assetStorageContracts[assetContractAddress.toLowerCase()]; @@ -795,17 +810,6 @@ class Web3Service { ]); } - async getAssertionIdsLength(assetContractAddress, tokenId) { - const assetStorageContractInstance = - this.assetStorageContracts[assetContractAddress.toString().toLowerCase()]; - if (!assetStorageContractInstance) - throw new Error('Unknown asset storage contract address'); - - return this.callContractFunction(assetStorageContractInstance, 'getAssertionIdsLength', [ - tokenId, - ]); - } - async getKnowledgeAssetOwner(assetContractAddress, tokenId) { const assetStorageContractInstance = this.assetStorageContracts[assetContractAddress.toString().toLowerCase()]; @@ -823,12 +827,6 @@ class Web3Service { ); } - async getAssertionIssuer(assertionId) { - return this.callContractFunction(this.AssertionStorageContract, 'getAssertionIssuer', [ - assertionId, - ]); - } - async getAgreementData(agreementId) { const result = await this.callContractFunction( this.ServiceAgreementStorageProxyContract, @@ -917,17 +915,32 @@ class Web3Service { } async getR2() { - const r2 = await this.callContractFunction(this.ParametersStorageContract, 'r2', []); + const r2 = await this.callContractFunction( + this.ParametersStorageContract, + 'r2', + [], + CONTRACTS.PARAMETERS_STORAGE_CONTRACT, + ); return r2; } async getR1() { - const r1 = await this.callContractFunction(this.ParametersStorageContract, 'r1', []); + const r1 = await this.callContractFunction( + this.ParametersStorageContract, + 'r1', + [], + CONTRACTS.PARAMETERS_STORAGE_CONTRACT, + ); return r1; } async getR0() { - const r0 = await this.callContractFunction(this.ParametersStorageContract, 'r0', []); + const r0 = await this.callContractFunction( + this.ParametersStorageContract, + 'r0', + [], + CONTRACTS.PARAMETERS_STORAGE_CONTRACT, + ); return r0; } @@ -936,6 +949,7 @@ class Web3Service { this.ParametersStorageContract, 'finalizationCommitsNumber', [], + CONTRACTS.PARAMETERS_STORAGE_CONTRACT, ); return finalizationCommitsNumber; } @@ -1107,6 +1121,7 @@ class Web3Service { this.ParametersStorageContract, 'updateCommitWindowDuration', [], + CONTRACTS.PARAMETERS_STORAGE_CONTRACT, ); return Number(commitWindowDurationPerc); } @@ -1116,6 +1131,7 @@ class Web3Service { this.ParametersStorageContract, 'commitWindowDurationPerc', [], + CONTRACTS.PARAMETERS_STORAGE_CONTRACT, ); return Number(commitWindowDurationPerc); } @@ -1125,6 +1141,7 @@ class Web3Service { this.ParametersStorageContract, 'proofWindowDurationPerc', [], + CONTRACTS.PARAMETERS_STORAGE_CONTRACT, ); } @@ -1133,6 +1150,7 @@ class Web3Service { this.ParametersStorageContract, 'epochLength', [], + CONTRACTS.PARAMETERS_STORAGE_CONTRACT, ); return Number(epochLength); } @@ -1143,22 +1161,6 @@ class Web3Service { ]); } - async isScoreFunction(scoreFunctionId) { - return this.callContractFunction(this.ScoringProxyContract, 'isScoreFunction(uint8)', [ - scoreFunctionId, - ]); - } - - async callScoreFunction(scoreFunctionId, hashFunctionId, peerId, keyword, stake) { - return this.callContractFunction(this.ScoringProxyContract, 'callScoreFunction', [ - scoreFunctionId, - hashFunctionId, - this.convertAsciiToHex(peerId), - keyword, - stake, - ]); - } - async getLog2PLDSFParams() { const log2pldsfParams = await this.callContractFunction( this.scoringFunctionsContracts[1], diff --git a/src/modules/triple-store/implementation/ot-blazegraph/ot-blazegraph.js b/src/modules/triple-store/implementation/ot-blazegraph/ot-blazegraph.js index f177b34b4f..c89ab90af5 100644 --- a/src/modules/triple-store/implementation/ot-blazegraph/ot-blazegraph.js +++ b/src/modules/triple-store/implementation/ot-blazegraph/ot-blazegraph.js @@ -4,6 +4,8 @@ import OtTripleStore from '../ot-triple-store.js'; class OtBlazegraph extends OtTripleStore { async initialize(config, logger) { await super.initialize(config, logger); + // this regex will match \Uxxxxxxxx but will exclude cases where there is a double slash before U (\\U) + this.unicodeRegex = /(? { @@ -47,6 +49,40 @@ class OtBlazegraph extends OtTripleStore { } } + hasUnicodeCodePoints(input) { + return this.unicodeRegex.test(input); + } + + decodeUnicodeCodePoints(input) { + const decodedString = input.replace(this.unicodeRegex, (match, hex) => { + const codePoint = parseInt(hex, 16); + return String.fromCodePoint(codePoint); + }); + + return decodedString; + } + + async _executeQuery(repository, query, mediaType) { + const result = await this.queryEngine.query( + query, + this.repositories[repository].queryContext, + ); + const { data } = await this.queryEngine.resultToString(result, mediaType); + + let response = ''; + + for await (const chunk of data) { + response += chunk; + } + + // Handle Blazegraph special characters corruption + if (this.hasUnicodeCodePoints(response)) { + response = this.decodeUnicodeCodePoints(response); + } + + return response; + } + async healthCheck(repository) { try { const response = await axios.get( diff --git a/src/service/blockchain-event-listener-service.js b/src/service/blockchain-event-listener-service.js index 6e3f2a9d84..39aab4c22b 100644 --- a/src/service/blockchain-event-listener-service.js +++ b/src/service/blockchain-event-listener-service.js @@ -79,6 +79,12 @@ class BlockchainEventListenerService { currentBlock, CONTRACT_EVENTS.SERVICE_AGREEMENT_V1, ), + this.getContractEvents( + blockchainId, + CONTRACTS.PARAMETERS_STORAGE_CONTRACT, + currentBlock, + CONTRACT_EVENTS.PARAMETERS_STORAGE, + ), ]; if (!devEnvironment) { @@ -227,6 +233,18 @@ class BlockchainEventListenerService { } } + async handleParameterChangedEvents(blockEvents) { + for (const event of blockEvents) { + const { parameterName, parameterValue } = JSON.parse(event.data); + this.blockchainModuleManager.setContractCallCache( + event.blockchainId, + CONTRACTS.PARAMETERS_STORAGE_CONTRACT, + parameterName, + parameterValue, + ); + } + } + handleNewContractEvents(blockEvents) { for (const event of blockEvents) { const { contractName, newContractAddress } = JSON.parse(event.data); diff --git a/src/service/triple-store-service.js b/src/service/triple-store-service.js index 92a2799dc3..787476ede5 100644 --- a/src/service/triple-store-service.js +++ b/src/service/triple-store-service.js @@ -1,6 +1,6 @@ import { formatAssertion } from 'assertion-tools'; -import { SCHEMA_CONTEXT, TRIPLE_STORE_REPOSITORIES } from '../constants/constants.js'; +import { SCHEMA_CONTEXT, TRIPLE_STORE_REPOSITORIES, MEDIA_TYPES } from '../constants/constants.js'; class TripleStoreService { constructor(ctx) { @@ -47,12 +47,23 @@ class TripleStoreService { keyword, }); + const oldUalConnection = await formatAssertion({ + '@context': SCHEMA_CONTEXT, + '@id': this.ualService.getUalWithoutChainId(ual, blockchain), + assertion: { '@id': `assertion:${assertionId}` }, + }); + await Promise.all([ this.tripleStoreModuleManager.insertAssetAssertionMetadata( this.repositoryImplementations[repository], repository, currentAssetNquads.join('\n'), ), + this.tripleStoreModuleManager.insertAssetAssertionMetadata( + this.repositoryImplementations[repository], + repository, + oldUalConnection.join('\n'), + ), this.tripleStoreModuleManager.insertAssertion( this.repositoryImplementations[repository], repository, @@ -76,7 +87,14 @@ class TripleStoreService { tokenId, keyword, ) { - const assertion = await this.getAssertion(fromRepository, assertionId); + let assertion; + // Try-catch to prevent infinite processing loop when unexpected error is thrown while getting KA + try { + assertion = await this.getAssertion(fromRepository, assertionId); + } catch (e) { + this.logger.error(`Error while getting assertion for moving asset: ${e.message}`); + return; + } // copy metadata and assertion await this.localStoreAsset( @@ -179,6 +197,11 @@ class TripleStoreService { repository, ual, ); + await this.tripleStoreModuleManager.deleteAssetMetadata( + this.repositoryImplementations[repository], + repository, + this.ualService.getUalWithoutChainId(ual, blockchain), + ); // Delete assertions that were linked only to this Knowledge Asset for (const linkedAssertionId of linkedAssertionIds) { @@ -212,8 +235,13 @@ class TripleStoreService { repository, assertionId, ); - - return this.dataService.parseBindings(bindings); + const count = this.dataService.parseBindings(bindings); + if (count > 1) { + // since 6.1.0 in asset metadata we are storing two triples connected to assertion id + // using 2 formats of ual - so we can expect that this query returns 2 triples per asset + return Math.round(count / 2); + } + return count; } async getAssertion(repository, assertionId) { @@ -225,7 +253,7 @@ class TripleStoreService { repository, assertionId, ); - nquads = await this.dataService.toNQuads(nquads, 'application/n-quads'); + nquads = await this.dataService.toNQuads(nquads, MEDIA_TYPES.N_QUADS); this.logger.debug( `Assertion: ${assertionId} ${ diff --git a/src/service/ual-service.js b/src/service/ual-service.js index b6e4cd10db..f3f2b35266 100644 --- a/src/service/ual-service.js +++ b/src/service/ual-service.js @@ -100,6 +100,15 @@ class UALService { [contract, firstAssertionId], ); } + + getUalWithoutChainId(ual, blockchain) { + const blockchainParts = blockchain.split(':'); + + if (ual.includes(blockchain)) { + return ual.replace(blockchain, blockchainParts[0]); + } + return ual; + } } export default UALService;