-
Notifications
You must be signed in to change notification settings - Fork 141
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Tr compiler v3 - Incremental Enumerative Compiler #418
Tr compiler v3 - Incremental Enumerative Compiler #418
Conversation
thresh
-enumerationthresh
-enumeration
cb5cf91
to
3d473c9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did some partial review.
src/policy/concrete.rs
Outdated
@@ -278,6 +278,7 @@ impl<Pk: MiniscriptKey> Policy<Pk> { | |||
)), | |||
_ => { | |||
let (internal_key, policy) = self.clone().extract_key(unspendable_key)?; | |||
policy.check_tapleaf()?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should update the name of the function. This implies that we can checking something on tapleafs. Perhaps, check_num_tapleaves
?
I would prefer to inline the check_num_tapleaves
here, but up to you.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, the function name is a misnomer. Will change the name as suggested.
src/policy/concrete.rs
Outdated
/// Check on the number of TapLeaves | ||
#[cfg(feature = "compiler")] | ||
fn check_tapleaf(&self) -> Result<(), Error> { | ||
if self.num_tap_leaves() > 100_000 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make this is local constant MAX_COMPILATION_TAP_LEAVES
#[cfg(feature = "compiler")] | ||
fn check_tapleaf(&self) -> Result<(), Error> { | ||
if self.num_tap_leaves() > 100_000 { | ||
return Err(errstr("Too many Tapleaves")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's use a dedicated error variant instead of errstr
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is still not addressed.
src/policy/concrete.rs
Outdated
Ok(node) | ||
|
||
#[cfg(feature = "compiler")] | ||
fn combination(n: usize, k: usize) -> usize { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whenever we call this, we need to make sure that we are having an overflow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function isn't supposed to be there. Seems I messed up while squashing the commits, my bad!
src/policy/concrete.rs
Outdated
fn num_tap_leaves(&self) -> usize { | ||
match self { | ||
Policy::Or(subs) => subs.iter().map(|(_prob, pol)| pol.num_tap_leaves()).sum(), | ||
Policy::Threshold(k, subs) if *k == 1 => combination(subs.len(), *k), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens when there is overflow here? We should use all the checked_sum, checked_mul
variants here to check for this. Return Option where we return None when there is overflow
#[cfg(feature = "compiler")] | ||
fn to_tapleaf_prob_vec(&self, prob: f64) -> Vec<(f64, Policy<Pk>)> { | ||
match *self { | ||
match self { | ||
Policy::Or(ref subs) => { | ||
let total_odds: usize = subs.iter().map(|(ref k, _)| k).sum(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove the ref k here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As in, remove the ref
. It should clean up * (*k) code in the next line
src/policy/concrete.rs
Outdated
let total_odds = subs.len(); | ||
subs.iter() | ||
.map(|policy| policy.to_tapleaf_prob_vec(prob / total_odds as f64)) | ||
.flatten() | ||
.collect::<Vec<_>>() | ||
} | ||
ref x => vec![(prob, x.clone())], | ||
// Instead of the fixed-point algorithm, consider direct k-choose-n split if limits |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see why this comment is relevant here. This function is only splitting ors AFAIU.
src/policy/concrete.rs
Outdated
/// Given a [`Policy`], return a vector of policies whose disjunction is isomorphic to the initial one. | ||
/// This function is supposed to incrementally expand i.e. represent the policy as disjunction over | ||
/// sub-policies output by it. The probability calculations are similar as | ||
/// [to_tapleaf_prob_vec][`Policy::to_tapleaf_prob_vec`] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you have the link twice?
src/policy/concrete.rs
Outdated
Policy::Or(subs) => { | ||
let total_odds = subs.iter().fold(0, |acc, x| acc + x.0); | ||
subs.iter() | ||
.map(|(odds, pol)| (prob * *odds as f64 / total_odds as f64, pol.clone())) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this not be recursive?
src/policy/concrete.rs
Outdated
Policy::Threshold(k, subs) if *k == 1 => { | ||
let total_odds = subs.len(); | ||
subs.iter() | ||
.map(|pol| (prob / total_odds as f64, pol.clone())) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment here
3d473c9
to
788a03b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
code logic ACK, but would need some re-factors that will make it faster
src/miniscript/limits.rs
Outdated
@@ -50,3 +50,6 @@ pub const MAX_BLOCK_WEIGHT: usize = 4000000; | |||
/// Maximum pubkeys as arguments to CHECKMULTISIG | |||
// https://github.com/bitcoin/bitcoin/blob/6acda4b00b3fc1bfac02f5de590e1a5386cbc779/src/script/script.h#L30 | |||
pub const MAX_PUBKEYS_PER_MULTISIG: usize = 20; | |||
|
|||
/// Maximum TapLeafs allowed in a compiled TapTree | |||
pub(crate) const MAX_COMPILATION_LEAVES: usize = 10_000; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These constants are constants related to consensus standardness limits of bitcoin and are not specific to rust-miniscript. We should move MAX_COMPILATION_LEAVES to compiler.rs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we move it to concrete.rs since that's where the tr compiler is?
src/policy/concrete.rs
Outdated
/// any one of the conditions exclusively. | ||
#[cfg(feature = "compiler")] | ||
fn generate_combination<Pk: MiniscriptKey>( | ||
policy_vec: &Vec<Policy<Pk>>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should use Rc instead of cloning it here multiple times. This should help in space and time complexity
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We would need a new data structure with Arc's here to store these instead of Policy. But we do not want so many clones here. This might be why everything is slow.
You can create something similar to Policy
but with Arcs instead of Owned sub-policies.
1355757
to
fee0f7c
Compare
@sanket1729 I've added a new structure |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mostly ACK. found a bug when dealing with more than MAX_COMPILATION_LEAVES part.
See the last commit here https://github.com/sanket1729/rust-miniscript/tree/pr418.
We are really close to merging this. I think you would run in --release mode to see the performance difference.
fee0f7c
to
a4cf8b5
Compare
src/policy/concrete.rs
Outdated
} | ||
|
||
// --- Sanity Checks --- | ||
if enum_len > MAX_COMPILATION_LEAVES || *curr_policy == PolicyArc::Unsatisfiable { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We do not enumerate the sub-policy under consideration since we either exceed MAX_COMPILATION_LEAVES
or the policy itself compiled to Unsatisfiable
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was causing bugs because the enumeration was incorrect. I think the logic here would need to be improved. If you replace thresh(51,...) with thresh(49) you would see a crash
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was a major bug. I've fixed it in the 9c8a1c3.
thresh
-enumerationa4cf8b5
to
2186b09
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Last few comments.
#[cfg(feature = "compiler")] | ||
fn check_tapleaf(&self) -> Result<(), Error> { | ||
if self.num_tap_leaves() > 100_000 { | ||
return Err(errstr("Too many Tapleaves")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is still not addressed.
src/policy/concrete.rs
Outdated
if enum_len > MAX_COMPILATION_LEAVES || *curr_policy == PolicyArc::Unsatisfiable { | ||
// Root-level enumeration exceeds the limit, so push back the initial policy | ||
if ret.is_empty() { | ||
ret.push((1.0, arc_self)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not the expected behavior. We need to split as much as we can until we hit the limit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The variable enum_len
stores the vector length if we consider the enumeration of plausible node. If this exceeds limit, we don't replace the initial plausible sub-policy by its enumerations (which is done after the check). I just handled the base-case where the root-level enumeration itself exceeds the limit, where we just return the policy itself.
a7b1e82
to
71e4f81
Compare
71e4f81
to
f9901ab
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK f9901ab. Can you also rebase to latest master? I think we are good to go here
Unless @kanishk779 found something else in review here. |
f9901ab
to
265b063
Compare
I will wait a couple of days for @kanishk779 to respond. Will merge this later |
@SarcasticNastik , can you also update the PR description? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK 265b063
@SarcasticNastik , sorry for this. But I promise, this would be last rebase |
265b063
to
55b48fc
Compare
55b48fc
to
97de242
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK 97de242
3f451db Release 8.0.0 (sanket1729) Pull request description: Draft release PR. Still blocked on reviews of 1) #418 2) #450 3) #461 ACKs for top commit: apoelstra: ACK 3f451db Tree-SHA512: aa455fd57a894b1edb49b6273126a05c9d0897ca50ee572fa8a59b4d2a96e2013f2ed9ec4b96cd5e449ba5b5ee6bd32aa57da110df69bd35b8a970ccb1440002
…022_10 51d66d1 Merge rust-bitcoin/rust-miniscript#418: Tr compiler v3 - Incremental Enumerative Compiler
This PR is a follow-up in the Tr-compiler series. This introduces splitting of a
thresh(k, ...n...)
policy into different Tapleaves.