From 87fdddc2a5651f47fd3238284186cc57ca05e88a Mon Sep 17 00:00:00 2001 From: Uladzislau Hubar Date: Fri, 3 Nov 2023 18:21:55 +0100 Subject: [PATCH] Implemented Fallback RPC Provider, changed the way of handling commit/proof errors --- config/config.json | 8 +- .../protocols/common/submit-commit-command.js | 9 ++- .../protocols/common/submit-proofs-command.js | 9 ++- src/constants/constants.js | 8 ++ .../blockchain/implementation/web3-service.js | 73 +++++++++---------- 5 files changed, 64 insertions(+), 43 deletions(-) diff --git a/config/config.json b/config/config.json index 7b490510c4..e16f1e509d 100644 --- a/config/config.json +++ b/config/config.json @@ -131,7 +131,10 @@ "config": { "networkId": "otp::testnet", "hubContractAddress": "0x707233a55bD035C6Bc732196CA4dbffa63CbA169", - "rpcEndpoints": ["https://lofar-tm-rpc.origin-trail.network"], + "rpcEndpoints": [ + "https://lofar-tm-rpc.origin-trail.network", + "https://lofar.origintrail.network/" + ], "initialStakeAmount": 50000, "initialAskAmount": 2 } @@ -585,7 +588,8 @@ "hubContractAddress": "0x5fA7916c48Fe6D5F1738d12Ad234b78c90B4cAdA", "rpcEndpoints": [ "https://astrosat-parachain-rpc.origin-trail.network", - "https://astrosat.origintrail.network/" + "https://astrosat.origintrail.network/", + "https://astrosat-2.origintrail.network/" ] } } diff --git a/src/commands/protocols/common/submit-commit-command.js b/src/commands/protocols/common/submit-commit-command.js index b2312b72ee..e4871b4465 100644 --- a/src/commands/protocols/common/submit-commit-command.js +++ b/src/commands/protocols/common/submit-commit-command.js @@ -52,7 +52,12 @@ class SubmitCommitCommand extends Command { const errorMessage = `Commit already submitted for blockchain: ${blockchain} agreement id: ${agreementId}, epoch: ${epoch}, state index: ${stateIndex}`; this.logger.trace(errorMessage); - await this.handleError(operationId, errorMessage, this.errorType, true); + this.operationIdService.emitChangeEvent( + OPERATION_ID_STATUS.COMMIT_PROOF.SUBMIT_COMMIT_END, + operationId, + agreementId, + epoch, + ); return Command.empty(); } @@ -66,7 +71,7 @@ class SubmitCommitCommand extends Command { epoch, stateIndex, (result) => { - if (result?.error) { + if (result?.error && !result.error.includes('NodeAlreadySubmittedCommit')) { reject(result.error); } resolve(); diff --git a/src/commands/protocols/common/submit-proofs-command.js b/src/commands/protocols/common/submit-proofs-command.js index 2e44f23ba2..e59e4ace28 100644 --- a/src/commands/protocols/common/submit-proofs-command.js +++ b/src/commands/protocols/common/submit-proofs-command.js @@ -103,7 +103,12 @@ class SubmitProofsCommand extends Command { const errorMessage = `Proofs already submitted for blockchain: ${blockchain} agreement id: ${agreementId}, epoch: ${epoch}, state index: ${stateIndex}`; this.logger.trace(errorMessage); - await this.handleError(operationId, errorMessage, this.errorType, true); + this.operationIdService.emitChangeEvent( + OPERATION_ID_STATUS.COMMIT_PROOF.SUBMIT_PROOFS_END, + operationId, + agreementId, + epoch, + ); return Command.empty(); } @@ -127,7 +132,7 @@ class SubmitProofsCommand extends Command { leaf, stateIndex, (result) => { - if (result?.error) { + if (result?.error && !result.error.includes('NodeAlreadyRewarded')) { reject(result.error); } resolve(); diff --git a/src/constants/constants.js b/src/constants/constants.js index 285441faee..ba1d328b3c 100644 --- a/src/constants/constants.js +++ b/src/constants/constants.js @@ -1,5 +1,13 @@ import { BigNumber } from 'ethers'; +export const WS_RPC_PROVIDER_PRIORITY = 2; + +export const HTTP_RPC_PROVIDER_PRIORITY = 1; + +export const FALLBACK_PROVIDER_QUORUM = 1; + +export const RPC_PROVIDER_STALL_TIMEOUT = 60 * 1000; + export const UINT256_MAX_BN = BigNumber.from(2).pow(256).sub(1); export const UINT32_MAX_BN = BigNumber.from(2).pow(32).sub(1); diff --git a/src/modules/blockchain/implementation/web3-service.js b/src/modules/blockchain/implementation/web3-service.js index 49632f426f..c3fbb03f68 100644 --- a/src/modules/blockchain/implementation/web3-service.js +++ b/src/modules/blockchain/implementation/web3-service.js @@ -15,6 +15,10 @@ import { TRANSACTION_POLLING_TIMEOUT_MILLIS, TRANSACTION_CONFIRMATIONS, BLOCK_TIME_MILLIS, + WS_RPC_PROVIDER_PRIORITY, + HTTP_RPC_PROVIDER_PRIORITY, + FALLBACK_PROVIDER_QUORUM, + RPC_PROVIDER_STALL_TIMEOUT, } from '../../../constants/constants.js'; const require = createRequire(import.meta.url); @@ -53,7 +57,6 @@ class Web3Service { this.config = config; this.logger = logger; - this.rpcNumber = 0; this.initializeTransactionQueue(TRANSACTION_QUEUE_CONCURRENCY); await this.initializeWeb3(); this.startBlock = await this.getBlockNumber(); @@ -89,37 +92,44 @@ class Web3Service { } async initializeWeb3() { - let tries = 0; - let isRpcConnected = false; - while (!isRpcConnected) { - if (tries >= this.config.rpcEndpoints.length) { - throw Error('RPC initialization failed'); - } - + const rpcProviders = []; + for (const rpcEndpoint of this.config.rpcEndpoints) { try { - if (this.config.rpcEndpoints[this.rpcNumber].startsWith('ws')) { - this.provider = new ethers.providers.WebSocketProvider( - this.config.rpcEndpoints[this.rpcNumber], - ); + if (rpcEndpoint.startsWith('ws')) { + rpcProviders.push({ + provider: new ethers.providers.WebSocketProvider(rpcEndpoint), + priority: WS_RPC_PROVIDER_PRIORITY, + weight: 1, + stallTimeout: RPC_PROVIDER_STALL_TIMEOUT, + }); } else { - this.provider = new ethers.providers.JsonRpcProvider( - this.config.rpcEndpoints[this.rpcNumber], - ); + rpcProviders.push({ + provider: new ethers.providers.JsonRpcProvider(rpcEndpoint), + priority: HTTP_RPC_PROVIDER_PRIORITY, + weight: 1, + stallTimeout: RPC_PROVIDER_STALL_TIMEOUT, + }); } - // eslint-disable-next-line no-await-in-loop - await this.providerReady(); - isRpcConnected = true; + this.logger.debug(`Connected to the blockchain RPC: ${rpcEndpoint}.`); } catch (e) { - this.logger.warn( - `Unable to connect to blockchain rpc : ${ - this.config.rpcEndpoints[this.rpcNumber] - }.`, - ); - tries += 1; - this.rpcNumber = (this.rpcNumber + 1) % this.config.rpcEndpoints.length; + this.logger.warn(`Unable to connect to the blockchain RPC: ${rpcEndpoint}.`); } } + try { + this.provider = new ethers.providers.FallbackProvider( + rpcProviders, + FALLBACK_PROVIDER_QUORUM, + ); + } catch (e) { + throw Error( + `RPC Fallback Provider initialization failed. Fallback Provider quorum: ${FALLBACK_PROVIDER_QUORUM}. Error: ${e.message}.`, + ); + } + + // eslint-disable-next-line no-await-in-loop + await this.providerReady(); + this.wallet = new ethers.Wallet(this.getPrivateKey(), this.provider); } @@ -164,9 +174,6 @@ class Web3Service { }); this.logger.info(`Contracts initialized`); - this.logger.debug( - `Connected to blockchain rpc : ${this.config.rpcEndpoints[this.rpcNumber]}.`, - ); await this.logBalances(); } @@ -925,12 +932,6 @@ class Web3Service { } async restartService() { - this.rpcNumber = (this.rpcNumber + 1) % this.config.rpcEndpoints.length; - this.logger.warn( - `There was an issue with current blockchain rpc. Connecting to ${ - this.config.rpcEndpoints[this.rpcNumber] - }`, - ); await this.initializeWeb3(); await this.initializeContracts(); } @@ -942,9 +943,7 @@ class Web3Service { } catch (rpcError) { isRpcError = true; this.logger.warn( - `Unable to execute smart contract function ${functionName} using blockchain rpc : ${ - this.config.rpcEndpoints[this.rpcNumber] - }.`, + `Unable to execute smart contract function ${functionName} using Fallback RPC Provider.`, ); await this.restartService(); }