bitcore-node
Version:
A blockchain indexing node with extended capabilities using bitcore
200 lines • 8.04 kB
JavaScript
"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