Merge btcscript repo into txscript directory.

This commit is contained in:
Dave Collins 2015-01-30 10:36:49 -06:00
commit be11f23e14
21 changed files with 21325 additions and 0 deletions

74
txscript/README.md Normal file
View file

@ -0,0 +1,74 @@
txscript
========
[![Build Status](https://travis-ci.org/btcsuite/btcd.png?branch=master)]
(https://travis-ci.org/btcsuite/btcd)
Package txscript implements the bitcoin transaction script language. There is
a comprehensive test suite. Package txscript is licensed under the liberal ISC
license.
This package has intentionally been designed so it can be used as a standalone
package for any projects needing to use or validate bitcoin transaction scripts.
## Bitcoin Scripts
Bitcoin provides a stack-based, FORTH-like langauge for the scripts in
the bitcoin transactions. This language is not turing complete
although it is still fairly powerful. A description of the language
can be found at https://en.bitcoin.it/wiki/Script
## Documentation
[![GoDoc](https://godoc.org/github.com/btcsuite/btcd/txscript?status.png)]
(http://godoc.org/github.com/btcsuite/btcd/txscript)
Full `go doc` style documentation for the project can be viewed online without
installing this package by using the GoDoc site
[here](http://godoc.org/github.com/btcsuite/btcd/txscript).
You can also view the documentation locally once the package is installed with
the `godoc` tool by running `godoc -http=":6060"` and pointing your browser to
http://localhost:6060/pkg/github.com/btcsuite/btcd/txscript
## Installation
```bash
$ go get github.com/btcsuite/btcd/txscript
```
## Examples
* [Standard Pay-to-pubkey-hash Script]
(http://godoc.org/github.com/btcsuite/btcd/txscript#example-PayToAddrScript)
Demonstrates creating a script which pays to a bitcoin address. It also
prints the created script hex and uses the DisasmString function to display
the disassembled script.
* [Extracting Details from Standard Scripts]
(http://godoc.org/github.com/btcsuite/btcd/txscript#example-ExtractPkScriptAddrs)
Demonstrates extracting information from a standard public key script.
## GPG Verification Key
All official release tags are signed by Conformal so users can ensure the code
has not been tampered with and is coming from Conformal. To verify the
signature perform the following:
- Download the public key from the Conformal website at
https://opensource.conformal.com/GIT-GPG-KEY-conformal.txt
- Import the public key into your GPG keyring:
```bash
gpg --import GIT-GPG-KEY-conformal.txt
```
- Verify the release tag with the following command where `TAG_NAME` is a
placeholder for the specific tag:
```bash
git tag -v TAG_NAME
```
## License
Package txscript is licensed under the liberal ISC License.

90
txscript/address.go Normal file
View file

@ -0,0 +1,90 @@
// Copyright (c) 2013-2015 Conformal Systems LLC.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package txscript
import (
"github.com/btcsuite/btcnet"
"github.com/btcsuite/btcutil"
)
// ExtractPkScriptAddrs returns the type of script, addresses and required
// signatures associated with the passed PkScript. Note that it only works for
// 'standard' transaction script types. Any data such as public keys which are
// invalid are omitted from the results.
func ExtractPkScriptAddrs(pkScript []byte, net *btcnet.Params) (ScriptClass, []btcutil.Address, int, error) {
var addrs []btcutil.Address
var requiredSigs int
// No valid addresses or required signatures if the script doesn't
// parse.
pops, err := parseScript(pkScript)
if err != nil {
return NonStandardTy, nil, 0, err
}
scriptClass := typeOfScript(pops)
switch scriptClass {
case PubKeyHashTy:
// A pay-to-pubkey-hash script is of the form:
// OP_DUP OP_HASH160 <hash> OP_EQUALVERIFY OP_CHECKSIG
// Therefore the pubkey hash is the 3rd item on the stack.
// Skip the pubkey hash if it's invalid for some reason.
requiredSigs = 1
addr, err := btcutil.NewAddressPubKeyHash(pops[2].data, net)
if err == nil {
addrs = append(addrs, addr)
}
case PubKeyTy:
// A pay-to-pubkey script is of the form:
// <pubkey> OP_CHECKSIG
// Therefore the pubkey is the first item on the stack.
// Skip the pubkey if it's invalid for some reason.
requiredSigs = 1
addr, err := btcutil.NewAddressPubKey(pops[0].data, net)
if err == nil {
addrs = append(addrs, addr)
}
case ScriptHashTy:
// A pay-to-script-hash script is of the form:
// OP_HASH160 <scripthash> OP_EQUAL
// Therefore the script hash is the 2nd item on the stack.
// Skip the script hash if it's invalid for some reason.
requiredSigs = 1
addr, err := btcutil.NewAddressScriptHashFromHash(pops[1].data, net)
if err == nil {
addrs = append(addrs, addr)
}
case MultiSigTy:
// A multi-signature script is of the form:
// <numsigs> <pubkey> <pubkey> <pubkey>... <numpubkeys> OP_CHECKMULTISIG
// Therefore the number of required signatures is the 1st item
// on the stack and the number of public keys is the 2nd to last
// item on the stack.
requiredSigs = asSmallInt(pops[0].opcode)
numPubKeys := asSmallInt(pops[len(pops)-2].opcode)
// Extract the public keys while skipping any that are invalid.
addrs = make([]btcutil.Address, 0, numPubKeys)
for i := 0; i < numPubKeys; i++ {
addr, err := btcutil.NewAddressPubKey(pops[i+1].data, net)
if err == nil {
addrs = append(addrs, addr)
}
}
case NullDataTy:
// Null data transactions have no addresses or required
// signatures.
case NonStandardTy:
// Don't attempt to extract addresses or required signatures for
// nonstandard transactions.
}
return scriptClass, addrs, requiredSigs, nil
}

368
txscript/address_test.go Normal file
View file

@ -0,0 +1,368 @@
// Copyright (c) 2013-2015 Conformal Systems LLC.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package txscript_test
import (
"encoding/hex"
"reflect"
"testing"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcnet"
"github.com/btcsuite/btcutil"
)
// decodeHex decodes the passed hex string and returns the resulting bytes. It
// panics if an error occurs. This is only used in the tests as a helper since
// the only way it can fail is if there is an error in the test source code.
func decodeHex(hexStr string) []byte {
b, err := hex.DecodeString(hexStr)
if err != nil {
panic("invalid hex string in test source: err " + err.Error() +
", hex: " + hexStr)
}
return b
}
// newAddressPubKey returns a new btcutil.AddressPubKey from the provided
// serialized public key. It panics if an error occurs. This is only used in
// the tests as a helper since the only way it can fail is if there is an error
// in the test source code.
func newAddressPubKey(serializedPubKey []byte) btcutil.Address {
addr, err := btcutil.NewAddressPubKey(serializedPubKey,
&btcnet.MainNetParams)
if err != nil {
panic("invalid public key in test source")
}
return addr
}
// newAddressPubKeyHash returns a new btcutil.AddressPubKeyHash from the
// provided hash. It panics if an error occurs. This is only used in the tests
// as a helper since the only way it can fail is if there is an error in the
// test source code.
func newAddressPubKeyHash(pkHash []byte) btcutil.Address {
addr, err := btcutil.NewAddressPubKeyHash(pkHash, &btcnet.MainNetParams)
if err != nil {
panic("invalid public key hash in test source")
}
return addr
}
// newAddressScriptHash returns a new btcutil.AddressScriptHash from the
// provided hash. It panics if an error occurs. This is only used in the tests
// as a helper since the only way it can fail is if there is an error in the
// test source code.
func newAddressScriptHash(scriptHash []byte) btcutil.Address {
addr, err := btcutil.NewAddressScriptHashFromHash(scriptHash,
&btcnet.MainNetParams)
if err != nil {
panic("invalid script hash in test source")
}
return addr
}
// TestExtractPkScriptAddrs ensures that extracting the type, addresses, and
// number of required signatures from PkScripts works as intended.
func TestExtractPkScriptAddrs(t *testing.T) {
tests := []struct {
name string
script []byte
addrs []btcutil.Address
reqSigs int
class txscript.ScriptClass
}{
{
name: "standard p2pk with compressed pubkey (0x02)",
script: decodeHex("2102192d74d0cb94344c9569c2e7790157" +
"3d8d7903c3ebec3a957724895dca52c6b4ac"),
addrs: []btcutil.Address{
newAddressPubKey(decodeHex("02192d74d0cb94344" +
"c9569c2e77901573d8d7903c3ebec3a95772" +
"4895dca52c6b4")),
},
reqSigs: 1,
class: txscript.PubKeyTy,
},
{
name: "standard p2pk with uncompressed pubkey (0x04)",
script: decodeHex("410411db93e1dcdb8a016b49840f8c53bc" +
"1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb" +
"84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643" +
"f656b412a3ac"),
addrs: []btcutil.Address{
newAddressPubKey(decodeHex("0411db93e1dcdb8a0" +
"16b49840f8c53bc1eb68a382e97b1482ecad" +
"7b148a6909a5cb2e0eaddfb84ccf9744464f" +
"82e160bfa9b8b64f9d4c03f999b8643f656b" +
"412a3")),
},
reqSigs: 1,
class: txscript.PubKeyTy,
},
{
name: "standard p2pk with hybrid pubkey (0x06)",
script: decodeHex("4106192d74d0cb94344c9569c2e7790157" +
"3d8d7903c3ebec3a957724895dca52c6b40d45264838" +
"c0bd96852662ce6a847b197376830160c6d2eb5e6a4c" +
"44d33f453eac"),
addrs: []btcutil.Address{
newAddressPubKey(decodeHex("06192d74d0cb94344" +
"c9569c2e77901573d8d7903c3ebec3a95772" +
"4895dca52c6b40d45264838c0bd96852662c" +
"e6a847b197376830160c6d2eb5e6a4c44d33" +
"f453e")),
},
reqSigs: 1,
class: txscript.PubKeyTy,
},
{
name: "standard p2pk with compressed pubkey (0x03)",
script: decodeHex("2103b0bd634234abbb1ba1e986e884185c" +
"61cf43e001f9137f23c2c409273eb16e65ac"),
addrs: []btcutil.Address{
newAddressPubKey(decodeHex("03b0bd634234abbb1" +
"ba1e986e884185c61cf43e001f9137f23c2c" +
"409273eb16e65")),
},
reqSigs: 1,
class: txscript.PubKeyTy,
},
{
name: "2nd standard p2pk with uncompressed pubkey (0x04)",
script: decodeHex("4104b0bd634234abbb1ba1e986e884185c" +
"61cf43e001f9137f23c2c409273eb16e6537a576782e" +
"ba668a7ef8bd3b3cfb1edb7117ab65129b8a2e681f3c" +
"1e0908ef7bac"),
addrs: []btcutil.Address{
newAddressPubKey(decodeHex("04b0bd634234abbb1" +
"ba1e986e884185c61cf43e001f9137f23c2c" +
"409273eb16e6537a576782eba668a7ef8bd3" +
"b3cfb1edb7117ab65129b8a2e681f3c1e090" +
"8ef7b")),
},
reqSigs: 1,
class: txscript.PubKeyTy,
},
{
name: "standard p2pk with hybrid pubkey (0x07)",
script: decodeHex("4107b0bd634234abbb1ba1e986e884185c" +
"61cf43e001f9137f23c2c409273eb16e6537a576782e" +
"ba668a7ef8bd3b3cfb1edb7117ab65129b8a2e681f3c" +
"1e0908ef7bac"),
addrs: []btcutil.Address{
newAddressPubKey(decodeHex("07b0bd634234abbb1" +
"ba1e986e884185c61cf43e001f9137f23c2c" +
"409273eb16e6537a576782eba668a7ef8bd3" +
"b3cfb1edb7117ab65129b8a2e681f3c1e090" +
"8ef7b")),
},
reqSigs: 1,
class: txscript.PubKeyTy,
},
{
name: "standard p2pkh",
script: decodeHex("76a914ad06dd6ddee55cbca9a9e3713bd7" +
"587509a3056488ac"),
addrs: []btcutil.Address{
newAddressPubKeyHash(decodeHex("ad06dd6ddee55" +
"cbca9a9e3713bd7587509a30564")),
},
reqSigs: 1,
class: txscript.PubKeyHashTy,
},
{
name: "standard p2sh",
script: decodeHex("a91463bcc565f9e68ee0189dd5cc67f1b0" +
"e5f02f45cb87"),
addrs: []btcutil.Address{
newAddressScriptHash(decodeHex("63bcc565f9e68" +
"ee0189dd5cc67f1b0e5f02f45cb")),
},
reqSigs: 1,
class: txscript.ScriptHashTy,
},
// from real tx 60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1, vout 0
{
name: "standard 1 of 2 multisig",
script: decodeHex("514104cc71eb30d653c0c3163990c47b97" +
"6f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473" +
"e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11" +
"fcdd0d348ac4410461cbdcc5409fb4b4d42b51d33381" +
"354d80e550078cb532a34bfa2fcfdeb7d76519aecc62" +
"770f5b0e4ef8551946d8a540911abe3e7854a26f39f5" +
"8b25c15342af52ae"),
addrs: []btcutil.Address{
newAddressPubKey(decodeHex("04cc71eb30d653c0c" +
"3163990c47b976f3fb3f37cccdcbedb169a1" +
"dfef58bbfbfaff7d8a473e7e2e6d317b87ba" +
"fe8bde97e3cf8f065dec022b51d11fcdd0d3" +
"48ac4")),
newAddressPubKey(decodeHex("0461cbdcc5409fb4b" +
"4d42b51d33381354d80e550078cb532a34bf" +
"a2fcfdeb7d76519aecc62770f5b0e4ef8551" +
"946d8a540911abe3e7854a26f39f58b25c15" +
"342af")),
},
reqSigs: 1,
class: txscript.MultiSigTy,
},
// from real tx d646f82bd5fbdb94a36872ce460f97662b80c3050ad3209bef9d1e398ea277ab, vin 1
{
name: "standard 2 of 3 multisig",
script: decodeHex("524104cb9c3c222c5f7a7d3b9bd152f363" +
"a0b6d54c9eb312c4d4f9af1e8551b6c421a6a4ab0e29" +
"105f24de20ff463c1c91fcf3bf662cdde4783d4799f7" +
"87cb7c08869b4104ccc588420deeebea22a7e900cc8b" +
"68620d2212c374604e3487ca08f1ff3ae12bdc639514" +
"d0ec8612a2d3c519f084d9a00cbbe3b53d071e9b09e7" +
"1e610b036aa24104ab47ad1939edcb3db65f7fedea62" +
"bbf781c5410d3f22a7a3a56ffefb2238af8627363bdf" +
"2ed97c1f89784a1aecdb43384f11d2acc64443c7fc29" +
"9cef0400421a53ae"),
addrs: []btcutil.Address{
newAddressPubKey(decodeHex("04cb9c3c222c5f7a7" +
"d3b9bd152f363a0b6d54c9eb312c4d4f9af1" +
"e8551b6c421a6a4ab0e29105f24de20ff463" +
"c1c91fcf3bf662cdde4783d4799f787cb7c0" +
"8869b")),
newAddressPubKey(decodeHex("04ccc588420deeebe" +
"a22a7e900cc8b68620d2212c374604e3487c" +
"a08f1ff3ae12bdc639514d0ec8612a2d3c51" +
"9f084d9a00cbbe3b53d071e9b09e71e610b0" +
"36aa2")),
newAddressPubKey(decodeHex("04ab47ad1939edcb3" +
"db65f7fedea62bbf781c5410d3f22a7a3a56" +
"ffefb2238af8627363bdf2ed97c1f89784a1" +
"aecdb43384f11d2acc64443c7fc299cef040" +
"0421a")),
},
reqSigs: 2,
class: txscript.MultiSigTy,
},
// The below are nonstandard script due to things such as
// invalid pubkeys, failure to parse, and not being of a
// standard form.
{
name: "p2pk with uncompressed pk missing OP_CHECKSIG",
script: decodeHex("410411db93e1dcdb8a016b49840f8c53bc" +
"1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb" +
"84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643" +
"f656b412a3"),
addrs: nil,
reqSigs: 0,
class: txscript.NonStandardTy,
},
{
name: "valid signature from a sigscript - no addresses",
script: decodeHex("47304402204e45e16932b8af514961a1d3" +
"a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd410220" +
"181522ec8eca07de4860a4acdd12909d831cc56cbbac" +
"4622082221a8768d1d0901"),
addrs: nil,
reqSigs: 0,
class: txscript.NonStandardTy,
},
// Note the technically the pubkey is the second item on the
// stack, but since the address extraction intentionally only
// works with standard PkScripts, this should not return any
// addresses.
{
name: "valid sigscript to reedeem p2pk - no addresses",
script: decodeHex("493046022100ddc69738bf2336318e4e04" +
"1a5a77f305da87428ab1606f023260017854350ddc02" +
"2100817af09d2eec36862d16009852b7e3a0f6dd7659" +
"8290b7834e1453660367e07a014104cd4240c198e125" +
"23b6f9cb9f5bed06de1ba37e96a1bbd13745fcf9d11c" +
"25b1dff9a519675d198804ba9962d3eca2d5937d58e5" +
"a75a71042d40388a4d307f887d"),
addrs: nil,
reqSigs: 0,
class: txscript.NonStandardTy,
},
// from real tx 691dd277dc0e90a462a3d652a1171686de49cf19067cd33c7df0392833fb986a, vout 0
// invalid public keys
{
name: "1 of 3 multisig with invalid pubkeys",
script: decodeHex("51411c2200007353455857696b696c6561" +
"6b73204361626c6567617465204261636b75700a0a63" +
"61626c65676174652d3230313031323034313831312e" +
"377a0a0a446f41776e6c6f61642074686520666f6c6c" +
"6f77696e67207472616e73616374696f6e7320776974" +
"68205361746f736869204e616b616d6f746f27732064" +
"6f776e6c6f61416420746f6f6c2077686963680a6361" +
"6e20626520666f756e6420696e207472616e73616374" +
"696f6e20366335336364393837313139656637393764" +
"35616463636453ae"),
addrs: []btcutil.Address{},
reqSigs: 1,
class: txscript.MultiSigTy,
},
// from real tx: 691dd277dc0e90a462a3d652a1171686de49cf19067cd33c7df0392833fb986a, vout 44
// invalid public keys
{
name: "1 of 3 multisig with invalid pubkeys 2",
script: decodeHex("5141346333656332353963373464616365" +
"36666430383862343463656638630a63363662633139" +
"39366338623934613338313162333635363138666531" +
"65396231623541366361636365393933613339383861" +
"34363966636336643664616266640a32363633636661" +
"39636634633033633630396335393363336539316665" +
"64653730323921313233646434326432353633396433" +
"38613663663530616234636434340a00000053ae"),
addrs: []btcutil.Address{},
reqSigs: 1,
class: txscript.MultiSigTy,
},
{
name: "empty script",
script: []byte{},
addrs: nil,
reqSigs: 0,
class: txscript.NonStandardTy,
},
{
name: "script that does not parse",
script: []byte{txscript.OP_DATA_45},
addrs: nil,
reqSigs: 0,
class: txscript.NonStandardTy,
},
}
t.Logf("Running %d tests.", len(tests))
for i, test := range tests {
class, addrs, reqSigs, err := txscript.ExtractPkScriptAddrs(
test.script, &btcnet.MainNetParams)
if err != nil {
}
if !reflect.DeepEqual(addrs, test.addrs) {
t.Errorf("ExtractPkScriptAddrs #%d (%s) unexpected "+
"addresses\ngot %v\nwant %v", i, test.name,
addrs, test.addrs)
continue
}
if reqSigs != test.reqSigs {
t.Errorf("ExtractPkScriptAddrs #%d (%s) unexpected "+
"number of required signatures - got %d, "+
"want %d", i, test.name, reqSigs, test.reqSigs)
continue
}
if class != test.class {
t.Errorf("ExtractPkScriptAddrs #%d (%s) unexpected "+
"script type - got %s, want %s", i, test.name,
class, test.class)
continue
}
}
}

8
txscript/data/LICENSE Normal file
View file

@ -0,0 +1,8 @@
The json files in this directory come from the bitcoind project
(https://github.com/bitcoin/bitcoin) and is released under the following
license:
Copyright (c) 2012-2014 The Bitcoin Core developers
Distributed under the MIT/X11 software license, see the accompanying
file COPYING or http://www.opensource.org/licenses/mit-license.php.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,111 @@
[
["The following are deserialized transactions which are invalid."],
["They are in the form"],
["[[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...],"],
["serializedTransaction, verifyFlags]"],
["Objects that are only a single string (like this one) are ignored"],
["0e1b5688cf179cd9f7cbda1fac0090f6e684bbf8cd946660120197c3f3681809 but with extra junk appended to the end of the scriptPubKey"],
[[["6ca7ec7b1847f6bdbd737176050e6a08d66ccd55bb94ad24f4018024107a5827", 0, "0x41 0x043b640e983c9690a14c039a2037ecc3467b27a0dcd58f19d76c7bc118d09fec45adc5370a1c5bf8067ca9f5557a4cf885fdb0fe0dcc9c3a7137226106fbc779a5 CHECKSIG VERIFY 1"]],
"010000000127587a10248001f424ad94bb55cd6cd6086a0e05767173bdbdf647187beca76c000000004948304502201b822ad10d6adc1a341ae8835be3f70a25201bbff31f59cbb9c5353a5f0eca18022100ea7b2f7074e9aa9cf70aa8d0ffee13e6b45dddabf1ab961bda378bcdb778fa4701ffffffff0100f2052a010000001976a914fc50c5907d86fed474ba5ce8b12a66e0a4c139d888ac00000000", "P2SH"],
["This is the nearly-standard transaction with CHECKSIGVERIFY 1 instead of CHECKSIG from tx_valid.json"],
["but with the signature duplicated in the scriptPubKey with a non-standard pushdata prefix"],
["See FindAndDelete, which will only remove if it uses the same pushdata prefix as is standard"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1 0x4c 0x47 0x3044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a01"]],
"01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", "P2SH"],
["Same as above, but with the sig in the scriptSig also pushed with the same non-standard OP_PUSHDATA"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1 0x4c 0x47 0x3044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a01"]],
"01000000010001000000000000000000000000000000000000000000000000000000000000000000006b4c473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", "P2SH"],
["An invalid P2SH Transaction"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7a052c840ba73af26755de42cf01cc9e0a49fef0 EQUAL"]],
"010000000100010000000000000000000000000000000000000000000000000000000000000000000009085768617420697320ffffffff010000000000000000015100000000", "P2SH"],
["Tests for CheckTransaction()"],
["No inputs"],
["Skipped because this is not checked by btcscript, this is a problem for chain."],
["No outputs"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x05ab9e14d983742513f0f451e105ffb4198d1dd4 EQUAL"]],
"01000000010001000000000000000000000000000000000000000000000000000000000000000000006d483045022100f16703104aab4e4088317c862daec83440242411b039d14280e03dd33b487ab802201318a7be236672c5c56083eb7a5a195bc57a40af7923ff8545016cd3b571e2a601232103c40e5d339df3f30bf753e7e04450ae4ef76c9e45587d1d993bdc4cd06f0651c7acffffffff0000000000", "P2SH"],
["Negative output"],
["Removed because btcscript doesn't do tx sanity checking."],
["MAX_MONEY + 1 output"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x32afac281462b822adbec5094b8d4d337dd5bd6a EQUAL"]],
"01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100e1eadba00d9296c743cb6ecc703fd9ddc9b3cd12906176a226ae4c18d6b00796022100a71aef7d2874deff681ba6080f1b278bac7bb99c61b08a85f4311970ffe7f63f012321030c0588dc44d92bdcbf8e72093466766fdc265ead8db64517b0c542275b70fffbacffffffff010140075af0750700015100000000", "P2SH"],
["MAX_MONEY output + 1 output"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0xb558cbf4930954aa6a344363a15668d7477ae716 EQUAL"]],
"01000000010001000000000000000000000000000000000000000000000000000000000000000000006d483045022027deccc14aa6668e78a8c9da3484fbcd4f9dcc9bb7d1b85146314b21b9ae4d86022100d0b43dece8cfb07348de0ca8bc5b86276fa88f7f2138381128b7c36ab2e42264012321029bb13463ddd5d2cc05da6e84e37536cb9525703cfd8f43afdb414988987a92f6acffffffff020040075af075070001510001000000000000015100000000", "P2SH"],
["Duplicate inputs"],
["Removed because btcscript doesn't check input duplication, btcchain does"],
["Coinbase of size 1"],
["Note the input is just required to make the tester happy"],
["Removed because btcscript doesn't handle coinbase checking, btcchain does"],
["Coinbase of size 101"],
["Note the input is just required to make the tester happy"],
["Removed because btcscript doesn't handle coinbase checking, btcchain does"],
["Null txin"],
["Removed because btcscript doesn't do tx sanity checking."],
["Same as the transactions in valid with one input SIGHASH_ALL and one SIGHASH_ANYONECANPAY, but we set the _ANYONECANPAY sequence number, invalidating the SIGHASH_ALL signature"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"],
["0000000000000000000000000000000000000000000000000000000000000200", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"]],
"01000000020001000000000000000000000000000000000000000000000000000000000000000000004948304502203a0f5f0e1f2bdbcd04db3061d18f3af70e07f4f467cbc1b8116f267025f5360b022100c792b6e215afc5afc721a351ec413e714305cb749aae3d7fee76621313418df10101000000000200000000000000000000000000000000000000000000000000000000000000000000484730440220201dc2d030e380e8f9cfb41b442d930fa5a685bb2c8db5906671f865507d0670022018d9e7a8d4c8d86a73c2a724ee38ef983ec249827e0e464841735955c707ece98101000000010100000000000000015100000000", "P2SH"],
["CHECKMULTISIG with incorrect signature order"],
["Note the input is just required to make the tester happy"],
[[["b3da01dd4aae683c7aee4d5d8b52a540a508e1115f77cd7fa9a291243f501223", 0, "HASH160 0x14 0xb1ce99298d5f07364b57b1e5c9cc00be0b04a954 EQUAL"]],
"01000000012312503f2491a2a97fcd775f11e108a540a5528b5d4dee7a3c68ae4add01dab300000000fdfe000048304502207aacee820e08b0b174e248abd8d7a34ed63b5da3abedb99934df9fddd65c05c4022100dfe87896ab5ee3df476c2655f9fbe5bd089dccbef3e4ea05b5d121169fe7f5f401483045022100f6649b0eddfdfd4ad55426663385090d51ee86c3481bdc6b0c18ea6c0ece2c0b0220561c315b07cffa6f7dd9df96dbae9200c2dee09bf93cc35ca05e6cdf613340aa014c695221031d11db38972b712a9fe1fc023577c7ae3ddb4a3004187d41c45121eecfdbb5b7210207ec36911b6ad2382860d32989c7b8728e9489d7bbc94a6b5509ef0029be128821024ea9fac06f666a4adc3fc1357b7bec1fd0bdece2b9d08579226a8ebde53058e453aeffffffff0180380100000000001976a914c9b99cddf847d10685a4fabaa0baf505f7c3dfab88ac00000000", "P2SH"],
["The following is a tweaked form of 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63"],
["It is an OP_CHECKMULTISIG with the dummy value missing"],
[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]],
"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004847304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH"],
["CHECKMULTISIG SCRIPT_VERIFY_NULLDUMMY tests:"],
["The following is a tweaked form of 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63"],
["It is an OP_CHECKMULTISIG with the dummy value set to something other than an empty string"],
[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]],
"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004a010047304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH,NULLDUMMY"],
["As above, but using a OP_1"],
[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]],
"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000495147304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH,NULLDUMMY"],
["As above, but using a OP_1NEGATE"],
[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]],
"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000494f47304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH,NULLDUMMY"],
["As above, but with the dummy byte missing"],
[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]],
"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004847304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH,NULLDUMMY"],
["Empty stack when we try to run CHECKSIG"],
[[["ad503f72c18df5801ee64d76090afe4c607fb2b822e9b7b63c5826c50e22fc3b", 0, "0x21 0x027c3a97665bf283a102a587a62a30a0c102d4d3b141015e2cae6f64e2543113e5 CHECKSIG NOT"]],
"01000000013bfc220ec526583cb6b7e922b8b27f604cfe0a09764de61e80f58dc1723f50ad0000000000ffffffff0101000000000000002321027c3a97665bf283a102a587a62a30a0c102d4d3b141015e2cae6f64e2543113e5ac00000000", "P2SH"],
["Inverted versions of tx_valid CODESEPARATOR IF block tests"],
["CODESEPARATOR in an unexecuted IF block does not change what is hashed"],
[[["a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944", 0, "IF CODESEPARATOR ENDIF 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 CHECKSIGVERIFY CODESEPARATOR 1"]],
"010000000144490eda355be7480f2ec828dcc1b9903793a8008fad8cfe9b0c6b4d2f0355a9000000004a48304502207a6974a77c591fa13dff60cabbb85a0de9e025c09c65a4b2285e47ce8e22f761022100f0efaac9ff8ac36b10721e0aae1fb975c90500b50c56e8a0cc52b0403f0425dd0151ffffffff010000000000000000016a00000000", "P2SH"],
["As above, with the IF block executed"],
[[["a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944", 0, "IF CODESEPARATOR ENDIF 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 CHECKSIGVERIFY CODESEPARATOR 1"]],
"010000000144490eda355be7480f2ec828dcc1b9903793a8008fad8cfe9b0c6b4d2f0355a9000000004a483045022100fa4a74ba9fd59c59f46c3960cf90cbe0d2b743c471d24a3d5d6db6002af5eebb02204d70ec490fd0f7055a7c45f86514336e3a7f03503dacecabb247fc23f15c83510100ffffffff010000000000000000016a00000000", "P2SH"],
["Make diffs cleaner by leaving a comment here without comma at the end"]
]

190
txscript/data/tx_valid.json Normal file
View file

@ -0,0 +1,190 @@
[
["The following are deserialized transactions which are valid."],
["They are in the form"],
["[[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...],"],
["serializedTransaction, verifyFlags]"],
["Objects that are only a single string (like this one) are ignored"],
["The following is 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63"],
["It is of particular interest because it contains an invalidly-encoded signature which OpenSSL accepts"],
["See http://r6.ca/blog/20111119T211504Z.html"],
["It is also the first OP_CHECKMULTISIG transaction in standard form"],
[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]],
"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000490047304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH"],
["The following is a tweaked form of 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63"],
["It is an OP_CHECKMULTISIG with an arbitrary extra byte stuffed into the signature at pos length - 2"],
["The dummy byte is fine however, so the NULLDUMMY flag should be happy"],
[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]],
"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004a0048304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2bab01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH,NULLDUMMY"],
["The following is a tweaked form of 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63"],
["It is an OP_CHECKMULTISIG with the dummy value set to something other than an empty string"],
[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]],
"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004a01ff47304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH"],
["As above, but using a OP_1"],
[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]],
"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000495147304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH"],
["As above, but using a OP_1NEGATE"],
[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]],
"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000494f47304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH"],
["The following is c99c49da4c38af669dea436d3e73780dfdb6c1ecf9958baa52960e8baee30e73"],
["It is of interest because it contains a 0-sequence as well as a signature of SIGHASH type 0 (which is not a real type)"],
[[["406b2b06bcd34d3c8733e6b79f7a394c8a431fbf4ff5ac705c93f4076bb77602", 0, "DUP HASH160 0x14 0xdc44b1164188067c3a32d4780f5996fa14a4f2d9 EQUALVERIFY CHECKSIG"]],
"01000000010276b76b07f4935c70acf54fbf1f438a4c397a9fb7e633873c4dd3bc062b6b40000000008c493046022100d23459d03ed7e9511a47d13292d3430a04627de6235b6e51a40f9cd386f2abe3022100e7d25b080f0bb8d8d5f878bba7d54ad2fda650ea8d158a33ee3cbd11768191fd004104b0e2c879e4daf7b9ab68350228c159766676a14f5815084ba166432aab46198d4cca98fa3e9981d0a90b2effc514b76279476550ba3663fdcaff94c38420e9d5000000000100093d00000000001976a9149a7b0f3b80c6baaeedce0a0842553800f832ba1f88ac00000000", "P2SH"],
["A nearly-standard transaction with CHECKSIGVERIFY 1 instead of CHECKSIG"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1"]],
"01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", "P2SH"],
["Same as above, but with the signature duplicated in the scriptPubKey with the proper pushdata prefix"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1 0x47 0x3044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a01"]],
"01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", "P2SH"],
["The following is f7fdd091fa6d8f5e7a8c2458f5c38faffff2d3f1406b6e4fe2c99dcc0d2d1cbb"],
["It caught a bug in the workaround for 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63 in an overly simple implementation"],
[[["b464e85df2a238416f8bdae11d120add610380ea07f4ef19c5f9dfd472f96c3d", 0, "DUP HASH160 0x14 0xbef80ecf3a44500fda1bc92176e442891662aed2 EQUALVERIFY CHECKSIG"],
["b7978cc96e59a8b13e0865d3f95657561a7f725be952438637475920bac9eb21", 1, "DUP HASH160 0x14 0xbef80ecf3a44500fda1bc92176e442891662aed2 EQUALVERIFY CHECKSIG"]],
"01000000023d6cf972d4dff9c519eff407ea800361dd0a121de1da8b6f4138a2f25de864b4000000008a4730440220ffda47bfc776bcd269da4832626ac332adfca6dd835e8ecd83cd1ebe7d709b0e022049cffa1cdc102a0b56e0e04913606c70af702a1149dc3b305ab9439288fee090014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff21ebc9ba20594737864352e95b727f1a565756f9d365083eb1a8596ec98c97b7010000008a4730440220503ff10e9f1e0de731407a4a245531c9ff17676eda461f8ceeb8c06049fa2c810220c008ac34694510298fa60b3f000df01caa244f165b727d4896eb84f81e46bcc4014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff01f0da5200000000001976a914857ccd42dded6df32949d4646dfa10a92458cfaa88ac00000000", "P2SH"],
["The following tests for the presence of a bug in the handling of SIGHASH_SINGLE"],
["It results in signing the constant 1, instead of something generated based on the transaction,"],
["when the input doing the signing has an index greater than the maximum output index"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0xe52b482f2faa8ecbf0db344f93c84ac908557f33 EQUALVERIFY CHECKSIG"], ["0000000000000000000000000000000000000000000000000000000000000200", 0, "1"]],
"01000000020002000000000000000000000000000000000000000000000000000000000000000000000151ffffffff0001000000000000000000000000000000000000000000000000000000000000000000006b483045022100c9cdd08798a28af9d1baf44a6c77bcc7e279f47dc487c8c899911bc48feaffcc0220503c5c50ae3998a733263c5c0f7061b483e2b56c4c41b456e7d2f5a78a74c077032102d5c25adb51b61339d2b05315791e21bbe80ea470a49db0135720983c905aace0ffffffff010000000000000000015100000000", "P2SH"],
["An invalid P2SH Transaction"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7a052c840ba73af26755de42cf01cc9e0a49fef0 EQUAL"]],
"010000000100010000000000000000000000000000000000000000000000000000000000000000000009085768617420697320ffffffff010000000000000000015100000000", "NONE"],
["A valid P2SH Transaction using the standard transaction type put forth in BIP 16"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x8febbed40483661de6958d957412f82deed8e2f7 EQUAL"]],
"01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100c66c9cdf4c43609586d15424c54707156e316d88b0a1534c9e6b0d4f311406310221009c0fe51dbc9c4ab7cc25d3fdbeccf6679fe6827f08edf2b4a9f16ee3eb0e438a0123210338e8034509af564c62644c07691942e0c056752008a173c89f60ab2a88ac2ebfacffffffff010000000000000000015100000000", "P2SH"],
["Tests for CheckTransaction()"],
["MAX_MONEY output"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x32afac281462b822adbec5094b8d4d337dd5bd6a EQUAL"]],
"01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100e1eadba00d9296c743cb6ecc703fd9ddc9b3cd12906176a226ae4c18d6b00796022100a71aef7d2874deff681ba6080f1b278bac7bb99c61b08a85f4311970ffe7f63f012321030c0588dc44d92bdcbf8e72093466766fdc265ead8db64517b0c542275b70fffbacffffffff010040075af0750700015100000000", "P2SH"],
["MAX_MONEY output + 0 output"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0xb558cbf4930954aa6a344363a15668d7477ae716 EQUAL"]],
"01000000010001000000000000000000000000000000000000000000000000000000000000000000006d483045022027deccc14aa6668e78a8c9da3484fbcd4f9dcc9bb7d1b85146314b21b9ae4d86022100d0b43dece8cfb07348de0ca8bc5b86276fa88f7f2138381128b7c36ab2e42264012321029bb13463ddd5d2cc05da6e84e37536cb9525703cfd8f43afdb414988987a92f6acffffffff020040075af075070001510000000000000000015100000000", "P2SH"],
["Coinbase of size 2"],
["Note the input is just required to make the tester happy"],
[[["0000000000000000000000000000000000000000000000000000000000000000", -1, "1"]],
"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff025151ffffffff010000000000000000015100000000", "P2SH"],
["Coinbase of size 100"],
["Note the input is just required to make the tester happy"],
[[["0000000000000000000000000000000000000000000000000000000000000000", -1, "1"]],
"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff6451515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151ffffffff010000000000000000015100000000", "P2SH"],
["Simple transaction with first input is signed with SIGHASH_ALL, second with SIGHASH_ANYONECANPAY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"],
["0000000000000000000000000000000000000000000000000000000000000200", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"]],
"010000000200010000000000000000000000000000000000000000000000000000000000000000000049483045022100d180fd2eb9140aeb4210c9204d3f358766eb53842b2a9473db687fa24b12a3cc022079781799cd4f038b85135bbe49ec2b57f306b2bb17101b17f71f000fcab2b6fb01ffffffff0002000000000000000000000000000000000000000000000000000000000000000000004847304402205f7530653eea9b38699e476320ab135b74771e1c48b81a5d041e2ca84b9be7a802200ac8d1f40fb026674fe5a5edd3dea715c27baa9baca51ed45ea750ac9dc0a55e81ffffffff010100000000000000015100000000", "P2SH"],
["Same as above, but we change the sequence number of the first input to check that SIGHASH_ANYONECANPAY is being followed"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"],
["0000000000000000000000000000000000000000000000000000000000000200", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"]],
"01000000020001000000000000000000000000000000000000000000000000000000000000000000004948304502203a0f5f0e1f2bdbcd04db3061d18f3af70e07f4f467cbc1b8116f267025f5360b022100c792b6e215afc5afc721a351ec413e714305cb749aae3d7fee76621313418df101010000000002000000000000000000000000000000000000000000000000000000000000000000004847304402205f7530653eea9b38699e476320ab135b74771e1c48b81a5d041e2ca84b9be7a802200ac8d1f40fb026674fe5a5edd3dea715c27baa9baca51ed45ea750ac9dc0a55e81ffffffff010100000000000000015100000000", "P2SH"],
["afd9c17f8913577ec3509520bd6e5d63e9c0fd2a5f70c787993b097ba6ca9fae which has several SIGHASH_SINGLE signatures"],
[[["63cfa5a09dc540bf63e53713b82d9ea3692ca97cd608c384f2aa88e51a0aac70", 0, "DUP HASH160 0x14 0xdcf72c4fd02f5a987cf9b02f2fabfcac3341a87d EQUALVERIFY CHECKSIG"],
["04e8d0fcf3846c6734477b98f0f3d4badfb78f020ee097a0be5fe347645b817d", 1, "DUP HASH160 0x14 0xdcf72c4fd02f5a987cf9b02f2fabfcac3341a87d EQUALVERIFY CHECKSIG"],
["ee1377aff5d0579909e11782e1d2f5f7b84d26537be7f5516dd4e43373091f3f", 1, "DUP HASH160 0x14 0xdcf72c4fd02f5a987cf9b02f2fabfcac3341a87d EQUALVERIFY CHECKSIG"]],
"010000000370ac0a1ae588aaf284c308d67ca92c69a39e2db81337e563bf40c59da0a5cf63000000006a4730440220360d20baff382059040ba9be98947fd678fb08aab2bb0c172efa996fd8ece9b702201b4fb0de67f015c90e7ac8a193aeab486a1f587e0f54d0fb9552ef7f5ce6caec032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff7d815b6447e35fbea097e00e028fb7dfbad4f3f0987b4734676c84f3fcd0e804010000006b483045022100c714310be1e3a9ff1c5f7cacc65c2d8e781fc3a88ceb063c6153bf950650802102200b2d0979c76e12bb480da635f192cc8dc6f905380dd4ac1ff35a4f68f462fffd032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff3f1f097333e4d46d51f5e77b53264db8f7f5d2e18217e1099957d0f5af7713ee010000006c493046022100b663499ef73273a3788dea342717c2640ac43c5a1cf862c9e09b206fcb3f6bb8022100b09972e75972d9148f2bdd462e5cb69b57c1214b88fc55ca638676c07cfc10d8032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff0380841e00000000001976a914bfb282c70c4191f45b5a6665cad1682f2c9cfdfb88ac80841e00000000001976a9149857cc07bed33a5cf12b9c5e0500b675d500c81188ace0fd1c00000000001976a91443c52850606c872403c0601e69fa34b26f62db4a88ac00000000", "P2SH"],
["ddc454a1c0c35c188c98976b17670f69e586d9c0f3593ea879928332f0a069e7, which spends an input that pushes using a PUSHDATA1 that is negative when read as signed"],
[[["c5510a5dd97a25f43175af1fe649b707b1df8e1a41489bac33a23087027a2f48", 0, "0x4c 0xae 0x606563686f2022553246736447566b58312b5a536e587574356542793066794778625456415675534a6c376a6a334878416945325364667657734f53474f36633338584d7439435c6e543249584967306a486956304f376e775236644546673d3d22203e20743b206f70656e73736c20656e63202d7061737320706173733a5b314a564d7751432d707269766b65792d6865785d202d64202d6165732d3235362d636263202d61202d696e207460 DROP DUP HASH160 0x14 0xbfd7436b6265aa9de506f8a994f881ff08cc2872 EQUALVERIFY CHECKSIG"]],
"0100000001482f7a028730a233ac9b48411a8edfb107b749e61faf7531f4257ad95d0a51c5000000008b483045022100bf0bbae9bde51ad2b222e87fbf67530fbafc25c903519a1e5dcc52a32ff5844e022028c4d9ad49b006dd59974372a54291d5764be541574bb0c4dc208ec51f80b7190141049dd4aad62741dc27d5f267f7b70682eee22e7e9c1923b9c0957bdae0b96374569b460eb8d5b40d972e8c7c0ad441de3d94c4a29864b212d56050acb980b72b2bffffffff0180969800000000001976a914e336d0017a9d28de99d16472f6ca6d5a3a8ebc9988ac00000000", "P2SH"],
["Correct signature order"],
["Note the input is just required to make the tester happy"],
[[["b3da01dd4aae683c7aee4d5d8b52a540a508e1115f77cd7fa9a291243f501223", 0, "HASH160 0x14 0xb1ce99298d5f07364b57b1e5c9cc00be0b04a954 EQUAL"]],
"01000000012312503f2491a2a97fcd775f11e108a540a5528b5d4dee7a3c68ae4add01dab300000000fdfe0000483045022100f6649b0eddfdfd4ad55426663385090d51ee86c3481bdc6b0c18ea6c0ece2c0b0220561c315b07cffa6f7dd9df96dbae9200c2dee09bf93cc35ca05e6cdf613340aa0148304502207aacee820e08b0b174e248abd8d7a34ed63b5da3abedb99934df9fddd65c05c4022100dfe87896ab5ee3df476c2655f9fbe5bd089dccbef3e4ea05b5d121169fe7f5f4014c695221031d11db38972b712a9fe1fc023577c7ae3ddb4a3004187d41c45121eecfdbb5b7210207ec36911b6ad2382860d32989c7b8728e9489d7bbc94a6b5509ef0029be128821024ea9fac06f666a4adc3fc1357b7bec1fd0bdece2b9d08579226a8ebde53058e453aeffffffff0180380100000000001976a914c9b99cddf847d10685a4fabaa0baf505f7c3dfab88ac00000000", "P2SH"],
["cc60b1f899ec0a69b7c3f25ddf32c4524096a9c5b01cbd84c6d0312a0c478984, which is a fairly strange transaction which relies on OP_CHECKSIG returning 0 when checking a completely invalid sig of length 0"],
[[["cbebc4da731e8995fe97f6fadcd731b36ad40e5ecb31e38e904f6e5982fa09f7", 0, "0x2102085c6600657566acc2d6382a47bc3f324008d2aa10940dd7705a48aa2a5a5e33ac7c2103f5d0fb955f95dd6be6115ce85661db412ec6a08abcbfce7da0ba8297c6cc0ec4ac7c5379a820d68df9e32a147cffa36193c6f7c43a1c8c69cda530e1c6db354bfabdcfefaf3c875379a820f531f3041d3136701ea09067c53e7159c8f9b2746a56c3d82966c54bbc553226879a5479827701200122a59a5379827701200122a59a6353798277537982778779679a68"]],
"0100000001f709fa82596e4f908ee331cb5e0ed46ab331d7dcfaf697fe95891e73dac4ebcb000000008c20ca42095840735e89283fec298e62ac2ddea9b5f34a8cbb7097ad965b87568100201b1b01dc829177da4a14551d2fc96a9db00c6501edfa12f22cd9cefd335c227f483045022100a9df60536df5733dd0de6bc921fab0b3eee6426501b43a228afa2c90072eb5ca02201c78b74266fac7d1db5deff080d8a403743203f109fbcabf6d5a760bf87386d20100ffffffff01c075790000000000232103611f9a45c18f28f06f19076ad571c344c82ce8fcfe34464cf8085217a2d294a6ac00000000", "P2SH"],
["Empty pubkey"],
[[["229257c295e7f555421c1bfec8538dd30a4b5c37c1c8810bbe83cafa7811652c", 0, "0x00 CHECKSIG NOT"]],
"01000000012c651178faca83be0b81c8c1375c4b0ad38d53c8fe1b1c4255f5e795c25792220000000049483045022100d6044562284ac76c985018fc4a90127847708c9edb280996c507b28babdc4b2a02203d74eca3f1a4d1eea7ff77b528fde6d5dc324ec2dbfdb964ba885f643b9704cd01ffffffff010100000000000000232102c2410f8891ae918cab4ffc4bb4a3b0881be67c7a1e7faa8b5acf9ab8932ec30cac00000000", "P2SH"],
["Empty signature"],
[[["9ca93cfd8e3806b9d9e2ba1cf64e3cc6946ee0119670b1796a09928d14ea25f7", 0, "0x21 0x028a1d66975dbdf97897e3a4aef450ebeb5b5293e4a0b4a6d3a2daaa0b2b110e02 CHECKSIG NOT"]],
"0100000001f725ea148d92096a79b1709611e06e94c63c4ef61cbae2d9b906388efd3ca99c000000000100ffffffff0101000000000000002321028a1d66975dbdf97897e3a4aef450ebeb5b5293e4a0b4a6d3a2daaa0b2b110e02ac00000000", "P2SH"],
[[["444e00ed7840d41f20ecd9c11d3f91982326c731a02f3c05748414a4fa9e59be", 0, "1 0x00 0x21 0x02136b04758b0b6e363e7a6fbe83aaf527a153db2b060d36cc29f7f8309ba6e458 2 CHECKMULTISIG"]],
"0100000001be599efaa4148474053c2fa031c7262398913f1dc1d9ec201fd44078ed004e44000000004900473044022022b29706cb2ed9ef0cb3c97b72677ca2dfd7b4160f7b4beb3ba806aa856c401502202d1e52582412eba2ed474f1f437a427640306fd3838725fab173ade7fe4eae4a01ffffffff010100000000000000232103ac4bba7e7ca3e873eea49e08132ad30c7f03640b6539e9b59903cf14fd016bbbac00000000", "P2SH"],
[[["e16abbe80bf30c080f63830c8dbf669deaef08957446e95940227d8c5e6db612", 0, "1 0x21 0x03905380c7013e36e6e19d305311c1b81fce6581f5ee1c86ef0627c68c9362fc9f 0x00 2 CHECKMULTISIG"]],
"010000000112b66d5e8c7d224059e946749508efea9d66bf8d0c83630f080cf30be8bb6ae100000000490047304402206ffe3f14caf38ad5c1544428e99da76ffa5455675ec8d9780fac215ca17953520220779502985e194d84baa36b9bd40a0dbd981163fa191eb884ae83fc5bd1c86b1101ffffffff010100000000000000232103905380c7013e36e6e19d305311c1b81fce6581f5ee1c86ef0627c68c9362fc9fac00000000", "P2SH"],
[[["ebbcf4bfce13292bd791d6a65a2a858d59adbf737e387e40370d4e64cc70efb0", 0, "2 0x21 0x033bcaa0a602f0d44cc9d5637c6e515b0471db514c020883830b7cefd73af04194 0x21 0x03a88b326f8767f4f192ce252afe33c94d25ab1d24f27f159b3cb3aa691ffe1423 2 CHECKMULTISIG NOT"]],
"0100000001b0ef70cc644e0d37407e387e73bfad598d852a5aa6d691d72b2913cebff4bceb000000004a00473044022068cd4851fc7f9a892ab910df7a24e616f293bcb5c5fbdfbc304a194b26b60fba022078e6da13d8cb881a22939b952c24f88b97afd06b4c47a47d7f804c9a352a6d6d0100ffffffff0101000000000000002321033bcaa0a602f0d44cc9d5637c6e515b0471db514c020883830b7cefd73af04194ac00000000", "P2SH"],
[[["ba4cd7ae2ad4d4d13ebfc8ab1d93a63e4a6563f25089a18bf0fc68f282aa88c1", 0, "2 0x21 0x037c615d761e71d38903609bf4f46847266edc2fb37532047d747ba47eaae5ffe1 0x21 0x02edc823cd634f2c4033d94f5755207cb6b60c4b1f1f056ad7471c47de5f2e4d50 2 CHECKMULTISIG NOT"]],
"0100000001c188aa82f268fcf08ba18950f263654a3ea6931dabc8bf3ed1d4d42aaed74cba000000004b0000483045022100940378576e069aca261a6b26fb38344e4497ca6751bb10905c76bb689f4222b002204833806b014c26fd801727b792b1260003c55710f87c5adbd7a9cb57446dbc9801ffffffff0101000000000000002321037c615d761e71d38903609bf4f46847266edc2fb37532047d747ba47eaae5ffe1ac00000000", "P2SH"],
["OP_CODESEPARATOR tests"],
["Test that SignatureHash() removes OP_CODESEPARATOR with FindAndDelete()"],
[[["bc7fd132fcf817918334822ee6d9bd95c889099c96e07ca2c1eb2cc70db63224", 0, "CODESEPARATOR 0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CHECKSIG"]],
"01000000012432b60dc72cebc1a27ce0969c0989c895bdd9e62e8234839117f8fc32d17fbc000000004a493046022100a576b52051962c25e642c0fd3d77ee6c92487048e5d90818bcf5b51abaccd7900221008204f8fb121be4ec3b24483b1f92d89b1b0548513a134e345c5442e86e8617a501ffffffff010000000000000000016a00000000", "P2SH"],
[[["83e194f90b6ef21fa2e3a365b63794fb5daa844bdc9b25de30899fcfe7b01047", 0, "CODESEPARATOR CODESEPARATOR 0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CHECKSIG"]],
"01000000014710b0e7cf9f8930de259bdc4b84aa5dfb9437b665a3e3a21ff26e0bf994e183000000004a493046022100a166121a61b4eeb19d8f922b978ff6ab58ead8a5a5552bf9be73dc9c156873ea02210092ad9bc43ee647da4f6652c320800debcf08ec20a094a0aaf085f63ecb37a17201ffffffff010000000000000000016a00000000", "P2SH"],
["Hashed data starts at the CODESEPARATOR"],
[[["326882a7f22b5191f1a0cc9962ca4b878cd969cf3b3a70887aece4d801a0ba5e", 0, "0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CODESEPARATOR CHECKSIG"]],
"01000000015ebaa001d8e4ec7a88703a3bcf69d98c874bca6299cca0f191512bf2a7826832000000004948304502203bf754d1c6732fbf87c5dcd81258aefd30f2060d7bd8ac4a5696f7927091dad1022100f5bcb726c4cf5ed0ed34cc13dadeedf628ae1045b7cb34421bc60b89f4cecae701ffffffff010000000000000000016a00000000", "P2SH"],
["But only if execution has reached it"],
[[["a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944", 0, "0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CHECKSIGVERIFY CODESEPARATOR 0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CHECKSIGVERIFY CODESEPARATOR 1"]],
"010000000144490eda355be7480f2ec828dcc1b9903793a8008fad8cfe9b0c6b4d2f0355a900000000924830450221009c0a27f886a1d8cb87f6f595fbc3163d28f7a81ec3c4b252ee7f3ac77fd13ffa02203caa8dfa09713c8c4d7ef575c75ed97812072405d932bd11e6a1593a98b679370148304502201e3861ef39a526406bad1e20ecad06be7375ad40ddb582c9be42d26c3a0d7b240221009d0a3985e96522e59635d19cc4448547477396ce0ef17a58e7d74c3ef464292301ffffffff010000000000000000016a00000000", "P2SH"],
["CODESEPARATOR in an unexecuted IF block does not change what is hashed"],
[[["a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944", 0, "IF CODESEPARATOR ENDIF 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 CHECKSIGVERIFY CODESEPARATOR 1"]],
"010000000144490eda355be7480f2ec828dcc1b9903793a8008fad8cfe9b0c6b4d2f0355a9000000004a48304502207a6974a77c591fa13dff60cabbb85a0de9e025c09c65a4b2285e47ce8e22f761022100f0efaac9ff8ac36b10721e0aae1fb975c90500b50c56e8a0cc52b0403f0425dd0100ffffffff010000000000000000016a00000000", "P2SH"],
["As above, with the IF block executed"],
[[["a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944", 0, "IF CODESEPARATOR ENDIF 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 CHECKSIGVERIFY CODESEPARATOR 1"]],
"010000000144490eda355be7480f2ec828dcc1b9903793a8008fad8cfe9b0c6b4d2f0355a9000000004a483045022100fa4a74ba9fd59c59f46c3960cf90cbe0d2b743c471d24a3d5d6db6002af5eebb02204d70ec490fd0f7055a7c45f86514336e3a7f03503dacecabb247fc23f15c83510151ffffffff010000000000000000016a00000000", "P2SH"],
["CHECKSIG is legal in scriptSigs"],
[[["ccf7f4053a02e653c36ac75c891b7496d0dc5ce5214f6c913d9cf8f1329ebee0", 0, "DUP HASH160 0x14 0xee5a6aa40facefb2655ac23c0c28c57c65c41f9b EQUALVERIFY CHECKSIG"]],
"0100000001e0be9e32f1f89c3d916c4f21e55cdcd096741b895cc76ac353e6023a05f4f7cc00000000d86149304602210086e5f736a2c3622ebb62bd9d93d8e5d76508b98be922b97160edc3dcca6d8c47022100b23c312ac232a4473f19d2aeb95ab7bdf2b65518911a0d72d50e38b5dd31dc820121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ac4730440220508fa761865c8abd81244a168392876ee1d94e8ed83897066b5e2df2400dad24022043f5ee7538e87e9c6aef7ef55133d3e51da7cc522830a9c4d736977a76ef755c0121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000", "P2SH"],
["Same semantics for OP_CODESEPARATOR"],
[[["10c9f0effe83e97f80f067de2b11c6a00c3088a4bce42c5ae761519af9306f3c", 1, "DUP HASH160 0x14 0xee5a6aa40facefb2655ac23c0c28c57c65c41f9b EQUALVERIFY CHECKSIG"]],
"01000000013c6f30f99a5161e75a2ce4bca488300ca0c6112bde67f0807fe983feeff0c91001000000e608646561646265656675ab61493046022100ce18d384221a731c993939015e3d1bcebafb16e8c0b5b5d14097ec8177ae6f28022100bcab227af90bab33c3fe0a9abfee03ba976ee25dc6ce542526e9b2e56e14b7f10121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ac493046022100c3b93edcc0fd6250eb32f2dd8a0bba1754b0f6c3be8ed4100ed582f3db73eba2022100bf75b5bd2eff4d6bf2bda2e34a40fcc07d4aa3cf862ceaa77b47b81eff829f9a01ab21038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000", "P2SH"],
["Signatures are removed from the script they are in by FindAndDelete() in the CHECKSIG code; even multiple instances of one signature can be removed."],
[[["6056ebd549003b10cbbd915cea0d82209fe40b8617104be917a26fa92cbe3d6f", 0, "DUP HASH160 0x14 0xee5a6aa40facefb2655ac23c0c28c57c65c41f9b EQUALVERIFY CHECKSIG"]],
"01000000016f3dbe2ca96fa217e94b1017860be49f20820dea5c91bdcb103b0049d5eb566000000000fd1d0147304402203989ac8f9ad36b5d0919d97fa0a7f70c5272abee3b14477dc646288a8b976df5022027d19da84a066af9053ad3d1d7459d171b7e3a80bc6c4ef7a330677a6be548140147304402203989ac8f9ad36b5d0919d97fa0a7f70c5272abee3b14477dc646288a8b976df5022027d19da84a066af9053ad3d1d7459d171b7e3a80bc6c4ef7a330677a6be548140121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ac47304402203757e937ba807e4a5da8534c17f9d121176056406a6465054bdd260457515c1a02200f02eccf1bec0f3a0d65df37889143c2e88ab7acec61a7b6f5aa264139141a2b0121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000", "P2SH"],
["That also includes ahead of the opcode being executed."],
[[["5a6b0021a6042a686b6b94abc36b387bef9109847774e8b1e51eb8cc55c53921", 1, "DUP HASH160 0x14 0xee5a6aa40facefb2655ac23c0c28c57c65c41f9b EQUALVERIFY CHECKSIG"]],
"01000000012139c555ccb81ee5b1e87477840991ef7b386bc3ab946b6b682a04a621006b5a01000000fdb40148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f2204148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390175ac4830450220646b72c35beeec51f4d5bc1cbae01863825750d7f490864af354e6ea4f625e9c022100f04b98432df3a9641719dbced53393022e7249fb59db993af1118539830aab870148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a580039017521038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000", "P2SH"],
["Finally CHECKMULTISIG removes all signatures prior to hashing the script containing those signatures. In conjunction with the SIGHASH_SINGLE bug this lets us test whether or not FindAndDelete() is actually present in scriptPubKey/redeemScript evaluation by including a signature of the digest 0x01 We can compute in advance for our pubkey, embed it it in the scriptPubKey, and then also using a normal SIGHASH_ALL signature. If FindAndDelete() wasn't run, the 'bugged' signature would still be in the hashed script, and the normal signature would fail."],
["Here's an example on mainnet within a P2SH redeemScript. Remarkably it's a standard transaction in <0.9"],
[[["b5b598de91787439afd5938116654e0b16b7a0d0f82742ba37564219c5afcbf9", 0, "DUP HASH160 0x14 0xf6f365c40f0739b61de827a44751e5e99032ed8f EQUALVERIFY CHECKSIG"],
["ab9805c6d57d7070d9a42c5176e47bb705023e6b67249fb6760880548298e742", 0, "HASH160 0x14 0xd8dacdadb7462ae15cd906f1878706d0da8660e6 EQUAL"]],
"0100000002f9cbafc519425637ba4227f8d0a0b7160b4e65168193d5af39747891de98b5b5000000006b4830450221008dd619c563e527c47d9bd53534a770b102e40faa87f61433580e04e271ef2f960220029886434e18122b53d5decd25f1f4acb2480659fea20aabd856987ba3c3907e0121022b78b756e2258af13779c1a1f37ea6800259716ca4b7f0b87610e0bf3ab52a01ffffffff42e7988254800876b69f24676b3e0205b77be476512ca4d970707dd5c60598ab00000000fd260100483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a53034930460221008431bdfa72bc67f9d41fe72e94c88fb8f359ffa30b33c72c121c5a877d922e1002210089ef5fc22dd8bfc6bf9ffdb01a9862d27687d424d1fefbab9e9c7176844a187a014c9052483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303210378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71210378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c7153aeffffffff01a08601000000000017a914d8dacdadb7462ae15cd906f1878706d0da8660e68700000000", "P2SH"],
["Same idea, but with bare CHECKMULTISIG"],
[[["ceafe58e0f6e7d67c0409fbbf673c84c166e3c5d3c24af58f7175b18df3bb3db", 0, "DUP HASH160 0x14 0xf6f365c40f0739b61de827a44751e5e99032ed8f EQUALVERIFY CHECKSIG"],
["ceafe58e0f6e7d67c0409fbbf673c84c166e3c5d3c24af58f7175b18df3bb3db", 1, "2 0x48 0x3045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 3 CHECKMULTISIG"]],
"0100000002dbb33bdf185b17f758af243c5d3c6e164cc873f6bb9f40c0677d6e0f8ee5afce000000006b4830450221009627444320dc5ef8d7f68f35010b4c050a6ed0d96b67a84db99fda9c9de58b1e02203e4b4aaa019e012e65d69b487fdf8719df72f488fa91506a80c49a33929f1fd50121022b78b756e2258af13779c1a1f37ea6800259716ca4b7f0b87610e0bf3ab52a01ffffffffdbb33bdf185b17f758af243c5d3c6e164cc873f6bb9f40c0677d6e0f8ee5afce010000009300483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303ffffffff01a0860100000000001976a9149bc0bbdd3024da4d0c38ed1aecf5c68dd1d3fa1288ac00000000", "P2SH"],
["Make diffs cleaner by leaving a comment here without comma at the end"]
]

