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/package-lock.json b/package-lock.json index 43c41e49d3..71744602bc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "origintrail_node", - "version": "6.1.1", + "version": "6.1.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "origintrail_node", - "version": "6.1.1", + "version": "6.1.2", "license": "ISC", "dependencies": { "@comunica/query-sparql": "^2.4.3", diff --git a/package.json b/package.json index 7ddcc1b845..36d67b1463 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "origintrail_node", - "version": "6.1.1", + "version": "6.1.2", "description": "OTNode V6", "main": "index.js", "type": "module", diff --git a/scripts/set-ask.js b/scripts/set-ask.js index 2ce056f599..9c1c3deed4 100644 --- a/scripts/set-ask.js +++ b/scripts/set-ask.js @@ -31,11 +31,11 @@ async function getGasPrice(gasPriceOracleLink) { if ( gasPriceOracleLink === 'https://api.gnosisscan.io/api?module=proxy&action=eth_gasPrice' ) { - gasPrice = Number(response.result, 10); + gasPrice = Number(response.data.result, 10); } else if ( gasPriceOracleLink === 'https://blockscout.chiadochain.net/api/v1/gas-price-oracle' ) { - gasPrice = Math.round(response.average * 1e9); + gasPrice = Math.round(response.data.average * 1e9); } else { gasPrice = Math.round(response.result * 1e9); } diff --git a/scripts/set-stake.js b/scripts/set-stake.js index 64938814e1..4db4be7fb0 100644 --- a/scripts/set-stake.js +++ b/scripts/set-stake.js @@ -38,11 +38,11 @@ async function getGasPrice(gasPriceOracleLink) { if ( gasPriceOracleLink === 'https://api.gnosisscan.io/api?module=proxy&action=eth_gasPrice' ) { - gasPrice = Number(response.result, 10); + gasPrice = Number(response.data.result, 10); } else if ( gasPriceOracleLink === 'https://blockscout.chiadochain.net/api/v1/gas-price-oracle' ) { - gasPrice = Math.round(response.average * 1e9); + gasPrice = Math.round(response.data.average * 1e9); } else { gasPrice = Math.round(response.result * 1e9); } diff --git a/src/commands/protocols/common/submit-commit-command.js b/src/commands/protocols/common/submit-commit-command.js index 124e985231..a0484d1c6c 100644 --- a/src/commands/protocols/common/submit-commit-command.js +++ b/src/commands/protocols/common/submit-commit-command.js @@ -84,7 +84,7 @@ class SubmitCommitCommand extends Command { return Command.empty(); } - const txGasPrice = gasPrice ?? (await this.blockchainModuleManager.getGasPrice()); + const txGasPrice = gasPrice ?? (await this.blockchainModuleManager.getGasPrice(blockchain)); const transactionCompletePromise = new Promise((resolve, reject) => { this.blockchainModuleManager.submitCommit( diff --git a/src/commands/protocols/common/submit-proofs-command.js b/src/commands/protocols/common/submit-proofs-command.js index 462d51fb27..f3c7e6d9ca 100644 --- a/src/commands/protocols/common/submit-proofs-command.js +++ b/src/commands/protocols/common/submit-proofs-command.js @@ -134,7 +134,7 @@ class SubmitProofsCommand extends Command { return Command.empty(); } - const txGasPrice = gasPrice ?? (await this.blockchainModuleManager.getGasPrice()); + const txGasPrice = gasPrice ?? (await this.blockchainModuleManager.getGasPrice(blockchain)); const transactionCompletePromise = new Promise((resolve, reject) => { this.blockchainModuleManager.sendProof( diff --git a/src/commands/protocols/update/receiver/submit-update-commit-command.js b/src/commands/protocols/update/receiver/submit-update-commit-command.js index e253372f87..d8c9b27297 100644 --- a/src/commands/protocols/update/receiver/submit-update-commit-command.js +++ b/src/commands/protocols/update/receiver/submit-update-commit-command.js @@ -68,7 +68,7 @@ class SubmitUpdateCommitCommand extends Command { return Command.empty(); } - const txGasPrice = gasPrice ?? (await this.blockchainModuleManager.getGasPrice()); + const txGasPrice = gasPrice ?? (await this.blockchainModuleManager.getGasPrice(blockchain)); const transactionCompletePromise = new Promise((resolve, reject) => { this.blockchainModuleManager.submitUpdateCommit( 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/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/gnosis/gnosis-service.js b/src/modules/blockchain/implementation/gnosis/gnosis-service.js index 4c74dbb03b..a265283c0a 100644 --- a/src/modules/blockchain/implementation/gnosis/gnosis-service.js +++ b/src/modules/blockchain/implementation/gnosis/gnosis-service.js @@ -19,9 +19,9 @@ class GnosisService extends Web3Service { const response = await axios.get(this.config.gasPriceOracleLink); let gasPrice; if (this.config.name.split(':')[1] === '100') { - gasPrice = Number(response.result, 10); + gasPrice = Number(response.data.result, 10); } else if (this.config.name.split(':')[1] === '10200') { - gasPrice = Math.round(response.average * 1e9); + gasPrice = Math.round(response.data.average * 1e9); } this.logger.debug(`Gas price on Gnosis: ${gasPrice}`); return gasPrice; diff --git a/src/modules/blockchain/implementation/web3-service.js b/src/modules/blockchain/implementation/web3-service.js index 4e41f9b2cd..3d00134bfd 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); @@ -56,7 +59,7 @@ class Web3Service { async initialize(config, logger) { this.config = config; this.logger = logger; - + this.contractCallCache = {}; this.initializeTransactionQueue(TRANSACTION_QUEUE_CONCURRENCY); await this.initializeWeb3(); this.startBlock = await this.getBlockNumber(); @@ -280,6 +283,32 @@ class Web3Service { } } + setContractCallCache(contractName, functionName, value) { + if (CACHED_FUNCTIONS[contractName]?.[functionName]) { + const type = CACHED_FUNCTIONS[contractName][functionName]; + if (!this.contractCallCache[contractName]) { + this.contractCallCache[contractName] = {}; + } + switch (type) { + case CACHE_DATA_TYPES.NUMBER: + this.contractCallCache[contractName][functionName] = Number(value); + break; + default: + this.contractCallCache[contractName][functionName] = value; + } + } + } + + getContractCallCache(contractName, functionName) { + if ( + CACHED_FUNCTIONS[contractName]?.[functionName] && + this.contractCallCache[contractName]?.[functionName] + ) { + return this.contractCallCache[contractName][functionName]; + } + return null; + } + initializeContract(contractName, contractAddress) { if (ABIs[contractName] != null) { this[`${contractName}Contract`] = new ethers.Contract( @@ -343,16 +372,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 +441,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 +761,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 +809,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 +826,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 +914,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 +948,7 @@ class Web3Service { this.ParametersStorageContract, 'finalizationCommitsNumber', [], + CONTRACTS.PARAMETERS_STORAGE_CONTRACT, ); return finalizationCommitsNumber; } @@ -1107,6 +1120,7 @@ class Web3Service { this.ParametersStorageContract, 'updateCommitWindowDuration', [], + CONTRACTS.PARAMETERS_STORAGE_CONTRACT, ); return Number(commitWindowDurationPerc); } @@ -1116,6 +1130,7 @@ class Web3Service { this.ParametersStorageContract, 'commitWindowDurationPerc', [], + CONTRACTS.PARAMETERS_STORAGE_CONTRACT, ); return Number(commitWindowDurationPerc); } @@ -1125,6 +1140,7 @@ class Web3Service { this.ParametersStorageContract, 'proofWindowDurationPerc', [], + CONTRACTS.PARAMETERS_STORAGE_CONTRACT, ); } @@ -1133,6 +1149,7 @@ class Web3Service { this.ParametersStorageContract, 'epochLength', [], + CONTRACTS.PARAMETERS_STORAGE_CONTRACT, ); return Number(epochLength); } @@ -1143,22 +1160,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 085acb8f19..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) { @@ -87,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( @@ -246,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} ${