use super::networks::Network;
use std::{
fmt::{self, Display},
path::Path,
};
pub const KMS_CONFIG_HEADER: &str = "# Tendermint KMS configuration file";
pub struct ConfigBuilder {
kms_home: String,
networks: Vec<Network>,
contents: String,
}
impl ConfigBuilder {
pub fn new(kms_home: impl AsRef<Path>, networks: &[Network]) -> Self {
let mut result = Self {
kms_home: kms_home.as_ref().display().to_string(),
networks: networks.to_vec(),
contents: String::new(),
};
result.add_str(KMS_CONFIG_HEADER);
result.add_str("\n\n");
result
}
pub fn generate(mut self) -> String {
self.add_chain_config();
self.add_provider_config();
self.add_validator_config();
self.contents
}
fn add_section_comment(&mut self, section: &str) {
self.add_str(format!("## {section}\n\n"));
}
fn add_chain_config(&mut self) {
self.add_section_comment("Chain Configuration");
for network in &self.networks.clone() {
self.add_template(match network {
Network::CosmosHub => include_str!("templates/networks/cosmoshub.toml"),
Network::IrisHub => include_str!("templates/networks/irishub.toml"),
Network::SentinelHub => include_str!("templates/networks/sentinelhub.toml"),
Network::Osmosis => include_str!("templates/networks/osmosis.toml"),
Network::Persistence => include_str!("templates/networks/persistence.toml"),
});
}
}
fn add_provider_config(&mut self) {
self.add_section_comment("Signing Provider Configuration");
#[cfg(feature = "yubihsm")]
self.add_yubihsm_provider_config();
#[cfg(feature = "ledger")]
self.add_ledgertm_provider_config();
#[cfg(feature = "softsign")]
self.add_softsign_provider_config();
#[cfg(feature = "fortanixdsm")]
self.add_fortanixdsm_provider_config();
}
fn add_validator_config(&mut self) {
self.add_section_comment("Validator Configuration");
self.add_template_with_chain_id(include_str!("templates/validator.toml"));
}
#[cfg(feature = "yubihsm")]
fn add_yubihsm_provider_config(&mut self) {
self.add_str("### YubiHSM2 Provider Configuration\n\n");
self.add_str(format_template(
include_str!("templates/keyring/yubihsm.toml"),
&[("$KMS_HOME", self.kms_home.as_ref())],
));
self.add_str("\nkeys = [\n");
let mut key_id = 1;
let key_types = ["consensus"];
for network in self.networks.clone() {
for key_type in key_types {
self.add_str(format!(
" {{ key = {}, type = \"{}\", chain_ids = [\"{}\"] }}, \n",
key_id,
key_type,
network.chain_id(),
));
key_id += 1;
}
}
self.add_str("]\n");
#[cfg(feature = "yubihsm-server")]
self.add_str(include_str!("templates/keyring/yubihsm_server.toml"));
self.add_str("\n");
}
#[cfg(feature = "ledger")]
fn add_ledgertm_provider_config(&mut self) {
self.add_str("### Ledger Provider Configuration\n\n");
self.add_template_with_chain_id(include_str!("templates/keyring/ledgertm.toml"));
}
#[cfg(feature = "softsign")]
fn add_softsign_provider_config(&mut self) {
self.add_str("### Software-based Signer Configuration\n\n");
self.add_template_with_chain_id(include_str!("templates/keyring/softsign_consensus.toml"));
}
#[cfg(feature = "fortanixdsm")]
fn add_fortanixdsm_provider_config(&mut self) {
self.add_str("### Fortanix DSM Signer Configuration\n\n");
self.add_template_with_chain_id(include_str!("templates/keyring/fortanixdsm.toml"));
}
fn add_template(&mut self, template: &str) {
self.add_str(format_template(
template,
&[("$KMS_HOME", self.kms_home.as_ref())],
));
self.add_str("\n\n");
}
fn add_template_with_chain_id(&mut self, template: &str) {
for network in self.networks.clone() {
self.add_str(format_template(
template,
&[
("$KMS_HOME", self.kms_home.as_ref()),
("$CHAIN_ID", network.chain_id()),
],
));
self.add_str("\n\n");
}
}
fn add_str(&mut self, str: impl AsRef<str>) {
self.contents.push_str(str.as_ref())
}
}
impl Display for ConfigBuilder {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.contents)
}
}
fn format_template(template: &str, substitutions: &[(&str, &str)]) -> String {
substitutions.iter().fold(
template.trim_end().to_owned(),
|string, (name, replacement)| string.replace(name, replacement),
)
}