Merge pull request #20 from kallewoof/07-add-btcdeb

Add btcdeb stuff to chapter 7
This commit is contained in:
Christopher Allen 2018-01-03 15:41:55 -08:00 committed by GitHub
commit cef5c38d1f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 343 additions and 0 deletions

View File

@ -4,6 +4,33 @@
Bitcoin Scripts may not initially seem that intuitive, but their execution is quite simple, using reverse Polish notation and a stack.
## Running Bitcoin Script code
It is recommended that you run through the examples in a Bitcoin Script Debugger (`btcdeb`) to see the transformations happening
on the stack.
### Installing btcdeb
From some appropriate folder (e.g. `~/workspace`), clone the btcdeb project from Github and compile/install it. Note that it is recommended that you install readline, as this makes the debugger a lot easier to use (history using up/down arrows, left-right movement, autocompletion using tab, etc.). The package is usually called `libreadline-dev` (linux) or just `readline` (mac).
```Bash
$ git clone https://github.com/kallewoof/btcdeb.git
$ cd btcdeb
$ ./autogen.sh
$ ./configure
$ make
$ make install
```
### Bitcoin Script Debugging Primer
`btcdeb` takes a script, as well as any number of stack entries, as startup arguments. If you start it up with no arguments, you simply get an interpreter
where you may issue `exec [opcode]` commands to perform actions directly.
`btcc` takes script opcodes and data and outputs a Bitcoin Script in hexadecimal form.
We will make use of both of these in the sections below.
## Understand the Scripting Language
A Bitcoin Script has three parts: it has a line of input; it has a stack for storage; and it has specific commands for execution.
@ -35,6 +62,45 @@ Stack: [ 1 2 ]
```
_Note that in this and in following examples the top of the stack is to the right and the bottom is to the left._
Let's try this out:
```Bash
$ btcc OP_1 OP_2 OP_ADD
515293
$ btcdeb $(btcc OP_1 OP_2 OP_ADD) # or: btcdeb 515293
btcdeb -- type `btcdeb -h` for start up options
valid script
3 op script loaded. type `help` for usage information
script | stack
--------+--------
1 |
2 |
OP_ADD |
#0001 1
btcdeb> step
<> PUSH stack 01
script | stack
--------+--------
2 | 01
OP_ADD |
#0002 2
btcdeb> step
<> PUSH stack 02
script | stack
--------+--------
OP_ADD | 02
| 01
#0003 OP_ADD
btcdeb> step
<> POP stack
<> POP stack
<> PUSH stack 03
script | stack
--------+--------
| 03
```
> `btcdeb` allows you to repeat the previous command by hitting enter. We will be doing this in subsequent examples, so don't be surprised about `btcdeb>` prompts with nothing as input. It is simply repeating the previous (often `step`) command.
### Understand the Opcodes
When a Bitcoin Script encounters an operator, it evaluates it. Each operator pops zero or more elements off the stack as inputs, usually one or two. It then processes them in a specific way before pushing zero or more elements back on the stack, usually one or two.
@ -71,6 +137,62 @@ Running: 5 4 OP_SUB
Stack: [ 1 ]
```
Let's try this one too:
```Bash
$ btcdeb $(btcc OP_3 OP_2 OP_ADD OP_4 OP_SUB)
btcdeb -- type `btcdeb -h` for start up options
valid script
5 op script loaded. type `help` for usage information
script | stack
--------+--------
3 |
2 |
OP_ADD |
4 |
OP_SUB |
#0001 3
btcdeb> step
<> PUSH stack 03
script | stack
--------+--------
2 | 03
OP_ADD |
4 |
OP_SUB |
#0002 2
btcdeb>
<> PUSH stack 02
script | stack
--------+--------
OP_ADD | 02
4 | 03
OP_SUB |
#0003 OP_ADD
btcdeb>
<> POP stack
<> POP stack
<> PUSH stack 05
script | stack
--------+--------
4 | 05
OP_SUB |
#0004 4
btcdeb>
<> PUSH stack 04
script | stack
--------+--------
OP_SUB | 04
| 05
#0005 OP_SUB
btcdeb>
<> POP stack
<> POP stack
<> PUSH stack 01
script | stack
--------+--------
| 01
```
## Understand the Usage of Bitcoin Script
That's pretty much Bitcoin Scripting ... other than a few intricacies for how this scripting language interacts with Bitcoin itself.

