diff --git a/relayer-cli/src/commands.rs b/relayer-cli/src/commands.rs index 0d26bb01f6..4faea92fe8 100644 --- a/relayer-cli/src/commands.rs +++ b/relayer-cli/src/commands.rs @@ -6,6 +6,7 @@ //! application's configuration file. mod config; +mod keys; mod light; mod listen; mod query; @@ -15,8 +16,8 @@ mod utils; mod version; use self::{ - config::ConfigCmd, light::LightCmd, listen::ListenCmd, query::QueryCmd, start::StartCmd, - tx::TxCmd, version::VersionCmd, + config::ConfigCmd, keys::KeysCmd, light::LightCmd, listen::ListenCmd, query::QueryCmd, + start::StartCmd, tx::TxCmd, version::VersionCmd, }; use crate::config::Config; @@ -60,6 +61,10 @@ pub enum CliCmd { /// The `light` subcommand #[options(help = "basic functionality for managing the lite clients")] Light(LightCmd), + + /// The `keys` subcommand + #[options(help = "manage keys in the relayer for each chain")] + Keys(KeysCmd), } /// This trait allows you to define how application configuration is loaded. diff --git a/relayer-cli/src/commands/keys.rs b/relayer-cli/src/commands/keys.rs new file mode 100644 index 0000000000..001dad462c --- /dev/null +++ b/relayer-cli/src/commands/keys.rs @@ -0,0 +1,16 @@ +//! `keys` subcommand +use abscissa_core::{Command, Help, Options, Runnable}; + +mod restore; + +/// `keys` subcommand +#[derive(Command, Debug, Options, Runnable)] +pub enum KeysCmd { + /// The `help` subcommand + #[options(help = "get usage information")] + Help(Help), + + /// The `keys restore` subcommand + #[options(help = "keys restore")] + Restore(restore::KeyRestoreCmd), +} diff --git a/relayer-cli/src/commands/keys/restore.rs b/relayer-cli/src/commands/keys/restore.rs new file mode 100644 index 0000000000..be65b0cc37 --- /dev/null +++ b/relayer-cli/src/commands/keys/restore.rs @@ -0,0 +1,71 @@ +use crate::application::app_config; +use abscissa_core::{Command, Options, Runnable}; +use relayer::config::Config; + +use crate::error::{Error, Kind}; +use crate::prelude::*; +use relayer::crypto::keybase::{restore_key, KeysRestoreOptions}; + +#[derive(Clone, Command, Debug, Options)] +pub struct KeyRestoreCmd { + #[options(free, help = "identifier of the chain")] + chain_id: Option, + + #[options(free, help = "the key name")] + name: Option, + + #[options(free, help = "mnemonic to add key")] + mnemonic: Option, +} + +impl KeyRestoreCmd { + fn validate_options(&self, config: &Config) -> Result { + let chain_id = self + .chain_id + .clone() + .ok_or_else(|| "missing chain identifier".to_string())?; + + let chain_config = config + .chains + .iter() + .find(|c| c.id == chain_id.parse().unwrap()) + .ok_or_else(|| "missing chain configuration".to_string())?; + + let key_name = self + .name + .clone() + .ok_or_else(|| "missing key name".to_string())?; + + let mnemonic_words = self + .name + .clone() + .ok_or_else(|| "missing mnemonic".to_string())?; + + Ok(KeysRestoreOptions { + name: key_name, + mnemonic: mnemonic_words, + chain_config: chain_config.clone(), + }) + } +} + +impl Runnable for KeyRestoreCmd { + fn run(&self) { + let config = app_config(); + + let opts = match self.validate_options(&config) { + Err(err) => { + status_err!("invalid options: {}", err); + return; + } + Ok(result) => result, + }; + + let res: Result<(), Error> = restore_key(opts).map_err(|e| Kind::Keys.context(e).into()); + + match res { + Ok(r) => status_info!("keys store, result: ", "{:?}", r), + Err(e) => status_info!("keys store failed, error: ", "{}", e), + } + } +} diff --git a/relayer-cli/src/error.rs b/relayer-cli/src/error.rs index 1ca66be639..f77b0e2324 100644 --- a/relayer-cli/src/error.rs +++ b/relayer-cli/src/error.rs @@ -24,6 +24,10 @@ pub enum Kind { /// Error during transaction submission #[error("tx error")] Tx, + + /// Error during transaction submission + #[error("keys error")] + Keys, } impl Kind { diff --git a/relayer/Cargo.toml b/relayer/Cargo.toml index 0b0c6f5ab0..f366bd8435 100644 --- a/relayer/Cargo.toml +++ b/relayer/Cargo.toml @@ -8,6 +8,7 @@ authors = [ [dependencies] ibc = { path = "../modules" } +ibc-proto = { version = "0.4.0", path = "../proto" } tendermint-proto = "0.1.0" anomaly = "0.2.0" diff --git a/relayer/src/chain/cosmos.rs b/relayer/src/chain/cosmos.rs index 66fb46eda1..37eb4f799d 100644 --- a/relayer/src/chain/cosmos.rs +++ b/relayer/src/chain/cosmos.rs @@ -18,10 +18,10 @@ use crate::config::ChainConfig; use crate::error::{Error, Kind}; use bytes::Bytes; -use ibc_proto::base::crypto::v1beta1::public_key::Sum as PKSum; -use ibc_proto::base::crypto::v1beta1::PublicKey as RawPublicKey; -use ibc_proto::tx::v1beta1::mode_info::{Single, Sum}; -use ibc_proto::tx::v1beta1::{AuthInfo, ModeInfo, SignDoc, SignerInfo, TxBody}; +use ibc_proto::cosmos::base::crypto::v1beta1::public_key::Sum as PKSum; +use ibc_proto::cosmos::base::crypto::v1beta1::PublicKey as RawPublicKey; +use ibc_proto::cosmos::tx::v1beta1::mode_info::{Single, Sum}; +use ibc_proto::cosmos::tx::v1beta1::{AuthInfo, ModeInfo, SignDoc, SignerInfo, TxBody}; use k256::ecdsa::{SigningKey, VerifyKey}; use prost::Message; use prost_types::Any; @@ -96,13 +96,23 @@ impl Chain for CosmosSDKChain { let pubkey_bytes = verify_key.to_bytes().to_vec(); let sum = Some(PKSum::Secp256k1(pubkey_bytes)); - let pk = Some(RawPublicKey { sum }); + let pk = RawPublicKey { sum }; let single = Single { mode: 1 }; let sum_single = Some(Sum::Single(single)); let mode = Some(ModeInfo { sum: sum_single }); + // A protobuf serialization of a Public Key + let mut pk_buf = Vec::new(); + prost::Message::encode(&pk, &mut pk_buf).unwrap(); + + // Create a MsgSend proto Any message + let pk_any = Any { + type_url: "/cosmos.base.crypto.v1beta1.PublicKey.".to_string(), + value: pk_buf, + }; + let signer_info = SignerInfo { - public_key: pk, + public_key: Some(pk_any), mode_info: mode, sequence: 0, }; diff --git a/relayer/src/crypto.rs b/relayer/src/crypto.rs new file mode 100644 index 0000000000..3d38329b52 --- /dev/null +++ b/relayer/src/crypto.rs @@ -0,0 +1 @@ +pub mod keybase; diff --git a/relayer/src/crypto/keybase.rs b/relayer/src/crypto/keybase.rs new file mode 100644 index 0000000000..34846d106b --- /dev/null +++ b/relayer/src/crypto/keybase.rs @@ -0,0 +1,16 @@ +use crate::chain::CosmosSDKChain; +use crate::config::ChainConfig; +use crate::error::{Error, Kind}; + +#[derive(Clone, Debug)] +pub struct KeysRestoreOptions { + pub name: String, + pub mnemonic: String, + pub chain_config: ChainConfig, +} + +pub fn restore_key(opts: KeysRestoreOptions) -> Result<(), Error> { + // Get the destination chain + let chain = CosmosSDKChain::from_config(opts.clone().chain_config)?; + Ok(()) +} diff --git a/relayer/src/lib.rs b/relayer/src/lib.rs index fda4032351..a922a93818 100644 --- a/relayer/src/lib.rs +++ b/relayer/src/lib.rs @@ -16,6 +16,7 @@ pub mod auth; pub mod chain; pub mod client; pub mod config; +pub mod crypto; pub mod error; pub mod event_handler; pub mod event_monitor;