mirror of
https://github.com/ChristopherA/Learning-Bitcoin-from-the-Command-Line.git
synced 2025-06-10 01:16:17 +00:00
Update 10_1_Using_Script_Conditionals.md
This commit is contained in:
parent
95ecd5c449
commit
70ef212835
@ -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.
|
||||
|
Loading…
x
Reference in New Issue
Block a user