Implement lowest fee metric correctly#13
Conversation
42f85c7 to
cb70133
Compare
f242bff to
628c01e
Compare
if is_target_met true it should continue to be true if you add a drain from a ChangePolicy. We should try and guarantee we never add a drain when it would invalidate the selection.
38229e5 to
dc46db3
Compare
It may improve best score allowing us to avoid ever adding the children to the heap if their bound function doesn't think they can improve on it.
That proptest is not hitting for some reason.
dc46db3 to
7360052
Compare
|
This now includes a fix for the lowest fee metric. The bound function uses the simplification from #14 to precisely target the amount of negative effective value it could use to remove the change output which is the position of the possible lowest fee. This is where most of complexity of the code comes from and unfortunately the logic of this branch isn't being hit by the proptests. I tried playing around with the parameters of proptest and running a lot more times to hit it but it refused. I had to write a manual test to target this branch. Also I made a change to branch and bound in 17cc8f2 We now score the branch before bounding its children. This allows the parent branch to improve the best score which may exclude its children (this leads to less iterations to find the best solution in one of the tests). |
If we only add a drain when it wouldn't increase waste then it is impossible to decrease waste by adding a new input -- but the logic of the bound function has to account for this situation. So by using min_value_and_waste we never test it!
I figured out why the tests weren't hitting it and fixed that: 9e1cecd
|
evanlinjin
left a comment
There was a problem hiding this comment.
Thanks for taking this forward and fixing my screw-up. I'm liking how this is looking.
Most of my comments are nits, except for the change to the assert! statement in lowest_fee.rs - please have a second look at it!
| let mut return_val = None; | ||
| if !branch.is_exclusion { | ||
| if let Some(score) = self.metric.score(&selector) { | ||
| let better = match self.best { | ||
| Some(best_score) => score < best_score, | ||
| None => true, | ||
| }; | ||
| if better { | ||
| self.best = Some(score); | ||
| return_val = Some(score); | ||
| } | ||
| }; | ||
| } | ||
|
|
||
| let score = match self.metric.score(&selector) { | ||
| Some(score) => score, | ||
| None => return Some(None), | ||
| }; | ||
|
|
||
| if let Some(best_score) = &self.best { | ||
| if score >= *best_score { | ||
| return Some(None); | ||
| } | ||
| } | ||
| self.best = Some(score); | ||
| Some(Some((selector, score))) | ||
| self.insert_new_branches(&selector); | ||
| Some(return_val.map(|score| (selector, score))) |
There was a problem hiding this comment.
Nit: I prefer the way it was written before as it was more readable for me.
| if let Some((_, low_sats_per_wu_candidate)) = cs.unselected().next_back() { | ||
| let ev = low_sats_per_wu_candidate.effective_value(self.target.feerate); | ||
| if ev < 0.0 { | ||
| if ev < -0.0 { |
There was a problem hiding this comment.
Nit: Would this make a difference? In the f32 docs, it states that 0.0 == -0.0 when it comes to comparisons.
If it does make a difference, please have a comment as it is not immediately apparent.
| let mut cs = cs.clone(); | ||
| cs.select(0); | ||
| cs.select(2); | ||
| cs.excess(target, Drain::none()); |
There was a problem hiding this comment.
Nit: do we need this? Was the intention to print the best solution's excess to check that it is greater than 0 for the test?
This replaces #11. This first commit just fixes the metric to make the tests fail. Note the previous calculation was overthinking it. The fee metric is just
inputs - outputs + long_term_feerate * change_weight.Next steps: