From 88307045b0f049b7f6b9c0cdc577c4a4bb3a041e Mon Sep 17 00:00:00 2001 From: Vladimir Fomene Date: Wed, 7 Sep 2022 20:45:22 +0300 Subject: [PATCH] Add more test to the database module This PR aims to add more test to database code so that we can catch bugs as soon as they occur. Contributing to fixing issue #699. --- src/database/keyvalue.rs | 40 +++++++ src/database/memory.rs | 40 +++++++ src/database/mod.rs | 219 ++++++++++++++++++++++++++++++++++++++- src/database/sqlite.rs | 40 +++++++ 4 files changed, 337 insertions(+), 2 deletions(-) diff --git a/src/database/keyvalue.rs b/src/database/keyvalue.rs index e10ada1f..f586ebeb 100644 --- a/src/database/keyvalue.rs +++ b/src/database/keyvalue.rs @@ -492,4 +492,44 @@ mod test { fn test_sync_time() { crate::database::test::test_sync_time(get_tree()); } + + #[test] + fn test_iter_raw_txs() { + crate::database::test::test_iter_raw_txs(get_tree()); + } + + #[test] + fn test_del_path_from_script_pubkey() { + crate::database::test::test_del_path_from_script_pubkey(get_tree()); + } + + #[test] + fn test_iter_script_pubkeys() { + crate::database::test::test_iter_script_pubkeys(get_tree()); + } + + #[test] + fn test_del_utxo() { + crate::database::test::test_del_utxo(get_tree()); + } + + #[test] + fn test_del_raw_tx() { + crate::database::test::test_del_raw_tx(get_tree()); + } + + #[test] + fn test_del_tx() { + crate::database::test::test_del_tx(get_tree()); + } + + #[test] + fn test_del_last_index() { + crate::database::test::test_del_last_index(get_tree()); + } + + #[test] + fn test_check_descriptor_checksum() { + crate::database::test::test_check_descriptor_checksum(get_tree()); + } } diff --git a/src/database/memory.rs b/src/database/memory.rs index eff5ecf1..691e7eb1 100644 --- a/src/database/memory.rs +++ b/src/database/memory.rs @@ -647,4 +647,44 @@ mod test { fn test_sync_time() { crate::database::test::test_sync_time(get_tree()); } + + #[test] + fn test_iter_raw_txs() { + crate::database::test::test_iter_raw_txs(get_tree()); + } + + #[test] + fn test_del_path_from_script_pubkey() { + crate::database::test::test_del_path_from_script_pubkey(get_tree()); + } + + #[test] + fn test_iter_script_pubkeys() { + crate::database::test::test_iter_script_pubkeys(get_tree()); + } + + #[test] + fn test_del_utxo() { + crate::database::test::test_del_utxo(get_tree()); + } + + #[test] + fn test_del_raw_tx() { + crate::database::test::test_del_raw_tx(get_tree()); + } + + #[test] + fn test_del_tx() { + crate::database::test::test_del_tx(get_tree()); + } + + #[test] + fn test_del_last_index() { + crate::database::test::test_del_last_index(get_tree()); + } + + #[test] + fn test_check_descriptor_checksum() { + crate::database::test::test_check_descriptor_checksum(get_tree()); + } } diff --git a/src/database/mod.rs b/src/database/mod.rs index c7ff1795..711dea7e 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -217,6 +217,7 @@ pub mod test { use std::str::FromStr; use bitcoin::consensus::encode::deserialize; + use bitcoin::consensus::serialize; use bitcoin::hashes::hex::*; use bitcoin::*; @@ -322,8 +323,24 @@ pub mod test { } pub fn test_raw_tx(mut tree: D) { - let hex_tx = Vec::::from_hex("0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000").unwrap(); - let tx: Transaction = deserialize(&hex_tx).unwrap(); + let hex_tx = Vec::::from_hex("02000000000101f58c18a90d7a76b30c7e47d4e817adfdd79a6a589a615ef36e360f913adce2cd0000000000feffffff0210270000000000001600145c9a1816d38db5cbdd4b067b689dc19eb7d930e2cf70aa2b080000001600140f48b63160043047f4f60f7f8f551f80458f693f024730440220413f42b7bc979945489a38f5221e5527d4b8e3aa63eae2099e01945896ad6c10022024ceec492d685c31d8adb64e935a06933877c5ae0e21f32efe029850914c5bad012102361caae96f0e9f3a453d354bb37a5c3244422fb22819bf0166c0647a38de39f21fca2300").unwrap(); + let mut tx: Transaction = deserialize(&hex_tx).unwrap(); + + tree.set_raw_tx(&tx).unwrap(); + + let txid = tx.txid(); + + assert_eq!(tree.get_raw_tx(&txid).unwrap(), Some(tx.clone())); + + // mutate transaction's witnesses + for tx_in in tx.input.iter_mut() { + tx_in.witness = Witness::new(); + } + + let updated_hex_tx = serialize(&tx); + + // verify that mutation was successful + assert_ne!(hex_tx, updated_hex_tx); tree.set_raw_tx(&tx).unwrap(); @@ -441,5 +458,203 @@ pub mod test { assert!(tree.get_sync_time().unwrap().is_none()); } + pub fn test_iter_raw_txs(mut db: D) { + let txs = db.iter_raw_txs().unwrap(); + assert!(txs.is_empty()); + + let hex_tx = Vec::::from_hex("0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000").unwrap(); + let first_tx: Transaction = deserialize(&hex_tx).unwrap(); + + let hex_tx = Vec::::from_hex("02000000000101f58c18a90d7a76b30c7e47d4e817adfdd79a6a589a615ef36e360f913adce2cd0000000000feffffff0210270000000000001600145c9a1816d38db5cbdd4b067b689dc19eb7d930e2cf70aa2b080000001600140f48b63160043047f4f60f7f8f551f80458f693f024730440220413f42b7bc979945489a38f5221e5527d4b8e3aa63eae2099e01945896ad6c10022024ceec492d685c31d8adb64e935a06933877c5ae0e21f32efe029850914c5bad012102361caae96f0e9f3a453d354bb37a5c3244422fb22819bf0166c0647a38de39f21fca2300").unwrap(); + let second_tx: Transaction = deserialize(&hex_tx).unwrap(); + + db.set_raw_tx(&first_tx).unwrap(); + db.set_raw_tx(&second_tx).unwrap(); + + let txs = db.iter_raw_txs().unwrap(); + + assert!(txs.contains(&first_tx)); + assert!(txs.contains(&second_tx)); + assert_eq!(txs.len(), 2); + } + + pub fn test_del_path_from_script_pubkey(mut db: D) { + let keychain = KeychainKind::External; + + let script = Script::from( + Vec::::from_hex("76a91402306a7c23f3e8010de41e9e591348bb83f11daa88ac").unwrap(), + ); + let path = 42; + + let res = db.del_path_from_script_pubkey(&script).unwrap(); + + assert!(res.is_none()); + + let _res = db.set_script_pubkey(&script, keychain, path); + let (chain, child) = db.del_path_from_script_pubkey(&script).unwrap().unwrap(); + + assert_eq!(chain, keychain); + assert_eq!(child, path); + + let res = db.get_path_from_script_pubkey(&script).unwrap(); + assert!(res.is_none()); + } + + pub fn test_iter_script_pubkeys(mut db: D) { + let keychain = KeychainKind::External; + let scripts = db.iter_script_pubkeys(Some(keychain)).unwrap(); + assert!(scripts.is_empty()); + + let first_script = Script::from( + Vec::::from_hex("76a91402306a7c23f3e8010de41e9e591348bb83f11daa88ac").unwrap(), + ); + let path = 42; + + db.set_script_pubkey(&first_script, keychain, path).unwrap(); + + let second_script = Script::from( + Vec::::from_hex("00145c9a1816d38db5cbdd4b067b689dc19eb7d930e2").unwrap(), + ); + let path = 57; + + db.set_script_pubkey(&second_script, keychain, path) + .unwrap(); + let scripts = db.iter_script_pubkeys(Some(keychain)).unwrap(); + + assert!(scripts.contains(&first_script)); + assert!(scripts.contains(&second_script)); + assert_eq!(scripts.len(), 2); + } + + pub fn test_del_utxo(mut db: D) { + let outpoint = OutPoint::from_str( + "5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456:0", + ) + .unwrap(); + let script = Script::from( + Vec::::from_hex("76a91402306a7c23f3e8010de41e9e591348bb83f11daa88ac").unwrap(), + ); + let txout = TxOut { + value: 133742, + script_pubkey: script, + }; + let utxo = LocalUtxo { + txout, + outpoint, + keychain: KeychainKind::External, + is_spent: true, + }; + + let res = db.del_utxo(&outpoint).unwrap(); + assert!(res.is_none()); + + db.set_utxo(&utxo).unwrap(); + + let res = db.del_utxo(&outpoint).unwrap(); + + assert_eq!(res.unwrap(), utxo); + + let res = db.get_utxo(&outpoint).unwrap(); + assert!(res.is_none()); + } + + pub fn test_del_raw_tx(mut db: D) { + let hex_tx = Vec::::from_hex("02000000000101f58c18a90d7a76b30c7e47d4e817adfdd79a6a589a615ef36e360f913adce2cd0000000000feffffff0210270000000000001600145c9a1816d38db5cbdd4b067b689dc19eb7d930e2cf70aa2b080000001600140f48b63160043047f4f60f7f8f551f80458f693f024730440220413f42b7bc979945489a38f5221e5527d4b8e3aa63eae2099e01945896ad6c10022024ceec492d685c31d8adb64e935a06933877c5ae0e21f32efe029850914c5bad012102361caae96f0e9f3a453d354bb37a5c3244422fb22819bf0166c0647a38de39f21fca2300").unwrap(); + let tx: Transaction = deserialize(&hex_tx).unwrap(); + + let res = db.del_raw_tx(&tx.txid()).unwrap(); + + assert!(res.is_none()); + + db.set_raw_tx(&tx).unwrap(); + + let res = db.del_raw_tx(&tx.txid()).unwrap(); + + assert_eq!(res.unwrap(), tx); + + let res = db.get_raw_tx(&tx.txid()).unwrap(); + assert!(res.is_none()); + } + + pub fn test_del_tx(mut db: D) { + let hex_tx = Vec::::from_hex("0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000").unwrap(); + let tx: Transaction = deserialize(&hex_tx).unwrap(); + let txid = tx.txid(); + let mut tx_details = TransactionDetails { + transaction: Some(tx.clone()), + txid, + received: 1337, + sent: 420420, + fee: Some(140), + confirmation_time: Some(BlockTime { + timestamp: 123456, + height: 1000, + }), + }; + + let res = db.del_tx(&tx.txid(), true).unwrap(); + + assert!(res.is_none()); + + db.set_tx(&tx_details).unwrap(); + + let res = db.del_tx(&tx.txid(), false).unwrap(); + tx_details.transaction = None; + assert_eq!(res.unwrap(), tx_details); + + let res = db.get_tx(&tx.txid(), true).unwrap(); + assert!(res.is_none()); + + let res = db.get_raw_tx(&tx.txid()).unwrap(); + assert_eq!(res.unwrap(), tx); + + db.set_tx(&tx_details).unwrap(); + let res = db.del_tx(&tx.txid(), true).unwrap(); + tx_details.transaction = Some(tx.clone()); + assert_eq!(res.unwrap(), tx_details); + + let res = db.get_tx(&tx.txid(), true).unwrap(); + assert!(res.is_none()); + + let res = db.get_raw_tx(&tx.txid()).unwrap(); + assert!(res.is_none()); + } + + pub fn test_del_last_index(mut db: D) { + let keychain = KeychainKind::External; + + let _res = db.increment_last_index(keychain); + + let res = db.get_last_index(keychain).unwrap().unwrap(); + + assert_eq!(res, 0); + + let _res = db.increment_last_index(keychain); + + let res = db.del_last_index(keychain).unwrap().unwrap(); + + assert_eq!(res, 1); + + let res = db.get_last_index(keychain).unwrap(); + assert!(res.is_none()); + } + + pub fn test_check_descriptor_checksum(mut db: D) { + // insert checksum associated to keychain + let checksum = "1cead456".as_bytes(); + let keychain = KeychainKind::External; + let _res = db.check_descriptor_checksum(keychain, checksum); + + // check if `check_descriptor_checksum` throws + // `Error::ChecksumMismatch` error if the + // function is passed a checksum that does + // not match the one initially inserted + let checksum = "1cead454".as_bytes(); + let keychain = KeychainKind::External; + let res = db.check_descriptor_checksum(keychain, checksum); + + assert!(res.is_err()); + } + // TODO: more tests... } diff --git a/src/database/sqlite.rs b/src/database/sqlite.rs index a9cbe1a7..bec6dd48 100644 --- a/src/database/sqlite.rs +++ b/src/database/sqlite.rs @@ -1038,4 +1038,44 @@ pub mod test { fn test_txs() { crate::database::test::test_list_transaction(get_database()); } + + #[test] + fn test_iter_raw_txs() { + crate::database::test::test_iter_raw_txs(get_database()); + } + + #[test] + fn test_del_path_from_script_pubkey() { + crate::database::test::test_del_path_from_script_pubkey(get_database()); + } + + #[test] + fn test_iter_script_pubkeys() { + crate::database::test::test_iter_script_pubkeys(get_database()); + } + + #[test] + fn test_del_utxo() { + crate::database::test::test_del_utxo(get_database()); + } + + #[test] + fn test_del_raw_tx() { + crate::database::test::test_del_raw_tx(get_database()); + } + + #[test] + fn test_del_tx() { + crate::database::test::test_del_tx(get_database()); + } + + #[test] + fn test_del_last_index() { + crate::database::test::test_del_last_index(get_database()); + } + + #[test] + fn test_check_descriptor_checksum() { + crate::database::test::test_check_descriptor_checksum(get_database()); + } }