UNPKG

@kyve/core-beta

Version:

🚀 The base KYVE node implementation.

309 lines (276 loc) • 8.63 kB
import { PoolResponse } from "@kyve/proto-beta/lcd/kyve/query/v1beta1/pools"; import KyveSDK, { KyveClient, KyveLCDClientType } from "@kyve/sdk-beta"; import { Command, OptionValues } from "commander"; import os from "os"; import { Logger } from "tslog"; import { version as coreVersion } from "../package.json"; import { parseCache, parseMnemonic, parseNetwork, parsePoolId, } from "./commander"; import { canPropose, canVote, claimUploaderRole, compressionFactory, continueRound, createBundleProposal, getBalances, runCache, runNode, saveBundleDecompress, saveBundleDownload, saveGetTransformDataItem, saveLoadValidationBundle, setupCacheProvider, setupLogger, setupMetrics, setupSDK, setupValidator, skipUploaderRole, storageProviderFactory, submitBundleProposal, syncPoolConfig, syncPoolState, validateBundleProposal, validateIsNodeValidator, validateIsPoolActive, validateRuntime, validateVersion, voteBundleProposal, waitForAuthorization, waitForCacheContinuation, waitForNextBundleProposal, waitForUploadInterval, } from "./methods"; import { ICacheProvider, IMetrics, IRuntime } from "./types"; import { standardizeJSON } from "./utils"; /** * Main class of KYVE protocol nodes representing a node. * * @class Node * @constructor */ export class Node { // reactor attributes protected runtime!: IRuntime; protected cacheProvider!: ICacheProvider; // sdk attributes public sdk!: KyveSDK; public client!: KyveClient; public lcd!: KyveLCDClientType; // node attributes public coreVersion!: string; public pool!: PoolResponse; public poolConfig!: any; public name!: string; // logger attributes public logger!: Logger; // metrics attributes public m!: IMetrics; // node option attributes protected poolId!: number; protected staker!: string; protected valaccount!: string; protected storagePriv!: string; protected network!: string; protected rpc!: string; protected rest!: string; protected cache!: string; protected debug!: boolean; protected metrics!: boolean; protected metricsPort!: number; protected home!: string; // setups protected setupLogger = setupLogger; protected setupCacheProvider = setupCacheProvider; protected setupMetrics = setupMetrics; protected setupSDK = setupSDK; protected setupValidator = setupValidator; // checks protected validateRuntime = validateRuntime; protected validateVersion = validateVersion; protected validateIsNodeValidator = validateIsNodeValidator; protected validateIsPoolActive = validateIsPoolActive; // timeouts protected waitForAuthorization = waitForAuthorization; protected waitForUploadInterval = waitForUploadInterval; protected waitForNextBundleProposal = waitForNextBundleProposal; protected waitForCacheContinuation = waitForCacheContinuation; // helpers protected continueRound = continueRound; protected saveGetTransformDataItem = saveGetTransformDataItem; // factories protected storageProviderFactory = storageProviderFactory; protected compressionFactory = compressionFactory; // txs protected claimUploaderRole = claimUploaderRole; protected skipUploaderRole = skipUploaderRole; protected voteBundleProposal = voteBundleProposal; protected submitBundleProposal = submitBundleProposal; // queries protected syncPoolState = syncPoolState; protected syncPoolConfig = syncPoolConfig; protected getBalances = getBalances; protected canVote = canVote; protected canPropose = canPropose; // validate protected saveBundleDownload = saveBundleDownload; protected saveBundleDecompress = saveBundleDecompress; protected saveLoadValidationBundle = saveLoadValidationBundle; protected validateBundleProposal = validateBundleProposal; // upload protected createBundleProposal = createBundleProposal; // main protected runNode = runNode; protected runCache = runCache; /** * Constructor for the core class. It is required to provide the * runtime class here in order to run the * * @method constructor * @param {IRuntime} runtime which implements the interface IRuntime */ constructor(runtime: IRuntime) { // set provided runtime this.runtime = runtime; // set @kyve/core version this.coreVersion = coreVersion; } /** * Bootstrap method for protocol node. It initializes all commands including * the main program which can be called with "start" * * @method bootstrap * @return {void} */ public bootstrap(): void { // define main program const program = new Command(); // define version command program .command("version") .description("Print runtime and core version") .action(() => { console.log(`${this.runtime.name} version: ${this.runtime.version}`); console.log(`@kyve/core version: ${this.coreVersion}`); console.log(`Node version: ${process.version}`); console.log(); console.log(`Platform: ${os.platform()}`); console.log(`Arch: ${os.arch()}`); }); // define start command program .command("start") .description("Run the protocol node") .requiredOption( "--pool <string>", "The ID of the pool this valaccount should participate as a validator", parsePoolId ) .requiredOption( "--valaccount <string>", "The mnemonic of the valaccount", parseMnemonic ) .requiredOption( "--storage-priv <string>", "The private key of the storage provider" ) .requiredOption( "--network <local|alpha|beta|korellia>", "The network of the KYVE chain", parseNetwork ) .option( "--rpc", "Custom rpc endpoint the node uses for submitting transactions to chain" ) .option( "--rest", "Custom rest api endpoint the node uses for querying from chain" ) .option( "--cache <memory|jsonfile|leveldb>", "The cache this node should use", parseCache, "leveldb" ) .option("--debug", "Run the validator node in debug mode") .option( "--verbose", "[DEPRECATED] Run the validator node in verbose logging mode" ) .option( "--metrics", "Start a prometheus metrics server on http://localhost:8080/metrics" ) .option( "--metrics-port <number>", "Specify the port of the metrics server. Only considered if '--metrics' is set [default = 8080]", "8080" ) .option( "--home <string>", "Specify the home directory of the node where logs and the cache should save their data. [default current directory]", "./" ) .action((options) => { this.start(options); }); // bootstrap program program.parse(); } /** * Main method of @kyve/core. By running this method the node will start and run. * For this method to run the Runtime, Storage Provider and the Cache have to be added first. * * This method will run indefinetely and only exits on specific exit conditions like running * an incorrect runtime or version. * * @method start * @param {OptionValues} options contains all node options defined in bootstrap * @return {Promise<void>} */ private async start(options: OptionValues): Promise<void> { // assign program options // to node instance this.poolId = options.pool; this.valaccount = options.valaccount; this.storagePriv = options.storagePriv; this.network = options.network; this.rpc = options.rpc; this.rest = options.rest; this.cache = options.cache; this.debug = options.debug; this.metrics = options.metrics; this.metricsPort = options.metricsPort; this.home = options.home; // perform setups this.setupLogger(); this.setupMetrics(); // perform async setups await this.setupSDK(); await this.setupValidator(); await this.setupCacheProvider(); // start the node process. Node and cache should run at the same time. // Thats why, although they are async they are called synchronously try { await this.syncPoolState(); this.runNode(); this.runCache(); } catch (err) { this.logger.fatal(`Unexpected runtime error. Exiting ...`); this.logger.fatal(standardizeJSON(err)); process.exit(1); } } } // export commander export * from "./commander"; // export types export * from "./types"; // export utils export * from "./utils";