Skip to content

Non-recursive bound checks for Miniscript fragments #150

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

Merged
merged 6 commits into from
Nov 10, 2020

Conversation

darosior
Copy link
Contributor

@darosior darosior commented Oct 8, 2020

This is based on #149 and keeps track of the maximum number of stack elements and the size used by both a satisfaction and a dissatisfaction directly in the Miniscript fragment extra data.
This avoids the recursive methods currently called each time we check for limits.

TODO:

  • implement it for satisfaction size as well (i'm using a tuple for the cost differing between witness and scriptSig)
  • replace callers to use these instead of recursive methods
  • fix the (likely compiler-related) error in Check for segwit standardness limits #149
  • cleanup the FIXMEs which are basically reminder for me to ask you

Moved from TODO to "can be done in a follow-up this one is large enough":

  • add new method to Miniscript to get both the dissatisfaction costs in size and stack elements

@darosior darosior force-pushed the avoid_recursion branch 2 times, most recently from c74fb84 to 90377d6 Compare October 8, 2020 14:21
@@ -211,6 +231,8 @@ impl Property for ExtData {
ops_count_nsat: None,
stack_elem_count_sat: Some(1),
stack_elem_count_dissat: Some(1),
max_sat_size: Some((33, 33)),
max_dissat_size: None,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be 33. Same for other hashes

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought hashes were not dissatisfiable ? Sipa implemented this https://github.com/sipa/miniscript/blob/027b422495a8ee3ea3fa7787150389bb65d1b9de/bitcoin/script/miniscript.h#L535-L538 and iirc we did too.

There is, however, a mistake on the stack_elem_count_dissat in this case.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made stack_elem_count_dissat None, as i really think the mistake is this way around.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed

Copy link
Member

@sanket1729 sanket1729 Nov 5, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that this is wrong in the sipa implementation. We should have that as 33 for reasons in the previous comment. @apoelstra

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, that is bug in the sipa implementation as he explicitly considers them being dissatifyable here:

https://github.com/sipa/miniscript/blob/027b422495a8ee3ea3fa7787150389bb65d1b9de/bitcoin/script/miniscript.h#L657 .

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Heh, good catch. There is definitely no canonical dissatisfaction for an unwrapped hash.

@darosior I think we want the estimation functions to return the worst-case value that is possible under standardness rules. If the fragment is supposed not to be satisfiable (for malleability checks or other reasons) then we should use the d flag to indicate that. But if we make it imposible to even estimate these values, it will become harder to work with incomplete fragments or other malleable scripts.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@darosior I think we want the estimation functions to return the worst-case value that is possible under standardness rules.

Does this mean we want this not to be None even if the dissat is malleable ? If so we could have a dissat cost for virtually all fragments here..

But if we make it imposible to even estimate these values, it will become harder to work with incomplete fragments or other malleable scripts.

Hmm.. That's how it was before this PR though ? Just to be clear (i didn't follow the last IRC discussions very closely): do we want to not ignore malleable dissatisfaction anymore ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean we want this not to be None even if the dissat is malleable ? If so we could have a dissat cost for virtually all fragments here..

I don't think there are any non-canonical ones that we are missing here. As you point out, it was a bug in the previous code too.

Copy link
Member

@sanket1729 sanket1729 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for doing this :) There are some breaking API changes here, but they are worth it for sure.

@sanket1729
Copy link
Member

It looks like one of tests was broken :) . https://github.com/rust-bitcoin/rust-miniscript/pull/150/checks?check_run_id=1226708928

} else {
// The thresh is dissatifiable iff all sub policies are dissatifiable
stack_elem_count_dissat = None;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sucks that we don't have Option::zip or Option::zip_with

apoelstra
apoelstra previously approved these changes Nov 4, 2020
Copy link
Member

@apoelstra apoelstra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ack 5881733

@apoelstra
Copy link
Member

Actually can you add a commit which removes max_dissatisfaction_witness_elements etc from astelem.rs? These methods are no longer needed.

@darosior
Copy link
Contributor Author

darosior commented Nov 5, 2020

Added

@sanket1729
Copy link
Member

Based on the comment from @apoelstra, I will re-review the entire PR assuming we are allowing malleable Miniscripts. I think my first review assumed that we were dealing with malleable miniscripts.

@@ -217,6 +235,8 @@ impl Property for ExtData {
ops_count_static: 4,
ops_count_sat: Some(4),
ops_count_nsat: None,
stack_elem_count_sat: Some(1),
stack_elem_count_dissat: None,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we allow malleable dissat, this should be Some(1). Same thing for rest of the hashes

Copy link
Member

@sanket1729 sanket1729 Nov 5, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that hash fragment is

SIZE <32> EQUALVERIFY SHA256 <h> EQUAL . So any 32 bit vec will dissat it

Copy link
Member

@sanket1729 sanket1729 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left a minor discussion comment about dissatisfying hash fragments.
If that requires more discussion, we can merge this PR and possibly have that as a small followup if it is required.

Copy link
Member

@sanket1729 sanket1729 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: the last commit gives a warning about unused std::cmp

@sanket1729 sanket1729 mentioned this pull request Nov 5, 2020
@apoelstra
Copy link
Member

Will need rebase on #169

This avoids recursion to check Segwit standardness limits.

Signed-off-by: Antoine Poinsot <darosior@protonmail.com>
Signed-off-by: Antoine Poinsot <darosior@protonmail.com>
Signed-off-by: Antoine Poinsot <darosior@protonmail.com>
This is inherently bound to the context, and avoids for the caller to
set the cost of 1 depending on wether they are using Segwitv0 or Legacy.

This also makes it reeturn an Option, as previously for
max_witness_elements().

Signed-off-by: Antoine Poinsot <darosior@protonmail.com>
And some other small followups to rust-bitcoin#149

Signed-off-by: Antoine Poinsot <darosior@protonmail.com>
…inal

We don't need them anymore

Signed-off-by: Antoine Poinsot <darosior@protonmail.com>
@darosior
Copy link
Contributor Author

darosior commented Nov 6, 2020

Rebased on master, left a comment in the inner discussion regarding the dissat cost computation.

@sanket1729
Copy link
Member

@darosior , In case you missed I added a comment here. #150 (comment) . We should have hashes be dissatisfyable

@darosior
Copy link
Contributor Author

darosior commented Nov 9, 2020 via email

@sanket1729
Copy link
Member

sanket1729 commented Nov 9, 2020

@darosior , I meant we can fix the opcode stuff later. We should fix the stack size and sat cost as they a part of this PR.

<darosior> But checking right now and we don't :)
<darosior> Hmm so i should fill_ops_count_nsat as well..
<darosior> Will add a new commit rather than amending
<sanket1729_> we can keep that as separate PR. I think this is almost good to go
<darosior> Ok, will open a new PR with the commit then

Copy link
Member

@apoelstra apoelstra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ack eb5e04b

We can fix the dissat thing later

@apoelstra apoelstra merged commit e1f6277 into rust-bitcoin:master Nov 10, 2020
@darosior
Copy link
Contributor Author

Sorry Sanket i never got to answer your comment, pretty busy right now...

<darosior> Hmm so i should fill_ops_count_nsat as well..
<darosior> Will add a new commit rather than amending
<sanket1729_> we can keep that as separate PR. I think this is almost good to go```

Yea, right. I misunderstood that it only concerned the ops.

@darosior darosior deleted the avoid_recursion branch November 10, 2020 20:49
@sanket1729
Copy link
Member

Sure, no worries :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants