Skip to content

Commit 5649628

Browse files
committed
Merge #412: Refactor threshold method
28662d2 Use fold combinator instead of manual implementation (Tobin C. Harding) cb4c037 Refactor out sort algorithm (Tobin C. Harding) 8622ee6 Remove stale comment (Tobin C. Harding) Pull request description: Do a few refactorings in an attempt to make the `threshold` method easier to read. ACKs for top commit: apoelstra: utACK 28662d2 sanket1729: ACK 28662d2. IMO, these are clean improvements. Tree-SHA512: be318930f093a5a1d1e4942bf4c2bf5dd04d69e49c07a8b8df91993bcde7e4510b93b63568d5735a231cbbdf79486e30c210bb0ce65a56672800fdc5c646033d
2 parents c13e3cf + 28662d2 commit 5649628

File tree

2 files changed

+97
-59
lines changed

2 files changed

+97
-59
lines changed

src/interpreter/inner.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -238,8 +238,6 @@ pub(super) fn from_txdata<'txin>(
238238
// Creating new contexts is cheap
239239
let secp = bitcoin::secp256k1::Secp256k1::verification_only();
240240
let tap_script = tap_script.encode();
241-
// Should not really need to call dangerous assumed tweaked here.
242-
// Should be fixed after RC
243241
if ctrl_blk.verify_taproot_commitment(&secp, output_key, &tap_script) {
244242
Ok((
245243
Inner::Script(ms, ScriptType::Tr),

src/miniscript/types/extra_props.rs

Lines changed: 97 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -775,17 +775,13 @@ impl Property for ExtData {
775775
let mut ops_count = 0;
776776
let mut ops_count_sat_vec = Vec::with_capacity(n);
777777
let mut ops_count_nsat_sum = 0;
778-
let mut op_count_sat = Some(0);
779778
let mut timelocks = Vec::with_capacity(n);
780779
let mut stack_elem_count_sat_vec = Vec::with_capacity(n);
781-
let mut stack_elem_count_sat = Some(0);
782780
let mut stack_elem_count_dissat = Some(0);
783781
let mut max_sat_size_vec = Vec::with_capacity(n);
784-
let mut max_sat_size = Some((0, 0));
785782
let mut max_dissat_size = Some((0, 0));
786783
// the max element count is same as max sat element count when satisfying one element + 1
787784
let mut exec_stack_elem_count_sat_vec = Vec::with_capacity(n);
788-
let mut exec_stack_elem_count_sat = Some(0);
789785
let mut exec_stack_elem_count_dissat = Some(0);
790786

791787
for i in 0..n {
@@ -822,61 +818,60 @@ impl Property for ExtData {
822818
);
823819
}
824820

825-
// We sort by [satisfaction cost - dissatisfaction cost] to make a worst-case (the most
826-
// costy satisfaction are satisfied, the most costy dissatisfactions are dissatisfied)
827-
// sum of the cost by iterating through the sorted vector *backward*.
828-
stack_elem_count_sat_vec.sort_by(|a, b| {
829-
a.0.map(|x| a.1.map(|y| x as isize - y as isize))
830-
.cmp(&b.0.map(|x| b.1.map(|y| x as isize - y as isize)))
831-
});
832-
for (i, &(x, y)) in stack_elem_count_sat_vec.iter().rev().enumerate() {
833-
stack_elem_count_sat = if i <= k {
834-
x.and_then(|x| stack_elem_count_sat.map(|count| count + x))
835-
} else {
836-
y.and_then(|y| stack_elem_count_sat.map(|count| count + y))
837-
};
838-
}
821+
stack_elem_count_sat_vec.sort_by(sat_minus_option_dissat);
822+
let stack_elem_count_sat =
823+
stack_elem_count_sat_vec
824+
.iter()
825+
.rev()
826+
.enumerate()
827+
.fold(Some(0), |acc, (i, &(x, y))| {
828+
if i <= k {
829+
opt_add(acc, x)
830+
} else {
831+
opt_add(acc, y)
832+
}
833+
});
839834

840-
// Same logic as above
841-
exec_stack_elem_count_sat_vec.sort_by(|a, b| {
842-
a.0.map(|x| a.1.map(|y| x as isize - y as isize))
843-
.cmp(&b.0.map(|x| b.1.map(|y| x as isize - y as isize)))
844-
});
845-
for (i, &(x, y)) in exec_stack_elem_count_sat_vec.iter().rev().enumerate() {
846-
exec_stack_elem_count_sat = if i <= k {
847-
opt_max(exec_stack_elem_count_sat, x)
848-
} else {
849-
opt_max(exec_stack_elem_count_sat, y)
850-
};
851-
}
835+
exec_stack_elem_count_sat_vec.sort_by(sat_minus_option_dissat);
836+
let exec_stack_elem_count_sat = exec_stack_elem_count_sat_vec
837+
.iter()
838+
.rev()
839+
.enumerate()
840+
.fold(Some(0), |acc, (i, &(x, y))| {
841+
if i <= k {
842+
opt_max(acc, x)
843+
} else {
844+
opt_max(acc, y)
845+
}
846+
});
852847

853-
// Same for the size cost. A bit more intricated as we need to account for both the witness
854-
// and scriptSig cost, so we end up with a tuple of Options of tuples. We use the witness
855-
// cost (first element of the mentioned tuple) here.
856848
// FIXME: Maybe make the ExtData struct aware of Ctx and add a one_cost() method here ?
857-
max_sat_size_vec.sort_by(|a, b| {
858-
a.0.map(|x| a.1.map(|y| x.0 as isize - y.0 as isize))
859-
.cmp(&b.0.map(|x| b.1.map(|y| x.0 as isize - y.0 as isize)))
860-
});
861-
for (i, &(x, y)) in max_sat_size_vec.iter().enumerate() {
862-
max_sat_size = if i <= k {
863-
x.and_then(|x| max_sat_size.map(|(w, s)| (w + x.0, s + x.1)))
864-
} else {
865-
y.and_then(|y| max_sat_size.map(|(w, s)| (w + y.0, s + y.1)))
866-
};
867-
}
849+
max_sat_size_vec.sort_by(sat_minus_dissat_witness);
850+
let max_sat_size =
851+
max_sat_size_vec
852+
.iter()
853+
.enumerate()
854+
.fold(Some((0, 0)), |acc, (i, &(x, y))| {
855+
if i <= k {
856+
opt_tuple_add(acc, x)
857+
} else {
858+
opt_tuple_add(acc, y)
859+
}
860+
});
861+
862+
ops_count_sat_vec.sort_by(sat_minus_dissat);
863+
let op_count_sat =
864+
ops_count_sat_vec
865+
.iter()
866+
.enumerate()
867+
.fold(Some(0), |acc, (i, &(x, y))| {
868+
if i <= k {
869+
opt_add(acc, x)
870+
} else {
871+
opt_add(acc, Some(y))
872+
}
873+
});
868874

869-
ops_count_sat_vec.sort_by(|a, b| {
870-
a.0.map(|x| x as isize - a.1 as isize)
871-
.cmp(&b.0.map(|x| x as isize - b.1 as isize))
872-
});
873-
for (i, &(x, y)) in ops_count_sat_vec.iter().enumerate() {
874-
op_count_sat = if i <= k {
875-
opt_add(op_count_sat, x)
876-
} else {
877-
opt_add(op_count_sat, Some(y))
878-
};
879-
}
880875
Ok(ExtData {
881876
pk_cost: pk_cost + n - 1, //all pk cost + (n-1)*ADD
882877
has_free_verify: true,
@@ -1034,7 +1029,47 @@ impl Property for ExtData {
10341029
}
10351030
}
10361031

1037-
// Returns Some(max(x,y)) is both x and y are Some. Otherwise, return none
1032+
// Function to pass to sort_by. Sort by (satisfaction cost - dissatisfaction cost).
1033+
//
1034+
// We sort by (satisfaction cost - dissatisfaction cost) to make a worst-case (the most
1035+
// costy satisfactions are satisfied, the most costy dissatisfactions are dissatisfied).
1036+
//
1037+
// Args are of form: (<count_sat>, <count_dissat>)
1038+
fn sat_minus_dissat<'r, 's>(
1039+
a: &'r (Option<usize>, usize),
1040+
b: &'s (Option<usize>, usize),
1041+
) -> std::cmp::Ordering {
1042+
a.0.map(|x| x as isize - a.1 as isize)
1043+
.cmp(&b.0.map(|x| x as isize - b.1 as isize))
1044+
}
1045+
1046+
// Function to pass to sort_by. Sort by (satisfaction cost - dissatisfaction cost).
1047+
//
1048+
// We sort by (satisfaction cost - dissatisfaction cost) to make a worst-case (the most
1049+
// costy satisfactions are satisfied, the most costy dissatisfactions are dissatisfied).
1050+
//
1051+
// Args are of form: (<count_sat>, <count_dissat>)
1052+
fn sat_minus_option_dissat<'r, 's>(
1053+
a: &'r (Option<usize>, Option<usize>),
1054+
b: &'s (Option<usize>, Option<usize>),
1055+
) -> std::cmp::Ordering {
1056+
a.0.map(|x| a.1.map(|y| x as isize - y as isize))
1057+
.cmp(&b.0.map(|x| b.1.map(|y| x as isize - y as isize)))
1058+
}
1059+
1060+
// Function to pass to sort_by. Sort by (satisfaction cost - dissatisfaction cost) of cost of witness.
1061+
//
1062+
// Args are of form: (<max_sat_size>, <count_dissat_size>)
1063+
// max_[dis]sat_size of form: (<cost_of_witness>, <cost_of_sciptsig>)
1064+
fn sat_minus_dissat_witness<'r, 's>(
1065+
a: &'r (Option<(usize, usize)>, Option<(usize, usize)>),
1066+
b: &'s (Option<(usize, usize)>, Option<(usize, usize)>),
1067+
) -> std::cmp::Ordering {
1068+
a.0.map(|x| a.1.map(|y| x.0 as isize - y.0 as isize))
1069+
.cmp(&b.0.map(|x| b.1.map(|y| x.0 as isize - y.0 as isize)))
1070+
}
1071+
1072+
/// Returns Some(max(x,y)) is both x and y are Some. Otherwise, returns `None`.
10381073
fn opt_max<T: Ord>(a: Option<T>, b: Option<T>) -> Option<T> {
10391074
if let (Some(x), Some(y)) = (a, b) {
10401075
Some(cmp::max(x, y))
@@ -1043,7 +1078,12 @@ fn opt_max<T: Ord>(a: Option<T>, b: Option<T>) -> Option<T> {
10431078
}
10441079
}
10451080

1046-
// Returns Some(x+y) is both x and y are Some. Otherwise, return none
1081+
/// Returns Some(x+y) is both x and y are Some. Otherwise, returns `None`.
10471082
fn opt_add(a: Option<usize>, b: Option<usize>) -> Option<usize> {
10481083
a.and_then(|x| b.map(|y| x + y))
10491084
}
1085+
1086+
/// Returns Some((x0+y0, x1+y1)) is both x and y are Some. Otherwise, returns `None`.
1087+
fn opt_tuple_add(a: Option<(usize, usize)>, b: Option<(usize, usize)>) -> Option<(usize, usize)> {
1088+
a.and_then(|x| b.map(|(w, s)| (w + x.0, s + x.1)))
1089+
}

0 commit comments

Comments
 (0)