]> Untitled Git - bdk-cli/commitdiff
Handle errors properly instead of unwraps.
authorrajarshimaitra <rajarshi149@gmail.com>
Tue, 7 Dec 2021 14:02:07 +0000 (19:32 +0530)
committerrajarshimaitra <rajarshi149@gmail.com>
Fri, 10 Dec 2021 13:20:36 +0000 (18:50 +0530)
src/bdk_cli.rs
src/lib.rs

index f2eac5e9dbdf8e3a79e2eee6fdea9951d27e9666..4902b0301fd0290f4a795d4fc35318f040424220 100644 (file)
@@ -100,14 +100,16 @@ pub enum ReplSubCommand {
     Exit,
 }
 
-fn prepare_home_dir() -> PathBuf {
+fn prepare_home_dir() -> Result<PathBuf, Error> {
     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<Tree, Error> {
+    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<String, Error>
             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<String, Error>
             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<String, Error>
         }
         #[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<String, Error>
                         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, clap::Error> =
-                            ReplSubCommand::from_iter_safe(split_line);
+                            .collect::<Result<Vec<_>, 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<String, Error>
                             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<String, Error>
                 }
             }
 
-            // rl.save_history("history.txt").unwrap();
             "Exiting REPL".to_string()
         }
         #[cfg(all(feature = "reserves", feature = "electrum"))]
index 5a51a933f07d530b0b1a93226a5219dbc7e15c21..71c8d60f3233100f260198120540aa253ac46261 100644 (file)
@@ -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, String> {
-    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::<Vec<_>>();
+                .collect::<Result<Vec<_>, 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<PartiallySignedTransaction, Error>>(
@@ -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::<u8>::from_hex(&tx).unwrap()).unwrap(),
+                (None, Some(tx)) => deserialize(&Vec::<u8>::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::<bdk::keys::bip39::ErrorKind>().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())))