]> Untitled Git - bdk/commitdiff
[wallet] Add tests for BranchAndBoundCoinSelection::bnb
authorDaniela Brozzoni <danielabrozzoni@protonmail.com>
Sat, 31 Oct 2020 15:28:12 +0000 (16:28 +0100)
committerDaniela Brozzoni <danielabrozzoni@protonmail.com>
Fri, 13 Nov 2020 11:42:06 +0000 (12:42 +0100)
src/wallet/coin_selection.rs

index 8f3b9241318287788be7c664812c3a6449ac2cc8..45bbe300db1f88eb7e10503e156d396a2be71029 100644 (file)
@@ -856,4 +856,135 @@ mod test {
         }
     }
 
+    #[test]
+    #[should_panic(expected = "BnBNoExactMatch")]
+    fn test_bnb_function_no_exact_match() {
+        let fee_rate = FeeRate::from_sat_per_vb(10.0);
+        let utxos: Vec<OutputGroup> = get_test_utxos()
+            .into_iter()
+            .map(|u| OutputGroup::new(u.0, u.1, fee_rate))
+            .collect();
+
+        let curr_available_value = utxos
+            .iter()
+            .fold(0, |acc, x| acc + x.effective_value as u64);
+
+        let size_of_change = 31;
+        let cost_of_change = size_of_change as f32 * fee_rate.as_sat_vb();
+        BranchAndBoundCoinSelection::new(size_of_change)
+            .bnb(
+                vec![],
+                utxos,
+                0,
+                curr_available_value,
+                20_000,
+                50.0,
+                cost_of_change,
+            )
+            .unwrap();
+    }
+
+    #[test]
+    #[should_panic(expected = "BnBTotalTriesExceeded")]
+    fn test_bnb_function_tries_exceeded() {
+        let fee_rate = FeeRate::from_sat_per_vb(10.0);
+        let utxos: Vec<OutputGroup> = generate_same_value_utxos(100_000, 100_000)
+            .into_iter()
+            .map(|u| OutputGroup::new(u.0, u.1, fee_rate))
+            .collect();
+
+        let curr_available_value = utxos
+            .iter()
+            .fold(0, |acc, x| acc + x.effective_value as u64);
+
+        let size_of_change = 31;
+        let cost_of_change = size_of_change as f32 * fee_rate.as_sat_vb();
+
+        BranchAndBoundCoinSelection::new(size_of_change)
+            .bnb(
+                vec![],
+                utxos,
+                0,
+                curr_available_value,
+                20_000,
+                50.0,
+                cost_of_change,
+            )
+            .unwrap();
+    }
+
+    // The match won't be exact but still in the range
+    #[test]
+    fn test_bnb_function_almost_exact_match_with_fees() {
+        let fee_rate = FeeRate::from_sat_per_vb(1.0);
+        let size_of_change = 31;
+        let cost_of_change = size_of_change as f32 * fee_rate.as_sat_vb();
+        let fee_amount = 50.0;
+
+        let utxos: Vec<_> = generate_same_value_utxos(50_000, 10)
+            .into_iter()
+            .map(|u| OutputGroup::new(u.0, u.1, fee_rate))
+            .collect();
+
+        let curr_value = 0;
+
+        let curr_available_value = utxos
+            .iter()
+            .fold(0, |acc, x| acc + x.effective_value as u64);
+
+        // 2*(value of 1 utxo)  - 2*(1 utxo fees with 1.0sat/vbyte fee rate) -
+        // cost_of_change + 5.
+        let target_amount = 2 * 50_000 - 2 * 67 - cost_of_change.ceil() as u64 + 5;
+
+        let result = BranchAndBoundCoinSelection::new(size_of_change)
+            .bnb(
+                vec![],
+                utxos,
+                curr_value,
+                curr_available_value,
+                target_amount,
+                fee_amount,
+                cost_of_change,
+            )
+            .unwrap();
+        assert_eq!(result.fee_amount, 186.0);
+        assert_eq!(result.selected_amount, 100_000);
+    }
+
+    // TODO: bnb() function should be optimized, and this test should be done with more utxos
+    #[test]
+    fn test_bnb_function_exact_match_more_utxos() {
+        let seed = [0; 32];
+        let mut rng: StdRng = SeedableRng::from_seed(seed);
+        let fee_rate = FeeRate::from_sat_per_vb(0.0);
+
+        for _ in 0..200 {
+            let optional_utxos: Vec<_> = generate_random_utxos(&mut rng, 40)
+                .into_iter()
+                .map(|u| OutputGroup::new(u.0, u.1, fee_rate))
+                .collect();
+
+            let curr_value = 0;
+
+            let curr_available_value = optional_utxos
+                .iter()
+                .fold(0, |acc, x| acc + x.effective_value as u64);
+
+            let target_amount = optional_utxos[3].effective_value as u64
+                + optional_utxos[23].effective_value as u64;
+
+            let result = BranchAndBoundCoinSelection::new(0)
+                .bnb(
+                    vec![],
+                    optional_utxos,
+                    curr_value,
+                    curr_available_value,
+                    target_amount,
+                    0.0,
+                    0.0,
+                )
+                .unwrap();
+            assert_eq!(result.selected_amount, target_amount);
+        }
+    }
 }