39
txscript/doc.go Normal file
View file

@ -0,0 +1,39 @@
// Copyright (c) 2013-2015 Conformal Systems LLC.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
/*
Package txscript implements the bitcoin transaction script language.
A complete description of the script language used by bitcoin can be found at
https://en.bitcoin.it/wiki/Script. The following only serves as a quick
overview to provide information on how to use the package.
This package provides data structures and functions to parse and execute
bitcoin transaction scripts.
Script Overview
Bitcoin transaction scripts are written in a stack-base, FORTH-like language.
The bitcoin script language consists of a number of opcodes which fall into
several categories such pushing and popping data to and from the stack,
performing basic and bitwise arithmetic, conditional branching, comparing
hashes, and checking cryptographic signatures. Scripts are processed from left
to right and intentionally do not provide loops.
The vast majority of Bitcoin scripts at the time of this writing are of several
standard forms which consist of a spender providing a public key and a signature
which proves the spender owns the associated private key. This information
is used to prove the the spender is authorized to perform the transaction.
One benefit of using a scripting language is added flexibility in specifying
what conditions must be met in order to spend bitcoins.
Errors
Errors returned by this package are of the form txscript.ErrStackX where X
indicates the specific error. See Variables in the package documentation for a
full list.
*/
package txscript

77
txscript/example_test.go Normal file
View file

