Update 10_1_Using_Script_Conditionals.md

This commit is contained in:
Shannon Appelcline 2017-06-01 12:21:59 -07:00 committed by GitHub
parent 95ecd5c449
commit 70ef212835

View File

@ -50,7 +50,7 @@ ENDIF
OP_EQUALVERIFY
OP_CHECKSIG
```
So, if the `OP_DUP` is successful, then we get to do the first block, else the second. But that doesn't make any sense! Why wouldn't the `OP_DUP` succeed.
So, you might think, if the `OP_DUP` is successful, then we get to do the first block, else the second. But that doesn't make any sense! Why wouldn't the `OP_DUP` succeed?!
And, indeed, it doesn't make any sense, because we accidentally read the statement using the wrong notation. The correct reading of this is:
```
@ -71,7 +71,7 @@ ENDIF
OP_EQUALVERIFY
OP_CHECKSIG
```
The `True` or `False` statement is placed on the stack _prior_ to running the `IF`, then the correct block is run base on that result.
The `True` or `False` statement is placed on the stack _prior_ to running the `IF`, then the correct block is run based on that result.
This is intended as a poor man's 1-of-2 multisignature. The owner of `<privKeyA>` would put `<signatureA> <pubKeyA> True` in his locking script, while the owner of `<privKeyB>` would put `<signatureB> <pubKeyB> False` in her locking script. That trailing `True` or `False` tells the script which hash to check against, then the `OP_EQUALVERIFY` and the `OP_CHECKSIG` at the end do the real work.
@ -111,9 +111,11 @@ Stack: [ <signatureA> <pubKeyA> ]
Then we run the first few, obvious commands, `OP_DUP` and `OP_HASH160` and push another constant:
```
Script: OP_HASH160 <pubKeyHashA> OP_EQUAL IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG ENDIF
Running: <pubKeyA> OP_DUP
Stack: [ <signatureA> <pubKeyA> <pubKeyA> ]
Script: <pubKeyHashA> OP_EQUAL IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG ENDIF
Running: <pubKeyA> OP_HASH160
Stack: [ <signatureA> <pubKeyA> <pubKeyHashA> ]
Script: OP_EQUAL IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG ENDIF
@ -122,16 +124,19 @@ Stack: [ <signatureA> <pubKeyA> <pubKeyHashA> <pubKeyHashA> ]
Next we run the `OP_EQUAL`, which is what's going to feed the `IF`:
```
Script: IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG ENDIF
Running: <pubKeyHashA> <pubKeyHashA> OP_EQUAL
Stack: [ <signatureA> <pubKeyA> True ]
```
Now the `IF` runs, and since there's a `True`, it only runs the first block, eliminating all the rest:
```
Script: OP_CHECKSIG
Running: True IF
Stack: [ <signatureA> <pubKeyA> ]
```
And the `OP_CHECKSIG` will end up `True` as well:
```
Script:
Running: <signatureA> <pubKeyA> OP_CHECKSIG
Stack: [ True ]
```
#### Run the False Branch
@ -149,9 +154,11 @@ Stack: [ <signatureB> <pubKeyB> ]
Then we run the first few, obvious commands, `OP_DUP` and `OP_HASH160` and push another constant:
```
Script: OP_HASH160 <pubKeyHashA> OP_EQUAL IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG ENDIF
Running: <pubKeyB> OP_DUP
Stack: [ <signatureB> <pubKeyB> <pubKeyB> ]
Script: <pubKeyHashA> OP_EQUAL IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG ENDIF
Running: <pubKeyB> OP_HASH160
Stack: [ <signatureB> <pubKeyB> <pubKeyHashB> ]
Script: OP_EQUAL IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG ENDIF
@ -160,30 +167,48 @@ Stack: [ <signatureB> <pubKeyB> <pubKeyHashB> <pubKeyHashA> ]
Next we run the `OP_EQUAL`, which is what's going to feed the `IF`:
```
Script: IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG ENDIF
Running: <pubKeyHashB> <pubKeyHashA> OP_EQUAL
Stack: [ <signatureB> <pubKeyB> False ]
```
Whoop! The result was `False` because `<pubKeyHashB>` does not equal `<pubKeyHashA>`. Now when the `IF` runs, it collapses down to just the `ELSE` statement:
```
Script: OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG
Running: False IF
Stack: [ <signatureB> <pubKeyB> ]
```
Afterward, we go through the whole rigamarole again, starting with another `OP_DUP`, but eventually testing against the other `pubKeyHash`:
```
Script: OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG
Running: <pubKeyB> OP_DUP
Stack: [ <signatureB> <pubKeyB> <pubKeyB> ]
Script: <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG
Running: <pubKeyB> OP_HASH160
Stack: [ <signatureB> <pubKeyB> <pubKeyHashB> ]
Script: OP_EQUALVERIFY OP_CHECKSIG
Stack: [ <signatureB> <pubKeyB> <pubKeyHashB> <pubKeyHashB> ]
Script: OP_EQUALVERIFY OP_CHECKSIG
Script:OP_CHECKSIG
Running: OP_EQUALVERIFY <pubKeyHashB> <pubKeyHashB>
Stack: [ <signatureB> <pubKeyB> ]
Script:
Running: <signatureB> <pubKeyB> OP_CHECKSIG
Stack: [ True ]
```
This probably isn't nearly as efficient as a true Bitcoin multisig, but it's a good example of how results pushed onto the stack by previous tests can be used to feed future conditions. In this case, it's the failure of the first signature which tells the conditional that maybe it should go check the second.
This probably isn't nearly as efficient as a true Bitcoin multisig, but it's a good example of how results pushed onto the stack by previous tests can be used to feed future conditionals. In this case, it's the failure of the first signature which tells the conditional that maybe it should go check the second one.
## Understand Other Conditionals
There are a few other conditionals of note. The big one is `OP_NOTIF` (0x64), which executes if the top item is `False`. An `ELSE` can be placed with it, which as usually is executed if the main block is not executed. You still end with `OP_ENDIF`.
There's also an `OP_IFDUP` (0x73), which duplicates the top stack item only if it's not 0.
These options are used much less than the main IF/ELSE/ENDIF construction.
## Summary: Using Script Conditionals
Conditionals in Bitcoin Script allow you to halt the Script (using `OP_VERIFY`) or to choose different branches of execution (using `OP_IF`). However, reading `OP_IF` can be a bit tricky. Remember that it's item pushed onto the stack _before_ the `OP_IF` is run that controls its execution; that item will typically be part of the unlocking script (or else a direct result of items in the unlocking script).
_What is the power of conditionals?_ Script Conditionals are the final major building block in Bitcoin Script. They're what are required to turn simple, static Bitcoin Scripts into complex, dynamic Bitcoin Scripts that can evaluate differently based on different times, different circumstances, or differe user inputs. In other words, they're the final basis of smart contracts.