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

refactor wallet context and fixup account cli #910

Merged
merged 2 commits into from
Oct 4, 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
25 changes: 25 additions & 0 deletions crates/rooch-key/src/keystore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1302,6 +1302,31 @@ impl FileBasedKeystore<RoochAddress, RoochKeyPair> {
})
}

pub fn load(path: &PathBuf) -> Result<Self, anyhow::Error> {
if path.exists() {
let reader = BufReader::new(File::open(path).map_err(|e| {
anyhow!(
"Can't open FileBasedKeystore from Rooch path {:?}: {}",
path,
e
)
})?);
let keystore = serde_json::from_reader(reader).map_err(|e| {
anyhow!(
"Can't deserialize FileBasedKeystore from Rooch path {:?}: {}",
path,
e
)
})?;
Ok(Self {
keystore,
path: Some(path.to_path_buf()),
})
} else {
Err(anyhow!("Key store path {:?} does not exist", path))
}
}

pub fn set_path(&mut self, path: &Path) {
self.path = Some(path.to_path_buf());
}
Expand Down
24 changes: 11 additions & 13 deletions crates/rooch-rpc-client/src/client_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,31 @@ use crate::{Client, ClientBuilder};
use anyhow::anyhow;
use rooch_config::config::Config;
use rooch_config::server_config::ServerConfig;
use rooch_key::keystore::Keystore;
use rooch_types::address::RoochAddress;
use rooch_types::chain_id::RoochChainID;
use rooch_types::crypto::RoochKeyPair;
use serde::Deserialize;
use serde::Serialize;
use serde_with::serde_as;
use std::fmt::{Display, Formatter, Write};
use std::path::PathBuf;

pub const DEFAULT_EXPIRATION_SECS: u64 = 30;
pub const ROOCH_DEV_NET_URL: &str = "https://dev-seed.rooch.network:443/";
pub const ROOCH_TEST_NET_URL: &str = "https://test-seed.rooch.network:443/";

