@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
JavaScript
;
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;