In Miniscript, we have type modifiers, which guarantee additional properties for an expression. 866284d makes the wrapper βd:β have the βuβ property under Tapscript.
What is the βd:β wrapper and the βuβ type modifier?
Why is it that we can make d: have the u property here? Why not in non-Tapscript Miniscript?
This PR adds some logic for statically ensuring no spending path exceeds the stack size at execution time:
Why does this matter for Tapscript?
Whatβs the approach taken by this PR? What are the pros/cons? (hint: efdd154)
Can you think of an alternative approach to ensure no spending path exceeds the stack size?
In e81635c, the scripts are optionally padded during fuzzing. Why?
What is the most significant change to the descriptor logic in this PR (hint: 08db38a). Why is it needed?
<josie> planning to review <a href='https://bitcoincore.reviews/27255-2' target='blank'>https://bitcoincore.reviews/27255-2</a> , which is a follow up to last weeks PR review club: https://bitcoincore.reviews/27255
<josie> cool, let's start with question 2: In Miniscript, we have type modifiers, which guarantee additional properties for an expression. commit 866284d makes the wrapper βd:β have the βuβ property under Tapscript
<abubakar> from miniscript website "d" is a dissatisfiable: does not include a signature or a hash preimage cannot rely on timelocks for being satisfied
<stickies-v> properties/type modifiers describe attributes of fragments (expressions), e.g. the `z` property says that a fragment with that property always consumes exactly 0 stack elements
<stickies-v> before taproot, OP_IF would evaluate to true for any value > 0, whereas in taproot we require the argument to be either 0/1. Which means that in case of true, the argument is definitely 1. Because the `d:` wrapper duplicates the argument (OP_DUP), we can state that in case of satisfaction this fragment will put 1 on the stack
<josie> perhaps a better way to phrase my question: was there anything pre-tapscript that would have prevented "regular" users from constructing transactions that used this OP_IF behavior?
<josie> I don't have a link to it, but darosier has shown some nasty examples where miners could exploit this to steal funds in scripts that use thresholds
<josie> so if people remember from last week, MINIMALIF was added as a consensus rule in tapscript, which means it is now safe to say that d:X fragments can have the u property
<kevkevin> didn't CHECKMULTISIG have a limit of 20, and CHECKSIGADD removed that limit so now we're bound by the stack size limit, not sure if I'm remembering correctly
<instagibbs> miniscript does more than 20 signatures fine I think. BIP342 introduces "It is extended to also apply to the size of initial stack" which means it can't exceed limits ever and succeed. Not sure that answers it
<stickies-v> miniscript also checks if a script is sane, which (amongst others) also means that it is consensus valid and standard - this helps a lot with analysis of scripts. for example, you may not care about the entire script, just that you have a certain spending path to which you control the keys. but if it then turns out that that spending path is actually not spendable (because of stack size limit), that's a problem
<josie> kevkevin: CHECKMULTISIG did have a limit, but I think its more correct to say CHECKMULTISIG was disabled in tapscript and CHECKSIGADD was added, and CHECKSIGADD doesn't have a limit (aside from the stack size limit)
<josie> stickies-v: great point re: miniscript. I think tapscript's decision to remove some of the "arbitrary" limits from before makes being able to reason about sanity much more straightforward
<josie> haha the silence is pretty deafening on this one (which admittedly is a pretty in the weeds question), so lets finish with the last question about descriptors
<stickies-v> sorry josie I didn't review this far ahead so just looking at the commit now - if you wouldn't mind summarizing your answer i'd appreciate that?
<josie> sure! basically, it tracks how the stack will be affected after the script executes, and also how many items will be pushed on the stack during execution. the second part is the part I don't fully understand, but it also checks the maximum witness size for a fragment and takes the lesser. regarding pros and cons, it mentions this being a conservative approach because the max
<josie> as a con, you could say since this is a conservative approximation, which might not let you do a script that you would otherwise be able to do with more precise accounting
<sipa> We could arguably define a multi() fragment that intelligently maps to multiple CHECKMULTISIG opcodes, and that wouldn't be bound by the 20 limit either, but that's just hiding a lot of complexity that can equally well be captured at a higher level (forcing the miniscript to combine multiple multi() fragments explicitly).