@ -0,0 +1,77 @@
// Copyright (c) 2014-2015 Conformal Systems LLC.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package txscript_test
import (
"encoding/hex"
"fmt"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcnet"
"github.com/btcsuite/btcutil"
)
// This example demonstrates creating a script which pays to a bitcoin address.
// It also prints the created script hex and uses the DisasmString function to
// display the disassembled script.
func ExamplePayToAddrScript() {
// Parse the address to send the coins to into a btcutil.Address
// which is useful to ensure the accuracy of the address and determine
// the address type. It is also required for the upcoming call to
// PayToAddrScript.
addressStr := "12gpXQVcCL2qhTNQgyLVdCFG2Qs2px98nV"
address, err := btcutil.DecodeAddress(addressStr, &btcnet.MainNetParams)
if err != nil {
fmt.Println(err)
return
}
// Create a public key script that pays to the address.
script, err := txscript.PayToAddrScript(address)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("Script Hex: %x\n", script)
disasm, err := txscript.DisasmString(script)
if err != nil {
fmt.Println(err)
return
}
fmt.Println("Script Disassembly:", disasm)
// Output:
// Script Hex: 76a914128004ff2fcaf13b2b91eb654b1dc2b674f7ec6188ac
// Script Disassembly: OP_DUP OP_HASH160 128004ff2fcaf13b2b91eb654b1dc2b674f7ec61 OP_EQUALVERIFY OP_CHECKSIG
}
// This example demonstrates extracting information from a standard public key
// script.
func ExampleExtractPkScriptAddrs() {
// Start with a standard pay-to-pubkey-hash script.
scriptHex := "76a914128004ff2fcaf13b2b91eb654b1dc2b674f7ec6188ac"
script, err := hex.DecodeString(scriptHex)
if err != nil {
fmt.Println(err)
return
}
// Extract and print details from the script.
scriptClass, addresses, reqSigs, err := txscript.ExtractPkScriptAddrs(
script, &btcnet.MainNetParams)
if err != nil {
fmt.Println(err)
return
}
fmt.Println("Script Class:", scriptClass)
fmt.Println("Addresses:", addresses)
fmt.Println("Required Signatures:", reqSigs)
// Output:
// Script Class: pubkeyhash
// Addresses: [12gpXQVcCL2qhTNQgyLVdCFG2Qs2px98nV]
// Required Signatures: 1
}

