UNPKG

@rsksmart/rif-storage-pinning

Version:

Application for providing your storage space to other to use in exchange of RIF Tokens

177 lines (176 loc) 10.1 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()); }); }; var __asyncValues = (this && this.__asyncValues) || function (o) { if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); var m = o[Symbol.asyncIterator], i; return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i); function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.BlockchainEventsProcessor = void 0; const web3_eth_1 = __importDefault(require("web3-eth")); const sequelize_store_1 = require("sequelize-store"); const config_1 = __importDefault(require("config")); const web3_events_1 = require("@rsksmart/web3-events"); const StorageManager_json_1 = __importDefault(require("@rsksmart/rif-marketplace-storage/build/contracts/StorageManager.json")); const offer_1 = __importDefault(require("./offer")); const agreement_1 = __importDefault(require("./agreement")); const index_1 = require("../index"); const utils_1 = require("../../utils"); const logger_1 = require("../../logger"); const agreement_model_1 = __importDefault(require("../../models/agreement.model")); const gc_1 = __importDefault(require("../../gc")); const event_transformer_1 = require("../../event-transformer"); const logger = logger_1.loggingFactory('processor:blockchain'); function ethFactory() { const provider = web3_eth_1.default.givenProvider || config_1.default.get('blockchain.provider'); logger.info(`Connecting to provider ${provider}`); return new web3_eth_1.default(provider); } function filterAndTransformBlockchainEvents(offerId, eventTransformer, callback) { return (originalEvent) => __awaiter(this, void 0, void 0, function* () { const event = eventTransformer(originalEvent); logger.debug(`Got ${event.event} for provider ${event.returnValues.provider}`); if (utils_1.isEventWithProvider(event) && event.returnValues.provider === offerId) { return callback(event); } if (event.event.startsWith('Agreement') && (yield agreement_model_1.default.findByPk(event.returnValues.agreementReference))) { return callback(event); } logger.debug(`Events not related to offer ${offerId}`); }); } function isServiceInitialized(serviceName) { const store = sequelize_store_1.getObject(); return store[`web3events.${serviceName}.${web3_events_1.LAST_FETCHED_BLOCK_NUMBER_KEY}`] !== undefined; } class BlockchainEventsProcessor extends index_1.EventProcessor { constructor(offerId, manager, options) { var _a, _b; super(offerId, options); this.handlers = [offer_1.default, agreement_1.default]; if (!(options === null || options === void 0 ? void 0 : options.appResetCallback)) { throw new Error('We need appResetCallback to be defined for BlockchainEventsProcessor!'); } this.contractAddresses = (_a = options.contractAddress) !== null && _a !== void 0 ? _a : config_1.default.get('blockchain.contractAddress'); this.appResetCallback = options.appResetCallback; this.manager = manager; this.errorHandler = (_b = options === null || options === void 0 ? void 0 : options.errorHandler) !== null && _b !== void 0 ? _b : utils_1.errorHandler; this.eth = ethFactory(); this.eventTransformer = event_transformer_1.getEventTransformer(StorageManager_json_1.default.abi); const deps = { manager: manager, eth: this.eth }; this.processor = filterAndTransformBlockchainEvents(this.offerId, this.eventTransformer, this.errorHandler(this.getProcessor(this.handlers, deps), logger)); } // eslint-disable-next-line require-await initialize() { return __awaiter(this, void 0, void 0, function* () { if (this.initialized) throw new Error('Already Initialized'); const logger = logger_1.loggingFactory('blockchain'); logger.info('Initializing Blockchain processor'); const networkId = config_1.default.get('blockchain.networkId'); const ethNetworkId = yield this.eth.net.getId(); logger.verbose(`Connected to network ID ${ethNetworkId}`); if (networkId !== '*' && networkId !== ethNetworkId) { throw new Error(`Network ID not defined or incorrect. Expected ${networkId}, got ${yield this.eth.net.getId()}`); } const web3events = new web3_events_1.Web3Events(this.eth, { store: sequelize_store_1.getObject('web3events.'), logger: logger_1.loggingFactory('web3events'), defaultNewBlockEmitter: config_1.default.get('blockchain.newBlockEmitter') }); this.newBlockEmitter = web3events.defaultNewBlockEmitter; const contract = new web3_events_1.Contract(StorageManager_json_1.default.abi, this.contractAddresses, 'storage'); const options = config_1.default.get('blockchain.eventsEmitter'); logger.info(`For listening on service 'blockchain' using contract on address: ${this.contractAddresses}`); this.eventsEmitter = web3events.createEventsEmitter(contract, options); this.initialized = true; }); } run() { var _a; return __awaiter(this, void 0, void 0, function* () { if (!this.initialized) yield this.initialize(); if (!this.eventsEmitter || !this.newBlockEmitter) { throw new Error('Processor was not correctly initialized!'); } // If not set then it is first time running ==> precache if (!isServiceInitialized('storage') || ((_a = this.options) === null || _a === void 0 ? void 0 : _a.forcePrecache)) { yield this.precache(); } this.eventsEmitter.on('error', (e) => { logger.error(`There was unknown error in the blockchain's Events Emitter! ${e}`); }); // Listen on Offer events this.eventsEmitter.on(web3_events_1.NEW_EVENT_EVENT_NAME, this.processor); // Listening for reorgs outside of confirmations range this.eventsEmitter.on(web3_events_1.REORG_OUT_OF_RANGE_EVENT_NAME, this.appResetCallback); // Pinning Garbage Collecting this.newBlockEmitter.on(web3_events_1.NEW_BLOCK_EVENT_NAME, this.errorHandler(gc_1.default({ manager: this.manager }), logger_1.loggingFactory('gc'))); }); } precache() { var e_1, _a; return __awaiter(this, void 0, void 0, function* () { if (!this.initialized) yield this.initialize(); if (!this.eventsEmitter) { throw new Error('Processor was not correctly initialized!'); } const precacheLogger = logger_1.loggingFactory('processor:blockchain:precache'); const processor = filterAndTransformBlockchainEvents(this.offerId, this.eventTransformer, this.errorHandler(this.getProcessor(this.handlers, { eth: this.eth }), logger)); // Wait to build up the database with latest data precacheLogger.verbose('Populating database'); try { for (var _b = __asyncValues(this.eventsEmitter.fetch()), _c; _c = yield _b.next(), !_c.done;) { const batch = _c.value; for (const event of batch.events) { yield processor(event); } precacheLogger.verbose(`Processing: ${Math.round(batch.stepsComplete / batch.totalSteps * 100)}%`); } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (_c && !_c.done && (_a = _b.return)) yield _a.call(_b); } finally { if (e_1) throw e_1.error; } } // Now lets pin every Agreement that has funds precacheLogger.info('Pinning valid Agreements'); for (const agreement of yield agreement_model_1.default.findAll()) { if (agreement.hasSufficientFunds) { yield this.manager.pin(agreement.dataReference, agreement.size, agreement.agreementReference); } } }); } // eslint-disable-next-line require-await stop() { var _a, _b; return __awaiter(this, void 0, void 0, function* () { if (!this.eventsEmitter && !this.eventsEmitter) throw new Error('No process running'); (_a = this.eventsEmitter) === null || _a === void 0 ? void 0 : _a.stop(); (_b = this.newBlockEmitter) === null || _b === void 0 ? void 0 : _b.stop(); }); } } exports.BlockchainEventsProcessor = BlockchainEventsProcessor;