Skip to content

Commit 72a8a38

Browse files
committed
Return vector instead of iterator
An earlier implementation called collect() before returning the results. Instead of calling collect(), the API was changed to just return the iterator since it's possible dependant applications may prefer to use the iterator. However, after a refactor, the call to collect() was removed, and now it no longer makes sense to return an iterator. Furthermore, return an opaque type makes for a more complicated return type, making it hard to alias for example. Returning a concrete type therefore simplifies the API.
1 parent c2594ed commit 72a8a38

File tree

4 files changed

+45
-44
lines changed

4 files changed

+45
-44
lines changed

benches/coin_selection.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
3434

3535
c.bench_function("bnb 1000", |b| {
3636
b.iter(|| {
37-
let (iteration_count, inputs_iter) = select_coins_bnb(
37+
let (iteration_count, inputs) = select_coins_bnb(
3838
black_box(target),
3939
black_box(cost_of_change),
4040
black_box(FeeRate::ZERO),
@@ -43,7 +43,6 @@ pub fn criterion_benchmark(c: &mut Criterion) {
4343
)
4444
.unwrap();
4545
assert_eq!(iteration_count, 100000);
46-
let inputs: Vec<_> = inputs_iter.collect();
4746

4847
assert_eq!(2, inputs.len());
4948
assert_eq!(Amount::from_sat(1_000), inputs[0].value());

src/branch_and_bound.rs

+16-20
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
//!
55
//! This module introduces the Branch and Bound Coin-Selection Algorithm.
66
7-
use std::vec::IntoIter;
8-
97
use bitcoin::amount::CheckedSum;
108
use bitcoin::{Amount, FeeRate, SignedAmount};
119

@@ -158,7 +156,7 @@ pub fn select_coins_bnb<Utxo: WeightedUtxo>(
158156
fee_rate: FeeRate,
159157
long_term_fee_rate: FeeRate,
160158
weighted_utxos: &[Utxo],
161-
) -> Option<(u32, IntoIter<&Utxo>)> {
159+
) -> Option<(u32, Vec<&Utxo>)> {
162160
// Total_Tries in Core:
163161
// https://github.com/bitcoin/bitcoin/blob/1d9da8da309d1dbf9aef15eb8dc43b4a2dc3d309/src/wallet/coinselection.cpp#L74
164162
const ITERATION_LIMIT: u32 = 100_000;
@@ -310,7 +308,7 @@ fn index_to_utxo_list<Utxo: WeightedUtxo>(
310308
iterations: u32,
311309
index_list: Vec<usize>,
312310
wu: Vec<(Amount, SignedAmount, &Utxo)>,
313-
) -> Option<(u32, std::vec::IntoIter<&Utxo>)> {
311+
) -> Option<(u32, Vec<&Utxo>)> {
314312
let mut result: Vec<_> = Vec::new();
315313
let list = index_list;
316314

@@ -322,7 +320,7 @@ fn index_to_utxo_list<Utxo: WeightedUtxo>(
322320
if result.is_empty() {
323321
None
324322
} else {
325-
Some((iterations, result.into_iter()))
323+
Some((iterations, result))
326324
}
327325
}
328326

@@ -337,7 +335,7 @@ mod tests {
337335
use bitcoin::{Amount, Weight};
338336

339337
use super::*;
340-
use crate::tests::{assert_proptest_bnb, Utxo, UtxoPool};
338+
use crate::tests::{assert_proptest_bnb, assert_ref_eq, Utxo, UtxoPool};
341339
use crate::WeightedUtxo;
342340

343341
const TX_IN_BASE_WEIGHT: u64 = 160;
@@ -363,15 +361,13 @@ mod tests {
363361
) {
364362
let target = Amount::from_str(target_str).unwrap();
365363
let pool = build_pool();
366-
let (iterations, inputs_iter) =
364+
let (iterations, inputs) =
367365
select_coins_bnb(target, Amount::ZERO, FeeRate::ZERO, FeeRate::ZERO, &pool.utxos)
368366
.unwrap();
369-
370367
assert_eq!(iterations, expected_iterations);
371368

372-
let inputs: Vec<_> = inputs_iter.cloned().collect();
373-
let expected_inputs: UtxoPool = UtxoPool::from_str_list(expected_inputs_str);
374-
assert_eq!(expected_inputs.utxos, inputs);
369+
let expected: UtxoPool = UtxoPool::from_str_list(expected_inputs_str);
370+
assert_ref_eq(inputs, expected.utxos);
375371
}
376372

377373
fn assert_coin_select_params(
@@ -395,12 +391,11 @@ mod tests {
395391
let pool: UtxoPool = UtxoPool::from_str_list(&p.weighted_utxos);
396392
let result = select_coins_bnb(target, cost_of_change, fee_rate, lt_fee_rate, &pool.utxos);
397393

398-
if let Some((iterations, inputs_iter)) = result {
394+
if let Some((iterations, inputs)) = result {
399395
assert_eq!(iterations, expected_iterations);
400396

401-
let inputs: Vec<Utxo> = inputs_iter.cloned().collect();
402-
let expected_inputs: UtxoPool = UtxoPool::from_str_list(expected_inputs_str.unwrap());
403-
assert_eq!(expected_inputs.utxos, inputs);
397+
let expected: UtxoPool = UtxoPool::from_str_list(expected_inputs_str.unwrap());
398+
assert_ref_eq(inputs, expected.utxos);
404399
}
405400
}
406401

@@ -746,7 +741,7 @@ mod tests {
746741
amts.push(Amount::from_sat(target));
747742
let pool: Vec<_> = amts.into_iter().map(|a| Utxo::new(a, Weight::ZERO)).collect();
748743

749-
let (iterations, mut utxos) = select_coins_bnb(
744+
let (iterations, utxos) = select_coins_bnb(
750745
Amount::from_sat(target),
751746
Amount::ONE_SAT,
752747
FeeRate::ZERO,
@@ -756,7 +751,7 @@ mod tests {
756751
.unwrap();
757752

758753
assert_eq!(utxos.len(), 1);
759-
assert_eq!(utxos.next().unwrap().value(), Amount::from_sat(target));
754+
assert_eq!(utxos[0].value(), Amount::from_sat(target));
760755
assert_eq!(100000, iterations);
761756
}
762757

@@ -774,8 +769,7 @@ mod tests {
774769
select_coins_bnb(utxo.value(), Amount::ZERO, FeeRate::ZERO, FeeRate::ZERO, &pool)
775770
.unwrap();
776771

777-
let coins: Vec<Utxo> = utxos.cloned().collect();
778-
772+
let coins: Vec<Utxo> = utxos.into_iter().cloned().collect();
779773
assert_eq!(coins, pool);
780774

781775
Ok(())
@@ -803,6 +797,7 @@ mod tests {
803797

804798
if let Some((_i, utxos)) = result {
805799
let sum: SignedAmount = utxos
800+
.into_iter()
806801
.map(|u| {
807802
effective_value(fee_rate, u.satisfaction_weight(), u.value())
808803
.unwrap()
@@ -812,7 +807,7 @@ mod tests {
812807
assert_eq!(amount_sum, target);
813808
} else {
814809
// if result was none, then assert that fail happened because overflow when
815-
// ssumming pool. In the future, assert specific error when added.
810+
// summing pool. In the future, assert specific error when added.
816811
let available_value = utxos.into_iter().map(|u| u.value()).checked_sum();
817812
assert!(available_value.is_none());
818813
}
@@ -872,6 +867,7 @@ mod tests {
872867

873868
if let Some((_i, utxos)) = result {
874869
let effective_value_sum: Amount = utxos
870+
.into_iter()
875871
.map(|u| {
876872
effective_value(fee_rate, u.satisfaction_weight(), u.value())
877873
.unwrap()

src/lib.rs

+19-11
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ pub fn select_coins<Utxo: WeightedUtxo>(
9393
fee_rate: FeeRate,
9494
long_term_fee_rate: FeeRate,
9595
weighted_utxos: &[Utxo],
96-
) -> Option<(u32, impl Iterator<Item = &Utxo>)> {
96+
) -> Option<(u32, Vec<&Utxo>)> {
9797
let bnb =
9898
select_coins_bnb(target, cost_of_change, fee_rate, long_term_fee_rate, weighted_utxos);
9999

@@ -133,6 +133,11 @@ mod tests {
133133
utxos
134134
}
135135

136+
pub fn assert_ref_eq(inputs: Vec<&Utxo>, expected: Vec<Utxo>) {
137+
let expected_ref: Vec<&Utxo> = expected.iter().collect();
138+
assert_eq!(inputs, expected_ref);
139+
}
140+
136141
#[derive(Debug, Clone, PartialEq, Ord, Eq, PartialOrd, Arbitrary)]
137142
pub struct Utxo {
138143
pub output: TxOut,
@@ -230,8 +235,8 @@ mod tests {
230235
let result = select_coins(target, cost_of_change, fee_rate, lt_fee_rate, &pool);
231236

232237
// This yields no solution because:
233-
// * BnB fails because the sum overage is greater than cost_of_change
234-
// * SRD fails because the sum is greater the utxo sum + CHANGE_LOWER
238+
// * BnB fails because the sum overage is greater than cost_of_change
239+
// * SRD fails because the sum is greater the utxo sum + CHANGE_LOWER
235240
assert!(result.is_none());
236241
}
237242

@@ -245,7 +250,7 @@ mod tests {
245250

246251
let result = select_coins(target, cost_of_change, fee_rate, lt_fee_rate, &pool);
247252
let (_iterations, utxos) = result.unwrap();
248-
let sum: Amount = utxos.map(|u| u.value()).sum();
253+
let sum: Amount = utxos.into_iter().map(|u| u.value()).sum();
249254
assert!(sum > target);
250255
}
251256

@@ -264,7 +269,7 @@ mod tests {
264269

265270
let result = select_coins(target, cost_of_change, fee_rate, lt_fee_rate, &pool);
266271
let (iterations, utxos) = result.unwrap();
267-
let sum: Amount = utxos.map(|u| u.value()).sum();
272+
let sum: Amount = utxos.into_iter().map(|u| u.value()).sum();
268273
assert!(sum > target);
269274
assert!(sum <= target + cost_of_change);
270275
assert_eq!(16, iterations);
@@ -325,18 +330,19 @@ mod tests {
325330
}
326331
}
327332

328-
pub fn assert_proptest_bnb<'a, T: Iterator<Item = &'a Utxo>>(
333+
pub fn assert_proptest_bnb(
329334
target: Amount,
330335
cost_of_change: Amount,
331336
fee_rate: FeeRate,
332337
pool: UtxoPool,
333-
result: Option<(u32, T)>,
338+
result: Option<(u32, Vec<&Utxo>)>,
334339
) {
335340
let mut bnb_solutions: Vec<Vec<&Utxo>> = Vec::new();
336341
build_possible_solutions_bnb(&pool, fee_rate, target, cost_of_change, &mut bnb_solutions);
337342

338343
if let Some((_i, utxos)) = result {
339344
let utxo_sum: Amount = utxos
345+
.into_iter()
340346
.map(|u| {
341347
effective_value(fee_rate, u.satisfaction_weight(), u.value())
342348
.unwrap()
@@ -354,17 +360,18 @@ mod tests {
354360
}
355361
}
356362

357-
pub fn assert_proptest_srd<'a, T: Iterator<Item = &'a Utxo>>(
363+
pub fn assert_proptest_srd(
358364
target: Amount,
359365
fee_rate: FeeRate,
360366
pool: UtxoPool,
361-
result: Option<(u32, T)>,
367+
result: Option<(u32, Vec<&Utxo>)>,
362368
) {
363369
let mut srd_solutions: Vec<Vec<&Utxo>> = Vec::new();
364370
build_possible_solutions_srd(&pool, fee_rate, target, &mut srd_solutions);
365371

366372
if let Some((_i, utxos)) = result {
367373
let utxo_sum: Amount = utxos
374+
.into_iter()
368375
.map(|u| {
369376
effective_value(fee_rate, u.satisfaction_weight(), u.value())
370377
.unwrap()
@@ -381,12 +388,12 @@ mod tests {
381388
}
382389
}
383390

384-
pub fn assert_proptest<'a, T: Iterator<Item = &'a Utxo>>(
391+
pub fn assert_proptest(
385392
target: Amount,
386393
cost_of_change: Amount,
387394
fee_rate: FeeRate,
388395
pool: UtxoPool,
389-
result: Option<(u32, T)>,
396+
result: Option<(u32, Vec<&Utxo>)>,
390397
) {
391398
let mut bnb_solutions: Vec<Vec<&Utxo>> = Vec::new();
392399
build_possible_solutions_bnb(&pool, fee_rate, target, cost_of_change, &mut bnb_solutions);
@@ -396,6 +403,7 @@ mod tests {
396403

397404
if let Some((_i, utxos)) = result {
398405
let utxo_sum: Amount = utxos
406+
.into_iter()
399407
.map(|u| {
400408
effective_value(fee_rate, u.satisfaction_weight(), u.value())
401409
.unwrap()

src/single_random_draw.rs

+9-11
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ pub fn select_coins_srd<'a, R: rand::Rng + ?Sized, Utxo: WeightedUtxo>(
4545
fee_rate: FeeRate,
4646
weighted_utxos: &'a [Utxo],
4747
rng: &mut R,
48-
) -> Option<(u32, std::vec::IntoIter<&'a Utxo>)> {
48+
) -> Option<(u32, Vec<&'a Utxo>)> {
4949
if target > Amount::MAX_MONEY {
5050
return None;
5151
}
@@ -73,7 +73,7 @@ pub fn select_coins_srd<'a, R: rand::Rng + ?Sized, Utxo: WeightedUtxo>(
7373
result.push(w_utxo);
7474

7575
if value >= threshold {
76-
return Some((iteration, result.into_iter()));
76+
return Some((iteration, result));
7777
}
7878
}
7979
}
@@ -93,7 +93,7 @@ mod tests {
9393

9494
use super::*;
9595
use crate::single_random_draw::select_coins_srd;
96-
use crate::tests::{assert_proptest_srd, Utxo, UtxoPool};
96+
use crate::tests::{assert_proptest_srd, assert_ref_eq, UtxoPool};
9797

9898
const FEE_RATE: FeeRate = FeeRate::from_sat_per_kwu(10);
9999

@@ -140,12 +140,11 @@ mod tests {
140140
let pool: UtxoPool = UtxoPool::from_str_list(&p.weighted_utxos);
141141
let result = select_coins_srd(target, fee_rate, &pool.utxos, &mut get_rng());
142142

143-
if let Some((iterations, inputs_iter)) = result {
143+
if let Some((iterations, inputs)) = result {
144144
assert_eq!(iterations, expected_iterations);
145145

146-
let inputs: Vec<Utxo> = inputs_iter.cloned().collect();
147-
let expected_pool: UtxoPool = UtxoPool::from_str_list(expected_inputs_str.unwrap());
148-
assert_eq!(inputs, expected_pool.utxos);
146+
let expected: UtxoPool = UtxoPool::from_str_list(expected_inputs_str.unwrap());
147+
assert_ref_eq(inputs, expected.utxos);
149148
}
150149
}
151150

@@ -157,13 +156,12 @@ mod tests {
157156
let target = Amount::from_str(target_str).unwrap();
158157
let pool = build_pool();
159158

160-
let (iterations, inputs_iter) =
159+
let (iterations, inputs) =
161160
select_coins_srd(target, FEE_RATE, &pool.utxos, &mut get_rng()).unwrap();
162161
assert_eq!(iterations, expected_iterations);
163162

164-
let inputs: Vec<_> = inputs_iter.cloned().collect();
165-
let expected_pool: UtxoPool = UtxoPool::from_str_list(expected_inputs_str);
166-
assert_eq!(inputs, expected_pool.utxos);
163+
let expected: UtxoPool = UtxoPool::from_str_list(expected_inputs_str);
164+
assert_ref_eq(inputs, expected.utxos);
167165
}
168166

169167
#[test]

0 commit comments

Comments
 (0)