4265
txscript/internal_test.go Normal file

File diff suppressed because it is too large Load diff

71
txscript/log.go Normal file
View file

@ -0,0 +1,71 @@
// Copyright (c) 2013-2015 Conformal Systems LLC.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package txscript
import (
"errors"
"io"
"github.com/btcsuite/btclog"
)
// log is a logger that is initialized with no output filters. This
// means the package will not perform any logging by default until the caller
// requests it.
var log btclog.Logger
// The default amount of logging is none.
func init() {
DisableLog()
}
// DisableLog disables all library log output. Logging output is disabled
// by default until either UseLogger or SetLogWriter are called.
func DisableLog() {
log = btclog.Disabled
}
// UseLogger uses a specified Logger to output package logging info.
// This should be used in preference to SetLogWriter if the caller is also
// using btclog.
func UseLogger(logger btclog.Logger) {
log = logger
}
// SetLogWriter uses a specified io.Writer to output package logging info.
// This allows a caller to direct package logging output without needing a
// dependency on seelog. If the caller is also using btclog, UseLogger should
// be used instead.
func SetLogWriter(w io.Writer, level string) error {
if w == nil {
return errors.New("nil writer")
}
lvl, ok := btclog.LogLevelFromString(level)
if !ok {
return errors.New("invalid log level")
}
l, err := btclog.NewLoggerFromWriter(w, lvl)
if err != nil {
return err
}
UseLogger(l)
return nil
}
// LogClosure is a closure that can be printed with %v to be used to
// generate expensive-to-create data for a detailed log level and avoid doing
// the work if the data isn't printed.
type logClosure func() string
func (c logClosure) String() string {
return c()
}
func newLogClosure(c func() string) logClosure {
return logClosure(c)
}

