diff --git a/CHANGELOG.md b/CHANGELOG.md index aa518fd645..7618400cb8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ ## Unreleased changes +- Add options `CONCORDIUM_NODE_VALIDATOR_CREDENTIALS_FILE` and + `CONCORDIUM_NODE_VALIDATOR_DECRYPT_CREDENTIALS` that alias + `CONCORDIUM_NODE_BAKER_CREDENTIALS_FILE` + `CONCORDIUM_NODE_BAKER_DECRYPT_CREDENTIALS`, respectively + The latter two options are still available, but hidden in the help text. +- Support `validatorId` in addition to `bakerId` in the credentials to start a validator. + ## 6.2.1 - The account map is now kept solely on disk in a separate lmdb database and it is no longer part of the internal block state database. diff --git a/VARIABLES.md b/VARIABLES.md index 866902486e..f746edd321 100644 --- a/VARIABLES.md +++ b/VARIABLES.md @@ -22,10 +22,10 @@ Then this should be set to the external port in order to allow other nodes to co - `CONCORDIUM_NODE_DATA_DIR` Where the node should store its data, in particular the nodes database is stored here. -## Baker -Configurations related to baking. +## Validator +Configurations related to running a validator. -- `CONCORDIUM_NODE_BAKER_CREDENTIALS_FILE` A path to the file containing the baker keys. The filepath must be either an absolute path or a relative filepath to the CWD of the process. If this variable is not set, then the node is not eligible for baking. +- `CONCORDIUM_NODE_VALIDATOR_CREDENTIALS_FILE` A path to the file containing the validator keys. The filepath must be either an absolute path or a relative filepath to the CWD of the process. If this variable is not set, then the node is not eligible for baking. ## Connection Network related configurations for a node. diff --git a/concordium-consensus/src/Concordium/Types/BakerIdentity.hs b/concordium-consensus/src/Concordium/Types/BakerIdentity.hs index 512d4ca835..835eddac31 100644 --- a/concordium-consensus/src/Concordium/Types/BakerIdentity.hs +++ b/concordium-consensus/src/Concordium/Types/BakerIdentity.hs @@ -3,7 +3,7 @@ module Concordium.Types.BakerIdentity where import Control.Monad -import Data.Aeson (FromJSON, parseJSON, withObject, (.:)) +import Data.Aeson (FromJSON, parseJSON, withObject, (.:), (.:?)) import qualified Concordium.Crypto.BlockSignature as Sig import qualified Concordium.Crypto.BlsSignature as BLS @@ -51,7 +51,16 @@ bakerElectionPublicKey ident = VRF.publicKey (bakerElectionKey ident) instance FromJSON BakerIdentity where parseJSON v = flip (withObject "Baker identity:") v $ \obj -> do - bakerId <- obj .: "bakerId" + maybeBakerId <- obj .:? "bakerId" + maybeValidatorId <- obj .:? "validatorId" + bakerId <- case (maybeBakerId, maybeValidatorId) of + (Nothing, Nothing) -> fail "Neither 'validatorId' nor 'bakerId' are specified." + (Just bid, Nothing) -> return bid + (Nothing, Just bid) -> return bid + (Just bid, Just vid) -> + if bid == vid + then return vid + else fail "'bakerId' and 'validatorId' are both specified, but different." bakerSignKey <- parseJSON v bakerElectionKey <- parseJSON v bakerAggregationKey <- obj .: "aggregationSignKey" diff --git a/concordium-node/src/configuration.rs b/concordium-node/src/configuration.rs index d8bec6c2b9..fb2c74690f 100644 --- a/concordium-node/src/configuration.rs +++ b/concordium-node/src/configuration.rs @@ -163,7 +163,14 @@ impl PrometheusConfig { } #[derive(StructOpt, Debug)] -// Parameters related to Baking (only used in cli). +/// Parameters related to Baking (only used in cli). +// +// This structure has a bit of redundancy. In particular it has duplicate +// options for specifying credentials. The reason for this is that Concordium +// underwent a renaming of "baker" to "validator". In order to streamline +// documentation the additional option using "validator" was added, but in order +// to keep backwards compatibility the existing options that use "baker" needed +// to remain. pub struct BakerConfig { #[cfg(feature = "profiling")] #[structopt( @@ -295,18 +302,34 @@ pub struct BakerConfig { pub account_cache_size: u32, #[structopt( long = "baker-credentials-file", + hidden = true, help = "Path to the baker credentials file. If the path is relative it is interpreted \ relative to the node process' working directory.", env = "CONCORDIUM_NODE_BAKER_CREDENTIALS_FILE" )] - pub baker_credentials_file: Option, + baker_credentials_file: Option, + #[structopt( + long = "validator-credentials-file", + help = "Path to the validator credentials file. If the path is relative it is interpreted \ + relative to the node process' working directory.", + env = "CONCORDIUM_NODE_VALIDATOR_CREDENTIALS_FILE" + )] + validator_credentials_file: Option, #[structopt( long = "decrypt-baker-credentials", + hidden = true, help = "Indicate that the baker credentials are provided encrypted and thus need to be \ decrypted.", env = "CONCORDIUM_NODE_BAKER_DECRYPT_CREDENTIALS" )] - pub decrypt_baker_credentials: bool, + decrypt_baker_credentials: bool, + #[structopt( + long = "decrypt-validator-credentials", + help = "Indicate that the validator credentials are provided encrypted and thus need to \ + be decrypted.", + env = "CONCORDIUM_NODE_VALIDATOR_DECRYPT_CREDENTIALS" + )] + decrypt_validator_credentials: bool, #[structopt( long = "modules-cache-size", help = "The maximum number of smart contract modules that can be stored in the module \ @@ -317,6 +340,56 @@ pub struct BakerConfig { pub modules_cache_size: u32, } +impl BakerConfig { + fn decrypt_credentials(&self) -> bool { + self.decrypt_baker_credentials || self.decrypt_validator_credentials + } + + /// If the [`BakerConfig`] specifies that baker credentials should be read + /// then attempt to read them, returning an `Err` if this is not + /// possible. + /// + /// If the configuration does not specify baker credentials return + /// `Ok(None)`. + pub fn read_baker_credentials(&self) -> anyhow::Result>> { + let path = match ( + self.baker_credentials_file.as_ref(), + self.validator_credentials_file.as_ref(), + ) { + (None, None) => return Ok(None), + (Some(bcred), Some(vcred)) => { + anyhow::ensure!( + bcred == vcred, + "Both --baker-credentials-file and --validator-credentials-file are supplied, \ + and different." + ); + bcred + } + (Some(cred), None) => cred, + (None, Some(cred)) => cred, + }; + let read_data = match std::fs::read(path) { + Ok(read_data) => read_data, + Err(e) => anyhow::bail!("Cannot open the validator credentials file ({})!", e), + }; + if self.decrypt_credentials() { + let et = serde_json::from_slice(&read_data)?; + let pass = rpassword::read_password_from_tty(Some( + "Enter password to decrypt baker credentials: ", + ))?; + match concordium_base::common::encryption::decrypt(&pass.into(), &et) { + Ok(d) => Ok(Some(d)), + Err(_) => anyhow::bail!( + "Could not decrypt validator credentials. Most likely the password you \ + provided is incorrect." + ), + } + } else { + Ok(Some(read_data)) + } + } +} + #[derive(StructOpt, Debug)] /// Parameters related to the V2 GRPC interface. pub struct GRPC2Config { diff --git a/concordium-node/src/plugins/consensus.rs b/concordium-node/src/plugins/consensus.rs index aa5968455e..6b3890518b 100644 --- a/concordium-node/src/plugins/consensus.rs +++ b/concordium-node/src/plugins/consensus.rs @@ -96,29 +96,7 @@ pub fn get_baker_data( Err(e) => bail!("Cannot open the genesis file ({})", e), }; - let private_data = if let Some(path) = &conf.baker_credentials_file { - let read_data = match std::fs::read(path) { - Ok(read_data) => read_data, - Err(e) => bail!("Cannot open the baker credentials file ({})!", e), - }; - if conf.decrypt_baker_credentials { - let et = serde_json::from_slice(&read_data)?; - let pass = rpassword::read_password_from_tty(Some( - "Enter password to decrypt baker credentials: ", - ))?; - match concordium_base::common::encryption::decrypt(&pass.into(), &et) { - Ok(d) => Some(d), - Err(_) => bail!( - "Could not decrypt baker credentials. Most likely the password you provided \ - is incorrect." - ), - } - } else { - Some(read_data) - } - } else { - None - }; + let private_data = conf.read_baker_credentials()?; Ok((genesis_data, private_data)) } diff --git a/scripts/distribution/macOS-package/README.md b/scripts/distribution/macOS-package/README.md index 50968e54fe..dbe7bc2731 100644 --- a/scripts/distribution/macOS-package/README.md +++ b/scripts/distribution/macOS-package/README.md @@ -156,8 +156,8 @@ The build script goes through the following major steps: EnviromentVariables section: ``` - CONCORDIUM_NODE_BAKER_CREDENTIALS_FILE - /Library/Application Support/Concordium Node/Mainnet/Config/baker-credentials.json + CONCORDIUM_NODE_VALIDATOR_CREDENTIALS_FILE + /Library/Application Support/Concordium Node/Mainnet/Config/validator-credentials.json ``` 2. Restart the given node by using the stop/start shortcuts. diff --git a/scripts/distribution/ubuntu-packages/README.md b/scripts/distribution/ubuntu-packages/README.md index 62630da1ec..940449d13c 100644 --- a/scripts/distribution/ubuntu-packages/README.md +++ b/scripts/distribution/ubuntu-packages/README.md @@ -192,17 +192,17 @@ which will set the environment variable `CONCORDIUM_NODE_LISTEN_PORT` to `8888` The node supports the following environment variables. -- `CONCORDIUM_NODE_BAKER_CREDENTIALS_FILE` the file with baker keys. - If it is set then the node will start as a baker, or at least attempt to. +- `CONCORDIUM_NODE_VALIDATOR_CREDENTIALS_FILE` the file with validator keys. + If it is set then the node will start as a validator, or at least attempt to. This must be a path relative to the `WorkingDirectory` or an absolute path. Since the node is sandboxed it does not have access to the `/home` directory and some other parts of the system. - The recommended way to expose the baker keys to the node is to use the + The recommended way to expose the validator keys to the node is to use the `BindReadOnlyPaths` option to remap the file from wherever it is on the host - system to a location which the node can read. For example (this assumes the baker keys are located in `/home/user/baker-credentials.json` on the host system) + system to a location which the node can read. For example (this assumes the validator keys are located in `/home/user/validator-credentials.json` on the host system) ``` - Environment=CONCORDIUM_NODE_BAKER_CREDENTIALS_FILE=%S/concordium-${build_genesis_hash}/baker-credentials.json - BindReadOnlyPaths=/home/user/baker-credentials.json:%S/concordium-${build_genesis_hash}/baker-credentials.json + Environment=CONCORDIUM_NODE_VALIDATOR_CREDENTIALS_FILE=%S/concordium-${build_genesis_hash}/validator-credentials.json + BindReadOnlyPaths=/home/user/validator-credentials.json:%S/concordium-${build_genesis_hash}/validator-credentials.json ``` diff --git a/service/windows/Configuration.md b/service/windows/Configuration.md index 65272be567..d0352f9fd4 100644 --- a/service/windows/Configuration.md +++ b/service/windows/Configuration.md @@ -52,11 +52,12 @@ data_dir = 'C:\ProgramData\Concordium\Node Runner\mainnet\data' The path to the data directory for the node, where the node's databases and the genesis data are stored. This must be a folder on your system, and must contain the genesis data file `genesis.dat`, or else the node will fail to start. -### **baker_credentials** (string; optional) +### **validator_credentials** (string; optional) ``` -baker_credentials = 'baker-credentials.json' +validator_credentials = 'validator-credentials.json' ``` -The path to a baker credentials file if the node is to run as a baker. +The path to a validator credentials file if the node is to run as a validator. +The legacy option `baker_credentials` is an alias of this option. ### **listen.port** (integer; optional) ``` diff --git a/service/windows/src/config.rs b/service/windows/src/config.rs index 3293316023..259f96f32d 100644 --- a/service/windows/src/config.rs +++ b/service/windows/src/config.rs @@ -154,6 +154,25 @@ fn load_config_file(conf_str: &str, conf_root: &Path) -> anyhow::Result ); let baker_credentials = toml_get_as!(as_str, &node, "baker_credentials").map(make_relative_path); + let validator_credentials = + toml_get_as!(as_str, &node, "validator_credentials").map(make_relative_path); + // In order to support legacy configuration files we support both + // baker_credentials and validator_credentials. + // We allow both, but to prevent errors we mandate that if both options are + // supplied they are consistent. + let baker_credentials = match (baker_credentials, validator_credentials) { + (Some(bcred), Some(vcred)) => { + anyhow::ensure!( + bcred == vcred, + "Both `baker_credentials` and `validator_credentials` are specified, and \ + different." + ); + Some(bcred) + } + (baker_credentials, validator_credentials) => { + baker_credentials.or(validator_credentials) + } + }; let log_config = if let Some(config) = toml_get_as!(as_str, &node, "log", "config") { LoggerConfig::Config(make_relative_path(config)) } else if let Some(log_path) = toml_get_as!(as_str, &node, "log", "path") { diff --git a/service/windows/src/node.rs b/service/windows/src/node.rs index 3a138be46d..56eacbf426 100644 --- a/service/windows/src/node.rs +++ b/service/windows/src/node.rs @@ -212,7 +212,7 @@ impl NodeConfig { cmd.env("CONCORDIUM_NODE_CONNECTION_BOOTSTRAP_NODES", self.bootstrap_nodes.clone()); self.baker_credentials .as_ref() - .map(|bcred| cmd.env("CONCORDIUM_NODE_BAKER_CREDENTIALS_FILE", bcred.clone())); + .map(|bcred| cmd.env("CONCORDIUM_NODE_VALIDATOR_CREDENTIALS_FILE", bcred.clone())); self.grpc2_address .as_ref() .map(|rpcaddr| cmd.env("CONCORDIUM_NODE_GRPC2_LISTEN_ADDRESS", rpcaddr.to_string()));