Skip to content
This repository has been archived by the owner on Oct 31, 2024. It is now read-only.

fix(config): fix the parse of edge_path ENV var #482

Merged
merged 2 commits into from
Mar 20, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions crates/topos-config/src/edge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ use std::{
use tokio::{spawn, task::JoinHandle};
use tracing::{error, info};

use self::command::BINARY_NAME;

// TODO: Provides the default arguments here
// Serde `flatten` and `default` doesn't work together yet
// https://github.com/serde-rs/serde/issues/1626
Expand Down Expand Up @@ -44,6 +46,39 @@ impl Config for EdgeConfig {
}
}

#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "kebab-case")]
pub struct EdgeBinConfig {
pub edge_path: PathBuf,
}

impl EdgeBinConfig {
pub fn binary_path(&self) -> PathBuf {
self.edge_path.join(BINARY_NAME)
}
}

impl Config for EdgeBinConfig {
type Output = EdgeBinConfig;

fn load_from_file(figment: Figment, home: &Path) -> Figment {
let home = home.join("config.toml");

let edge = Figment::new()
.merge(Toml::file(home).nested())
.select("edge");

figment.merge(edge)
}

fn load_context(figment: Figment) -> Result<Self::Output, figment::Error> {
figment.extract()
}

fn profile() -> String {
"edge".to_string()
}
}
pub mod command;