66
txscript/log_test.go Normal file
View file

@ -0,0 +1,66 @@
// Copyright (c) 2013-2015 Conformal Systems LLC.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package txscript_test
import (
"errors"
"io"
"os"
"testing"
"github.com/btcsuite/btcd/txscript"
)
func TestSetLogWriter(t *testing.T) {
tests := []struct {
name string
w io.Writer
level string
expected error
}{
{
name: "nil writer",
w: nil,
level: "trace",
expected: errors.New("nil writer"),
},
{
name: "invalid log level",
w: os.Stdout,
level: "wrong",
expected: errors.New("invalid log level"),
},
{
name: "use off level",
w: os.Stdout,
level: "off",
expected: errors.New("min level can't be greater than max. Got min: 6, max: 5"),
},
{
name: "pass",
w: os.Stdout,
level: "debug",
expected: nil,
},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
err := txscript.SetLogWriter(test.w, test.level)
if err != nil {
if err.Error() != test.expected.Error() {
t.Errorf("SetLogWriter #%d (%s) wrong result\n"+
"got: %v\nwant: %v", i, test.name, err,
test.expected)
}
} else {
if test.expected != nil {
t.Errorf("SetLogWriter #%d (%s) wrong result\n"+
"got: %v\nwant: %v", i, test.name, err,
test.expected)
}
}
}
}

