diff --git a/CHANGELOG.md b/CHANGELOG.md index 7835dcc1e..34130747d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ The changelog format is based on [Keep a Changelog](https://keepachangelog.com/e | ---------------- | ------- | ------------------------------------------------------------------ | | Symbol Bootstrap | v1.1.2 | [symbol-bootstrap](https://www.npmjs.com/package/symbol-bootstrap) | +- The `bootstrap` preset is not the default anymore. The name must be provided via --preset or as a custom preset field. +- A 'safe' custom preset is cached in the target folder. It's not required when upgrading the node without a configuration change. - Added `--logger` option to the commands. ## [1.1.1] - Nov-16-2021 diff --git a/README.md b/README.md index afa184e94..5e5510922 100644 --- a/README.md +++ b/README.md @@ -64,14 +64,17 @@ Presets are defined at 4 levels from general to specific: Properties in each file override the previous values (by object deep merge). -### Out-of-the-box presets: +### Out-of-the-box presets and assemblies: -- `-p bootstrap`: Default [preset](https://github.com/nemtech/symbol-bootstrap/blob/main/presets/bootstrap/network.yml). It's a private network with 1 mongo database, 2 peers, 1 api and 1 rest gateway. Nemesis block is generated. -- `-p bootstrap -a light`: A [light](https://github.com/nemtech/symbol-bootstrap/blob/main/presets/bootstrap/assembly-light.yml) network. It's a version of bootstrap preset with 1 mongo database, 1 dual peer and 1 rest gateway. Great for faster light e2e automatic testing. Nemesis block is generated. -- `-p bootstrap -a full`: A [full](https://github.com/nemtech/symbol-bootstrap/blob/main/presets/bootstrap/assembly-full.yml) network. The default bootstrap preset plus 1 wallet, 1 explorer and 1 faucet. Great for demonstration purposes. Nemesis block is generated. +- `-p bootstrap`: A [multinode](https://github.com/nemtech/symbol-bootstrap/blob/main/presets/bootstrap/network.yml) local network. A network with 1 mongo database, 2 peers, 1 api and 1 rest gateway. Nemesis block is generated. +- `-p bootstrap -a light`: A [light](https://github.com/nemtech/symbol-bootstrap/blob/main/presets/bootstrap/assembly-light.yml) local network. It's a version of bootstrap preset with 1 mongo database, 1 dual peer and 1 rest gateway. Great for faster light e2e automatic testing. Nemesis block is generated. +- `-p bootstrap -a full`: A [full](https://github.com/nemtech/symbol-bootstrap/blob/main/presets/bootstrap/assembly-full.yml) local network. The bootstrap preset plus 1 wallet, 1 explorer and 1 faucet. Great for demonstration purposes. Nemesis block is generated. - `-p testnet -a peer`: A [harvesting](https://github.com/nemtech/symbol-bootstrap/blob/main/presets/testnet/assembly-peer.yml) peer node that connects to the current public [testnet](https://github.com/nemtech/symbol-bootstrap/blob/main/presets/testnet/network.yml). [Nemesis block](https://github.com/nemtech/symbol-bootstrap/tree/main/presets/testnet/seed/00000) is copied over. - `-p testnet -a api`: A [api](https://github.com/nemtech/symbol-bootstrap/blob/main/presets/testnet/assembly-api.yml) peer node that connects to the current public [testnet](https://github.com/nemtech/symbol-bootstrap/blob/main/presets/testnet/network.yml) running its own mongo database and rest gateway. [Nemesis block](https://github.com/nemtech/symbol-bootstrap/tree/main/presets/testnet/seed/00000) is copied over. - `-p testnet -a dual`: A [dual](https://github.com/nemtech/symbol-bootstrap/blob/main/presets/testnet/assembly-dual.yml) haversting peer node that connects to the current public [testnet](https://github.com/nemtech/symbol-bootstrap/blob/main/presets/testnet/network.yml) running its own mongo database and rest gateway. [Nemesis block](https://github.com/nemtech/symbol-bootstrap/tree/main/presets/testnet/seed/00000) is copied over. +- `-p mainnet -a peer`: A [harvesting](https://github.com/nemtech/symbol-bootstrap/blob/main/presets/mainnet/assembly-peer.yml) peer node that connects to the current public [mainnet](https://github.com/nemtech/symbol-bootstrap/blob/main/presets/mainnet/network.yml). [Nemesis block](https://github.com/nemtech/symbol-bootstrap/tree/main/presets/mainnet/seed/00000) is copied over. +- `-p mainnet -a api`: A [api](https://github.com/nemtech/symbol-bootstrap/blob/main/presets/mainnet/assembly-api.yml) peer node that connects to the current public [mainnet](https://github.com/nemtech/symbol-bootstrap/blob/main/presets/mainnet/network.yml) running its own mongo database and rest gateway. [Nemesis block](https://github.com/nemtech/symbol-bootstrap/tree/main/presets/mainnet/seed/00000) is copied over. +- `-p mainnet -a dual`: A [dual](https://github.com/nemtech/symbol-bootstrap/blob/main/presets/mainnet/assembly-dual.yml) haversting peer node that connects to the current public [mainnet](https://github.com/nemtech/symbol-bootstrap/blob/main/presets/mainnet/network.yml) running its own mongo database and rest gateway. [Nemesis block](https://github.com/nemtech/symbol-bootstrap/tree/main/presets/mainnet/seed/00000) is copied over. ### Custom preset: diff --git a/docs/clean.md b/docs/clean.md index 157659311..bb609ec11 100644 --- a/docs/clean.md +++ b/docs/clean.md @@ -17,8 +17,8 @@ OPTIONS -h, --help It shows the help of this command. -t, --target=target [default: target] The target folder where the symbol-bootstrap network is generated - --logger=logger [default: ConsoleLog,File] The loggers the command will use. Options are: - Console,ConsoleLog,File,Silent. Use ',' to select multiple loggers. + --logger=logger [default: Console,File] The loggers the command will use. Options are: Console,File,Silent. Use + ',' to select multiple loggers. EXAMPLE $ symbol-bootstrap clean diff --git a/docs/compose.md b/docs/compose.md index 659c863bd..4bfd9c23c 100644 --- a/docs/compose.md +++ b/docs/compose.md @@ -20,8 +20,8 @@ OPTIONS -u, --user=user [default: current] User used to run the services in the docker-compose.yml file. "current" means the current user. - --logger=logger [default: ConsoleLog,File] The loggers the command will use. Options are: - Console,ConsoleLog,File,Silent. Use ',' to select multiple loggers. + --logger=logger [default: Console,File] The loggers the command will use. Options are: Console,File,Silent. Use + ',' to select multiple loggers. --noPassword When provided, Bootstrap will not use a password, so private keys will be stored in plain text. Use with caution. diff --git a/docs/config.md b/docs/config.md index a1d00b825..1e6e4105b 100644 --- a/docs/config.md +++ b/docs/config.md @@ -14,17 +14,19 @@ USAGE $ symbol-bootstrap config OPTIONS - -a, --assembly=assembly The assembly, example "dual" for testnet. If not provided, the value is - resolved from the target/preset.yml file. + -a, --assembly=assembly The assembly that defines the node(s) layout. It can be provided via custom + preset or cli parameter. If not provided, the value is resolved from the + target/preset.yml file. - -c, --customPreset=customPreset External preset file. Values in this file will override the provided presets + -c, --customPreset=customPreset External preset file. Values in this file will override the provided + presets. -h, --help It shows the help of this command. - -p, --preset=(bootstrap|testnet|mainnet) The network preset, can be provided via custom preset or cli parameter. If - not provided, the value is resolved from the target/preset.yml file. + -p, --preset=(bootstrap|testnet|mainnet) The network preset. It can be provided via custom preset or cli parameter. + If not provided, the value is resolved from the target/preset.yml file. - -r, --reset It resets the configuration generating a new one + -r, --reset It resets the configuration generating a new one. -t, --target=target [default: target] The target folder where the symbol-bootstrap network is generated @@ -33,8 +35,8 @@ OPTIONS configuration files like certificates or nemesis block. "current" means the current user. - --logger=logger [default: ConsoleLog,File] The loggers the command will use. Options are: - Console,ConsoleLog,File,Silent. Use ',' to select multiple loggers. + --logger=logger [default: Console,File] The loggers the command will use. Options are: + Console,File,Silent. Use ',' to select multiple loggers. --noPassword When provided, Bootstrap will not use a password, so private keys will be stored in plain text. Use with caution. @@ -49,12 +51,12 @@ OPTIONS --upgrade It regenerates the configuration reusing the previous keys. Use this flag when upgrading the version of bootstrap to keep your node up to date without - dropping the local data. The original preset (-t), assembly (-a), and custom - preset (-a) must be used. Backup the target folder before upgrading. + dropping the local data. Backup the target folder before upgrading. EXAMPLES $ symbol-bootstrap config -p bootstrap $ symbol-bootstrap config -p testnet -a dual --password 1234 + $ symbol-bootstrap config -p mainnet -a peer -c custom-preset.yml $ echo "$MY_ENV_VAR_PASSWORD" | symbol-bootstrap config -p testnet -a dual ``` diff --git a/docs/decrypt.md b/docs/decrypt.md index 31de07693..54503aecf 100644 --- a/docs/decrypt.md +++ b/docs/decrypt.md @@ -19,8 +19,8 @@ OPTIONS -h, --help It shows the help of this command. --destination=destination (required) The destination decrypted file to create. The destination file must not exist. - --logger=logger [default: Console] The loggers the command will use. Options are: - Console,ConsoleLog,File,Silent. Use ',' to select multiple loggers. + --logger=logger [default: Console] The loggers the command will use. Options are: Console,File,Silent. Use + ',' to select multiple loggers. --password=password The password to use to decrypt the source file into the destination file. Bootstrap prompts for a password by default, can be provided in the command line (--password=XXXX) or diff --git a/docs/encrypt.md b/docs/encrypt.md index 771b64e64..9f070cdae 100644 --- a/docs/encrypt.md +++ b/docs/encrypt.md @@ -19,8 +19,8 @@ OPTIONS -h, --help It shows the help of this command. --destination=destination (required) The destination encrypted file to create. The destination file must not exist. - --logger=logger [default: Console] The loggers the command will use. Options are: - Console,ConsoleLog,File,Silent. Use ',' to select multiple loggers. + --logger=logger [default: Console] The loggers the command will use. Options are: Console,File,Silent. Use + ',' to select multiple loggers. --password=password The password to use to encrypt the source file into the destination file. Bootstrap prompts for a password by default, can be provided in the command line (--password=XXXX) or diff --git a/docs/healthCheck.md b/docs/healthCheck.md index d73d06e38..71eaddd0d 100644 --- a/docs/healthCheck.md +++ b/docs/healthCheck.md @@ -24,8 +24,8 @@ OPTIONS -h, --help It shows the help of this command. -t, --target=target [default: target] The target folder where the symbol-bootstrap network is generated - --logger=logger [default: ConsoleLog,File] The loggers the command will use. Options are: - Console,ConsoleLog,File,Silent. Use ',' to select multiple loggers. + --logger=logger [default: Console,File] The loggers the command will use. Options are: Console,File,Silent. Use + ',' to select multiple loggers. DESCRIPTION This command checks: diff --git a/docs/link.md b/docs/link.md index aa20124c3..c3eb23390 100644 --- a/docs/link.md +++ b/docs/link.md @@ -27,8 +27,7 @@ OPTIONS -u, --url=url [default: http://localhost:3000] the network url --logger=logger [default: Console] The loggers the command will use. Options are: - Console,ConsoleLog,File,Silent. Use ',' to select multiple - loggers. + Console,File,Silent. Use ',' to select multiple loggers. --maxFee=maxFee the max fee used when announcing (absolute). The node min multiplier will be used if it is not provided. diff --git a/docs/modifyMultisig.md b/docs/modifyMultisig.md index 102754dc1..1fb071356 100644 --- a/docs/modifyMultisig.md +++ b/docs/modifyMultisig.md @@ -41,8 +41,7 @@ OPTIONS -u, --url=url [default: http://localhost:3000] the network url --logger=logger [default: Console] The loggers the command will use. Options are: - Console,ConsoleLog,File,Silent. Use ',' to select multiple - loggers. + Console,File,Silent. Use ',' to select multiple loggers. --maxFee=maxFee the max fee used when announcing (absolute). The node min multiplier will be used if it is not provided. diff --git a/docs/pack.md b/docs/pack.md index fb1a2f568..92067b07b 100644 --- a/docs/pack.md +++ b/docs/pack.md @@ -14,17 +14,19 @@ USAGE $ symbol-bootstrap pack OPTIONS - -a, --assembly=assembly (required) The assembly, example "dual" for testnet. + -a, --assembly=assembly The assembly that defines the node(s) layout. It can be provided via custom + preset or cli parameter. If not provided, the value is resolved from the + target/preset.yml file. - -c, --customPreset=customPreset (required) External preset file. Values in this file will override the - provided presets + -c, --customPreset=customPreset External preset file. Values in this file will override the provided + presets. -h, --help It shows the help of this command. - -p, --preset=(bootstrap|testnet|mainnet) (required) The network preset, can be provided via custom preset or cli - parameter. + -p, --preset=(bootstrap|testnet|mainnet) The network preset. It can be provided via custom preset or cli parameter. + If not provided, the value is resolved from the target/preset.yml file. - -r, --reset It resets the configuration generating a new one + -r, --reset It resets the configuration generating a new one. -t, --target=target [default: target] The target folder where the symbol-bootstrap network is generated @@ -33,8 +35,8 @@ OPTIONS configuration files like certificates or nemesis block. "current" means the current user. - --logger=logger [default: ConsoleLog] The loggers the command will use. Options are: - Console,ConsoleLog,File,Silent. Use ',' to select multiple loggers. + --logger=logger [default: Console] The loggers the command will use. Options are: + Console,File,Silent. Use ',' to select multiple loggers. --noPassword When provided, Bootstrap will not use a password, so private keys will be stored in plain text. Use with caution. @@ -51,15 +53,14 @@ OPTIONS --upgrade It regenerates the configuration reusing the previous keys. Use this flag when upgrading the version of bootstrap to keep your node up to date without - dropping the local data. The original preset (-t), assembly (-a), and custom - preset (-a) must be used. Backup the target folder before upgrading. + dropping the local data. Backup the target folder before upgrading. EXAMPLES $ symbol-bootstrap pack - $ symbol-bootstrap pack -p bootstrap -c custom-preset.yml + $ symbol-bootstrap pack -c custom-preset.yml $ symbol-bootstrap pack -p testnet -a dual -c custom-preset.yml $ symbol-bootstrap pack -p mainnet -a dual --password 1234 -c custom-preset.yml - $ echo "$MY_ENV_VAR_PASSWORD" | symbol-bootstrap pack -p mainnet -a dual -c custom-preset.yml + $ echo "$MY_ENV_VAR_PASSWORD" | symbol-bootstrap pack -c custom-preset.yml ``` _See code: [src/commands/pack.ts](https://github.com/nemtech/symbol-bootstrap/blob/v1.1.2/src/commands/pack.ts)_ diff --git a/docs/report.md b/docs/report.md index af207b39e..976408274 100644 --- a/docs/report.md +++ b/docs/report.md @@ -17,8 +17,8 @@ OPTIONS -h, --help It shows the help of this command. -t, --target=target [default: target] The target folder where the symbol-bootstrap network is generated - --logger=logger [default: ConsoleLog,File] The loggers the command will use. Options are: - Console,ConsoleLog,File,Silent. Use ',' to select multiple loggers. + --logger=logger [default: Console,File] The loggers the command will use. Options are: Console,File,Silent. Use + ',' to select multiple loggers. EXAMPLE $ symbol-bootstrap report diff --git a/docs/resetData.md b/docs/resetData.md index 2a4b5b26a..4101a4998 100644 --- a/docs/resetData.md +++ b/docs/resetData.md @@ -17,8 +17,8 @@ OPTIONS -h, --help It shows the help of this command. -t, --target=target [default: target] The target folder where the symbol-bootstrap network is generated - --logger=logger [default: ConsoleLog,File] The loggers the command will use. Options are: - Console,ConsoleLog,File,Silent. Use ',' to select multiple loggers. + --logger=logger [default: Console,File] The loggers the command will use. Options are: Console,File,Silent. Use + ',' to select multiple loggers. EXAMPLE $ symbol-bootstrap resetData diff --git a/docs/run.md b/docs/run.md index 4a5ea4e73..7121caa39 100644 --- a/docs/run.md +++ b/docs/run.md @@ -41,8 +41,8 @@ OPTIONS The health check process handles 'repeat' and custom 'openPort' services. --logger=logger - [default: ConsoleLog,File] The loggers the command will use. Options are: Console,ConsoleLog,File,Silent. Use ',' to - select multiple loggers. + [default: Console,File] The loggers the command will use. Options are: Console,File,Silent. Use ',' to select + multiple loggers. --pullImages It pulls the images from DockerHub when running the configuration. It only affects alpha/dev docker images. diff --git a/docs/start.md b/docs/start.md index aad813a4e..5528847d9 100644 --- a/docs/start.md +++ b/docs/start.md @@ -15,13 +15,14 @@ USAGE OPTIONS -a, --assembly=assembly - The assembly, example "dual" for testnet. If not provided, the value is resolved from the target/preset.yml file. + The assembly that defines the node(s) layout. It can be provided via custom preset or cli parameter. If not + provided, the value is resolved from the target/preset.yml file. -b, --build If provided, docker-compose will run with -b (--build) -c, --customPreset=customPreset - External preset file. Values in this file will override the provided presets + External preset file. Values in this file will override the provided presets. -d, --detached If provided, docker-compose will run with -d (--detached) and this command will wait unit server is running before @@ -31,11 +32,11 @@ OPTIONS It shows the help of this command. -p, --preset=(bootstrap|testnet|mainnet) - The network preset, can be provided via custom preset or cli parameter. If not provided, the value is resolved from - the target/preset.yml file. + The network preset. It can be provided via custom preset or cli parameter. If not provided, the value is resolved + from the target/preset.yml file. -r, --reset - It resets the configuration generating a new one + It resets the configuration generating a new one. -t, --target=target [default: target] The target folder where the symbol-bootstrap network is generated @@ -58,8 +59,8 @@ OPTIONS The health check process handles 'repeat' and custom 'openPort' services. --logger=logger - [default: ConsoleLog,File] The loggers the command will use. Options are: Console,ConsoleLog,File,Silent. Use ',' to - select multiple loggers. + [default: Console,File] The loggers the command will use. Options are: Console,File,Silent. Use ',' to select + multiple loggers. --noPassword When provided, Bootstrap will not use a password, so private keys will be stored in plain text. Use with caution. @@ -83,13 +84,12 @@ OPTIONS --upgrade It regenerates the configuration reusing the previous keys. Use this flag when upgrading the version of bootstrap to - keep your node up to date without dropping the local data. The original preset (-t), assembly (-a), and custom - preset (-a) must be used. Backup the target folder before upgrading. + keep your node up to date without dropping the local data. Backup the target folder before upgrading. EXAMPLES - $ symbol-bootstrap start $ symbol-bootstrap start -p bootstrap $ symbol-bootstrap start -p testnet -a dual + $ symbol-bootstrap start -p mainnet -a peer -c custom-preset.yml $ symbol-bootstrap start -p testnet -a dual --password 1234 $ echo "$MY_ENV_VAR_PASSWORD" | symbol-bootstrap start -p testnet -a dual ``` diff --git a/docs/stop.md b/docs/stop.md index aa759cf0e..d130b73c9 100644 --- a/docs/stop.md +++ b/docs/stop.md @@ -17,8 +17,8 @@ OPTIONS -h, --help It shows the help of this command. -t, --target=target [default: target] The target folder where the symbol-bootstrap network is generated - --logger=logger [default: ConsoleLog,File] The loggers the command will use. Options are: - Console,ConsoleLog,File,Silent. Use ',' to select multiple loggers. + --logger=logger [default: Console,File] The loggers the command will use. Options are: Console,File,Silent. Use + ',' to select multiple loggers. EXAMPLE $ symbol-bootstrap stop diff --git a/docs/updateVotingKeys.md b/docs/updateVotingKeys.md index 7ef6b0d9b..79e46ee77 100644 --- a/docs/updateVotingKeys.md +++ b/docs/updateVotingKeys.md @@ -31,8 +31,8 @@ OPTIONS --finalizationEpoch=finalizationEpoch The network's finalization epoch. It can be retrieved from the /chain/info rest endpoint. If not provided, the bootstrap known epoch is used. - --logger=logger [default: ConsoleLog,File] The loggers the command will use. Options are: - Console,ConsoleLog,File,Silent. Use ',' to select multiple loggers. + --logger=logger [default: Console,File] The loggers the command will use. Options are: + Console,File,Silent. Use ',' to select multiple loggers. DESCRIPTION If the node's current voting file has an end epoch close to the current network epoch, this command will create a new diff --git a/docs/verify.md b/docs/verify.md index a15c5e621..3e442e3de 100644 --- a/docs/verify.md +++ b/docs/verify.md @@ -16,8 +16,8 @@ USAGE OPTIONS -h, --help It shows the help of this command. - --logger=logger [default: ConsoleLog,File] The loggers the command will use. Options are: - Console,ConsoleLog,File,Silent. Use ',' to select multiple loggers. + --logger=logger [default: Console,File] The loggers the command will use. Options are: Console,File,Silent. Use ',' + to select multiple loggers. EXAMPLE $ symbol-bootstrap verify diff --git a/docs/wizard.md b/docs/wizard.md index 860f17f2e..b86bb501b 100644 --- a/docs/wizard.md +++ b/docs/wizard.md @@ -21,7 +21,7 @@ OPTIONS generated --logger=logger [default: Console] The loggers the command will use. Options are: - Console,ConsoleLog,File,Silent. Use ',' to select multiple loggers. + Console,File,Silent. Use ',' to select multiple loggers. --network=mainnet|testnet|localNetwork The node or network you want to create diff --git a/src/commands/config.ts b/src/commands/config.ts index 43b96078a..1df1a3032 100644 --- a/src/commands/config.ts +++ b/src/commands/config.ts @@ -24,42 +24,36 @@ export default class Config extends Command { static examples = [ `$ symbol-bootstrap config -p bootstrap`, `$ symbol-bootstrap config -p testnet -a dual --password 1234`, + `$ symbol-bootstrap config -p mainnet -a peer -c custom-preset.yml`, `$ echo "$MY_ENV_VAR_PASSWORD" | symbol-bootstrap config -p testnet -a dual`, ]; - //@typescript-eslint/explicit-module-boundary-types - static resolveFlags = (required: boolean) => ({ + + static flags = { help: CommandUtils.helpFlag, target: CommandUtils.targetFlag, password: CommandUtils.passwordFlag, noPassword: CommandUtils.noPasswordFlag, preset: flags.enum({ char: 'p', - description: `The network preset, can be provided via custom preset or cli parameter. ${ - required ? '' : 'If not provided, the value is resolved from the target/preset.yml file.' - }`, + description: `The network preset. It can be provided via custom preset or cli parameter. If not provided, the value is resolved from the target/preset.yml file.`, options: Object.keys(Preset).map((v) => v as Preset), - required: required, }), assembly: flags.string({ char: 'a', - description: `The assembly, example "dual" for testnet. ${ - required ? '' : 'If not provided, the value is resolved from the target/preset.yml file.' - }`, - required: required, + description: `The assembly that defines the node(s) layout. It can be provided via custom preset or cli parameter. If not provided, the value is resolved from the target/preset.yml file.`, }), customPreset: flags.string({ char: 'c', - description: `External preset file. Values in this file will override the provided presets`, - required: required, + description: `External preset file. Values in this file will override the provided presets.`, }), reset: flags.boolean({ char: 'r', - description: 'It resets the configuration generating a new one', + description: 'It resets the configuration generating a new one.', default: ConfigService.defaultParams.reset, }), upgrade: flags.boolean({ - description: `It regenerates the configuration reusing the previous keys. Use this flag when upgrading the version of bootstrap to keep your node up to date without dropping the local data. The original preset (-t), assembly (-a), and custom preset (-a) must be used. Backup the target folder before upgrading.`, + description: `It regenerates the configuration reusing the previous keys. Use this flag when upgrading the version of bootstrap to keep your node up to date without dropping the local data. Backup the target folder before upgrading.`, default: ConfigService.defaultParams.reset, }), @@ -74,9 +68,7 @@ export default class Config extends Command { default: BootstrapUtils.CURRENT_USER, }), logger: CommandUtils.getLoggerFlag(...System), - }); - - static flags = Config.resolveFlags(false); + }; public async run(): Promise { const { flags } = this.parse(Config); diff --git a/src/commands/pack.ts b/src/commands/pack.ts index 7001d32e1..9be16060d 100644 --- a/src/commands/pack.ts +++ b/src/commands/pack.ts @@ -28,16 +28,16 @@ export default class Pack extends Command { static examples = [ `$ symbol-bootstrap pack`, - `$ symbol-bootstrap pack -p bootstrap -c custom-preset.yml`, + `$ symbol-bootstrap pack -c custom-preset.yml`, `$ symbol-bootstrap pack -p testnet -a dual -c custom-preset.yml`, `$ symbol-bootstrap pack -p mainnet -a dual --password 1234 -c custom-preset.yml`, - `$ echo "$MY_ENV_VAR_PASSWORD" | symbol-bootstrap pack -p mainnet -a dual -c custom-preset.yml`, + `$ echo "$MY_ENV_VAR_PASSWORD" | symbol-bootstrap pack -c custom-preset.yml`, ]; static flags = { ...Compose.flags, ...Clean.flags, - ...Config.resolveFlags(true), + ...Config.flags, ready: flags.boolean({ description: 'If --ready is provided, the command will not ask offline confirmation.', }), @@ -48,9 +48,7 @@ export default class Pack extends Command { const { flags } = this.parse(Pack); CommandUtils.showBanner(); const logger = LoggerFactory.getLogger(flags.logger); - const preset = flags.preset; - const assembly = flags.assembly; - const targetZip = join(dirname(flags.target), `${preset}-${assembly || 'default'}-node.zip`); + const targetZip = join(dirname(flags.target), `symbol-node.zip`); if (existsSync(targetZip)) { throw new Error( @@ -113,7 +111,7 @@ export default class Pack extends Command { ]; await new ZipUtils(logger).zip(targetZip, zipItems); - BootstrapUtils.deleteFile(noPrivateKeyTempFile); + await BootstrapUtils.deleteFile(noPrivateKeyTempFile); logger.info(''); logger.info(`Zip file ${targetZip} has been created. You can unzip it in your node's machine and run:`); logger.info(`$ symbol-bootstrap start`); diff --git a/src/commands/start.ts b/src/commands/start.ts index 4f6a590dc..a56628cc3 100644 --- a/src/commands/start.ts +++ b/src/commands/start.ts @@ -27,9 +27,9 @@ export default class Start extends Command { static description = 'Single command that aggregates config, compose and run in one line!'; static examples = [ - `$ symbol-bootstrap start`, `$ symbol-bootstrap start -p bootstrap`, `$ symbol-bootstrap start -p testnet -a dual`, + `$ symbol-bootstrap start -p mainnet -a peer -c custom-preset.yml`, `$ symbol-bootstrap start -p testnet -a dual --password 1234`, `$ echo "$MY_ENV_VAR_PASSWORD" | symbol-bootstrap start -p testnet -a dual`, ]; diff --git a/src/commands/updateVotingKeys.ts b/src/commands/updateVotingKeys.ts index 3812d1297..adf991f4e 100644 --- a/src/commands/updateVotingKeys.ts +++ b/src/commands/updateVotingKeys.ts @@ -15,7 +15,6 @@ */ import { Command, flags } from '@oclif/command'; -import { join } from 'path'; import { LoggerFactory, System } from '../logger'; import { ConfigPreset } from '../model'; import { BootstrapUtils, CommandUtils, ConfigLoader, CryptoUtils, RemoteNodeService, VotingService } from '../service'; @@ -55,16 +54,20 @@ When a new voting file is created, Bootstrap will advise running the \`link\` co const logger = LoggerFactory.getLogger(flags.logger); const configLoader = new ConfigLoader(logger); const addressesLocation = configLoader.getGeneratedAddressLocation(target); - const existingPreset = configLoader.loadExistingPresetData(target, password); - const preset = existingPreset.preset; - if (!preset) { - throw new Error(`Network preset could not be resolved!`); + let presetData: ConfigPreset; + try { + const oldPresetData = configLoader.loadExistingPresetData(target, password); + presetData = configLoader.createPresetData({ + password: password, + oldPresetData, + }); + } catch (e) { + throw new Error( + `Node's preset cannot be loaded. Have you provided the right --target? If you have, please rerun the 'config' command with --upgrade. Error: ${ + e.message || 'unknown' + }`, + ); } - // Adds new shared/network properties to the existing preset. This is for upgrades.. - const sharedPreset = BootstrapUtils.loadYaml(join(BootstrapUtils.ROOT_FOLDER, 'presets', 'shared.yml'), false); - const networkPreset = BootstrapUtils.loadYaml(join(BootstrapUtils.ROOT_FOLDER, 'presets', preset, 'network.yml'), false); - const presetData = configLoader.mergePresets(sharedPreset, networkPreset, existingPreset) as ConfigPreset; - const addresses = configLoader.loadExistingAddresses(target, password); const privateKeySecurityMode = CryptoUtils.getPrivateKeySecurityMode(presetData.privateKeySecurityMode); diff --git a/src/commands/wizard.ts b/src/commands/wizard.ts index 1810efbf0..c4b683c01 100644 --- a/src/commands/wizard.ts +++ b/src/commands/wizard.ts @@ -133,7 +133,7 @@ export class Wizard { if (network == Network.localNetwork) { this.logger.info('For a local network, just run: '); this.logger.info(''); - this.logger.info(`$ symbol-bootstrap start -b ${preset}${assembly ? ` -a ${assembly}` : ''}`); + this.logger.info(`$ symbol-bootstrap start -b ${preset} -a ${assembly}`); return; } @@ -277,20 +277,13 @@ export class Wizard { `Once you have finished the custom preset customization, You can use the 'start' to run the node in this machine:`, ); this.logger.info(''); - this.logger.info( - `$ symbol-bootstrap start -p ${network} -a ${assembly} -c ${customPresetFile} ${ - target !== defaultParams.target ? `-t ${target}` : '' - }`, - ); + const targetParam = target !== defaultParams.target ? `-t ${target}` : ''; + this.logger.info(`$ symbol-bootstrap start -c ${customPresetFile} ${targetParam}`); this.logger.info(''); this.logger.info(`Alternatively, to create a zip file that can be deployed in your node machine you can use the 'pack' command:`); this.logger.info(''); - this.logger.info( - `$ symbol-bootstrap pack -p ${network} -a ${assembly} -c ${customPresetFile} ${ - target !== defaultParams.target ? `-t ${target}` : '' - }`, - ); + this.logger.info(`$ symbol-bootstrap pack -c ${customPresetFile} ${targetParam}`); this.logger.info(''); this.logger.info( `Once the target folder is created, Bootstrap will use the protected and encrypted addresses.yml, and preset.yml in inside the target folder.`, diff --git a/src/model/ConfigPreset.ts b/src/model/ConfigPreset.ts index b3b2e827c..ca6cec646 100644 --- a/src/model/ConfigPreset.ts +++ b/src/model/ConfigPreset.ts @@ -449,6 +449,7 @@ export interface ConfigPreset extends CommonConfigPreset { wallets?: WalletPreset[]; faucets?: FaucetPreset[]; httpsProxies?: HttpsProxyPreset[]; + customPresetCache?: CustomPreset; } export interface CustomPreset extends Partial { diff --git a/src/service/ConfigLoader.ts b/src/service/ConfigLoader.ts index 3443c23c8..f4ebf74cc 100644 --- a/src/service/ConfigLoader.ts +++ b/src/service/ConfigLoader.ts @@ -23,7 +23,6 @@ import { ConfigAccount, ConfigPreset, CustomPreset, - DeepPartial, MosaicAccounts, NodeAccount, NodePreset, @@ -38,7 +37,11 @@ export class ConfigLoader { public static presetInfoLogged = false; constructor(private readonly logger: Logger) {} - public async generateRandomConfiguration(oldAddresses: Addresses | undefined, presetData: ConfigPreset): Promise { + public async generateRandomConfiguration( + oldAddresses: Addresses | undefined, + oldPresetData: ConfigPreset | undefined, + presetData: ConfigPreset, + ): Promise { const networkType = presetData.networkType; const addresses: Addresses = { version: this.getAddressesMigration(presetData.networkType).length + 1, @@ -122,8 +125,12 @@ export class ConfigLoader { if (presetData.nemesis) { if (oldAddresses) { + if (!oldPresetData) { + throw new Error('oldPresetData must be defined when upgrading!'); + } // Nemesis configuration cannot be changed on upgrade. addresses.mosaics = oldAddresses.mosaics; + presetData.nemesis = oldPresetData.nemesis; } else { if (presetData.nemesis.mosaics) { const mosaics: MosaicAccounts[] = []; @@ -363,19 +370,18 @@ export class ConfigLoader { return BootstrapUtils.loadYaml(fileLocation, false); } - public mergePresets(object: ConfigPreset, ...otherArgs: (CustomPreset | undefined)[]): any { - const presets: (CustomPreset | undefined)[] = [object, ...otherArgs]; - const reversed = _.reverse(presets); - const inflation = reversed.find((p) => p?.inflation)?.inflation || {}; - const knownRestGateways = reversed.find((p) => p?.knownRestGateways)?.knownRestGateways || []; - const knownPeers = reversed.find((p) => p?.knownPeers)?.knownPeers || []; - const presetData = _.merge(object, ...otherArgs); - presetData.inflation = inflation; - presetData.knownRestGateways = knownRestGateways; - presetData.knownPeers = knownPeers; + public mergePresets(object: T | undefined, ...otherArgs: (CustomPreset | undefined)[]): T { + const presets = [object, ...otherArgs]; + const reversed = [...presets].reverse(); + const presetData = _.merge({}, ...presets); + const inflation = reversed.find((p) => !_.isEmpty(p?.inflation))?.inflation; + const knownRestGateways = reversed.find((p) => !_.isEmpty(p?.knownRestGateways))?.knownRestGateways; + const knownPeers = reversed.find((p) => !_.isEmpty(p?.knownPeers))?.knownPeers; + if (inflation) presetData.inflation = inflation; + if (knownRestGateways) presetData.knownRestGateways = knownRestGateways; + if (knownPeers) presetData.knownPeers = knownPeers; return presetData; } - public createPresetData(params: { password: Password; preset?: Preset; @@ -388,13 +394,12 @@ export class ConfigLoader { const customPresetObject = params.customPresetObject; const oldPresetData = params.oldPresetData; const customPresetFileObject = this.loadCustomPreset(customPreset, params.password); - const preset = - params.preset || - params.customPresetObject?.preset || - customPresetFileObject?.preset || - oldPresetData?.preset || - Preset.bootstrap; - + const preset = params.preset || params.customPresetObject?.preset || customPresetFileObject?.preset || oldPresetData?.preset; + if (!preset) { + throw new KnownError( + 'Preset value could not be resolved from target folder contents. Please provide the --preset parameter when running the config/start command.', + ); + } const assembly = params.assembly || params.customPresetObject?.assembly || customPresetFileObject?.assembly || params.oldPresetData?.assembly; @@ -402,12 +407,15 @@ export class ConfigLoader { const networkPreset = BootstrapUtils.loadYaml(join(BootstrapUtils.ROOT_FOLDER, 'presets', preset, 'network.yml'), false); const assemblyPreset = this.loadAssembly(preset, assembly); - const presetData = this.mergePresets(sharedPreset, networkPreset, assemblyPreset, customPresetFileObject, customPresetObject, { - preset, - }); + const providedCustomPreset = this.mergePresets(customPresetFileObject, customPresetObject); + const resolvedCustomPreset = _.isEmpty(providedCustomPreset) ? oldPresetData?.customPresetCache || {} : providedCustomPreset; + + const presetData = this.mergePresets(sharedPreset, networkPreset, assemblyPreset, resolvedCustomPreset); if (presetData.assemblies && !assembly) { - throw new Error(`Preset ${preset} requires assembly (-a, --assembly option). Possible values are: ${presetData.assemblies}`); + throw new KnownError( + `Preset ${preset} requires assembly (-a, --assembly option). Possible values are: ${presetData.assemblies}. Please provide the --assembly parameter when running the config/start command.`, + ); } if (!ConfigLoader.presetInfoLogged) { this.logger.info(`Generating config from preset '${preset}'`); @@ -419,23 +427,24 @@ export class ConfigLoader { } } ConfigLoader.presetInfoLogged = true; - const presetDataWithDynamicDefaults = { + const presetDataWithDynamicDefaults: ConfigPreset = { + ...presetData, version: 1, preset: preset, assembly: assembly || '', - ...presetData, nodes: this.dynamicDefaultNodeConfiguration(presetData.nodes), + customPresetCache: resolvedCustomPreset, }; - return _.merge(oldPresetData || {}, this.expandRepeat(presetDataWithDynamicDefaults)); + return this.expandRepeat(presetDataWithDynamicDefaults); } - public dynamicDefaultNodeConfiguration(nodes?: NodePreset[]): NodePreset[] { + public dynamicDefaultNodeConfiguration(nodes?: Partial[]): NodePreset[] { return _.map(nodes || [], (node) => { - return { ...this.getDefaultConfiguration(node), ...node }; + return { ...this.getDefaultConfiguration(node), ...node } as NodePreset; }); } - private getDefaultConfiguration(node: NodePreset): DeepPartial { + private getDefaultConfiguration(node: Partial): Partial { if (node.harvesting && node.api) { return { syncsource: true, diff --git a/src/service/ConfigService.ts b/src/service/ConfigService.ts index 9012f90a2..d0af2c3cd 100644 --- a/src/service/ConfigService.ts +++ b/src/service/ConfigService.ts @@ -149,7 +149,7 @@ export class ConfigService { } const presetData: ConfigPreset = this.resolveCurrentPresetData(oldPresetData, password); - const addresses = await this.configLoader.generateRandomConfiguration(oldAddresses, presetData); + const addresses = await this.configLoader.generateRandomConfiguration(oldAddresses, oldPresetData, presetData); const privateKeySecurityMode = CryptoUtils.getPrivateKeySecurityMode(presetData.privateKeySecurityMode); await BootstrapUtils.mkdir(target); diff --git a/src/service/VotingService.ts b/src/service/VotingService.ts index ee86a62e2..43deddaf4 100644 --- a/src/service/VotingService.ts +++ b/src/service/VotingService.ts @@ -48,7 +48,9 @@ export class VotingService { const votingKeyDesiredFutureLifetime = presetData.votingKeyDesiredFutureLifetime; const votingKeyDesiredLifetime = presetData.votingKeyDesiredLifetime; if (votingKeyDesiredFutureLifetime > votingKeyDesiredLifetime) { - throw new Error('votingKeyDesiredFutureLifetime cannot be greater than votingKeyDesiredLifetime'); + throw new Error( + `votingKeyDesiredFutureLifetime (${votingKeyDesiredFutureLifetime}) cannot be greater than votingKeyDesiredLifetime (${votingKeyDesiredLifetime})`, + ); } await BootstrapUtils.mkdir(votingKeysFolder); const votingUtils = new VotingUtils(); diff --git a/test/commands/config.test.ts b/test/commands/config.test.ts index 3453dc3c7..f976da4c4 100644 --- a/test/commands/config.test.ts +++ b/test/commands/config.test.ts @@ -18,7 +18,7 @@ import { test } from '@oclif/test'; describe('config', () => { test.stdout() - .command(['config', '-r', '--password', '1111']) + .command(['config', '-p', 'bootstrap', '-r', '--password', '1111']) .it('runs config', (ctx) => { console.log(ctx.stdout); }); @@ -26,7 +26,7 @@ describe('config', () => { describe('config with opt in', () => { test.stdout() - .command(['config', '-r', '-c', './test/optin_preset.yml', '--noPassword']) + .command(['config', '-p', 'bootstrap', '-r', '-c', './test/optin_preset.yml', '--noPassword']) .it('runs config', (ctx) => { console.log(ctx.stdout); }); diff --git a/test/override-currency-preset.yml b/test/override-currency-preset.yml index b1a1fd5bc..a7621d3dd 100644 --- a/test/override-currency-preset.yml +++ b/test/override-currency-preset.yml @@ -1,3 +1,4 @@ +preset: bootstrap nemesis: mosaics: - accounts: 20 diff --git a/test/service/ConfigLoader.test.ts b/test/service/ConfigLoader.test.ts index 750aa6121..b848baa3b 100644 --- a/test/service/ConfigLoader.test.ts +++ b/test/service/ConfigLoader.test.ts @@ -44,7 +44,9 @@ describe('ConfigLoader', () => { password: 'abc', }); } catch (e) { - expect(e.message).to.equal('Preset testnet requires assembly (-a, --assembly option). Possible values are: api, dual, peer'); + expect(e.message).to.equal( + 'Preset testnet requires assembly (-a, --assembly option). Possible values are: api, dual, peer. Please provide the --assembly parameter when running the config/start command.', + ); return; } expect(true).to.be.false; @@ -62,6 +64,113 @@ describe('ConfigLoader', () => { expect(presetData).to.not.be.undefined; }); + it('ConfigLoader custom maxUnlockedAccounts', async () => { + const configLoader = new ConfigLoaderMocked(logger); + const originalPresetData = await configLoader.createPresetData({ + preset: Preset.testnet, + assembly: 'dual', + customPreset: 'test/unit-test-profiles/custom_preset.yml', + customPresetObject: { + maxUnlockedAccounts: 30, + }, + password: 'abcd', + }); + expect(originalPresetData).to.not.be.undefined; + expect(originalPresetData.nodes![0].maxUnlockedAccounts).eq(undefined); + expect(originalPresetData.maxUnlockedAccounts).eq(30); + expect(originalPresetData.customPresetCache).deep.eq({ + maxUnlockedAccounts: 30, + nodes: [ + { + host: 'my-host.io', + mainPrivateKey: 'CA82E7ADAF7AB729A5462A1BD5AA78632390634904A64EB1BB22295E2E1A1BDD', + remotePrivateKey: 'EFE3F0EF0AB368B8D7AC194D52A8CCFA2D5050B80B9C76E4D2F4D4BF2CD461C1', + transportPrivateKey: '6154154096354BC3DB522174ACD8BFE553893A0991BD5D105599846F17A3383B', + voting: true, + vrfPrivateKey: 'F3C24C153783B683E40FB2671493B54480370BF4E3AB8027D4BF1293E14EB9B8', + }, + ], + privateKeySecurityMode: 'PROMPT_MAIN', + }); + + const upgradedPresetData = await configLoader.createPresetData({ + oldPresetData: originalPresetData, + preset: Preset.testnet, + assembly: 'dual', + password: 'abcd', + }); + expect(upgradedPresetData).to.not.be.undefined; + expect(upgradedPresetData.nodes![0].maxUnlockedAccounts).eq(undefined); + expect(upgradedPresetData.maxUnlockedAccounts).eq(30); + expect(upgradedPresetData.customPresetCache).deep.eq({ + maxUnlockedAccounts: 30, + nodes: [ + { + host: 'my-host.io', + mainPrivateKey: 'CA82E7ADAF7AB729A5462A1BD5AA78632390634904A64EB1BB22295E2E1A1BDD', + remotePrivateKey: 'EFE3F0EF0AB368B8D7AC194D52A8CCFA2D5050B80B9C76E4D2F4D4BF2CD461C1', + transportPrivateKey: '6154154096354BC3DB522174ACD8BFE553893A0991BD5D105599846F17A3383B', + voting: true, + vrfPrivateKey: 'F3C24C153783B683E40FB2671493B54480370BF4E3AB8027D4BF1293E14EB9B8', + }, + ], + privateKeySecurityMode: 'PROMPT_MAIN', + }); + + const upgradedPresetResetToDefaults = await configLoader.createPresetData({ + oldPresetData: originalPresetData, + preset: Preset.testnet, + customPresetObject: { + maxUnlockedAccounts: 15, + }, + assembly: 'dual', + password: 'abcd', + }); + expect(upgradedPresetResetToDefaults).to.not.be.undefined; + expect(upgradedPresetResetToDefaults.nodes![0].maxUnlockedAccounts).eq(undefined); + expect(upgradedPresetResetToDefaults.maxUnlockedAccounts).eq(15); + expect(upgradedPresetResetToDefaults.customPresetCache).deep.eq({ + maxUnlockedAccounts: 15, + }); + }); + + it('mergePreset', async () => { + const configLoader = new ConfigLoaderMocked(logger); + expect( + configLoader.mergePresets( + { maxUnlockedAccounts: 1, inflation: { a: 1, c: 1, d: 1 } }, + { maxUnlockedAccounts: 2 }, + { maxUnlockedAccounts: 3, inflation: { c: 2, d: 2, e: 2 } }, + { maxUnlockedAccounts: 4 }, + ), + ).deep.eq({ maxUnlockedAccounts: 4, inflation: { c: 2, d: 2, e: 2 } }); + }); + + it('mergePreset with node', async () => { + const configLoader = new ConfigLoaderMocked(logger); + const merged = configLoader.mergePresets( + { + maxUnlockedAccounts: 1, + inflation: { a: 1, c: 1, d: 1 }, + }, + { nodes: [{ maxUnlockedAccounts: 5, name: 'name1' }], knownRestGateways: ['r1', 'r2'] }, + { maxUnlockedAccounts: 3, inflation: { c: 2, d: 2, e: 2 }, knownRestGateways: ['r2', 'r3'] }, + { + maxUnlockedAccounts: 4, + nodes: [{ maxUnlockedAccounts: 3 }, { maxUnlockedAccounts: 4, name: 'nameB' }], + }, + ); + expect(merged).deep.eq({ + maxUnlockedAccounts: 4, + inflation: { c: 2, d: 2, e: 2 }, + nodes: [ + { maxUnlockedAccounts: 3, name: 'name1' }, + { maxUnlockedAccounts: 4, name: 'nameB' }, + ], + knownRestGateways: ['r2', 'r3'], + }); + }); + it('ConfigLoader loadPresetData bootstrap custom', async () => { const configLoader = new ConfigLoaderMocked(logger); const presetData = await configLoader.createPresetData({ diff --git a/test/service/ConfigService.test.ts b/test/service/ConfigService.test.ts index dffd93815..5fd767bc2 100644 --- a/test/service/ConfigService.test.ts +++ b/test/service/ConfigService.test.ts @@ -20,16 +20,17 @@ import { LoggerFactory, LogType } from '../../src'; import { ConfigService, CryptoUtils, Preset } from '../../src/service'; const logger = LoggerFactory.getLogger(LogType.Silent); describe('ConfigService', () => { - it('ConfigService default run with optin_preset.yml', async () => { + it('ConfigService bootstrap run with optin_preset.yml', async () => { await new ConfigService(logger, { ...ConfigService.defaultParams, reset: true, + preset: Preset.bootstrap, target: 'target/tests/ConfigService.test.optin', customPreset: './test/optin_preset.yml', }).run(); }); - it('ConfigService default run with override-currency-preset.yml', async () => { + it('ConfigService bootstrap in custom preset run with override-currency-preset.yml', async () => { await new ConfigService(logger, { ...ConfigService.defaultParams, reset: true, @@ -62,16 +63,23 @@ describe('ConfigService', () => { const configResult = await new ConfigService(logger, { ...ConfigService.defaultParams, reset: true, + password: '1111', target: 'target/tests/bootstrap', preset: Preset.bootstrap, }).run(); + expect(configResult.addresses.mosaics?.length).eq(2); + expect(configResult.addresses.mosaics?.[0]?.accounts.length).eq(5); + expect(configResult.addresses.mosaics?.[1]?.accounts.length).eq(2); + const configResultUpgrade = await new ConfigService(logger, { ...ConfigService.defaultParams, upgrade: true, + password: '1111', target: 'target/tests/bootstrap', preset: Preset.bootstrap, }).run(); + expect(configResult.addresses).deep.eq(configResultUpgrade.addresses); expect(CryptoUtils.removePrivateKeys(configResultUpgrade.presetData)).deep.eq( CryptoUtils.removePrivateKeys(configResult.presetData), diff --git a/test/unit-test-profiles/custom_preset.yml b/test/unit-test-profiles/custom_preset.yml new file mode 100644 index 000000000..657309f1c --- /dev/null +++ b/test/unit-test-profiles/custom_preset.yml @@ -0,0 +1,8 @@ +privateKeySecurityMode: PROMPT_MAIN +nodes: + - voting: true + host: 'my-host.io' + mainPrivateKey: CA82E7ADAF7AB729A5462A1BD5AA78632390634904A64EB1BB22295E2E1A1BDD + transportPrivateKey: 6154154096354BC3DB522174ACD8BFE553893A0991BD5D105599846F17A3383B + remotePrivateKey: EFE3F0EF0AB368B8D7AC194D52A8CCFA2D5050B80B9C76E4D2F4D4BF2CD461C1 + vrfPrivateKey: F3C24C153783B683E40FB2671493B54480370BF4E3AB8027D4BF1293E14EB9B8