UNPKG

lisk-framework

Version:

Lisk blockchain application platform

258 lines 12.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getBlockProcessingEnv = void 0; const fs = require("fs-extra"); const path = require("path"); const os = require("os"); const lisk_chain_1 = require("@liskhq/lisk-chain"); const lisk_db_1 = require("@liskhq/lisk-db"); const lisk_utils_1 = require("@liskhq/lisk-utils"); const lisk_codec_1 = require("@liskhq/lisk-codec"); const mocks_1 = require("./mocks"); const fixtures_1 = require("./fixtures"); const utils_1 = require("./utils"); const state_machine_1 = require("../state_machine"); const engine_1 = require("../engine"); const method_context_1 = require("../state_machine/method_context"); const genesis_asset_1 = require("./fixtures/genesis-asset"); const validators_1 = require("../modules/validators"); const token_1 = require("../modules/token"); const auth_1 = require("../modules/auth"); const fee_1 = require("../modules/fee"); const random_1 = require("../modules/random"); const pos_1 = require("../modules/pos"); const abi_handler_1 = require("../abi_handler/abi_handler"); const genesis_block_1 = require("../genesis_block"); const system_dirs_1 = require("../system_dirs"); const prefixed_state_read_writer_1 = require("../state_machine/prefixed_state_read_writer"); const logger_1 = require("../logger"); const interoperability_1 = require("../modules/interoperability"); const dynamic_reward_1 = require("../modules/dynamic_reward"); const getAppConfig = (genesisConfig, moduleConfig) => { const mergedConfig = lisk_utils_1.objects.mergeDeep({}, { ...fixtures_1.defaultConfig, system: { ...fixtures_1.defaultConfig.system, dataPath: path.join(os.tmpdir(), `lisk-framework-test-${Date.now().toString()}`), }, genesis: { ...fixtures_1.defaultConfig.genesis, ...(genesisConfig !== null && genesisConfig !== void 0 ? genesisConfig : {}), }, modules: { ...(moduleConfig !== null && moduleConfig !== void 0 ? moduleConfig : {}), }, }); return mergedConfig; }; const getNextTimestamp = (engine, previousBlock, distance = 1) => { const previousSlotNumber = engine['_consensus']['_bft'].method.getSlotNumber(previousBlock.timestamp); return engine['_consensus']['_bft'].method.getSlotTime(previousSlotNumber + distance); }; const createProcessableBlock = async (engine, transactions, timestamp) => { engine['_logger'].info({ numberOfTransactions: transactions.length }, 'Start generating block'); const stateStore = new lisk_chain_1.StateStore(engine['_blockchainDB']); const previousBlockHeader = engine['_chain'].lastBlock.header; const nextTimestamp = timestamp !== null && timestamp !== void 0 ? timestamp : getNextTimestamp(engine, previousBlockHeader); const generator = await engine['_consensus']['_bft'].method.getGeneratorAtTimestamp(stateStore, previousBlockHeader.height + 1, nextTimestamp); const generatorPrivateKey = (0, fixtures_1.getGeneratorPrivateKeyFromDefaultConfig)(generator.address); for (const tx of transactions) { await engine['_generator']['_pool'].add(tx); } const block = await engine.generateBlock({ generatorAddress: generator.address, height: previousBlockHeader.height + 1, privateKey: generatorPrivateKey, timestamp: nextTimestamp, transactions, }); engine['_logger'].info({ height: block.header.height, numberOfTransactions: block.transactions.length }, 'Generated block'); return block; }; const getBlockProcessingEnv = async (params) => { var _a, _b, _c, _d; const chainID = Buffer.from('00000000', 'hex'); const appConfig = getAppConfig(((_a = params.options) === null || _a === void 0 ? void 0 : _a.genesis) ? { ...params.options.genesis, chainID: chainID.toString('hex'), } : { chainID: chainID.toString('hex') }, (_c = (_b = params.options) === null || _b === void 0 ? void 0 : _b.modules) !== null && _c !== void 0 ? _c : {}); const systemDir = (0, system_dirs_1.systemDirs)(appConfig.system.dataPath); (0, utils_1.removeDB)(systemDir.data); const moduleDB = new lisk_db_1.Database(path.join(systemDir.data, 'module.db')); const stateDB = new lisk_db_1.StateDB(path.join(systemDir.data, 'state.db')); const validatorsModule = new validators_1.ValidatorsModule(); const authModule = new auth_1.AuthModule(); const tokenModule = new token_1.TokenModule(); const feeModule = new fee_1.FeeModule(); const rewardModule = new dynamic_reward_1.DynamicRewardModule(); const randomModule = new random_1.RandomModule(); const posModule = new pos_1.PoSModule(); const interopModule = new interoperability_1.MainchainInteroperabilityModule(); const modules = [ validatorsModule, authModule, tokenModule, feeModule, rewardModule, randomModule, posModule, ]; const stateMachine = new state_machine_1.StateMachine(); const logger = (0, logger_1.createLogger)({ name: 'blockProcessingEnv', logLevel: (_d = params.logLevel) !== null && _d !== void 0 ? _d : 'none' }); tokenModule.addDependencies(interopModule.method, feeModule.method); feeModule.addDependencies(tokenModule.method, interopModule.method); rewardModule.addDependencies(tokenModule.method, randomModule.method, validatorsModule.method, posModule.method); posModule.addDependencies(randomModule.method, validatorsModule.method, tokenModule.method, feeModule.method); stateMachine.registerModule(feeModule); stateMachine.registerModule(authModule); stateMachine.registerModule(validatorsModule); stateMachine.registerModule(tokenModule); stateMachine.registerModule(rewardModule); stateMachine.registerModule(randomModule); stateMachine.registerModule(posModule); const blockAssets = genesis_asset_1.blockAssetsJSON.map(asset => ({ ...asset, data: lisk_codec_1.codec.fromJSON(asset.schema, asset.data), })); await stateMachine.init(logger, appConfig.genesis, appConfig.modules); const genesisBlock = await (0, genesis_block_1.generateGenesisBlock)(stateMachine, logger, { timestamp: Math.floor(Date.now() / 1000) - 60 * 60 * 12, assets: blockAssets, chainID, }); const abiHandler = new abi_handler_1.ABIHandler({ channel: mocks_1.channelMock, config: appConfig, logger, stateDB, moduleDB, modules, stateMachine, chainID, }); appConfig.genesis.block.blob = genesisBlock.getBytes().toString('hex'); appConfig.generator.keys.fromFile = path.join(__dirname, './fixtures/keys_fixture.json'); const engine = new engine_1.Engine(abiHandler, appConfig); await engine['_init'](); engine['_logger'] = logger; engine['_consensus']['_logger'] = logger; await abiHandler.init({ chainID, lastBlockHeight: engine['_chain'].lastBlock.header.height, lastStateRoot: engine['_chain'].lastBlock.header.stateRoot, }); return { createBlock: async (transactions = [], timestamp) => createProcessableBlock(engine, transactions, timestamp), getGenesisBlock: () => genesisBlock, getChain: () => engine['_chain'], getConsensus: () => engine['_consensus'], getConsensusStore: () => new lisk_chain_1.StateStore(engine['_blockchainDB']), getGenerator: () => engine['_generator'], getMethodContext: () => (0, method_context_1.createNewMethodContext)(stateDB.newReadWriter()), getBlockchainDB: () => engine['_blockchainDB'], process: async (block) => { logger.debug({ height: block.header.height, numberOfTransactions: block.transactions.length }, 'Start executing block'); await engine['_consensus']['_execute'](block, 'peer-id'); logger.debug({ height: block.header.height, numberOfTransactions: block.transactions.length }, 'Executed block'); }, processUntilHeight: async (height) => { while (engine['_chain'].lastBlock.header.height < height) { const nextBlock = await createProcessableBlock(engine, []); await engine['_consensus'].execute(nextBlock); } }, getLastBlock: () => engine['_chain'].lastBlock, getNextValidatorKeys: async (previousBlockHeader, distance = 1) => { const stateStore = new lisk_chain_1.StateStore(engine['_blockchainDB']); const nextTimestamp = getNextTimestamp(engine, previousBlockHeader, distance); const validator = await engine['_consensus']['_bft'].method.getGeneratorAtTimestamp(stateStore, previousBlockHeader.height + distance, nextTimestamp); const keys = (0, fixtures_1.getKeysFromDefaultConfig)(validator.address); return keys; }, getEvents: async (height, module, name) => { const handler = engine['_rpcServer']['_getHandler']('chain', 'getEvents'); if (!handler) { throw new Error('invalid'); } const resp = (await handler({ logger, chainID: engine['_chain'].chainID, params: { height }, })); const eventMetadata = stateMachine['_modules'] .map(m => ({ module: m.name, ...m.metadata().events })) .flat(); const results = []; for (const event of resp) { if (module && event.module !== module) { continue; } if (name && event.name !== name) { continue; } if (event.name === 'commandExecutionResult') { results.push({ ...event, decodedData: lisk_codec_1.codec.decodeJSON(lisk_chain_1.standardEventDataSchema, Buffer.from(event.data, 'hex')), }); continue; } const metadata = eventMetadata.find(e => e.module === event.module && e.name === event.name); results.push({ ...event, decodedData: metadata ? lisk_codec_1.codec.decodeJSON(metadata.schema, Buffer.from(event.data, 'hex')) : {}, }); } return results; }, async invoke(func, input = {}) { const [namespace, method] = func.split('_'); const handler = engine['_rpcServer']['_getHandler'](namespace, method); if (handler) { const resp = (await handler({ logger, chainID: engine['_chain'].chainID, params: input, })); return resp; } const moduleIndex = modules.findIndex(mod => mod.name === namespace); if (moduleIndex < 0) { throw new Error(`namespace ${namespace} is not registered`); } const moduleHandler = modules[moduleIndex].endpoint[method]; if (!moduleHandler) { throw new Error(`Method ${method} in namespace ${namespace} is not registered`); } const bindedHandler = moduleHandler.bind(modules[moduleIndex].endpoint); const stateStore = new prefixed_state_read_writer_1.PrefixedStateReadWriter(stateDB.newReadWriter()); try { const result = await bindedHandler({ getStore: (moduleID, storePrefix) => stateStore.getStore(moduleID, storePrefix), getImmutableMethodContext: () => (0, method_context_1.createImmutableMethodContext)(stateStore), logger: engine['_logger'], chainID: engine['_chain'].chainID, params: input, }); return result; } finally { stateStore.inner.close(); } }, getChainID: () => chainID, getDataAccess: () => engine['_chain'].dataAccess, cleanup: (_val) => { engine['_closeDB'](); moduleDB.close(); stateDB.close(); fs.removeSync(systemDir.data); }, }; }; exports.getBlockProcessingEnv = getBlockProcessingEnv; //# sourceMappingURL=block_processing_env.js.map