lisk-framework
Version:
Lisk blockchain application platform
296 lines • 13.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Engine = exports.BLOCKCHAIN_DB_NAME = void 0;
const path = require("path");
const lisk_chain_1 = require("@liskhq/lisk-chain");
const lisk_cryptography_1 = require("@liskhq/lisk-cryptography");
const lisk_db_1 = require("@liskhq/lisk-db");
const logger_1 = require("../logger");
const network_1 = require("./network");
const consensus_1 = require("./consensus");
const generator_1 = require("./generator");
const endpoint_1 = require("../endpoint");
const bft_1 = require("./bft");
const events_1 = require("./events");
const rpc_server_1 = require("./rpc/rpc_server");
const chain_1 = require("./endpoint/chain");
const system_1 = require("./endpoint/system");
const constants_1 = require("./consensus/constants");
const txpool_1 = require("./endpoint/txpool");
const constants_2 = require("./generator/constants");
const consensus_2 = require("./endpoint/consensus");
const state_1 = require("./endpoint/state");
const genesis_block_1 = require("../utils/genesis_block");
const legacy_chain_handler_1 = require("./legacy/legacy_chain_handler");
const endpoint_2 = require("./legacy/endpoint");
const metrics_1 = require("./metrics/metrics");
const backup_1 = require("../utils/backup");
const isEmpty = (value) => {
switch (typeof value) {
case 'undefined':
return true;
case 'string':
return value === '';
case 'number':
return value === 0;
case 'bigint':
return value === BigInt(0);
case 'object':
if (value === null) {
return true;
}
if (Array.isArray(value) && value.length === 0) {
return true;
}
if (Object.keys(value).length === 0) {
return true;
}
return false;
default:
throw new Error('Unknown type.');
}
};
const emptyOrDefault = (value, defaultValue) => (isEmpty(value) ? defaultValue : value);
exports.BLOCKCHAIN_DB_NAME = 'blockchain.db';
class Engine {
constructor(abi, config) {
this._abi = abi;
this._config = config;
}
async generateBlock(input) {
return this._generator.generateBlock(input);
}
async start() {
if (this._config.system.enableMetrics) {
metrics_1.defaultMetrics.enable();
}
await this._init();
await this._network.start();
if (this._config.legacy.sync) {
this._logger.info('Legacy block sync started');
await this._legacyChainHandler.sync();
this._logger.info('Legacy block sync completed');
}
await this._generator.start();
await this._consensus.start();
await this._rpcServer.start();
await this._abi.init({
lastBlockHeight: this._chain.lastBlock.header.height,
chainID: this._chain.chainID,
lastStateRoot: this._chain.lastBlock.header.stateRoot,
});
this._logger.info('Engine started');
}
async stop() {
this._logger.info('Engine cleanup started');
await this._network.stop();
await this._generator.stop();
await this._consensus.stop();
this._legacyChainHandler.stop();
this._rpcServer.stop();
this._closeDB();
this._logger.info('Engine cleanup completed');
}
async _init() {
this._logger = (0, logger_1.createLogger)({
name: 'engine',
logLevel: emptyOrDefault(this._config.system.logLevel, 'info'),
});
this._logger.info('Engine initialization starting');
this._network = new network_1.Network({
options: this._config.network,
});
this._chain = new lisk_chain_1.Chain({
maxTransactionsSize: this._config.genesis.maxTransactionsSize,
keepEventsForHeights: this._config.system.keepEventsForHeights,
keepInclusionProofsForHeights: this._config.system.keepInclusionProofsForHeights,
});
this._bftModule = new bft_1.BFTModule();
this._consensus = new consensus_1.Consensus({
abi: this._abi,
network: this._network,
chain: this._chain,
genesisConfig: this._config.genesis,
systemConfig: this._config.system,
bft: this._bftModule,
});
this._generator = new generator_1.Generator({
abi: this._abi,
chain: this._chain,
consensus: this._consensus,
bft: this._bftModule,
config: this._config,
network: this._network,
});
this._legacyChainHandler = new legacy_chain_handler_1.LegacyChainHandler({
legacyConfig: this._config.legacy,
network: this._network,
logger: this._logger,
});
this._rpcServer = new rpc_server_1.RPCServer(this._config.system.dataPath, this._config.rpc);
const genesis = (0, genesis_block_1.readGenesisBlock)(this._config, this._logger);
this._blockchainDB = new lisk_db_1.Database(path.join(this._config.system.dataPath, 'data', exports.BLOCKCHAIN_DB_NAME));
this._generatorDB = new lisk_db_1.Database(path.join(this._config.system.dataPath, 'data', 'generator.db'));
this._legacyDB = new lisk_db_1.Database(path.join(this._config.system.dataPath, 'data', 'legacy.db'));
this._nodeDB = new lisk_db_1.Database(path.join(this._config.system.dataPath, 'data', 'node.db'));
this._chainID = Buffer.from(this._config.genesis.chainID, 'hex');
this._chain.init({
db: this._blockchainDB,
chainID: this._chainID,
genesisBlock: genesis,
});
await this._network.init({
nodeDB: this._nodeDB,
logger: this._logger,
chainID: this._chainID,
});
await this._consensus.init({
db: this._blockchainDB,
genesisBlock: genesis,
logger: this._logger,
legacyDB: this._legacyDB,
});
await this._generator.init({
blockchainDB: this._blockchainDB,
generatorDB: this._generatorDB,
logger: this._logger,
genesisHeight: genesis.header.height,
});
await this._legacyChainHandler.init({
db: this._legacyDB,
});
this._registerEventListeners();
this._rpcServer.init({
logger: this._logger,
chainID: this._chain.chainID,
});
const legacyEndpoint = new endpoint_2.LegacyEndpoint({
db: this._legacyDB,
legacyConfig: this._config.legacy,
});
const chainEndpoint = new chain_1.ChainEndpoint({
chain: this._chain,
bftMethod: this._bftModule.method,
});
chainEndpoint.init(this._blockchainDB);
const consensusEndpoint = new consensus_2.ConsensusEndpoint({
bftMethod: this._bftModule.method,
blockchainDB: this._blockchainDB,
});
const stateEndpoint = new state_1.StateEndpoint({
abi: this._abi,
chain: this._chain,
});
const systemEndpoint = new system_1.SystemEndpoint({
abi: this._abi,
chain: this._chain,
consensus: this._consensus,
generator: this._generator,
config: this._config,
genesisHeight: genesis.header.height,
});
const txpoolEndpoint = new txpool_1.TxpoolEndpoint({
abi: this._abi,
broadcaster: this._generator.broadcaster,
pool: this._generator.txpool,
chain: this._chain,
});
for (const [name, handler] of (0, endpoint_1.getEndpointHandlers)(legacyEndpoint)) {
this._rpcServer.registerEndpoint('legacy', name, handler);
}
for (const [name, handler] of (0, endpoint_1.getEndpointHandlers)(chainEndpoint)) {
this._rpcServer.registerEndpoint('chain', name, handler);
}
for (const [name, handler] of (0, endpoint_1.getEndpointHandlers)(consensusEndpoint)) {
this._rpcServer.registerEndpoint('consensus', name, handler);
}
for (const [name, handler] of (0, endpoint_1.getEndpointHandlers)(stateEndpoint)) {
this._rpcServer.registerEndpoint('state', name, handler);
}
for (const [name, handler] of (0, endpoint_1.getEndpointHandlers)(systemEndpoint)) {
this._rpcServer.registerEndpoint('system', name, handler);
}
for (const [name, handler] of (0, endpoint_1.getEndpointHandlers)(txpoolEndpoint)) {
this._rpcServer.registerEndpoint('txpool', name, handler);
}
for (const [name, handler] of (0, endpoint_1.getEndpointHandlers)(this._generator.endpoint)) {
this._rpcServer.registerEndpoint('generator', name, handler);
}
for (const [name, handler] of (0, endpoint_1.getEndpointHandlers)(this._network.endpoint)) {
this._rpcServer.registerEndpoint('network', name, handler);
}
this._rpcServer.registerNotFoundEndpoint(async (namespace, method, context) => {
const { data } = await this._abi.query({
header: this._chain.lastBlock.header.toObject(),
method: `${namespace}_${method}`,
params: Buffer.from(JSON.stringify(context.params), 'utf-8'),
});
return JSON.parse(data.toString('utf-8'));
});
}
_registerEventListeners() {
this._consensus.events.on(consensus_1.CONSENSUS_EVENT_BLOCK_NEW, ({ block }) => {
this._generator.onNewBlock(block);
Promise.all([
this._rpcServer.publish(events_1.EVENT_CHAIN_BLOCK_NEW, { blockHeader: block.header.toJSON() }),
this._rpcServer.publish(events_1.EVENT_NETWORK_BLOCK_NEW, { blockHeader: block.header.toJSON() }),
]).catch(err => this._logger.error({ err: err }, 'Fail to publish event'));
if (this._config.system.backup.height > 0 &&
block.header.height === this._config.system.backup.height) {
(0, backup_1.backupDatabase)(this._config.system.dataPath, exports.BLOCKCHAIN_DB_NAME, this._blockchainDB).catch(err => {
this._logger.error({ err: err, height: this._config.system.backup.height }, 'Failed to create backup for stateDB');
});
}
});
this._consensus.events.on(consensus_1.CONSENSUS_EVENT_BLOCK_DELETE, ({ block }) => {
this._generator.onDeleteBlock(block);
this._rpcServer
.publish(events_1.EVENT_CHAIN_BLOCK_DELETE, { blockHeader: block.header.toJSON() })
.catch(err => this._logger.error({ err: err }, 'Fail to publish event'));
});
this._consensus.events.on(constants_1.CONSENSUS_EVENT_FORK_DETECTED, ({ block }) => {
this._rpcServer
.publish(events_1.EVENT_CHAIN_FORK, { blockHeader: block.header.toJSON() })
.catch(err => this._logger.error({ err: err }, 'Fail to publish event'));
});
this._consensus.events.on(constants_1.CONSENSUS_EVENT_NETWORK_BLOCK_NEW, ({ block }) => {
this._rpcServer
.publish(events_1.EVENT_NETWORK_BLOCK_NEW, { blockHeader: block.header.toJSON() })
.catch(err => this._logger.error({ err: err }, 'Fail to publish event'));
});
this._consensus.events.on(constants_1.CONSENSUS_EVENT_VALIDATORS_CHANGED, (update) => {
this._rpcServer
.publish(events_1.EVENT_CHAIN_VALIDATORS_CHANGE, {
nextValidators: update.nextValidators.map(v => ({
address: lisk_cryptography_1.address.getLisk32AddressFromAddress(v.address),
blsKey: v.blsKey.toString('hex'),
generatorKey: v.generatorKey.toString('hex'),
bftWeight: v.bftWeight.toString(),
})),
preCommitThreshold: update.preCommitThreshold.toString(),
certificateThreshold: update.certificateThreshold.toString(),
})
.catch(err => this._logger.error({ err: err }, 'Fail to publish event'));
});
this._generator.events.on(constants_2.GENERATOR_EVENT_NEW_TRANSACTION_ANNOUNCEMENT, (event) => {
this._rpcServer
.publish(events_1.EVENT_NETWORK_TRANSACTION_NEW, {
transactionIDs: event.transactionIds.map(id => id.toString('hex')),
})
.catch(err => this._logger.error({ err: err }, 'Fail to publish event'));
});
this._generator.events.on(constants_2.GENERATOR_EVENT_NEW_TRANSACTION, (event) => {
this._rpcServer
.publish(events_1.EVENT_TX_POOL_TRANSACTION_NEW, event)
.catch(err => this._logger.error({ err: err }, 'Fail to publish event'));
});
}
_closeDB() {
this._blockchainDB.close();
this._generatorDB.close();
this._legacyDB.close();
this._nodeDB.close();
}
}
exports.Engine = Engine;
//# sourceMappingURL=engine.js.map