1977
txscript/opcode.go Normal file

File diff suppressed because it is too large Load diff

4452
txscript/opcode_test.go Normal file

File diff suppressed because it is too large Load diff

1666
txscript/script.go Normal file

File diff suppressed because it is too large Load diff

4784
txscript/script_test.go Normal file

File diff suppressed because it is too large Load diff

285
txscript/scriptbuilder.go Normal file
View file

@ -0,0 +1,285 @@
// Copyright (c) 2013-2015 Conformal Systems LLC.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package txscript
import (
"encoding/binary"
"fmt"
"math/big"
)
const (
// defaultScriptAlloc is the default size used for the backing array
// for a script being built by the ScriptBuilder. The array will
// dynamically grow as needed, but this figure is intended to provide
// enough space for vast majority of scripts without needing to grow the
// backing array multiple times.
defaultScriptAlloc = 500
)
// ErrScriptNotCanonical identifies a non-canonical script. The caller can use
// a type assertion to detect this error type.
type ErrScriptNotCanonical string
// Error implements the error interface.
func (e ErrScriptNotCanonical) Error() string {
return string(e)
}
// ScriptBuilder provides a facility for building custom scripts. It allows
// you to push opcodes, ints, and data while respecting canonical encoding. In
// general it does not ensure the script will execute correctly, however any
// data pushes which would exceed the maximum allowed script engine limits and
// are therefore guaranteed not to execute will not be pushed and will result in
// the Script function returning an error.
//
// For example, the following would build a 2-of-3 multisig script for usage in
// a pay-to-script-hash (although in this situation MultiSigScript() would be a
// better choice to generate the script):
// builder := txscript.NewScriptBuilder()
// builder.AddOp(txscript.OP_2).AddData(pubKey1).AddData(pubKey2)
// builder.AddData(pubKey3).AddOp(txscript.OP_3)
// builder.AddOp(txscript.OP_CHECKMULTISIG)
// script, err := builder.Script()
// if err != nil {
// // Handle the error.
// return
// }
// fmt.Printf("Final multi-sig script: %x\n", script)
type ScriptBuilder struct {
script []byte
err error
}
// AddOp pushes the passed opcode to the end of the script. The script will not
// be modified if pushing the opcode would cause the script to exceed the
// maximum allowed script engine size.
func (b *ScriptBuilder) AddOp(opcode byte) *ScriptBuilder {
if b.err != nil {
return b
}
// Pushes that would cause the script to exceed the largest allowed
// script size would result in a non-canonical script.
if len(b.script)+1 > maxScriptSize {
str := fmt.Sprintf("adding an opcode would exceed the maximum "+
"allowed canonical script length of %d", maxScriptSize)
b.err = ErrScriptNotCanonical(str)
return b
}
b.script = append(b.script, opcode)
return b
}
// canonicalDataSize returns the number of bytes the canonical encoding of the
// data will take.
func canonicalDataSize(data []byte) int {
dataLen := len(data)
// When the data consists of a single number that can be represented
// by one of the "small integer" opcodes, that opcode will be instead
// of a data push opcode followed by the number.
if dataLen == 0 {
return 1
} else if dataLen == 1 && data[0] <= 16 {
return 1
} else if dataLen == 1 && data[0] == 0x81 {
return 1
}
if dataLen < OP_PUSHDATA1 {
return 1 + dataLen
} else if dataLen <= 0xff {
return 2 + dataLen
} else if dataLen <= 0xffff {
return 3 + dataLen
}
return 5 + dataLen
}
// addData is the internal function that actually pushes the passed data to the
// end of the script. It automatically chooses canonical opcodes depending on
// the length of the data. A zero length buffer will lead to a push of empty
// data onto the stack (OP_0). No data limits are enforced with this function.
func (b *ScriptBuilder) addData(data []byte) *ScriptBuilder {
dataLen := len(data)
// When the data consists of a single number that can be represented
// by one of the "small integer" opcodes, use that opcode instead of
// a data push opcode followed by the number.
if dataLen == 0 || dataLen == 1 && data[0] == 0 {
b.script = append(b.script, OP_0)
return b
} else if dataLen == 1 && data[0] <= 16 {
b.script = append(b.script, byte((OP_1-1)+data[0]))
return b
} else if dataLen == 1 && data[0] == 0x81 {
b.script = append(b.script, byte(OP_1NEGATE))
return b
}
// Use one of the OP_DATA_# opcodes if the length of the data is small
// enough so the data push instruction is only a single byte.
// Otherwise, choose the smallest possible OP_PUSHDATA# opcode that
// can represent the length of the data.
if dataLen < OP_PUSHDATA1 {
b.script = append(b.script, byte((OP_DATA_1-1)+dataLen))
} else if dataLen <= 0xff {
b.script = append(b.script, OP_PUSHDATA1, byte(dataLen))
} else if dataLen <= 0xffff {
buf := make([]byte, 2)
binary.LittleEndian.PutUint16(buf, uint16(dataLen))
b.script = append(b.script, OP_PUSHDATA2)
b.script = append(b.script, buf...)
} else {
buf := make([]byte, 4)
binary.LittleEndian.PutUint32(buf, uint32(dataLen))
b.script = append(b.script, OP_PUSHDATA4)
b.script = append(b.script, buf...)
}
// Append the actual data.
b.script = append(b.script, data...)
return b
}
// AddFullData should not typically be used by ordinary users as it does not
// include the checks which prevent data pushes larger than the maximum allowed
// sizes which leads to scripts that can't be executed. This is provided for
// testing purposes such as regression tests where sizes are intentionally made
// larger than allowed.
//
// Use AddData instead.
func (b *ScriptBuilder) AddFullData(data []byte) *ScriptBuilder {
if b.err != nil {
return b
}
return b.addData(data)
}
// AddData pushes the passed data to the end of the script. It automatically
// chooses canonical opcodes depending on the length of the data. A zero length
// buffer will lead to a push of empty data onto the stack (OP_0) and any push
// of data greater than MaxScriptElementSize will not modify the script since
// that is not allowed by the script engine. Also, the script will not be
// modified if pushing the data would cause the script to exceed the maximum
// allowed script engine size.
func (b *ScriptBuilder) AddData(data []byte) *ScriptBuilder {
if b.err != nil {
return b
}
// Pushes that would cause the script to exceed the largest allowed
// script size would result in a non-canonical script.
dataSize := canonicalDataSize(data)
if len(b.script)+dataSize > maxScriptSize {
str := fmt.Sprintf("adding %d bytes of data would exceed the "+
"maximum allowed canonical script length of %d",
dataSize, maxScriptSize)
b.err = ErrScriptNotCanonical(str)
return b
}
// Pushes larger than the max script element size would result in a
// script that is not canonical.
dataLen := len(data)
if dataLen > MaxScriptElementSize {
str := fmt.Sprintf("adding a data element of %d bytes would "+
"exceed the maximum allowed script element size of %d",
dataLen, maxScriptSize)
b.err = ErrScriptNotCanonical(str)
return b
}
return b.addData(data)
}
// AddInt64 pushes the passed integer to the end of the script. The script will
// not be modified if pushing the data would cause the script to exceed the
// maximum allowed script engine size.
func (b *ScriptBuilder) AddInt64(val int64) *ScriptBuilder {
if b.err != nil {
return b
}
// Pushes that would cause the script to exceed the largest allowed
// script size would result in a non-canonical script.
if len(b.script)+1 > maxScriptSize {
str := fmt.Sprintf("adding an integer would exceed the "+
"maximum allow canonical script length of %d",
maxScriptSize)
b.err = ErrScriptNotCanonical(str)
return b
}
// Fast path for small integers and OP_1NEGATE.
if val == 0 {
b.script = append(b.script, OP_0)
return b
}
if val == -1 || (val >= 1 && val <= 16) {
b.script = append(b.script, byte((OP_1-1)+val))
return b
}
return b.AddData(fromInt(new(big.Int).SetInt64(val)))
}
// AddUint64 pushes the passed integer to the end of the script. The script
// will not be modified if pushing the data would cause the script to
// exceed the maximum allowed script engine size.
func (b *ScriptBuilder) AddUint64(val uint64) *ScriptBuilder {
if b.err != nil {
return b
}
// Pushes that would cause the script to exceed the largest allowed
// script size would result in a non-canonical script.
if len(b.script)+1 > maxScriptSize {
str := fmt.Sprintf("adding an unsigned integer would exceed "+
"the maximum allow canonical script length of %d",
maxScriptSize)
b.err = ErrScriptNotCanonical(str)
return b
}
// Fast path for small integers.
if val == 0 {
b.script = append(b.script, OP_0)
return b
}
if val >= 1 && val <= 16 {
b.script = append(b.script, byte((OP_1-1)+val))
return b
}
return b.AddData(fromInt(new(big.Int).SetUint64(val)))
}
// Reset resets the script so it has no content.
func (b *ScriptBuilder) Reset() *ScriptBuilder {
b.script = b.script[0:0]
b.err = nil
return b
}
// Script returns the currently built script. When any errors occured while
// building the script, the script will be returned up the point of the first
// error along with the error.
func (b *ScriptBuilder) Script() ([]byte, error) {
return b.script, b.err
}
// NewScriptBuilder returns a new instance of a script builder. See
// ScriptBuilder for details.
func NewScriptBuilder() *ScriptBuilder {
return &ScriptBuilder{
script: make([]byte, 0, defaultScriptAlloc),
}
}

View file

