Update 09_3_Testing_a_Bitcoin_Script.md

This commit is contained in:
Shannon Appelcline 2020-07-15 12:20:49 -10:00 committed by GitHub
parent d432925e44
commit 52bfcd3c5b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -1,65 +1,193 @@
> :warning: **WARNING:** This section is of limited utility due to a lack of good test sites and test suites. # 9.3: Testing a Bitcoin Script
# 9.5: Testing a Bitcoin Script
> :information_source: **NOTE:** This is a draft in progress, so that I can get some feedback from early reviewers. It is not yet ready for learning. > :information_source: **NOTE:** This is a draft in progress, so that I can get some feedback from early reviewers. It is not yet ready for learning.
Bitcoin Scripting allows for considerable additional control over Bitcoin transactions, but it's also somewhat dangerous. As we'll describe in [§8.1](08_1_Understanding_the_Foundation_of_P2SH.md), the actual Scripts are somewhat isolated from the Bitcoin network, which means that it's possible to write a script and have it accepted by the network even if it's impossible to redeem from that script! So, you need to thoroughly test your Scripts before you put your money into them. Bitcoin Scripting allows for considerable additional control over Bitcoin transactions, but it's also somewhat dangerous. As we'll describe in [§10.1](10_1_Understanding_the_Foundation_of_P2SH.md), the actual Scripts are somewhat isolated from the Bitcoin network, which means that it's possible to write a script and have it accepted by the network even if it's impossible to redeem from that script! So, you need to thoroughly test your Scripts before you put your money into them.
This chapter thus describes a prime method for testing Bitcoin Scripts, which we'll also be using for occasional examples throughout the rest of this Part.
## Install btcdeb
The Bitcoin Script Debugger (`btcdeb`) by @kallewoof is one of the most reliable methods we've found for debugging Bitcoin Scripts. It does, however, require setting up C++ and a few other accessories on your machine, so we'll also offer a few other options toward the end of this chapter.
First, you need to clone the `btcdeb` GitHub, which will also require installing `git if you don't yet have it.
```
$ sudo apt-get install git
$ git clone https://github.com/kallewoof/btcdeb.git
```
Note that when you run `git clone` it will copy `btcdeb` into your current directory. We've chosen to do so in our `~standup` directory.
```
$ ls
bitcoin-0.20.0-x86_64-linux-gnu.tar.gz btcdeb laanwj-releases.asc SHA256SUMS.asc
```
Afterward, you must install required C++ and other packages.
```
$ sudo apt-get install autoconf libtool g++ pkg-config make
```
You're now ready to compile and install `btcdeb`:
```
$ cd btcdeb
$ ./autogen.sh
$ ./configure
$ make
$ sudo make install
```
After all of that, you should have a copy of `btcdeb`:
```
$ which btcdeb
/usr/local/bin/btcdeb
```
You should also install readline, as this makes the debugger a lot easier to use by supporting history using up/down arrows, left-right movement, autocompletion using tab, and other good user interfaces.
```
$ sudo apt-get install libreadline-dev
```
## Use btcdeb
`btcdeb` works like a standard debugger. It takes a script (as well as any number of stack entries) as a startup argument. You then can `step` through the script.
If you instead start it up with no arguments, you simply get an interpreter where you may issue `exec [opcode]` commands to perform actions directly.
### Use btcdeb for an Addition Example
The following example shows the use of `btcdeb` for the addition example from the previous section, `1 2 OP_ADD`
```
$ btcdeb '[1 2 OP_ADD]'
btcdeb 0.2.19 -- type `btcdeb -h` for start up options
warning: ambiguous input 1 is interpreted as a numeric value; use OP_1 to force into opcode
warning: ambiguous input 2 is interpreted as a numeric value; use OP_2 to force into opcode
miniscript failed to parse script; miniscript support disabled
valid script
3 op script loaded. type `help` for usage information
script | stack
--------+--------
1 |
2 |
OP_ADD |
#0000 1
```
It shows our initial script, running top to bottom, and also shows what will be executed next in the script.
We type `step` and it advances one step by taking the first item in the script and pushing it onto the stack:
```
btcdeb> step
<> PUSH stack 01
script | stack
--------+--------
2 | 01
OP_ADD |
#0001 2
```
And again:
```
btcdeb> step
<> PUSH stack 02
script | stack
--------+--------
OP_ADD | 02
| 01
#0002 OP_ADD
```
Now we execute the the `OP_ADD` and there's great excitement because that opcode pops the first two items off the stack, adds them together, then pushes their sum onto the stack.
```
btcdeb> step
<> POP stack
<> POP stack
<> PUSH stack 03
script | stack
--------+--------
| 03
```
And that's where our script ends, with nothing more to execute and an `03` sitting on top of our stack as the result of the Script.
> :note: **NOTE:** `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.
### Use btcdeb for a Subtraction Example
The previous section also included a slightly more complex subtraction example of Scripting: `3 2 OP_ADD 4 OP_SUB`. Here's what that looks like:
```
$ btcdeb '[3 2 OP_ADD 4 OP_SUB]'
btcdeb 0.2.19 -- type `btcdeb -h` for start up options
warning: ambiguous input 3 is interpreted as a numeric value; use OP_3 to force into opcode
warning: ambiguous input 2 is interpreted as a numeric value; use OP_2 to force into opcode
warning: ambiguous input 4 is interpreted as a numeric value; use OP_4 to force into opcode
miniscript failed to parse script; miniscript support disabled
valid script
5 op script loaded. type `help` for usage information
script | stack
--------+--------
3 |
2 |
OP_ADD |
4 |
OP_SUB |
#0000 3
btcdeb> step
<> PUSH stack 03
script | stack
--------+--------
2 | 03
OP_ADD |
4 |
OP_SUB |
#0001 2
btcdeb>
<> PUSH stack 02
script | stack
--------+--------
OP_ADD | 02
4 | 03
OP_SUB |
#0002 OP_ADD
btcdeb>
<> POP stack
<> POP stack
<> PUSH stack 05
script | stack
--------+--------
4 | 05
OP_SUB |
#0003 4
btcdeb>
<> PUSH stack 04
script | stack
--------+--------
OP_SUB | 04
| 05
#0004 OP_SUB
btcdeb>
<> POP stack
<> POP stack
<> PUSH stack 01
script | stack
--------+--------
| 01
```
We'll be returning to `btcdeb` from time to time, and it will remain an excellent tool for testing your own scripts.
## Test a Script Online ## Test a Script Online
Web simulators seem like they should be a great option for Bitcoin Script testing. Unfortunately, at the time of this writing, online simulators are few, and the ones that exist are almost fatally buggy and also out-of-date for recent features such as CSV. A few are included here mainly for completeness sake: because they used to work pretty well and perhaps might again. Someday. For now, they're not particularly recommended though. There are also a few web simulators that you can use to test scripts online. They can be superior to a command-line tool by offering a more graphical output, but we also find that they tend to have shortcomings.
### The Script Playground In the past we've tried to give extensive guidelines on using sites such as the [Script Playground](http://www.crmarsh.com/script-playground/) or the [Bitcoin Online Script Debugger](https://bitcoin-script-debugger.visvirial.com/), but they become out of date and/or disappear to quickly to keep up with them.
Charlie Marsh has built an extensive [Script Playground](http://www.crmarsh.com/script-playground/). Just put together your unlocking script and your locking script and run them. The Playground will play an `OP_VERIFY` at the end, and tell you with a green checkmark or a red X whether the transaction was unlocked or not. Assume that these debuggers have the nice advantage of showing things visually and explicitly telling you whether a script succeeds (unlocks) or fails (stays locked). Assume that they have disadvantages with signatures, where many of them either always return `true` for signature tests or else have very cumbersome mechanisms for incorporating them.
Type in the test from [§7.2: Running a Bitcoin Script.md](07_2_Running_a_Bitcoin_Script.md) of `1 98 OP_ADD 99 OP_EQUAL` and watch it verify; change it to `1 97 OP_ADD 99 OP_EQUAL` and see it fail.
If you prefer, you can grab the [JavaScript code](https://github.com/crm416/script/) and run it on your own machine.
#### Bugs & Challenges
_Signature Problems._ To really test Scripts you need to be able to verify hashes and signatures. The Playground tried to make that easy with buttons that can be used to cut-and-paste public keys and signatures, but they haven't kept up with Flash security upgrades and no longer work reliably. This makes any testing extremely cumbersome, as you have to dump addresses, public keys, and private keys from `bitcoin-cli`. Signing is simplified by just checking the signature of a nonce of "Secure", but given that `bitcoin-cli` produces a base64 signature instead of a hex signature, you're deep in the weeds. As a result of all of this, unless you're deeply comfortable with Bitcoin signatures, you're unlikely to be able to use Script Playground for anything but tests of flow control.
_Number Problems_. The Script Playground doesn't recognize integers of 100 or more.
_If the signature buttons worked right, the Playground would be great, but until that happens, it's not very useful._
### Web BTC Script Debugger
WebBTC has a [Script Debugger](https://webbtc.com/script) that not only shows you the execution of a script, but also explains its parts and shows you the stack. The following example is similar to the add-to-99 script from [§7.2](07_2_Running_a_Bitcoin_Script.md): [Add to 15 Script](https://webbtc.com/script/1%2014/OP_ADD%2015%20OP_EQUAL/).
#### Bugs & Challenges
_Web Problems._ The web submit form no longer works, requiring you to type all script into a URL(!) of the form `https://webbtc.com/script/[unlocking-script]/[locking-script]/`. Each script is a series of opcodes and constants separated by `%20`s. For example `1%2014` is `1 14` and `OP_ADD%2015%20OP_EQUAL` is `OP_ADD 15 OP_EQUAL`. (But, you can just use spaces when you type your Script into the URL, and they'll convert to `%20`s.)
_Visual Problems._ The stack is upside down.
_Signature Problems._ Allegedly, all signatures are assumed valid if a scripthash is not provided. This does not seem to be the case. Given that you're not signing actual transactions, and there's no discussion of how to sign a nonce, it's unclear how this even would work — again majorly impacting the utility of this site.
_Number Problems_. The BTC debugger doesn't recognize integers of 17 or more. This is not unusual, as 1 to 16 translate to OP_1 to OP_16, while going beyond that requires more effort when you're writing opcodes. However, if you're not insulated from this sort of complexity, you might as well be doing the low-level translation of opcodes yourself.
_If signatures were indeed considered valid, this would be a great resource, but between that not working and having to annoyingly type in code as a URL, this is another online script tester that's barely usable currently. The one saving grace is that real transactions can be examined, down to the Bitcoin script ... but the site hasn't been recording new transactions since December 2016.
## Test a Script with Software Packages
Software packages may be a possible future for the testing of Bitcoin Scripts. A Python package called [Hashmal](https://github.com/mazaclub/hashmal) is very promising, but it was still in Alpha at the time of this writing.
## Test a Script with Bitcoin ## Test a Script with Bitcoin
Someday web sites and software packages _might_ offer great opportunities for testing Bitcoin Scripts. However, they'll never be the real thing, because you can't guarantee that they follow the consensus rules. For example, the Script Playground explicitly says that it ignores a bug that's implicit in Bitcoin multisignatures. This means that any multisig code that you successfully test on the Script Playground will break in the real world. Even with a great tool like `btcdeb` or transient resources like the various online script testers, you're not working with the real thing. You can't guarantee that they follow Bitcoin's consensus rules, which means you can't guarantee their results. For example, the Script Playground explicitly says that it ignores a bug that's implicit in Bitcoin multisignatures. This means that any multisig code that you successfully test on the Script Playground will break in the real world.
So the only way to _really_ test Bitcoin Scripts is to try them out on Testnet. So the only way to _really_ test Bitcoin Scripts is to try them out on Testnet.
And how do you do that? As it happens that's the topic of the next chapter, which looks into introducing these abstract scripts to the real world of Bitcoin by embedding them in P2SH transactions. (But even then, you will probably need an API to push your P2SH transaction onto the Bitcoin network, so full testing will still be a ways in the future.) And how do you do that? As it happens that's the topic of [chapter 10](10_0_Embedding_Bitcoin_Scripts_in_P2SH_Transactions.md), which looks into introducing these abstract scripts to the real world of Bitcoin by embedding them in P2SH transactions. (But even then, you will probably need an API to push your P2SH transaction onto the Bitcoin network, so full testing will still be a ways in the future.)
_Whatever_ other testing methods you've used, this should be your final test _before_ you put your Script on Mainnet. Don't trust that your code is right; don't just eyeball it. Don't even trust whatever simulators or interpreters you've been using. Doing so is another great way to lose funds on Bitcoin. _Whatever_ other testing methods you've used, testing a script on Testnet should be your final test _before_ you put your Script on Mainnet. Don't trust that your code is right; don't just eyeball it. Don't even trust whatever simulators or debuggers you've been using. Doing so is another great way to lose funds on Bitcoin.
## Summary: Testing a Bitcoin Script ## Summary: Testing a Bitcoin Script
It turns out that there aren't currently any great tools for testing Bitcoin Scripts, except perhaps for some very simple flow control testing. We hope that some of the options in this section will mature (or get fixed) in the future, but for now you're going to need to jump ahead to APIs when you really need to do some real-world testing. You should install `btcdeb` as a command-line tool to test out your Bitcoin Scripts. As of this writing, it produces accurate results that can step through the entire scripting process. You can also look at some online sites for a more visual representation. When you're all done, you're going to need to go to testnet to make sure things are working accurately, before you deploy more generally.
## What's Next? ## What's Next?
Advance through "Bitcoin Scripting" with [Chapter Eight: Embedding Bitcoin Scripts in P2SH Transactions](08_0_Embedding_Bitcoin_Scripts_in_P2SH_Transactions.md). Continue "Introducing Bitcoin Scripts" with our first real-life example: [§9.4: Scripting a P2PKH](09_4_Scripting_a_P2PKH.md).