UNPKG

bitcore-node

Version:

A blockchain indexing node with extended capabilities using bitcore

200 lines 8.04 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.SyncWorker = void 0; const crypto_rpc_1 = require("crypto-rpc"); const worker = __importStar(require("worker_threads")); const logger_1 = __importDefault(require("../../../../logger")); const config_1 = require("../../../../services/config"); const storage_1 = require("../../../../services/storage"); const utils_1 = require("../../../../utils"); const block_1 = require("../models/block"); const transaction_1 = require("../models/transaction"); const rpcs_1 = require("./rpcs"); class SyncWorker { constructor() { this.chain = worker.workerData.chain; this.network = worker.workerData.network; this.parentPort = worker.parentPort; this.stopping = false; this.isWorking = false; this.chainConfig = config_1.Config.get().chains[this.chain][this.network]; } async start() { await this.connect(); await storage_1.Storage.start(); this.parentPort.on('message', this.messageHandler.bind(this)); } async stop() { this.stopping = true; logger_1.default.info('Stopping syncing thread ' + worker.threadId); while (this.isWorking) { await (0, utils_1.wait)(1000); } await storage_1.Storage.stop(); await this.web3?.currentProvider?.disconnect(); process.exit(0); } async messageHandler(msg) { switch (msg.message) { case 'shutdown': this.stop(); return; default: this.syncBlock(msg); return; } } async syncBlock({ blockNum }) { try { if (this.stopping) { return; } this.isWorking = true; const block = await this.rpc.getBlock(blockNum); if (!block) { worker.parentPort.postMessage({ message: 'sync', notFound: true, blockNum, threadId: worker.threadId }); return; } const { convertedBlock, convertedTxs } = await this.convertBlock(block); await this.processBlock(convertedBlock, convertedTxs); worker.parentPort.postMessage({ message: 'sync', notFound: !block, blockNum: block.number, threadId: worker.threadId }); } catch (err) { logger_1.default.debug(`Syncing thread ${worker.threadId} error: ${err.stack}`); let error = err.message; if (error === 'Invalid JSON RPC response: ""') { error = null; } if (error.includes('connect')) { error = null; logger_1.default.info(`Syncing thread ${worker.threadId} lost connection to the node. Reconnecting.`); await this.connect(); } worker.parentPort.postMessage({ message: 'sync', notFound: true, blockNum, threadId: worker.threadId, error }); } finally { this.isWorking = false; } } async getClient() { const nodeVersion = await this.web3.eth.getNodeInfo(); const client = nodeVersion.split('/')[0].toLowerCase(); if (client !== 'erigon' && client !== 'geth') { // assume it's a geth fork, or at least more like geth. // this is helpful when using a dev solution like ganache. return 'geth'; } return client; } async connect() { const providerIdx = worker.threadId % (this.chainConfig.providers || []).length; const providerConfig = this.chainConfig.provider || this.chainConfig.providers[providerIdx]; const rpcConfig = { ...providerConfig, chain: this.chain, currencyConfig: {} }; this.web3 = new crypto_rpc_1.CryptoRpc(rpcConfig).get(this.chain).web3; this.client = await this.getClient(); this.rpc = new rpcs_1.Rpcs[this.client](this.web3); return { web3: this.web3, rpc: this.rpc }; } async processBlock(block, transactions) { await block_1.EVMBlockStorage.addBlock({ chain: this.chain, network: this.network, forkHeight: this.chainConfig.forkHeight, parentChain: this.chainConfig.parentChain, initialSyncComplete: false, block, transactions }); } getBlockReward(block) { block; return 0; } async convertBlock(block) { const blockTime = Number(block.timestamp) * 1000; const hash = block.hash; const height = block.number; const reward = this.getBlockReward(block); const convertedBlock = { chain: this.chain, network: this.network, height, hash, coinbase: Buffer.from(block.miner), merkleRoot: Buffer.from(block.transactionsRoot), time: new Date(blockTime), timeNormalized: new Date(blockTime), nonce: Buffer.from(block.extraData), previousBlockHash: block.parentHash, difficulty: block.difficulty, totalDifficulty: block.totalDifficulty, nextBlockHash: '', transactionCount: block.transactions.length, size: block.size, reward, logsBloom: Buffer.from(block.logsBloom), sha3Uncles: Buffer.from(block.sha3Uncles), receiptsRoot: Buffer.from(block.receiptsRoot), processed: false, gasLimit: block.gasLimit, gasUsed: block.gasUsed, stateRoot: Buffer.from(block.stateRoot) }; const transactions = block.transactions; const convertedTxs = transactions.map(t => transaction_1.EVMTransactionStorage.convertRawTx(this.chain, this.network, t, convertedBlock)); const traceTxs = await this.rpc.getTransactionsFromBlock(convertedBlock.height); transaction_1.EVMTransactionStorage.addEffectsToTxs(convertedTxs); this.rpc.reconcileTraces(convertedBlock, convertedTxs, traceTxs); return { convertedBlock, convertedTxs }; } } exports.SyncWorker = SyncWorker; worker.parentPort.once('message', async function (msg) { if (msg.message !== 'start') { throw new Error('Unknown startup message'); } await new SyncWorker().start(); return worker.parentPort.postMessage({ message: 'ready' }); }); //# sourceMappingURL=syncWorker.js.map