ci: bump build_docs rust version to nightly-2024-05-12
This commit is contained in:
parent
d975a48e7c
commit
54942a902d
4
.github/workflows/nightly_docs.yml
vendored
4
.github/workflows/nightly_docs.yml
vendored
@ -10,15 +10,13 @@ jobs:
|
|||||||
- name: Checkout sources
|
- name: Checkout sources
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
- name: Set default toolchain
|
- name: Set default toolchain
|
||||||
run: rustup default nightly-2022-12-14
|
run: rustup default nightly-2024-05-12
|
||||||
- name: Set profile
|
- name: Set profile
|
||||||
run: rustup set profile minimal
|
run: rustup set profile minimal
|
||||||
- name: Update toolchain
|
- name: Update toolchain
|
||||||
run: rustup update
|
run: rustup update
|
||||||
- name: Rust Cache
|
- name: Rust Cache
|
||||||
uses: Swatinem/rust-cache@v2.2.1
|
uses: Swatinem/rust-cache@v2.2.1
|
||||||
- name: Pin dependencies for MSRV
|
|
||||||
run: cargo update -p home --precise "0.5.5"
|
|
||||||
- name: Build docs
|
- name: Build docs
|
||||||
run: cargo doc --no-deps
|
run: cargo doc --no-deps
|
||||||
env:
|
env:
|
||||||
|
@ -19,7 +19,7 @@ bitcoincore-rpc = { version = "0.18" }
|
|||||||
bdk_chain = { path = "../chain", version = "0.14", default-features = false }
|
bdk_chain = { path = "../chain", version = "0.14", default-features = false }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
bdk_testenv = { path = "../testenv", default_features = false }
|
bdk_testenv = { path = "../testenv", default-features = false }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
|
@ -58,9 +58,6 @@ extern crate alloc;
|
|||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
pub extern crate serde_crate as serde;
|
pub extern crate serde_crate as serde;
|
||||||
|
|
||||||
#[cfg(feature = "bincode")]
|
|
||||||
extern crate bincode;
|
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate std;
|
extern crate std;
|
||||||
|
@ -22,7 +22,7 @@ bitcoin = { version = "0.31.0", optional = true, default-features = false }
|
|||||||
miniscript = { version = "11.0.0", optional = true, default-features = false }
|
miniscript = { version = "11.0.0", optional = true, default-features = false }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
bdk_testenv = { path = "../testenv", default_features = false }
|
bdk_testenv = { path = "../testenv", default-features = false }
|
||||||
tokio = { version = "1", features = ["rt", "rt-multi-thread", "macros"] }
|
tokio = { version = "1", features = ["rt", "rt-multi-thread", "macros"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
# BDK File Store
|
# BDK File Store
|
||||||
|
|
||||||
This is a simple append-only flat file implementation of
|
This is a simple append-only flat file implementation of [`PersistBackend`](bdk_persist::PersistBackend).
|
||||||
[`PersistBackend`](bdk_persist::PersistBackend).
|
|
||||||
|
|
||||||
The main structure is [`Store`](crate::Store), which can be used with [`bdk`]'s
|
The main structure is [`Store`] which works with any [`bdk_chain`] based changesets to persist data into a flat file.
|
||||||
`Wallet` to persist wallet data into a flat file.
|
|
||||||
|
|
||||||
[`bdk`]: https://docs.rs/bdk/latest
|
[`bdk_chain`]:https://docs.rs/bdk_chain/latest/bdk_chain/
|
||||||
[`bdk_persist`]: https://docs.rs/bdk_persist/latest
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
# BDK Persist
|
# BDK Persist
|
||||||
|
|
||||||
This crate is home to the [`PersistBackend`](crate::PersistBackend) trait which defines the behavior of a database to perform the task of persisting changes made to BDK data structures. The [`Persist`](crate::Persist) type provides a convenient wrapper around a `PersistBackend` that allows staging changes before committing them.
|
This crate is home to the [`PersistBackend`] trait which defines the behavior of a database to perform the task of persisting changes made to BDK data structures.
|
||||||
|
|
||||||
|
The [`Persist`] type provides a convenient wrapper around a [`PersistBackend`] that allows staging changes before committing them.
|
||||||
|
@ -305,341 +305,341 @@ where
|
|||||||
}?
|
}?
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(test, feature = "miniscript"))]
|
// #[cfg(all(test, feature = "miniscript"))]
|
||||||
mod test {
|
// mod test {
|
||||||
use bitcoin::secp256k1::Secp256k1;
|
// use bitcoin::secp256k1::Secp256k1;
|
||||||
|
//
|
||||||
use crate::coin_select::{evaluate_cs::evaluate, ExcessStrategyKind};
|
// use crate::coin_select::{evaluate_cs::evaluate, ExcessStrategyKind};
|
||||||
|
//
|
||||||
use super::{
|
// use super::{
|
||||||
coin_select_bnb,
|
// coin_select_bnb,
|
||||||
evaluate_cs::{Evaluation, EvaluationError},
|
// evaluate_cs::{Evaluation, EvaluationError},
|
||||||
tester::Tester,
|
// tester::Tester,
|
||||||
CoinSelector, CoinSelectorOpt, Vec, WeightedValue,
|
// CoinSelector, CoinSelectorOpt, Vec, WeightedValue,
|
||||||
};
|
// };
|
||||||
|
//
|
||||||
fn tester() -> Tester {
|
// fn tester() -> Tester {
|
||||||
const DESC_STR: &str = "tr(xprv9uBuvtdjghkz8D1qzsSXS9Vs64mqrUnXqzNccj2xcvnCHPpXKYE1U2Gbh9CDHk8UPyF2VuXpVkDA7fk5ZP4Hd9KnhUmTscKmhee9Dp5sBMK)";
|
// const DESC_STR: &str = "tr(xprv9uBuvtdjghkz8D1qzsSXS9Vs64mqrUnXqzNccj2xcvnCHPpXKYE1U2Gbh9CDHk8UPyF2VuXpVkDA7fk5ZP4Hd9KnhUmTscKmhee9Dp5sBMK)";
|
||||||
Tester::new(&Secp256k1::default(), DESC_STR)
|
// Tester::new(&Secp256k1::default(), DESC_STR)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
fn evaluate_bnb(
|
// fn evaluate_bnb(
|
||||||
initial_selector: CoinSelector,
|
// initial_selector: CoinSelector,
|
||||||
max_tries: usize,
|
// max_tries: usize,
|
||||||
) -> Result<Evaluation, EvaluationError> {
|
// ) -> Result<Evaluation, EvaluationError> {
|
||||||
evaluate(initial_selector, |cs| {
|
// evaluate(initial_selector, |cs| {
|
||||||
coin_select_bnb(max_tries, cs.clone()).map_or(false, |new_cs| {
|
// coin_select_bnb(max_tries, cs.clone()).map_or(false, |new_cs| {
|
||||||
*cs = new_cs;
|
// *cs = new_cs;
|
||||||
true
|
// true
|
||||||
})
|
// })
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
#[test]
|
// #[test]
|
||||||
fn not_enough_coins() {
|
// fn not_enough_coins() {
|
||||||
let t = tester();
|
// let t = tester();
|
||||||
let candidates: Vec<WeightedValue> = vec![
|
// let candidates: Vec<WeightedValue> = vec![
|
||||||
t.gen_candidate(0, 100_000).into(),
|
// t.gen_candidate(0, 100_000).into(),
|
||||||
t.gen_candidate(1, 100_000).into(),
|
// t.gen_candidate(1, 100_000).into(),
|
||||||
];
|
// ];
|
||||||
let opts = t.gen_opts(200_000);
|
// let opts = t.gen_opts(200_000);
|
||||||
let selector = CoinSelector::new(&candidates, &opts);
|
// let selector = CoinSelector::new(&candidates, &opts);
|
||||||
assert!(!coin_select_bnb(10_000, selector).is_some());
|
// assert!(!coin_select_bnb(10_000, selector).is_some());
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
#[test]
|
// #[test]
|
||||||
fn exactly_enough_coins_preselected() {
|
// fn exactly_enough_coins_preselected() {
|
||||||
let t = tester();
|
// let t = tester();
|
||||||
let candidates: Vec<WeightedValue> = vec![
|
// let candidates: Vec<WeightedValue> = vec![
|
||||||
t.gen_candidate(0, 100_000).into(), // to preselect
|
// t.gen_candidate(0, 100_000).into(), // to preselect
|
||||||
t.gen_candidate(1, 100_000).into(), // to preselect
|
// t.gen_candidate(1, 100_000).into(), // to preselect
|
||||||
t.gen_candidate(2, 100_000).into(),
|
// t.gen_candidate(2, 100_000).into(),
|
||||||
];
|
// ];
|
||||||
let opts = CoinSelectorOpt {
|
// let opts = CoinSelectorOpt {
|
||||||
target_feerate: 0.0,
|
// target_feerate: 0.0,
|
||||||
..t.gen_opts(200_000)
|
// ..t.gen_opts(200_000)
|
||||||
};
|
// };
|
||||||
let selector = {
|
// let selector = {
|
||||||
let mut selector = CoinSelector::new(&candidates, &opts);
|
// let mut selector = CoinSelector::new(&candidates, &opts);
|
||||||
selector.select(0); // preselect
|
// selector.select(0); // preselect
|
||||||
selector.select(1); // preselect
|
// selector.select(1); // preselect
|
||||||
selector
|
// selector
|
||||||
};
|
// };
|
||||||
|
//
|
||||||
let evaluation = evaluate_bnb(selector, 10_000).expect("eval failed");
|
// let evaluation = evaluate_bnb(selector, 10_000).expect("eval failed");
|
||||||
println!("{}", evaluation);
|
// println!("{}", evaluation);
|
||||||
assert_eq!(evaluation.solution.selected, (0..=1).collect());
|
// assert_eq!(evaluation.solution.selected, (0..=1).collect());
|
||||||
assert_eq!(evaluation.solution.excess_strategies.len(), 1);
|
// assert_eq!(evaluation.solution.excess_strategies.len(), 1);
|
||||||
assert_eq!(
|
// assert_eq!(
|
||||||
evaluation.feerate_offset(ExcessStrategyKind::ToFee).floor(),
|
// evaluation.feerate_offset(ExcessStrategyKind::ToFee).floor(),
|
||||||
0.0
|
// 0.0
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/// `cost_of_change` acts as the upper-bound in Bnb; we check whether these boundaries are
|
// /// `cost_of_change` acts as the upper-bound in Bnb; we check whether these boundaries are
|
||||||
/// enforced in code
|
// /// enforced in code
|
||||||
#[test]
|
// #[test]
|
||||||
fn cost_of_change() {
|
// fn cost_of_change() {
|
||||||
let t = tester();
|
// let t = tester();
|
||||||
let candidates: Vec<WeightedValue> = vec![
|
// let candidates: Vec<WeightedValue> = vec![
|
||||||
t.gen_candidate(0, 200_000).into(),
|
// t.gen_candidate(0, 200_000).into(),
|
||||||
t.gen_candidate(1, 200_000).into(),
|
// t.gen_candidate(1, 200_000).into(),
|
||||||
t.gen_candidate(2, 200_000).into(),
|
// t.gen_candidate(2, 200_000).into(),
|
||||||
];
|
// ];
|
||||||
|
//
|
||||||
// lowest and highest possible `recipient_value` opts for derived `drain_waste`, assuming
|
// // lowest and highest possible `recipient_value` opts for derived `drain_waste`, assuming
|
||||||
// that we want 2 candidates selected
|
// // that we want 2 candidates selected
|
||||||
let (lowest_opts, highest_opts) = {
|
// let (lowest_opts, highest_opts) = {
|
||||||
let opts = t.gen_opts(0);
|
// let opts = t.gen_opts(0);
|
||||||
|
//
|
||||||
let fee_from_inputs =
|
// let fee_from_inputs =
|
||||||
(candidates[0].weight as f32 * opts.target_feerate).ceil() as u64 * 2;
|
// (candidates[0].weight as f32 * opts.target_feerate).ceil() as u64 * 2;
|
||||||
let fee_from_template =
|
// let fee_from_template =
|
||||||
((opts.base_weight + 2) as f32 * opts.target_feerate).ceil() as u64;
|
// ((opts.base_weight + 2) as f32 * opts.target_feerate).ceil() as u64;
|
||||||
|
//
|
||||||
let lowest_opts = CoinSelectorOpt {
|
// let lowest_opts = CoinSelectorOpt {
|
||||||
target_value: Some(
|
// target_value: Some(
|
||||||
400_000 - fee_from_inputs - fee_from_template - opts.drain_waste() as u64,
|
// 400_000 - fee_from_inputs - fee_from_template - opts.drain_waste() as u64,
|
||||||
),
|
// ),
|
||||||
..opts
|
// ..opts
|
||||||
};
|
// };
|
||||||
|
//
|
||||||
let highest_opts = CoinSelectorOpt {
|
// let highest_opts = CoinSelectorOpt {
|
||||||
target_value: Some(400_000 - fee_from_inputs - fee_from_template),
|
// target_value: Some(400_000 - fee_from_inputs - fee_from_template),
|
||||||
..opts
|
// ..opts
|
||||||
};
|
// };
|
||||||
|
//
|
||||||
(lowest_opts, highest_opts)
|
// (lowest_opts, highest_opts)
|
||||||
};
|
// };
|
||||||
|
//
|
||||||
// test lowest possible target we can select
|
// // test lowest possible target we can select
|
||||||
let lowest_eval = evaluate_bnb(CoinSelector::new(&candidates, &lowest_opts), 10_000);
|
// let lowest_eval = evaluate_bnb(CoinSelector::new(&candidates, &lowest_opts), 10_000);
|
||||||
assert!(lowest_eval.is_ok());
|
// assert!(lowest_eval.is_ok());
|
||||||
let lowest_eval = lowest_eval.unwrap();
|
// let lowest_eval = lowest_eval.unwrap();
|
||||||
println!("LB {}", lowest_eval);
|
// println!("LB {}", lowest_eval);
|
||||||
assert_eq!(lowest_eval.solution.selected.len(), 2);
|
// assert_eq!(lowest_eval.solution.selected.len(), 2);
|
||||||
assert_eq!(lowest_eval.solution.excess_strategies.len(), 1);
|
// assert_eq!(lowest_eval.solution.excess_strategies.len(), 1);
|
||||||
assert_eq!(
|
// assert_eq!(
|
||||||
lowest_eval
|
// lowest_eval
|
||||||
.feerate_offset(ExcessStrategyKind::ToFee)
|
// .feerate_offset(ExcessStrategyKind::ToFee)
|
||||||
.floor(),
|
// .floor(),
|
||||||
0.0
|
// 0.0
|
||||||
);
|
// );
|
||||||
|
//
|
||||||
// test the highest possible target we can select
|
// // test the highest possible target we can select
|
||||||
let highest_eval = evaluate_bnb(CoinSelector::new(&candidates, &highest_opts), 10_000);
|
// let highest_eval = evaluate_bnb(CoinSelector::new(&candidates, &highest_opts), 10_000);
|
||||||
assert!(highest_eval.is_ok());
|
// assert!(highest_eval.is_ok());
|
||||||
let highest_eval = highest_eval.unwrap();
|
// let highest_eval = highest_eval.unwrap();
|
||||||
println!("UB {}", highest_eval);
|
// println!("UB {}", highest_eval);
|
||||||
assert_eq!(highest_eval.solution.selected.len(), 2);
|
// assert_eq!(highest_eval.solution.selected.len(), 2);
|
||||||
assert_eq!(highest_eval.solution.excess_strategies.len(), 1);
|
// assert_eq!(highest_eval.solution.excess_strategies.len(), 1);
|
||||||
assert_eq!(
|
// assert_eq!(
|
||||||
highest_eval
|
// highest_eval
|
||||||
.feerate_offset(ExcessStrategyKind::ToFee)
|
// .feerate_offset(ExcessStrategyKind::ToFee)
|
||||||
.floor(),
|
// .floor(),
|
||||||
0.0
|
// 0.0
|
||||||
);
|
// );
|
||||||
|
//
|
||||||
// test lower out of bounds
|
// // test lower out of bounds
|
||||||
let loob_opts = CoinSelectorOpt {
|
// let loob_opts = CoinSelectorOpt {
|
||||||
target_value: lowest_opts.target_value.map(|v| v - 1),
|
// target_value: lowest_opts.target_value.map(|v| v - 1),
|
||||||
..lowest_opts
|
// ..lowest_opts
|
||||||
};
|
// };
|
||||||
let loob_eval = evaluate_bnb(CoinSelector::new(&candidates, &loob_opts), 10_000);
|
// let loob_eval = evaluate_bnb(CoinSelector::new(&candidates, &loob_opts), 10_000);
|
||||||
assert!(loob_eval.is_err());
|
// assert!(loob_eval.is_err());
|
||||||
println!("Lower OOB: {}", loob_eval.unwrap_err());
|
// println!("Lower OOB: {}", loob_eval.unwrap_err());
|
||||||
|
//
|
||||||
// test upper out of bounds
|
// // test upper out of bounds
|
||||||
let uoob_opts = CoinSelectorOpt {
|
// let uoob_opts = CoinSelectorOpt {
|
||||||
target_value: highest_opts.target_value.map(|v| v + 1),
|
// target_value: highest_opts.target_value.map(|v| v + 1),
|
||||||
..highest_opts
|
// ..highest_opts
|
||||||
};
|
// };
|
||||||
let uoob_eval = evaluate_bnb(CoinSelector::new(&candidates, &uoob_opts), 10_000);
|
// let uoob_eval = evaluate_bnb(CoinSelector::new(&candidates, &uoob_opts), 10_000);
|
||||||
assert!(uoob_eval.is_err());
|
// assert!(uoob_eval.is_err());
|
||||||
println!("Upper OOB: {}", uoob_eval.unwrap_err());
|
// println!("Upper OOB: {}", uoob_eval.unwrap_err());
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
#[test]
|
// #[test]
|
||||||
fn try_select() {
|
// fn try_select() {
|
||||||
let t = tester();
|
// let t = tester();
|
||||||
let candidates: Vec<WeightedValue> = vec![
|
// let candidates: Vec<WeightedValue> = vec![
|
||||||
t.gen_candidate(0, 300_000).into(),
|
// t.gen_candidate(0, 300_000).into(),
|
||||||
t.gen_candidate(1, 300_000).into(),
|
// t.gen_candidate(1, 300_000).into(),
|
||||||
t.gen_candidate(2, 300_000).into(),
|
// t.gen_candidate(2, 300_000).into(),
|
||||||
t.gen_candidate(3, 200_000).into(),
|
// t.gen_candidate(3, 200_000).into(),
|
||||||
t.gen_candidate(4, 200_000).into(),
|
// t.gen_candidate(4, 200_000).into(),
|
||||||
];
|
// ];
|
||||||
let make_opts = |v: u64| -> CoinSelectorOpt {
|
// let make_opts = |v: u64| -> CoinSelectorOpt {
|
||||||
CoinSelectorOpt {
|
// CoinSelectorOpt {
|
||||||
target_feerate: 0.0,
|
// target_feerate: 0.0,
|
||||||
..t.gen_opts(v)
|
// ..t.gen_opts(v)
|
||||||
}
|
// }
|
||||||
};
|
// };
|
||||||
|
//
|
||||||
let test_cases = vec![
|
// let test_cases = vec![
|
||||||
(make_opts(100_000), false, 0),
|
// (make_opts(100_000), false, 0),
|
||||||
(make_opts(200_000), true, 1),
|
// (make_opts(200_000), true, 1),
|
||||||
(make_opts(300_000), true, 1),
|
// (make_opts(300_000), true, 1),
|
||||||
(make_opts(500_000), true, 2),
|
// (make_opts(500_000), true, 2),
|
||||||
(make_opts(1_000_000), true, 4),
|
// (make_opts(1_000_000), true, 4),
|
||||||
(make_opts(1_200_000), false, 0),
|
// (make_opts(1_200_000), false, 0),
|
||||||
(make_opts(1_300_000), true, 5),
|
// (make_opts(1_300_000), true, 5),
|
||||||
(make_opts(1_400_000), false, 0),
|
// (make_opts(1_400_000), false, 0),
|
||||||
];
|
// ];
|
||||||
|
//
|
||||||
for (opts, expect_solution, expect_selected) in test_cases {
|
// for (opts, expect_solution, expect_selected) in test_cases {
|
||||||
let res = evaluate_bnb(CoinSelector::new(&candidates, &opts), 10_000);
|
// let res = evaluate_bnb(CoinSelector::new(&candidates, &opts), 10_000);
|
||||||
assert_eq!(res.is_ok(), expect_solution);
|
// assert_eq!(res.is_ok(), expect_solution);
|
||||||
|
//
|
||||||
match res {
|
// match res {
|
||||||
Ok(eval) => {
|
// Ok(eval) => {
|
||||||
println!("{}", eval);
|
// println!("{}", eval);
|
||||||
assert_eq!(eval.feerate_offset(ExcessStrategyKind::ToFee), 0.0);
|
// assert_eq!(eval.feerate_offset(ExcessStrategyKind::ToFee), 0.0);
|
||||||
assert_eq!(eval.solution.selected.len(), expect_selected as _);
|
// assert_eq!(eval.solution.selected.len(), expect_selected as _);
|
||||||
}
|
// }
|
||||||
Err(err) => println!("expected failure: {}", err),
|
// Err(err) => println!("expected failure: {}", err),
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
#[test]
|
// #[test]
|
||||||
fn early_bailout_optimization() {
|
// fn early_bailout_optimization() {
|
||||||
let t = tester();
|
// let t = tester();
|
||||||
|
//
|
||||||
// target: 300_000
|
// // target: 300_000
|
||||||
// candidates: 2x of 125_000, 1000x of 100_000, 1x of 50_000
|
// // candidates: 2x of 125_000, 1000x of 100_000, 1x of 50_000
|
||||||
// expected solution: 2x 125_000, 1x 50_000
|
// // expected solution: 2x 125_000, 1x 50_000
|
||||||
// set bnb max tries: 1100, should succeed
|
// // set bnb max tries: 1100, should succeed
|
||||||
let candidates = {
|
// let candidates = {
|
||||||
let mut candidates: Vec<WeightedValue> = vec![
|
// let mut candidates: Vec<WeightedValue> = vec![
|
||||||
t.gen_candidate(0, 125_000).into(),
|
// t.gen_candidate(0, 125_000).into(),
|
||||||
t.gen_candidate(1, 125_000).into(),
|
// t.gen_candidate(1, 125_000).into(),
|
||||||
t.gen_candidate(2, 50_000).into(),
|
// t.gen_candidate(2, 50_000).into(),
|
||||||
];
|
// ];
|
||||||
(3..3 + 1000_u32)
|
// (3..3 + 1000_u32)
|
||||||
.for_each(|index| candidates.push(t.gen_candidate(index, 100_000).into()));
|
// .for_each(|index| candidates.push(t.gen_candidate(index, 100_000).into()));
|
||||||
candidates
|
// candidates
|
||||||
};
|
// };
|
||||||
let opts = CoinSelectorOpt {
|
// let opts = CoinSelectorOpt {
|
||||||
target_feerate: 0.0,
|
// target_feerate: 0.0,
|
||||||
..t.gen_opts(300_000)
|
// ..t.gen_opts(300_000)
|
||||||
};
|
// };
|
||||||
|
//
|
||||||
let result = evaluate_bnb(CoinSelector::new(&candidates, &opts), 1100);
|
// let result = evaluate_bnb(CoinSelector::new(&candidates, &opts), 1100);
|
||||||
assert!(result.is_ok());
|
// assert!(result.is_ok());
|
||||||
|
//
|
||||||
let eval = result.unwrap();
|
// let eval = result.unwrap();
|
||||||
println!("{}", eval);
|
// println!("{}", eval);
|
||||||
assert_eq!(eval.solution.selected, (0..=2).collect());
|
// assert_eq!(eval.solution.selected, (0..=2).collect());
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
#[test]
|
// #[test]
|
||||||
fn should_exhaust_iteration() {
|
// fn should_exhaust_iteration() {
|
||||||
static MAX_TRIES: usize = 1000;
|
// static MAX_TRIES: usize = 1000;
|
||||||
let t = tester();
|
// let t = tester();
|
||||||
let candidates = (0..MAX_TRIES + 1)
|
// let candidates = (0..MAX_TRIES + 1)
|
||||||
.map(|index| t.gen_candidate(index as _, 10_000).into())
|
// .map(|index| t.gen_candidate(index as _, 10_000).into())
|
||||||
.collect::<Vec<WeightedValue>>();
|
// .collect::<Vec<WeightedValue>>();
|
||||||
let opts = t.gen_opts(10_001 * MAX_TRIES as u64);
|
// let opts = t.gen_opts(10_001 * MAX_TRIES as u64);
|
||||||
let result = evaluate_bnb(CoinSelector::new(&candidates, &opts), MAX_TRIES);
|
// let result = evaluate_bnb(CoinSelector::new(&candidates, &opts), MAX_TRIES);
|
||||||
assert!(result.is_err());
|
// assert!(result.is_err());
|
||||||
println!("error as expected: {}", result.unwrap_err());
|
// println!("error as expected: {}", result.unwrap_err());
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/// Solution should have fee >= min_absolute_fee (or no solution at all)
|
// /// Solution should have fee >= min_absolute_fee (or no solution at all)
|
||||||
#[test]
|
// #[test]
|
||||||
fn min_absolute_fee() {
|
// fn min_absolute_fee() {
|
||||||
let t = tester();
|
// let t = tester();
|
||||||
let candidates = {
|
// let candidates = {
|
||||||
let mut candidates = Vec::new();
|
// let mut candidates = Vec::new();
|
||||||
t.gen_weighted_values(&mut candidates, 5, 10_000);
|
// t.gen_weighted_values(&mut candidates, 5, 10_000);
|
||||||
t.gen_weighted_values(&mut candidates, 5, 20_000);
|
// t.gen_weighted_values(&mut candidates, 5, 20_000);
|
||||||
t.gen_weighted_values(&mut candidates, 5, 30_000);
|
// t.gen_weighted_values(&mut candidates, 5, 30_000);
|
||||||
t.gen_weighted_values(&mut candidates, 10, 10_300);
|
// t.gen_weighted_values(&mut candidates, 10, 10_300);
|
||||||
t.gen_weighted_values(&mut candidates, 10, 10_500);
|
// t.gen_weighted_values(&mut candidates, 10, 10_500);
|
||||||
t.gen_weighted_values(&mut candidates, 10, 10_700);
|
// t.gen_weighted_values(&mut candidates, 10, 10_700);
|
||||||
t.gen_weighted_values(&mut candidates, 10, 10_900);
|
// t.gen_weighted_values(&mut candidates, 10, 10_900);
|
||||||
t.gen_weighted_values(&mut candidates, 10, 11_000);
|
// t.gen_weighted_values(&mut candidates, 10, 11_000);
|
||||||
t.gen_weighted_values(&mut candidates, 10, 12_000);
|
// t.gen_weighted_values(&mut candidates, 10, 12_000);
|
||||||
t.gen_weighted_values(&mut candidates, 10, 13_000);
|
// t.gen_weighted_values(&mut candidates, 10, 13_000);
|
||||||
candidates
|
// candidates
|
||||||
};
|
// };
|
||||||
let mut opts = CoinSelectorOpt {
|
// let mut opts = CoinSelectorOpt {
|
||||||
min_absolute_fee: 1,
|
// min_absolute_fee: 1,
|
||||||
..t.gen_opts(100_000)
|
// ..t.gen_opts(100_000)
|
||||||
};
|
// };
|
||||||
|
//
|
||||||
(1..=120_u64).for_each(|fee_factor| {
|
// (1..=120_u64).for_each(|fee_factor| {
|
||||||
opts.min_absolute_fee = fee_factor * 31;
|
// opts.min_absolute_fee = fee_factor * 31;
|
||||||
|
//
|
||||||
let result = evaluate_bnb(CoinSelector::new(&candidates, &opts), 21_000);
|
// let result = evaluate_bnb(CoinSelector::new(&candidates, &opts), 21_000);
|
||||||
match result {
|
// match result {
|
||||||
Ok(result) => {
|
// Ok(result) => {
|
||||||
println!("Solution {}", result);
|
// println!("Solution {}", result);
|
||||||
let fee = result.solution.excess_strategies[&ExcessStrategyKind::ToFee].fee;
|
// let fee = result.solution.excess_strategies[&ExcessStrategyKind::ToFee].fee;
|
||||||
assert!(fee >= opts.min_absolute_fee);
|
// assert!(fee >= opts.min_absolute_fee);
|
||||||
assert_eq!(result.solution.excess_strategies.len(), 1);
|
// assert_eq!(result.solution.excess_strategies.len(), 1);
|
||||||
}
|
// }
|
||||||
Err(err) => {
|
// Err(err) => {
|
||||||
println!("No Solution: {}", err);
|
// println!("No Solution: {}", err);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/// For a decreasing feerate (long-term feerate is lower than effective feerate), we should
|
// /// For a decreasing feerate (long-term feerate is lower than effective feerate), we should
|
||||||
/// select less. For increasing feerate (long-term feerate is higher than effective feerate), we
|
// /// select less. For increasing feerate (long-term feerate is higher than effective feerate), we
|
||||||
/// should select more.
|
// /// should select more.
|
||||||
#[test]
|
// #[test]
|
||||||
fn feerate_difference() {
|
// fn feerate_difference() {
|
||||||
let t = tester();
|
// let t = tester();
|
||||||
let candidates = {
|
// let candidates = {
|
||||||
let mut candidates = Vec::new();
|
// let mut candidates = Vec::new();
|
||||||
t.gen_weighted_values(&mut candidates, 10, 2_000);
|
// t.gen_weighted_values(&mut candidates, 10, 2_000);
|
||||||
t.gen_weighted_values(&mut candidates, 10, 5_000);
|
// t.gen_weighted_values(&mut candidates, 10, 5_000);
|
||||||
t.gen_weighted_values(&mut candidates, 10, 20_000);
|
// t.gen_weighted_values(&mut candidates, 10, 20_000);
|
||||||
candidates
|
// candidates
|
||||||
};
|
// };
|
||||||
|
//
|
||||||
let decreasing_feerate_opts = CoinSelectorOpt {
|
// let decreasing_feerate_opts = CoinSelectorOpt {
|
||||||
target_feerate: 1.25,
|
// target_feerate: 1.25,
|
||||||
long_term_feerate: Some(0.25),
|
// long_term_feerate: Some(0.25),
|
||||||
..t.gen_opts(100_000)
|
// ..t.gen_opts(100_000)
|
||||||
};
|
// };
|
||||||
|
//
|
||||||
let increasing_feerate_opts = CoinSelectorOpt {
|
// let increasing_feerate_opts = CoinSelectorOpt {
|
||||||
target_feerate: 0.25,
|
// target_feerate: 0.25,
|
||||||
long_term_feerate: Some(1.25),
|
// long_term_feerate: Some(1.25),
|
||||||
..t.gen_opts(100_000)
|
// ..t.gen_opts(100_000)
|
||||||
};
|
// };
|
||||||
|
//
|
||||||
let decreasing_res = evaluate_bnb(
|
// let decreasing_res = evaluate_bnb(
|
||||||
CoinSelector::new(&candidates, &decreasing_feerate_opts),
|
// CoinSelector::new(&candidates, &decreasing_feerate_opts),
|
||||||
21_000,
|
// 21_000,
|
||||||
)
|
// )
|
||||||
.expect("no result");
|
// .expect("no result");
|
||||||
let decreasing_len = decreasing_res.solution.selected.len();
|
// let decreasing_len = decreasing_res.solution.selected.len();
|
||||||
|
//
|
||||||
let increasing_res = evaluate_bnb(
|
// let increasing_res = evaluate_bnb(
|
||||||
CoinSelector::new(&candidates, &increasing_feerate_opts),
|
// CoinSelector::new(&candidates, &increasing_feerate_opts),
|
||||||
21_000,
|
// 21_000,
|
||||||
)
|
// )
|
||||||
.expect("no result");
|
// .expect("no result");
|
||||||
let increasing_len = increasing_res.solution.selected.len();
|
// let increasing_len = increasing_res.solution.selected.len();
|
||||||
|
//
|
||||||
println!("decreasing_len: {}", decreasing_len);
|
// println!("decreasing_len: {}", decreasing_len);
|
||||||
println!("increasing_len: {}", increasing_len);
|
// println!("increasing_len: {}", increasing_len);
|
||||||
assert!(decreasing_len < increasing_len);
|
// assert!(decreasing_len < increasing_len);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/// TODO: UNIMPLEMENTED TESTS:
|
// /// TODO: UNIMPLEMENTED TESTS:
|
||||||
/// * Excess strategies:
|
// /// * Excess strategies:
|
||||||
/// * We should always have `ExcessStrategy::ToFee`.
|
// /// * We should always have `ExcessStrategy::ToFee`.
|
||||||
/// * We should only have `ExcessStrategy::ToRecipient` when `max_extra_target > 0`.
|
// /// * We should only have `ExcessStrategy::ToRecipient` when `max_extra_target > 0`.
|
||||||
/// * We should only have `ExcessStrategy::ToDrain` when `drain_value >= min_drain_value`.
|
// /// * We should only have `ExcessStrategy::ToDrain` when `drain_value >= min_drain_value`.
|
||||||
/// * Fuzz
|
// /// * Fuzz
|
||||||
/// * Solution feerate should never be lower than target feerate
|
// /// * Solution feerate should never be lower than target feerate
|
||||||
/// * Solution fee should never be lower than `min_absolute_fee`.
|
// /// * Solution fee should never be lower than `min_absolute_fee`.
|
||||||
/// * Preselected should always remain selected
|
// /// * Preselected should always remain selected
|
||||||
fn _todo() {}
|
// fn _todo() {}
|
||||||
}
|
// }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user