diff --git a/CLI.md b/CLI.md index 914d89f9385..13ba8ea3b22 100644 --- a/CLI.md +++ b/CLI.md @@ -122,9 +122,10 @@ Client implementation and command-line tool for the Linera blockchain ###### **Options:** -* `--wallet ` — Sets the file storing the private state of user chains (an empty one will be created if missing) -* `--keystore ` — Sets the file storing the keystore state -* `-w`, `--with-wallet ` — Given an ASCII alphanumeric parameter `X`, read the wallet state and the wallet storage config from the environment variables `LINERA_WALLET_{X}` and `LINERA_STORAGE_{X}` instead of `LINERA_WALLET` and `LINERA_STORAGE` +* `--wallet ` — DEPRECATED: Use --with-wallet=NAME instead. Sets the file storing the private state of user chains (an empty one will be created if missing) +* `--keystore ` — DEPRECATED: Use --with-wallet=NAME instead. Sets the file storing the keystore state +* `--home-directory ` — Sets the home directory for storing Linera wallets. Alternatively, one may set the environment variable LINERA_HOME +* `-w`, `--with-wallet ` — Name of the wallet to be used. Data will be stored in the corresponding subdirectory of the home directory -- unless other (deprecated) options are used * `--send-timeout-ms ` — Timeout for sending queries (milliseconds) Default value: `4000` diff --git a/README.md b/README.md index a82007c44d0..8cb4c82bafb 100644 --- a/README.md +++ b/README.md @@ -93,10 +93,8 @@ FAUCET_URL=http://localhost:8080 # LINERA_TMP_DIR=$(mktemp -d) # FAUCET_URL=https://faucet.testnet-XXX.linera.net # for some value XXX -# Set the path of the future wallet. -export LINERA_WALLET="$LINERA_TMP_DIR/wallet.json" -export LINERA_KEYSTORE="$LINERA_TMP_DIR/keystore.json" -export LINERA_STORAGE="rocksdb:$LINERA_TMP_DIR/client.db" +# Set the home directory for future wallets. +export LINERA_HOME="$LINERA_TMP_DIR" # Initialize a new user wallet. linera wallet init --faucet $FAUCET_URL diff --git a/examples/amm/README.md b/examples/amm/README.md index cad5c5f133e..4657fd6031a 100644 --- a/examples/amm/README.md +++ b/examples/amm/README.md @@ -53,9 +53,8 @@ linera_spawn linera net up --with-faucet --faucet-port $FAUCET_PORT Create the user wallet and add chains to it: ```bash -export LINERA_WALLET="$LINERA_TMP_DIR/wallet.json" -export LINERA_KEYSTORE="$LINERA_TMP_DIR/keystore.json" -export LINERA_STORAGE="rocksdb:$LINERA_TMP_DIR/client.db" +# Set the home directory for future wallets. +export LINERA_HOME="$LINERA_TMP_DIR" linera wallet init --faucet $FAUCET_URL diff --git a/examples/counter/README.md b/examples/counter/README.md index ff953d05d41..7f7cdcfd67f 100644 --- a/examples/counter/README.md +++ b/examples/counter/README.md @@ -40,9 +40,8 @@ linera_spawn linera net up --with-faucet --faucet-port $LINERA_FAUCET_PORT Create the user wallet and add chains to it: ```bash -export LINERA_WALLET="$LINERA_TMP_DIR/wallet.json" -export LINERA_KEYSTORE="$LINERA_TMP_DIR/keystore.json" -export LINERA_STORAGE="rocksdb:$LINERA_TMP_DIR/client.db" +# Set the home directory for future wallets. +export LINERA_HOME="$LINERA_TMP_DIR" linera wallet init --faucet $LINERA_FAUCET_URL diff --git a/examples/crowd-funding/README.md b/examples/crowd-funding/README.md index 23f2ed2d11e..8e891591181 100644 --- a/examples/crowd-funding/README.md +++ b/examples/crowd-funding/README.md @@ -65,12 +65,8 @@ linera_spawn linera net up --with-faucet --faucet-port $FAUCET_PORT Create the user wallets and add chains to them: ```bash -export LINERA_WALLET_1="$LINERA_TMP_DIR/wallet_1.json" -export LINERA_KEYSTORE_1="$LINERA_TMP_DIR/keystore_1.json" -export LINERA_STORAGE_1="rocksdb:$LINERA_TMP_DIR/client_1.db" -export LINERA_WALLET_2="$LINERA_TMP_DIR/wallet_2.json" -export LINERA_KEYSTORE_2="$LINERA_TMP_DIR/keystore_2.json" -export LINERA_STORAGE_2="rocksdb:$LINERA_TMP_DIR/client_2.db" +# Set the home directory for future wallets. +export LINERA_HOME="$LINERA_TMP_DIR" linera --with-wallet 1 wallet init --faucet $FAUCET_URL linera --with-wallet 2 wallet init --faucet $FAUCET_URL @@ -83,9 +79,6 @@ OWNER_1="${INFO_1[1]}" OWNER_2="${INFO_2[1]}" ``` -Note that `linera --with-wallet 1` is equivalent to `linera --wallet "$LINERA_WALLET_1" --keystore "$LINERA_KEYSTORE_1" ---storage "$LINERA_STORAGE_1"`. - The command below can be used to list the chains created for the test as known by each wallet: diff --git a/examples/fungible/README.md b/examples/fungible/README.md index c14b455a1dd..eec6de98936 100644 --- a/examples/fungible/README.md +++ b/examples/fungible/README.md @@ -57,9 +57,8 @@ linera_spawn linera net up --with-faucet --faucet-port $FAUCET_PORT Create the user wallet and add chains to it: ```bash -export LINERA_WALLET="$LINERA_TMP_DIR/wallet.json" -export LINERA_KEYSTORE="$LINERA_TMP_DIR/keystore.json" -export LINERA_STORAGE="rocksdb:$LINERA_TMP_DIR/client.db" +# Set the home directory for future wallets. +export LINERA_HOME="$LINERA_TMP_DIR" linera wallet init --faucet $FAUCET_URL diff --git a/examples/gen-nft/README.md b/examples/gen-nft/README.md index 89e1dbca36a..c6a26f05d89 100644 --- a/examples/gen-nft/README.md +++ b/examples/gen-nft/README.md @@ -52,9 +52,8 @@ linera_spawn linera net up --with-faucet --faucet-port $FAUCET_PORT Create the user wallet and add chains to it: ```bash -export LINERA_WALLET="$LINERA_TMP_DIR/wallet.json" -export LINERA_KEYSTORE="$LINERA_TMP_DIR/keystore.json" -export LINERA_STORAGE="rocksdb:$LINERA_TMP_DIR/client.db" +# Set the home directory for future wallets. +export LINERA_HOME="$LINERA_TMP_DIR" linera wallet init --faucet $FAUCET_URL diff --git a/examples/hex-game/README.md b/examples/hex-game/README.md index ed7de0ae4cd..8e950599fdd 100644 --- a/examples/hex-game/README.md +++ b/examples/hex-game/README.md @@ -48,12 +48,8 @@ linera_spawn linera net up --with-faucet --faucet-port $FAUCET_PORT Create the user wallets and add chains to them: ```bash -export LINERA_WALLET_1="$LINERA_TMP_DIR/wallet_1.json" -export LINERA_KEYSTORE_1="$LINERA_TMP_DIR/keystore_1.json" -export LINERA_STORAGE_1="rocksdb:$LINERA_TMP_DIR/client_1.db" -export LINERA_WALLET_2="$LINERA_TMP_DIR/wallet_2.json" -export LINERA_KEYSTORE_2="$LINERA_TMP_DIR/keystore_2.json" -export LINERA_STORAGE_2="rocksdb:$LINERA_TMP_DIR/client_2.db" +# Set the home directory for future wallets. +export LINERA_HOME="$LINERA_TMP_DIR" linera --with-wallet 1 wallet init --faucet $FAUCET_URL linera --with-wallet 2 wallet init --faucet $FAUCET_URL @@ -66,9 +62,6 @@ OWNER_1="${INFO_1[1]}" OWNER_2="${INFO_2[1]}" ``` -Note that `linera --with-wallet 1` or `linera -w1` is equivalent to `linera --wallet -"$LINERA_WALLET_1" --keystore "$LINERA_KEYSTORE_1" --storage "$LINERA_STORAGE_1"`. - ### Creating the Game Chain We open a new chain owned by both `$OWNER_1` and `$OWNER_2`, create the application on it, and diff --git a/examples/how-to/perform-http-requests/README.md b/examples/how-to/perform-http-requests/README.md index 48d208597e3..f281ccaf701 100644 --- a/examples/how-to/perform-http-requests/README.md +++ b/examples/how-to/perform-http-requests/README.md @@ -90,9 +90,8 @@ FAUCET_URL=http://localhost:8081 We then create a wallet and obtain a chain to use with the application. ```bash -export LINERA_WALLET="$LINERA_TMP_DIR/wallet.json" -export LINERA_KEYSTORE="$LINERA_TMP_DIR/keystore.json" -export LINERA_STORAGE="rocksdb:$LINERA_TMP_DIR/client.db" +# Set the home directory for future wallets. +export LINERA_HOME="$LINERA_TMP_DIR" linera wallet init --faucet $FAUCET_URL diff --git a/examples/llm/README.md b/examples/llm/README.md index a53a132329a..1c1f7869e94 100644 --- a/examples/llm/README.md +++ b/examples/llm/README.md @@ -55,9 +55,8 @@ linera_spawn linera net up --with-faucet --faucet-port $FAUCET_PORT Create the user wallet and add chains to it: ```bash -export LINERA_WALLET="$LINERA_TMP_DIR/wallet.json" -export LINERA_KEYSTORE="$LINERA_TMP_DIR/keystore.json" -export LINERA_STORAGE="rocksdb:$LINERA_TMP_DIR/client.db" +# Set the home directory for future wallets. +export LINERA_HOME="$LINERA_TMP_DIR" linera wallet init --faucet $FAUCET_URL diff --git a/examples/matching-engine/README.md b/examples/matching-engine/README.md index 8d68605b9c1..06adbc5346e 100644 --- a/examples/matching-engine/README.md +++ b/examples/matching-engine/README.md @@ -64,9 +64,8 @@ linera_spawn linera net up --with-faucet --faucet-port $FAUCET_PORT Create the user wallet and add chains to it: ```bash -export LINERA_WALLET="$LINERA_TMP_DIR/wallet.json" -export LINERA_KEYSTORE="$LINERA_TMP_DIR/keystore.json" -export LINERA_STORAGE="rocksdb:$LINERA_TMP_DIR/client.db" +# Set the home directory for future wallets. +export LINERA_HOME="$LINERA_TMP_DIR" linera wallet init --faucet $FAUCET_URL diff --git a/examples/native-fungible/README.md b/examples/native-fungible/README.md index cf4c0799d42..c3c341491ba 100644 --- a/examples/native-fungible/README.md +++ b/examples/native-fungible/README.md @@ -35,9 +35,8 @@ linera_spawn linera net up --with-faucet --faucet-port $LINERA_FAUCET_PORT Create the user wallet and add chains to it: ```bash -export LINERA_WALLET="$LINERA_TMP_DIR/wallet.json" -export LINERA_KEYSTORE="$LINERA_TMP_DIR/keystore.json" -export LINERA_STORAGE="rocksdb:$LINERA_TMP_DIR/client.db" +# Set the home directory for future wallets. +export LINERA_HOME="$LINERA_TMP_DIR" linera wallet init --faucet $LINERA_FAUCET_URL diff --git a/examples/non-fungible/README.md b/examples/non-fungible/README.md index 72d646e6f4d..157aca49e57 100644 --- a/examples/non-fungible/README.md +++ b/examples/non-fungible/README.md @@ -52,9 +52,8 @@ linera_spawn linera net up --with-faucet --faucet-port $FAUCET_PORT Create the user wallet and add chains to it: ```bash -export LINERA_WALLET="$LINERA_TMP_DIR/wallet.json" -export LINERA_KEYSTORE="$LINERA_TMP_DIR/keystore.json" -export LINERA_STORAGE="rocksdb:$LINERA_TMP_DIR/client.db" +# Set the home directory for future wallets. +export LINERA_HOME="$LINERA_TMP_DIR" linera wallet init --faucet $FAUCET_URL diff --git a/examples/rfq/README.md b/examples/rfq/README.md index ae28a90e71c..bb6b393d30f 100644 --- a/examples/rfq/README.md +++ b/examples/rfq/README.md @@ -65,12 +65,8 @@ linera_spawn linera net up --with-faucet --faucet-port $FAUCET_PORT Create the user wallets and add chains to them: ```bash -export LINERA_WALLET_1="$LINERA_TMP_DIR/wallet_1.json" -export LINERA_KEYSTORE_1="$LINERA_TMP_DIR/keystore_1.json" -export LINERA_STORAGE_1="rocksdb:$LINERA_TMP_DIR/client_1.db" -export LINERA_WALLET_2="$LINERA_TMP_DIR/wallet_2.json" -export LINERA_KEYSTORE_2="$LINERA_TMP_DIR/keystore_2.json" -export LINERA_STORAGE_2="rocksdb:$LINERA_TMP_DIR/client_2.db" +# Set the home directory for future wallets. +export LINERA_HOME="$LINERA_TMP_DIR" linera --with-wallet 1 wallet init --faucet $FAUCET_URL linera --with-wallet 2 wallet init --faucet $FAUCET_URL @@ -83,9 +79,6 @@ OWNER_1="${INFO_1[1]}" OWNER_2="${INFO_2[1]}" ``` -Note that `linera --with-wallet 1` is equivalent to `linera --wallet "$LINERA_WALLET_1" --keystore "$LINERA_KEYSTORE_1" ---storage "$LINERA_STORAGE_1"`. - Now, we can publish the fungible module and create the fungible applications. ```bash diff --git a/examples/social/README.md b/examples/social/README.md index 7ef5b06da2b..0dd7681251b 100644 --- a/examples/social/README.md +++ b/examples/social/README.md @@ -53,12 +53,8 @@ linera_spawn linera net up --with-faucet --faucet-port $FAUCET_PORT Create the user wallets and add chains to them: ```bash -export LINERA_WALLET_1="$LINERA_TMP_DIR/wallet_1.json" -export LINERA_KEYSTORE_1="$LINERA_TMP_DIR/keystore_1.json" -export LINERA_STORAGE_1="rocksdb:$LINERA_TMP_DIR/client_1.db" -export LINERA_WALLET_2="$LINERA_TMP_DIR/wallet_2.json" -export LINERA_KEYSTORE_2="$LINERA_TMP_DIR/keystore_2.json" -export LINERA_STORAGE_2="rocksdb:$LINERA_TMP_DIR/client_2.db" +# Set the home directory for future wallets. +export LINERA_HOME="$LINERA_TMP_DIR" linera --with-wallet 1 wallet init --faucet $FAUCET_URL linera --with-wallet 2 wallet init --faucet $FAUCET_URL @@ -71,9 +67,6 @@ OWNER_1="${INFO_1[3]}" OWNER_2="${INFO_2[3]}" ``` -Note that `linera --with-wallet 1` is equivalent to `linera --wallet "$LINERA_WALLET_1" --keystore "$LINERA_KEYSTORE_1" ---storage "$LINERA_STORAGE_1"`. - Compile the `social` example and create an application with it: ```bash diff --git a/linera-client/src/client_options.rs b/linera-client/src/client_options.rs index bbe2ce86ab4..1b1323c60d0 100644 --- a/linera-client/src/client_options.rs +++ b/linera-client/src/client_options.rs @@ -45,19 +45,25 @@ util::impl_from_infallible!(Error); #[derive(Clone, clap::Parser)] pub struct ClientContextOptions { - /// Sets the file storing the private state of user chains (an empty one will be created if missing) + /// DEPRECATED: Use --with-wallet=NAME instead. Sets the file + /// storing the private state of user chains (an empty one will be created if missing) #[arg(long = "wallet")] pub wallet_state_path: Option, - /// Sets the file storing the keystore state. + /// DEPRECATED: Use --with-wallet=NAME instead. Sets the file + /// storing the keystore state. #[arg(long = "keystore")] pub keystore_path: Option, - /// Given an ASCII alphanumeric parameter `X`, read the wallet state and the wallet - /// storage config from the environment variables `LINERA_WALLET_{X}` and - /// `LINERA_STORAGE_{X}` instead of `LINERA_WALLET` and - /// `LINERA_STORAGE`. - #[arg(long, short = 'w', value_parser = util::parse_ascii_alphanumeric_string)] + /// Sets the home directory for storing Linera wallets. Alternatively, one may set the + /// environment variable LINERA_HOME. + #[arg(long, env = "LINERA_HOME")] + pub home_directory: Option, + + /// Name of the wallet to be used. Data will be stored in the corresponding + /// subdirectory of the home directory -- unless other (deprecated) options are + /// used. + #[arg(long, short = 'w', value_name = "NAME", value_parser = util::parse_ascii_alphanumeric_string)] pub with_wallet: Option, /// Timeout for sending queries (milliseconds) diff --git a/linera-service/src/cli/main.rs b/linera-service/src/cli/main.rs index 89eebf0d89d..89938f0fcc7 100644 --- a/linera-service/src/cli/main.rs +++ b/linera-service/src/cli/main.rs @@ -1814,17 +1814,21 @@ impl ClientOptions { .unwrap_or_default() } - fn config_path() -> Result { - let mut config_dir = dirs::config_dir().ok_or_else(|| anyhow!( + fn config_path(&self, file: &str) -> Result { + let mut path = self.context_options.home_directory.clone().or_else(dirs::config_dir).ok_or_else(|| anyhow!( "Default wallet directory is not supported in this platform: please specify storage and wallet paths" ))?; - config_dir.push("linera"); - if !config_dir.exists() { - debug!("Creating default wallet directory {}", config_dir.display()); - fs_err::create_dir_all(&config_dir)?; + path.push("linera"); + if let Some(name) = &self.context_options.with_wallet { + path.push(name); } - info!("Using default wallet directory {}", config_dir.display()); - Ok(config_dir) + if !path.exists() { + debug!("Creating default wallet directory {}", path.display()); + fs_err::create_dir_all(&path)?; + } + path.push(file); + info!("Using wallet path {}", path.display()); + Ok(path) } fn storage_config(&self) -> Result { @@ -1834,6 +1838,7 @@ impl ClientOptions { let suffix = self.suffix(); let storage_env_var = env::var(format!("LINERA_STORAGE{suffix}")).ok(); if let Some(config) = storage_env_var { + warn!("LINERA_STORAGE_* is deprecated. Use --with-wallet=NAME or --storage=CONFIG instead."); return config.parse(); } cfg_if::cfg_if! { @@ -1841,7 +1846,7 @@ impl ClientOptions { let spawn_mode = linera_views::rocks_db::RocksDbSpawnMode::get_spawn_mode_from_runtime(); let inner_storage_config = linera_service::storage::InnerStorageConfig::RocksDb { - path: Self::config_path()?.join("wallet.db"), + path: self.config_path("wallet.db")?, spawn_mode, }; let namespace = "default".to_string(); @@ -1857,28 +1862,30 @@ impl ClientOptions { fn wallet_path(&self) -> Result { if let Some(path) = &self.context_options.wallet_state_path { + warn!("Option --wallet is deprecated. Use --with-wallet=NAME instead."); return Ok(path.clone()); } let suffix = self.suffix(); let wallet_env_var = env::var(format!("LINERA_WALLET{suffix}")).ok(); if let Some(path) = wallet_env_var { + warn!("LINERA_WALLET_* is deprecated. Use --with-wallet=NAME instead."); return Ok(path.parse()?); } - let config_path = Self::config_path()?; - Ok(config_path.join("wallet.json")) + self.config_path("wallet.json") } fn keystore_path(&self) -> Result { if let Some(path) = &self.context_options.keystore_path { + warn!("Option --keystore is deprecated. Use --with-wallet=NAME instead."); return Ok(path.clone()); } let suffix = self.suffix(); let keystore_env_var = env::var(format!("LINERA_KEYSTORE{suffix}")).ok(); if let Some(path) = keystore_env_var { + warn!("LINERA_KEYSTORE_* is deprecated. Use --with-wallet=NAME instead."); return Ok(path.parse()?); } - let config_path = Self::config_path()?; - Ok(config_path.join("keystore.json")) + self.config_path("keystore.json") } pub fn create_wallet( diff --git a/linera-service/src/cli/net_up_utils.rs b/linera-service/src/cli/net_up_utils.rs index 809a01a3aea..77c88e4cacb 100644 --- a/linera-service/src/cli/net_up_utils.rs +++ b/linera-service/src/cli/net_up_utils.rs @@ -311,29 +311,16 @@ async fn print_messages_and_create_faucet( eprintln!( "To use the admin wallet of this test network, you may set \ - the environment variables LINERA_WALLET, LINERA_KEYSTORE, \ - and LINERA_STORAGE as follows.\n" + the environment variable LINERA_HOME as follows.\n" ); println!( "{}", format!( - "export LINERA_WALLET=\"{}\"", - client.wallet_path().display(), + "export LINERA_HOME=\"{}\"", + client.path_provider.path().display() ) .bold(), ); - println!( - "{}", - format!( - "export LINERA_KEYSTORE=\"{}\"", - client.keystore_path().display(), - ) - .bold() - ); - println!( - "{}", - format!("export LINERA_STORAGE=\"{}\"", client.storage_path()).bold(), - ); let wallet = client.load_wallet()?; let chains = wallet.chain_ids(); diff --git a/linera-service/src/cli_wrappers/wallet.rs b/linera-service/src/cli_wrappers/wallet.rs index 8be38fe41db..da87887bdb2 100644 --- a/linera-service/src/cli_wrappers/wallet.rs +++ b/linera-service/src/cli_wrappers/wallet.rs @@ -68,12 +68,10 @@ fn reqwest_client() -> reqwest::Client { pub struct ClientWrapper { binary_path: sync::Mutex>, testing_prng_seed: Option, - storage: String, - wallet: String, - keystore: String, max_pending_message_bundles: usize, network: Network, pub path_provider: PathProvider, + wallet_id: usize, on_drop: OnClientDrop, extra_args: Vec, } @@ -92,14 +90,14 @@ impl ClientWrapper { path_provider: PathProvider, network: Network, testing_prng_seed: Option, - id: usize, + wallet_id: usize, on_drop: OnClientDrop, ) -> Self { Self::new_with_extra_args( path_provider, network, testing_prng_seed, - id, + wallet_id, on_drop, vec!["--wait-for-outgoing-messages".to_string()], ) @@ -109,26 +107,17 @@ impl ClientWrapper { path_provider: PathProvider, network: Network, testing_prng_seed: Option, - id: usize, + wallet_id: usize, on_drop: OnClientDrop, extra_args: Vec, ) -> Self { - let storage = format!( - "rocksdb:{}/client_{}.db", - path_provider.path().display(), - id - ); - let wallet = format!("wallet_{}.json", id); - let keystore = format!("keystore_{}.json", id); Self { binary_path: sync::Mutex::new(None), testing_prng_seed, - storage, - wallet, - keystore, max_pending_message_bundles: 10_000, network, path_provider, + wallet_id, on_drop, extra_args, } @@ -234,12 +223,10 @@ impl ClientWrapper { fn required_command_arguments(&self) -> impl Iterator> + '_ { [ - "--wallet".into(), - self.wallet.as_str().into(), - "--keystore".into(), - self.keystore.as_str().into(), - "--storage".into(), - self.storage.as_str().into(), + "--home-directory".into(), + self.path_provider.path().display().to_string().into(), + "--with-wallet".into(), + self.wallet_id.to_string().into(), "--send-timeout-ms".into(), "500000".into(), "--recv-timeout-ms".into(), @@ -982,15 +969,17 @@ impl ClientWrapper { } pub fn wallet_path(&self) -> PathBuf { - self.path_provider.path().join(&self.wallet) + self.path_provider + .path() + .join(self.wallet_id.to_string()) + .join("wallet.json") } pub fn keystore_path(&self) -> PathBuf { - self.path_provider.path().join(&self.keystore) - } - - pub fn storage_path(&self) -> &str { - &self.storage + self.path_provider + .path() + .join(self.wallet_id.to_string()) + .join("keystore.json") } pub fn get_owner(&self) -> Option { diff --git a/web/@linera/client/src/lib.rs b/web/@linera/client/src/lib.rs index 2848c0bb688..4e856854b90 100644 --- a/web/@linera/client/src/lib.rs +++ b/web/@linera/client/src/lib.rs @@ -94,6 +94,7 @@ pub const OPTIONS: ClientContextOptions = ClientContextOptions { // TODO(linera-protocol#2944): separate these out from the // `ClientOptions` struct, since they apply only to the CLI/native // client + home_directory: None, wallet_state_path: None, keystore_path: None, with_wallet: None,