@ -0,0 +1,475 @@
// Copyright (c) 2013-2015 Conformal Systems LLC.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package txscript_test
import (
"bytes"
"testing"
"github.com/btcsuite/btcd/txscript"
)
// TestScriptBuilderAddOp tests that pushing opcodes to a script via the
// ScriptBuilder API works as expected.
func TestScriptBuilderAddOp(t *testing.T) {
t.Parallel()
tests := []struct {
name string
opcodes []byte
expected []byte
}{
{
name: "push OP_0",
opcodes: []byte{txscript.OP_0},
expected: []byte{txscript.OP_0},
},
{
name: "push OP_1 OP_2",
opcodes: []byte{txscript.OP_1, txscript.OP_2},
expected: []byte{txscript.OP_1, txscript.OP_2},
},
{
name: "push OP_HASH160 OP_EQUAL",
opcodes: []byte{txscript.OP_HASH160, txscript.OP_EQUAL},
expected: []byte{txscript.OP_HASH160, txscript.OP_EQUAL},
},
}
builder := txscript.NewScriptBuilder()
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
builder.Reset()
for _, opcode := range test.opcodes {
builder.AddOp(opcode)
}
result, err := builder.Script()
if err != nil {
t.Errorf("ScriptBuilder.AddOp #%d (%s) unexpected "+
"error: %v", i, test.name, err)
continue
}
if !bytes.Equal(result, test.expected) {
t.Errorf("ScriptBuilder.AddOp #%d (%s) wrong result\n"+
"got: %x\nwant: %x", i, test.name, result,
test.expected)
continue
}
}
}
// TestScriptBuilderAddInt64 tests that pushing signed integers to a script via
// the ScriptBuilder API works as expected.
func TestScriptBuilderAddInt64(t *testing.T) {
t.Parallel()
tests := []struct {
name string
val int64
expected []byte
}{
{name: "push -1", val: -1, expected: []byte{txscript.OP_1NEGATE}},
{name: "push small int 0", val: 0, expected: []byte{txscript.OP_0}},
{name: "push small int 1", val: 1, expected: []byte{txscript.OP_1}},
{name: "push small int 2", val: 2, expected: []byte{txscript.OP_2}},
{name: "push small int 3", val: 3, expected: []byte{txscript.OP_3}},
{name: "push small int 4", val: 4, expected: []byte{txscript.OP_4}},
{name: "push small int 5", val: 5, expected: []byte{txscript.OP_5}},
{name: "push small int 6", val: 6, expected: []byte{txscript.OP_6}},
{name: "push small int 7", val: 7, expected: []byte{txscript.OP_7}},
{name: "push small int 8", val: 8, expected: []byte{txscript.OP_8}},
{name: "push small int 9", val: 9, expected: []byte{txscript.OP_9}},
{name: "push small int 10", val: 10, expected: []byte{txscript.OP_10}},
{name: "push small int 11", val: 11, expected: []byte{txscript.OP_11}},
{name: "push small int 12", val: 12, expected: []byte{txscript.OP_12}},
{name: "push small int 13", val: 13, expected: []byte{txscript.OP_13}},
{name: "push small int 14", val: 14, expected: []byte{txscript.OP_14}},
{name: "push small int 15", val: 15, expected: []byte{txscript.OP_15}},
{name: "push small int 16", val: 16, expected: []byte{txscript.OP_16}},
{name: "push 17", val: 17, expected: []byte{txscript.OP_DATA_1, 0x11}},
{name: "push 65", val: 65, expected: []byte{txscript.OP_DATA_1, 0x41}},
{name: "push 127", val: 127, expected: []byte{txscript.OP_DATA_1, 0x7f}},
{name: "push 128", val: 128, expected: []byte{txscript.OP_DATA_2, 0x80, 0}},
{name: "push 255", val: 255, expected: []byte{txscript.OP_DATA_2, 0xff, 0}},
{name: "push 256", val: 256, expected: []byte{txscript.OP_DATA_2, 0, 0x01}},
{name: "push 32767", val: 32767, expected: []byte{txscript.OP_DATA_2, 0xff, 0x7f}},
{name: "push 32768", val: 32768, expected: []byte{txscript.OP_DATA_3, 0, 0x80, 0}},
{name: "push -2", val: -2, expected: []byte{txscript.OP_DATA_1, 0x82}},
{name: "push -3", val: -3, expected: []byte{txscript.OP_DATA_1, 0x83}},
{name: "push -4", val: -4, expected: []byte{txscript.OP_DATA_1, 0x84}},
{name: "push -5", val: -5, expected: []byte{txscript.OP_DATA_1, 0x85}},
{name: "push -17", val: -17, expected: []byte{txscript.OP_DATA_1, 0x91}},
{name: "push -65", val: -65, expected: []byte{txscript.OP_DATA_1, 0xc1}},
{name: "push -127", val: -127, expected: []byte{txscript.OP_DATA_1, 0xff}},
{name: "push -128", val: -128, expected: []byte{txscript.OP_DATA_2, 0x80, 0x80}},
{name: "push -255", val: -255, expected: []byte{txscript.OP_DATA_2, 0xff, 0x80}},
{name: "push -256", val: -256, expected: []byte{txscript.OP_DATA_2, 0x00, 0x81}},
{name: "push -32767", val: -32767, expected: []byte{txscript.OP_DATA_2, 0xff, 0xff}},
{name: "push -32768", val: -32768, expected: []byte{txscript.OP_DATA_3, 0x00, 0x80, 0x80}},
}
builder := txscript.NewScriptBuilder()
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
builder.Reset().AddInt64(test.val)
result, err := builder.Script()
if err != nil {
t.Errorf("ScriptBuilder.AddInt64 #%d (%s) unexpected "+
"error: %v", i, test.name, err)
continue
}
if !bytes.Equal(result, test.expected) {
t.Errorf("ScriptBuilder.AddInt64 #%d (%s) wrong result\n"+
"got: %x\nwant: %x", i, test.name, result,
test.expected)
continue
}
}
}
// TestScriptBuilderAddUint64 tests that pushing unsigned integers to a script
// via the ScriptBuilder API works as expected.
func TestScriptBuilderAddUint64(t *testing.T) {
t.Parallel()
tests := []struct {
name string
val uint64
expected []byte
}{
{name: "push small int 0", val: 0, expected: []byte{txscript.OP_0}},
{name: "push small int 1", val: 1, expected: []byte{txscript.OP_1}},
{name: "push small int 2", val: 2, expected: []byte{txscript.OP_2}},
{name: "push small int 3", val: 3, expected: []byte{txscript.OP_3}},
{name: "push small int 4", val: 4, expected: []byte{txscript.OP_4}},
{name: "push small int 5", val: 5, expected: []byte{txscript.OP_5}},
{name: "push small int 6", val: 6, expected: []byte{txscript.OP_6}},
{name: "push small int 7", val: 7, expected: []byte{txscript.OP_7}},
{name: "push small int 8", val: 8, expected: []byte{txscript.OP_8}},
{name: "push small int 9", val: 9, expected: []byte{txscript.OP_9}},
{name: "push small int 10", val: 10, expected: []byte{txscript.OP_10}},
{name: "push small int 11", val: 11, expected: []byte{txscript.OP_11}},
{name: "push small int 12", val: 12, expected: []byte{txscript.OP_12}},
{name: "push small int 13", val: 13, expected: []byte{txscript.OP_13}},
{name: "push small int 14", val: 14, expected: []byte{txscript.OP_14}},
{name: "push small int 15", val: 15, expected: []byte{txscript.OP_15}},
{name: "push small int 16", val: 16, expected: []byte{txscript.OP_16}},
{name: "push 17", val: 17, expected: []byte{txscript.OP_DATA_1, 0x11}},
{name: "push 65", val: 65, expected: []byte{txscript.OP_DATA_1, 0x41}},
{name: "push 127", val: 127, expected: []byte{txscript.OP_DATA_1, 0x7f}},
{name: "push 128", val: 128, expected: []byte{txscript.OP_DATA_2, 0x80, 0}},
{name: "push 255", val: 255, expected: []byte{txscript.OP_DATA_2, 0xff, 0}},
{name: "push 256", val: 256, expected: []byte{txscript.OP_DATA_2, 0, 0x01}},
{name: "push 32767", val: 32767, expected: []byte{txscript.OP_DATA_2, 0xff, 0x7f}},
{name: "push 32768", val: 32768, expected: []byte{txscript.OP_DATA_3, 0, 0x80, 0}},
}
builder := txscript.NewScriptBuilder()
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
builder.Reset().AddUint64(test.val)
result, err := builder.Script()
if err != nil {
t.Errorf("ScriptBuilder.AddUint64 #%d (%s) unexpected "+
"error: %v", i, test.name, err)
continue
}
if !bytes.Equal(result, test.expected) {
t.Errorf("ScriptBuilder.AddUint64 #%d (%s) wrong result\n"+
"got: %x\nwant: %x", i, test.name, result,
test.expected)
continue
}
}
}
// TestScriptBuilderAddData tests that pushing data to a script via the
// ScriptBuilder API works as expected and conforms to BIP0062.
func TestScriptBuilderAddData(t *testing.T) {
t.Parallel()
tests := []struct {
name string
data []byte
expected []byte
useFull bool // use AddFullData instead of AddData.
}{
// BIP0062: Pushing an empty byte sequence must use OP_0.
{name: "push empty byte sequence", data: []byte{}, expected: []byte{txscript.OP_0}},
{name: "push 1 byte 0x00", data: []byte{0x00}, expected: []byte{txscript.OP_0}},
// BIP0062: Pushing a 1-byte sequence of byte 0x01 through 0x10 must use OP_n.
{name: "push 1 byte 0x01", data: []byte{0x01}, expected: []byte{txscript.OP_1}},
{name: "push 1 byte 0x02", data: []byte{0x02}, expected: []byte{txscript.OP_2}},
{name: "push 1 byte 0x03", data: []byte{0x03}, expected: []byte{txscript.OP_3}},
{name: "push 1 byte 0x04", data: []byte{0x04}, expected: []byte{txscript.OP_4}},
{name: "push 1 byte 0x05", data: []byte{0x05}, expected: []byte{txscript.OP_5}},
{name: "push 1 byte 0x06", data: []byte{0x06}, expected: []byte{txscript.OP_6}},
{name: "push 1 byte 0x07", data: []byte{0x07}, expected: []byte{txscript.OP_7}},
{name: "push 1 byte 0x08", data: []byte{0x08}, expected: []byte{txscript.OP_8}},
{name: "push 1 byte 0x09", data: []byte{0x09}, expected: []byte{txscript.OP_9}},
{name: "push 1 byte 0x0a", data: []byte{0x0a}, expected: []byte{txscript.OP_10}},
{name: "push 1 byte 0x0b", data: []byte{0x0b}, expected: []byte{txscript.OP_11}},
{name: "push 1 byte 0x0c", data: []byte{0x0c}, expected: []byte{txscript.OP_12}},
{name: "push 1 byte 0x0d", data: []byte{0x0d}, expected: []byte{txscript.OP_13}},
{name: "push 1 byte 0x0e", data: []byte{0x0e}, expected: []byte{txscript.OP_14}},
{name: "push 1 byte 0x0f", data: []byte{0x0f}, expected: []byte{txscript.OP_15}},
{name: "push 1 byte 0x10", data: []byte{0x10}, expected: []byte{txscript.OP_16}},
// BIP0062: Pushing the byte 0x81 must use OP_1NEGATE.
{name: "push 1 byte 0x81", data: []byte{0x81}, expected: []byte{txscript.OP_1NEGATE}},
// BIP0062: Pushing any other byte sequence up to 75 bytes must
// use the normal data push (opcode byte n, with n the number of
// bytes, followed n bytes of data being pushed).
{name: "push 1 byte 0x11", data: []byte{0x11}, expected: []byte{txscript.OP_DATA_1, 0x11}},
{name: "push 1 byte 0x80", data: []byte{0x80}, expected: []byte{txscript.OP_DATA_1, 0x80}},
{name: "push 1 byte 0x82", data: []byte{0x82}, expected: []byte{txscript.OP_DATA_1, 0x82}},
{name: "push 1 byte 0xff", data: []byte{0xff}, expected: []byte{txscript.OP_DATA_1, 0xff}},
{
name: "push data len 17",
data: bytes.Repeat([]byte{0x49}, 17),
expected: append([]byte{txscript.OP_DATA_17}, bytes.Repeat([]byte{0x49}, 17)...),
},
{
name: "push data len 75",
data: bytes.Repeat([]byte{0x49}, 75),
expected: append([]byte{txscript.OP_DATA_75}, bytes.Repeat([]byte{0x49}, 75)...),
},
// BIP0062: Pushing 76 to 255 bytes must use OP_PUSHDATA1.
{
name: "push data len 76",
data: bytes.Repeat([]byte{0x49}, 76),
expected: append([]byte{txscript.OP_PUSHDATA1, 76}, bytes.Repeat([]byte{0x49}, 76)...),
},
{
name: "push data len 255",
data: bytes.Repeat([]byte{0x49}, 255),
expected: append([]byte{txscript.OP_PUSHDATA1, 255}, bytes.Repeat([]byte{0x49}, 255)...),
},
// BIP0062: Pushing 256 to 520 bytes must use OP_PUSHDATA2.
{
name: "push data len 256",
data: bytes.Repeat([]byte{0x49}, 256),
expected: append([]byte{txscript.OP_PUSHDATA2, 0, 1}, bytes.Repeat([]byte{0x49}, 256)...),
},
{
name: "push data len 520",
data: bytes.Repeat([]byte{0x49}, 520),
expected: append([]byte{txscript.OP_PUSHDATA2, 0x08, 0x02}, bytes.Repeat([]byte{0x49}, 520)...),
},
// BIP0062: OP_PUSHDATA4 can never be used, as pushes over 520
// bytes are not allowed, and those below can be done using
// other operators.
{
name: "push data len 521",
data: bytes.Repeat([]byte{0x49}, 521),
expected: []byte{},
},
{
name: "push data len 32767 (canonical)",
data: bytes.Repeat([]byte{0x49}, 32767),
expected: []byte{},
},
{
name: "push data len 65536 (canonical)",
data: bytes.Repeat([]byte{0x49}, 65536),
expected: []byte{},
},
// Additional tests for the PushFullData function that
// intentionally allows data pushes to exceed the limit for
// regression testing purposes.
// 3-byte data push via OP_PUSHDATA_2.
{
name: "push data len 32767 (non-canonical)",
data: bytes.Repeat([]byte{0x49}, 32767),
expected: append([]byte{txscript.OP_PUSHDATA2, 255, 127}, bytes.Repeat([]byte{0x49}, 32767)...),
useFull: true,
},
// 5-byte data push via OP_PUSHDATA_4.
{
name: "push data len 65536 (non-canonical)",
data: bytes.Repeat([]byte{0x49}, 65536),
expected: append([]byte{txscript.OP_PUSHDATA4, 0, 0, 1, 0}, bytes.Repeat([]byte{0x49}, 65536)...),
useFull: true,
},
}
builder := txscript.NewScriptBuilder()
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
if !test.useFull {
builder.Reset().AddData(test.data)
} else {
builder.Reset().AddFullData(test.data)
}
result, _ := builder.Script()
if !bytes.Equal(result, test.expected) {
t.Errorf("ScriptBuilder.AddData #%d (%s) wrong result\n"+
"got: %x\nwant: %x", i, test.name, result,
test.expected)
continue
}
}
}
// TestExceedMaxScriptSize ensures that all of the functions that can be used
// to add data to a script don't allow the script to exceed the max allowed
// size.
func TestExceedMaxScriptSize(t *testing.T) {
t.Parallel()
// Start off by constructing a max size script.
maxScriptSize := txscript.TstMaxScriptSize
builder := txscript.NewScriptBuilder()
builder.Reset().AddFullData(make([]byte, maxScriptSize-3))
origScript, err := builder.Script()
if err != nil {
t.Fatalf("Unexpected error for max size script: %v", err)
}
// Ensure adding data that would exceed the maximum size of the script
// does not add the data.
script, err := builder.AddData([]byte{0x00}).Script()
if _, ok := err.(txscript.ErrScriptNotCanonical); !ok || err == nil {
t.Fatalf("ScriptBuilder.AddData allowed exceeding max script "+
"size: %v", len(script))
}
if !bytes.Equal(script, origScript) {
t.Fatalf("ScriptBuilder.AddData unexpected modified script - "+
"got len %d, want len %d", len(script), len(origScript))
}
// Ensure adding an opcode that would exceed the maximum size of the
// script does not add the data.
builder.Reset().AddFullData(make([]byte, maxScriptSize-3))
script, err = builder.AddOp(txscript.OP_0).Script()
if _, ok := err.(txscript.ErrScriptNotCanonical); !ok || err == nil {
t.Fatalf("ScriptBuilder.AddOp unexpected modified script - "+
"got len %d, want len %d", len(script), len(origScript))
}
if !bytes.Equal(script, origScript) {
t.Fatalf("ScriptBuilder.AddOp unexpected modified script - "+
"got len %d, want len %d", len(script), len(origScript))
}
// Ensure adding an integer that would exceed the maximum size of the
// script does not add the data.
builder.Reset().AddFullData(make([]byte, maxScriptSize-3))
script, err = builder.AddInt64(0).Script()
if _, ok := err.(txscript.ErrScriptNotCanonical); !ok || err == nil {
t.Fatalf("ScriptBuilder.AddInt64 unexpected modified script - "+
"got len %d, want len %d", len(script), len(origScript))
}
if !bytes.Equal(script, origScript) {
t.Fatalf("ScriptBuilder.AddInt64 unexpected modified script - "+
"got len %d, want len %d", len(script), len(origScript))
}
// Ensure adding an unsigned integer that would exceed the maximum size
// of the script does not add the data.
builder.Reset().AddFullData(make([]byte, maxScriptSize-3))
script, err = builder.AddUint64(0).Script()
if _, ok := err.(txscript.ErrScriptNotCanonical); !ok || err == nil {
t.Fatalf("ScriptBuilder.AddUint64 unexpected modified script - "+
"got len %d, want len %d", len(script), len(origScript))
}
if !bytes.Equal(script, origScript) {
t.Fatalf("ScriptBuilder.AddUint64 unexpected modified script - "+
"got len %d, want len %d", len(script), len(origScript))
}
}
// TestErroredScript ensures that all of the functions that can be used to add
// data to a script don't modify the script once an error has happened.
func TestErroredScript(t *testing.T) {
t.Parallel()
// Start off by constructing a near max size script that has enough
// space left to add each data type without an error and force an
// initial error condition.
maxScriptSize := txscript.TstMaxScriptSize
builder := txscript.NewScriptBuilder()
builder.Reset().AddFullData(make([]byte, maxScriptSize-8))
origScript, err := builder.Script()
if err != nil {
t.Fatalf("ScriptBuilder.AddFullData unexpected error: %v", err)
}
script, err := builder.AddData([]byte{0x00, 0x00, 0x00, 0x00, 0x00}).Script()
if _, ok := err.(txscript.ErrScriptNotCanonical); !ok || err == nil {
t.Fatalf("ScriptBuilder.AddData allowed exceeding max script "+
"size: %v", len(script))
}
if !bytes.Equal(script, origScript) {
t.Fatalf("ScriptBuilder.AddData unexpected modified script - "+
"got len %d, want len %d", len(script), len(origScript))
}
// Ensure adding data, even using the non-canonical path, to a script
// that has errored doesn't succeed.
script, err = builder.AddFullData([]byte{0x00}).Script()
if _, ok := err.(txscript.ErrScriptNotCanonical); !ok || err == nil {
t.Fatal("ScriptBuilder.AddFullData succeeded on errored script")
}
if !bytes.Equal(script, origScript) {
t.Fatalf("ScriptBuilder.AddFullData unexpected modified "+
"script - got len %d, want len %d", len(script),
len(origScript))
}
// Ensure adding data to a script that has errored doesn't succeed.
script, err = builder.AddData([]byte{0x00}).Script()
if _, ok := err.(txscript.ErrScriptNotCanonical); !ok || err == nil {
t.Fatal("ScriptBuilder.AddData succeeded on errored script")
}
if !bytes.Equal(script, origScript) {
t.Fatalf("ScriptBuilder.AddData unexpected modified "+
"script - got len %d, want len %d", len(script),
len(origScript))
}
// Ensure adding an opcode to a script that has errored doesn't succeed.
script, err = builder.AddOp(txscript.OP_0).Script()
if _, ok := err.(txscript.ErrScriptNotCanonical); !ok || err == nil {
t.Fatal("ScriptBuilder.AddOp succeeded on errored script")
}
if !bytes.Equal(script, origScript) {
t.Fatalf("ScriptBuilder.AddOp unexpected modified script - "+
"got len %d, want len %d", len(script), len(origScript))
}
// Ensure adding an integer to a script that has errored doesn't
// succeed.
script, err = builder.AddInt64(0).Script()
if _, ok := err.(txscript.ErrScriptNotCanonical); !ok || err == nil {
t.Fatal("ScriptBuilder.AddInt64 succeeded on errored script")
}
if !bytes.Equal(script, origScript) {
t.Fatalf("ScriptBuilder.AddInt64 unexpected modified script - "+
"got len %d, want len %d", len(script), len(origScript))
}
// Ensure adding an unsigned integer to a script that has errored
// doesn't succeed.
script, err = builder.AddUint64(0).Script()
if _, ok := err.(txscript.ErrScriptNotCanonical); !ok || err == nil {
t.Fatal("ScriptBuilder.AddUint64 succeeded on errored script")
}
if !bytes.Equal(script, origScript) {
t.Fatalf("ScriptBuilder.AddUint64 unexpected modified script - "+
"got len %d, want len %d", len(script), len(origScript))
}
// Ensure the error has a message set.
if err.Error() == "" {
t.Fatal("ErrScriptNotCanonical.Error does not have any text")
}
}

