diff --git a/src/bdk_cli.rs b/src/bdk_cli.rs index f2eac5e..4902b03 100644 --- a/src/bdk_cli.rs +++ b/src/bdk_cli.rs @@ -100,14 +100,16 @@ pub enum ReplSubCommand { Exit, } -fn prepare_home_dir() -> PathBuf { +fn prepare_home_dir() -> Result { let mut dir = PathBuf::new(); - dir.push(&dirs_next::home_dir().unwrap()); + dir.push( + &dirs_next::home_dir().ok_or_else(|| Error::Generic("home dir not found".to_string()))?, + ); dir.push(".bdk-bitcoin"); if !dir.exists() { info!("Creating home directory {}", dir.as_path().display()); - fs::create_dir(&dir).unwrap(); + fs::create_dir(&dir).map_err(|e| Error::Generic(e.to_string()))?; } #[cfg(not(feature = "compact_filters"))] @@ -115,16 +117,16 @@ fn prepare_home_dir() -> PathBuf { #[cfg(feature = "compact_filters")] dir.push("compact_filters"); - dir + Ok(dir) } -fn open_database(wallet_opts: &WalletOpts) -> Tree { - let mut database_path = prepare_home_dir(); +fn open_database(wallet_opts: &WalletOpts) -> Result { + let mut database_path = prepare_home_dir()?; database_path.push(wallet_opts.wallet.clone()); - let database = sled::open(database_path).unwrap(); - let tree = database.open_tree(&wallet_opts.wallet).unwrap(); + let database = sled::open(database_path)?; + let tree = database.open_tree(&wallet_opts.wallet)?; debug!("database opened successfully"); - tree + Ok(tree) } #[cfg(any( @@ -183,7 +185,10 @@ where AnyBlockchainConfig::CompactFilters(CompactFiltersBlockchainConfig { peers, network, - storage_dir: prepare_home_dir().into_os_string().into_string().unwrap(), + storage_dir: prepare_home_dir()? + .into_os_string() + .into_string() + .map_err(|_| Error::Generic("Internal OS_String conversion error".to_string()))?, skip_blocks: Some(wallet_opts.compactfilter_opts.skip_blocks), }) }; @@ -277,7 +282,7 @@ fn handle_command(cli_opts: CliOpts, network: Network) -> Result wallet_opts, subcommand: WalletSubCommand::OnlineWalletSubCommand(online_subcommand), } => { - let database = open_database(&wallet_opts); + let database = open_database(&wallet_opts)?; let wallet = new_online_wallet(network, &wallet_opts, database)?; let result = bdk_cli::handle_online_wallet_subcommand(&wallet, online_subcommand)?; serde_json::to_string_pretty(&result)? @@ -286,7 +291,7 @@ fn handle_command(cli_opts: CliOpts, network: Network) -> Result wallet_opts, subcommand: WalletSubCommand::OfflineWalletSubCommand(offline_subcommand), } => { - let database = open_database(&wallet_opts); + let database = open_database(&wallet_opts)?; let wallet = new_offline_wallet(network, &wallet_opts, database)?; let result = bdk_cli::handle_offline_wallet_subcommand( &wallet, @@ -311,7 +316,7 @@ fn handle_command(cli_opts: CliOpts, network: Network) -> Result } #[cfg(feature = "repl")] CliSubCommand::Repl { wallet_opts } => { - let database = open_database(&wallet_opts); + let database = open_database(&wallet_opts)?; #[cfg(any( feature = "electrum", @@ -349,24 +354,17 @@ fn handle_command(cli_opts: CliOpts, network: Network) -> Result let split_line: Vec<&str> = split_regex .captures_iter(&line) .map(|c| { - c.get(1) + Ok(c.get(1) .or_else(|| c.get(2)) .or_else(|| c.get(3)) - .unwrap() - .as_str() + .ok_or_else(|| Error::Generic("Invalid commands".to_string()))? + .as_str()) }) - .collect(); - let repl_subcommand: Result = - ReplSubCommand::from_iter_safe(split_line); + .collect::, Error>>()?; + let repl_subcommand = ReplSubCommand::from_iter_safe(split_line) + .map_err(|e| Error::Generic(e.to_string()))?; debug!("repl_subcommand = {:?}", repl_subcommand); - if let Err(err) = repl_subcommand { - println!("{}", err.message); - continue; - } - - let repl_subcommand = repl_subcommand.unwrap(); - let result = match repl_subcommand { #[cfg(any( feature = "electrum", @@ -390,10 +388,7 @@ fn handle_command(cli_opts: CliOpts, network: Network) -> Result ReplSubCommand::Exit => break, }; - println!( - "{}", - serde_json::to_string_pretty(&result.unwrap()).unwrap() - ); + println!("{}", serde_json::to_string_pretty(&result?)?); } Err(ReadlineError::Interrupted) => continue, Err(ReadlineError::Eof) => break, @@ -404,7 +399,6 @@ fn handle_command(cli_opts: CliOpts, network: Network) -> Result } } - // rl.save_history("history.txt").unwrap(); "Exiting REPL".to_string() } #[cfg(all(feature = "reserves", feature = "electrum"))] diff --git a/src/lib.rs b/src/lib.rs index 5a51a93..71c8d60 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -877,17 +877,10 @@ fn parse_recipient(s: &str) -> Result<(Script, u64), String> { if parts.len() != 2 { return Err("Invalid format".to_string()); } + let addr = Address::from_str(parts[0]).map_err(|e| e.to_string())?; + let val = u64::from_str(parts[1]).map_err(|e| e.to_string())?; - let addr = Address::from_str(parts[0]); - if let Err(e) = addr { - return Err(format!("{:?}", e)); - } - let val = u64::from_str(parts[1]); - if let Err(e) = val { - return Err(format!("{:?}", e)); - } - - Ok((addr.unwrap().script_pubkey(), val.unwrap())) + Ok((addr.script_pubkey(), val)) } #[cfg(any( feature = "electrum", @@ -908,7 +901,7 @@ fn parse_proxy_auth(s: &str) -> Result<(String, String), String> { } fn parse_outpoint(s: &str) -> Result { - OutPoint::from_str(s).map_err(|e| format!("{:?}", e)) + OutPoint::from_str(s).map_err(|e| e.to_string()) } /// Execute an offline wallet sub-command @@ -1034,8 +1027,7 @@ where assume_height, trust_witness_utxo, } => { - let psbt = base64::decode(&psbt) - .map_err(|e| Error::Generic(format!("Base64 decode error: {:?}", e)))?; + let psbt = base64::decode(&psbt).map_err(|e| Error::Generic(e.to_string()))?; let mut psbt: PartiallySignedTransaction = deserialize(&psbt)?; let signopt = SignOptions { assume_height, @@ -1052,8 +1044,8 @@ where } } ExtractPsbt { psbt } => { - let psbt = base64::decode(&psbt).unwrap(); - let psbt: PartiallySignedTransaction = deserialize(&psbt).unwrap(); + let psbt = base64::decode(&psbt).map_err(|e| Error::Generic(e.to_string()))?; + let psbt: PartiallySignedTransaction = deserialize(&psbt)?; Ok(json!({"raw_tx": serialize_hex(&psbt.extract_tx()),})) } FinalizePsbt { @@ -1061,8 +1053,8 @@ where assume_height, trust_witness_utxo, } => { - let psbt = base64::decode(&psbt).unwrap(); - let mut psbt: PartiallySignedTransaction = deserialize(&psbt).unwrap(); + let psbt = base64::decode(&psbt).map_err(|e| Error::Generic(e.to_string()))?; + let mut psbt: PartiallySignedTransaction = deserialize(&psbt)?; let signopt = SignOptions { assume_height, @@ -1082,13 +1074,15 @@ where let mut psbts = psbt .iter() .map(|s| { - let psbt = base64::decode(&s).unwrap(); - let psbt: PartiallySignedTransaction = deserialize(&psbt).unwrap(); - psbt + let psbt = base64::decode(&s).map_err(|e| Error::Generic(e.to_string()))?; + let psbt: PartiallySignedTransaction = deserialize(&psbt)?; + Ok(psbt) }) - .collect::>(); + .collect::, Error>>()?; - let init_psbt = psbts.pop().unwrap(); + let init_psbt = psbts + .pop() + .ok_or_else(|| Error::Generic("Invalid PSBT input".to_string()))?; let final_psbt = psbts .into_iter() .try_fold::<_, _, Result>( @@ -1130,11 +1124,11 @@ where Broadcast { psbt, tx } => { let tx = match (psbt, tx) { (Some(psbt), None) => { - let psbt = base64::decode(&psbt).unwrap(); - let psbt: PartiallySignedTransaction = deserialize(&psbt).unwrap(); + let psbt = base64::decode(&psbt).map_err(|e| Error::Generic(e.to_string()))?; + let psbt: PartiallySignedTransaction = deserialize(&psbt)?; psbt.extract_tx() } - (None, Some(tx)) => deserialize(&Vec::::from_hex(&tx).unwrap()).unwrap(), + (None, Some(tx)) => deserialize(&Vec::::from_hex(&tx)?)?, (Some(_), Some(_)) => panic!("Both `psbt` and `tx` options not allowed"), (None, None) => panic!("Missing `psbt` and `tx` option"), }; @@ -1261,11 +1255,13 @@ pub fn handle_key_subcommand( _ => WordCount::Words24, }; let mnemonic: GeneratedKey<_, miniscript::BareCtx> = - Mnemonic::generate((mnemonic_type, Language::English)).unwrap(); - //.map_err(|e| KeyError::from(e.unwrap()))?; + Mnemonic::generate((mnemonic_type, Language::English)) + .map_err(|_| Error::Generic("Mnemonic generation error".to_string()))?; let mnemonic = mnemonic.into_key(); let xkey: ExtendedKey = (mnemonic.clone(), password).into_extended_key()?; - let xprv = xkey.into_xprv(network).unwrap(); + let xprv = xkey.into_xprv(network).ok_or_else(|| { + Error::Generic("Privatekey info not found (should not happen)".to_string()) + })?; let fingerprint = xprv.fingerprint(&secp); let phrase = mnemonic .word_iter() @@ -1277,12 +1273,12 @@ pub fn handle_key_subcommand( ) } KeySubCommand::Restore { mnemonic, password } => { - let mnemonic = Mnemonic::parse(mnemonic).unwrap(); - // .map_err(|e| { - // KeyError::from(e.downcast::().unwrap()) - // })?; + let mnemonic = Mnemonic::parse_in(Language::English, mnemonic) + .map_err(|e| Error::Generic(e.to_string()))?; let xkey: ExtendedKey = (mnemonic, password).into_extended_key()?; - let xprv = xkey.into_xprv(network).unwrap(); + let xprv = xkey.into_xprv(network).ok_or_else(|| { + Error::Generic("Privatekey info not found (should not happen)".to_string()) + })?; let fingerprint = xprv.fingerprint(&secp); Ok(json!({ "xprv": xprv.to_string(), "fingerprint": fingerprint.to_string() })) @@ -1299,7 +1295,9 @@ pub fn handle_key_subcommand( derived_xprv.into_descriptor_key(Some(origin), DerivationPath::default())?; if let Secret(desc_seckey, _, _) = derived_xprv_desc_key { - let desc_pubkey = desc_seckey.as_public(&secp).unwrap(); + let desc_pubkey = desc_seckey + .as_public(&secp) + .map_err(|e| Error::Generic(e.to_string()))?; Ok(json!({"xpub": desc_pubkey.to_string(), "xprv": desc_seckey.to_string()})) } else { Err(Error::Key(Message("Invalid key variant".to_string())))