diff --git a/package-lock.json b/package-lock.json index 32fec62..292de39 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "@ethereumjs/common": "^2.6.0", "@ethereumjs/tx": "^3.4.0", "@orbs-network/orbs-ethereum-contracts-v2": "0.0.38", + "abort-controller": "^3.0.0", "lodash": "^4.17.15", "node-fetch": "^2.6.0", "orbs-client-sdk": "^2.3.1", @@ -598,6 +599,17 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, "node_modules/accepts": { "version": "1.3.7", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", @@ -3167,6 +3179,14 @@ "npm": ">=3" } }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "engines": { + "node": ">=6" + } + }, "node_modules/eventemitter3": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", @@ -5750,7 +5770,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.1.tgz", "integrity": "sha512-xowrxvpxojqkagPcWRQVXZl0YXhRhAtBEIq3VoER1NH5Mw1n1o0ojdspp+GS2J//2gCVyrzQDApQ4unGF+QOoA==", - "hasInstallScript": true, "dependencies": { "node-gyp-build": "~3.7.0" } @@ -10633,7 +10652,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.1.tgz", "integrity": "sha512-epq90L9jlFWCW7+pQa6JOnKn2Xgl2mtI664seYR6MHskvI9agt7AnDqmAlp9TqU4/caMYbA08Hi5DMZAl5zdkA==", - "hasInstallScript": true, "dependencies": { "node-addon-api": "^2.0.0", "node-gyp-build": "^4.2.0" @@ -13930,7 +13948,6 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.2.tgz", "integrity": "sha512-UDar4sKvWAksIlfX3xIaQReADn+WFnHvbVujpcbr+9Sf/69odMwy2MUsz5CKLQgX9nsIyrjuxL2imVyoNHa3fg==", - "hasInstallScript": true, "dependencies": { "elliptic": "^6.5.2", "node-addon-api": "^2.0.0", @@ -15459,7 +15476,6 @@ "version": "5.0.2", "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.2.tgz", "integrity": "sha512-SwV++i2gTD5qh2XqaPzBnNX88N6HdyhQrNNRykvcS0QKvItV9u3vPEJr+X5Hhfb1JC0r0e1alL0iB09rY8+nmw==", - "hasInstallScript": true, "dependencies": { "node-gyp-build": "~3.7.0" } @@ -22740,6 +22756,14 @@ } } }, + "abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "requires": { + "event-target-shim": "^5.0.0" + } + }, "accepts": { "version": "1.3.7", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", @@ -24828,6 +24852,11 @@ "strip-hex-prefix": "1.0.0" } }, + "event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" + }, "eventemitter3": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", diff --git a/package.json b/package.json index 15fd333..c78c64f 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,7 @@ "@orbs-network/orbs-ethereum-contracts-v2": "0.0.38", "lodash": "^4.17.15", "node-fetch": "^2.6.0", + "abort-controller": "^3.0.0", "orbs-client-sdk": "^2.3.1", "orbs-signer-client": "^1.1.0", "ts-json-decode": "^0.5.1", diff --git a/src/read/guardians-reputations.ts b/src/read/guardians-reputations.ts index a7de640..a4bd6e6 100644 --- a/src/read/guardians-reputations.ts +++ b/src/read/guardians-reputations.ts @@ -1,7 +1,7 @@ import * as Logger from '../logger'; import {Reputations, State} from '../model/state'; import {getCurrentClockTime} from '../helpers'; -import {fetchManagementStatus, ManagementStatusResponse} from "./management"; +import {fetchManagementStatusWithTimeout, ManagementStatusResponse} from "./management"; const GUARDIAN_FALLBACK_PORT = "18888"; @@ -122,7 +122,7 @@ async function fetchMnmgnmtSrvStatusForGuardian(ethAddress: string, config: Repu try { - response = await fetchManagementStatus( + response = await fetchManagementStatusWithTimeout( managementServiceEndpoint ); @@ -134,7 +134,7 @@ async function fetchMnmgnmtSrvStatusForGuardian(ethAddress: string, config: Repu managementServiceEndpoint = config.ManagementServiceEndpointSchema.replace(/{{GUARDIAN_IP}}/g, guardian?.Ip + ":" + GUARDIAN_FALLBACK_PORT); - response = await fetchManagementStatus( + response = await fetchManagementStatusWithTimeout( managementServiceEndpoint ); diff --git a/src/read/management.ts b/src/read/management.ts index b223a53..13005f0 100644 --- a/src/read/management.ts +++ b/src/read/management.ts @@ -1,11 +1,12 @@ import _ from 'lodash'; import * as Logger from '../logger'; -import { State } from '../model/state'; +import {State} from '../model/state'; import fetch from 'node-fetch'; -import { Decoder, decodeString, num, object, record, bool, str, array, maybe } from 'ts-json-decode'; -import { getCurrentClockTime } from '../helpers'; -import { findEthFromOrbsAddress } from '../model/helpers'; -import { getAbiByContractRegistryKey } from '@orbs-network/orbs-ethereum-contracts-v2'; +import {array, bool, Decoder, decodeString, maybe, num, object, record, str} from 'ts-json-decode'; +import {getCurrentClockTime} from '../helpers'; +import {findEthFromOrbsAddress} from '../model/helpers'; +import {getAbiByContractRegistryKey} from '@orbs-network/orbs-ethereum-contracts-v2'; +import AbortController from "abort-controller"; // update guardianRegistration contract instance and address export function updateGuardianRegistrationContract(state: State, address:string){ @@ -13,11 +14,11 @@ export function updateGuardianRegistrationContract(state: State, address:string) if(!address) { Logger.error('guardianRegistrationAddress is not valid') - return + return } // addigment state.guardianRegistrationAddress = address; - + const regAbi = getAbiByContractRegistryKey('guardiansRegistration'); if(!regAbi) { Logger.error(`failed to create regApi`); @@ -27,9 +28,9 @@ export function updateGuardianRegistrationContract(state: State, address:string) Logger.error(`web3 is not initialized`); return; } - + state.guardianRegistration = new state.web3.eth.Contract(regAbi, state.guardianRegistrationAddress); - if(!state.guardianRegistration) + if(!state.guardianRegistration) Logger.error(`failed to create state.guardianRegistration web3 instance`); } export async function readManagementStatus(endpoint: string, myOrbsAddress: string, state: State) { @@ -44,10 +45,10 @@ export async function readManagementStatus(endpoint: string, myOrbsAddress: stri state.ManagementCurrentTopology = response.Payload.CurrentTopology; state.ManagementEthToOrbsAddress = _.mapValues(response.Payload.Guardians, (node) => node.OrbsAddress); - if(state.guardianRegistrationAddress !== response.Payload.CurrentContractAddress.guardiansRegistration){ + if(state.guardianRegistrationAddress !== response.Payload.CurrentContractAddress.guardiansRegistration){ updateGuardianRegistrationContract(state, response.Payload.CurrentContractAddress.guardiansRegistration); } - + if(!state.myEthGuardianAddress) state.myEthGuardianAddress = findEthFromOrbsAddress(myOrbsAddress, state); @@ -77,6 +78,51 @@ export async function fetchManagementStatus(url: string): Promise controller.abort(), timeout); + + try { + + + Logger.log(`** fetching management service status from ${url}`) + + res = await fetch(url, { + signal: controller.signal, + }); + + clearTimeout(timeoutId); + + Logger.log(`** DONE fetching management service status from ${url}`) + + body = await res.text(); + + return decodeString(managementStatusResponseDecoder, body); + + } catch (err) { + + Logger.error(err.message); + throw new Error(`Error fetching Management status from ${url}, response: ${res}, body: ${body}`); + + } finally { + + clearTimeout(timeoutId); + + } + +} + export interface ManagementStatusResponse { Payload: { CurrentRefTime: number; @@ -124,7 +170,7 @@ const managementStatusResponseDecoder: Decoder = objec CurrentContractAddress: object({ guardiansRegistration: str, }), - + Guardians: record( object({ OrbsAddress: str, @@ -143,5 +189,5 @@ const managementStatusResponseDecoder: Decoder = objec export async function isGuardianRegistered(state: State): Promise { if (!state.myEthGuardianAddress) return false; // if myEthGuardianAddress is empty it means the node is not registered (not present in matic reader) - return await state.guardianRegistration?.methods.isRegistered(state.myEthGuardianAddress).call(); + return await state.guardianRegistration?.methods.isRegistered(state.myEthGuardianAddress).call(); }