Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge light clients config in relayer config and add commands to add/remove light clients #348

Merged
merged 15 commits into from
Nov 3, 2020
13 changes: 9 additions & 4 deletions relayer-cli/src/commands/light.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@

use abscissa_core::{Command, Options, Runnable};

mod init;
mod add;
mod rm;

/// `light` subcommand
#[derive(Command, Debug, Options, Runnable)]
pub enum LightCmd {
/// The `light init` subcommand
#[options(help = "initiate a light client for a given chain")]
Init(init::InitCmd),
/// The `light add` subcommand
#[options(help = "add a light client peer for a given chain")]
Add(add::AddCmd),

/// The `light rm` subcommand
#[options(help = "remove a light client peer for a given chain")]
Rm(rm::RmCmd),
}
158 changes: 158 additions & 0 deletions relayer-cli/src/commands/light/add.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
use std::ops::Deref;

use crate::prelude::*;

use abscissa_core::{application::fatal_error, error::BoxError, Command, Options, Runnable};

use relayer::config::{Config, LightClientConfig, PeersConfig};
use tendermint::chain::Id as ChainId;
use tendermint::hash::Hash;
use tendermint::{block::Height, net};
use tendermint_light_client::types::PeerId;

#[derive(Command, Debug, Options)]
pub struct AddCmd {
#[options(free, help = "identifier of the chain")]
chain_id: Option<ChainId>,

/// peer id for this client
#[options(short = "i")]
peer_id: Option<PeerId>,

/// whether this is the primary peer
primary: bool,

/// trusted header hash
#[options(short = "x")]
hash: Option<Hash>,

/// RPC network address
#[options(short = "a")]
address: Option<net::Address>,

/// trusted header height
#[options(short = "h")]
height: Option<Height>,

/// allow overriding an existing peer
force: bool,
}

#[derive(Clone, Debug)]
struct AddOptions {
/// identifier of the chain
chain_id: ChainId,

/// peer id for this client
peer_id: PeerId,

/// RPC network address
address: net::Address,

/// trusted header hash
trusted_hash: Hash,

/// trusted header height
trusted_height: Height,

/// whether this is the primary peer or not
primary: bool,

/// allow overriding an existing peer
force: bool,
}

impl AddOptions {
fn from_cmd(cmd: &AddCmd) -> Result<AddOptions, BoxError> {
let chain_id = cmd.chain_id.clone().ok_or("missing chain identifier")?;
let peer_id = cmd.peer_id.ok_or("missing peer identifier")?;
let address = cmd.address.clone().ok_or("missing RPC network address")?;
let trusted_hash = cmd.hash.ok_or("missing trusted hash")?;
let trusted_height = cmd.height.ok_or("missing chain identifier")?;
let primary = cmd.primary;
let force = cmd.force;

Ok(AddOptions {
chain_id,
peer_id,
address,
trusted_hash,
trusted_height,
primary,
force,
})
}
}

impl AddCmd {
fn update_config(options: AddOptions, config: &mut Config) -> Result<PeerId, BoxError> {
let chain_config = config
.chains
.iter_mut()
.find(|c| c.id == options.chain_id)
.ok_or_else(|| format!("could not find config for chain: {}", options.chain_id))?;

let peers_config = chain_config.peers.get_or_insert_with(|| PeersConfig {
primary: options.peer_id,
light_clients: vec![],
});

// Check if the given peer exists already, in which case throw an error except if the
// --force flag is set.
let peer_exists = peers_config.light_client(options.peer_id).is_some();
if peer_exists && !options.force {
return Err(format!("a peer with id {} already exists, remove it first or pass the --force flag to override it", options.peer_id).into());
}

let light_client_config = LightClientConfig {
peer_id: options.peer_id,
address: options.address.clone(),
trusted_header_hash: options.trusted_hash,
trusted_height: options.trusted_height,
};

if peer_exists {
// Filter out the light client config with the specified peer id
peers_config
.light_clients
.retain(|p| p.peer_id != options.peer_id);
}

peers_config.light_clients.push(light_client_config);

if options.primary {
peers_config.primary = options.peer_id;
}

Ok(peers_config.primary)
}

fn cmd(&self) -> Result<(), BoxError> {
let options = AddOptions::from_cmd(self).map_err(|e| format!("invalid options: {}", e))?;
let mut config = (*app_config()).clone();

let new_primary = Self::update_config(options.clone(), &mut config)?;

let config_path = crate::config::config_path()?;
relayer::config::store(&config, config_path)?;

status_ok!(
"Added",
"light client peer:\npeer_id = {}\naddress = {}\nhash = {}\nheight = {}\nprimary = {}",
options.peer_id,
options.address,
options.trusted_hash,
options.trusted_height,
options.peer_id == new_primary,
);

Ok(())
}
}

impl Runnable for AddCmd {
fn run(&self) {
self.cmd()
.unwrap_or_else(|e| fatal_error(app_reader().deref(), &*e))
}
}
104 changes: 0 additions & 104 deletions relayer-cli/src/commands/light/init.rs

This file was deleted.

Loading