369
txscript/stack.go Normal file
View file

@ -0,0 +1,369 @@
// Copyright (c) 2013-2015 Conformal Systems LLC.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package txscript
import (
"encoding/hex"
"math/big"
)
// asInt converts a byte array to a bignum by treating it as a little endian
// number with sign bit.
func asInt(v []byte) (*big.Int, error) {
// Only 32bit numbers allowed.
if len(v) > 4 {
return nil, ErrStackNumberTooBig
}
if len(v) == 0 {
return big.NewInt(0), nil
}
negative := false
origlen := len(v)
msb := v[len(v)-1]
if msb&0x80 == 0x80 {
negative = true
// remove sign bit
msb &= 0x7f
}
// trim leading 0 bytes
for ; msb == 0; msb = v[len(v)-1] {
v = v[:len(v)-1]
if len(v) == 0 {
break
}
}
// reverse bytes with a copy since stack is immutable.
intArray := make([]byte, len(v))
for i := range v {
intArray[len(v)-i-1] = v[i]
}
// IFF the value is negative and no 0 bytes were trimmed,
// the leading byte needs to be sign corrected
if negative && len(intArray) == origlen {
intArray[0] &= 0x7f
}
num := new(big.Int).SetBytes(intArray)
if negative {
num = num.Neg(num)
}
return num, nil
}
// fromInt provies a Big.Int in little endian format with the high bit of the
// msb donating sign.
func fromInt(v *big.Int) []byte {
negative := false
if v.Sign() == -1 {
negative = true
}
// Int.Bytes() trims leading zeros for us, so we don't have to.
b := v.Bytes()
if len(b) == 0 {
return []byte{}
}
arr := make([]byte, len(b))
for i := range b {
arr[len(b)-i-1] = b[i]
}
// if would otherwise be negative, add a zero byte
if arr[len(arr)-1]&0x80 == 0x80 {
arr = append(arr, 0)
}
if negative {
arr[len(arr)-1] |= 0x80
}
return arr
}
// asBool gets the boolean value of the byte array.
func asBool(t []byte) bool {
for i := range t {
if t[i] != 0 {
return true
}
}
return false
}
// fromBool converts a boolean into the appropriate byte array.
func fromBool(v bool) []byte {
if v {
return []byte{1}
}
return []byte{0}
}
// Stack represents a stack of immutable objects to be used with bitcoin scripts
// Objects may be shared, therefore in usage if a value is to be changed it
// *must* be deep-copied first to avoid changing other values on the stack.
type Stack struct {
stk [][]byte
}
// PushByteArray adds the given back array to the top of the stack.
func (s *Stack) PushByteArray(so []byte) {
s.stk = append(s.stk, so)
}
// PushInt converts the provided bignum to a suitable byte array then pushes
// it onto the top of the stack.
func (s *Stack) PushInt(val *big.Int) {
s.PushByteArray(fromInt(val))
}
// PushBool converts the provided boolean to a suitable byte array then pushes
// it onto the top of the stack.
func (s *Stack) PushBool(val bool) {
s.PushByteArray(fromBool(val))
}
// PopByteArray pops the value off the top of the stack and returns it.
func (s *Stack) PopByteArray() ([]byte, error) {
return s.nipN(0)
}
// PopInt pops the value off the top of the stack, converts it into a bignum and
// returns it.
func (s *Stack) PopInt() (*big.Int, error) {
so, err := s.PopByteArray()
if err != nil {
return nil, err
}
return asInt(so)
}
// PopBool pops the value off the top of the stack, converts it into a bool and
// returns it.
func (s *Stack) PopBool() (bool, error) {
so, err := s.PopByteArray()
if err != nil {
return false, err
}
return asBool(so), nil
}
// PeekByteArray returns the nth item on the stack without removing it.
func (s *Stack) PeekByteArray(idx int) (so []byte, err error) {
sz := len(s.stk)
if idx < 0 || idx >= sz {
return nil, ErrStackUnderflow
}
return s.stk[sz-idx-1], nil
}
// PeekInt returns the nth item on the stack as a bignum without removing it.
func (s *Stack) PeekInt(idx int) (i *big.Int, err error) {
so, err := s.PeekByteArray(idx)
if err != nil {
return nil, err
}
return asInt(so)
}
// PeekBool returns the nth item on the stack as a bool without removing it.
func (s *Stack) PeekBool(idx int) (i bool, err error) {
so, err := s.PeekByteArray(idx)
if err != nil {
return false, err
}
return asBool(so), nil
}
// nipN is an internal function that removes the nth item on the stack and
// returns it.
func (s *Stack) nipN(idx int) (so []byte, err error) {
sz := len(s.stk)
if idx < 0 || idx > sz-1 {
err = ErrStackUnderflow
return
}
so = s.stk[sz-idx-1]
if idx == 0 {
s.stk = s.stk[:sz-1]
} else if idx == sz-1 {
s1 := make([][]byte, sz-1, sz-1)
copy(s1, s.stk[1:])
s.stk = s1
} else {
s1 := s.stk[sz-idx : sz]
s.stk = s.stk[:sz-idx-1]
s.stk = append(s.stk, s1...)
}
return
}
// NipN removes the Nth object on the stack
func (s *Stack) NipN(idx int) error {
_, err := s.nipN(idx)
return err
}
// Tuck copies the item at the top of the stack and inserts it before the 2nd
// to top item. e.g.: 2,1 -> 2,1,2
func (s *Stack) Tuck() error {
so2, err := s.PopByteArray()
if err != nil {
return err
}
so1, err := s.PopByteArray()
if err != nil {
return err
}
s.PushByteArray(so2) // stack 2
s.PushByteArray(so1) // stack 1,2
s.PushByteArray(so2) // stack 2,1,2
return nil
}
// Depth returns the number of items on the stack.
func (s *Stack) Depth() (sz int) {
sz = len(s.stk)
return
}
// DropN removes the top N items from the stack.
// e.g.
// DropN(1): 1,2,3 -> 1,2
// DropN(2): 1,2,3 -> 1
func (s *Stack) DropN(n int) error {
if n < 1 {
return ErrStackInvalidArgs
}
for ; n > 0; n-- {
_, err := s.PopByteArray()
if err != nil {
return err
}
}
return nil
}
// DupN duplicates the top N items on the stack.
// e.g.
// DupN(1): 1,2,3 -> 1,2,3,3
// DupN(2): 1,2,3 -> 1,2,3,2,3
func (s *Stack) DupN(n int) error {
if n < 1 {
return ErrStackInvalidArgs
}
// Iteratively duplicate the value n-1 down the stack n times.
// this leaves us with an in-order duplicate of the top N items on the
// stack.
for i := n; i > 0; i-- {
so, err := s.PeekByteArray(n - 1)
if err != nil {
return err
}
s.PushByteArray(so)
}
return nil
}
// RotN rotates the top 3N items on the stack to the left
// e.g.
// RotN(1): 1,2,3 -> 2,3,1
func (s *Stack) RotN(n int) error {
if n < 1 {
return ErrStackInvalidArgs
}
entry := 3*n - 1
// Nip the 3n-1th item from the stack to the top n times to rotate
// them up to the head of the stack.
for i := n; i > 0; i-- {
so, err := s.nipN(entry)
if err != nil {
return err
}
s.PushByteArray(so)
}
return nil
}
// SwapN swaps the top N items on the stack with those below them.
// E.g.:
// SwapN(1): 1,2 -> 2,1
// SwapN(2): 1,2,3,4 -> 3,4,1,2
func (s *Stack) SwapN(n int) error {
if n < 1 {
return ErrStackInvalidArgs
}
entry := 2*n - 1
for i := n; i > 0; i-- {
// swap 2n-1th entry to topj
so, err := s.nipN(entry)
if err != nil {
return err
}
s.PushByteArray(so)
}
return nil
}
// OverN copies N items N spaces back to the top of the stack.
// e.g.:
// OverN(1): 1,2 -> 1,2,1
// OverN(2): 1,2,3,4 -> 1,2,3,4,1,2
func (s *Stack) OverN(n int) error {
if n < 1 {
return ErrStackInvalidArgs
}
// Copy 2n-1th entry to top of the stack
entry := 2*n - 1
for ; n > 0; n-- {
so, err := s.PeekByteArray(entry)
if err != nil {
return err
}
s.PushByteArray(so)
// 4,1,2,3,4, now code original 3rd entry to top.
}
return nil
}
// PickN copies the item N items back in the stack to the top.
// e.g.:
// PickN(1): 1,2,3 -> 1,2,3,2
// PickN(2): 1,2,3 -> 1,2,3,1
func (s *Stack) PickN(n int) error {
so, err := s.PeekByteArray(n)
if err != nil {
return err
}
s.PushByteArray(so)
return nil
}
// RollN moves the item N items back in the stack to the top.
// e.g.:
// RollN(1): 1,2,3 -> 1,3,2
// RollN(2): 1,2,3 -> 2,3,1
func (s *Stack) RollN(n int) error {
so, err := s.nipN(n)
if err != nil {
return err
}
s.PushByteArray(so)
return nil
}
// String returns the stack in a readable format.
func (s *Stack) String() string {
var result string
for _, stack := range s.stk {
result += hex.Dump(stack)
}
return result
}

1005
txscript/stack_test.go Normal file

File diff suppressed because it is too large Load diff