From f0d8a1d2038e1534f8247efaf80fc1f55b73a5a0 Mon Sep 17 00:00:00 2001 From: baichuan3 Date: Wed, 4 Oct 2023 13:17:46 +0800 Subject: [PATCH 1/2] refactor wallet context and fixup account cli --- crates/rooch-key/src/keystore.rs | 25 +++++++++++++++ crates/rooch-rpc-client/src/client_config.rs | 24 +++++++------- crates/rooch-rpc-client/src/wallet_context.rs | 21 +++++++++---- crates/rooch/src/cli_types.rs | 4 ++- .../src/commands/account/commands/create.rs | 31 +++++++------------ .../src/commands/account/commands/import.rs | 1 - .../src/commands/account/commands/list.rs | 3 +- .../src/commands/account/commands/nullify.rs | 1 - .../src/commands/account/commands/switch.rs | 7 +---- .../src/commands/account/commands/update.rs | 1 - crates/rooch/src/commands/init.rs | 4 ++- .../move_cli/commands/run_function.rs | 1 - .../src/commands/server/commands/start.rs | 3 -- .../commands/session_key/commands/create.rs | 5 +-- 14 files changed, 72 insertions(+), 59 deletions(-) diff --git a/crates/rooch-key/src/keystore.rs b/crates/rooch-key/src/keystore.rs index 328723f207..42a4d16d48 100644 --- a/crates/rooch-key/src/keystore.rs +++ b/crates/rooch-key/src/keystore.rs @@ -1302,6 +1302,31 @@ impl FileBasedKeystore { }) } + pub fn load(path: &PathBuf) -> Result { + 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()); } diff --git a/crates/rooch-rpc-client/src/client_config.rs b/crates/rooch-rpc-client/src/client_config.rs index c8ae9bc18c..80b1893b62 100644 --- a/crates/rooch-rpc-client/src/client_config.rs +++ b/crates/rooch-rpc-client/src/client_config.rs @@ -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 { - pub keystore: Keystore, - pub active_address: Option, +#[derive(Serialize, Deserialize, Debug)] +pub struct ClientConfig { + pub keystore_path: PathBuf, + pub active_address: Option, pub envs: Vec, pub active_env: Option, } -impl ClientConfig { - pub fn new(keystore: Keystore) -> Self { +impl ClientConfig { + pub fn new(keystore_path: PathBuf) -> Self { ClientConfig { - keystore, + keystore_path, active_address: None, envs: vec![], active_env: None, @@ -134,19 +133,18 @@ impl Display for Env { } } -impl Config for ClientConfig {} +impl Config for ClientConfig {} -impl Display for ClientConfig { +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() { diff --git a/crates/rooch-rpc-client/src/wallet_context.rs b/crates/rooch-rpc-client/src/wallet_context.rs index 7b1ee11ebb..d9039ebd86 100644 --- a/crates/rooch-rpc-client/src/wallet_context.rs +++ b/crates/rooch-rpc-client/src/wallet_context.rs @@ -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}; @@ -27,18 +27,19 @@ use std::sync::Arc; use std::time::Duration; use tokio::sync::RwLock; -pub struct WalletContext { +pub struct WalletContext { client: Arc>>, - pub client_config: PersistedConfig>, + pub client_config: PersistedConfig, pub server_config: PersistedConfig, + pub keystore: Keystore, } -impl WalletContext { +impl WalletContext { pub async fn new(config_path: Option) -> Result { 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 = 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 @@ -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::::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, }) } @@ -124,7 +134,6 @@ impl WalletContext { key_pair_type: KeyPairType, ) -> RoochResult { let kp = self - .client_config .keystore .get_key_pair_by_key_pair_type(&sender, key_pair_type) .ok() diff --git a/crates/rooch/src/cli_types.rs b/crates/rooch/src/cli_types.rs index dd8e48b87e..fd58b9b6a4 100644 --- a/crates/rooch/src/cli_types.rs +++ b/crates/rooch/src/cli_types.rs @@ -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] @@ -99,7 +101,7 @@ pub struct WalletContextOptions { } impl WalletContextOptions { - pub async fn build(&self) -> RoochResult { + pub async fn build(&self) -> RoochResult> { WalletContext::new(self.config_dir.clone()) .await .map_err(RoochError::from) diff --git a/crates/rooch/src/commands/account/commands/create.rs b/crates/rooch/src/commands/account/commands/create.rs index cf92f48764..d37905b454 100644 --- a/crates/rooch/src/commands/account/commands/create.rs +++ b/crates/rooch/src/commands/account/commands/create.rs @@ -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 @@ -20,30 +20,21 @@ pub struct CreateCommand { } impl CreateCommand { - pub async fn execute(self) -> RoochResult { + pub async fn execute(self) -> RoochResult { 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) } } diff --git a/crates/rooch/src/commands/account/commands/import.rs b/crates/rooch/src/commands/account/commands/import.rs index dc30de8780..9f6fc18c54 100644 --- a/crates/rooch/src/commands/account/commands/import.rs +++ b/crates/rooch/src/commands/account/commands/import.rs @@ -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()))?; diff --git a/crates/rooch/src/commands/account/commands/list.rs b/crates/rooch/src/commands/account/commands/list.rs index 320778dd1a..34d6c24e72 100644 --- a/crates/rooch/src/commands/account/commands/list.rs +++ b/crates/rooch/src/commands/account/commands/list.rs @@ -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) { diff --git a/crates/rooch/src/commands/account/commands/nullify.rs b/crates/rooch/src/commands/account/commands/nullify.rs index 0adc470da7..89f23db4fa 100644 --- a/crates/rooch/src/commands/account/commands/nullify.rs +++ b/crates/rooch/src/commands/account/commands/nullify.rs @@ -52,7 +52,6 @@ impl CommandAction 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, diff --git a/crates/rooch/src/commands/account/commands/switch.rs b/crates/rooch/src/commands/account/commands/switch.rs index c0de0ec379..39c2151a78 100644 --- a/crates/rooch/src/commands/account/commands/switch.rs +++ b/crates/rooch/src/commands/account/commands/switch.rs @@ -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 diff --git a/crates/rooch/src/commands/account/commands/update.rs b/crates/rooch/src/commands/account/commands/update.rs index 05b4f3411e..b80be1e180 100644 --- a/crates/rooch/src/commands/account/commands/update.rs +++ b/crates/rooch/src/commands/account/commands/update.rs @@ -37,7 +37,6 @@ impl CommandAction for UpdateCommand { })?; let kp = context - .client_config .keystore .update_address_with_key_pair_from_key_pair_type( &existing_address, diff --git a/crates/rooch/src/commands/init.rs b/crates/rooch/src/commands/init.rs index 832df2b2bc..48ffcff0e5 100644 --- a/crates/rooch/src/commands/init.rs +++ b/crates/rooch/src/commands/init.rs @@ -49,6 +49,8 @@ impl CommandAction<()> for Init { .parent() .unwrap_or(&rooch_config_dir()?) .join(ROOCH_KEYSTORE_FILENAME); + println!("Debug client_config_path: {:?}", client_config_path); + println!("Debug keystore_path: {:?}", keystore_path); let keystore_result = FileBasedKeystore::::new(&keystore_path); let mut keystore = match keystore_result { @@ -145,7 +147,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 diff --git a/crates/rooch/src/commands/move_cli/commands/run_function.rs b/crates/rooch/src/commands/move_cli/commands/run_function.rs index 0fb45117a9..c90976aec0 100644 --- a/crates/rooch/src/commands/move_cli/commands/run_function.rs +++ b/crates/rooch/src/commands/move_cli/commands/run_function.rs @@ -90,7 +90,6 @@ impl CommandAction 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()))?; diff --git a/crates/rooch/src/commands/server/commands/start.rs b/crates/rooch/src/commands/server/commands/start.rs index 7395650268..7c0d7b4299 100644 --- a/crates/rooch/src/commands/server/commands/start.rs +++ b/crates/rooch/src/commands/server/commands/start.rs @@ -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()))?; @@ -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()))?; @@ -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()))?; diff --git a/crates/rooch/src/commands/session_key/commands/create.rs b/crates/rooch/src/commands/session_key/commands/create.rs index bf08b55ec1..69e7b8a157 100644 --- a/crates/rooch/src/commands/session_key/commands/create.rs +++ b/crates/rooch/src/commands/session_key/commands/create.rs @@ -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; From c4b6b4aae00a0aea1c70d96bbd6de48642dad74b Mon Sep 17 00:00:00 2001 From: baichuan3 Date: Wed, 4 Oct 2023 13:23:48 +0800 Subject: [PATCH 2/2] cleanup debug info --- crates/rooch/src/commands/init.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/crates/rooch/src/commands/init.rs b/crates/rooch/src/commands/init.rs index 48ffcff0e5..97d4548703 100644 --- a/crates/rooch/src/commands/init.rs +++ b/crates/rooch/src/commands/init.rs @@ -49,8 +49,6 @@ impl CommandAction<()> for Init { .parent() .unwrap_or(&rooch_config_dir()?) .join(ROOCH_KEYSTORE_FILENAME); - println!("Debug client_config_path: {:?}", client_config_path); - println!("Debug keystore_path: {:?}", keystore_path); let keystore_result = FileBasedKeystore::::new(&keystore_path); let mut keystore = match keystore_result {