diff --git a/README.md b/README.md index be4f5487..1d5fa390 100644 --- a/README.md +++ b/README.md @@ -7,9 +7,10 @@ Facilitator init command will create facilitator config for an auxiliary chain. A simple run would be the following: ``` -./facilitator init --mosaic-config --aux-chain-id --origin-password --auxiliary-password --origin-rpc --auxiliary-rpc --origin-graph-ws --origin-graph-rpc --auxiliary-graph-ws --auxiliary-graph-rpc --db-path --force +./facilitator init --gateway-config --mosaic-config --aux-chain-id --origin-password --auxiliary-password --origin-rpc --auxiliary-rpc --origin-graph-ws --origin-graph-rpc --auxiliary-graph-ws --auxiliary-graph-rpc --db-path --force ``` +* Replace `` with location where gateway config is present. * Replace `` with location where mosaic config is present. * Replace `` with auxiliary chain id. * Replace `` with the password required to encrypt the worker account of origin chain created with this command. It will be required to unlock worker account while starting facilitator. @@ -29,17 +30,36 @@ Facilitator start command will start the facilitator. Facilitator can be started in below two ways :- +#### Facilitator start for EIP20 gateways: 1. `./facilitator start --facilitator-config --mosaic-config ` - * Replace `` with the path to facilitator-config.json using `facilitator init`. - * `--mosaic-config` is optional argument. - * If both `--mosaic-config` is given it will read mosaic and facilitator configs from `` and `` paths respectively. + * Replace `` with the path to facilitator-config.json generated using `facilitator init`. + * Replace `` with the path to mosaic-config.json. + * When `--mosaic-config` and `--facilitator-config` is given then it will read gateway and facilitator configs from `` and `` paths respectively and validates origin and aux chain id's. -2. `./facilitator start ` +2. `./facilitator start --facilitator-config --mosaic-config ` * Replace `` with name of the origin chain. * Replace `` with id of the auxiliary chain. - - ##### Options - * `--mosaic-config` and `--facilitator-config` refers to file path of mosaic config and facilitator config respectively. They are optional fields. - * If `--mosaic-config` is given then it will read the facilitator config from default path for `` and mosaic-config from `` path. Argument `` and `` should be present in mosaic-config. - * If `--facilitator-config` is given then it will read the mosaic config from default path for `` and facilitator-config from `` path. Argument`` and `` should be present in it. + * Replace `` with the path to facilitator-config.json generated using `facilitator init`. + * Replace `` with the path to gateway-config.json. + * It validates `` and `` id's in faciltiator and mosaic configs. + +3. `./facilitator start ` + * It loads mosaic config and facilitator config from default paths. + +4. `./facilitator start --facilitator-config ` + * It loads facilitator from `` path. + +#### Facilitator start for mosaic gateways: + +1. `./facilitator start --facilitator-config --gateway-config ` + * Replace `` with the path to facilitator-config.json generated using `facilitator init`. + * Replace `` with the path to gateway-config.json. + * When `--gateway-config` and `--facilitator-config` is given then it will read gateway and facilitator configs from `` and `` paths respectively and validates origin and aux chain id's. +2. `./facilitator start --facilitator-config --gateway-config ` + * Replace `` with name of the origin chain. + * Replace `` with id of the auxiliary chain. + * Replace `` with the path to facilitator-config.json generated using `facilitator init`. + * Replace `` with the path to gateway-config.json. + + * **Note** : Both `--mosaic-config` and `--gateway-config` are together not allowed in command. diff --git a/src/Config/Config.ts b/src/Config/Config.ts index eb68a35d..36f4f382 100644 --- a/src/Config/Config.ts +++ b/src/Config/Config.ts @@ -21,6 +21,7 @@ import path from 'path'; import Web3 from 'web3'; import MosaicConfig from '@openst/mosaic-chains/lib/src/Config/MosaicConfig'; +import GatewayConfig from '@openst/mosaic-chains/lib/src/Config/GatewayConfig'; import Account from '../Account'; import Directory from '../Directory'; import { @@ -41,6 +42,12 @@ enum DBType { SQLITE = 'SQLITE', } +// Database type +export enum ConfigType { + GATEWAY = 'Gateway', + MOSAIC = 'Mosaic', +} + /** * Holds database configurations. */ @@ -314,23 +321,34 @@ export class Config { /** * It provides config object from the path specified. This will throw if - * mosaic config path or facilitator config path doesn't exists. - * @param mosaicConfigPath Path to mosaic config file path. - * @param facilitatorConfigPath Path to facilitator config file path/ + * mosaic config path or facilitator config path doesn't exists and invalid config type + * is provided. + * @param facilitatorConfigPath Path to facilitator config file path. + * @param configPath Path to mosaic or gateway config. + * @param configType Type of config. * @returns Config object consisting of gateway addresses and facilitator configurations. */ public static fromFile( - mosaicConfigPath: string, facilitatorConfigPath: string, + configPath: string, + configType: ConfigType, ): Config { - const mosaic: MosaicConfig = MosaicConfig.fromFile(mosaicConfigPath); const facilitator: FacilitatorConfig = FacilitatorConfig.fromFile(facilitatorConfigPath); - return new Config( - GatewayAddresses.fromMosaicConfig( - mosaic, + let gatewayAddresses: GatewayAddresses; + if (ConfigType.GATEWAY === configType) { + gatewayAddresses = GatewayAddresses.fromGatewayConfig(GatewayConfig.fromFile(configPath)); + } else if (ConfigType.MOSAIC === configType) { + gatewayAddresses = GatewayAddresses.fromMosaicConfig( + MosaicConfig.fromFile(configPath), facilitator.auxChainId, - ), + ); + } else { + throw new Error(`Invalid config type ${configType}`); + } + + return new Config( + gatewayAddresses, facilitator, ); } diff --git a/src/Config/ConfigFactory.ts b/src/Config/ConfigFactory.ts index 12c857ce..b13dec1e 100644 --- a/src/Config/ConfigFactory.ts +++ b/src/Config/ConfigFactory.ts @@ -16,8 +16,9 @@ import MosaicConfig from '@openst/mosaic-chains/lib/src/Config/MosaicConfig'; +import GatewayConfig from '@openst/mosaic-chains/lib/src/Config/GatewayConfig'; import { FacilitatorStartException } from '../Exception'; -import { Config, FacilitatorConfig } from './Config'; +import { Config, FacilitatorConfig, ConfigType } from './Config'; import GatewayAddresses from './GatewayAddresses'; /* eslint-disable @typescript-eslint/no-non-null-assertion */ @@ -34,27 +35,32 @@ export default class ConfigFactory { public facilitatorConfigPath?: string; + public gatewayConfigPath?: string; + /** * @param originChain Name of the origin chain. * @param auxChainId Identifier of the aux chain. * @param mosaicConfigPath Path to mosaic config file. - * @param facilitatorConfigPath Path to facilitator config path. + * @param facilitatorConfigPath Path to facilitator config. + * @param gatewayConfigPath Path to gateway config. */ public constructor( originChain?: string, auxChainId?: number, mosaicConfigPath?: string, facilitatorConfigPath?: string, + gatewayConfigPath?: string, ) { this.originChain = originChain; this.auxChainId = auxChainId; this.mosaicConfigPath = mosaicConfigPath; this.facilitatorConfigPath = facilitatorConfigPath; + this.gatewayConfigPath = gatewayConfigPath; } /** * It would evaluate the parameters and return config object. - * @returns Config object that contains mosaic and facilitator configs. + * @returns Config object that contains gateway and facilitator configs. */ public getConfig(): Config { if (this.isFacilitatorConfigPathAvailable()) { @@ -65,7 +71,7 @@ export default class ConfigFactory { /** * This method returns Config object when origin chain and aux chain is defined. - * @returns Config object encapsulating facilitator and mosaic configs. + * @returns Config object encapsulating facilitator and gateway configs. */ private handleOriginAuxChainOption(): Config { this.verifyOriginAuxChainDefined(); @@ -74,15 +80,25 @@ export default class ConfigFactory { const facilitatorConfig: FacilitatorConfig = FacilitatorConfig.fromFile( this.facilitatorConfigPath, ); - this.verifyChainIdInFacilitatorConfig(facilitatorConfig); - // when mosaic config path is given. if (this.mosaicConfigPath) { const mosaicConfig: MosaicConfig = MosaicConfig.fromFile(this.mosaicConfigPath); // verify origin chain and aux chain is present in mosaic config. this.verifyChainIdInMosaicConfig(mosaicConfig); - return Config.fromFile(this.mosaicConfigPath, this.facilitatorConfigPath); + return Config.fromFile( + this.facilitatorConfigPath, + this.mosaicConfigPath, + ConfigType.MOSAIC, + ); + } + + if (this.gatewayConfigPath) { + return Config.fromFile( + this.facilitatorConfigPath, + this.gatewayConfigPath, + ConfigType.GATEWAY, + ); } const mosaicConfig: MosaicConfig = MosaicConfig.fromChain(this.originChain!); @@ -109,6 +125,16 @@ export default class ConfigFactory { ); } + if (this.gatewayConfigPath) { + const facilitator: FacilitatorConfig = FacilitatorConfig.fromChain(this.auxChainId!); + const gatewayConfig = GatewayConfig.fromFile(this.gatewayConfigPath); + this.verifyChainIdInGatewayConfig(gatewayConfig); + return new Config( + GatewayAddresses.fromGatewayConfig(gatewayConfig), + facilitator, + ); + } + const facilitator: FacilitatorConfig = FacilitatorConfig.fromChain(this.auxChainId!); const mosaic: MosaicConfig = MosaicConfig.fromChain(this.originChain!); return new Config( @@ -123,16 +149,16 @@ export default class ConfigFactory { /** * This method returns config object when facilitator config is provided and * origin chain and aux chain is not provided. - * @returns Config object encapsulating facilitator and mosaic configs. + * @returns Config object encapsulating facilitator and gateway configs. */ private handleFacilitatorConfigOption(): Config { let configObj; + const facilitatorConfig = FacilitatorConfig.fromFile(this.facilitatorConfigPath!); + this.auxChainId = facilitatorConfig.auxChainId; + this.originChain = facilitatorConfig.originChain; // When no origin and aux chain provided. if (this.mosaicConfigPath) { const mosaicConfig = MosaicConfig.fromFile(this.mosaicConfigPath); - const facilitatorConfig = FacilitatorConfig.fromFile(this.facilitatorConfigPath!); - this.auxChainId = facilitatorConfig.auxChainId; - this.originChain = facilitatorConfig.originChain; this.verifyChainIdInMosaicConfig(mosaicConfig); @@ -143,17 +169,31 @@ export default class ConfigFactory { ), facilitatorConfig, ); - } else { - const facilitatorConfig: FacilitatorConfig = FacilitatorConfig.fromFile( - this.facilitatorConfigPath!, + } else if (this.gatewayConfigPath) { + const gatewayConfig = GatewayConfig.fromFile(this.gatewayConfigPath); + + this.verifyChainIdInGatewayConfig(gatewayConfig); + + configObj = new Config( + GatewayAddresses.fromGatewayConfig( + gatewayConfig, + ), + facilitatorConfig, ); + } else { + // only facilitator config is given. + if (!MosaicConfig.exists(this.originChain)) { + throw new Error('mosaic config not found'); + } const mosaicConfig: MosaicConfig = MosaicConfig.fromChain( - facilitatorConfig.originChain, + this.originChain, ); + + this.verifyChainIdInMosaicConfig(mosaicConfig); configObj = new Config( GatewayAddresses.fromMosaicConfig( mosaicConfig, - facilitatorConfig.auxChainId, + this.auxChainId, ), facilitatorConfig, ); @@ -191,13 +231,28 @@ export default class ConfigFactory { if (mosaicConfig.auxiliaryChains[this.auxChainId!] === undefined) { throw new FacilitatorStartException('aux chain is not present in mosaic config'); } - if (mosaicConfig.originChain.chain !== this.originChain) { throw new FacilitatorStartException('origin chain id in mosaic config is different ' + 'than the one provided'); } } + /** + * It verifies chain id's in gateway config. + * @param gatewayConfig GatewayConfig object. + */ + private verifyChainIdInGatewayConfig( + gatewayConfig: GatewayConfig, + ): void { + this.verifyChainIdInMosaicConfig(gatewayConfig.mosaicConfig); + if (gatewayConfig.auxChainId !== this.auxChainId) { + throw new FacilitatorStartException( + `Aux chain id ${gatewayConfig.auxChainId} in gatewayconfig and provided auxchain id ` + + `${this.auxChainId} are not same`, + ); + } + } + /** * It verifies whether both origin and aux chain ids are defined. */ diff --git a/src/Container.ts b/src/Container.ts index 83fe594e..c8168218 100644 --- a/src/Container.ts +++ b/src/Container.ts @@ -15,39 +15,24 @@ // ---------------------------------------------------------------------------- -import ConfigFactory from './Config/ConfigFactory'; import Facilitator from './Facilitator'; import Handlers from './handlers/Handlers'; -import Logger from './Logger'; import Repositories from './repositories/Repositories'; import Services from './services/Services'; import Subscriptions from './subscriptions/Subscriptions'; import TransactionHandler from './TransactionHandler'; +import { Config } from './Config/Config'; export default class Container { /** * This instantiate all the dependencies. - * @param originChain Origin chain Identifier - * @param auxChainId Auxiliary chain ID. - * @param mosaicConfigPath Mosaic Config path. - * @param facilitatorConfigPath Facilitator config path. + * @param config Config object/ * @return Promise that resolves to facilitator instance. */ public static async create( - originChain?: string, - auxChainId?: string, - mosaicConfigPath?: string, - facilitatorConfigPath?: string, + config: Config, + ): Promise { - Logger.debug('Reading config file'); - const configFactory: ConfigFactory = new ConfigFactory( - originChain, - auxChainId ? Number.parseInt(auxChainId, 10) : undefined, - mosaicConfigPath, - facilitatorConfigPath, - ); - const config = configFactory.getConfig(); - Logger.debug('Config loaded successfully.'); const repositories = await Repositories.create(config.facilitator.database.path); const handler = Handlers.create( repositories, diff --git a/src/bin/facilitator-init.ts b/src/bin/facilitator-init.ts index f15dd070..6ba7f07d 100644 --- a/src/bin/facilitator-init.ts +++ b/src/bin/facilitator-init.ts @@ -18,7 +18,6 @@ import commander from 'commander'; import Web3 from 'web3'; -import MosaicConfig from '@openst/mosaic-chains/lib/src/Config/MosaicConfig'; import Account from '../Account'; import { Chain, FacilitatorConfig, Config, ENV_WORKER_PASSWORD_PREFIX, @@ -29,16 +28,18 @@ import Logger from '../Logger'; import Repositories from '../repositories/Repositories'; import SeedData from '../SeedData'; import GatewayAddresses from '../Config/GatewayAddresses'; +import FacilitatorInit from '../lib/FacilitatorInit'; commander .option('-m, --mosaic-config ', 'path to mosaic configuration') + .option('-g, --gateway-config ', 'path to gateway configuration') .option('-c, --aux-chain-id ', 'auxiliary chain id') .option('-o, --origin-password ', 'origin chain account password') .option('-a, --auxiliary-password ', 'auxiliary chain account password') .option('-r, --origin-rpc ', 'origin chain rpc') .option('-h, --auxiliary-rpc ', 'auxiliary chain rpc') .option('-e, --origin-graph-ws ', 'origin ws subgraph endpoint ') - .option('-g, --origin-graph-rpc ', 'origin rpc subgraph endpoint') + .option('-n, --origin-graph-rpc ', 'origin rpc subgraph endpoint') .option('-s, --auxiliary-graph-ws ', 'auxiliary ws subgraph endpoint') .option('-i, --auxiliary-graph-rpc ', 'auxiliary rpc subgraph endpoint') .option('-d, --db-path ', 'path where db path is present') @@ -47,8 +48,11 @@ commander // Validating mandatory parameters let mandatoryOptionMissing = false; - if (options.mosaicConfig === undefined) { - Logger.error('required --mosaic-config '); + if ( + (options.mosaicConfig && options.gatewayConfig) + || (options.gatewayConfig === undefined && options.mosaicConfig === undefined) + ) { + Logger.error('one option out of gateway config and mosaic config is required.'); mandatoryOptionMissing = true; } @@ -99,101 +103,116 @@ commander } if (mandatoryOptionMissing) { + Logger.info('refer readme for more details'); process.exit(1); } - if (options.force) { - FacilitatorConfig.remove(auxChainId); - } else { - try { - if (FacilitatorConfig.isFacilitatorConfigPresent(auxChainId)) { - Logger.error('facilitator config already present. use -f option to override the existing facilitator config.'); - process.exit(1); - } - } catch (e) { - Logger.info('creating facilitator config as it is not present'); + try { + if (options.force) { + FacilitatorConfig.remove(auxChainId); + } else if (FacilitatorConfig.isFacilitatorConfigPresent(auxChainId)) { + throw new Error('facilitator config already present. use -f option to override the existing facilitator config.'); + } + Logger.info('creating facilitator config as it is not present'); + const facilitatorConfig = FacilitatorConfig.fromChain(auxChainId); + + // Get origin chain id. + let originChainId: string | undefined; + let gatewayAddresses: GatewayAddresses | undefined; + if (options.mosaicConfig !== undefined) { + ( + { + originChainId, + gatewayAddresses, + } = FacilitatorInit.getFromMosaicConfig(auxChainId, options.mosaicConfig) + ); } - } - - const facilitatorConfig = FacilitatorConfig.fromChain(auxChainId); - - // Get origin chain id. - const mosaicConfig = MosaicConfig.fromFile(options.mosaicConfig); - const auxChain = mosaicConfig.auxiliaryChains[auxChainId]; - if (auxChain === null || auxChain === undefined) { - Logger.error('aux chain id is not present in the mosaic config'); - process.exit(1); - } - const originChainId = mosaicConfig.originChain.chain; + if (options.gatewayConfig !== undefined) { + ( + { + originChainId, + gatewayAddresses, + } = FacilitatorInit.getFromMosaicConfig(auxChainId, options.mosaicConfig) + ); + } - let { dbPath } = options; - if (dbPath === undefined || dbPath === null) { - Logger.info('database path is not provided'); - dbPath = DatabaseFileHelper.create(auxChainId); - } else if (DatabaseFileHelper.verify(dbPath)) { - Logger.info('DB file verified'); - } else { - Logger.error('DB file doesn\'t exists or file extension is incorrect'); - process.exit(1); - } + facilitatorConfig.originChain = originChainId!; + facilitatorConfig.auxChainId = auxChainId; + + let { dbPath } = options; + if (dbPath === undefined || dbPath === null) { + Logger.info('database path is not provided'); + dbPath = DatabaseFileHelper.create(auxChainId); + } else if (DatabaseFileHelper.verify(dbPath)) { + Logger.info('DB file verified'); + } else { + throw new Error('DB file doesn\'t exists or file extension is incorrect'); + } - facilitatorConfig.database.path = dbPath; - facilitatorConfig.originChain = originChainId; - facilitatorConfig.auxChainId = auxChainId; - const setFacilitator = ( - chainId: string, - rpc: string, - subGraphWs: string, - subGraphRpc: string, - password: string, - ): void => { - const account: Account = Account.create(new Web3(''), password); - - facilitatorConfig.chains[chainId] = new Chain(rpc, account.address, subGraphWs, subGraphRpc); - const envVariableNameForWorkerPassword = `${ENV_WORKER_PASSWORD_PREFIX}${account.address}`; - process.env[envVariableNameForWorkerPassword] = password; - - facilitatorConfig.encryptedAccounts[account.address] = account.encryptedKeyStore; - }; - - setFacilitator( - originChainId, - options.originRpc, - options.originGraphWs, - options.originGraphRpc, - options.originPassword, - ); - - setFacilitator( - auxChainId, - options.auxiliaryRpc, - options.auxiliaryGraphWs, - options.auxiliaryGraphRpc, - options.auxiliaryPassword, - ); - - const gatewayAddresses = GatewayAddresses.fromMosaicConfig(mosaicConfig, auxChainId); - const config = new Config(gatewayAddresses, facilitatorConfig); - const repositories = await Repositories.create(config.facilitator.database.path); - const seedData = new SeedData( - config, - repositories.gatewayRepository, - repositories.auxiliaryChainRepository, - repositories.contractEntityRepository, - ); - await seedData.populateDb(); - - facilitatorConfig.writeToFacilitatorConfig(auxChainId); - Logger.info('facilitator config file is generated'); - - Logger.info(`šŸ‘‰ worker address for ${originChainId} chain is ` - + `${facilitatorConfig.chains[originChainId].worker}`); - - Logger.info(`šŸ‘‰ worker address for ${auxChainId} chain is ` + facilitatorConfig.database.path = dbPath; + + const setFacilitator = ( + chainId: string, + rpc: string, + subGraphWs: string, + subGraphRpc: string, + password: string, + ): void => { + const account: Account = Account.create(new Web3(''), password); + + facilitatorConfig.chains[chainId] = new Chain( + rpc, + account.address, + subGraphWs, + subGraphRpc, + ); + const envVariableNameForWorkerPassword = `${ENV_WORKER_PASSWORD_PREFIX}${account.address}`; + process.env[envVariableNameForWorkerPassword] = password; + + facilitatorConfig.encryptedAccounts[account.address] = account.encryptedKeyStore; + }; + + setFacilitator( + originChainId!, + options.originRpc, + options.originGraphWs, + options.originGraphRpc, + options.originPassword, + ); + + setFacilitator( + auxChainId, + options.auxiliaryRpc, + options.auxiliaryGraphWs, + options.auxiliaryGraphRpc, + options.auxiliaryPassword, + ); + + const config = new Config(gatewayAddresses!, facilitatorConfig); + const repositories = await Repositories.create(config.facilitator.database.path); + const seedData = new SeedData( + config, + repositories.gatewayRepository, + repositories.auxiliaryChainRepository, + repositories.contractEntityRepository, + ); + await seedData.populateDb(); + + facilitatorConfig.writeToFacilitatorConfig(auxChainId); + Logger.info('facilitator config file is generated'); + + Logger.info(`šŸ‘‰ worker address for ${originChainId} chain is ` + + `${facilitatorConfig.chains[originChainId!].worker}`); + + Logger.info(`šŸ‘‰ worker address for ${auxChainId} chain is ` + `${facilitatorConfig.chains[auxChainId].worker}`); - Logger.info(`\nā„¹ļø Run below two commands on terminal by replacing and with origin and auxiliary password entered in command. \n - 1. export ${ENV_WORKER_PASSWORD_PREFIX + facilitatorConfig.chains[originChainId].worker}= + Logger.info(`\nā„¹ļø Run below two commands on terminal by replacing and with origin and auxiliary password entered in command. \n + 1. export ${ENV_WORKER_PASSWORD_PREFIX + facilitatorConfig.chains[originChainId!].worker}= 2. export ${ENV_WORKER_PASSWORD_PREFIX + facilitatorConfig.chains[auxChainId].worker}= \n\n`); + } catch (e) { + Logger.error(e); + process.exit(1); + } }) .parse(process.argv); diff --git a/src/bin/facilitator-start.ts b/src/bin/facilitator-start.ts index 254430bc..9ff55aa4 100644 --- a/src/bin/facilitator-start.ts +++ b/src/bin/facilitator-start.ts @@ -20,6 +20,7 @@ import commander from 'commander'; import Container from '../Container'; import Facilitator from '../Facilitator'; import Logger from '../Logger'; +import ConfigFactory from '../Config/ConfigFactory'; const facilitatorCmd = commander .arguments('[origin_chain] [aux_chain_id]'); @@ -39,14 +40,35 @@ process.on('SIGTERM', terminationHandler); facilitatorCmd .option('-m, --mosaic-config ', 'path to mosaic configuration') + .option('-g, --gateway-config ', 'path to gateway configuration') .option('-t, --facilitator-config ', 'path to facilitator configuration') .action(async (origin_chain, aux_chain_id, options) => { + let mandatoryOptionMissing = false; try { - facilitator = await Container.create( + if ( + (options.mosaicConfig && options.gatewayConfig) + ) { + Logger.error('one option out of gateway config and mosaic config is required.'); + mandatoryOptionMissing = true; + } + + if (mandatoryOptionMissing) { + Logger.info('refer readme for more details'); + process.exit(1); + } + + Logger.debug('Reading config file'); + const configFactory: ConfigFactory = new ConfigFactory( origin_chain, - aux_chain_id, + aux_chain_id ? Number.parseInt(aux_chain_id, 10) : undefined, options.mosaicConfig, options.facilitatorConfig, + options.gatewayConfig, + ); + const config = configFactory.getConfig(); + Logger.debug('Config loaded successfully.'); + facilitator = await Container.create( + config, ); Logger.info('facilitator starting...'); await facilitator.start(); diff --git a/src/bin/facilitator.ts b/src/bin/facilitator.ts index 6cabef30..3097ef11 100644 --- a/src/bin/facilitator.ts +++ b/src/bin/facilitator.ts @@ -21,5 +21,5 @@ import facilitator from 'commander'; facilitator .command('init ', 'initializes the facilitator config') - .command('start ', 'starts the facilitator') + .command('start ', 'starts the facilitator') .parse(process.argv); diff --git a/src/lib/FacilitatorInit.ts b/src/lib/FacilitatorInit.ts new file mode 100644 index 00000000..a88297dd --- /dev/null +++ b/src/lib/FacilitatorInit.ts @@ -0,0 +1,58 @@ +import MosaicConfig from '@openst/mosaic-chains/lib/src/Config/MosaicConfig'; +import GatewayConfig from '@openst/mosaic-chains/lib/src/Config/GatewayConfig'; +import GatewayAddresses from '../Config/GatewayAddresses'; + +/** + * It contains helper methods for facilitator init command. + */ +export default class FacilitatorInit { +/** + * It provides gateway addresses and origin chain id. It is to be used when mosaic + * config is provided. + * @param auxChainId Auxiliary chain id. + * @param mosaicConfigPath Path to mosaic config. + * @returns originchain id and gatewayaddresses object. + */ + public static getFromMosaicConfig( + auxChainId: number, + mosaicConfigPath: string, + ): { + originChainId?: string; gatewayAddresses?: GatewayAddresses; + } { + const mosaicConfig = MosaicConfig.fromFile(mosaicConfigPath); + const auxChain = mosaicConfig.auxiliaryChains[auxChainId]; + if (!auxChain) { + return {}; + } + + return { + originChainId: mosaicConfig.originChain.chain, + gatewayAddresses: GatewayAddresses.fromMosaicConfig(mosaicConfig, auxChainId), + }; + } + + /** + * It provides gateway addresses and origin chain id. It is to be used when gateway + * config is provided. + * @param auxChainId Auxiliary chain id. + * @param gatewayConfigPath Path to gateway config. + * @returns originchain id and gatewayaddresses object. + */ + public static getFromGatewayConfig( + auxChainId: number, + gatewayConfigPath: string, + ): { + originChainId?: string; gatewayAddresses?: GatewayAddresses; + } { + const gatewayConfig = GatewayConfig.fromFile(gatewayConfigPath); + + if (!(auxChainId === gatewayConfig.auxChainId)) { + return {}; + } + + return { + originChainId: gatewayConfig.mosaicConfig.originChain.chain, + gatewayAddresses: GatewayAddresses.fromGatewayConfig(gatewayConfig), + }; + } +} diff --git a/test/Config/createWeb3Instance.test.ts b/test/Config/createWeb3Instance.test.ts index 8e2f7d87..bcd94ba9 100644 --- a/test/Config/createWeb3Instance.test.ts +++ b/test/Config/createWeb3Instance.test.ts @@ -19,7 +19,9 @@ import sinon from 'sinon'; import Web3 from 'web3'; import Account from '../../src/Account'; -import { Chain, Config, ENV_WORKER_PASSWORD_PREFIX } from '../../src/Config/Config'; +import { + Chain, Config, ConfigType, ENV_WORKER_PASSWORD_PREFIX, +} from '../../src/Config/Config'; import assert from '../test_utils/assert'; import SpyAssert from '../test_utils/SpyAssert'; @@ -29,7 +31,7 @@ describe('Config.createWeb3Instance', () => { beforeEach(() => { const mosaicConfigPath = 'test/Facilitator/testdata/mosaic.json'; const facilitatorConfigPath = 'test/FacilitatorConfig/testdata/facilitator-config.json'; - config = Config.fromFile(mosaicConfigPath, facilitatorConfigPath); + config = Config.fromFile(facilitatorConfigPath, mosaicConfigPath, ConfigType.MOSAIC); chain = config.facilitator.chains[config.facilitator.originChain]; }); diff --git a/test/Config/fromChain.test.ts b/test/Config/fromChain.test.ts index 24d52287..3f77f6ff 100644 --- a/test/Config/fromChain.test.ts +++ b/test/Config/fromChain.test.ts @@ -63,7 +63,7 @@ describe('Config.fromChain()', () => { assert.strictEqual( config.gatewayAddresses, gatewayAddresses, - 'Mosaic object is different', + 'GatewayAddresses object is different', ); sinon.restore(); diff --git a/test/Config/fromFile.test.ts b/test/Config/fromFile.test.ts index ddec7e6d..42015d09 100644 --- a/test/Config/fromFile.test.ts +++ b/test/Config/fromFile.test.ts @@ -18,7 +18,7 @@ import sinon from 'sinon'; import MosaicConfig from '@openst/mosaic-chains/lib/src/Config/MosaicConfig'; -import { Config, FacilitatorConfig } from '../../src/Config/Config'; +import { Config, FacilitatorConfig, ConfigType } from '../../src/Config/Config'; import assert from '../test_utils/assert'; import SpyAssert from '../test_utils/SpyAssert'; import GatewayAddresses from '../../src/Config/GatewayAddresses'; @@ -52,7 +52,7 @@ describe('Config.fromFile()', () => { sinon.fake.returns(facilitator), ); - const config = Config.fromFile(mosaicConfigPath, facilitatorConfigPath); + const config = Config.fromFile(facilitatorConfigPath, mosaicConfigPath, ConfigType.MOSAIC); SpyAssert.assert(mosaicConfigSpy, 1, [[mosaicConfigPath]]); SpyAssert.assert(facilitatorConfigSpy, 1, [[facilitatorConfigPath]]); @@ -70,4 +70,24 @@ describe('Config.fromFile()', () => { sinon.restore(); }); + + it('should fail when invalid config type is provided', () => { + const mosaic = sinon.createStubInstance(MosaicConfig); + const facilitator = FacilitatorConfig.fromChain(auxChain); + facilitator.auxChainId = auxChain; + const gatewayAddresses = sinon.createStubInstance(GatewayAddresses); + const invalidConfigType = 'invalidconfigtype' as ConfigType; + + sinon.replace(MosaicConfig, 'fromFile', sinon.fake.returns(mosaic)); + + sinon.replace(GatewayAddresses, 'fromMosaicConfig', sinon.fake.returns(gatewayAddresses)); + + sinon.replace(FacilitatorConfig, 'fromFile', sinon.fake.returns(facilitator)); + + assert.throws( + () => Config.fromFile(facilitatorConfigPath, mosaicConfigPath, invalidConfigType), + `Invalid config type ${invalidConfigType}`, + ); + sinon.restore(); + }); }); diff --git a/test/Config/getAuxiliaryWeb3.test.ts b/test/Config/getAuxiliaryWeb3.test.ts index 07514229..bb795dcf 100644 --- a/test/Config/getAuxiliaryWeb3.test.ts +++ b/test/Config/getAuxiliaryWeb3.test.ts @@ -19,7 +19,7 @@ import { assert } from 'chai'; import sinon from 'sinon'; import Web3 from 'web3'; -import { Chain, Config } from '../../src/Config/Config'; +import { Chain, Config, ConfigType } from '../../src/Config/Config'; import SpyAssert from '../test_utils/SpyAssert'; describe('Config.auxiliaryWeb3', () => { @@ -28,7 +28,7 @@ describe('Config.auxiliaryWeb3', () => { beforeEach(() => { const mosaicConfigPath = 'test/Facilitator/testdata/mosaic.json'; const facilitatorConfigPath = 'test/FacilitatorConfig/testdata/facilitator-config.json'; - config = Config.fromFile(mosaicConfigPath, facilitatorConfigPath); + config = Config.fromFile(facilitatorConfigPath, mosaicConfigPath, ConfigType.MOSAIC); chain = config.facilitator.chains[config.facilitator.auxChainId]; }); diff --git a/test/Config/getOriginWeb3.test.ts b/test/Config/getOriginWeb3.test.ts index 499c362e..48769656 100644 --- a/test/Config/getOriginWeb3.test.ts +++ b/test/Config/getOriginWeb3.test.ts @@ -19,7 +19,7 @@ import { assert } from 'chai'; import sinon from 'sinon'; import Web3 from 'web3'; -import { Chain, Config } from '../../src/Config/Config'; +import { Chain, Config, ConfigType } from '../../src/Config/Config'; import SpyAssert from '../test_utils/SpyAssert'; describe('Config.originWeb3', () => { @@ -28,7 +28,7 @@ describe('Config.originWeb3', () => { beforeEach(() => { const mosaicConfigPath = 'test/Facilitator/testdata/mosaic.json'; const facilitatorConfigPath = 'test/FacilitatorConfig/testdata/facilitator-config.json'; - config = Config.fromFile(mosaicConfigPath, facilitatorConfigPath); + config = Config.fromFile(facilitatorConfigPath, mosaicConfigPath, ConfigType.MOSAIC); chain = config.facilitator.chains[config.facilitator.originChain]; }); diff --git a/test/ConfigFactory/getConfig.test.ts b/test/ConfigFactory/getConfig.test.ts index 383232d0..0834e4d9 100644 --- a/test/ConfigFactory/getConfig.test.ts +++ b/test/ConfigFactory/getConfig.test.ts @@ -15,22 +15,76 @@ // ---------------------------------------------------------------------------- -import sinon from 'sinon'; +import sinon, { SinonStub, SinonStubbedInstance } from 'sinon'; import MosaicConfig from '@openst/mosaic-chains/lib/src/Config/MosaicConfig'; -import { Config, FacilitatorConfig } from '../../src/Config/Config'; +import GatewayConfig from '@openst/mosaic-chains/lib/src/Config/GatewayConfig'; +import { Config, ConfigType, FacilitatorConfig } from '../../src/Config/Config'; import ConfigFactory from '../../src/Config/ConfigFactory'; import assert from '../test_utils/assert'; import SpyAssert from '../test_utils/SpyAssert'; import GatewayAddresses from '../../src/Config/GatewayAddresses'; -describe('FacilitatorOptionParser.getConfig()', () => { +describe('ConfigFactory.getConfig()', () => { const originChain = '2'; const auxChain = 3; + + function getMosaic(): object { + return { + originChain: + { + chain: originChain, + }, + auxiliaryChains: + { + [auxChain]: + { + chainId: auxChain, + }, + }, + }; + } + + function getFacilitator(): object { + return { + originChain, + auxChainId: auxChain, + chains: + { + [originChain]: + { + worker: '0x123', + }, + [auxChain]: + { + worker: '0x123', + }, + }, + }; + } + const facilitatorConfigPath = './facilitator-config.json'; const mosaicConfigPath = './test/mosaic-config.json'; + const gatewayConfigPath = './gateway-config.json'; + const mosaic = getMosaic() as MosaicConfig; + + const facilitator = getFacilitator() as FacilitatorConfig; + + function spyFromGatewayConfig( + gatewayAddresses: GatewayAddresses, + ): SinonStub<[GatewayConfig], GatewayAddresses> { + const spy = sinon.stub( + GatewayAddresses, + 'fromGatewayConfig', + ).callsFake( + sinon.fake.returns(gatewayAddresses), + ); + return spy; + } - function spyFacilitatorFromFile(fcConfig: any): any { + function spyFacilitatorFromFile( + fcConfig: FacilitatorConfig | SinonStubbedInstance, + ): SinonStub<[string], FacilitatorConfig> { const spy = sinon.stub( FacilitatorConfig, 'fromFile', @@ -40,7 +94,21 @@ describe('FacilitatorOptionParser.getConfig()', () => { return spy; } - function spyFacilitatorFromChain(fcConfig: any): any { + function spyGatewayConfigFromFile( + gatewayConfig: GatewayConfig, + ): SinonStub<[string], GatewayConfig> { + const spy = sinon.stub( + GatewayConfig, + 'fromFile', + ).callsFake( + sinon.fake.returns(gatewayConfig), + ); + return spy; + } + + function spyFacilitatorFromChain( + fcConfig: FacilitatorConfig, + ): SinonStub<[number], FacilitatorConfig> { const spy = sinon.stub( FacilitatorConfig, 'fromChain', @@ -50,7 +118,7 @@ describe('FacilitatorOptionParser.getConfig()', () => { return spy; } - function spyMosaicFromChain(mosaicConfig: MosaicConfig): any { + function spyMosaicFromChain(mosaicConfig: MosaicConfig): SinonStub<[string], MosaicConfig> { const spy = sinon.stub( MosaicConfig, 'fromChain', @@ -60,7 +128,9 @@ describe('FacilitatorOptionParser.getConfig()', () => { return spy; } - function spyGatewayAddressesFromMosaicConfig(gatewayAddresses: GatewayAddresses): any { + function spyGatewayAddressesFromMosaicConfig( + gatewayAddresses: GatewayAddresses, + ): SinonStub<[MosaicConfig, number], GatewayAddresses> { const spy = sinon.stub( GatewayAddresses, 'fromMosaicConfig', @@ -70,7 +140,7 @@ describe('FacilitatorOptionParser.getConfig()', () => { return spy; } - function spyMosaicfromFile(mosaicConfig: MosaicConfig): any { + function spyMosaicfromFile(mosaicConfig: MosaicConfig): SinonStub<[string], MosaicConfig> { const spy = sinon.stub( MosaicConfig, 'fromFile', @@ -80,6 +150,33 @@ describe('FacilitatorOptionParser.getConfig()', () => { return spy; } + function spyConfigfromFile(config: Config): SinonStub<[string, string, ConfigType], Config> { + const spy = sinon.stub( + Config, + 'fromFile', + ).callsFake( + sinon.fake.returns(config), + ); + return spy; + } + + function spyMosaicExists(status: boolean): SinonStub<[string], boolean> { + const spy = sinon.stub( + MosaicConfig, + 'exists', + ).callsFake( + sinon.fake.returns(status), + ); + return spy; + } + + function getGatewayConfigStub(auxChain: number): SinonStubbedInstance { + const stubGatewayConfig = sinon.createStubInstance(GatewayConfig); + stubGatewayConfig.mosaicConfig = mosaic; + stubGatewayConfig.auxChainId = auxChain; + return stubGatewayConfig; + } + it('should fail when origin chain is provided but aux chain id is undefined', () => { const fs: ConfigFactory = new ConfigFactory( originChain, @@ -94,7 +191,7 @@ describe('FacilitatorOptionParser.getConfig()', () => { ); }); - it('should fail when origin chain is provided but aux chain id is blank', () => { + it('should fail when origin chain is provided but aux chain id is undefined', () => { const fs: ConfigFactory = new ConfigFactory( originChain, undefined, @@ -179,9 +276,8 @@ describe('FacilitatorOptionParser.getConfig()', () => { }); it('should fail when mosaic config path is provided and input origin chain doesn\'t match in it', () => { - const config = `{"originChain":{"chain":"${originChain}"},"auxiliaryChains":{"${auxChain}":{"chainId": ${auxChain}}}}`; const dummyoriginChain = '9'; - const spy = spyMosaicfromFile(JSON.parse(config)); + const spy = spyMosaicfromFile(getMosaic() as MosaicConfig); const fs: ConfigFactory = new ConfigFactory( dummyoriginChain, @@ -200,9 +296,8 @@ describe('FacilitatorOptionParser.getConfig()', () => { }); it('should fail when mosaic config path is provided and aux chain id is not present in it', () => { - const config = `{"originChain":{"chain":"${originChain}"},"auxiliaryChains":{"${auxChain}":{"chainId": ${auxChain}}}}`; const dummyAuxChainId = 9; - const spy = spyMosaicfromFile(JSON.parse(config)); + const spy = spyMosaicfromFile(getMosaic() as MosaicConfig); const fs: ConfigFactory = new ConfigFactory( originChain, dummyAuxChainId, @@ -221,10 +316,9 @@ describe('FacilitatorOptionParser.getConfig()', () => { it('should pass when origin chain, aux chain id is provided and facilitator config path is ' + 'provided', () => { - const config = `{"originChain":"7","auxChainId":"${auxChain}","chains":{"${originChain}":{"worker": "0x123"},"${auxChain}":{"worker": "0x123"}}}`; const mosaicConfig = sinon.createStubInstance(MosaicConfig); const gatewayAddresses = sinon.createStubInstance(GatewayAddresses); - const facilitatorConfig = JSON.parse(config) as FacilitatorConfig; + const facilitatorConfig = getFacilitator() as FacilitatorConfig; const facilitatorSpy = spyFacilitatorFromFile(facilitatorConfig); const mosaicSpy = spyMosaicFromChain(mosaicConfig); const gatewayAddressesSpy = spyGatewayAddressesFromMosaicConfig(gatewayAddresses); @@ -239,7 +333,7 @@ describe('FacilitatorOptionParser.getConfig()', () => { const configObj: Config = fs.getConfig(); SpyAssert.assert(facilitatorSpy, 1, [[facilitatorConfigPath]]); SpyAssert.assert(mosaicSpy, 1, [[originChain]]); - SpyAssert.assert(gatewayAddressesSpy, 1, [[mosaicConfig, auxChain.toString()]]); + SpyAssert.assert(gatewayAddressesSpy, 1, [[mosaicConfig, auxChain]]); assert.strictEqual( configObj.gatewayAddresses, @@ -253,12 +347,8 @@ describe('FacilitatorOptionParser.getConfig()', () => { }); it('should pass when origin chain, aux chain and mosaic config path is provided', () => { - const mosaicJson = `{"originChain":{"chain":"${originChain}"},"auxiliaryChains":{"${auxChain}":{"chainId": ${auxChain}}}}`; - const facilitatorJson = `{"originChain":"7","auxChainId":"${auxChain}","chains":{"${originChain}":{"worker": "0x123"},"${auxChain}":{"worker": "0x123"}}}`; - const mosaic = JSON.parse(mosaicJson) as MosaicConfig; const mosaicSpy = spyMosaicfromFile(mosaic); const gatewayAddresses = sinon.createStubInstance(GatewayAddresses); - const facilitator = JSON.parse(facilitatorJson) as FacilitatorConfig; const facilitatorSpy = spyFacilitatorFromChain(facilitator); const gatewayAddressesSpy = spyGatewayAddressesFromMosaicConfig(gatewayAddresses); @@ -267,13 +357,14 @@ describe('FacilitatorOptionParser.getConfig()', () => { auxChain, mosaicConfigPath, '', + '', ); const configObj = fs.getConfig(); SpyAssert.assert(mosaicSpy, 1, [[mosaicConfigPath]]); SpyAssert.assert(facilitatorSpy, 1, [[auxChain]]); - SpyAssert.assert(gatewayAddressesSpy, 1, [[mosaic, auxChain.toString()]]); + SpyAssert.assert(gatewayAddressesSpy, 1, [[mosaic, auxChain]]); assert.strictEqual( configObj.facilitator, facilitator as any, @@ -290,10 +381,7 @@ describe('FacilitatorOptionParser.getConfig()', () => { }); it('should pass when origin chain and aux chain is provided', () => { - const facilitatorJson = `{"originChain":"7","auxChainId":"${auxChain}","chains":{"${originChain}":{"worker": "0x123"},"${auxChain}":{"worker": "0x123"}}}`; - const facilitator = JSON.parse(facilitatorJson) as FacilitatorConfig; const gatewayAddresses = sinon.createStubInstance(GatewayAddresses); - const mosaic = sinon.createStubInstance(MosaicConfig); const facilitatorSpy = spyFacilitatorFromChain(facilitator); const mosaicSpy = spyMosaicFromChain(mosaic); @@ -304,7 +392,7 @@ describe('FacilitatorOptionParser.getConfig()', () => { SpyAssert.assert(mosaicSpy, 1, [[originChain]]); SpyAssert.assert(facilitatorSpy, 1, [[auxChain]]); - SpyAssert.assert(gatewayAddressesSpy, 1, [[mosaic, auxChain.toString()]]); + SpyAssert.assert(gatewayAddressesSpy, 1, [[mosaic, auxChain]]); assert.strictEqual( config.gatewayAddresses, gatewayAddresses, @@ -322,12 +410,7 @@ describe('FacilitatorOptionParser.getConfig()', () => { }); it('should pass when facilitator config and mosaic config is provided', () => { - const mosaicJson = `{"originChain":{"chain":"${originChain}"},"auxiliaryChains":{"${auxChain}":{"chainId": ${auxChain}}}}`; - const mosaic = JSON.parse(mosaicJson) as MosaicConfig; const mosaicFromFileSpy = spyMosaicfromFile(mosaic); - const facilitator = sinon.createStubInstance(FacilitatorConfig); - facilitator.originChain = originChain; - facilitator.auxChainId = auxChain; const gatewayAddresses = sinon.createStubInstance(GatewayAddresses); const facilitatorFromFileSpy = spyFacilitatorFromFile(facilitator); const gatewayAddressesSpy = spyGatewayAddressesFromMosaicConfig(gatewayAddresses); @@ -359,13 +442,13 @@ describe('FacilitatorOptionParser.getConfig()', () => { it('should fail when facilitator config and mosaic config is provided but origin chain doesn\'t match', () => { const configJson = `{"originChain":{"chain":"${originChain}"},"auxiliaryChains":{"${auxChain}":{"chainId": ${auxChain}}}}`; - const mosaic = JSON.parse(configJson) as MosaicConfig; - const facilitator = sinon.createStubInstance(FacilitatorConfig); - facilitator.originChain = '5'; + const mosaicConfig = JSON.parse(configJson) as MosaicConfig; + const facilitatorStub = sinon.createStubInstance(FacilitatorConfig); + facilitatorStub.originChain = '5'; - facilitator.auxChainId = 3; - spyMosaicfromFile(mosaic); - spyFacilitatorFromFile(facilitator); + facilitatorStub.auxChainId = 3; + spyMosaicfromFile(mosaicConfig); + spyFacilitatorFromFile(facilitatorStub); const fs: ConfigFactory = new ConfigFactory( undefined as any, @@ -378,22 +461,18 @@ describe('FacilitatorOptionParser.getConfig()', () => { () => fs.getConfig(), 'origin chain id in mosaic config is different than the one provided', ); - sinon.restore(); }); it('should fail when facilitator config and mosaic config is provided but auxiliary ' + 'id doesn\'t match', () => { - const configJson = `{"originChain":{"chain":"${originChain}"},"auxiliaryChains":{"${auxChain}":{"chainId": ${auxChain}}}}`; - const mosaic = JSON.parse(configJson) as MosaicConfig; - - const facilitator = sinon.createStubInstance(FacilitatorConfig); - facilitator.originChain = '5'; + const facilitatorStub = sinon.createStubInstance(FacilitatorConfig); + facilitatorStub.originChain = '5'; - facilitator.auxChainId = 3; + facilitatorStub.auxChainId = 3; spyMosaicfromFile(mosaic); - spyFacilitatorFromFile(facilitator); + spyFacilitatorFromFile(facilitatorStub); const fs: ConfigFactory = new ConfigFactory( undefined as any, @@ -411,13 +490,11 @@ describe('FacilitatorOptionParser.getConfig()', () => { }); it('should pass when only facilitator config is provided', () => { - const facilitatorJson = `{"originChain":"${originChain}","auxChainId":"${auxChain}","chains":{"${originChain}":{"worker": "0x123"},"${auxChain}":{"worker": "0x123"}}}`; - const mosaic = sinon.createStubInstance(MosaicConfig); const gatewayAddresses = sinon.createStubInstance(GatewayAddresses); - const facilitatorSpy = spyFacilitatorFromFile(JSON.parse(facilitatorJson)); + const facilitatorSpy = spyFacilitatorFromFile(getFacilitator() as FacilitatorConfig); const mosaicSpy = spyMosaicFromChain(mosaic); const gatewayAddressesSpy = spyGatewayAddressesFromMosaicConfig(gatewayAddresses); - + const mosaicExistsSpy = spyMosaicExists(true); const fs: ConfigFactory = new ConfigFactory( undefined, undefined, @@ -428,7 +505,8 @@ describe('FacilitatorOptionParser.getConfig()', () => { SpyAssert.assert(facilitatorSpy, 1, [[facilitatorConfigPath]]); SpyAssert.assert(mosaicSpy, 1, [[originChain]]); - SpyAssert.assert(gatewayAddressesSpy, 1, [[mosaic, auxChain.toString()]]); + SpyAssert.assert(gatewayAddressesSpy, 1, [[mosaic, auxChain]]); + SpyAssert.assert(mosaicExistsSpy, 1, [[originChain]]); assert.strictEqual( config.gatewayAddresses, gatewayAddresses, @@ -441,8 +519,225 @@ describe('FacilitatorOptionParser.getConfig()', () => { `Expected chain id is ${originChain} but got ${config.facilitator.originChain}`, ); - sinon.restore(); facilitatorSpy.restore(); mosaicSpy.restore(); + sinon.restore(); + }); + + it('should pass when origin chain, aux chain id, facilitator config and mosaic config is provided', () => { + const mosaicFromFileSpy = spyMosaicfromFile(mosaic); + const fakeConfig = sinon.createStubInstance(Config); + const configFromFileSpy = spyConfigfromFile(fakeConfig); + const facilitatorFromFileSpy = spyFacilitatorFromFile(facilitator); + const fs: ConfigFactory = new ConfigFactory( + originChain, + auxChain, + mosaicConfigPath, + facilitatorConfigPath, + ); + + const config: Config = fs.getConfig(); + + SpyAssert.assert(facilitatorFromFileSpy, 1, [[facilitatorConfigPath]]); + SpyAssert.assert(mosaicFromFileSpy, 1, [[mosaicConfigPath]]); + SpyAssert.assert( + configFromFileSpy, + 1, + [[facilitatorConfigPath, mosaicConfigPath, ConfigType.MOSAIC]], + ); + assert.strictEqual( + config, + fakeConfig, + 'Invalid gateway addresses object', + ); + + facilitatorFromFileSpy.restore(); + configFromFileSpy.restore(); + mosaicFromFileSpy.restore(); + sinon.restore(); + }); + + it('should pass when origin chain, aux chain id and gateway config is provided', () => { + const stubGatewayConfig = getGatewayConfigStub(auxChain); + const facilitatorFromChainSpy = spyFacilitatorFromChain(facilitator); + const gatewayConfigFromFileSpy = spyGatewayConfigFromFile(stubGatewayConfig); + const gatewayAddresses = sinon.createStubInstance(GatewayAddresses); + const fromGatewayConfigSpy = spyFromGatewayConfig(gatewayAddresses); + + const fs: ConfigFactory = new ConfigFactory( + originChain, + auxChain, + undefined, + undefined, + gatewayConfigPath, + ); + + const config: Config = fs.getConfig(); + + SpyAssert.assert(facilitatorFromChainSpy, 1, [[auxChain]]); + SpyAssert.assert(gatewayConfigFromFileSpy, 1, [[gatewayConfigPath]]); + SpyAssert.assert(fromGatewayConfigSpy, 1, [[stubGatewayConfig]]); + + assert.strictEqual( + config.gatewayAddresses, + gatewayAddresses, + 'Invalid gateway addresses object', + ); + + assert.strictEqual( + config.facilitator, + facilitator, + 'Invalid facilitator object', + ); + + sinon.restore(); + }); + + it('should fail when origin chain, aux chain id and gateway config is provided but aux chain id is incorrect in mosaic config', () => { + const stubGatewayConfig = getGatewayConfigStub(auxChain); + spyFacilitatorFromChain(facilitator); + spyGatewayConfigFromFile(stubGatewayConfig); + const gatewayAddresses = sinon.createStubInstance(GatewayAddresses); + spyFromGatewayConfig(gatewayAddresses); + const auxChainId = 200; + + const fs: ConfigFactory = new ConfigFactory( + originChain, + auxChainId, + undefined, + undefined, + gatewayConfigPath, + ); + + assert.throws( + () => fs.getConfig(), + 'aux chain is not present in mosaic config', + ); + + sinon.restore(); + }); + + it('should pass when origin chain, aux chain id and gateway config is provided', () => { + const stubGatewayConfig = getGatewayConfigStub(auxChain); + const facilitatorFromChainSpy = spyFacilitatorFromChain(facilitator); + const gatewayConfigFromFileSpy = spyGatewayConfigFromFile(stubGatewayConfig); + const gatewayAddresses = sinon.createStubInstance(GatewayAddresses); + const fromGatewayConfigSpy = spyFromGatewayConfig(gatewayAddresses); + + const fs: ConfigFactory = new ConfigFactory( + originChain, + auxChain, + undefined, + undefined, + gatewayConfigPath, + ); + + const config: Config = fs.getConfig(); + + SpyAssert.assert(facilitatorFromChainSpy, 1, [[auxChain]]); + SpyAssert.assert(gatewayConfigFromFileSpy, 1, [[gatewayConfigPath]]); + SpyAssert.assert(fromGatewayConfigSpy, 1, [[stubGatewayConfig]]); + + assert.strictEqual( + config.gatewayAddresses, + gatewayAddresses, + 'Invalid gateway addresses object', + ); + + assert.strictEqual( + config.facilitator, + facilitator, + 'Invalid facilitator object', + ); + + facilitatorFromChainSpy.restore(); + gatewayConfigFromFileSpy.restore(); + fromGatewayConfigSpy.restore(); + sinon.restore(); + }); + + it('should pass when facilitator and gateway config path is provided', () => { + const stubGatewayConfig = getGatewayConfigStub(auxChain); + const facilitatorFromFileSpy = spyFacilitatorFromFile(facilitator); + const gatewayConfigFromFileSpy = spyGatewayConfigFromFile(stubGatewayConfig); + const gatewayAddresses = sinon.createStubInstance(GatewayAddresses); + const fromGatewayConfigSpy = spyFromGatewayConfig(gatewayAddresses); + + const fs: ConfigFactory = new ConfigFactory( + undefined, + undefined, + undefined, + facilitatorConfigPath, + gatewayConfigPath, + ); + + const config: Config = fs.getConfig(); + + SpyAssert.assert(facilitatorFromFileSpy, 1, [[facilitatorConfigPath]]); + SpyAssert.assert(gatewayConfigFromFileSpy, 1, [[gatewayConfigPath]]); + SpyAssert.assert(fromGatewayConfigSpy, 1, [[stubGatewayConfig]]); + + assert.strictEqual( + config.gatewayAddresses, + gatewayAddresses, + 'Invalid gateway addresses object', + ); + + assert.strictEqual( + config.facilitator, + facilitator, + 'Invalid facilitator object', + ); + + sinon.restore(); + }); + + it('should fail when facilitator and gateway config path is provided but aux chain id is different', () => { + const auxChainIdInGatewayConfig = 200; + const stubGatewayConfig = getGatewayConfigStub(auxChainIdInGatewayConfig); + spyFacilitatorFromFile(facilitator); + spyGatewayConfigFromFile(stubGatewayConfig); + const gatewayAddresses = sinon.createStubInstance(GatewayAddresses); + spyFromGatewayConfig(gatewayAddresses); + + const fs: ConfigFactory = new ConfigFactory( + undefined, + undefined, + undefined, + facilitatorConfigPath, + gatewayConfigPath, + ); + + assert.throws( + () => fs.getConfig(), + `Aux chain id ${auxChainIdInGatewayConfig} in gatewayconfig and provided auxchain id ${auxChain} are not same`, + ); + + + sinon.restore(); + }); + + it('should fail when only facilitator config is provided but mosaic config is not found', () => { + const gatewayAddresses = sinon.createStubInstance(GatewayAddresses); + const facilitatorSpy = spyFacilitatorFromFile(getFacilitator() as FacilitatorConfig); + const mosaicConfig = MosaicConfig.fromChain('200'); + spyMosaicExists(false); + spyMosaicFromChain(mosaicConfig); + spyGatewayAddressesFromMosaicConfig(gatewayAddresses); + + const fs: ConfigFactory = new ConfigFactory( + undefined, + undefined, + undefined, + facilitatorConfigPath, + ); + + assert.throws( + () => fs.getConfig(), + 'mosaic config not found', + ); + + facilitatorSpy.restore(); + sinon.restore(); }); }); diff --git a/test/SeedData/populateDb.test.ts b/test/SeedData/populateDb.test.ts index 27a816c0..3ebc5152 100644 --- a/test/SeedData/populateDb.test.ts +++ b/test/SeedData/populateDb.test.ts @@ -22,7 +22,7 @@ import * as Web3Utils from 'web3-utils'; import { interacts } from '@openst/mosaic-contracts'; -import { Config } from '../../src/Config/Config'; +import { Config, ConfigType } from '../../src/Config/Config'; import AuxiliaryChain from '../../src/models/AuxiliaryChain'; import ContractEntity, { EntityType } from '../../src/models/ContractEntity'; import Gateway from '../../src/models/Gateway'; @@ -289,7 +289,7 @@ describe('SeedData.populateDb()', (): void => { ); const mosaicConfigPath = 'test/Facilitator/testdata/mosaic.json'; const facilitatorConfigPath = 'test/FacilitatorConfig/testdata/facilitator-config.json'; - config = Config.fromFile(mosaicConfigPath, facilitatorConfigPath); + config = Config.fromFile(facilitatorConfigPath, mosaicConfigPath, ConfigType.MOSAIC); sinon.replaceGetter( config, 'originWeb3', diff --git a/test/lib/FacilitatorInit/getFromGatewayConfig.test.ts b/test/lib/FacilitatorInit/getFromGatewayConfig.test.ts new file mode 100644 index 00000000..68966f9f --- /dev/null +++ b/test/lib/FacilitatorInit/getFromGatewayConfig.test.ts @@ -0,0 +1,128 @@ +// Copyright 2019 OpenST Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ---------------------------------------------------------------------------- + + +import sinon, { SinonStub, SinonStubbedInstance } from 'sinon'; + +import MosaicConfig from '@openst/mosaic-chains/lib/src/Config/MosaicConfig'; +import GatewayConfig from '@openst/mosaic-chains/lib/src/Config/GatewayConfig'; +import assert from '../../test_utils/assert'; +import SpyAssert from '../../test_utils/SpyAssert'; +import FacilitatorInit from '../../../src/lib/FacilitatorInit'; +import GatewayAddresses from '../../../src/Config/GatewayAddresses'; + + +describe('FacilitatorInit.getFromGatewayConfig()', () => { + const gatewayConfigPath = 'test/Config/gateway-config.json'; + const auxChain = 3; + const originChain = '2'; + + function getMosaic(): object { + return { + originChain: + { + chain: originChain, + }, + auxiliaryChains: + { + [auxChain]: + { + chainId: auxChain, + }, + }, + }; + } + + const mosaic = getMosaic() as MosaicConfig; + + function getGatewayConfigStub(): SinonStubbedInstance { + const stubGatewayConfig = sinon.createStubInstance(GatewayConfig); + stubGatewayConfig.mosaicConfig = mosaic; + stubGatewayConfig.auxChainId = auxChain; + return stubGatewayConfig; + } + + function spyGatewayConfigfromFile( + gatewayConfig: GatewayConfig, + ): SinonStub<[string], GatewayConfig> { + const spy = sinon.stub( + GatewayConfig, + 'fromFile', + ).callsFake( + sinon.fake.returns(gatewayConfig), + ); + return spy; + } + + function spyFromGatewayConfig( + gatewayAddresses: GatewayAddresses, + ): SinonStub<[GatewayConfig], GatewayAddresses> { + const spy = sinon.stub( + GatewayAddresses, + 'fromGatewayConfig', + ).callsFake( + sinon.fake.returns(gatewayAddresses), + ); + return spy; + } + + it('should pass with valid arguments', () => { + const gatewayConfig = getGatewayConfigStub(); + + const gatewayConfigFromFileSpy = spyGatewayConfigfromFile(gatewayConfig); + const dummyGatewayAddresses = sinon.createStubInstance(GatewayAddresses); + const fromGatewayConfigSpy = spyFromGatewayConfig(dummyGatewayAddresses); + + const { + originChainId, + gatewayAddresses, + } = FacilitatorInit.getFromGatewayConfig(auxChain, gatewayConfigPath); + + SpyAssert.assert(gatewayConfigFromFileSpy, 1, [[gatewayConfigPath]]); + SpyAssert.assert(fromGatewayConfigSpy, 1, [[gatewayConfig]]); + + assert.strictEqual( + originChainId, + originChain, + 'Facilitator object is different', + ); + assert.strictEqual( + gatewayAddresses, + dummyGatewayAddresses, + 'GatewayAddresses object is different', + ); + + sinon.restore(); + }); + + it('should fail when aux chain is not present in gateway config', () => { + const gatewayConfig = getGatewayConfigStub(); + + const gatewayConfigFromFileSpy = spyGatewayConfigfromFile(gatewayConfig); + const invalidAuxChain = 200; + const emptyObject = FacilitatorInit.getFromGatewayConfig(invalidAuxChain, gatewayConfigPath); + + + SpyAssert.assert(gatewayConfigFromFileSpy, 1, [[gatewayConfigPath]]); + assert.strictEqual( + Object.keys(emptyObject).length === 0, + true, + 'Object must be empty', + ); + + sinon.restore(); + }); +}); diff --git a/test/lib/FacilitatorInit/getFromMosaicConfig.test.ts b/test/lib/FacilitatorInit/getFromMosaicConfig.test.ts new file mode 100644 index 00000000..a07925f5 --- /dev/null +++ b/test/lib/FacilitatorInit/getFromMosaicConfig.test.ts @@ -0,0 +1,113 @@ +// Copyright 2019 OpenST Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ---------------------------------------------------------------------------- + + +import sinon, { SinonStub } from 'sinon'; + +import MosaicConfig from '@openst/mosaic-chains/lib/src/Config/MosaicConfig'; +import assert from '../../test_utils/assert'; +import SpyAssert from '../../test_utils/SpyAssert'; +import FacilitatorInit from '../../../src/lib/FacilitatorInit'; +import GatewayAddresses from '../../../src/Config/GatewayAddresses'; + + +describe('FacilitatorInit.getFromMosaicConfig()', () => { + const mosaicConfigPath = 'test/Config/mosaic-config.json'; + const auxChain = 3; + const originChain = '2'; + + function getMosaic(): object { + return { + originChain: + { + chain: originChain, + }, + auxiliaryChains: + { + [auxChain]: + { + chainId: auxChain, + }, + }, + }; + } + + const mosaic = getMosaic() as MosaicConfig; + + function spyMosaicfromFile(mosaicConfig: MosaicConfig): SinonStub<[string], MosaicConfig> { + const spy = sinon.stub( + MosaicConfig, + 'fromFile', + ).callsFake( + sinon.fake.returns(mosaicConfig), + ); + return spy; + } + + function spyFromMosaicConfig( + gatewayAddresses: GatewayAddresses, + ): SinonStub<[MosaicConfig, number], GatewayAddresses> { + const spy = sinon.stub( + GatewayAddresses, + 'fromMosaicConfig', + ).callsFake( + sinon.fake.returns(gatewayAddresses), + ); + return spy; + } + + it('should pass with valid arguments', () => { + const mosaicFromFileSpy = spyMosaicfromFile(mosaic); + const dummyGatewayAddresses = sinon.createStubInstance(GatewayAddresses); + const fromMosaicConfigSpy = spyFromMosaicConfig(dummyGatewayAddresses); + + const { + originChainId, + gatewayAddresses, + } = FacilitatorInit.getFromMosaicConfig(auxChain, mosaicConfigPath); + + SpyAssert.assert(fromMosaicConfigSpy, 1, [[mosaic, auxChain]]); + SpyAssert.assert(mosaicFromFileSpy, 1, [[mosaicConfigPath]]); + + assert.strictEqual( + originChainId, + originChain, + `Expected origin chain id is ${originChain} but got ${originChainId}`, + ); + assert.strictEqual( + gatewayAddresses, + dummyGatewayAddresses, + 'GatewayAddresses object is different', + ); + + sinon.restore(); + }); + + it('should fail when aux chain is not present in mosaic config', () => { + const mosaicFromFileSpy = spyMosaicfromFile(mosaic); + + const emptyObject = FacilitatorInit.getFromMosaicConfig(100, mosaicConfigPath); + + SpyAssert.assert(mosaicFromFileSpy, 1, [[mosaicConfigPath]]); + assert.strictEqual( + Object.keys(emptyObject).length === 0, + true, + 'Object must be empty', + ); + + sinon.restore(); + }); +}); diff --git a/test_integration/0xA7f056b1320fE619571849f138Cd1Ae2f2e64179.json b/test_integration/0xA7f056b1320fE619571849f138Cd1Ae2f2e64179.json new file mode 100644 index 00000000..92d010df --- /dev/null +++ b/test_integration/0xA7f056b1320fE619571849f138Cd1Ae2f2e64179.json @@ -0,0 +1,15 @@ +{ + "mosaicConfigFilePath":"./test_integration/mosaic.json", + "auxChainId":1000, + "originContracts":{ + "baseTokenAddress":"0x8e183Fd2cd55C7C05bBf4FAC989740f69e559A6d", + "valueTokenAddress":"0x8e183Fd2cd55C7C05bBf4FAC989740f69e559A6d", + "gatewayOrganizationAddress":"0x3f99f42d226A0CD1C1Fcae1e8dC11b2f7a9DcE4B", + "eip20GatewayAddress":"0xaE02C7b1C324A8D94A564bC8d713Df89eae441fe" + }, + "auxiliaryContracts":{ + "coGatewayOrganizationAddress":"0x2D586C7E220839a9284888B10aDF4823AcD6EdF3", + "utilityTokenAddress":"0x62F8729C1C282C231a22252e90CE9735533D2518", + "eip20CoGatewayAddress":"0xc6fF898ceBf631eFb58eEc7187E4c1f70AE8d943" + } +} diff --git a/test_integration/Utils.ts b/test_integration/Utils.ts index 87714af5..da1a04fa 100644 --- a/test_integration/Utils.ts +++ b/test_integration/Utils.ts @@ -42,7 +42,7 @@ export default class Utils { private redeemPool: string; - private ostPrime: string; + private utilityTokenAddresses: string; public gatewayAddresses: GatewayAddresses; @@ -70,7 +70,7 @@ export default class Utils { this.auxiliaryWeb3.transactionConfirmationBlocks = 1; this.stakePoolAddress = this.gatewayAddresses.stakePoolAddress; this.redeemPool = this.gatewayAddresses.redeemPoolAddress; - this.ostPrime = this.gatewayAddresses.utilityTokenAddress; + this.utilityTokenAddresses = this.gatewayAddresses.utilityTokenAddress; } /** @@ -829,7 +829,7 @@ export default class Utils { public getSimpleTokenPrimeInstance(): OSTPrime { const simpletokenPrimeInstance: OSTPrime = interacts.getOSTPrime( this.auxiliaryWeb3, - this.ostPrime, + this.utilityTokenAddresses, ); return simpletokenPrimeInstance; } diff --git a/test_integration/mosaic.json b/test_integration/mosaic.json index 5b734412..b1c12edb 100644 --- a/test_integration/mosaic.json +++ b/test_integration/mosaic.json @@ -16,7 +16,7 @@ ], "contractAddresses": { "origin": { - "baseTokenAddress":"0x7de07272E4c6cb822503B46C8a41517935C3f0c0", + "baseTokenAddress":"0x9AC77F4c0ca4D0F2142D7a77175cf4F1295fb2d8", "anchorOrganizationAddress": "0x7de07272E4c6cb822503B46C8a41517935C3f0c0", "anchorAddress": "0xEa8D41fc6C6C0Ee155E5F6FbF9Cc1167Fa17927E", "gatewayOrganizationAddress": "0xaB5335771fBA0270634e649882229c7e8CaA6158",