2

I was watching this Andreas Antonopoulos presentation on Advanced Bitcoin Scripting.

It appears from Andreas' examples that for a redeem script to satisfy the conditions of the script it needs to leave TRUE (and nothing else) on the stack after it has been executed. This was also enquired about here.

Therefore there is a VERIFY suffix such that some opcodes (e.g. EQUAL, CHECKSIG, CHECKMULTISIG) have competing opcodes (e.g. EQUALVERIFY, CHECKSIGVERIFY, CHECKMULTISIGVERIFY). Instead of leaving TRUE on the stack these VERIFY opcodes will "continue execution of the Script if the outcome of the conditional operator is TRUE" but "will not push that TRUE back to the stack, it will simply continue execution". These VERIFY opcodes can be used to ensure the execution of the redeem script leave TRUE (and nothing else) on the stack rather than say TRUE TRUE TRUE.

However, in this Bitcoin Core PR review club session Pieter Wuille stated (paraphrasing):

For CLEANSTACK you have to have a stack with a single element in it which has to be nonzero. Without CLEANSTACK a non-empty stack with multiple elements is ok as long as the top element is nonzero

I have two questions:

  1. Presumably TRUE is equivalent to 1 and FALSE is equivalent to 0?

  2. Any opcodes that evaluate to FALSE will result in immediate failure and termination of execution? So with non-CLEANSTACK you would never see a resulting stack of TRUE FALSE TRUE pass as FALSE would result in immediate failure and you wouldn't assess the final TRUE. However, you could see a stack of say TRUE 3 TRUE 5 and this would pass with non-CLEANSTACK. (It would fail with CLEANSTACK as CLEANSTACK must have a single element in the resulting stack).

3

Thanks to harding for answering this question on IRC and sanket1729 for edits.

Presumably TRUE is equivalent to 1 and FALSE is equivalent to 0?

TRUE is any non-zero value. This is often used in scripts involving the former OP_NOPx opcodes that don't pop their values off the stack after verification, e.g. a script that can be spend by a miner after a certain height could use: <locktime> OP_CLTV ; if CLTV fails, the transaction is invalid; if it passes, then the non-zero value left on the stack allows the script to pass.

Any opcodes that evaluate to FALSE will result in immediate failure and termination of execution? So with non-CLEANSTACK you would never see a resulting stack of TRUE FALSE TRUE pass as FALSE would result in immediate failure and you wouldn't assess the final TRUE. However, you could see a stack of say TRUE 3 TRUE 5 and this would pass with non-CLEANSTACK. (It would fail with CLEANSTACK as CLEANSTACK must have a single element in the resulting stack).

All that matters without CLEANSTACK is the top value on the stack at the end of execution. Anything further down the stack doesn't matter.

CLEANSTACK is a standardness rule for P2SH but it is a consensus rule for Segwit v0 (BIP141 specification) and Tapscript, SegWit v1 (BIP342 specification, rule 4, ii)

The word "failure" is ambiguous here. There are different ways different opcodes can fail. For example, if OP_CHECKSIG fails it just pushes a 0 to the stack. But if OP_CHECKSIGVERIFY fails, the whole script fails. You can put TRUE FALSE FALSE on the stack using just OP_0 OP_0 OP_1.

Some of the VERIFY opcodes e.g. EQUALVERIFY, CHECKSIGVERIFY, CHECKMULTISIGVERIFY terminate immediately on failure but their non-VERIFY equivalents don't.

All that matters is the state of the stack at the end of script evaluation. For example, you could do OP_CHECKSIG followed by OP_IF OP_PUSHNUM1 OP_ELSE OP_PUSHNUM2 OP_ENDIF, e.g. if the signature succeeds, take one branch; if it fails, take another branch (This isn't considered best practice though and shouldn't generally be done.)

CLEANSTACK is an attempt to prevent malleability by having people put a bunch of junk in your scriptSig or witness data. Because you can just push a bunch of data onto the stack that never gets used and doesn't prevent the script from evaluating correctly. (Pre-segwit, this affected txid malleability and was enforced as a standardness policy rule; with segwit, this is no longer possible as it is a consensus rule)

5
  • Which IRC channel? – Prayank Dec 7 '20 at 14:06
  • 1
    Miniscript ##miniscript – Michael Folkson Dec 7 '20 at 14:08
  • 1
    I think the transaction will fail there is no matching OF_ENDIF for a OP_IF, but I am not 100% sure about it. – sanket1729 Dec 7 '20 at 18:36
  • 1
    just checked this and suggested an edit – sanket1729 Dec 7 '20 at 18:45
  • @sanket1729 Yes, if there are unbalanced IF and ENDIF then the script will fail. Similarly if you use ELSE outside of any IF statement. (Curiously, you can use multiple ELSE statements in a row, and the interpreter will just execute all the odd/even ones depending on the input to the IF.) – Andrew Poelstra Dec 8 '20 at 2:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.