diff --git a/src/bitcoin/d/mod.rs b/src/bitcoin/d/mod.rs index a6f8ce48..9704ff83 100644 --- a/src/bitcoin/d/mod.rs +++ b/src/bitcoin/d/mod.rs @@ -183,7 +183,7 @@ impl BitcoinD { .url(&watchonly_url) .map_err(BitcoindError::from)? .timeout(Duration::from_secs(RPC_SOCKET_TIMEOUT)) - .cookie_auth(cookie_string.clone()) + .cookie_auth(cookie_string) .build(), ); @@ -249,7 +249,7 @@ impl BitcoinD { let res = resp.result().map_err(BitcoindError::Server)?; log::trace!("Got from bitcoind: {:#?}", res); - return Ok(res); + Ok(res) } Err(e) => Err(BitcoindError::Server(e)), } @@ -289,16 +289,14 @@ impl BitcoinD { fn get_bitcoind_version(&self) -> u64 { self.make_node_request("getnetworkinfo", &[]) .get("version") - .map(Json::as_u64) - .flatten() + .and_then(Json::as_u64) .expect("Missing or invalid 'version' in 'getnetworkinfo' result?") } fn get_network_bip70(&self) -> String { self.make_node_request("getblockchaininfo", &[]) .get("chain") - .map(Json::as_str) - .flatten() + .and_then(Json::as_str) .expect("Missing or invalid 'chain' in 'getblockchaininfo' result?") .to_string() } @@ -341,7 +339,7 @@ impl BitcoinD { ), ); - if let Some(warning) = res.get("warning").map(Json::as_str).flatten() { + if let Some(warning) = res.get("warning").and_then(Json::as_str) { if !warning.is_empty() { return Some(warning.to_string()); } @@ -365,12 +363,9 @@ impl BitcoinD { let all_succeeded = res .as_array() .map(|results| { - results.iter().all(|res| { - res.get("success") - .map(Json::as_bool) - .flatten() - .unwrap_or(false) - }) + results + .iter() + .all(|res| res.get("success").and_then(Json::as_bool).unwrap_or(false)) }) .unwrap_or(false); if all_succeeded { @@ -615,7 +610,7 @@ impl BitcoinD { .get("txid") .and_then(Json::as_str) .expect("A valid txid must be present"); - if visited_txs.contains(&spending_txid) || &spent_txid == spending_txid { + if visited_txs.contains(&spending_txid) || spent_txid == spending_txid { continue; } else { visited_txs.insert(spending_txid); @@ -729,7 +724,7 @@ impl From for LSBlockRes { .get("transactions") .and_then(Json::as_array) .expect("Array must be present") - .into_iter() + .iter() .filter_map(|j| { if j.get("category") .and_then(Json::as_str) @@ -770,7 +765,7 @@ impl From for GetTxRes { .and_then(Json::as_array) .map(|array| { array - .into_iter() + .iter() .map(|v| { bitcoin::Txid::from_str(v.as_str().expect("wrong json format")).unwrap() }) diff --git a/src/bitcoin/mod.rs b/src/bitcoin/mod.rs index ff60b615..f4c2df81 100644 --- a/src/bitcoin/mod.rs +++ b/src/bitcoin/mod.rs @@ -130,8 +130,8 @@ impl BitcoinInterface for d::BitcoinD { let mut spent = Vec::with_capacity(outpoints.len()); for op in outpoints { - if self.is_spent(&op) { - let spending_txid = if let Some(txid) = self.get_spender_txid(&op) { + if self.is_spent(op) { + let spending_txid = if let Some(txid) = self.get_spender_txid(op) { txid } else { // TODO: better handling of this edge case. @@ -180,7 +180,7 @@ impl BitcoinInterface for d::BitcoinD { let tx: Option<&d::GetTxRes> = match cache.get(txid) { Some(tx) => tx.as_ref(), None => { - let tx = self.get_transaction(&txid); + let tx = self.get_transaction(txid); txs_to_cache.push((*txid, tx)); txs_to_cache.last().unwrap().1.as_ref() } diff --git a/src/bitcoin/poller/looper.rs b/src/bitcoin/poller/looper.rs index 5afd7e85..2ade7202 100644 --- a/src/bitcoin/poller/looper.rs +++ b/src/bitcoin/poller/looper.rs @@ -30,7 +30,7 @@ fn update_coins( // Start by fetching newly received coins. let curr_coins = db_conn.unspent_coins(); let mut received = Vec::new(); - for utxo in bit.received_coins(&previous_tip) { + for utxo in bit.received_coins(previous_tip) { if let Some(derivation_index) = db_conn.derivation_index_by_address(&utxo.address) { if !curr_coins.contains_key(&utxo.outpoint) { let UTxO { @@ -119,7 +119,7 @@ fn new_tip(bit: &impl BitcoinInterface, current_tip: &BlockChainTip) -> Option current_tip.height { // Make sure we are on the same chain. - if bit.is_in_chain(¤t_tip) { + if bit.is_in_chain(current_tip) { // All good, we just moved forward. return Some(bitcoin_tip); } diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 5bdb6278..c94e0e0a 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -109,7 +109,7 @@ fn sanity_check_psbt(psbt: &Psbt) -> Result<(), CommandError> { value_in += psbtin .witness_utxo .as_ref() - .ok_or(CommandError::SanityCheckFailure(psbt.clone()))? + .ok_or_else(|| CommandError::SanityCheckFailure(psbt.clone()))? .value; } @@ -117,17 +117,17 @@ fn sanity_check_psbt(psbt: &Psbt) -> Result<(), CommandError> { let value_out: u64 = tx.output.iter().map(|o| o.value).sum(); let abs_fee = value_in .checked_sub(value_out) - .ok_or(CommandError::SanityCheckFailure(psbt.clone()))?; + .ok_or_else(|| CommandError::SanityCheckFailure(psbt.clone()))?; if abs_fee > MAX_FEE { return Err(CommandError::SanityCheckFailure(psbt.clone())); } // Check the feerate isn't insane. - let tx_vb: u64 = tx_vbytes(&tx); + let tx_vb: u64 = tx_vbytes(tx); let feerate_sats_vb = abs_fee .checked_div(tx_vb) - .ok_or(CommandError::SanityCheckFailure(psbt.clone()))?; - if feerate_sats_vb > MAX_FEERATE || feerate_sats_vb < 1 { + .ok_or_else(|| CommandError::SanityCheckFailure(psbt.clone()))?; + if !(1..=MAX_FEERATE).contains(&feerate_sats_vb) { return Err(CommandError::SanityCheckFailure(psbt.clone())); } @@ -188,7 +188,7 @@ impl DaemonControl { let address = self .config .main_descriptor - .derive(index.into(), &self.secp) + .derive(index, &self.secp) .address(self.config.bitcoin_config.network); GetAddressResult { address } } @@ -320,7 +320,7 @@ impl DaemonControl { // Get the change address to create a dummy change txo. // TODO: decent change management let first_coin = coins - .get(&coins_outpoints.get(0).expect("We checked it wasn't empty")) + .get(coins_outpoints.get(0).expect("We checked it wasn't empty")) .expect("We checked they were all present"); let coin_desc = self.derived_desc(first_coin.derivation_index); let mut change_txo = bitcoin::TxOut { @@ -696,13 +696,11 @@ mod tests { .iter() .cloned() .collect(); - let destinations_c: HashMap = [ - (dummy_addr_a.clone(), dummy_value_a), - (dummy_addr_b.clone(), dummy_value_b), - ] - .iter() - .cloned() - .collect(); + let destinations_c: HashMap = + [(dummy_addr_a, dummy_value_a), (dummy_addr_b, dummy_value_b)] + .iter() + .cloned() + .collect(); let mut psbt_a = control .create_spend(&[dummy_op_a], &destinations_a, 1) .unwrap() diff --git a/src/commands/utils.rs b/src/commands/utils.rs index 90dbc398..a736ebf5 100644 --- a/src/commands/utils.rs +++ b/src/commands/utils.rs @@ -48,11 +48,7 @@ pub fn change_index(psbt: &Psbt) -> Option { }; let tx = &psbt.global.unsigned_tx; - for i in (0..tx.output.len()).rev() { - if &tx.output[i].script_pubkey == first_coin_spk { - return Some(i); - } - } - - None + (0..tx.output.len()) + .rev() + .find(|&i| &tx.output[i].script_pubkey == first_coin_spk) } diff --git a/src/config.rs b/src/config.rs index 92ef7db2..8e8a0dd2 100644 --- a/src/config.rs +++ b/src/config.rs @@ -113,7 +113,7 @@ pub enum ConfigError { DatadirNotFound, FileNotFound, ReadingFile(String), - UnexpectedDescriptor(InheritanceDescriptor), + UnexpectedDescriptor(Box), Unexpected(String), } @@ -187,7 +187,7 @@ impl Config { /// futile duplication. pub fn from_file(custom_path: Option) -> Result { let config_file = - custom_path.unwrap_or(config_file_path().ok_or_else(|| ConfigError::DatadirNotFound)?); + custom_path.unwrap_or(config_file_path().ok_or(ConfigError::DatadirNotFound)?); let config = toml::from_slice::(&std::fs::read(&config_file)?) .map_err(|e| ConfigError::ReadingFile(format!("Parsing configuration file: {}", e)))?; diff --git a/src/database/mod.rs b/src/database/mod.rs index 5e181bf2..6cc0c300 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -61,16 +61,16 @@ pub trait DatabaseConnection { fn list_spending_coins(&mut self) -> HashMap; /// Store new UTxOs. Coins must not already be in database. - fn new_unspent_coins<'a>(&mut self, coins: &[Coin]); + fn new_unspent_coins(&mut self, coins: &[Coin]); /// Mark a set of coins as being confirmed at a specified height and block time. - fn confirm_coins<'a>(&mut self, outpoints: &[(bitcoin::OutPoint, i32, u32)]); + fn confirm_coins(&mut self, outpoints: &[(bitcoin::OutPoint, i32, u32)]); /// Mark a set of coins as being spent by a specified txid of a pending transaction. - fn spend_coins<'a>(&mut self, outpoints: &[(bitcoin::OutPoint, bitcoin::Txid)]); + fn spend_coins(&mut self, outpoints: &[(bitcoin::OutPoint, bitcoin::Txid)]); /// Mark a set of coins as spent by a specified txid at a specified block time. - fn confirm_spend<'a>(&mut self, outpoints: &[(bitcoin::OutPoint, bitcoin::Txid, u32)]); + fn confirm_spend(&mut self, outpoints: &[(bitcoin::OutPoint, bitcoin::Txid, u32)]); /// Get specific coins from the database. fn coins_by_outpoints( @@ -107,7 +107,7 @@ impl DatabaseConnection for SqliteConn { } fn update_tip(&mut self, tip: &BlockChainTip) { - self.update_tip(&tip) + self.update_tip(tip) } fn derivation_index(&mut self) -> bip32::ChildNumber { @@ -186,7 +186,7 @@ impl DatabaseConnection for SqliteConn { } } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Coin { pub outpoint: bitcoin::OutPoint, pub block_height: Option, @@ -221,12 +221,6 @@ impl std::convert::From for Coin { } } -impl std::hash::Hash for Coin { - fn hash(&self, h: &mut H) { - self.outpoint.hash(h) - } -} - impl Coin { pub fn is_confirmed(&self) -> bool { self.block_height.is_some() diff --git a/src/database/sqlite/mod.rs b/src/database/sqlite/mod.rs index cc114139..eb24d259 100644 --- a/src/database/sqlite/mod.rs +++ b/src/database/sqlite/mod.rs @@ -36,7 +36,7 @@ pub enum SqliteDbError { FileNotFound(path::PathBuf), UnsupportedVersion(i64), InvalidNetwork(bitcoin::Network), - DescriptorMismatch(InheritanceDescriptor), + DescriptorMismatch(Box), Rusqlite(rusqlite::Error), } @@ -102,7 +102,7 @@ impl SqliteDb { log::info!("Created a fresh database at {}.", db_path.display()); } if !db_path.exists() { - return Err(SqliteDbError::FileNotFound(db_path.to_path_buf())); + return Err(SqliteDbError::FileNotFound(db_path)); } Ok(SqliteDb { db_path }) @@ -139,7 +139,9 @@ impl SqliteDb { // The config and db descriptors must match! let db_wallet = conn.db_wallet(); if &db_wallet.main_descriptor != main_descriptor { - return Err(SqliteDbError::DescriptorMismatch(db_wallet.main_descriptor)); + return Err(SqliteDbError::DescriptorMismatch( + db_wallet.main_descriptor.into(), + )); } Ok(()) @@ -215,15 +217,13 @@ impl SqliteConn { let network = self.db_tip().network; db_exec(&mut self.conn, |db_tx| { - let db_wallet: DbWallet = db_tx_query( - &db_tx, - "SELECT * FROM wallets", - rusqlite::params![], - |row| row.try_into(), - ) - .expect("Db must not fail") - .pop() - .expect("There is always a row in the wallet table"); + let db_wallet: DbWallet = + db_tx_query(db_tx, "SELECT * FROM wallets", rusqlite::params![], |row| { + row.try_into() + }) + .expect("Db must not fail") + .pop() + .expect("There is always a row in the wallet table"); let next_index: u32 = db_wallet .deposit_derivation_index .increment() @@ -240,7 +240,7 @@ impl SqliteConn { let next_la_index = next_index + LOOK_AHEAD_LIMIT - 1; let next_la_address = db_wallet .main_descriptor - .derive(next_la_index.into(), &secp) + .derive(next_la_index.into(), secp) .address(network); db_tx .execute( @@ -470,7 +470,7 @@ mod tests { .iter() .collect(); let options = dummy_options(); - let db = SqliteDb::new(db_path.clone(), Some(options.clone()), &secp).unwrap(); + let db = SqliteDb::new(db_path, Some(options.clone()), &secp).unwrap(); (tmp_dir, options, secp, db) } @@ -510,7 +510,7 @@ mod tests { let db = SqliteDb::new(db_path.clone(), Some(options.clone()), &secp).unwrap(); db.sanity_check(bitcoin::Network::Bitcoin, &options.main_descriptor) .unwrap(); - let db = SqliteDb::new(db_path.clone(), None, &secp).unwrap(); + let db = SqliteDb::new(db_path, None, &secp).unwrap(); db.sanity_check(bitcoin::Network::Bitcoin, &options.main_descriptor) .unwrap(); @@ -607,14 +607,8 @@ mod tests { assert_eq!(coins[0].outpoint, coin_b.outpoint); let coins = conn.db_coins(&[coin_a.outpoint, coin_b.outpoint]); assert_eq!(coins.len(), 2); - assert!(coins - .iter() - .find(|c| c.outpoint == coin_a.outpoint) - .is_some()); - assert!(coins - .iter() - .find(|c| c.outpoint == coin_b.outpoint) - .is_some()); + assert!(coins.iter().any(|c| c.outpoint == coin_a.outpoint)); + assert!(coins.iter().any(|c| c.outpoint == coin_b.outpoint)); // Now if we confirm one, it'll be marked as such. let height = 174500; diff --git a/src/database/sqlite/schema.rs b/src/database/sqlite/schema.rs index e0478eaa..8a97696c 100644 --- a/src/database/sqlite/schema.rs +++ b/src/database/sqlite/schema.rs @@ -126,7 +126,7 @@ impl TryFrom<&rusqlite::Row<'_>> for DbWallet { } } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct DbCoin { pub id: i64, pub wallet_id: i64, @@ -139,12 +139,6 @@ pub struct DbCoin { pub spent_at: Option, } -impl std::hash::Hash for DbCoin { - fn hash(&self, h: &mut H) { - self.outpoint.hash(h) - } -} - impl TryFrom<&rusqlite::Row<'_>> for DbCoin { type Error = rusqlite::Error; diff --git a/src/database/sqlite/utils.rs b/src/database/sqlite/utils.rs index 1b0f07c4..b7cb6218 100644 --- a/src/database/sqlite/utils.rs +++ b/src/database/sqlite/utils.rs @@ -28,13 +28,9 @@ where P::Item: rusqlite::ToSql, F: FnMut(&rusqlite::Row<'_>) -> rusqlite::Result, { - // rustc says 'borrowed value does not live long enough' - let x = tx - .prepare(stmt_str)? + tx.prepare(stmt_str)? .query_map(params, f)? - .collect::>>(); - - x + .collect::>>() } /// Internal helper for queries boilerplate @@ -49,13 +45,9 @@ where P::Item: rusqlite::ToSql, F: FnMut(&rusqlite::Row<'_>) -> rusqlite::Result, { - // rustc says 'borrowed value does not live long enough' - let x = conn - .prepare(stmt_str)? + conn.prepare(stmt_str)? .query_map(params, f)? - .collect::>>(); - - x + .collect::>>() } // Sqlite supports up to i64, thus rusqlite prevents us from inserting u64's. diff --git a/src/descriptors.rs b/src/descriptors.rs index eb258ff1..0ddb7ac2 100644 --- a/src/descriptors.rs +++ b/src/descriptors.rs @@ -106,7 +106,7 @@ impl str::FromStr for DerivedPublicKey { return Err(DescCreationError::DerivedKeyParsing); } - let key = bitcoin::PublicKey::from_str(&key_str) + let key = bitcoin::PublicKey::from_str(key_str) .map_err(|_| DescCreationError::DerivedKeyParsing)?; Ok(DerivedPublicKey { @@ -434,31 +434,31 @@ mod tests { #[test] fn inheritance_descriptor_creation() { - let owner_key = descriptor::DescriptorPublicKey::from_str(&"xpub6Eze7yAT3Y1wGrnzedCNVYDXUqa9NmHVWck5emBaTbXtURbe1NWZbK9bsz1TiVE7Cz341PMTfYgFw1KdLWdzcM1UMFTcdQfCYhhXZ2HJvTW/*").unwrap(); - let heir_key = descriptor::DescriptorPublicKey::from_str(&"xpub688Hn4wScQAAiYJLPg9yH27hUpfZAUnmJejRQBCiwfP5PEDzjWMNW1wChcninxr5gyavFqbbDjdV1aK5USJz8NDVjUy7FRQaaqqXHh5SbXe/*").unwrap(); + let owner_key = descriptor::DescriptorPublicKey::from_str("xpub6Eze7yAT3Y1wGrnzedCNVYDXUqa9NmHVWck5emBaTbXtURbe1NWZbK9bsz1TiVE7Cz341PMTfYgFw1KdLWdzcM1UMFTcdQfCYhhXZ2HJvTW/*").unwrap(); + let heir_key = descriptor::DescriptorPublicKey::from_str("xpub688Hn4wScQAAiYJLPg9yH27hUpfZAUnmJejRQBCiwfP5PEDzjWMNW1wChcninxr5gyavFqbbDjdV1aK5USJz8NDVjUy7FRQaaqqXHh5SbXe/*").unwrap(); let timelock = 52560; assert_eq!(InheritanceDescriptor::new(owner_key.clone(), heir_key.clone(), timelock).unwrap().to_string(), "wsh(or_d(pk(xpub6Eze7yAT3Y1wGrnzedCNVYDXUqa9NmHVWck5emBaTbXtURbe1NWZbK9bsz1TiVE7Cz341PMTfYgFw1KdLWdzcM1UMFTcdQfCYhhXZ2HJvTW/*),and_v(v:pkh(xpub688Hn4wScQAAiYJLPg9yH27hUpfZAUnmJejRQBCiwfP5PEDzjWMNW1wChcninxr5gyavFqbbDjdV1aK5USJz8NDVjUy7FRQaaqqXHh5SbXe/*),older(52560))))#eeyujkt7"); // We prevent footguns with timelocks InheritanceDescriptor::new(owner_key.clone(), heir_key.clone(), 0x00_01_0f_00).unwrap_err(); InheritanceDescriptor::new(owner_key.clone(), heir_key.clone(), (1 << 31) + 1).unwrap_err(); - InheritanceDescriptor::new(owner_key.clone(), heir_key.clone(), (1 << 22) + 1).unwrap_err(); + InheritanceDescriptor::new(owner_key, heir_key, (1 << 22) + 1).unwrap_err(); - let owner_key = descriptor::DescriptorPublicKey::from_str(&"[aabb0011/10/4893]xpub661MyMwAqRbcFG59fiikD8UV762quhruT8K8bdjqy6N2o3LG7yohoCdLg1m2HAY1W6rfBrtauHkBhbfA4AQ3iazaJj5wVPhwgaRCHBW2DBg/*").unwrap(); - let heir_key = descriptor::DescriptorPublicKey::from_str(&"xpub661MyMwAqRbcFfxf71L4Dx4w5TmyNXrBicTEAM7vLzumxangwATWWgdJPb6xH1JHcJH9S3jNZx3fCnkkB1WyqrqGgavj1rehHcbythmruvZ/24/32/*").unwrap(); + let owner_key = descriptor::DescriptorPublicKey::from_str("[aabb0011/10/4893]xpub661MyMwAqRbcFG59fiikD8UV762quhruT8K8bdjqy6N2o3LG7yohoCdLg1m2HAY1W6rfBrtauHkBhbfA4AQ3iazaJj5wVPhwgaRCHBW2DBg/*").unwrap(); + let heir_key = descriptor::DescriptorPublicKey::from_str("xpub661MyMwAqRbcFfxf71L4Dx4w5TmyNXrBicTEAM7vLzumxangwATWWgdJPb6xH1JHcJH9S3jNZx3fCnkkB1WyqrqGgavj1rehHcbythmruvZ/24/32/*").unwrap(); let timelock = 57600; assert_eq!(InheritanceDescriptor::new(owner_key.clone(), heir_key, timelock).unwrap().to_string(), "wsh(or_d(pk([aabb0011/10/4893]xpub661MyMwAqRbcFG59fiikD8UV762quhruT8K8bdjqy6N2o3LG7yohoCdLg1m2HAY1W6rfBrtauHkBhbfA4AQ3iazaJj5wVPhwgaRCHBW2DBg/*),and_v(v:pkh(xpub661MyMwAqRbcFfxf71L4Dx4w5TmyNXrBicTEAM7vLzumxangwATWWgdJPb6xH1JHcJH9S3jNZx3fCnkkB1WyqrqGgavj1rehHcbythmruvZ/24/32/*),older(57600))))#8kamh6y8"); // We can't pass a raw key, an xpub that is not deriveable, or only hardened derivable - let heir_key = descriptor::DescriptorPublicKey::from_str(&"xpub661MyMwAqRbcFfxf71L4Dx4w5TmyNXrBicTEAM7vLzumxangwATWWgdJPb6xH1JHcJH9S3jNZx3fCnkkB1WyqrqGgavj1rehHcbythmruvZ/0/354").unwrap(); + let heir_key = descriptor::DescriptorPublicKey::from_str("xpub661MyMwAqRbcFfxf71L4Dx4w5TmyNXrBicTEAM7vLzumxangwATWWgdJPb6xH1JHcJH9S3jNZx3fCnkkB1WyqrqGgavj1rehHcbythmruvZ/0/354").unwrap(); InheritanceDescriptor::new(owner_key.clone(), heir_key, timelock).unwrap_err(); - let heir_key = descriptor::DescriptorPublicKey::from_str(&"xpub661MyMwAqRbcFfxf71L4Dx4w5TmyNXrBicTEAM7vLzumxangwATWWgdJPb6xH1JHcJH9S3jNZx3fCnkkB1WyqrqGgavj1rehHcbythmruvZ/0/*'").unwrap(); + let heir_key = descriptor::DescriptorPublicKey::from_str("xpub661MyMwAqRbcFfxf71L4Dx4w5TmyNXrBicTEAM7vLzumxangwATWWgdJPb6xH1JHcJH9S3jNZx3fCnkkB1WyqrqGgavj1rehHcbythmruvZ/0/*'").unwrap(); InheritanceDescriptor::new(owner_key.clone(), heir_key, timelock).unwrap_err(); let heir_key = descriptor::DescriptorPublicKey::from_str( - &"02e24913be26dbcfdf8e8e94870b28725cdae09b448b6c127767bf0154e3a3c8e5", + "02e24913be26dbcfdf8e8e94870b28725cdae09b448b6c127767bf0154e3a3c8e5", ) .unwrap(); - InheritanceDescriptor::new(owner_key.clone(), heir_key, timelock).unwrap_err(); + InheritanceDescriptor::new(owner_key, heir_key, timelock).unwrap_err(); } #[test] diff --git a/src/jsonrpc/api.rs b/src/jsonrpc/api.rs index 9a08ad35..1d480e46 100644 --- a/src/jsonrpc/api.rs +++ b/src/jsonrpc/api.rs @@ -10,38 +10,38 @@ use miniscript::bitcoin::{self, consensus, util::psbt::PartiallySignedTransactio fn create_spend(control: &DaemonControl, params: Params) -> Result { let outpoints = params .get(0, "outpoints") - .ok_or(Error::invalid_params("Missing 'outpoints' parameter."))? + .ok_or_else(|| Error::invalid_params("Missing 'outpoints' parameter."))? .as_array() .and_then(|arr| { - arr.into_iter() + arr.iter() .map(|entry| { entry .as_str() - .and_then(|e| bitcoin::OutPoint::from_str(&e).ok()) + .and_then(|e| bitcoin::OutPoint::from_str(e).ok()) }) .collect::>>() }) - .ok_or(Error::invalid_params("Invalid 'outpoints' parameter."))?; + .ok_or_else(|| Error::invalid_params("Invalid 'outpoints' parameter."))?; let destinations = params .get(1, "destinations") - .ok_or(Error::invalid_params("Missing 'destinations' parameter."))? + .ok_or_else(|| Error::invalid_params("Missing 'destinations' parameter."))? .as_object() .and_then(|obj| { obj.into_iter() .map(|(k, v)| { - let addr = bitcoin::Address::from_str(&k).ok()?; + let addr = bitcoin::Address::from_str(k).ok()?; let amount: u64 = v.as_i64()?.try_into().ok()?; Some((addr, amount)) }) .collect::>>() }) - .ok_or(Error::invalid_params("Invalid 'destinations' parameter."))?; + .ok_or_else(|| Error::invalid_params("Invalid 'destinations' parameter."))?; let feerate: u64 = params .get(2, "feerate") - .ok_or(Error::invalid_params("Missing 'feerate' parameter."))? + .ok_or_else(|| Error::invalid_params("Missing 'feerate' parameter."))? .as_i64() .and_then(|i| i.try_into().ok()) - .ok_or(Error::invalid_params("Invalid 'feerate' parameter."))?; + .ok_or_else(|| Error::invalid_params("Invalid 'feerate' parameter."))?; let res = control.create_spend(&outpoints, &destinations, feerate)?; Ok(serde_json::json!(&res)) @@ -50,11 +50,11 @@ fn create_spend(control: &DaemonControl, params: Params) -> Result Result { let psbt: Psbt = params .get(0, "psbt") - .ok_or(Error::invalid_params("Missing 'psbt' parameter."))? + .ok_or_else(|| Error::invalid_params("Missing 'psbt' parameter."))? .as_str() .and_then(|s| base64::decode(&s).ok()) .and_then(|bytes| consensus::deserialize(&bytes).ok()) - .ok_or(Error::invalid_params("Invalid 'feerate' parameter."))?; + .ok_or_else(|| Error::invalid_params("Invalid 'feerate' parameter."))?; control.update_spend(psbt)?; Ok(serde_json::json!({})) @@ -63,10 +63,10 @@ fn update_spend(control: &DaemonControl, params: Params) -> Result Result { let txid = params .get(0, "txid") - .ok_or(Error::invalid_params("Missing 'txid' parameter."))? + .ok_or_else(|| Error::invalid_params("Missing 'txid' parameter."))? .as_str() - .and_then(|s| bitcoin::Txid::from_str(&s).ok()) - .ok_or(Error::invalid_params("Invalid 'feerate' parameter."))?; + .and_then(|s| bitcoin::Txid::from_str(s).ok()) + .ok_or_else(|| Error::invalid_params("Invalid 'feerate' parameter."))?; control.delete_spend(&txid); Ok(serde_json::json!({})) @@ -76,15 +76,17 @@ fn delete_spend(control: &DaemonControl, params: Params) -> Result Result { let result = match req.method.as_str() { "createspend" => { - let params = req.params.ok_or(Error::invalid_params( - "Missing 'outpoints', 'destinations' and 'feerate' parameters.", - ))?; + let params = req.params.ok_or_else(|| { + Error::invalid_params( + "Missing 'outpoints', 'destinations' and 'feerate' parameters.", + ) + })?; create_spend(control, params)? } "delspendtx" => { let params = req .params - .ok_or(Error::invalid_params("Missing 'txid' parameter."))?; + .ok_or_else(|| Error::invalid_params("Missing 'txid' parameter."))?; delete_spend(control, params)? } "getinfo" => serde_json::json!(&control.get_info()), @@ -95,7 +97,7 @@ pub fn handle_request(control: &DaemonControl, req: Request) -> Result { let params = req .params - .ok_or(Error::invalid_params("Missing 'psbt' parameter."))?; + .ok_or_else(|| Error::invalid_params("Missing 'psbt' parameter."))?; update_spend(control, params)? } _ => { diff --git a/src/jsonrpc/mod.rs b/src/jsonrpc/mod.rs index 91683a75..7bde56f0 100644 --- a/src/jsonrpc/mod.rs +++ b/src/jsonrpc/mod.rs @@ -7,7 +7,7 @@ use std::{error, fmt}; use serde::{self, Deserialize, Deserializer, Serialize, Serializer}; -#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] #[serde(deny_unknown_fields)] #[serde(untagged)] pub enum Params { @@ -29,7 +29,7 @@ impl Params { } } -#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] #[serde(deny_unknown_fields)] #[serde(untagged)] pub enum ReqId { @@ -38,7 +38,7 @@ pub enum ReqId { } /// A JSONRPC2 request. See https://www.jsonrpc.org/specification#request_object. -#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] #[serde(deny_unknown_fields)] pub struct Request { /// Version. Must be "2.0". @@ -52,7 +52,7 @@ pub struct Request { } /// JSONRPC2 error codes. See https://www.jsonrpc.org/specification#error_object. -#[derive(Debug, PartialEq, Clone)] +#[derive(Debug, PartialEq, Eq, Clone)] pub enum ErrorCode { /// The method does not exist / is not available. MethodNotFound, @@ -64,9 +64,9 @@ pub enum ErrorCode { ServerError(i64), } -impl Into for &ErrorCode { - fn into(self) -> i64 { - match self { +impl From<&ErrorCode> for i64 { + fn from(code: &ErrorCode) -> i64 { + match code { ErrorCode::MethodNotFound => -32601, ErrorCode::InvalidParams => -32602, ErrorCode::InternalError => -32603, @@ -105,7 +105,7 @@ impl Serialize for ErrorCode { } /// JSONRPC2 error response. See https://www.jsonrpc.org/specification#error_object. -#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] +#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] #[serde(deny_unknown_fields)] pub struct Error { pub code: ErrorCode, @@ -164,7 +164,7 @@ impl From for Error { } /// JSONRPC2 response. See https://www.jsonrpc.org/specification#response_object. -#[derive(Clone, Debug, PartialEq, Serialize)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize)] #[serde(deny_unknown_fields)] pub struct Response { /// Version. Must be "2.0". diff --git a/src/jsonrpc/server.rs b/src/jsonrpc/server.rs index ce18f94a..29acaa0b 100644 --- a/src/jsonrpc/server.rs +++ b/src/jsonrpc/server.rs @@ -196,7 +196,9 @@ pub fn rpcserver_setup(socket_path: &path::Path) -> Result> = req.into_iter().map(|c| vec![*c]).collect(); + let tmp: Vec> = req.iter().map(|c| vec![*c]).collect(); let mut to_send: Vec<&[u8]> = tmp.iter().map(|v| v.as_slice()).collect(); to_send.push(b"\n"); write_messages(&socket_path, &to_send); diff --git a/src/lib.rs b/src/lib.rs index 6c282cb1..702a9c87 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -497,7 +497,7 @@ mod tests { } // Send them a response to 'listwallets' with the watchonly wallet path - fn complete_wallet_check<'a>(server: &net::TcpListener, watchonly_wallet_path: &'a str) { + fn complete_wallet_check(server: &net::TcpListener, watchonly_wallet_path: &str) { let net_resp = [ "HTTP/1.1 200\n\r\n{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":[\"".as_bytes(), watchonly_wallet_path.as_bytes(), @@ -511,7 +511,7 @@ mod tests { } // Send them a response to 'listdescriptors' with the main descriptor - fn complete_desc_check<'a>(server: &net::TcpListener, desc: &'a str) { + fn complete_desc_check(server: &net::TcpListener, desc: &str) { let net_resp = [ "HTTP/1.1 200\n\r\n{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":{\"descriptors\":[{\"desc\":\"".as_bytes(), desc.as_bytes(), @@ -525,7 +525,7 @@ mod tests { } // Send them a response to 'getblockhash' with the genesis block hash - fn complete_tip_init<'a>(server: &net::TcpListener) { + fn complete_tip_init(server: &net::TcpListener) { let net_resp = [ "HTTP/1.1 200\n\r\n{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":\"000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f\"}\n".as_bytes(), ] @@ -537,7 +537,7 @@ mod tests { } // Send them a response to 'getblockchaininfo' saying we are far from being synced - fn complete_sync_check<'a>(server: &net::TcpListener) { + fn complete_sync_check(server: &net::TcpListener) { let net_resp = [ "HTTP/1.1 200\n\r\n{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":{\"verificationprogress\":0.1}}\n".as_bytes(), ] @@ -590,7 +590,7 @@ mod tests { }; let bitcoind_config = BitcoindConfig { addr, - cookie_path: cookie.clone(), + cookie_path: cookie, }; // Create a dummy config with this bitcoind @@ -599,7 +599,7 @@ mod tests { let config = Config { bitcoin_config, bitcoind_config: Some(bitcoind_config), - data_dir: Some(data_dir.clone()), + data_dir: Some(data_dir), #[cfg(unix)] daemon: false, log_level: log::LevelFilter::Debug, diff --git a/src/testutils.rs b/src/testutils.rs index 3803f99f..54a9cbb1 100644 --- a/src/testutils.rs +++ b/src/testutils.rs @@ -82,6 +82,12 @@ impl DummyDb { } } +impl Default for DummyDb { + fn default() -> DummyDb { + DummyDb::new() + } +} + impl DatabaseInterface for sync::Arc> { fn connection(&self) -> Box { Box::new(DummyDbConn { db: self.clone() }) @@ -121,8 +127,8 @@ impl DatabaseConnection for DummyDbConn { fn list_spending_coins(&mut self) -> HashMap { let mut result = HashMap::new(); for (k, v) in self.db.read().unwrap().coins.iter() { - if !v.spend_txid.is_none() { - result.insert(k.clone(), v.clone()); + if v.spend_txid.is_some() { + result.insert(*k, v.clone()); } } result @@ -163,7 +169,7 @@ impl DatabaseConnection for DummyDbConn { for (op, spend_txid, time) in outpoints { let mut db = self.db.write().unwrap(); let spent = &mut db.coins.get_mut(op).unwrap(); - assert!(!spent.spend_txid.is_none()); + assert!(spent.spend_txid.is_some()); assert!(spent.spent_at.is_none()); spent.spend_txid = Some(*spend_txid); spent.spent_at = Some(*time); @@ -185,7 +191,7 @@ impl DatabaseConnection for DummyDbConn { .coins .clone() .into_iter() - .filter(|(op, _)| outpoints.contains(&op)) + .filter(|(op, _)| outpoints.contains(op)) .collect() } @@ -260,7 +266,7 @@ impl DummyMinisafe { let config = Config { bitcoin_config, bitcoind_config: None, - data_dir: Some(data_dir.clone()), + data_dir: Some(data_dir), #[cfg(unix)] daemon: false, log_level: log::LevelFilter::Debug,