#[serde_as]
#[derive(Serialize, Deserialize)]
pub struct ClientConfig<K: Ord, V> {
pub keystore: Keystore<K, V>,
pub active_address: Option<K>,
#[derive(Serialize, Deserialize, Debug)]
pub struct ClientConfig {
pub keystore_path: PathBuf,
pub active_address: Option<RoochAddress>,
pub envs: Vec<Env>,
pub active_env: Option<String>,
}

impl ClientConfig<RoochAddress, RoochKeyPair> {
pub fn new(keystore: Keystore<RoochAddress, RoochKeyPair>) -> Self {
impl ClientConfig {
pub fn new(keystore_path: PathBuf) -> Self {
ClientConfig {
keystore,
keystore_path,
active_address: None,
envs: vec![],
active_env: None,
Expand Down Expand Up @@ -134,19 +133,18 @@ impl Display for Env {
}
}

impl Config for ClientConfig<RoochAddress, RoochKeyPair> {}
impl Config for ClientConfig {}

impl Display for ClientConfig<RoochAddress, RoochKeyPair> {
impl Display for ClientConfig {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let mut writer = String::new();

writeln!(writer, "Managed addresses : {}", self.keystore)?;
writeln!(writer, "Keystore path : {:?}", self.keystore_path)?;
write!(writer, "Active address: ")?;
match self.active_address {
Some(r) => writeln!(writer, "{}", r)?,
None => writeln!(writer, "None")?,
};
writeln!(writer, "{}", self.keystore)?;
write!(writer, "server: ")?;

if let Ok(env) = self.get_active_env() {
Expand Down
21 changes: 15 additions & 6 deletions crates/rooch-rpc-client/src/wallet_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use rooch_config::config::{Config, PersistedConfig};
use rooch_config::server_config::ServerConfig;
use rooch_config::{rooch_config_dir, ROOCH_CLIENT_CONFIG, ROOCH_SERVER_CONFIG};
use rooch_key::keypair::KeyPairType;
use rooch_key::keystore::AccountKeystore;
use rooch_key::keystore::{AccountKeystore, FileBasedKeystore, Keystore};
use rooch_rpc_api::jsonrpc_types::{ExecuteTransactionResponseView, KeptVMStatusView};
use rooch_types::address::RoochAddress;
use rooch_types::crypto::{RoochKeyPair, Signature};
Expand All @@ -27,18 +27,19 @@ use std::sync::Arc;
use std::time::Duration;
use tokio::sync::RwLock;

pub struct WalletContext {
pub struct WalletContext<K: Ord, V> {
client: Arc<RwLock<Option<Client>>>,
pub client_config: PersistedConfig<ClientConfig<RoochAddress, RoochKeyPair>>,
pub client_config: PersistedConfig<ClientConfig>,
pub server_config: PersistedConfig<ServerConfig>,
pub keystore: Keystore<K, V>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have not found a suitable approach to supporting the Ethereum transaction in CLI. We can make the Keystore<K<V> to Keystore<RoochAddress, RoochKeyPair>. After we support other KeyPairType to the WalletContext, we can refactor it later.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I merge this PR first, we can refactor it later.

}

impl WalletContext {
impl WalletContext<RoochAddress, RoochKeyPair> {
pub async fn new(config_path: Option<PathBuf>) -> Result<Self, anyhow::Error> {
let config_dir = config_path.unwrap_or(rooch_config_dir()?);
let client_config_path = config_dir.join(ROOCH_CLIENT_CONFIG);
let server_config_path = config_dir.join(ROOCH_SERVER_CONFIG);
let client_config: ClientConfig<RoochAddress, RoochKeyPair> = PersistedConfig::read(&client_config_path).map_err(|err| {
let client_config: ClientConfig = PersistedConfig::read(&client_config_path).map_err(|err| {
anyhow!(
"Cannot open wallet config file at {:?}. Err: {err}, Use `rooch init` to configuration",
client_config_path
Expand All @@ -53,10 +54,19 @@ impl WalletContext {

let client_config = client_config.persisted(&client_config_path);
let server_config = server_config.persisted(&server_config_path);

let keystore_result =
FileBasedKeystore::<RoochAddress, RoochKeyPair>::load(&client_config.keystore_path);
let keystore = match keystore_result {
Ok(file_keystore) => Keystore::File(file_keystore),
Err(error) => return Err(error),
};

Ok(Self {
client: Default::default(),
client_config,
server_config,
keystore,
})
}

Expand Down Expand Up @@ -124,7 +134,6 @@ impl WalletContext {
key_pair_type: KeyPairType,
) -> RoochResult<RoochTransaction> {
let kp = self
.client_config
.keystore
.get_key_pair_by_key_pair_type(&sender, key_pair_type)
.ok()
Expand Down
4 changes: 3 additions & 1 deletion crates/rooch/src/cli_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ use std::fmt::{Display, Formatter};
use std::ops::Deref;
use std::path::PathBuf;

use rooch_types::address::RoochAddress;
use rooch_types::crypto::RoochKeyPair;
use std::str::FromStr;

#[async_trait]
Expand Down Expand Up @@ -99,7 +101,7 @@ pub struct WalletContextOptions {
}

impl WalletContextOptions {
pub async fn build(&self) -> RoochResult<WalletContext> {
pub async fn build(&self) -> RoochResult<WalletContext<RoochAddress, RoochKeyPair>> {
WalletContext::new(self.config_dir.clone())
.await
.map_err(RoochError::from)
Expand Down
31 changes: 11 additions & 20 deletions crates/rooch/src/commands/account/commands/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ use crate::cli_types::WalletContextOptions;
use clap::Parser;
use move_core_types::account_address::AccountAddress;
use rooch_key::{keypair::KeyPairType, keystore::AccountKeystore};
use rooch_rpc_api::jsonrpc_types::ExecuteTransactionResponseView;
use rooch_types::{account::AccountModule, error::RoochResult};
use rooch_types::error::RoochResult;

/// Create a new account on-chain
/// Create a new account off-chain.
/// If an account not exist on-chain, contract will auto create the account on-chain.
///
/// An account can be created by transferring coins, or by making an explicit
/// call to create an account. This will create an account with no coins, and
Expand All @@ -20,30 +20,21 @@ pub struct CreateCommand {
}

impl CreateCommand {
pub async fn execute(self) -> RoochResult<ExecuteTransactionResponseView> {
pub async fn execute(self) -> RoochResult<String> {
let mut context = self.context_options.build().await?;

let (new_address, phrase, multichain_id) = context
.client_config
.keystore
.generate_and_add_new_key(KeyPairType::RoochKeyPairType, None, None)?;
let (new_address, phrase, multichain_id) =
context
.keystore
.generate_and_add_new_key(KeyPairType::RoochKeyPairType, None, None)?;

println!("{}", AccountAddress::from(new_address).to_hex_literal());
let address = AccountAddress::from(new_address).to_hex_literal();
println!(
"Generated new keypair for address with multichain id {:?} [{new_address}]",
KeyPairType::RoochKeyPairType.type_of()
multichain_id
);
println!("Secret Recovery Phrase : [{phrase}]");

// Obtain account address
let address = AccountAddress::from(new_address);

// Create account action
let action = AccountModule::create_account_action(address);

let result = context
.sign_and_execute(new_address, action, multichain_id)
.await?;
context.assert_execute_success(result)
Ok(address)
}
}
1 change: 0 additions & 1 deletion crates/rooch/src/commands/account/commands/import.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ impl CommandAction<()> for ImportCommand {
let mut context = self.context_options.build().await?;

let address = context
.client_config
.keystore
.import_from_mnemonic(&self.mnemonic_phrase, KeyPairType::RoochKeyPairType, None)
.map_err(|e| RoochError::ImportAccountError(e.to_string()))?;
Expand Down
3 changes: 2 additions & 1 deletion crates/rooch/src/commands/account/commands/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ impl CommandAction<()> for ListCommand {
"Rooch Address (Ed25519)", "Public Key (Base64)", "Auth Validator ID", "Active Address"
);
println!("{}", ["-"; 153].join(""));
for (address, public_key) in context.client_config.keystore.get_address_public_keys() {

for (address, public_key) in context.keystore.get_address_public_keys() {
let auth_validator_id = public_key.auth_validator().flag();
let mut active = "";
if active_address == Some(address) {
Expand Down
1 change: 0 additions & 1 deletion crates/rooch/src/commands/account/commands/nullify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ impl CommandAction<ExecuteTransactionResponseView> for NullifyCommand {

// Remove keypair by coin id from Rooch key store after successfully executing transaction
context
.client_config
.keystore
.nullify_address_with_key_pair_from_key_pair_type(
&existing_address,
Expand Down
7 changes: 1 addition & 6 deletions crates/rooch/src/commands/account/commands/switch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,7 @@ impl CommandAction<()> for SwitchCommand {
RoochError::CommandArgumentError(format!("Invalid Rooch address String: {}", e))
})?;

if !context
.client_config
.keystore
.addresses()
.contains(&rooch_address)
{
if !context.keystore.addresses().contains(&rooch_address) {
return Err(RoochError::SwitchAccountError(format!(
"Address `{}` does not in the Rooch keystore",
self.address
Expand Down
1 change: 0 additions & 1 deletion crates/rooch/src/commands/account/commands/update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ impl CommandAction<ExecuteTransactionResponseView> for UpdateCommand {
})?;

let kp = context
.client_config
.keystore
.update_address_with_key_pair_from_key_pair_type(
&existing_address,
Expand Down
2 changes: 1 addition & 1 deletion crates/rooch/src/commands/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ impl CommandAction<()> for Init {
let dev_env = Env::new_dev_env();
let active_env_alias = dev_env.alias.clone();
ClientConfig {
keystore,
keystore_path,
envs: vec![env, dev_env],
active_address: Some(new_address),
// make dev env as default env
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@ impl CommandAction<ExecuteTransactionResponseView> for RunFunction {
(_, Some(session_key)) => {
let tx_data = context.build_rooch_tx_data(sender, action).await?;
let tx = context
.client_config
.keystore
.sign_transaction_via_session_key(&sender, tx_data, &session_key)
.map_err(|e| RoochError::SignMessageError(e.to_string()))?;
Expand Down
3 changes: 0 additions & 3 deletions crates/rooch/src/commands/server/commands/start.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ impl CommandAction<()> for StartCommand {
)?
};
let sequencer_keypair = context
.client_config
.keystore
.get_key_pair_by_key_pair_type(&sequencer_account, KeyPairType::RoochKeyPairType)
.map_err(|e| RoochError::SequencerKeyPairDoesNotExistError(e.to_string()))?;
Expand All @@ -71,7 +70,6 @@ impl CommandAction<()> for StartCommand {
)?
};
let proposer_keypair = context
.client_config
.keystore
.get_key_pair_by_key_pair_type(&proposer_account, KeyPairType::RoochKeyPairType)
.map_err(|e| RoochError::ProposerKeyPairDoesNotExistError(e.to_string()))?;
Expand All @@ -93,7 +91,6 @@ impl CommandAction<()> for StartCommand {
)?
};
let relayer_keypair = context
.client_config
.keystore
.get_key_pair_by_key_pair_type(&relayer_account, KeyPairType::RoochKeyPairType)
.map_err(|e| RoochError::RelayerKeyPairDoesNotExistError(e.to_string()))?;
Expand Down
5 changes: 1 addition & 4 deletions crates/rooch/src/commands/session_key/commands/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,7 @@ impl CreateCommand {
.parse_account_arg(self.tx_options.sender_account.unwrap())?
.into();

let session_auth_key = context
.client_config
.keystore
.generate_session_key(&sender)?;
let session_auth_key = context.keystore.generate_session_key(&sender)?;

let session_scope = self.scope;

Expand Down