Add reset command

This makes it simpler to re-initialize the wallet without needing to
load in the existing mnemonic phrase again.
This commit is contained in:
Jack Grigg 2023-11-10 05:00:56 +00:00
parent 9a5b97898b
commit 2cc7637342
4 changed files with 68 additions and 27 deletions

View File

@ -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;

View File

@ -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<Channel>,
params: impl Parameters + 'static,
wallet_dir: Option<String>,
seed: SecretVec<u8>,
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));

View File

@ -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<P: AsRef<Path>>(
pub(crate) fn get_wallet_seed<P: AsRef<Path>>(
wallet_dir: Option<P>,
) -> Result<SecretVec<u8>, anyhow::Error> {
let (seed, _) = get_wallet_seed_and_birthday(wallet_dir)?;
Ok(seed)
}
pub(crate) fn get_wallet_seed_and_birthday<P: AsRef<Path>>(
wallet_dir: Option<P>,
) -> Result<(SecretVec<u8>, 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<P: AsRef<Path>>(
.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<P: AsRef<Path>>(wallet_dir: Option<P>) -> Result<BlockHeight, error::Error> {
// 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::<u32>()
// .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::<u32>()
.map(BlockHeight::from)
.map_err(|_| error::Error::InvalidKeysFile)?;
Ok((secret, birthday))
}
pub(crate) fn get_db_paths<P: AsRef<Path>>(wallet_dir: Option<P>) -> (PathBuf, PathBuf) {
let a = wallet_dir
@ -103,3 +109,21 @@ pub(crate) fn get_db_paths<P: AsRef<Path>>(wallet_dir: Option<P>) -> (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<P: AsRef<Path>>(wallet_dir: Option<P>) {
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);
}
}

View File

@ -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),