index.js 47 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030
  1. "use strict";
  2. var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
  3. function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
  4. return new (P || (P = Promise))(function (resolve, reject) {
  5. function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
  6. function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
  7. function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
  8. step((generator = generator.apply(thisArg, _arguments || [])).next());
  9. });
  10. };
  11. var __generator = (this && this.__generator) || function (thisArg, body) {
  12. var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
  13. return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
  14. function verb(n) { return function (v) { return step([n, v]); }; }
  15. function step(op) {
  16. if (f) throw new TypeError("Generator is already executing.");
  17. while (_) try {
  18. if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
  19. if (y = 0, t) op = [op[0] & 2, t.value];
  20. switch (op[0]) {
  21. case 0: case 1: t = op; break;
  22. case 4: _.label++; return { value: op[1], done: false };
  23. case 5: _.label++; y = op[1]; op = [0]; continue;
  24. case 7: op = _.ops.pop(); _.trys.pop(); continue;
  25. default:
  26. if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
  27. if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
  28. if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
  29. if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
  30. if (t[2]) _.ops.pop();
  31. _.trys.pop(); continue;
  32. }
  33. op = body.call(thisArg, _);
  34. } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
  35. if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
  36. }
  37. };
  38. exports.__esModule = true;
  39. var sequelize_1 = require("sequelize");
  40. var models_1 = require("../db/models");
  41. var get = require("./lib/getters");
  42. //import {fetchReports} from './lib/github'
  43. var axios_1 = require("axios");
  44. var moment_1 = require("moment");
  45. var chalk_1 = require("chalk");
  46. // TODO fetch consts from db/chain
  47. var TERMDURATION = 144000;
  48. var VOTINGDURATION = 57601;
  49. var CYCLE = VOTINGDURATION + TERMDURATION;
  50. var DELAY = 0; // ms
  51. var lastUpdate = 0;
  52. var queuedAll = false;
  53. var queue = [];
  54. var processing = '';
  55. var busy = false;
  56. var processNext = function () { return __awaiter(void 0, void 0, void 0, function () {
  57. var task, result;
  58. return __generator(this, function (_a) {
  59. switch (_a.label) {
  60. case 0:
  61. if (busy)
  62. return [2 /*return*/];
  63. task = queue.shift();
  64. if (!task)
  65. return [2 /*return*/];
  66. return [4 /*yield*/, task()];
  67. case 1:
  68. result = _a.sent();
  69. busy = false;
  70. setTimeout(function () { return processNext(); }, DELAY);
  71. return [2 /*return*/];
  72. }
  73. });
  74. }); };
  75. var getBlockHash = function (api, blockId) {
  76. return api.rpc.chain.getBlockHash(blockId).then(function (array) { return array.toHuman(); });
  77. };
  78. var getEraAtHash = function (api, hash) {
  79. return api.query.staking.activeEra
  80. .at(hash)
  81. .then(function (era) { return era.unwrap().index.toNumber(); });
  82. };
  83. var getEraAtBlock = function (api, block) { return __awaiter(void 0, void 0, void 0, function () { var _a, _b; return __generator(this, function (_c) {
  84. switch (_c.label) {
  85. case 0:
  86. _a = getEraAtHash;
  87. _b = [api];
  88. return [4 /*yield*/, getBlockHash(api, block)];
  89. case 1: return [2 /*return*/, _a.apply(void 0, _b.concat([_c.sent()]))];
  90. }
  91. }); }); };
  92. var getTimestamp = function (api, hash) { return __awaiter(void 0, void 0, void 0, function () {
  93. var timestamp, _a;
  94. return __generator(this, function (_b) {
  95. switch (_b.label) {
  96. case 0:
  97. if (!hash) return [3 /*break*/, 2];
  98. return [4 /*yield*/, api.query.timestamp.now.at(hash)];
  99. case 1:
  100. _a = _b.sent();
  101. return [3 /*break*/, 4];
  102. case 2: return [4 /*yield*/, api.query.timestamp.now()];
  103. case 3:
  104. _a = _b.sent();
  105. _b.label = 4;
  106. case 4:
  107. timestamp = _a;
  108. return [2 /*return*/, moment_1["default"].utc(timestamp.toNumber()).valueOf()];
  109. }
  110. });
  111. }); };
  112. var findCouncilAtBlock = function (api, block) {
  113. var _a, _b;
  114. return models_1.Council.findOne({
  115. where: {
  116. start: (_a = {}, _a[sequelize_1.Op.lte] = block, _a),
  117. end: (_b = {}, _b[sequelize_1.Op.gte] = block - VOTINGDURATION, _b)
  118. }
  119. });
  120. };
  121. var addBlock = function (api, io, header, status) {
  122. if (status === void 0) { status = {
  123. block: 0,
  124. era: 0,
  125. round: 0,
  126. members: 0,
  127. channels: 0,
  128. categories: 0,
  129. threads: 0,
  130. posts: 0,
  131. proposals: 0,
  132. proposalPosts: 0
  133. }; }
  134. return __awaiter(void 0, void 0, void 0, function () {
  135. var id, exists, block, key, account, _a, _b, _c, handle, q;
  136. var _d;
  137. return __generator(this, function (_e) {
  138. switch (_e.label) {
  139. case 0:
  140. id = +header.number;
  141. return [4 /*yield*/, models_1.Block.findByPk(id)];
  142. case 1:
  143. exists = _e.sent();
  144. if (exists) {
  145. console.error("TODO handle fork", String(header.author));
  146. return [2 /*return*/, status];
  147. }
  148. return [4 /*yield*/, processBlock(api, id)];
  149. case 2:
  150. block = _e.sent();
  151. key = (_d = header.author) === null || _d === void 0 ? void 0 : _d.toString();
  152. return [4 /*yield*/, models_1.Account.findOrCreate({ where: { key: key } })];
  153. case 3:
  154. account = (_e.sent())[0];
  155. return [4 /*yield*/, block.setValidator(account.key)
  156. //account.addBlock(block.id) // TODO needed?
  157. ];
  158. case 4:
  159. _e.sent();
  160. //account.addBlock(block.id) // TODO needed?
  161. _b = (_a = io).emit;
  162. _c = ['block'];
  163. return [4 /*yield*/, models_1.Block.findByIdWithIncludes(id)];
  164. case 5:
  165. //account.addBlock(block.id) // TODO needed?
  166. _b.apply(_a, _c.concat([_e.sent()]));
  167. return [4 /*yield*/, getHandleOrKey(api, key)];
  168. case 6:
  169. handle = _e.sent();
  170. q = queue.length ? chalk_1["default"].green(" [" + queue.length + ":" + processing + "]") : '';
  171. console.log("[Joystream] block " + id + " " + handle + " " + q);
  172. return [2 /*return*/, updateStatus(api, status, id)];
  173. }
  174. });
  175. });
  176. };
  177. var processBlock = function (api, id) { return __awaiter(void 0, void 0, void 0, function () {
  178. var exists, last, lastBlockTimestamp, lastBlockHash, block, _a, currentBlockTimestamp;
  179. return __generator(this, function (_b) {
  180. switch (_b.label) {
  181. case 0: return [4 /*yield*/, models_1.Block.findByPk(id)];
  182. case 1:
  183. exists = _b.sent();
  184. if (exists)
  185. return [2 /*return*/, exists];
  186. processing = "block " + id;
  187. return [4 /*yield*/, models_1.Block.findByPk(id - 1)];
  188. case 2:
  189. last = _b.sent();
  190. if (!last) return [3 /*break*/, 3];
  191. lastBlockTimestamp = last.timestamp.getTime();
  192. return [3 /*break*/, 6];
  193. case 3: return [4 /*yield*/, getBlockHash(api, id - 1)];
  194. case 4:
  195. lastBlockHash = _b.sent();
  196. return [4 /*yield*/, getTimestamp(api, lastBlockHash)];
  197. case 5:
  198. lastBlockTimestamp = _b.sent();
  199. _b.label = 6;
  200. case 6: return [4 /*yield*/, models_1.Block.findOrCreate({ where: { id: id } })];
  201. case 7:
  202. block = (_b.sent())[0];
  203. _a = block;
  204. return [4 /*yield*/, getBlockHash(api, id)];
  205. case 8:
  206. _a.hash = _b.sent();
  207. return [4 /*yield*/, getTimestamp(api, block.hash)];
  208. case 9:
  209. currentBlockTimestamp = _b.sent();
  210. block.timestamp = new Date(currentBlockTimestamp);
  211. block.blocktime = (currentBlockTimestamp - lastBlockTimestamp);
  212. block.save();
  213. processEvents(api, id, block.hash);
  214. return [4 /*yield*/, importEraAtBlock(api, id, block.hash)];
  215. case 10:
  216. _b.sent();
  217. return [2 /*return*/, block];
  218. }
  219. });
  220. }); };
  221. var addBlockRange = function (api, startBlock, endBlock) { return __awaiter(void 0, void 0, void 0, function () {
  222. var _loop_1, block;
  223. return __generator(this, function (_a) {
  224. _loop_1 = function (block) {
  225. queue.push(function () { return processBlock(api, block); });
  226. };
  227. for (block = startBlock; block <= endBlock; block++) {
  228. _loop_1(block);
  229. }
  230. return [2 /*return*/];
  231. });
  232. }); };
  233. var updateStatus = function (api, old, block) { return __awaiter(void 0, void 0, void 0, function () {
  234. var status, _a;
  235. var _b;
  236. return __generator(this, function (_c) {
  237. switch (_c.label) {
  238. case 0: return [4 /*yield*/, getEraAtBlock(api, block)];
  239. case 1:
  240. _a = Number;
  241. return [4 /*yield*/, api.query.councilElection.round()];
  242. case 2: return [4 /*yield*/, api.query.members.nextMemberId()];
  243. case 3: return [4 /*yield*/, get.currentChannelId(api)];
  244. case 4: return [4 /*yield*/, get.currentCategoryId(api)];
  245. case 5: return [4 /*yield*/, get.currentThreadId(api)];
  246. case 6: return [4 /*yield*/, get.currentPostId(api)];
  247. case 7: return [4 /*yield*/, get.proposalCount(api)];
  248. case 8: return [4 /*yield*/, api.query.proposalsDiscussion.postCount()];
  249. case 9:
  250. status = (_b = {
  251. block: block
  252. },
  253. _b.era = _c.sent(),
  254. _b.round = _a.apply(void 0, [_c.sent()]),
  255. _b.members = (_c.sent()) - 1,
  256. _b.channels = _c.sent(),
  257. _b.categories = _c.sent(),
  258. _b.threads = _c.sent(),
  259. _b.posts = _c.sent(),
  260. _b.proposals = _c.sent(),
  261. _b.proposalPosts = (_c.sent()).toHuman(),
  262. _b);
  263. if (!queuedAll)
  264. fetchAll(api, status);
  265. else {
  266. // TODO catch if more than one are added
  267. status.members > old.members && fetchMember(api, status.members);
  268. status.posts > old.posts && fetchPost(api, status.posts);
  269. status.proposals > old.proposals && fetchProposal(api, status.proposals);
  270. status.channels > old.channels && fetchChannel(api, status.channels);
  271. status.categories > old.categories && fetchCategory(api, status.categories);
  272. status.proposalPosts > old.proposalPosts &&
  273. fetchProposalPosts(api, status.proposalPosts);
  274. }
  275. return [2 /*return*/, status];
  276. }
  277. });
  278. }); };
  279. var fetchAll = function (api, status) { return __awaiter(void 0, void 0, void 0, function () {
  280. var _loop_2, id, _loop_3, id, _loop_4, id, _loop_5, id, _loop_6, id, _loop_7, id, _loop_8, id;
  281. return __generator(this, function (_a) {
  282. queue.push(function () { return fetchAccounts(api, status.block); });
  283. _loop_2 = function (id) {
  284. queue.push(function () { return fetchMember(api, id); });
  285. };
  286. for (id = status.members; id > 0; id--) {
  287. _loop_2(id);
  288. }
  289. _loop_3 = function (id) {
  290. queue.push(function () { return fetchCouncil(api, id); });
  291. };
  292. for (id = status.round; id > 0; id--) {
  293. _loop_3(id);
  294. }
  295. _loop_4 = function (id) {
  296. queue.push(function () { return fetchProposal(api, id); });
  297. };
  298. for (id = status.proposals; id > 0; id--) {
  299. _loop_4(id);
  300. }
  301. _loop_5 = function (id) {
  302. queue.push(function () { return fetchChannel(api, id); });
  303. };
  304. for (id = status.channels; id > 0; id--) {
  305. _loop_5(id);
  306. }
  307. _loop_6 = function (id) {
  308. queue.push(function () { return fetchCategory(api, id); });
  309. };
  310. for (id = status.categories; id > 0; id--) {
  311. _loop_6(id);
  312. }
  313. _loop_7 = function (id) {
  314. queue.push(function () { return fetchThread(api, id); });
  315. };
  316. for (id = status.threads; id > 0; id--) {
  317. _loop_7(id);
  318. }
  319. _loop_8 = function (id) {
  320. queue.push(function () { return fetchPost(api, id); });
  321. };
  322. for (id = status.posts; id > 0; id--) {
  323. _loop_8(id);
  324. }
  325. queue.push(function () { return fetchProposalPosts(api, status.proposalPosts); });
  326. queue.push(function () { return addBlockRange(api, 1, status.block); });
  327. queuedAll = true;
  328. processNext();
  329. return [2 /*return*/];
  330. });
  331. }); };
  332. var processEvents = function (api, blockId, hash) { return __awaiter(void 0, void 0, void 0, function () {
  333. var blockEvents, e_1;
  334. return __generator(this, function (_a) {
  335. switch (_a.label) {
  336. case 0:
  337. processing = "events block " + blockId;
  338. _a.label = 1;
  339. case 1:
  340. _a.trys.push([1, 3, , 4]);
  341. return [4 /*yield*/, api.query.system.events.at(hash)];
  342. case 2:
  343. blockEvents = _a.sent();
  344. blockEvents.forEach(function (_a) {
  345. var event = _a.event;
  346. var section = event.section, method = event.method, data = event.data;
  347. models_1.Event.create({ blockId: blockId, section: section, method: method, data: JSON.stringify(data) });
  348. });
  349. return [3 /*break*/, 4];
  350. case 3:
  351. e_1 = _a.sent();
  352. console.log("failed to fetch events for block " + blockId + " " + hash);
  353. return [3 /*break*/, 4];
  354. case 4: return [2 /*return*/];
  355. }
  356. });
  357. }); };
  358. var fetchValidators = function (api, hash) { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
  359. return [2 /*return*/, api.query.staking.snapshotValidators.at(hash)];
  360. }); }); };
  361. var importEraAtBlock = function (api, blockId, hash) { return __awaiter(void 0, void 0, void 0, function () {
  362. var id, era;
  363. return __generator(this, function (_a) {
  364. switch (_a.label) {
  365. case 0: return [4 /*yield*/, getEraAtHash(api, hash)];
  366. case 1:
  367. id = _a.sent();
  368. return [4 /*yield*/, models_1.Era.findOrCreate({ where: { id: id } })];
  369. case 2:
  370. era = (_a.sent())[0];
  371. era.addBlock(blockId);
  372. if (era.active)
  373. return [2 /*return*/];
  374. processing = "era " + id;
  375. try {
  376. fetchValidators(api, hash).then(function (snapshot) { return __awaiter(void 0, void 0, void 0, function () {
  377. var validatorCount, _a, _b, chainTimestamp;
  378. return __generator(this, function (_c) {
  379. switch (_c.label) {
  380. case 0:
  381. if (snapshot.isEmpty)
  382. return [2 /*return*/];
  383. console.log("[Joystream] Found validator info for era " + id);
  384. validatorCount = snapshot.unwrap().length;
  385. _a = era;
  386. return [4 /*yield*/, api.query.staking.validatorCount.at(hash)];
  387. case 1:
  388. _a.slots = (_c.sent()).toNumber();
  389. era.active = Math.min(era.slots, validatorCount);
  390. era.waiting =
  391. validatorCount > era.slots ? validatorCount - era.slots : 0;
  392. _b = era;
  393. return [4 /*yield*/, api.query.staking.erasTotalStake.at(hash, id)];
  394. case 2:
  395. _b.stake = _c.sent();
  396. return [4 /*yield*/, api.query.timestamp.now.at(hash)];
  397. case 3:
  398. chainTimestamp = (_c.sent());
  399. era.timestamp = moment_1["default"](chainTimestamp.toNumber());
  400. // era.update({ slots, active, waiting, stake, timestamp })
  401. era.blockId = id;
  402. era.save();
  403. updateBalances(api, hash);
  404. return [2 /*return*/];
  405. }
  406. });
  407. }); });
  408. }
  409. catch (e) {
  410. console.error("import era " + blockId + " " + hash, e);
  411. }
  412. return [2 /*return*/];
  413. }
  414. });
  415. }); };
  416. var validatorStatus = function (api, blockId) { return __awaiter(void 0, void 0, void 0, function () {
  417. var hash, totalValidators, totalNrValidators, maxSlots, _a, actives, waiting, timestamp, date;
  418. return __generator(this, function (_b) {
  419. switch (_b.label) {
  420. case 0: return [4 /*yield*/, getBlockHash(api, blockId)];
  421. case 1:
  422. hash = _b.sent();
  423. return [4 /*yield*/, api.query.staking.snapshotValidators.at(hash)];
  424. case 2:
  425. totalValidators = _b.sent();
  426. if (totalValidators.isEmpty)
  427. return [2 /*return*/];
  428. totalNrValidators = totalValidators.unwrap().length;
  429. _a = Number;
  430. return [4 /*yield*/, api.query.staking.validatorCount.at(hash)];
  431. case 3:
  432. maxSlots = _a.apply(void 0, [_b.sent()]);
  433. actives = Math.min(maxSlots, totalNrValidators);
  434. waiting = totalNrValidators > maxSlots ? totalNrValidators - maxSlots : 0;
  435. return [4 /*yield*/, api.query.timestamp.now.at(hash)];
  436. case 4:
  437. timestamp = _b.sent();
  438. date = moment_1["default"](timestamp.toNumber()).valueOf();
  439. return [2 /*return*/, { blockId: blockId, actives: actives, waiting: waiting, maxSlots: maxSlots, date: date }];
  440. }
  441. });
  442. }); };
  443. var updateBalances = function (api, blockHash) { return __awaiter(void 0, void 0, void 0, function () {
  444. var currentEra, era;
  445. return __generator(this, function (_a) {
  446. switch (_a.label) {
  447. case 0: return [4 /*yield*/, api.query.staking.currentEra.at(blockHash)];
  448. case 1:
  449. currentEra = _a.sent();
  450. return [4 /*yield*/, models_1.Era.findOrCreate({ where: { id: currentEra } })];
  451. case 2:
  452. era = _a.sent();
  453. try {
  454. processing = "balances " + era;
  455. models_1.Account.findAll().then(function (account) { return __awaiter(void 0, void 0, void 0, function () {
  456. var key, data, free, reserved, miscFrozen, feeFrozen, balance;
  457. return __generator(this, function (_a) {
  458. switch (_a.label) {
  459. case 0:
  460. key = account.key;
  461. if (!key)
  462. return [2 /*return*/];
  463. console.log("updating balance of", key, key);
  464. return [4 /*yield*/, getAccountAtBlock(api, blockHash, key)];
  465. case 1:
  466. data = (_a.sent()).data;
  467. free = data.free, reserved = data.reserved, miscFrozen = data.miscFrozen, feeFrozen = data.feeFrozen;
  468. balance = { available: free, reserved: reserved, frozen: miscFrozen };
  469. console.log("balance " + era, balance);
  470. models_1.Balance.create(balance).then(function (balance) {
  471. balance.setAccount(key);
  472. balance.setEra(era.id);
  473. console.log("balance", era.id, key, balance.available);
  474. });
  475. return [2 /*return*/];
  476. }
  477. });
  478. }); });
  479. }
  480. catch (e) {
  481. console.error("balances era " + era);
  482. }
  483. return [2 /*return*/];
  484. }
  485. });
  486. }); };
  487. var fetchTokenomics = function () { return __awaiter(void 0, void 0, void 0, function () {
  488. var data;
  489. return __generator(this, function (_a) {
  490. switch (_a.label) {
  491. case 0:
  492. console.debug("Updating tokenomics");
  493. return [4 /*yield*/, axios_1["default"].get('https://status.joystream.org/status')];
  494. case 1:
  495. data = (_a.sent()).data;
  496. if (!data)
  497. return [2 /*return*/];
  498. return [2 /*return*/];
  499. }
  500. });
  501. }); };
  502. var fetchChannel = function (api, id) { return __awaiter(void 0, void 0, void 0, function () {
  503. var exists, data, handle, title, description, avatar, banner, content, created, channel, chan, owner;
  504. return __generator(this, function (_a) {
  505. switch (_a.label) {
  506. case 0:
  507. if (id <= 0)
  508. return [2 /*return*/];
  509. return [4 /*yield*/, models_1.Channel.findByPk(id)];
  510. case 1:
  511. exists = _a.sent();
  512. if (exists)
  513. return [2 /*return*/, exists];
  514. processing = "channel " + id;
  515. return [4 /*yield*/, api.query.contentWorkingGroup.channelById(id)];
  516. case 2:
  517. data = _a.sent();
  518. handle = data.handle, title = data.title, description = data.description, avatar = data.avatar, banner = data.banner, content = data.content, created = data.created;
  519. channel = {
  520. id: id,
  521. handle: String(handle),
  522. title: String(title),
  523. description: String(description),
  524. avatar: String(avatar),
  525. banner: String(banner),
  526. content: String(content),
  527. publicationStatus: data.publication_status === 'Public' ? true : false,
  528. curation: String(data.curation_status),
  529. createdAt: +created,
  530. principal: Number(data.principal_id)
  531. };
  532. return [4 /*yield*/, models_1.Channel.create(channel)];
  533. case 3:
  534. chan = _a.sent();
  535. return [4 /*yield*/, fetchMember(api, data.owner)];
  536. case 4:
  537. owner = _a.sent();
  538. chan.setOwner(owner);
  539. return [2 /*return*/, chan];
  540. }
  541. });
  542. }); };
  543. var fetchCategory = function (api, id) { return __awaiter(void 0, void 0, void 0, function () {
  544. var exists, data, title, description, deleted, archived, category;
  545. return __generator(this, function (_a) {
  546. switch (_a.label) {
  547. case 0:
  548. if (id <= 0)
  549. return [2 /*return*/];
  550. return [4 /*yield*/, models_1.Category.findByPk(+id)];
  551. case 1:
  552. exists = _a.sent();
  553. if (exists)
  554. return [2 /*return*/, exists];
  555. processing = "category " + id;
  556. return [4 /*yield*/, api.query.forum.categoryById(id)];
  557. case 2:
  558. data = _a.sent();
  559. title = data.title, description = data.description, deleted = data.deleted, archived = data.archived;
  560. return [4 /*yield*/, models_1.Category.create({
  561. id: id,
  562. title: title,
  563. threadId: +data.thread_id,
  564. description: description,
  565. createdAt: +data.created_at.block,
  566. deleted: deleted,
  567. archived: archived,
  568. subcategories: Number(data.num_direct_subcategories),
  569. moderatedThreads: Number(data.num_direct_moderated_threads),
  570. unmoderatedThreads: Number(data.num_direct_unmoderated_threads)
  571. })];
  572. case 3:
  573. category = _a.sent();
  574. createModeration(api, { categoryId: id }, String(data.moderator_id), category);
  575. return [2 /*return*/, category];
  576. }
  577. });
  578. }); };
  579. var fetchPost = function (api, id) { return __awaiter(void 0, void 0, void 0, function () {
  580. var exists, data, author, member, authorId, threadId, thread, text, history, createdAt, post;
  581. return __generator(this, function (_a) {
  582. switch (_a.label) {
  583. case 0:
  584. if (id <= 0)
  585. return [2 /*return*/];
  586. return [4 /*yield*/, models_1.Post.findByPk(id)];
  587. case 1:
  588. exists = _a.sent();
  589. if (exists)
  590. return [2 /*return*/, exists];
  591. processing = "post " + id;
  592. return [4 /*yield*/, api.query.forum.postById(id)];
  593. case 2:
  594. data = _a.sent();
  595. author = String(data.author_id);
  596. return [4 /*yield*/, fetchMemberByAccount(api, author)];
  597. case 3:
  598. member = _a.sent();
  599. authorId = member ? member.id : null;
  600. threadId = Number(data.thread_id);
  601. return [4 /*yield*/, fetchThread(api, threadId)];
  602. case 4:
  603. thread = _a.sent();
  604. text = data.current_text;
  605. history = data.text_change_history // TODO needed?
  606. ;
  607. createdAt = data.created_at.block;
  608. return [4 /*yield*/, models_1.Post.create({ id: id, authorId: authorId, text: text, createdAt: createdAt, threadId: threadId })];
  609. case 5:
  610. post = _a.sent();
  611. if (data.moderation)
  612. createModeration(api, { postId: id }, data.moderation, post);
  613. return [2 /*return*/, post];
  614. }
  615. });
  616. }); };
  617. var createModeration = function (api, where, key, object) { return __awaiter(void 0, void 0, void 0, function () {
  618. var moderation;
  619. return __generator(this, function (_a) {
  620. switch (_a.label) {
  621. case 0:
  622. if (key === '')
  623. return [2 /*return*/];
  624. return [4 /*yield*/, models_1.Account.findOrCreate({ where: { key: key } })];
  625. case 1:
  626. _a.sent();
  627. return [4 /*yield*/, models_1.Moderation.create({ moderatorKey: key })];
  628. case 2:
  629. moderation = _a.sent();
  630. object.setModeration(moderation.id);
  631. return [2 /*return*/, moderation];
  632. }
  633. });
  634. }); };
  635. var fetchThread = function (api, id) { return __awaiter(void 0, void 0, void 0, function () {
  636. var exists, data, title, moderation, nr_in_category, account, t, thread, category, author, moderated_at, moderator_id, rationale, created, createdAt;
  637. return __generator(this, function (_a) {
  638. switch (_a.label) {
  639. case 0:
  640. if (id <= 0)
  641. return [2 /*return*/];
  642. return [4 /*yield*/, models_1.Thread.findByPk(id)];
  643. case 1:
  644. exists = _a.sent();
  645. if (exists)
  646. return [2 /*return*/, exists];
  647. processing = "thread " + id;
  648. return [4 /*yield*/, api.query.forum.threadById(id)];
  649. case 2:
  650. data = _a.sent();
  651. title = data.title, moderation = data.moderation, nr_in_category = data.nr_in_category;
  652. account = String(data.author_id);
  653. t = {
  654. id: id,
  655. title: title,
  656. nrInCategory: +nr_in_category,
  657. createdAt: +data.created_at.block
  658. };
  659. return [4 /*yield*/, models_1.Thread.create(t)];
  660. case 3:
  661. thread = _a.sent();
  662. return [4 /*yield*/, fetchCategory(api, +data.category_id)];
  663. case 4:
  664. category = _a.sent();
  665. if (category)
  666. thread.setCategory(category.id);
  667. return [4 /*yield*/, fetchMemberByAccount(api, account)];
  668. case 5:
  669. author = _a.sent();
  670. if (author)
  671. thread.setCreator(author.id);
  672. if (moderation) {
  673. moderated_at = moderation.moderated_at, moderator_id = moderation.moderator_id, rationale = moderation.rationale;
  674. created = moderated_at.block;
  675. createdAt = moment_1["default"].utc(moderated_at.time);
  676. createModeration(api, { created: created, createdAt: createdAt, rationale: rationale }, moderator_id.toHuman(), thread);
  677. }
  678. return [2 /*return*/, thread];
  679. }
  680. });
  681. }); };
  682. var fetchCouncil = function (api, round) { return __awaiter(void 0, void 0, void 0, function () {
  683. var exists, start, end, council, seats, startHash, _a, e_2, endHash, _b, e_3;
  684. return __generator(this, function (_c) {
  685. switch (_c.label) {
  686. case 0:
  687. if (round <= 0)
  688. return [2 /*return*/, console.log(chalk_1["default"].red("[fetchCouncil] round:" + round))];
  689. return [4 /*yield*/, models_1.Council.findByPk(round)];
  690. case 1:
  691. exists = _c.sent();
  692. if (exists)
  693. return [2 /*return*/, exists];
  694. processing = "council " + round;
  695. start = 57601 + (round - 1) * CYCLE;
  696. end = start + TERMDURATION;
  697. council = { round: round, start: start, end: end, startDate: 0, endDate: 0 };
  698. _c.label = 2;
  699. case 2:
  700. _c.trys.push([2, 6, , 7]);
  701. return [4 /*yield*/, getBlockHash(api, start)];
  702. case 3:
  703. startHash = _c.sent();
  704. _a = council;
  705. return [4 /*yield*/, getTimestamp(api, startHash)];
  706. case 4:
  707. _a.startDate = _c.sent();
  708. return [4 /*yield*/, api.query.council.activeCouncil.at(startHash)];
  709. case 5:
  710. seats = _c.sent();
  711. return [3 /*break*/, 7];
  712. case 6:
  713. e_2 = _c.sent();
  714. return [2 /*return*/, console.log("council term " + round + " lies in the future " + start)];
  715. case 7:
  716. _c.trys.push([7, 10, , 11]);
  717. return [4 /*yield*/, getBlockHash(api, end)];
  718. case 8:
  719. endHash = _c.sent();
  720. _b = council;
  721. return [4 /*yield*/, getTimestamp(api, endHash)];
  722. case 9:
  723. _b.endDate = _c.sent();
  724. return [3 /*break*/, 11];
  725. case 10:
  726. e_3 = _c.sent();
  727. console.warn("end of council term " + round + " lies in the future " + end);
  728. return [3 /*break*/, 11];
  729. case 11:
  730. try {
  731. models_1.Council.create(council).then(function (_a) {
  732. var round = _a.round;
  733. return seats.map(function (_a) {
  734. var member = _a.member, stake = _a.stake, backers = _a.backers;
  735. return fetchMemberByAccount(api, member.toHuman()).then(function (_a) {
  736. var id = _a.id;
  737. return models_1.Consul.create({
  738. stake: Number(stake),
  739. councilRound: round,
  740. memberId: id
  741. }).then(function (consul) {
  742. return backers.map(function (_a) {
  743. var member = _a.member, stake = _a.stake;
  744. return __awaiter(void 0, void 0, void 0, function () {
  745. return __generator(this, function (_b) {
  746. return [2 /*return*/, fetchMemberByAccount(api, member.toHuman()).then(function (_a) {
  747. var id = _a.id;
  748. return models_1.ConsulStake.create({
  749. stake: Number(stake),
  750. consulId: consul.id,
  751. memberId: id
  752. });
  753. })];
  754. });
  755. });
  756. });
  757. });
  758. });
  759. });
  760. });
  761. }
  762. catch (e) {
  763. console.error("Failed to save council " + round, e);
  764. }
  765. return [2 /*return*/];
  766. }
  767. });
  768. }); };
  769. var fetchProposal = function (api, id) { return __awaiter(void 0, void 0, void 0, function () {
  770. var exists, proposal;
  771. return __generator(this, function (_a) {
  772. switch (_a.label) {
  773. case 0:
  774. if (id <= 0)
  775. return [2 /*return*/];
  776. return [4 /*yield*/, models_1.Proposal.findByPk(+id)];
  777. case 1:
  778. exists = _a.sent();
  779. if (exists) {
  780. fetchProposalVotes(api, exists);
  781. return [2 /*return*/, exists];
  782. }
  783. processing = "proposal " + id;
  784. return [4 /*yield*/, get.proposalDetail(api, id)];
  785. case 2:
  786. proposal = _a.sent();
  787. return [4 /*yield*/, fetchMember(api, proposal.authorId)];
  788. case 3:
  789. _a.sent();
  790. fetchProposalVotes(api, proposal);
  791. return [2 /*return*/, models_1.Proposal.create(proposal)];
  792. }
  793. });
  794. }); };
  795. var fetchProposalPost = function (api, threadId, postId) {
  796. return api.query.proposalsDiscussion.postThreadIdByPostId(threadId, postId);
  797. };
  798. var fetchProposalPosts = function (api, posts) { return __awaiter(void 0, void 0, void 0, function () {
  799. var threads, proposalId, _loop_9, out_id_1, id;
  800. return __generator(this, function (_a) {
  801. switch (_a.label) {
  802. case 0: return [4 /*yield*/, api.query.proposalsDiscussion.threadCount()];
  803. case 1:
  804. threads = (_a.sent()).toNumber();
  805. proposalId = 1;
  806. _loop_9 = function (id) {
  807. var exists, post, proposal;
  808. return __generator(this, function (_a) {
  809. switch (_a.label) {
  810. case 0: return [4 /*yield*/, models_1.ProposalPost.findByPk(id)];
  811. case 1:
  812. exists = _a.sent();
  813. if (exists) {
  814. id++;
  815. proposalId = 1;
  816. return [2 /*return*/, (out_id_1 = id, "continue")];
  817. }
  818. processing = "proposal post " + id + "/" + posts + " " + proposalId + "/" + threads;
  819. return [4 /*yield*/, fetchProposalPost(api, proposalId, id)];
  820. case 2:
  821. post = _a.sent();
  822. if (!post.text.length) {
  823. proposalId++;
  824. return [2 /*return*/, (out_id_1 = id, "continue")];
  825. }
  826. return [4 /*yield*/, models_1.Proposal.findByPk(proposalId)];
  827. case 3:
  828. proposal = _a.sent();
  829. if (!proposal) {
  830. console.warn("[fetchProposalPosts] proposal " + proposalId + " not found.");
  831. id++;
  832. return [2 /*return*/, (out_id_1 = id, "continue")];
  833. }
  834. models_1.ProposalPost.create({
  835. id: id,
  836. text: post.text.toHuman(),
  837. created: Number(post.created_at),
  838. updated: Number(post.updated_at),
  839. edition: Number(post.edition_number),
  840. authorId: Number(post.author_id)
  841. }).then(function (p) { return proposal.addPost(p); });
  842. id++;
  843. proposalId = 1;
  844. out_id_1 = id;
  845. return [2 /*return*/];
  846. }
  847. });
  848. };
  849. id = 1;
  850. _a.label = 2;
  851. case 2:
  852. if (!(id <= posts && proposalId <= threads)) return [3 /*break*/, 5];
  853. return [5 /*yield**/, _loop_9(id)];
  854. case 3:
  855. _a.sent();
  856. id = out_id_1;
  857. _a.label = 4;
  858. case 4: return [3 /*break*/, 2];
  859. case 5: return [2 /*return*/];
  860. }
  861. });
  862. }); };
  863. var fetchProposalVotes = function (api, proposal) { return __awaiter(void 0, void 0, void 0, function () {
  864. var createdAt, finalizedAt, start, _a, end, _b, councils, consuls, e_4;
  865. var _c;
  866. return __generator(this, function (_d) {
  867. switch (_d.label) {
  868. case 0:
  869. if (!proposal)
  870. return [2 /*return*/, console.error("[fetchProposalVotes] empty proposal")];
  871. processing = "votes proposal " + proposal.id;
  872. createdAt = proposal.createdAt, finalizedAt = proposal.finalizedAt;
  873. _d.label = 1;
  874. case 1:
  875. _d.trys.push([1, 9, , 10]);
  876. if (!createdAt) return [3 /*break*/, 3];
  877. return [4 /*yield*/, findCouncilAtBlock(api, createdAt)];
  878. case 2:
  879. _a = _d.sent();
  880. return [3 /*break*/, 4];
  881. case 3:
  882. _a = null;
  883. _d.label = 4;
  884. case 4:
  885. start = _a;
  886. if (start)
  887. start.addProposal(proposal.id);
  888. else
  889. return [2 /*return*/, console.error("[fetchProposalVotes] no council found for proposal " + proposal.id)
  890. // some proposals make it into a second term
  891. ];
  892. if (!finalizedAt) return [3 /*break*/, 6];
  893. return [4 /*yield*/, findCouncilAtBlock(api, finalizedAt)];
  894. case 5:
  895. _b = _d.sent();
  896. return [3 /*break*/, 7];
  897. case 6:
  898. _b = null;
  899. _d.label = 7;
  900. case 7:
  901. end = _b;
  902. councils = [start && start.round, end && end.round];
  903. return [4 /*yield*/, models_1.Consul.findAll({
  904. where: { councilRound: (_c = {}, _c[sequelize_1.Op.or] = councils, _c) }
  905. })];
  906. case 8:
  907. consuls = _d.sent();
  908. consuls.map(function (_a) {
  909. var id = _a.id, memberId = _a.memberId;
  910. return fetchProposalVoteByConsul(api, proposal.id, id, memberId);
  911. });
  912. return [3 /*break*/, 10];
  913. case 9:
  914. e_4 = _d.sent();
  915. console.log("failed to fetch votes of proposal " + proposal.id, e_4);
  916. return [3 /*break*/, 10];
  917. case 10: return [2 /*return*/];
  918. }
  919. });
  920. }); };
  921. var fetchProposalVoteByConsul = function (api, proposalId, consulId, memberId) { return __awaiter(void 0, void 0, void 0, function () {
  922. var exists, query, args, hasVoted, vote;
  923. var _a;
  924. return __generator(this, function (_b) {
  925. switch (_b.label) {
  926. case 0:
  927. processing = "vote by " + consulId + " for proposal " + proposalId;
  928. return [4 /*yield*/, models_1.ProposalVote.findOne({
  929. where: { proposalId: proposalId, memberId: memberId, consulId: consulId }
  930. })];
  931. case 1:
  932. exists = _b.sent();
  933. if (exists)
  934. return [2 /*return*/, exists];
  935. query = api.query.proposalsEngine;
  936. args = [proposalId, memberId];
  937. return [4 /*yield*/, (_a = query.voteExistsByProposalByVoter).size.apply(_a, args)];
  938. case 2:
  939. hasVoted = _b.sent();
  940. if (!hasVoted.toNumber())
  941. return [2 /*return*/];
  942. return [4 /*yield*/, query.voteExistsByProposalByVoter.apply(query, args)];
  943. case 3:
  944. vote = (_b.sent()).toHuman();
  945. return [4 /*yield*/, fetchMember(api, memberId)]; // TODO needed?
  946. case 4:
  947. _b.sent(); // TODO needed?
  948. return [2 /*return*/, models_1.ProposalVote.create({ vote: vote, proposalId: proposalId, consulId: consulId, memberId: memberId })];
  949. }
  950. });
  951. }); };
  952. // accounts
  953. var getHandleOrKey = function (api, key) { return __awaiter(void 0, void 0, void 0, function () {
  954. var member;
  955. return __generator(this, function (_a) {
  956. switch (_a.label) {
  957. case 0: return [4 /*yield*/, fetchMemberByAccount(api, key)];
  958. case 1:
  959. member = _a.sent();
  960. return [2 /*return*/, member ? member.handle : key]; //abbrKey(key)
  961. }
  962. });
  963. }); };
  964. var abbrKey = function (key) {
  965. return key.slice(0, 5) + ".." + key.slice(key.length - 5);
  966. };
  967. var getAccountAtBlock = function (api, hash, account) { return api.query.system.account.at(hash, account); };
  968. var fetchAccounts = function (api, blockId) { return __awaiter(void 0, void 0, void 0, function () {
  969. return __generator(this, function (_a) {
  970. processing = "accounts";
  971. api.query.system.account
  972. .entries()
  973. .then(function (account) {
  974. return models_1.Account.findOrCreate({ where: { key: account[0][0].toHuman()[0] } });
  975. });
  976. return [2 /*return*/];
  977. });
  978. }); };
  979. var fetchMemberByAccount = function (api, rootKey) { return __awaiter(void 0, void 0, void 0, function () {
  980. var member, id, _a;
  981. return __generator(this, function (_b) {
  982. switch (_b.label) {
  983. case 0: return [4 /*yield*/, models_1.Member.findOne({ where: { rootKey: rootKey } })];
  984. case 1:
  985. member = _b.sent();
  986. if (member)
  987. return [2 /*return*/, member];
  988. _a = Number;
  989. return [4 /*yield*/, get.memberIdByAccount(api, rootKey)];
  990. case 2:
  991. id = _a.apply(void 0, [_b.sent()]);
  992. if (id)
  993. return [2 /*return*/, fetchMember(api, id)];
  994. else
  995. models_1.Account.findOrCreate({ where: { key: rootKey } });
  996. return [2 /*return*/];
  997. }
  998. });
  999. }); };
  1000. var fetchMember = function (api, id) { return __awaiter(void 0, void 0, void 0, function () {
  1001. var exists, membership, about, handle, createdAt, rootKey;
  1002. return __generator(this, function (_a) {
  1003. switch (_a.label) {
  1004. case 0:
  1005. if (id <= 0)
  1006. return [2 /*return*/];
  1007. return [4 /*yield*/, models_1.Member.findByPk(+id)];
  1008. case 1:
  1009. exists = _a.sent();
  1010. if (exists)
  1011. return [2 /*return*/, exists];
  1012. processing = "member " + id;
  1013. return [4 /*yield*/, get.membership(api, id)];
  1014. case 2:
  1015. membership = _a.sent();
  1016. about = String(membership.about);
  1017. handle = String(membership.handle);
  1018. createdAt = +membership.registered_at_block;
  1019. rootKey = String(membership.root_account);
  1020. return [2 /*return*/, models_1.Member.create({ id: id, about: about, createdAt: createdAt, handle: handle, rootKey: rootKey }).then(function (member) {
  1021. models_1.Account.findOrCreate({ where: { key: rootKey } }).then(function (_a) {
  1022. var account = _a[0];
  1023. return account.setMember(id);
  1024. });
  1025. return member;
  1026. })];
  1027. }
  1028. });
  1029. }); };
  1030. module.exports = { addBlock: addBlock, addBlockRange: addBlockRange };