slightly less ghetto handling of .env files

This commit is contained in:
Jędrzej Stuczyński
2024-07-11 14:30:34 +01:00
parent 429ff6045d
commit bc647fc8e2
7 changed files with 192 additions and 81 deletions
@@ -3,6 +3,7 @@
use crate::cli::CommonArgs;
use crate::error::NetworkManagerError;
use crate::manager::env::Env;
use nym_bin_common::output_format::OutputFormat;
use std::path::PathBuf;
use std::time::Duration;
@@ -20,6 +21,7 @@ pub(crate) struct Args {
network_name: Option<String>,
/// Specifies custom duration of mixnet epochs
/// It's recommended to set it to rather low value (like 60s) if you intend to bond the mixnet afterward.
#[clap(long)]
custom_epoch_duration_secs: Option<u64>,
@@ -37,12 +39,11 @@ pub(crate) async fn execute(args: Args) -> Result<(), NetworkManagerError> {
args.network_name,
args.custom_epoch_duration_secs.map(Duration::from_secs),
)
.await?;
.await?
.into_loaded();
println!(
"add the following to your .env file: \n{}",
network.unchecked_to_env_file_section()
);
let env = Env::from(&network);
println!("add the following to your .env file: \n{env}",);
Ok(())
}
@@ -4,6 +4,7 @@
use crate::cli::CommonArgs;
use crate::error::NetworkManagerError;
use crate::helpers::default_storage_dir;
use crate::manager::env::Env;
use crate::manager::network::LoadedNetwork;
use nym_bin_common::output_format::OutputFormat;
use std::path::PathBuf;
@@ -34,6 +35,7 @@ pub(crate) struct Args {
bypass_dkg_contract: PathBuf,
/// Specifies custom duration of mixnet epochs
/// It's recommended to set it to rather low value (like 60s) if you intend to bond the mixnet afterward.
#[clap(long)]
custom_epoch_duration_secs: Option<u64>,
@@ -59,7 +61,7 @@ pub(crate) async fn execute(args: Args) -> Result<(), NetworkManagerError> {
default_storage_dir().join(&network.name)
};
let env = network.to_env_file_section();
let env = Env::from(&network);
manager
.attempt_bypass_dkg(
@@ -3,6 +3,7 @@
use crate::error::NetworkManagerError;
use crate::helpers::default_db_file;
use crate::manager::env::Env;
use crate::manager::NetworkManager;
use nym_bin_common::output_format::OutputFormat;
use std::path::PathBuf;
@@ -27,10 +28,8 @@ pub(crate) async fn execute(args: Args) -> Result<(), NetworkManagerError> {
.load_existing_network(args.network_name)
.await?;
println!(
"add the following to your .env file: \n{}",
network.to_env_file_section()
);
let env = Env::from(&network);
println!("add the following to your .env file: \n{env}",);
Ok(())
}
@@ -0,0 +1,173 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::error::NetworkManagerError;
use crate::manager::network::LoadedNetwork;
use nym_config::defaults::var_names;
use std::fmt::{Display, Formatter};
use std::fs;
use std::fs::File;
use std::io::Write;
use std::path::Path;
use tracing::{trace, warn};
#[derive(Default)]
pub struct Env {
pub(crate) mixnet_contract_address: Option<String>,
pub(crate) vesting_contract_address: Option<String>,
pub(crate) ecash_contract_address: Option<String>,
pub(crate) cw4_group_contract_address: Option<String>,
pub(crate) cw3_multisig_contract_address: Option<String>,
pub(crate) dkg_contract_address: Option<String>,
pub(crate) nyxd_endpoint: Option<String>,
pub(crate) nym_api_endpoint: Option<String>,
}
impl Env {
pub fn with_nym_api<S: Into<String>>(mut self, nym_api: S) -> Self {
self.nym_api_endpoint = Some(nym_api.into());
self
}
// this will be used eventually
#[allow(dead_code)]
pub fn try_load<P: AsRef<Path>>(path: P) -> Result<Self, NetworkManagerError> {
let mut env = Env::default();
let content = fs::read_to_string(path)?;
for entry in content.lines().map(|l| l.trim()).filter(|l| !l.is_empty()) {
let Some((k, v)) = entry.split_once('=') else {
warn!("malformed .env entry: '{entry}'");
continue;
};
match k {
var_names::CONFIGURED
| var_names::BECH32_PREFIX
| var_names::MIX_DENOM
| var_names::MIX_DENOM_DISPLAY
| var_names::STAKE_DENOM
| var_names::STAKE_DENOM_DISPLAY
| var_names::DENOMS_EXPONENT => {
trace!("ignoring values for {k} and using default instead")
}
var_names::MIXNET_CONTRACT_ADDRESS => {
env.mixnet_contract_address = Some(v.to_string())
}
var_names::VESTING_CONTRACT_ADDRESS => {
env.vesting_contract_address = Some(v.to_string())
}
var_names::ECASH_CONTRACT_ADDRESS => {
env.ecash_contract_address = Some(v.to_string())
}
var_names::GROUP_CONTRACT_ADDRESS => {
env.cw4_group_contract_address = Some(v.to_string())
}
var_names::MULTISIG_CONTRACT_ADDRESS => {
env.cw3_multisig_contract_address = Some(v.to_string())
}
var_names::COCONUT_DKG_CONTRACT_ADDRESS => {
env.dkg_contract_address = Some(v.to_string())
}
var_names::NYXD => env.nyxd_endpoint = Some(v.to_string()),
var_names::NYM_API => env.nym_api_endpoint = Some(v.to_string()),
other => warn!("unsupported .env entry: '{other}'"),
}
}
Ok(env)
}
pub fn save<P: AsRef<Path>>(&self, path: P) -> Result<(), NetworkManagerError> {
let path = path.as_ref();
if let Some(parent) = path.parent() {
fs::create_dir_all(parent)?;
}
let mut env_file = File::create(path)?;
let content = self.to_string();
env_file.write_all(content.as_bytes())?;
Ok(())
}
}
impl<'a> From<&'a LoadedNetwork> for Env {
fn from(network: &'a LoadedNetwork) -> Self {
Env {
mixnet_contract_address: Some(network.contracts.mixnet.address.to_string()),
vesting_contract_address: Some(network.contracts.vesting.address.to_string()),
ecash_contract_address: Some(network.contracts.ecash.address.to_string()),
cw4_group_contract_address: Some(network.contracts.cw4_group.address.to_string()),
cw3_multisig_contract_address: Some(network.contracts.cw3_multisig.address.to_string()),
dkg_contract_address: Some(network.contracts.dkg.address.to_string()),
nyxd_endpoint: Some(network.rpc_endpoint.to_string()),
nym_api_endpoint: None,
}
}
}
impl Display for Env {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"CONFIGURED=true\n\
\n\
BECH32_PREFIX=n\n\
MIX_DENOM=unym\n\
MIX_DENOM_DISPLAY=nym\n\
STAKE_DENOM=unyx\n\
STAKE_DENOM_DISPLAY=nyx\n\
DENOMS_EXPONENT=6\n\
\n\
"
)?;
if let Some(mixnet_contract_address) = &self.mixnet_contract_address {
writeln!(
f,
"{}={mixnet_contract_address}",
var_names::MIXNET_CONTRACT_ADDRESS
)?;
}
if let Some(vesting_contract_address) = &self.vesting_contract_address {
writeln!(
f,
"{}={vesting_contract_address}",
var_names::VESTING_CONTRACT_ADDRESS
)?;
}
if let Some(ecash_contract_address) = &self.ecash_contract_address {
writeln!(
f,
"{}={ecash_contract_address}",
var_names::ECASH_CONTRACT_ADDRESS
)?;
}
if let Some(cw4_group_contract_address) = &self.cw4_group_contract_address {
writeln!(
f,
"{}={cw4_group_contract_address}",
var_names::GROUP_CONTRACT_ADDRESS
)?;
}
if let Some(cw3_multisig_contract_address) = &self.cw3_multisig_contract_address {
writeln!(
f,
"{}={cw3_multisig_contract_address}",
var_names::MULTISIG_CONTRACT_ADDRESS
)?;
}
if let Some(dkg_contract_address) = &self.dkg_contract_address {
writeln!(
f,
"{}={dkg_contract_address}",
var_names::COCONUT_DKG_CONTRACT_ADDRESS
)?;
}
if let Some(nyxd_endpoint) = &self.nyxd_endpoint {
writeln!(f, "{}={nyxd_endpoint}", var_names::NYXD)?;
}
if let Some(nym_api_endpoint) = &self.nym_api_endpoint {
writeln!(f, "{}={nym_api_endpoint}", var_names::NYM_API)?;
}
Ok(())
}
}
@@ -4,6 +4,7 @@
use crate::error::NetworkManagerError;
use crate::helpers::{ProgressCtx, ProgressTracker, RunCommands};
use crate::manager::dkg_skip::EcashSignerWithPaths;
use crate::manager::env::Env;
use crate::manager::network::LoadedNetwork;
use crate::manager::NetworkManager;
use console::style;
@@ -11,8 +12,6 @@ use nym_config::{
must_get_home, DEFAULT_CONFIG_DIR, DEFAULT_CONFIG_FILENAME, DEFAULT_NYM_APIS_DIR, NYM_DIR,
};
use std::fs;
use std::fs::File;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::process::Stdio;
use tokio::process::Command;
@@ -183,21 +182,15 @@ impl NetworkManager {
ctx: &LocalApisCtx,
env_file: P,
) -> Result<(), NetworkManagerError> {
let base_env = ctx.network.to_env_file_section();
let updated_env = format!("{base_env}NYM_API={}", ctx.signers[0].data.endpoint);
let env_file_path = env_file.as_ref();
if let Some(parent) = env_file_path.parent() {
fs::create_dir_all(parent)?;
}
let env = Env::from(ctx.network).with_nym_api(ctx.signers[0].data.endpoint.as_ref());
let latest = self.default_latest_env_file_path();
if fs::read_link(&latest).is_ok() {
fs::remove_file(&latest)?;
}
let mut env_file = File::create(env_file_path)?;
env_file.write_all(updated_env.as_bytes())?;
let env_file_path = env_file.as_ref();
env.save(env_file_path)?;
// make symlink for usability purposes
std::os::unix::fs::symlink(env_file_path, &latest)?;
@@ -18,6 +18,7 @@ use zeroize::Zeroizing;
mod contract;
mod dkg_skip;
pub(crate) mod env;
mod local_apis;
mod local_client;
mod local_nodes;
@@ -27,35 +27,8 @@ pub struct Network {
}
impl Network {
pub fn unchecked_to_env_file_section(&self) -> String {
format!(
"CONFIGURED=true\n\
\n\
BECH32_PREFIX=n\n\
MIX_DENOM=unym\n\
MIX_DENOM_DISPLAY=nym\n\
STAKE_DENOM=unyx\n\
STAKE_DENOM_DISPLAY=nyx\n\
DENOMS_EXPONENT=6\n\
\n\
REWARDING_VALIDATOR_ADDRESS={}\n\
MIXNET_CONTRACT_ADDRESS={}\n\
VESTING_CONTRACT_ADDRESS={}\n\
ECASH_CONTRACT_ADDRESS={}\n\
GROUP_CONTRACT_ADDRESS={}\n\
MULTISIG_CONTRACT_ADDRESS={}\n\
COCONUT_DKG_CONTRACT_ADDRESS={}\n\
NYXD={}\n\
",
self.auxiliary_addresses.mixnet_rewarder.address,
self.contracts.mixnet.address().unwrap(),
self.contracts.vesting.address().unwrap(),
self.contracts.ecash.address().unwrap(),
self.contracts.cw4_group.address().unwrap(),
self.contracts.cw3_multisig.address().unwrap(),
self.contracts.dkg.address().unwrap(),
self.rpc_endpoint,
)
pub fn into_loaded(self) -> LoadedNetwork {
self.into()
}
}
@@ -151,37 +124,6 @@ impl LoadedNetwork {
self.contracts.cw4_group.admin_mnemonic.clone(),
)?)
}
pub fn to_env_file_section(&self) -> String {
format!(
"CONFIGURED=true\n\
\n\
BECH32_PREFIX=n\n\
MIX_DENOM=unym\n\
MIX_DENOM_DISPLAY=nym\n\
STAKE_DENOM=unyx\n\
STAKE_DENOM_DISPLAY=nyx\n\
DENOMS_EXPONENT=6\n\
\n\
REWARDING_VALIDATOR_ADDRESS={}\n\
MIXNET_CONTRACT_ADDRESS={}\n\
VESTING_CONTRACT_ADDRESS={}\n\
ECASH_CONTRACT_ADDRESS={}\n\
GROUP_CONTRACT_ADDRESS={}\n\
MULTISIG_CONTRACT_ADDRESS={}\n\
COCONUT_DKG_CONTRACT_ADDRESS={}\n\
NYXD={}\n\
",
self.auxiliary_addresses.mixnet_rewarder.address,
self.contracts.mixnet.address,
self.contracts.vesting.address,
self.contracts.ecash.address,
self.contracts.cw4_group.address,
self.contracts.cw3_multisig.address,
self.contracts.dkg.address,
self.rpc_endpoint,
)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]