View File

@ -67,6 +67,227 @@ Stack: [ True ]
```
The Script now ends and the transaction is allowed to respend the UTXO in question.
## Running through a real example
If you have a scriptPubKey (the script) and a signature and pubkey (the result of running the sigScript of the input), you can debug these by doing
```Bash
$ btcdeb <script> <signature> <pubkey>
```
For example, transaction [4de699d05b416175ad7a119013563a0f436abe46c6a52f05bf59baca1b2aec41](https://www.smartbit.com.au/tx/4de699d05b416175ad7a119013563a0f436abe46c6a52f05bf59baca1b2aec41) in block 499033 has as its first output the script sig `483045022100c7d8e302908fdc601b125c2734de63ed3bf54353e13a835313c2a2aa5e8f21810220131fad73787989d7fbbdbbd8420674f56bdf61fed5dc2653c826a4789c685011012103b05bdbdf395e495a61add92442071e32703518b8fca3fc34149db4b56c93be42`.
The spent transaction output (txid [d0fcb7713582e7cda598d79b3ab084132f93db00e2ccde9bbd1d2660c55abe47](https://www.smartbit.com.au/tx/d0fcb7713582e7cda598d79b3ab084132f93db00e2ccde9bbd1d2660c55abe47) index 33) has as its script pub key `76a914897c81ac37ae36f7bc5b91356cfb0138bfacb3c188ac`.
We can interpret this in two ways. Either put the two together into one big script:
```Bash
$ btcdeb 483045022100c7d8e302908fdc601b125c2734de63ed3bf54353e13a835313c2a2aa5e8f21810220131fad73787989d7fbbdbbd8420674f56bdf61fed5dc2653c826a4789c685011012103b05bdbdf395e495a61add92442071e32703518b8fca3fc34149db4b56c93be4276a914897c81ac37ae36f7bc5b91356cfb0138bfacb3c188ac
btcdeb -- type `btcdeb -h` for start up options
valid script
7 op script loaded. type `help` for usage information
script | stack
-------------------------------------------------------------------+--------
3045022100c7d8e302908fdc601b125c2734de63ed3bf54353e13a835313c2a... |
03b05bdbdf395e495a61add92442071e32703518b8fca3fc34149db4b56c93be42 |
OP_DUP |
OP_HASH160 |
897c81ac37ae36f7bc5b91356cfb0138bfacb3c1 |
OP_EQUALVERIFY |
OP_CHECKSIG |
```
Or we can interpret them one at a time, and use the script sig resulting stack as the input stack to the script pub key -- since we only really want the
output, we can pipe the script to `btcdeb` and it will just print out the results (presuming the script executes cleanly):
```Bash
$ echo "483045022100c7d8e302908fdc601b125c2734de63ed3bf54353e13a835313c2a2aa5e8f21810220131fad73787989d7fbbdbbd8420674f56bdf61fed5dc2653c826a4789c685011012103b05bdbdf395e495a61add92442071e32703518b8fca3fc34149db4b56c93be42" | btcdeb
3045022100c7d8e302908fdc601b125c2734de63ed3bf54353e13a835313c2a2aa5e8f21810220131fad73787989d7fbbdbbd8420674f56bdf61fed5dc2653c826a4789c68501101
03b05bdbdf395e495a61add92442071e32703518b8fca3fc34149db4b56c93be42
```
We can then run the script pub key with these two stack entries as arguments:
```Bash
$ btcdeb 76a914897c81ac37ae36f7bc5b91356cfb0138bfacb3c188ac \
3045022100c7d8e302908fdc601b125c2734de63ed3bf54353e13a835313c2a2aa5e8f21810220131fad73787989d7fbbdbbd8420674f56bdf61fed5dc2653c826a4789c68501101 \
03b05bdbdf395e495a61add92442071e32703518b8fca3fc34149db4b56c93be42
btcdeb -- type `btcdeb -h` for start up options
valid script
5 op script loaded. type `help` for usage information
script | stack
-----------------------------------------+-------------------------------------------------------------------
OP_DUP | 03b05bdbdf395e495a61add92442071e32703518b8fca3fc34149db4b56c93be42
OP_HASH160 | 3045022100c7d8e302908fdc601b125c2734de63ed3bf54353e13a835313c2a...
897c81ac37ae36f7bc5b91356cfb0138bfacb3c1 |
OP_EQUALVERIFY |
OP_CHECKSIG |
#0001 OP_DUP
```
We can also be fancy and run the results of the pipe call as argument to the second call,
```Bash
$ btcdeb 76a914897c81ac37ae36f7bc5b91356cfb0138bfacb3c188ac $(echo "483045022100c7d8e302908fdc601b125c2734de63ed3bf54353e13a835313c2a2aa5e8f21810220131fad73787989d7fbbdbbd8420674f56bdf61fed5dc2653c826a4789c685011012103b05bdbdf395e495a61add92442071e32703518b8fca3fc34149db4b56c93be42" | btcdeb)
btcdeb -- type `btcdeb -h` for start up options
valid script
5 op script loaded. type `help` for usage information
script | stack
-----------------------------------------+-------------------------------------------------------------------
OP_DUP | 03b05bdbdf395e495a61add92442071e32703518b8fca3fc34149db4b56c93be42
OP_HASH160 | 3045022100c7d8e302908fdc601b125c2734de63ed3bf54353e13a835313c2a...
897c81ac37ae36f7bc5b91356cfb0138bfacb3c1 |
OP_EQUALVERIFY |
OP_CHECKSIG |
#0001 OP_DUP
```
Either way we do it, we end up with the script on the left hand side and the stack on the right hand side.
The top-most item in the stack is the top item, and things are "popped off" from top to bottom.
The first item here is a public key and the second item is a signature.
We can check the stack directly using the `stack` command.
```Bash
btcdeb> stack
<01> 03b05bdbdf395e495a61add92442071e32703518b8fca3fc34149db4b56c93be42 (top)
<02> 3045022100c7d8e302908fdc601b125c2734de63ed3bf54353e13a835313c2a2aa5e8f21810220131fad73787989d7fbbdbbd8420674f56bdf61fed5dc2653c826a4789c68501101
```
We can also check the script we're running with `print`:
```Bash
btcdeb> print
-> #0001 OP_DUP
#0002 OP_HASH160
#0003 897c81ac37ae36f7bc5b91356cfb0138bfacb3c1
#0004 OP_EQUALVERIFY
#0005 OP_CHECKSIG
```
The `->` arrow shows us the next instruction that is to be executed. If we run `step` we will perform the `OP_DUP` command:
```Bash
btcdeb> step
<> PUSH stack 03b05bdbdf395e495a61add92442071e32703518b8fca3fc34149db4b56c93be42
script | stack
-----------------------------------------+-------------------------------------------------------------------
OP_HASH160 | 03b05bdbdf395e495a61add92442071e32703518b8fca3fc34149db4b56c93be42
897c81ac37ae36f7bc5b91356cfb0138bfacb3c1 | 03b05bdbdf395e495a61add92442071e32703518b8fca3fc34149db4b56c93be42
OP_EQUALVERIFY | 3045022100c7d8e302908fdc601b125c2734de63ed3bf54353e13a835313c2a...
OP_CHECKSIG |
#0002 OP_HASH160
```
Firstly, directly following the command are any PUSH or POP operations done to the stack, listed with some right-indentation and with a `<>` prefix.
Here we see that `03b...` was pushed onto the stack. The right side shows us that the `03b...` that was there was duplicated and put on the
stack again at the top.
We can keep stepping through the program and watch as it operates on the stack based on the left hand opcodes.
```Bash
btcdeb> step
<> PUSH stack 03b05bdbdf395e495a61add92442071e32703518b8fca3fc34149db4b56c93be42
script | stack
-----------------------------------------+-------------------------------------------------------------------
OP_HASH160 | 03b05bdbdf395e495a61add92442071e32703518b8fca3fc34149db4b56c93be42
897c81ac37ae36f7bc5b91356cfb0138bfacb3c1 | 03b05bdbdf395e495a61add92442071e32703518b8fca3fc34149db4b56c93be42
OP_EQUALVERIFY | 3045022100c7d8e302908fdc601b125c2734de63ed3bf54353e13a835313c2a...
OP_CHECKSIG |
#0002 OP_HASH160
btcdeb> step
<> POP stack
<> PUSH stack 897c81ac37ae36f7bc5b91356cfb0138bfacb3c1
script | stack
-----------------------------------------+-------------------------------------------------------------------
897c81ac37ae36f7bc5b91356cfb0138bfacb3c1 | 897c81ac37ae36f7bc5b91356cfb0138bfacb3c1
OP_EQUALVERIFY | 03b05bdbdf395e495a61add92442071e32703518b8fca3fc34149db4b56c93be42
OP_CHECKSIG | 3045022100c7d8e302908fdc601b125c2734de63ed3bf54353e13a835313c2a...
#0003 897c81ac37ae36f7bc5b91356cfb0138bfacb3c1
btcdeb>
<> PUSH stack 897c81ac37ae36f7bc5b91356cfb0138bfacb3c1
script | stack
-----------------------------------------+-------------------------------------------------------------------
OP_EQUALVERIFY | 897c81ac37ae36f7bc5b91356cfb0138bfacb3c1
OP_CHECKSIG | 897c81ac37ae36f7bc5b91356cfb0138bfacb3c1
| 03b05bdbdf395e495a61add92442071e32703518b8fca3fc34149db4b56c93be42
| 3045022100c7d8e302908fdc601b125c2734de63ed3bf54353e13a835313c2a...
#0004 OP_EQUALVERIFY
```
In the second step above, the "opcode" was simply a chunk of data. Data is interpreted as a "push" operation of the data itself,
which you can see is what happened here. The next operator is the `OP_EQUALVERIFY` which checks that the two top items are identical.
Which you can observe that they are, so the operation should succeed. If the two were not identical, it should fail.
> *EXERCISE:* Pop off the top entry, and push some other random data on and step into the data. You should receive an error. Now pop your data off and push 897c81ac37ae36f7bc5b91356cfb0138bfacb3c1 back onto the stack and then try stepping again. It should now succeed. Use the `exec` command to perform operations on-the-fly.
If you `step` two more times, you will have an error. This is because `btcdeb` does not know enough to verify
the signature of the transaction (specifically, it needs the transaction itself). We can pass that in to test the
signature verification part as well by grabbing the transaction hex (note: not the txid, we need the entire hex
of the transaction) and including it in the call to `btcdeb`.
We can get the hex of any transaction by appending `?format=hex` to the end of a transaction on
blockchain.info. The transaction here is found at: https://blockchain.info/tx/4de699d05b416175ad7a119013563a0f436abe46c6a52f05bf59baca1b2aec41?format=hex
Restart btcdeb with `tx=`(hex):
```Bash
$ ./btcdeb \
tx=010000000247be5ac560261dbd9bdecce200db932f1384b03a9bd798a5cde7823571b7fcd0210000006b483045022100c7d8e302908fdc601b125c2734de63ed3bf54353e13a835313c2a2aa5e8f21810220131fad73787989d7fbbdbbd8420674f56bdf61fed5dc2653c826a4789c685011012103b05bdbdf395e495a61add92442071e32703518b8fca3fc34149db4b56c93be42ffffffffc6f5428a05fc20d1aa27c14e1e9bacb07f16d67895d2d48b97792167ad9c7cd1010000006a47304402201b0e1e9e3632740859c1f76dc002af546d28ecca10dbe96f5350fbc8daa3b279022017878fda5c2d47bb03d1554ed4637b554ec63b135df5387a4a32125cda6dd794012103e7cfd3c98952410dd14079e9160f91f968240da2603e25e4b3ef555fc7ed7d09ffffffff030066e9000000000017a9146c52f451a2bc85b815610fa5cd13127cb5c5a7c787c3df5307000000001976a914726d8c8926da39704d60dd401fa4026aa836068e88aca0950100000000001976a91475eac11f3cfda3e79c90469dac0ebaaaacde701488ac00000000 \
76a914897c81ac37ae36f7bc5b91356cfb0138bfacb3c188ac \
3045022100c7d8e302908fdc601b125c2734de63ed3bf54353e13a835313c2a2aa5e8f21810220131fad73787989d7fbbdbbd8420674f56bdf61fed5dc2653c826a4789c68501101 \
03b05bdbdf395e495a61add92442071e32703518b8fca3fc34149db4b56c93be42
btcdeb -- type `./btcdeb -h` for start up options
got transaction:
CTransaction(hash=4de699d05b, ver=1, vin.size=2, vout.size=3, nLockTime=0)
CTxIn(COutPoint(d0fcb77135, 33), scriptSig=483045022100c7d8e302908f)
CTxIn(COutPoint(d17c9cad67, 1), scriptSig=47304402201b0e1e9e363274)
CScriptWitness()
CScriptWitness()
CTxOut(nValue=0.15296000, scriptPubKey=a9146c52f451a2bc85b815610fa5cd)
CTxOut(nValue=1.22937283, scriptPubKey=76a914726d8c8926da39704d60dd40)
CTxOut(nValue=0.00103840, scriptPubKey=76a91475eac11f3cfda3e79c90469d)
valid script
5 op script loaded. type `help` for usage information
script | stack
-----------------------------------------+-------------------------------------------------------------------
OP_DUP | 03b05bdbdf395e495a61add92442071e32703518b8fca3fc34149db4b56c93be42
OP_HASH160 | 3045022100c7d8e302908fdc601b125c2734de63ed3bf54353e13a835313c2a...
897c81ac37ae36f7bc5b91356cfb0138bfacb3c1 |
OP_EQUALVERIFY |
OP_CHECKSIG |
#0001 OP_DUP
btcdeb> step
[...]
々 step
TransactionSignatureChecker::CheckSig(72 len sig, 33 len pubkey, sigversion=0)
sig = 3045022100c7d8e302908fdc601b125c2734de63ed3bf54353e13a835313c2a2aa5e8f21810220131fad73787989d7fbbdbbd8420674f56bdf61fed5dc2653c826a4789c68501101
pub key = 03b05bdbdf395e495a61add92442071e32703518b8fca3fc34149db4b56c93be42
script code = 76a914897c81ac37ae36f7bc5b91356cfb0138bfacb3c188ac
hash type = 01 (SIGHASH_ALL)
SignatureHash(nIn=0, nHashType=01)
- sigversion = SIGVERSION_BASE (non-segwit style)
Serializing transaction
<< txTo.nVersion (00000001)
<< nInputs = 2 [compact]
(serialize input 0)
<< txTo.vin[nInput=0].prevout = COutPoint(d0fcb77135, 33)
(SerializeScriptCode)
<< scriptCode.size()=25 - nCodeSeparators=0
<< script:76a914897c81ac37ae36f7bc5b91356cfb0138bfacb3c188ac
<< txTo.vin[nInput].nSequence = 4294967295 [0xffffffff]
(serialize input 1)
<< txTo.vin[nInput=1].prevout = COutPoint(d17c9cad67, 1)
<< [empty script] (reason: nInput != nIn)
<< txTo.vin[nInput].nSequence = 4294967295 [0xffffffff]
<< nOutputs = 3 [compact]
(serialize output 0)
<< txTo.vout[nOutput] = CTxOut(nValue=0.15296000, scriptPubKey=a9146c52f451a2bc85b815610fa5cd)
(serialize output 1)
<< txTo.vout[nOutput] = CTxOut(nValue=1.22937283, scriptPubKey=76a914726d8c8926da39704d60dd40)
(serialize output 2)
<< txTo.vout[nOutput] = CTxOut(nValue=0.00103840, scriptPubKey=76a91475eac11f3cfda3e79c90469d)
<< txTo.nLockTime = 0 [0x0]
sighash = 8b2fc7c4b0ce353c524dbd1059f2fcb7355597555e5d840ad5506d9b473923fd
pubkey.Verify(sig=3045022100c7d8e302908fdc601b125c2734de63ed3bf54353e13a835313c2a2aa5e8f21810220131fad73787989d7fbbdbbd8420674f56bdf61fed5dc2653c826a4789c685011, sighash=8b2fc7c4b0ce353c524dbd1059f2fcb7355597555e5d840ad5506d9b473923fd):
- secp256k1_ecdsa_verify() returned success
result: success
<> POP stack
<> POP stack
<> PUSH stack 01
script | stack
-----------------------------------------+-------------------------------------------------------------------
| 01
btcdeb>
```
## Summary: Scripting a Pay to Public Key Hash
Sending to a P2PKH address was relatively easy when you were just using `bitcoin-cli`. Examining the Bitcoin Script underlying it lays bare the cryptographic functions that were implicit in funding that transaction: how the UTXO was unlocked with a signature and a public key.