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

Configurable keyring store directory #3273

Merged
merged 5 commits into from
Apr 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- Added a configuration to specify the directory used to the keyring store
([#1541](https://github.com/informalsystems/hermes/issues/1541))
4 changes: 4 additions & 0 deletions config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,10 @@ account_prefix = 'cosmos'
# https://hermes.informal.systems/commands/keys/index.html#adding-keys
key_name = 'testkey'

# Specify the folder used to store the keys. Optional
# If this is not specified then the hermes home folder is used.
# key_store_folder = '$HOME/.hermes/keys'

# Specify the address type which determines:
# 1) address derivation;
# 2) how to retrieve and decode accounts and pubkeys;
Expand Down
1 change: 1 addition & 0 deletions crates/relayer-cli/src/chain_registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ where
account_prefix: chain_data.bech32_prefix,
key_name: String::new(),
key_store_type: Store::default(),
key_store_folder: None,
store_prefix: "ibc".to_string(),
default_gas: Some(100000),
max_gas: Some(400000),
Expand Down
16 changes: 12 additions & 4 deletions crates/relayer-cli/src/commands/keys/add.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,8 +200,12 @@ pub fn add_key(
) -> eyre::Result<AnySigningKeyPair> {
let key_pair = match config.r#type {
ChainType::CosmosSdk => {
let mut keyring =
KeyRing::new_secp256k1(Store::Test, &config.account_prefix, &config.id)?;
let mut keyring = KeyRing::new_secp256k1(
Store::Test,
&config.account_prefix,
&config.id,
&config.key_store_folder,
)?;

check_key_exists(&keyring, key_name, overwrite);

Expand Down Expand Up @@ -229,8 +233,12 @@ pub fn restore_key(

let key_pair = match config.r#type {
ChainType::CosmosSdk => {
let mut keyring =
KeyRing::new_secp256k1(Store::Test, &config.account_prefix, &config.id)?;
let mut keyring = KeyRing::new_secp256k1(
Store::Test,
&config.account_prefix,
&config.id,
&config.key_store_folder,
)?;

check_key_exists(&keyring, key_name, overwrite);

Expand Down
16 changes: 12 additions & 4 deletions crates/relayer-cli/src/commands/keys/delete.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,12 @@ impl Runnable for KeysDeleteCmd {
pub fn delete_key(config: &ChainConfig, key_name: &str) -> eyre::Result<()> {
match config.r#type {
ChainType::CosmosSdk => {
let mut keyring =
KeyRing::new_secp256k1(Store::Test, &config.account_prefix, &config.id)?;
let mut keyring = KeyRing::new_secp256k1(
Store::Test,
&config.account_prefix,
&config.id,
&config.key_store_folder,
)?;
keyring.remove_key(key_name)?;
}
}
Expand All @@ -126,8 +130,12 @@ pub fn delete_key(config: &ChainConfig, key_name: &str) -> eyre::Result<()> {
pub fn delete_all_keys(config: &ChainConfig) -> eyre::Result<()> {
match config.r#type {
ChainType::CosmosSdk => {
let mut keyring =
KeyRing::new_secp256k1(Store::Test, &config.account_prefix, &config.id)?;
let mut keyring = KeyRing::new_secp256k1(
Store::Test,
&config.account_prefix,
&config.id,
&config.key_store_folder,
)?;
let keys = keyring.keys()?;
for (key_name, _) in keys {
keyring.remove_key(&key_name)?;
Expand Down
10 changes: 7 additions & 3 deletions crates/relayer/src/chain/cosmos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -776,9 +776,13 @@ impl ChainEndpoint for CosmosSdkChain {
let light_client = TmLightClient::from_config(&config, node_info.id)?;

// Initialize key store and load key
let keybase =
KeyRing::new_secp256k1(config.key_store_type, &config.account_prefix, &config.id)
.map_err(Error::key_base)?;
let keybase = KeyRing::new_secp256k1(
config.key_store_type,
&config.account_prefix,
&config.id,
&config.key_store_folder,
)
.map_err(Error::key_base)?;

let grpc_addr = Uri::from_str(&config.grpc_addr.to_string())
.map_err(|e| Error::invalid_uri(config.grpc_addr.to_string(), e))?;
Expand Down
8 changes: 7 additions & 1 deletion crates/relayer/src/chain/cosmos/batch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,13 @@ mod tests {
"/tests/config/fixtures/relayer-seed.json"
);
let seed_file_content = fs::read_to_string(path).unwrap();
let _keyring = KeyRing::new_secp256k1(keyring::Store::Memory, "cosmos", &chain_id).unwrap();
let _keyring = KeyRing::new_secp256k1(
keyring::Store::Memory,
"cosmos",
&chain_id,
&chain_config.key_store_folder,
)
.unwrap();
let hd_path = COSMOS_HD_PATH.parse().unwrap();
let key_pair = Secp256k1KeyPair::from_seed_file(&seed_file_content, &hd_path).unwrap();

Expand Down
8 changes: 7 additions & 1 deletion crates/relayer/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,12 @@ use core::{
str::FromStr,
time::Duration,
};
use std::{fs, fs::File, io::Write, path::Path};
use std::{
fs,
fs::File,
io::Write,
path::{Path, PathBuf},
};
use tendermint::block::Height as BlockHeight;
use tendermint_rpc::{Url, WebSocketClientUrl};

Expand Down Expand Up @@ -448,6 +453,7 @@ pub struct ChainConfig {
pub key_name: String,
#[serde(default)]
pub key_store_type: Store,
pub key_store_folder: Option<PathBuf>,
pub store_prefix: String,
pub default_gas: Option<u64>,
pub max_gas: Option<u64>,
Expand Down
39 changes: 27 additions & 12 deletions crates/relayer/src/keyring.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ mod signing_key_pair;
use alloc::collections::btree_map::BTreeMap as HashMap;
use std::ffi::OsStr;
use std::fs::{self, File};
use std::path::{Path, PathBuf};
use std::path::PathBuf;

use ibc_relayer_types::core::ics24_host::identifier::ChainId;
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -200,12 +200,17 @@ pub enum KeyRing<S> {
}

impl<S: SigningKeyPairSized> KeyRing<S> {
pub fn new(store: Store, account_prefix: &str, chain_id: &ChainId) -> Result<Self, Error> {
pub fn new(
store: Store,
account_prefix: &str,
chain_id: &ChainId,
ks_folder: &Option<PathBuf>,
) -> Result<Self, Error> {
match store {
Store::Memory => Ok(Self::Memory(Memory::new(account_prefix.to_string()))),

Store::Test => {
let keys_folder = disk_store_path(chain_id.as_str())?;
let keys_folder = disk_store_path(chain_id.as_str(), ks_folder)?;

// Create keys folder if it does not exist
fs::create_dir_all(&keys_folder).map_err(|e| {
Expand Down Expand Up @@ -265,8 +270,9 @@ impl KeyRing<Secp256k1KeyPair> {
store: Store,
account_prefix: &str,
chain_id: &ChainId,
ks_folder: &Option<PathBuf>,
) -> Result<Self, Error> {
Self::new(store, account_prefix, chain_id)
Self::new(store, account_prefix, chain_id, ks_folder)
}
}

Expand All @@ -275,15 +281,21 @@ impl KeyRing<Ed25519KeyPair> {
store: Store,
account_prefix: &str,
chain_id: &ChainId,
ks_folder: &Option<PathBuf>,
) -> Result<Self, Error> {
Self::new(store, account_prefix, chain_id)
Self::new(store, account_prefix, chain_id, ks_folder)
}
}

pub fn list_keys(config: &ChainConfig) -> Result<Vec<(String, AnySigningKeyPair)>, Error> {
let keys = match config.r#type {
ChainType::CosmosSdk => {
let keyring = KeyRing::new_secp256k1(Store::Test, &config.account_prefix, &config.id)?;
let keyring = KeyRing::new_secp256k1(
Store::Test,
&config.account_prefix,
&config.id,
&config.key_store_folder,
)?;
keyring
.keys()?
.into_iter()
Expand All @@ -294,13 +306,16 @@ pub fn list_keys(config: &ChainConfig) -> Result<Vec<(String, AnySigningKeyPair)
Ok(keys)
}

fn disk_store_path(folder_name: &str) -> Result<PathBuf, Error> {
let home = dirs_next::home_dir().ok_or_else(Error::home_location_unavailable)?;
fn disk_store_path(folder_name: &str, keystore_folder: &Option<PathBuf>) -> Result<PathBuf, Error> {
let ks_folder = match keystore_folder {
Some(folder) => folder.to_owned(),
None => {
let home = dirs_next::home_dir().ok_or_else(Error::home_location_unavailable)?;
home.join(KEYSTORE_DEFAULT_FOLDER)
}
};

let folder = Path::new(home.as_path())
.join(KEYSTORE_DEFAULT_FOLDER)
.join(folder_name)
.join(KEYSTORE_DISK_BACKEND);
let folder = ks_folder.join(folder_name).join(KEYSTORE_DISK_BACKEND);

Ok(folder)
}
19 changes: 12 additions & 7 deletions tools/integration-test/src/tests/client_refresh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,15 +119,19 @@ impl TestOverrides for ClientFailsTest {
impl BinaryChainTest for ClientFailsTest {
fn run<ChainA: ChainHandle, ChainB: ChainHandle>(
&self,
_config: &TestConfig,
config: &TestConfig,
_relayer: RelayerDriver,
chains: ConnectedChains<ChainA, ChainB>,
) -> Result<(), Error> {
// Override the configuration in order to use a small `gas_multiplier` which will cause the update client to fail.
let chains2 = override_connected_chains(chains, |config| {
config.chains[0].gas_multiplier = Some(GasMultiplier::unsafe_new(0.8));
config.chains[1].gas_multiplier = Some(GasMultiplier::unsafe_new(0.8));
})?;
let chains2 = override_connected_chains(
chains,
|config| {
config.chains[0].gas_multiplier = Some(GasMultiplier::unsafe_new(0.8));
config.chains[1].gas_multiplier = Some(GasMultiplier::unsafe_new(0.8));
},
config,
)?;

// Use chains with misconfiguration in order to trigger a ChainError when submitting `MsgClientUpdate`
// during the refresh call.
Expand Down Expand Up @@ -156,15 +160,16 @@ impl BinaryChainTest for ClientFailsTest {
fn override_connected_chains<ChainA, ChainB>(
chains: ConnectedChains<ChainA, ChainB>,
config_modifier: impl FnOnce(&mut Config),
test_config: &TestConfig,
) -> Result<ConnectedChains<impl ChainHandle, impl ChainHandle>, Error>
where
ChainA: ChainHandle,
ChainB: ChainHandle,
{
let mut config = Config::default();

add_chain_config(&mut config, chains.node_a.value())?;
add_chain_config(&mut config, chains.node_b.value())?;
add_chain_config(&mut config, chains.node_a.value(), test_config)?;
add_chain_config(&mut config, chains.node_b.value(), test_config)?;

config_modifier(&mut config);

Expand Down
13 changes: 9 additions & 4 deletions tools/test-framework/src/bootstrap/binary/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ pub fn bootstrap_chains_with_full_nodes(
> {
let mut config = Config::default();

add_chain_config(&mut config, &node_a)?;
add_chain_config(&mut config, &node_b)?;
add_chain_config(&mut config, &node_a, test_config)?;
add_chain_config(&mut config, &node_b, test_config)?;

config_modifier(&mut config);

Expand Down Expand Up @@ -249,8 +249,13 @@ pub fn new_registry(config: Config) -> SharedRegistry<CountingAndCachingChainHan
Generate [`ChainConfig`](ibc_relayer::config::ChainConfig) from a running
[`FullNode`] and add it to the relayer's [`Config`].
*/
pub fn add_chain_config(config: &mut Config, running_node: &FullNode) -> Result<(), Error> {
let chain_config = running_node.generate_chain_config(&running_node.chain_driver.chain_type)?;
pub fn add_chain_config(
config: &mut Config,
running_node: &FullNode,
test_config: &TestConfig,
) -> Result<(), Error> {
let chain_config =
running_node.generate_chain_config(&running_node.chain_driver.chain_type, test_config)?;

config.chains.push(chain_config);
Ok(())
Expand Down
2 changes: 1 addition & 1 deletion tools/test-framework/src/bootstrap/nary/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ pub fn boostrap_chains_with_any_nodes(
let mut config = Config::default();

for node in full_nodes.iter() {
add_chain_config(&mut config, node)?;
add_chain_config(&mut config, node, test_config)?;
}

config_modifier(&mut config);
Expand Down
16 changes: 10 additions & 6 deletions tools/test-framework/src/types/single/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use tendermint_rpc::WebSocketClientUrl;
use crate::chain::chain_type::ChainType as TestedChainType;
use crate::chain::driver::ChainDriver;
use crate::ibc::denom::Denom;
use crate::prelude::TestConfig;
use crate::types::env::{prefix_writer, EnvWriter, ExportEnv};
use crate::types::process::ChildProcess;
use crate::types::tagged::*;
Expand Down Expand Up @@ -124,7 +125,14 @@ impl FullNode {
pub fn generate_chain_config(
&self,
chain_type: &TestedChainType,
test_config: &TestConfig,
) -> Result<config::ChainConfig, Error> {
let hermes_keystore_dir = test_config
.chain_store_dir
.join("hermes_keyring")
.as_path()
.display()
.to_string();
Ok(config::ChainConfig {
id: self.chain_driver.chain_id.clone(),
r#type: ChainType::CosmosSdk,
Expand All @@ -135,12 +143,8 @@ impl FullNode {
genesis_restart: None,
account_prefix: self.chain_driver.account_prefix.clone(),
key_name: self.wallets.relayer.id.0.clone(),

// By default we use in-memory key store to avoid polluting
// ~/.hermes/keys. See
// https://github.com/informalsystems/hermes/issues/1541
key_store_type: Store::Memory,

key_store_type: Store::Test,
key_store_folder: Some(hermes_keystore_dir.into()),
store_prefix: "ibc".to_string(),
default_gas: None,
max_gas: Some(3000000),
Expand Down