Skip to content

Commit

Permalink
ux fixes (#8)
Browse files Browse the repository at this point in the history
* fix: UX
  • Loading branch information
apoorvsadana authored Jan 9, 2024
1 parent 2dd4694 commit 223f537
Show file tree
Hide file tree
Showing 11 changed files with 167 additions and 78 deletions.
21 changes: 16 additions & 5 deletions src/cli/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ pub fn init() {
panic!("Failed to write config: {}", err);
}
};
// fund_msg(&config.da_layer);

log::info!("\n");
log::info!("✅ New app chain initialised.");
}

Expand All @@ -50,21 +51,31 @@ fn generate_config() -> Result<AppChainConfig, InitError> {
let binding = app_chains_home.join(format!("{}/data", app_chain));
let default_base_path = binding.to_str().unwrap_or("madara-data");

let base_path = get_text_input("Enter base path for data directory of your app chain:", Some(default_base_path))?;
let mode = get_option("Select mode for your app chain:", RollupMode::iter().collect::<Vec<_>>())?;
let da_layer = get_option("Select DA layer for your app chain:", DALayer::iter().collect::<Vec<_>>())?;
let madara_version = get_latest_commit_hash(MADARA_REPO_ORG, MADARA_REPO_NAME)?;
let config_version = ConfigVersion::Version1;

match DAFactory::new_da(&da_layer).setup_and_generate_keypair(&app_chain) {
log::info!("\n");

let config = AppChainConfig {
app_chain,
base_path: default_base_path.to_string(),
mode,
da_layer: da_layer.clone(),
madara_version,
config_version,
};

match DAFactory::new_da(&da_layer).setup_and_generate_keypair(&config) {
Ok(_) => (),
Err(err) => {
log::error!("Failed to generate keypair: {}", err);
return Err(InitError::FailedToGenerateKeypair);
}
};

Ok(AppChainConfig { app_chain, base_path, mode, da_layer, madara_version, config_version })
Ok(config)
}

fn write_config(config: &AppChainConfig) -> Result<(), InitError> {
Expand All @@ -74,7 +85,7 @@ fn write_config(config: &AppChainConfig) -> Result<(), InitError> {
if let Err(err) = fs::write(file_path, toml) {
panic!("Error writing to file: {}", err);
} else {
log::info!("Config file saved!");
log::debug!("Config file saved!");
}

Ok(())
Expand Down
21 changes: 19 additions & 2 deletions src/cli/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ use thiserror::Error;

use crate::cli::list::get_apps_list;
use crate::cli::prompt::get_option;
use crate::da::da_layers::{DAFactory, DaError};
use crate::utils::errors::MadaraError;
use crate::utils::madara;
use crate::utils::toml::regenerate_app_config;

#[derive(Debug, Error)]
pub enum RunError {
Expand All @@ -14,14 +16,18 @@ pub enum RunError {
FailedToStartMadara(#[from] MadaraError),
#[error("Failed to get app chains: {0}")]
FailedToGetAppChains(#[from] std::io::Error),
#[error("Failed to regenerate config: {0}")]
FailedToRegenerateConfig(String),
#[error("Failed with DA error: {0}")]
FailedWithDaError(#[from] DaError),
}
pub fn run() {
match start_app_chain() {
Ok(_) => {
log::info!("Madara setup successful");
}
Err(err) => {
log::error!("Failed to setup Madara: {:?}", err);
log::error!("Failed to setup Madara: {}", err);
}
}
}
Expand All @@ -31,8 +37,19 @@ fn start_app_chain() -> Result<(), RunError> {
let app = get_option("Select the app chain:", app_chains_list)?;
let app_chain: &str = &app;

let (config, _) = match regenerate_app_config(app_chain) {
Ok((config, valid)) => (config, valid),
Err(err) => {
log::error!("Failed to fetch the required app chain: {}", err);
return Err(RunError::FailedToRegenerateConfig(app_chain.to_string()));
}
};

madara::clone_madara_and_build_repo()?;
madara::setup_and_run_madara(app_chain)?;

DAFactory::new_da(&config.da_layer).confirm_minimum_balance(&config)?;

madara::setup_and_run_madara(config)?;

Ok(())
}
91 changes: 65 additions & 26 deletions src/da/avail.rs
Original file line number Diff line number Diff line change
@@ -1,54 +1,93 @@
use std::fs;

use crate::app::config::AppChainConfig;
use crate::cli::prompt::get_boolean_input;
use hex::encode;
use serde_json::json;
use serde::{Deserialize, Serialize};
use sp_core::{sr25519, Pair};
use thiserror::Error;

use crate::da::da_layers::DaConfig;
use crate::da::errors::KeyGenError;
use crate::utils::constants::{APP_DA_CONFIG_NAME, APP_SECRET_PHRASE};
use crate::utils::paths::get_app_home;
use crate::da::da_layers::{DaClient, DaError};

pub struct AvailConfig {}
pub struct AvailClient;

impl DaConfig for AvailConfig {
fn setup_and_generate_keypair(&self, app_chain: &str) -> Result<(), KeyGenError> {
let file_path = get_app_home(app_chain)?.join(APP_SECRET_PHRASE);
#[derive(Debug, Serialize, Deserialize)]
pub struct AvailConfig {
pub ws_provider: String,
pub mode: String,
pub seed: String,
pub app_id: u32,
pub address: String,
}

#[derive(Error, Debug)]
pub enum AvailError {
#[error("Failed to serialize config: {0}")]
FailedToSerializeConfig(#[from] serde_json::Error),
#[error("Faucet funds needed for DA to be submitted")]
FaucetFundsNeeded,
}

const AVAIL_DOCS: &str = "https://docs.availproject.org/about/faucet/";

impl DaClient for AvailClient {
fn setup_and_generate_keypair(&self, config: &AppChainConfig) -> Result<(), DaError> {
let file_path = self.get_da_config_path(config)?;
let file_path_str = file_path.to_string_lossy().to_string();
let (pair, phrase, seed) = <sr25519::Pair as Pair>::generate_with_phrase(None);
let seed_str = format!("0x{}", encode(seed.as_ref()));

if let Err(err) = fs::write(file_path, phrase) {
panic!("Error writing to file: {}", err);
} else {
log::info!("Secret phrase stored in app home: {}", file_path_str);
log::info!("🔑 Secret phrase stored in app home: {}", file_path_str);
log::info!("💧 Avail address: {}", pair.public());
log::info!(
"Please fund {} with atleast 1 AVL (https://docs.availproject.org/about/faucet/)",
pair.public()
);
"=> Please fund your Avail address to be able to submit blobs to the goldberg network. Docs: {}",
AVAIL_DOCS
)
}

generate_config(app_chain, &seed_str)?;
generate_config(file_path_str.as_str(), &seed_str, pair.public().to_string().as_str())?;

Ok(())
}
}

fn generate_config(app_chain: &str, seed: &str) -> Result<(), KeyGenError> {
let file_path = get_app_home(app_chain)?.join(APP_DA_CONFIG_NAME);
fn confirm_minimum_balance(&self, config: &AppChainConfig) -> Result<(), DaError> {
let avail_config_path = self.get_da_config_path(config)?;
let avail_config: AvailConfig = serde_json::from_str(
fs::read_to_string(avail_config_path).map_err(DaError::FailedToReadDaConfigFile)?.as_str(),
)
.map_err(DaError::FailedToDeserializeDaConfig)?;
match get_boolean_input(
format!(
"Have you funded your Avail address {} using the faucet? Docs: {}",
avail_config.address, AVAIL_DOCS
)
.as_str(),
Some(true),
)? {
true => Ok(()),
false => Err(DaError::AvailError(AvailError::FaucetFundsNeeded)),
}
}
}

let avail_config = json! ({
"ws_provider": "wss://goldberg.avail.tools:443/ws",
"mode": "sovereign",
"seed": seed,
"app_id": 0,
})
.to_string();
fn generate_config(da_config_path: &str, seed: &str, address: &str) -> Result<(), DaError> {
let avail_config = AvailConfig {
ws_provider: "wss://goldberg.avail.tools:443/ws".to_string(),
mode: "sovereign".to_string(),
seed: seed.to_string(),
app_id: 0,
address: address.to_string(),
};

if let Err(err) = fs::write(file_path, avail_config) {
if let Err(err) =
fs::write(da_config_path, serde_json::to_string(&avail_config).map_err(DaError::FailedToSerializeDaConfig)?)
{
panic!("Error writing to file: {}", err);
} else {
log::info!("Successfully generated Avail config!");
log::debug!("Successfully generated Avail config!");
}

Ok(())
Expand Down
44 changes: 35 additions & 9 deletions src/da/da_layers.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,54 @@
use std::io;
use std::path::PathBuf;

use serde::{Deserialize, Serialize};
use strum_macros::{Display, EnumIter};
use thiserror::Error;

use crate::da::avail::AvailConfig;
use crate::da::errors::KeyGenError;
use crate::app::config::AppChainConfig;
use crate::da::avail::{AvailClient, AvailError};
use crate::da::no_da::NoDAConfig;
use crate::utils::constants::APP_DA_CONFIG_NAME;
use crate::utils::paths::get_app_home;

#[derive(Debug, Serialize, Deserialize, EnumIter, Display)]
#[derive(Debug, Serialize, Deserialize, EnumIter, Display, Clone)]
pub enum DALayer {
Avail,
Celestia,
Ethereum,
NoDA,
}

pub trait DaConfig {
fn setup_and_generate_keypair(&self, app_chain: &str) -> Result<(), KeyGenError>;
#[derive(Error, Debug)]
pub enum DaError {
#[error("avail error: {0}")]
AvailError(#[from] AvailError),
#[error("failed to read app home: {0}")]
FailedToReadAppHome(io::Error),
#[error("inquire error")]
InquireError(#[from] inquire::InquireError),
#[error("Failed to read DA config file")]
FailedToReadDaConfigFile(io::Error),
#[error("Failed to deserialize config")]
FailedToDeserializeDaConfig(serde_json::Error),
#[error("Failed to serialize config")]
FailedToSerializeDaConfig(serde_json::Error),
}

pub trait DaClient {
fn setup_and_generate_keypair(&self, config: &AppChainConfig) -> Result<(), DaError>;

fn confirm_minimum_balance(&self, config: &AppChainConfig) -> Result<(), DaError>;

fn get_da_config_path(&self, config: &AppChainConfig) -> Result<PathBuf, DaError> {
Ok(get_app_home(&config.app_chain).map_err(DaError::FailedToReadAppHome)?.join(APP_DA_CONFIG_NAME))
}
}

pub struct DAFactory;

impl DAFactory {
pub fn new_da(da: &DALayer) -> Box<dyn DaConfig> {
pub fn new_da(da: &DALayer) -> Box<dyn DaClient> {
match da {
DALayer::Avail => Box::new(AvailConfig {}),
DALayer::Avail => Box::new(AvailClient {}),
_ => Box::new(NoDAConfig {}),
}
}
Expand Down
14 changes: 0 additions & 14 deletions src/da/errors.rs

This file was deleted.

2 changes: 0 additions & 2 deletions src/da/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,4 @@ pub mod da_layers;

pub mod avail;

pub mod errors;

pub mod no_da;
14 changes: 9 additions & 5 deletions src/da/no_da.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
pub struct NoDAConfig;

use crate::da::da_layers::DaConfig;
use crate::da::errors::KeyGenError;
use crate::app::config::AppChainConfig;
use crate::da::da_layers::{DaClient, DaError};

impl DaConfig for NoDAConfig {
fn setup_and_generate_keypair(&self, app_chain: &str) -> Result<(), KeyGenError> {
log::info!("Launching {} without any DA mode", app_chain);
impl DaClient for NoDAConfig {
fn setup_and_generate_keypair(&self, config: &AppChainConfig) -> Result<(), DaError> {
log::info!("Launching {} without any DA mode", config.app_chain);
Ok(())
}

fn confirm_minimum_balance(&self, _config: &AppChainConfig) -> Result<(), DaError> {
Ok(())
}
}
7 changes: 6 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,12 @@ enum Commands {
}

fn main() {
env_logger::Builder::from_default_env().filter_level(LevelFilter::Info).init();
env_logger::Builder::from_default_env()
.filter_level(LevelFilter::Info)
.format_timestamp(None)
.format_level(false)
.format_target(false)
.init();

let cli = Cli::parse();

Expand Down
2 changes: 1 addition & 1 deletion src/utils/cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ pub fn execute_cmd_stdout(program: &str, args: &[&str], dir: &PathBuf, out: Stdi
match result {
Ok(output) => {
if output.status.success() {
log::info!("Successfully executed {}", program);
log::debug!("Successfully executed {}", program);
Ok(output)
} else {
Err(Error::new(ErrorKind::Other, "Unable to execute command"))
Expand Down
3 changes: 3 additions & 0 deletions src/utils/errors.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::ffi::OsString;
use thiserror::Error;

#[derive(Debug, Error)]
Expand Down Expand Up @@ -26,6 +27,8 @@ pub enum MadaraError {
FailedToRegenerateConfig,
#[error("Failed to get DA config")]
FailedToGetDAConfig,
#[error("Unable to fetch remote")]
FailedToConvertToString(OsString),
}

#[derive(Debug, Error)]
Expand Down
Loading

0 comments on commit 223f537

Please sign in to comment.