UNPKG

evm-blockchain-tools

Version:

This is a collection of resuseable tools to support development for EVM-powered blockchains

82 lines 3.93 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.RoundRobinSignerPicker = void 0; const mvc_common_toolkit_1 = require("mvc-common-toolkit"); const constants_1 = require("../common/constants"); class RoundRobinSignerPicker { constructor(transactionStorage) { this.transactionStorage = transactionStorage; this._signerMap = new Map(); this._signerCallingMap = new Map(); } resetSignerData(address, signerList) { this._signerMap.set(address, signerList); this._signerCallingMap.set(address, 0); } advanceNextIndex(address) { const signers = this._signerMap.get(address); if (!signers || signers.length === 0) { throw new Error(`Signer list for address ${address} is empty.`); } const currentCallingIndex = this._signerCallingMap.get(address); const maxIndex = this._signerMap.get(address).length - 1; const nextIndex = currentCallingIndex + 1 > maxIndex ? 0 : currentCallingIndex + 1; this._signerCallingMap.set(address, nextIndex); return nextIndex; } pick(address, signerList) { return __awaiter(this, void 0, void 0, function* () { if (!signerList.length) { throw new Error("signer list cannot be empty"); } if (!address) { throw new Error("address cannot be empty"); } if (this._signerMap.has(address)) { const existingSigners = this._signerMap.get(address); if (existingSigners !== signerList) { this.resetSignerData(address, signerList); } } else { this.resetSignerData(address, signerList); } const allSignersCount = this._signerMap.get(address).length; const retryTask = new mvc_common_toolkit_1.workflows.RetryTask(() => __awaiter(this, void 0, void 0, function* () { const nextIndex = this.advanceNextIndex(address); const nextSigner = this._signerMap.get(address)[nextIndex]; const signerAddress = yield nextSigner.getAddress(); yield nextSigner.getChainId(); const signerLastTx = yield this.transactionStorage.findSignerLastTransaction(signerAddress); if (!signerLastTx) { return nextSigner; } if (signerLastTx.status === constants_1.TransactionStatus.SCHEDULED) { throw new Error(`signer ${signerAddress} is still busy`); } return nextSigner; }), { retryCount: allSignersCount * 3, taskName: `pick_signer_for_contract_${address}`, retryIntervalInMs: 2000, returnOperationResult: true, }); const result = yield retryTask.run(); if (!result.success) { throw new Error("all signers are busy or unavailable"); } return result.data; }); } } exports.RoundRobinSignerPicker = RoundRobinSignerPicker; //# sourceMappingURL=round-robin-signer-picker-service.js.map