pub fn generate_edge_config(
Expand Down
2 changes: 1 addition & 1 deletion crates/topos-config/src/genesis/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,6 @@ impl TryFrom<&NodeConfig> for Genesis {
type Error = Error;

fn try_from(config: &NodeConfig) -> Result<Self, Self::Error> {
Genesis::new(&config.edge_path)
Genesis::new(&config.genesis_path)
}
}
4 changes: 2 additions & 2 deletions crates/topos-config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ pub trait Config: Serialize {
/// It will load the configuration from the file and an optional existing struct (if any)
/// and then extract the configuration from the context in order to build the Config.
/// The Config is then returned or an error if the configuration is not valid.
fn load<S: Serialize>(home: &Path, config: Option<S>) -> Result<Self::Output, figment::Error> {
fn load<S: Serialize>(home: &Path, config: Option<&S>) -> Result<Self::Output, figment::Error> {
let mut figment = Figment::new();

figment = Self::load_from_file(figment, home);
Expand All @@ -61,7 +61,7 @@ pub trait Config: Serialize {

pub(crate) fn load_config<T: Config, S: Serialize>(
node_path: &Path,
config: Option<S>,
config: Option<&S>,
) -> T::Output {
match T::load(node_path, config) {
Ok(config) => config,
Expand Down
28 changes: 21 additions & 7 deletions crates/topos-config/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ use topos_wallet::SecretManager;
use tracing::{debug, error};

use crate::{
base::BaseConfig, edge::EdgeConfig, load_config, sequencer::SequencerConfig, tce::TceConfig,
base::BaseConfig,
edge::{EdgeBinConfig, EdgeConfig},
load_config,
sequencer::SequencerConfig,
tce::TceConfig,
Config,
};

Expand All @@ -36,7 +40,10 @@ pub struct NodeConfig {
pub node_path: PathBuf,

#[serde(skip)]
pub edge_path: PathBuf,
pub genesis_path: PathBuf,

#[serde(skip)]
pub edge_bin: Option<EdgeBinConfig>,
}

impl NodeConfig {
Expand All @@ -47,7 +54,7 @@ impl NodeConfig {
pub fn try_from<S: Serialize>(
home_path: &Path,
node_name: &str,
config: Option<S>,
config: Option<&S>,
) -> Result<Self, std::io::Error> {
let node_path = home_path.join("node").join(node_name);
let config_path = node_path.join("config.toml");
Expand All @@ -68,26 +75,30 @@ impl NodeConfig {
///
/// It doesn't check the existence of the config file.
/// It's useful for creating a config file for a new node, relying on the default values.
pub fn create<S: Serialize>(home_path: &Path, node_name: &str, config: Option<S>) -> Self {
pub fn create<S: Serialize>(home_path: &Path, node_name: &str, config: Option<&S>) -> Self {
let node_path = home_path.join("node").join(node_name);

Self::build_config(node_path, home_path, config)
}

/// Common function to build a node config struct from the given home path and node name.
fn build_config<S: Serialize>(node_path: PathBuf, home_path: &Path, config: Option<S>) -> Self {
fn build_config<S: Serialize>(
node_path: PathBuf,
home_path: &Path,
config: Option<&S>,
) -> Self {
let node_folder = node_path.as_path();
let base = load_config::<BaseConfig, _>(node_folder, config);

// Load genesis pointed by the local config
let edge_path = home_path
let genesis_path = home_path
.join("subnet")
.join(base.subnet.clone())
.join("genesis.json");

let mut config = NodeConfig {
node_path: node_path.to_path_buf(),
edge_path,
genesis_path,
home_path: home_path.to_path_buf(),
base: base.clone(),
sequencer: base
Expand All @@ -96,6 +107,9 @@ impl NodeConfig {
tce: base
.need_tce()
.then(|| load_config::<TceConfig, ()>(node_folder, None)),
edge_bin: base
.need_edge()
.then(|| load_config::<EdgeBinConfig, _>(node_folder, config)),
edge: base
.need_edge()
.then(|| load_config::<EdgeConfig, ()>(node_folder, None)),
Expand Down
10 changes: 5 additions & 5 deletions crates/topos-node/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ use tokio::{
};
use tokio_util::sync::CancellationToken;
use topos_config::{
edge::command::BINARY_NAME,
genesis::Genesis,
node::{NodeConfig, NodeRole},
};
Expand Down Expand Up @@ -76,7 +75,7 @@ pub async fn start(
info!(
"Could not load genesis.json file on path {} \n Please make sure to have a valid \
genesis.json file for your subnet in the {}/subnet/{} folder.",
config.edge_path.display(),
config.genesis_path.display(),
config.home_path.display(),
&config.base.subnet
);
Expand Down Expand Up @@ -159,21 +158,22 @@ fn spawn_processes(
info!("Using external edge node, skip running of local edge instance...")
} else {
let edge_config = config.edge.take().ok_or(Error::MissingEdgeConfig)?;
let edge_bin_config = config.edge_bin.take().ok_or(Error::MissingEdgeConfig)?;

let data_dir = config.node_path.clone();

info!(
"Spawning edge process with genesis file: {}, data directory: {}, additional edge \
arguments: {:?}",
config.edge_path.display(),
config.genesis_path.display(),
data_dir.display(),
edge_config.args
);

processes.push(process::spawn_edge_process(
config.home_path.join(BINARY_NAME),
edge_bin_config.binary_path(),
data_dir,
config.edge_path.clone(),
config.genesis_path.clone(),
edge_config.args,
));
}
Expand Down
7 changes: 6 additions & 1 deletion crates/topos/src/components/node/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,12 @@ pub(crate) struct NodeCommand {
pub(crate) home: PathBuf,

/// Installation directory path for Polygon Edge binary
#[arg(long, env = "TOPOS_POLYGON_EDGE_BIN_PATH", default_value = ".")]
#[arg(
global = true,
long,
env = "TOPOS_POLYGON_EDGE_BIN_PATH",
default_value = "."
)]
pub(crate) edge_path: PathBuf,

#[clap(subcommand)]
Expand Down
6 changes: 6 additions & 0 deletions crates/topos/src/components/node/commands/init.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::path::PathBuf;

use clap::Args;
use serde::Serialize;
use topos_config::node::NodeRole;
Expand Down Expand Up @@ -27,4 +29,8 @@ pub struct Init {
/// rely on polygon-edge during runtime. Example: A sequencer which runs for an external EVM chain
#[arg(long, env = "TOPOS_NO_EDGE_PROCESS", action)]
pub no_edge_process: bool,

/// Installation directory path for Polygon Edge binary
#[clap(from_global)]
pub(crate) edge_path: PathBuf,
}
6 changes: 6 additions & 0 deletions crates/topos/src/components/node/commands/up.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::path::PathBuf;

use clap::Args;
use serde::Serialize;

Expand Down Expand Up @@ -26,4 +28,8 @@ pub struct Up {
/// If not provided open telemetry will not be used
#[arg(long, env = "TOPOS_OTLP_SERVICE_NAME")]
pub otlp_service_name: Option<String>,

/// Installation directory path for Polygon Edge binary
#[clap(from_global)]
pub(crate) edge_path: PathBuf,
}
4 changes: 2 additions & 2 deletions crates/topos/src/components/node/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ pub(crate) async fn handle_command(
}
}

let node_config = NodeConfig::create(&home, &name, Some(cmd));
let node_config = NodeConfig::create(&home, &name, Some(&cmd));

// Creating the TOML output
let config_toml = match node_config.to_toml() {
Expand Down Expand Up @@ -135,7 +135,7 @@ pub(crate) async fn handle_command(
.as_ref()
.expect("No name or default was given for node");

let config = NodeConfig::try_from(&home, name, Some(command))?;
let config = NodeConfig::try_from(&home, name, Some(&command))?;

topos_node::start(
verbose,
Expand Down
76 changes: 76 additions & 0 deletions crates/topos/tests/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,4 +99,80 @@ mod serial_integration {

Ok(())
}

#[test_log::test(tokio::test)]
async fn command_node_up_custom_polygon() -> Result<(), Box<dyn std::error::Error>> {
let tmp_home_dir = tempdir()?;

// Create config file
let node_up_home_env = tmp_home_dir.path().to_str().unwrap();
let custom_path = tmp_home_dir.path().join("custom_path");
let node_edge_path_env = utils::setup_polygon_edge(custom_path.to_str().unwrap()).await;
let node_up_name_env = "TEST_NODE_UP";
let node_up_role_env = "full-node";
let node_up_subnet_env = "topos-up-env-subnet";

let mut cmd = Command::cargo_bin("topos")?;
cmd.arg("node")
.env("TOPOS_POLYGON_EDGE_BIN_PATH", &node_edge_path_env)
.env("TOPOS_HOME", node_up_home_env)
.env("TOPOS_NODE_NAME", node_up_name_env)
.env("TOPOS_NODE_ROLE", node_up_role_env)
.env("TOPOS_NODE_SUBNET", node_up_subnet_env)
.arg("init");

let output = cmd.assert().success();
let result: &str = std::str::from_utf8(&output.get_output().stdout)?;
assert!(result.contains("Created node config file"));

// Run node init with cli flags
let home = PathBuf::from(node_up_home_env);
// Verification: check that the config file was created
let config_path = home.join("node").join(node_up_name_env).join("config.toml");
assert!(config_path.exists());

// Generate polygon edge genesis file
let polygon_edge_bin = format!("{}/polygon-edge", node_edge_path_env);
generate_polygon_edge_genesis_file(
&polygon_edge_bin,
node_up_home_env,
node_up_name_env,
node_up_subnet_env,
)
.await?;
let polygon_edge_genesis_path = home
.join("subnet")
.join(node_up_subnet_env)
.join("genesis.json");
assert!(polygon_edge_genesis_path.exists());

let mut cmd = Command::cargo_bin("topos")?;
cmd.arg("node")
.env("TOPOS_POLYGON_EDGE_BIN_PATH", &node_edge_path_env)
.env("TOPOS_HOME", node_up_home_env)
.env("TOPOS_NODE_NAME", node_up_name_env)
.arg("up");

let mut cmd = tokio::process::Command::from(cmd).spawn().unwrap();
let pid = cmd.id().unwrap();
let _ = tokio::time::sleep(std::time::Duration::from_secs(10)).await;

let s = System::new_all();
if let Some(process) = s.process(Pid::from_u32(pid)) {
if process.kill_with(Signal::Term).is_none() {
eprintln!("This signal isn't supported on this platform");
}
}

if let Ok(code) = cmd.wait().await {
assert!(code.success());
} else {
panic!("Failed to shutdown gracefully");
}

// Cleanup
std::fs::remove_dir_all(node_up_home_env)?;

Ok(())
}
}
Loading
Loading