diff --git a/src/commands.rs b/src/commands.rs index 255d337..a39af4a 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -2,6 +2,7 @@ pub(crate) mod balance; pub(crate) mod init; pub(crate) mod list_tx; pub(crate) mod list_unspent; +pub(crate) mod reset; pub(crate) mod send; pub(crate) mod sync; pub(crate) mod upgrade; diff --git a/src/commands/init.rs b/src/commands/init.rs index 8584607..72e97d7 100644 --- a/src/commands/init.rs +++ b/src/commands/init.rs @@ -1,9 +1,10 @@ use gumdrop::Options; use secrecy::{SecretVec, Zeroize}; +use tonic::transport::Channel; use zcash_client_backend::{ data_api::{AccountBirthday, WalletWrite}, - proto::service, + proto::service::{self, compact_tx_streamer_client::CompactTxStreamerClient}, }; use zcash_client_sqlite::{ chain::init::init_blockmeta_db, wallet::init::init_wallet_db, FsBlockDb, WalletDb, @@ -61,6 +62,23 @@ impl Command { // Save the wallet keys to disk. init_wallet_keys(wallet_dir.as_ref(), &mnemonic, birthday)?; + let seed = { + let mut seed = mnemonic.to_seed(""); + let secret = seed.to_vec(); + seed.zeroize(); + SecretVec::new(secret) + }; + + Self::init_dbs(client, params, wallet_dir, seed, birthday).await + } + + pub(crate) async fn init_dbs( + mut client: CompactTxStreamerClient, + params: impl Parameters + 'static, + wallet_dir: Option, + seed: SecretVec, + birthday: u64, + ) -> Result<(), anyhow::Error> { // Initialise the block and wallet DBs. let (db_cache, db_data) = get_db_paths(wallet_dir); let mut db_cache = FsBlockDb::for_path(db_cache).map_err(error::Error::from)?; @@ -79,12 +97,6 @@ impl Command { }; // Add one account. - let seed = { - let mut seed = mnemonic.to_seed(""); - let secret = seed.to_vec(); - seed.zeroize(); - SecretVec::new(secret) - }; let (account, _) = db_data.create_account(&seed, birthday)?; assert_eq!(account, AccountId::from(0)); diff --git a/src/data.rs b/src/data.rs index ffd384c..8305b0f 100644 --- a/src/data.rs +++ b/src/data.rs @@ -3,9 +3,10 @@ use std::io::{BufRead, BufReader, Write}; use std::path::{Path, PathBuf}; use secrecy::{SecretVec, Zeroize}; +use tracing::error; use zcash_client_sqlite::chain::BlockMeta; -use zcash_primitives::zip339::Mnemonic; +use zcash_primitives::{consensus::BlockHeight, zip339::Mnemonic}; use crate::error; @@ -57,10 +58,18 @@ pub(crate) fn get_keys_file>( pub(crate) fn get_wallet_seed>( wallet_dir: Option

, ) -> Result, anyhow::Error> { + let (seed, _) = get_wallet_seed_and_birthday(wallet_dir)?; + Ok(seed) +} + +pub(crate) fn get_wallet_seed_and_birthday>( + wallet_dir: Option

, +) -> Result<(SecretVec, BlockHeight), anyhow::Error> { let keys_file = get_keys_file(wallet_dir)?; + let mut keys_file_lines = keys_file.lines(); + let mnemonic = Mnemonic::from_phrase( - keys_file - .lines() + keys_file_lines .next() .ok_or(error::Error::InvalidKeysFile)?? .split('#') @@ -69,25 +78,22 @@ pub(crate) fn get_wallet_seed>( .trim(), )?; let mut seed = mnemonic.to_seed(""); - let secret = seed.to_vec(); + let secret = SecretVec::new(seed.to_vec()); seed.zeroize(); - Ok(SecretVec::new(secret)) -} -// fn get_wallet_birthday>(wallet_dir: Option

) -> Result { -// let keys_file = get_keys_file(wallet_dir)?; -// keys_file -// .lines() -// .nth(1) -// .ok_or(error::Error::InvalidKeysFile)?? -// .split('#') -// .next() -// .ok_or(error::Error::InvalidKeysFile)? -// .trim() -// .parse::() -// .map(BlockHeight::from) -// .map_err(|_| error::Error::InvalidKeysFile) -// } + let birthday = keys_file_lines + .next() + .ok_or(error::Error::InvalidKeysFile)?? + .split('#') + .next() + .ok_or(error::Error::InvalidKeysFile)? + .trim() + .parse::() + .map(BlockHeight::from) + .map_err(|_| error::Error::InvalidKeysFile)?; + + Ok((secret, birthday)) +} pub(crate) fn get_db_paths>(wallet_dir: Option

) -> (PathBuf, PathBuf) { let a = wallet_dir @@ -103,3 +109,21 @@ pub(crate) fn get_db_paths>(wallet_dir: Option

) -> (PathBuf, P pub(crate) fn get_block_path(fsblockdb_root: &Path, meta: &BlockMeta) -> PathBuf { meta.block_file_path(&fsblockdb_root.join(BLOCKS_FOLDER)) } + +pub(crate) async fn erase_wallet_state>(wallet_dir: Option

) { + let (fsblockdb_root, db_data) = get_db_paths(wallet_dir); + let blocks_meta = fsblockdb_root.join("blockmeta.sqlite"); + let blocks_folder = fsblockdb_root.join(BLOCKS_FOLDER); + + if let Err(e) = tokio::fs::remove_dir_all(&blocks_folder).await { + error!("Failed to remove {:?}: {}", blocks_folder, e); + } + + if let Err(e) = tokio::fs::remove_file(&blocks_meta).await { + error!("Failed to remove {:?}: {}", blocks_meta, e); + } + + if let Err(e) = tokio::fs::remove_file(&db_data).await { + error!("Failed to remove {:?}: {}", db_data, e); + } +} diff --git a/src/main.rs b/src/main.rs index 1c3138b..216b31a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -36,6 +36,9 @@ enum Command { #[options(help = "initialise a new light wallet")] Init(commands::init::Command), + #[options(help = "reset an existing light wallet to its initalised state")] + Reset(commands::reset::Command), + #[options(help = "upgrade an existing light wallet")] Upgrade(commands::upgrade::Command), @@ -80,6 +83,7 @@ fn main() -> Result<(), anyhow::Error> { runtime.block_on(async { match opts.command { Some(Command::Init(command)) => command.run(params, opts.wallet_dir).await, + Some(Command::Reset(command)) => command.run(params, opts.wallet_dir).await, Some(Command::Upgrade(command)) => command.run(params, opts.wallet_dir), Some(Command::Sync(command)) => command.run(params, opts.wallet_dir).await, Some(Command::Balance(command)) => command.run(params, opts.wallet_dir),