diff --git a/txscript/README.md b/txscript/README.md new file mode 100644 index 000000000..96fce1444 --- /dev/null +++ b/txscript/README.md @@ -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. diff --git a/txscript/address.go b/txscript/address.go new file mode 100644 index 000000000..cfa5dd09a --- /dev/null +++ b/txscript/address.go @@ -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 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: + // 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 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: + // ... 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 +} diff --git a/txscript/address_test.go b/txscript/address_test.go new file mode 100644 index 000000000..9345e7d73 --- /dev/null +++ b/txscript/address_test.go @@ -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 + } + } +} diff --git a/txscript/data/LICENSE b/txscript/data/LICENSE new file mode 100644 index 000000000..30d808c58 --- /dev/null +++ b/txscript/data/LICENSE @@ -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. + diff --git a/txscript/data/script_invalid.json b/txscript/data/script_invalid.json new file mode 100644 index 000000000..4f1d55438 --- /dev/null +++ b/txscript/data/script_invalid.json @@ -0,0 +1,413 @@ +[ +["", "DEPTH", "P2SH,STRICTENC", "Test the test: we should have an empty stack after scriptSig evaluation"], +[" ", "DEPTH", "P2SH,STRICTENC", "and multiple spaces should not change that."], +[" ", "DEPTH", "P2SH,STRICTENC"], +[" ", "DEPTH", "P2SH,STRICTENC"], + +["", "", "P2SH,STRICTENC"], +["", "NOP", "P2SH,STRICTENC"], +["", "NOP DEPTH", "P2SH,STRICTENC"], +["NOP", "", "P2SH,STRICTENC"], +["NOP", "DEPTH", "P2SH,STRICTENC"], +["NOP","NOP", "P2SH,STRICTENC"], +["NOP","NOP DEPTH", "P2SH,STRICTENC"], + +["DEPTH", "", "P2SH,STRICTENC"], + +["0x4c01","0x01 NOP", "P2SH,STRICTENC", "PUSHDATA1 with not enough bytes"], +["0x4d0200ff","0x01 NOP", "P2SH,STRICTENC", "PUSHDATA2 with not enough bytes"], +["0x4e03000000ffff","0x01 NOP", "P2SH,STRICTENC", "PUSHDATA4 with not enough bytes"], + +["1", "IF 0x50 ENDIF 1", "P2SH,STRICTENC", "0x50 is reserved"], +["0x52", "0x5f ADD 0x60 EQUAL", "P2SH,STRICTENC", "0x51 through 0x60 push 1 through 16 onto stack"], +["0","NOP", "P2SH,STRICTENC"], +["1", "IF VER ELSE 1 ENDIF", "P2SH,STRICTENC", "VER non-functional"], +["0", "IF VERIF ELSE 1 ENDIF", "P2SH,STRICTENC", "VERIF illegal everywhere"], +["0", "IF ELSE 1 ELSE VERIF ENDIF", "P2SH,STRICTENC", "VERIF illegal everywhere"], +["0", "IF VERNOTIF ELSE 1 ENDIF", "P2SH,STRICTENC", "VERNOTIF illegal everywhere"], +["0", "IF ELSE 1 ELSE VERNOTIF ENDIF", "P2SH,STRICTENC", "VERNOTIF illegal everywhere"], + +["1 IF", "1 ENDIF", "P2SH,STRICTENC", "IF/ENDIF can't span scriptSig/scriptPubKey"], +["1 IF 0 ENDIF", "1 ENDIF", "P2SH,STRICTENC"], +["1 ELSE 0 ENDIF", "1", "P2SH,STRICTENC"], +["0 NOTIF", "123", "P2SH,STRICTENC"], + +["0", "DUP IF ENDIF", "P2SH,STRICTENC"], +["0", "IF 1 ENDIF", "P2SH,STRICTENC"], +["0", "DUP IF ELSE ENDIF", "P2SH,STRICTENC"], +["0", "IF 1 ELSE ENDIF", "P2SH,STRICTENC"], +["0", "NOTIF ELSE 1 ENDIF", "P2SH,STRICTENC"], + +["0 1", "IF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC"], +["0 0", "IF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC"], +["1 0", "IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC"], +["0 1", "IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC"], + +["0 0", "NOTIF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC"], +["0 1", "NOTIF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC"], +["1 1", "NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC"], +["0 0", "NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC"], + +["1", "IF RETURN ELSE ELSE 1 ENDIF", "P2SH,STRICTENC", "Multiple ELSEs"], +["1", "IF 1 ELSE ELSE RETURN ENDIF", "P2SH,STRICTENC"], + +["1", "ENDIF", "P2SH,STRICTENC", "Malformed IF/ELSE/ENDIF sequence"], +["1", "ELSE ENDIF", "P2SH,STRICTENC"], +["1", "ENDIF ELSE", "P2SH,STRICTENC"], +["1", "ENDIF ELSE IF", "P2SH,STRICTENC"], +["1", "IF ELSE ENDIF ELSE", "P2SH,STRICTENC"], +["1", "IF ELSE ENDIF ELSE ENDIF", "P2SH,STRICTENC"], +["1", "IF ENDIF ENDIF", "P2SH,STRICTENC"], +["1", "IF ELSE ELSE ENDIF ENDIF", "P2SH,STRICTENC"], + +["1", "RETURN", "P2SH,STRICTENC"], +["1", "DUP IF RETURN ENDIF", "P2SH,STRICTENC"], + +["1", "RETURN 'data'", "P2SH,STRICTENC", "canonical prunable txout format"], +["0 IF", "RETURN ENDIF 1", "P2SH,STRICTENC", "still prunable because IF/ENDIF can't span scriptSig/scriptPubKey"], + +["0", "VERIFY 1", "P2SH,STRICTENC"], +["1", "VERIFY", "P2SH,STRICTENC"], +["1", "VERIFY 0", "P2SH,STRICTENC"], + +["1 TOALTSTACK", "FROMALTSTACK 1", "P2SH,STRICTENC", "alt stack not shared between sig/pubkey"], + +["IFDUP", "DEPTH 0 EQUAL", "P2SH,STRICTENC"], +["DROP", "DEPTH 0 EQUAL", "P2SH,STRICTENC"], +["DUP", "DEPTH 0 EQUAL", "P2SH,STRICTENC"], +["1", "DUP 1 ADD 2 EQUALVERIFY 0 EQUAL", "P2SH,STRICTENC"], +["NOP", "NIP", "P2SH,STRICTENC"], +["NOP", "1 NIP", "P2SH,STRICTENC"], +["NOP", "1 0 NIP", "P2SH,STRICTENC"], +["NOP", "OVER 1", "P2SH,STRICTENC"], +["1", "OVER", "P2SH,STRICTENC"], +["0 1", "OVER DEPTH 3 EQUALVERIFY", "P2SH,STRICTENC"], +["19 20 21", "PICK 19 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC"], +["NOP", "0 PICK", "P2SH,STRICTENC"], +["1", "-1 PICK", "P2SH,STRICTENC"], +["19 20 21", "0 PICK 20 EQUALVERIFY DEPTH 3 EQUAL", "P2SH,STRICTENC"], +["19 20 21", "1 PICK 21 EQUALVERIFY DEPTH 3 EQUAL", "P2SH,STRICTENC"], +["19 20 21", "2 PICK 22 EQUALVERIFY DEPTH 3 EQUAL", "P2SH,STRICTENC"], +["NOP", "0 ROLL", "P2SH,STRICTENC"], +["1", "-1 ROLL", "P2SH,STRICTENC"], +["19 20 21", "0 ROLL 20 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC"], +["19 20 21", "1 ROLL 21 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC"], +["19 20 21", "2 ROLL 22 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC"], +["NOP", "ROT 1", "P2SH,STRICTENC"], +["NOP", "1 ROT 1", "P2SH,STRICTENC"], +["NOP", "1 2 ROT 1", "P2SH,STRICTENC"], +["NOP", "0 1 2 ROT", "P2SH,STRICTENC"], +["NOP", "SWAP 1", "P2SH,STRICTENC"], +["1", "SWAP 1", "P2SH,STRICTENC"], +["0 1", "SWAP 1 EQUALVERIFY", "P2SH,STRICTENC"], +["NOP", "TUCK 1", "P2SH,STRICTENC"], +["1", "TUCK 1", "P2SH,STRICTENC"], +["1 0", "TUCK DEPTH 3 EQUALVERIFY SWAP 2DROP", "P2SH,STRICTENC"], +["NOP", "2DUP 1", "P2SH,STRICTENC"], +["1", "2DUP 1", "P2SH,STRICTENC"], +["NOP", "3DUP 1", "P2SH,STRICTENC"], +["1", "3DUP 1", "P2SH,STRICTENC"], +["1 2", "3DUP 1", "P2SH,STRICTENC"], +["NOP", "2OVER 1", "P2SH,STRICTENC"], +["1", "2 3 2OVER 1", "P2SH,STRICTENC"], +["NOP", "2SWAP 1", "P2SH,STRICTENC"], +["1", "2 3 2SWAP 1", "P2SH,STRICTENC"], + +["'a' 'b'", "CAT", "P2SH,STRICTENC", "CAT disabled"], +["'a' 'b' 0", "IF CAT ELSE 1 ENDIF", "P2SH,STRICTENC", "CAT disabled"], +["'abc' 1 1", "SUBSTR", "P2SH,STRICTENC", "SUBSTR disabled"], +["'abc' 1 1 0", "IF SUBSTR ELSE 1 ENDIF", "P2SH,STRICTENC", "SUBSTR disabled"], +["'abc' 2 0", "IF LEFT ELSE 1 ENDIF", "P2SH,STRICTENC", "LEFT disabled"], +["'abc' 2 0", "IF RIGHT ELSE 1 ENDIF", "P2SH,STRICTENC", "RIGHT disabled"], + +["NOP", "SIZE 1", "P2SH,STRICTENC"], + +["'abc'", "IF INVERT ELSE 1 ENDIF", "P2SH,STRICTENC", "INVERT disabled"], +["1 2 0 IF AND ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "AND disabled"], +["1 2 0 IF OR ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "OR disabled"], +["1 2 0 IF XOR ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "XOR disabled"], +["2 0 IF 2MUL ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "2MUL disabled"], +["2 0 IF 2DIV ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "2DIV disabled"], +["2 2 0 IF MUL ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "MUL disabled"], +["2 2 0 IF DIV ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DIV disabled"], +["2 2 0 IF MOD ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "MOD disabled"], +["2 2 0 IF LSHIFT ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "LSHIFT disabled"], +["2 2 0 IF RSHIFT ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "RSHIFT disabled"], + +["0 1","EQUAL", "P2SH,STRICTENC"], +["1 1 ADD", "0 EQUAL", "P2SH,STRICTENC"], +["11 1 ADD 12 SUB", "11 EQUAL", "P2SH,STRICTENC"], + +["2147483648 0 ADD", "NOP", "P2SH,STRICTENC", "arithmetic operands must be in range [-2^31...2^31] "], +["-2147483648 0 ADD", "NOP", "P2SH,STRICTENC", "arithmetic operands must be in range [-2^31...2^31] "], +["2147483647 DUP ADD", "4294967294 NUMEQUAL", "P2SH,STRICTENC", "NUMEQUAL must be in numeric range"], +["'abcdef' NOT", "0 EQUAL", "P2SH,STRICTENC", "NOT is an arithmetic operand"], + +["2 DUP MUL", "4 EQUAL", "P2SH,STRICTENC", "disabled"], +["2 DUP DIV", "1 EQUAL", "P2SH,STRICTENC", "disabled"], +["2 2MUL", "4 EQUAL", "P2SH,STRICTENC", "disabled"], +["2 2DIV", "1 EQUAL", "P2SH,STRICTENC", "disabled"], +["7 3 MOD", "1 EQUAL", "P2SH,STRICTENC", "disabled"], +["2 2 LSHIFT", "8 EQUAL", "P2SH,STRICTENC", "disabled"], +["2 1 RSHIFT", "1 EQUAL", "P2SH,STRICTENC", "disabled"], + +["1","NOP1 NOP2 NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 2 EQUAL", "P2SH,STRICTENC"], +["'NOP_1_to_10' NOP1 NOP2 NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10","'NOP_1_to_11' EQUAL", "P2SH,STRICTENC"], + +["Ensure 100% coverage of discouraged NOPS"], +["1", "NOP1", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"], +["1", "NOP2", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"], +["1", "NOP3", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"], +["1", "NOP4", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"], +["1", "NOP5", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"], +["1", "NOP6", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"], +["1", "NOP7", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"], +["1", "NOP8", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"], +["1", "NOP9", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"], +["1", "NOP10", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"], + +["NOP10", "1", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "Discouraged NOP10 in scriptSig"], + +["1 0x01 0xb9", "HASH160 0x14 0x15727299b05b45fdaf9ac9ecf7565cfe27c3e567 EQUAL", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "Discouraged NOP10 in redeemScript"], + +["0x50","1", "P2SH,STRICTENC", "opcode 0x50 is reserved"], +["1", "IF 0xba ELSE 1 ENDIF", "P2SH,STRICTENC", "opcodes above NOP10 invalid if executed"], +["1", "IF 0xbb ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xbc ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xbd ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xbe ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xbf ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xc0 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xc1 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xc2 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xc3 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xc4 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xc5 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xc6 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xc7 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xc8 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xc9 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xca ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xcb ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xcc ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xcd ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xce ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xcf ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xd0 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xd1 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xd2 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xd3 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xd4 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xd5 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xd6 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xd7 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xd8 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xd9 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xda ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xdb ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xdc ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xdd ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xde ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xdf ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xe0 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xe1 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xe2 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xe3 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xe4 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xe5 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xe6 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xe7 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xe8 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xe9 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xea ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xeb ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xec ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xed ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xee ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xef ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xf0 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xf1 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xf2 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xf3 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xf4 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xf5 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xf6 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xf7 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xf8 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xf9 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xfa ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xfb ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xfc ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xfd ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xfe ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 0xff ELSE 1 ENDIF", "P2SH,STRICTENC"], + +["1 IF 1 ELSE", "0xff ENDIF", "P2SH,STRICTENC", "invalid because scriptSig and scriptPubKey are processed separately"], + +["NOP", "RIPEMD160", "P2SH,STRICTENC"], +["NOP", "SHA1", "P2SH,STRICTENC"], +["NOP", "SHA256", "P2SH,STRICTENC"], +["NOP", "HASH160", "P2SH,STRICTENC"], +["NOP", "HASH256", "P2SH,STRICTENC"], + +["NOP", +"'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'", +"P2SH,STRICTENC", +">520 byte push"], +["0", +"IF 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' ENDIF 1", +"P2SH,STRICTENC", +">520 byte push in non-executed IF branch"], +["1", +"0x61616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161", +"P2SH,STRICTENC", +">201 opcodes executed. 0x61 is NOP"], +["0", +"IF 0x6161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161 ENDIF 1", +"P2SH,STRICTENC", +">201 opcodes including non-executed IF branch. 0x61 is NOP"], +["1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", +"1 2 3 4 5 6 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", +"P2SH,STRICTENC", +">1,000 stack size (0x6f is 3DUP)"], +["1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", +"1 TOALTSTACK 2 TOALTSTACK 3 4 5 6 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", +"P2SH,STRICTENC", +">1,000 stack+altstack size"], +["NOP", +"0 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f 2DUP 0x616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161", +"P2SH,STRICTENC", +"10,001-byte scriptPubKey"], + +["NOP1","NOP10", "P2SH,STRICTENC"], + +["1","VER", "P2SH,STRICTENC", "OP_VER is reserved"], +["1","VERIF", "P2SH,STRICTENC", "OP_VERIF is reserved"], +["1","VERNOTIF", "P2SH,STRICTENC", "OP_VERNOTIF is reserved"], +["1","RESERVED", "P2SH,STRICTENC", "OP_RESERVED is reserved"], +["1","RESERVED1", "P2SH,STRICTENC", "OP_RESERVED1 is reserved"], +["1","RESERVED2", "P2SH,STRICTENC", "OP_RESERVED2 is reserved"], +["1","0xba", "P2SH,STRICTENC", "0xba == OP_NOP10 + 1"], + +["2147483648", "1ADD 1", "P2SH,STRICTENC", "We cannot do math on 5-byte integers"], +["2147483648", "NEGATE 1", "P2SH,STRICTENC", "We cannot do math on 5-byte integers"], +["-2147483648", "1ADD 1", "P2SH,STRICTENC", "Because we use a sign bit, -2147483648 is also 5 bytes"], +["2147483647", "1ADD 1SUB 1", "P2SH,STRICTENC", "We cannot do math on 5-byte integers, even if the result is 4-bytes"], +["2147483648", "1SUB 1", "P2SH,STRICTENC", "We cannot do math on 5-byte integers, even if the result is 4-bytes"], + +["2147483648 1", "BOOLOR 1", "P2SH,STRICTENC", "We cannot do BOOLOR on 5-byte integers (but we can still do IF etc)"], +["2147483648 1", "BOOLAND 1", "P2SH,STRICTENC", "We cannot do BOOLAND on 5-byte integers"], + +["1", "1 ENDIF", "P2SH,STRICTENC", "ENDIF without IF"], +["1", "IF 1", "P2SH,STRICTENC", "IF without ENDIF"], +["1 IF 1", "ENDIF", "P2SH,STRICTENC", "IFs don't carry over"], + +["NOP", "IF 1 ENDIF", "P2SH,STRICTENC", "The following tests check the if(stack.size() < N) tests in each opcode"], +["NOP", "NOTIF 1 ENDIF", "P2SH,STRICTENC", "They are here to catch copy-and-paste errors"], +["NOP", "VERIFY 1", "P2SH,STRICTENC", "Most of them are duplicated elsewhere,"], + +["NOP", "TOALTSTACK 1", "P2SH,STRICTENC", "but, hey, more is always better, right?"], +["1", "FROMALTSTACK", "P2SH,STRICTENC"], +["1", "2DROP 1", "P2SH,STRICTENC"], +["1", "2DUP", "P2SH,STRICTENC"], +["1 1", "3DUP", "P2SH,STRICTENC"], +["1 1 1", "2OVER", "P2SH,STRICTENC"], +["1 1 1 1 1", "2ROT", "P2SH,STRICTENC"], +["1 1 1", "2SWAP", "P2SH,STRICTENC"], +["NOP", "IFDUP 1", "P2SH,STRICTENC"], +["NOP", "DROP 1", "P2SH,STRICTENC"], +["NOP", "DUP 1", "P2SH,STRICTENC"], +["1", "NIP", "P2SH,STRICTENC"], +["1", "OVER", "P2SH,STRICTENC"], +["1 1 1 3", "PICK", "P2SH,STRICTENC"], +["0", "PICK 1", "P2SH,STRICTENC"], +["1 1 1 3", "ROLL", "P2SH,STRICTENC"], +["0", "ROLL 1", "P2SH,STRICTENC"], +["1 1", "ROT", "P2SH,STRICTENC"], +["1", "SWAP", "P2SH,STRICTENC"], +["1", "TUCK", "P2SH,STRICTENC"], + +["NOP", "SIZE 1", "P2SH,STRICTENC"], + +["1", "EQUAL 1", "P2SH,STRICTENC"], +["1", "EQUALVERIFY 1", "P2SH,STRICTENC"], + +["NOP", "1ADD 1", "P2SH,STRICTENC"], +["NOP", "1SUB 1", "P2SH,STRICTENC"], +["NOP", "NEGATE 1", "P2SH,STRICTENC"], +["NOP", "ABS 1", "P2SH,STRICTENC"], +["NOP", "NOT 1", "P2SH,STRICTENC"], +["NOP", "0NOTEQUAL 1", "P2SH,STRICTENC"], + +["1", "ADD", "P2SH,STRICTENC"], +["1", "SUB", "P2SH,STRICTENC"], +["1", "BOOLAND", "P2SH,STRICTENC"], +["1", "BOOLOR", "P2SH,STRICTENC"], +["1", "NUMEQUAL", "P2SH,STRICTENC"], +["1", "NUMEQUALVERIFY 1", "P2SH,STRICTENC"], +["1", "NUMNOTEQUAL", "P2SH,STRICTENC"], +["1", "LESSTHAN", "P2SH,STRICTENC"], +["1", "GREATERTHAN", "P2SH,STRICTENC"], +["1", "LESSTHANOREQUAL", "P2SH,STRICTENC"], +["1", "GREATERTHANOREQUAL", "P2SH,STRICTENC"], +["1", "MIN", "P2SH,STRICTENC"], +["1", "MAX", "P2SH,STRICTENC"], +["1 1", "WITHIN", "P2SH,STRICTENC"], + +["NOP", "RIPEMD160 1", "P2SH,STRICTENC"], +["NOP", "SHA1 1", "P2SH,STRICTENC"], +["NOP", "SHA256 1", "P2SH,STRICTENC"], +["NOP", "HASH160 1", "P2SH,STRICTENC"], +["NOP", "HASH256 1", "P2SH,STRICTENC"], + +["", +"0 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG", +"P2SH,STRICTENC", +"202 CHECKMULTISIGS, fails due to 201 op limit"], + +["1", +"0 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY", +"P2SH,STRICTENC"], + +["", +"NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG", +"P2SH,STRICTENC", +"Fails due to 201 sig op limit"], + +["1", +"NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY", +"P2SH,STRICTENC"], + + +["0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21", "21 CHECKMULTISIG 1", "P2SH,STRICTENC", "nPubKeys > 20"], +["0 'sig' 1 0", "CHECKMULTISIG 1", "P2SH,STRICTENC", "nSigs > nPubKeys"], + + +["NOP 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL", "P2SH,STRICTENC", "Tests for Script.IsPushOnly()"], +["NOP1 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL", "P2SH,STRICTENC"], + +["0 0x01 0x50", "HASH160 0x14 0xece424a6bb6ddf4db592c0faed60685047a361b1 EQUAL", "P2SH,STRICTENC", "OP_RESERVED in P2SH should fail"], +["0 0x01 VER", "HASH160 0x14 0x0f4d7845db968f2a81b530b6f3c1d6246d4c7e01 EQUAL", "P2SH,STRICTENC", "OP_VER in P2SH should fail"], + +["0x00", "'00' EQUAL", "P2SH,STRICTENC", "Basic OP_0 execution"], + +[ + "0 0x47 0x3044022035341cc377b19138f944f90c45772cb06338c6d56a4c0c31a65bf1a8a105fadc022046dd232850b6bacb25879c9da82a7a628982aa19d055f1753468f68047662e0301 DUP", + "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG", + "SIGPUSHONLY", + "2-of-2 with two identical keys and sigs pushed using OP_DUP" +], +[ + "0x47 0x304402204d8b99eea2f53382fd67e0dbc8ed0596bd614aa0dad6bc6843c7860c79b901c3022062f022a71993013e3d9b22302a8e4b40109d7bb057aeb250b9aab2197b3e96b801 0x23 0x2103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640ac", + "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG", + "", + "P2SH(P2PK) with non-push scriptSig but no SIGPUSHONLY" +], +[ + "0x47 0x30440220078c887c33abc67fbbd827ceb3f661c1c459e78218161b652f23e3ca76cfabbd022047df245eacb8a88d8c5ca7b5228e3b4d070c102d2f542433362d3f443cd24eda01 0x23 0x2103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640ac", + "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG", + "SIGPUSHONLY", + "P2SH(P2PK) with non-push scriptSig" +] + +] diff --git a/txscript/data/script_valid.json b/txscript/data/script_valid.json new file mode 100644 index 000000000..db62b9267 --- /dev/null +++ b/txscript/data/script_valid.json @@ -0,0 +1,540 @@ +[ +["", "DEPTH 0 EQUAL", "P2SH,STRICTENC", "Test the test: we should have an empty stack after scriptSig evaluation"], +[" ", "DEPTH 0 EQUAL", "P2SH,STRICTENC", "and multiple spaces should not change that."], +[" ", "DEPTH 0 EQUAL", "P2SH,STRICTENC"], +[" ", "DEPTH 0 EQUAL", "P2SH,STRICTENC"], +["1 2", "2 EQUALVERIFY 1 EQUAL", "P2SH,STRICTENC", "Similarly whitespace around and between symbols"], +["1 2", "2 EQUALVERIFY 1 EQUAL", "P2SH,STRICTENC"], +[" 1 2", "2 EQUALVERIFY 1 EQUAL", "P2SH,STRICTENC"], +["1 2 ", "2 EQUALVERIFY 1 EQUAL", "P2SH,STRICTENC"], +[" 1 2 ", "2 EQUALVERIFY 1 EQUAL", "P2SH,STRICTENC"], + +["1", "", "P2SH,STRICTENC"], +["0x02 0x01 0x00", "", "P2SH,STRICTENC", "all bytes are significant, not only the last one"], +["0x09 0x00000000 0x00000000 0x10", "", "P2SH,STRICTENC", "equals zero when cast to Int64"], + +["0x01 0x0b", "11 EQUAL", "P2SH,STRICTENC", "push 1 byte"], +["0x02 0x417a", "'Az' EQUAL", "P2SH,STRICTENC"], +["0x4b 0x417a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a", + "'Azzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz' EQUAL", "P2SH,STRICTENC", "push 75 bytes"], + +["0x4c 0x01 0x07","7 EQUAL", "P2SH,STRICTENC", "0x4c is OP_PUSHDATA1"], +["0x4d 0x0100 0x08","8 EQUAL", "P2SH,STRICTENC", "0x4d is OP_PUSHDATA2"], +["0x4e 0x01000000 0x09","9 EQUAL", "P2SH,STRICTENC", "0x4e is OP_PUSHDATA4"], + +["0x4c 0x00","0 EQUAL", "P2SH,STRICTENC"], +["0x4d 0x0000","0 EQUAL", "P2SH,STRICTENC"], +["0x4e 0x00000000","0 EQUAL", "P2SH,STRICTENC"], +["0x4f 1000 ADD","999 EQUAL", "P2SH,STRICTENC"], +["0", "IF 0x50 ENDIF 1", "P2SH,STRICTENC", "0x50 is reserved (ok if not executed)"], +["0x51", "0x5f ADD 0x60 EQUAL", "P2SH,STRICTENC", "0x51 through 0x60 push 1 through 16 onto stack"], +["1","NOP", "P2SH,STRICTENC"], +["0", "IF VER ELSE 1 ENDIF", "P2SH,STRICTENC", "VER non-functional (ok if not executed)"], +["0", "IF RESERVED RESERVED1 RESERVED2 ELSE 1 ENDIF", "P2SH,STRICTENC", "RESERVED ok in un-executed IF"], + +["1", "DUP IF ENDIF", "P2SH,STRICTENC"], +["1", "IF 1 ENDIF", "P2SH,STRICTENC"], +["1", "DUP IF ELSE ENDIF", "P2SH,STRICTENC"], +["1", "IF 1 ELSE ENDIF", "P2SH,STRICTENC"], +["0", "IF ELSE 1 ENDIF", "P2SH,STRICTENC"], + +["1 1", "IF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC"], +["1 0", "IF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC"], +["1 1", "IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC"], +["0 0", "IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC"], + +["1 0", "NOTIF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC"], +["1 1", "NOTIF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC"], +["1 0", "NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC"], +["0 1", "NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC"], + +["0", "IF 0 ELSE 1 ELSE 0 ENDIF", "P2SH,STRICTENC", "Multiple ELSE's are valid and executed inverts on each ELSE encountered"], +["1", "IF 1 ELSE 0 ELSE ENDIF", "P2SH,STRICTENC"], +["1", "IF ELSE 0 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["1", "IF 1 ELSE 0 ELSE 1 ENDIF ADD 2 EQUAL", "P2SH,STRICTENC"], +["'' 1", "IF SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ENDIF 0x14 0x68ca4fec736264c13b859bac43d5173df6871682 EQUAL", "P2SH,STRICTENC"], + +["1", "NOTIF 0 ELSE 1 ELSE 0 ENDIF", "P2SH,STRICTENC", "Multiple ELSE's are valid and execution inverts on each ELSE encountered"], +["0", "NOTIF 1 ELSE 0 ELSE ENDIF", "P2SH,STRICTENC"], +["0", "NOTIF ELSE 0 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "NOTIF 1 ELSE 0 ELSE 1 ENDIF ADD 2 EQUAL", "P2SH,STRICTENC"], +["'' 0", "NOTIF SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ENDIF 0x14 0x68ca4fec736264c13b859bac43d5173df6871682 EQUAL", "P2SH,STRICTENC"], + +["0", "IF 1 IF RETURN ELSE RETURN ELSE RETURN ENDIF ELSE 1 IF 1 ELSE RETURN ELSE 1 ENDIF ELSE RETURN ENDIF ADD 2 EQUAL", "P2SH,STRICTENC", "Nested ELSE ELSE"], +["1", "NOTIF 0 NOTIF RETURN ELSE RETURN ELSE RETURN ENDIF ELSE 0 NOTIF 1 ELSE RETURN ELSE 1 ENDIF ELSE RETURN ENDIF ADD 2 EQUAL", "P2SH,STRICTENC"], + +["0", "IF RETURN ENDIF 1", "P2SH,STRICTENC", "RETURN only works if executed"], + +["1 1", "VERIFY", "P2SH,STRICTENC"], +["1 0x05 0x01 0x00 0x00 0x00 0x00", "VERIFY", "P2SH,STRICTENC", "values >4 bytes can be cast to boolean"], + +["10 0 11 TOALTSTACK DROP FROMALTSTACK", "ADD 21 EQUAL", "P2SH,STRICTENC"], +["'gavin_was_here' TOALTSTACK 11 FROMALTSTACK", "'gavin_was_here' EQUALVERIFY 11 EQUAL", "P2SH,STRICTENC"], + +["0 IFDUP", "DEPTH 1 EQUALVERIFY 0 EQUAL", "P2SH,STRICTENC"], +["1 IFDUP", "DEPTH 2 EQUALVERIFY 1 EQUALVERIFY 1 EQUAL", "P2SH,STRICTENC"], +["0 DROP", "DEPTH 0 EQUAL", "P2SH,STRICTENC"], +["0", "DUP 1 ADD 1 EQUALVERIFY 0 EQUAL", "P2SH,STRICTENC"], +["0 1", "NIP", "P2SH,STRICTENC"], +["1 0", "OVER DEPTH 3 EQUALVERIFY", "P2SH,STRICTENC"], +["22 21 20", "0 PICK 20 EQUALVERIFY DEPTH 3 EQUAL", "P2SH,STRICTENC"], +["22 21 20", "1 PICK 21 EQUALVERIFY DEPTH 3 EQUAL", "P2SH,STRICTENC"], +["22 21 20", "2 PICK 22 EQUALVERIFY DEPTH 3 EQUAL", "P2SH,STRICTENC"], +["22 21 20", "0 ROLL 20 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC"], +["22 21 20", "1 ROLL 21 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC"], +["22 21 20", "2 ROLL 22 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC"], +["22 21 20", "ROT 22 EQUAL", "P2SH,STRICTENC"], +["22 21 20", "ROT DROP 20 EQUAL", "P2SH,STRICTENC"], +["22 21 20", "ROT DROP DROP 21 EQUAL", "P2SH,STRICTENC"], +["22 21 20", "ROT ROT 21 EQUAL", "P2SH,STRICTENC"], +["22 21 20", "ROT ROT ROT 20 EQUAL", "P2SH,STRICTENC"], +["25 24 23 22 21 20", "2ROT 24 EQUAL", "P2SH,STRICTENC"], +["25 24 23 22 21 20", "2ROT DROP 25 EQUAL", "P2SH,STRICTENC"], +["25 24 23 22 21 20", "2ROT 2DROP 20 EQUAL", "P2SH,STRICTENC"], +["25 24 23 22 21 20", "2ROT 2DROP DROP 21 EQUAL", "P2SH,STRICTENC"], +["25 24 23 22 21 20", "2ROT 2DROP 2DROP 22 EQUAL", "P2SH,STRICTENC"], +["25 24 23 22 21 20", "2ROT 2DROP 2DROP DROP 23 EQUAL", "P2SH,STRICTENC"], +["25 24 23 22 21 20", "2ROT 2ROT 22 EQUAL", "P2SH,STRICTENC"], +["25 24 23 22 21 20", "2ROT 2ROT 2ROT 20 EQUAL", "P2SH,STRICTENC"], +["1 0", "SWAP 1 EQUALVERIFY 0 EQUAL", "P2SH,STRICTENC"], +["0 1", "TUCK DEPTH 3 EQUALVERIFY SWAP 2DROP", "P2SH,STRICTENC"], +["13 14", "2DUP ROT EQUALVERIFY EQUAL", "P2SH,STRICTENC"], +["-1 0 1 2", "3DUP DEPTH 7 EQUALVERIFY ADD ADD 3 EQUALVERIFY 2DROP 0 EQUALVERIFY", "P2SH,STRICTENC"], +["1 2 3 5", "2OVER ADD ADD 8 EQUALVERIFY ADD ADD 6 EQUAL", "P2SH,STRICTENC"], +["1 3 5 7", "2SWAP ADD 4 EQUALVERIFY ADD 12 EQUAL", "P2SH,STRICTENC"], +["0", "SIZE 0 EQUAL", "P2SH,STRICTENC"], +["1", "SIZE 1 EQUAL", "P2SH,STRICTENC"], +["127", "SIZE 1 EQUAL", "P2SH,STRICTENC"], +["128", "SIZE 2 EQUAL", "P2SH,STRICTENC"], +["32767", "SIZE 2 EQUAL", "P2SH,STRICTENC"], +["32768", "SIZE 3 EQUAL", "P2SH,STRICTENC"], +["8388607", "SIZE 3 EQUAL", "P2SH,STRICTENC"], +["8388608", "SIZE 4 EQUAL", "P2SH,STRICTENC"], +["2147483647", "SIZE 4 EQUAL", "P2SH,STRICTENC"], +["2147483648", "SIZE 5 EQUAL", "P2SH,STRICTENC"], +["549755813887", "SIZE 5 EQUAL", "P2SH,STRICTENC"], +["549755813888", "SIZE 6 EQUAL", "P2SH,STRICTENC"], +["9223372036854775807", "SIZE 8 EQUAL", "P2SH,STRICTENC"], +["-1", "SIZE 1 EQUAL", "P2SH,STRICTENC"], +["-127", "SIZE 1 EQUAL", "P2SH,STRICTENC"], +["-128", "SIZE 2 EQUAL", "P2SH,STRICTENC"], +["-32767", "SIZE 2 EQUAL", "P2SH,STRICTENC"], +["-32768", "SIZE 3 EQUAL", "P2SH,STRICTENC"], +["-8388607", "SIZE 3 EQUAL", "P2SH,STRICTENC"], +["-8388608", "SIZE 4 EQUAL", "P2SH,STRICTENC"], +["-2147483647", "SIZE 4 EQUAL", "P2SH,STRICTENC"], +["-2147483648", "SIZE 5 EQUAL", "P2SH,STRICTENC"], +["-549755813887", "SIZE 5 EQUAL", "P2SH,STRICTENC"], +["-549755813888", "SIZE 6 EQUAL", "P2SH,STRICTENC"], +["-9223372036854775807", "SIZE 8 EQUAL", "P2SH,STRICTENC"], +["'abcdefghijklmnopqrstuvwxyz'", "SIZE 26 EQUAL", "P2SH,STRICTENC"], + +["42", "SIZE 1 EQUALVERIFY 42 EQUAL", "P2SH,STRICTENC", "SIZE does not consume argument"], + +["2 -2 ADD", "0 EQUAL", "P2SH,STRICTENC"], +["2147483647 -2147483647 ADD", "0 EQUAL", "P2SH,STRICTENC"], +["-1 -1 ADD", "-2 EQUAL", "P2SH,STRICTENC"], + +["0 0","EQUAL", "P2SH,STRICTENC"], +["1 1 ADD", "2 EQUAL", "P2SH,STRICTENC"], +["1 1ADD", "2 EQUAL", "P2SH,STRICTENC"], +["111 1SUB", "110 EQUAL", "P2SH,STRICTENC"], +["111 1 ADD 12 SUB", "100 EQUAL", "P2SH,STRICTENC"], +["0 ABS", "0 EQUAL", "P2SH,STRICTENC"], +["16 ABS", "16 EQUAL", "P2SH,STRICTENC"], +["-16 ABS", "-16 NEGATE EQUAL", "P2SH,STRICTENC"], +["0 NOT", "NOP", "P2SH,STRICTENC"], +["1 NOT", "0 EQUAL", "P2SH,STRICTENC"], +["11 NOT", "0 EQUAL", "P2SH,STRICTENC"], +["0 0NOTEQUAL", "0 EQUAL", "P2SH,STRICTENC"], +["1 0NOTEQUAL", "1 EQUAL", "P2SH,STRICTENC"], +["111 0NOTEQUAL", "1 EQUAL", "P2SH,STRICTENC"], +["-111 0NOTEQUAL", "1 EQUAL", "P2SH,STRICTENC"], +["1 1 BOOLAND", "NOP", "P2SH,STRICTENC"], +["1 0 BOOLAND", "NOT", "P2SH,STRICTENC"], +["0 1 BOOLAND", "NOT", "P2SH,STRICTENC"], +["0 0 BOOLAND", "NOT", "P2SH,STRICTENC"], +["16 17 BOOLAND", "NOP", "P2SH,STRICTENC"], +["1 1 BOOLOR", "NOP", "P2SH,STRICTENC"], +["1 0 BOOLOR", "NOP", "P2SH,STRICTENC"], +["0 1 BOOLOR", "NOP", "P2SH,STRICTENC"], +["0 0 BOOLOR", "NOT", "P2SH,STRICTENC"], +["16 17 BOOLOR", "NOP", "P2SH,STRICTENC"], +["11 10 1 ADD", "NUMEQUAL", "P2SH,STRICTENC"], +["11 10 1 ADD", "NUMEQUALVERIFY 1", "P2SH,STRICTENC"], +["11 10 1 ADD", "NUMNOTEQUAL NOT", "P2SH,STRICTENC"], +["111 10 1 ADD", "NUMNOTEQUAL", "P2SH,STRICTENC"], +["11 10", "LESSTHAN NOT", "P2SH,STRICTENC"], +["4 4", "LESSTHAN NOT", "P2SH,STRICTENC"], +["10 11", "LESSTHAN", "P2SH,STRICTENC"], +["-11 11", "LESSTHAN", "P2SH,STRICTENC"], +["-11 -10", "LESSTHAN", "P2SH,STRICTENC"], +["11 10", "GREATERTHAN", "P2SH,STRICTENC"], +["4 4", "GREATERTHAN NOT", "P2SH,STRICTENC"], +["10 11", "GREATERTHAN NOT", "P2SH,STRICTENC"], +["-11 11", "GREATERTHAN NOT", "P2SH,STRICTENC"], +["-11 -10", "GREATERTHAN NOT", "P2SH,STRICTENC"], +["11 10", "LESSTHANOREQUAL NOT", "P2SH,STRICTENC"], +["4 4", "LESSTHANOREQUAL", "P2SH,STRICTENC"], +["10 11", "LESSTHANOREQUAL", "P2SH,STRICTENC"], +["-11 11", "LESSTHANOREQUAL", "P2SH,STRICTENC"], +["-11 -10", "LESSTHANOREQUAL", "P2SH,STRICTENC"], +["11 10", "GREATERTHANOREQUAL", "P2SH,STRICTENC"], +["4 4", "GREATERTHANOREQUAL", "P2SH,STRICTENC"], +["10 11", "GREATERTHANOREQUAL NOT", "P2SH,STRICTENC"], +["-11 11", "GREATERTHANOREQUAL NOT", "P2SH,STRICTENC"], +["-11 -10", "GREATERTHANOREQUAL NOT", "P2SH,STRICTENC"], +["1 0 MIN", "0 NUMEQUAL", "P2SH,STRICTENC"], +["0 1 MIN", "0 NUMEQUAL", "P2SH,STRICTENC"], +["-1 0 MIN", "-1 NUMEQUAL", "P2SH,STRICTENC"], +["0 -2147483647 MIN", "-2147483647 NUMEQUAL", "P2SH,STRICTENC"], +["2147483647 0 MAX", "2147483647 NUMEQUAL", "P2SH,STRICTENC"], +["0 100 MAX", "100 NUMEQUAL", "P2SH,STRICTENC"], +["-100 0 MAX", "0 NUMEQUAL", "P2SH,STRICTENC"], +["0 -2147483647 MAX", "0 NUMEQUAL", "P2SH,STRICTENC"], +["0 0 1", "WITHIN", "P2SH,STRICTENC"], +["1 0 1", "WITHIN NOT", "P2SH,STRICTENC"], +["0 -2147483647 2147483647", "WITHIN", "P2SH,STRICTENC"], +["-1 -100 100", "WITHIN", "P2SH,STRICTENC"], +["11 -100 100", "WITHIN", "P2SH,STRICTENC"], +["-2147483647 -100 100", "WITHIN NOT", "P2SH,STRICTENC"], +["2147483647 -100 100", "WITHIN NOT", "P2SH,STRICTENC"], + +["2147483647 2147483647 SUB", "0 EQUAL", "P2SH,STRICTENC"], +["2147483647 DUP ADD", "4294967294 EQUAL", "P2SH,STRICTENC", ">32 bit EQUAL is valid"], +["2147483647 NEGATE DUP ADD", "-4294967294 EQUAL", "P2SH,STRICTENC"], + +["''", "RIPEMD160 0x14 0x9c1185a5c5e9fc54612808977ee8f548b2258d31 EQUAL", "P2SH,STRICTENC"], +["'a'", "RIPEMD160 0x14 0x0bdc9d2d256b3ee9daae347be6f4dc835a467ffe EQUAL", "P2SH,STRICTENC"], +["'abcdefghijklmnopqrstuvwxyz'", "RIPEMD160 0x14 0xf71c27109c692c1b56bbdceb5b9d2865b3708dbc EQUAL", "P2SH,STRICTENC"], +["''", "SHA1 0x14 0xda39a3ee5e6b4b0d3255bfef95601890afd80709 EQUAL", "P2SH,STRICTENC"], +["'a'", "SHA1 0x14 0x86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 EQUAL", "P2SH,STRICTENC"], +["'abcdefghijklmnopqrstuvwxyz'", "SHA1 0x14 0x32d10c7b8cf96570ca04ce37f2a19d84240d3a89 EQUAL", "P2SH,STRICTENC"], +["''", "SHA256 0x20 0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 EQUAL", "P2SH,STRICTENC"], +["'a'", "SHA256 0x20 0xca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb EQUAL", "P2SH,STRICTENC"], +["'abcdefghijklmnopqrstuvwxyz'", "SHA256 0x20 0x71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73 EQUAL", "P2SH,STRICTENC"], +["''", "DUP HASH160 SWAP SHA256 RIPEMD160 EQUAL", "P2SH,STRICTENC"], +["''", "DUP HASH256 SWAP SHA256 SHA256 EQUAL", "P2SH,STRICTENC"], +["''", "NOP HASH160 0x14 0xb472a266d0bd89c13706a4132ccfb16f7c3b9fcb EQUAL", "P2SH,STRICTENC"], +["'a'", "HASH160 NOP 0x14 0x994355199e516ff76c4fa4aab39337b9d84cf12b EQUAL", "P2SH,STRICTENC"], +["'abcdefghijklmnopqrstuvwxyz'", "HASH160 0x4c 0x14 0xc286a1af0947f58d1ad787385b1c2c4a976f9e71 EQUAL", "P2SH,STRICTENC"], +["''", "HASH256 0x20 0x5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456 EQUAL", "P2SH,STRICTENC"], +["'a'", "HASH256 0x20 0xbf5d3affb73efd2ec6c36ad3112dd933efed63c4e1cbffcfa88e2759c144f2d8 EQUAL", "P2SH,STRICTENC"], +["'abcdefghijklmnopqrstuvwxyz'", "HASH256 0x4c 0x20 0xca139bc10c2f660da42666f72e89a225936fc60f193c161124a672050c434671 EQUAL", "P2SH,STRICTENC"], + + +["1","NOP1 NOP2 NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 1 EQUAL", "P2SH,STRICTENC"], +["'NOP_1_to_10' NOP1 NOP2 NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10","'NOP_1_to_10' EQUAL", "P2SH,STRICTENC"], + +["1", "NOP", "P2SH,STRICTENC,DISCOURAGE_UPGRADABLE_NOPS", "Discourage NOPx flag allows OP_NOP"], + +["0", "IF NOP10 ENDIF 1", "P2SH,STRICTENC,DISCOURAGE_UPGRADABLE_NOPS", "Discouraged NOPs are allowed if not executed"], + +["0", "IF 0xba ELSE 1 ENDIF", "P2SH,STRICTENC", "opcodes above NOP10 invalid if executed"], +["0", "IF 0xbb ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xbc ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xbd ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xbe ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xbf ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xc0 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xc1 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xc2 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xc3 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xc4 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xc5 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xc6 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xc7 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xc8 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xc9 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xca ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xcb ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xcc ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xcd ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xce ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xcf ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xd0 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xd1 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xd2 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xd3 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xd4 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xd5 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xd6 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xd7 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xd8 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xd9 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xda ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xdb ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xdc ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xdd ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xde ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xdf ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xe0 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xe1 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xe2 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xe3 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xe4 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xe5 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xe6 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xe7 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xe8 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xe9 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xea ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xeb ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xec ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xed ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xee ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xef ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xf0 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xf1 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xf2 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xf3 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xf4 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xf5 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xf6 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xf7 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xf8 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xf9 ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xfa ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xfb ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xfc ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xfd ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xfe ELSE 1 ENDIF", "P2SH,STRICTENC"], +["0", "IF 0xff ELSE 1 ENDIF", "P2SH,STRICTENC"], + +["NOP", +"'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'", +"P2SH,STRICTENC", +"520 byte push"], +["1", +"0x616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161", +"P2SH,STRICTENC", +"201 opcodes executed. 0x61 is NOP"], +["1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", +"1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", +"P2SH,STRICTENC", +"1,000 stack size (0x6f is 3DUP)"], +["1 TOALTSTACK 2 TOALTSTACK 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", +"1 2 3 4 5 6 7 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", +"P2SH,STRICTENC", +"1,000 stack size (altstack cleared between scriptSig/scriptPubKey)"], +["'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", +"'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f 2DUP 0x616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161", +"P2SH,STRICTENC", +"Max-size (10,000-byte), max-push(520 bytes), max-opcodes(201), max stack size(1,000 items). 0x6f is 3DUP, 0x61 is NOP"], + +["0", +"IF 0x5050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050 ENDIF 1", +"P2SH,STRICTENC", +">201 opcodes, but RESERVED (0x50) doesn't count towards opcode limit."], + +["NOP","1", "P2SH,STRICTENC"], + +["1", "0x01 0x01 EQUAL", "P2SH,STRICTENC", "The following is useful for checking implementations of BN_bn2mpi"], +["127", "0x01 0x7F EQUAL", "P2SH,STRICTENC"], +["128", "0x02 0x8000 EQUAL", "P2SH,STRICTENC", "Leave room for the sign bit"], +["32767", "0x02 0xFF7F EQUAL", "P2SH,STRICTENC"], +["32768", "0x03 0x008000 EQUAL", "P2SH,STRICTENC"], +["8388607", "0x03 0xFFFF7F EQUAL", "P2SH,STRICTENC"], +["8388608", "0x04 0x00008000 EQUAL", "P2SH,STRICTENC"], +["2147483647", "0x04 0xFFFFFF7F EQUAL", "P2SH,STRICTENC"], +["2147483648", "0x05 0x0000008000 EQUAL", "P2SH,STRICTENC"], +["549755813887", "0x05 0xFFFFFFFF7F EQUAL", "P2SH,STRICTENC"], +["549755813888", "0x06 0xFFFFFFFF7F EQUAL", "P2SH,STRICTENC"], +["9223372036854775807", "0x08 0xFFFFFFFFFFFFFF7F EQUAL", "P2SH,STRICTENC"], +["-1", "0x01 0x81 EQUAL", "P2SH,STRICTENC", "Numbers are little-endian with the MSB being a sign bit"], +["-127", "0x01 0xFF EQUAL", "P2SH,STRICTENC"], +["-128", "0x02 0x8080 EQUAL", "P2SH,STRICTENC"], +["-32767", "0x02 0xFFFF EQUAL", "P2SH,STRICTENC"], +["-32768", "0x03 0x008080 EQUAL", "P2SH,STRICTENC"], +["-8388607", "0x03 0xFFFFFF EQUAL", "P2SH,STRICTENC"], +["-8388608", "0x04 0x00008080 EQUAL", "P2SH,STRICTENC"], +["-2147483647", "0x04 0xFFFFFFFF EQUAL", "P2SH,STRICTENC"], +["-2147483648", "0x05 0x0000008080 EQUAL", "P2SH,STRICTENC"], +["-4294967295", "0x05 0xFFFFFFFF80 EQUAL", "P2SH,STRICTENC"], +["-549755813887", "0x05 0xFFFFFFFFFF EQUAL", "P2SH,STRICTENC"], +["-549755813888", "0x06 0x000000008080 EQUAL", "P2SH,STRICTENC"], +["-9223372036854775807", "0x08 0xFFFFFFFFFFFFFFFF EQUAL", "P2SH,STRICTENC"], + +["2147483647", "1ADD 2147483648 EQUAL", "P2SH,STRICTENC", "We can do math on 4-byte integers, and compare 5-byte ones"], +["2147483647", "1ADD 1", "P2SH,STRICTENC"], +["-2147483647", "1ADD 1", "P2SH,STRICTENC"], + +["1", "0x02 0x0100 EQUAL NOT", "P2SH,STRICTENC", "Not the same byte array..."], +["1", "0x02 0x0100 NUMEQUAL", "P2SH,STRICTENC", "... but they are numerically equal"], +["11", "0x4c 0x03 0x0b0000 NUMEQUAL", "P2SH,STRICTENC"], +["0", "0x01 0x80 EQUAL NOT", "P2SH,STRICTENC"], +["0", "0x01 0x80 NUMEQUAL", "P2SH,STRICTENC", "Zero numerically equals negative zero"], +["0", "0x02 0x0080 NUMEQUAL", "P2SH,STRICTENC"], +["0x03 0x000080", "0x04 0x00000080 NUMEQUAL", "P2SH,STRICTENC"], +["0x03 0x100080", "0x04 0x10000080 NUMEQUAL", "P2SH,STRICTENC"], +["0x03 0x100000", "0x04 0x10000000 NUMEQUAL", "P2SH,STRICTENC"], + +["NOP", "NOP 1", "P2SH,STRICTENC", "The following tests check the if(stack.size() < N) tests in each opcode"], +["1", "IF 1 ENDIF", "P2SH,STRICTENC", "They are here to catch copy-and-paste errors"], +["0", "NOTIF 1 ENDIF", "P2SH,STRICTENC", "Most of them are duplicated elsewhere,"], +["1", "VERIFY 1", "P2SH,STRICTENC", "but, hey, more is always better, right?"], + +["0", "TOALTSTACK 1", "P2SH,STRICTENC"], +["1", "TOALTSTACK FROMALTSTACK", "P2SH,STRICTENC"], +["0 0", "2DROP 1", "P2SH,STRICTENC"], +["0 1", "2DUP", "P2SH,STRICTENC"], +["0 0 1", "3DUP", "P2SH,STRICTENC"], +["0 1 0 0", "2OVER", "P2SH,STRICTENC"], +["0 1 0 0 0 0", "2ROT", "P2SH,STRICTENC"], +["0 1 0 0", "2SWAP", "P2SH,STRICTENC"], +["1", "IFDUP", "P2SH,STRICTENC"], +["NOP", "DEPTH 1", "P2SH,STRICTENC"], +["0", "DROP 1", "P2SH,STRICTENC"], +["1", "DUP", "P2SH,STRICTENC"], +["0 1", "NIP", "P2SH,STRICTENC"], +["1 0", "OVER", "P2SH,STRICTENC"], +["1 0 0 0 3", "PICK", "P2SH,STRICTENC"], +["1 0", "PICK", "P2SH,STRICTENC"], +["1 0 0 0 3", "ROLL", "P2SH,STRICTENC"], +["1 0", "ROLL", "P2SH,STRICTENC"], +["1 0 0", "ROT", "P2SH,STRICTENC"], +["1 0", "SWAP", "P2SH,STRICTENC"], +["0 1", "TUCK", "P2SH,STRICTENC"], + +["1", "SIZE", "P2SH,STRICTENC"], + +["0 0", "EQUAL", "P2SH,STRICTENC"], +["0 0", "EQUALVERIFY 1", "P2SH,STRICTENC"], + +["0", "1ADD", "P2SH,STRICTENC"], +["2", "1SUB", "P2SH,STRICTENC"], +["-1", "NEGATE", "P2SH,STRICTENC"], +["-1", "ABS", "P2SH,STRICTENC"], +["0", "NOT", "P2SH,STRICTENC"], +["-1", "0NOTEQUAL", "P2SH,STRICTENC"], + +["1 0", "ADD", "P2SH,STRICTENC"], +["1 0", "SUB", "P2SH,STRICTENC"], +["-1 -1", "BOOLAND", "P2SH,STRICTENC"], +["-1 0", "BOOLOR", "P2SH,STRICTENC"], +["0 0", "NUMEQUAL", "P2SH,STRICTENC"], +["0 0", "NUMEQUALVERIFY 1", "P2SH,STRICTENC"], +["-1 0", "NUMNOTEQUAL", "P2SH,STRICTENC"], +["-1 0", "LESSTHAN", "P2SH,STRICTENC"], +["1 0", "GREATERTHAN", "P2SH,STRICTENC"], +["0 0", "LESSTHANOREQUAL", "P2SH,STRICTENC"], +["0 0", "GREATERTHANOREQUAL", "P2SH,STRICTENC"], +["-1 0", "MIN", "P2SH,STRICTENC"], +["1 0", "MAX", "P2SH,STRICTENC"], +["-1 -1 0", "WITHIN", "P2SH,STRICTENC"], + +["0", "RIPEMD160", "P2SH,STRICTENC"], +["0", "SHA1", "P2SH,STRICTENC"], +["0", "SHA256", "P2SH,STRICTENC"], +["0", "HASH160", "P2SH,STRICTENC"], +["0", "HASH256", "P2SH,STRICTENC"], +["NOP", "CODESEPARATOR 1", "P2SH,STRICTENC"], + +["NOP", "NOP1 1", "P2SH,STRICTENC"], +["NOP", "NOP2 1", "P2SH,STRICTENC"], +["NOP", "NOP3 1", "P2SH,STRICTENC"], +["NOP", "NOP4 1", "P2SH,STRICTENC"], +["NOP", "NOP5 1", "P2SH,STRICTENC"], +["NOP", "NOP6 1", "P2SH,STRICTENC"], +["NOP", "NOP7 1", "P2SH,STRICTENC"], +["NOP", "NOP8 1", "P2SH,STRICTENC"], +["NOP", "NOP9 1", "P2SH,STRICTENC"], +["NOP", "NOP10 1", "P2SH,STRICTENC"], + +["", "0 0 0 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "CHECKMULTISIG is allowed to have zero keys and/or sigs"], +["", "0 0 0 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], +["", "0 0 0 1 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "Zero sigs means no sigs are checked"], +["", "0 0 0 1 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], + +["", "0 0 0 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "CHECKMULTISIG is allowed to have zero keys and/or sigs"], +["", "0 0 0 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], +["", "0 0 0 1 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "Zero sigs means no sigs are checked"], +["", "0 0 0 1 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], + +["", "0 0 'a' 'b' 2 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "Test from up to 20 pubkeys, all not checked"], +["", "0 0 'a' 'b' 'c' 3 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], +["", "0 0 'a' 'b' 'c' 'd' 4 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 5 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 6 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 7 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 8 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 9 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 10 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 11 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 12 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 13 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 14 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 15 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 16 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 17 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 18 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 19 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], +["", "0 0 'a' 1 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], +["", "0 0 'a' 'b' 2 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], +["", "0 0 'a' 'b' 'c' 3 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], +["", "0 0 'a' 'b' 'c' 'd' 4 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 5 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 6 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 7 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 8 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 9 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 10 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 11 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 12 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 13 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 14 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 15 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 16 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 17 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 18 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 19 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], +["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], + +["", +"0 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG", +"P2SH,STRICTENC", +"nOpCount is incremented by the number of keys evaluated in addition to the usual one op per op. In this case we have zero keys, so we can execute 201 CHECKMULTISIGS"], + +["1", +"0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY", +"P2SH,STRICTENC"], + +["", +"NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG", +"P2SH,STRICTENC", +"Even though there are no signatures being checked nOpCount is incremented by the number of keys."], + +["1", +"NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY", +"P2SH,STRICTENC"], + +["0 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL", "P2SH,STRICTENC", "Very basic P2SH"], +["0x4c 0 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL", "P2SH,STRICTENC"], + +["0x40 0x42424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242", +"0x4d 0x4000 0x42424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242 EQUAL", +"P2SH,STRICTENC", +"Basic PUSH signedness check"], + +["0x4c 0x40 0x42424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242", +"0x4d 0x4000 0x42424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242 EQUAL", +"P2SH,STRICTENC", +"Basic PUSHDATA1 signedness check"], + +["0x00", "SIZE 0 EQUAL", "P2SH,STRICTENC", "Basic OP_0 execution"], + +[ + "0 0x47 0x3044022002a27769ee33db258bdf7a3792e7da4143ec4001b551f73e6a190b8d1bde449d02206742c56ccd94a7a2e16ca52fc1ae4a0aa122b0014a867a80de104f9cb18e472c01 DUP", + "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG", + "", + "2-of-2 with two identical keys and sigs pushed using OP_DUP but no SIGPUSHONLY" +], +[ + "0 0x47 0x304402203acf75dd59bbef171aeeedae4f1020b824195820db82575c2b323b8899f95de9022067df297d3a5fad049ba0bb81255d0e495643cbcf9abae9e396988618bc0c6dfe01 0x47 0x304402205f8b859230c1cab7d4e8de38ff244d2ebe046b64e8d3f4219b01e483c203490a022071bdc488e31b557f7d9e5c8a8bec90dc92289ca70fa317685f4f140e38b30c4601", + "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG", + "SIGPUSHONLY", + "2-of-2 with two identical keys and sigs pushed" +] + +] diff --git a/txscript/data/tx_invalid.json b/txscript/data/tx_invalid.json new file mode 100644 index 000000000..d5f7d7dc8 --- /dev/null +++ b/txscript/data/tx_invalid.json @@ -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"] +] diff --git a/txscript/data/tx_valid.json b/txscript/data/tx_valid.json new file mode 100644 index 000000000..026771d4e --- /dev/null +++ b/txscript/data/tx_valid.json @@ -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"] +] diff --git a/txscript/doc.go b/txscript/doc.go new file mode 100644 index 000000000..dfd1f2f2f --- /dev/null +++ b/txscript/doc.go @@ -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 diff --git a/txscript/example_test.go b/txscript/example_test.go new file mode 100644 index 000000000..4317ef5cd --- /dev/null +++ b/txscript/example_test.go @@ -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 +} diff --git a/txscript/internal_test.go b/txscript/internal_test.go new file mode 100644 index 000000000..1bd9cd478 --- /dev/null +++ b/txscript/internal_test.go @@ -0,0 +1,4265 @@ +// 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" + "encoding/json" + "errors" + "fmt" + "io/ioutil" + "strconv" + "strings" + "testing" + + "github.com/btcsuite/btcutil" + "github.com/btcsuite/btcwire" +) + +// TstMaxScriptSize makes the internal maxScriptSize constant available to the +// test package. +const TstMaxScriptSize = maxScriptSize + +// this file is present to export some internal interfaces so that we can +// test them reliably. + +func TstRemoveOpcode(pkscript []byte, opcode byte) ([]byte, error) { + pops, err := parseScript(pkscript) + if err != nil { + return nil, err + } + pops = removeOpcode(pops, opcode) + return unparseScript(pops) +} + +func TstRemoveOpcodeByData(pkscript []byte, data []byte) ([]byte, error) { + pops, err := parseScript(pkscript) + if err != nil { + return nil, err + } + pops = removeOpcodeByData(pops, data) + return unparseScript(pops) +} + +// TestSetPC allows the test modules to set the program counter to whatever they +// want. +func (s *Script) TstSetPC(script, off int) { + s.scriptidx = script + s.scriptoff = off +} + +// Internal tests for opcodde parsing with bad data templates. +func TestParseOpcode(t *testing.T) { + fakemap := make(map[byte]*opcode) + // deep copy + for k, v := range opcodemap { + fakemap[k] = v + } + // wrong length -8. + fakemap[OP_PUSHDATA4] = &opcode{value: OP_PUSHDATA4, + name: "OP_PUSHDATA4", length: -8, opfunc: opcodePushData} + + // this script would be fine if -8 was a valid length. + _, err := parseScriptTemplate([]byte{OP_PUSHDATA4, 0x1, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00}, fakemap) + if err == nil { + t.Errorf("no error with dodgy opcode map!") + } + + // Missing entry. + fakemap = make(map[byte]*opcode) + for k, v := range opcodemap { + fakemap[k] = v + } + delete(fakemap, OP_PUSHDATA4) + // this script would be fine if -8 was a valid length. + _, err = parseScriptTemplate([]byte{OP_PUSHDATA4, 0x1, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00}, fakemap) + if err == nil { + t.Errorf("no error with dodgy opcode map (missing entry)!") + } +} + +type popTest struct { + name string + pop *parsedOpcode + expectedErr error +} + +var popTests = []popTest{ + { + name: "OP_FALSE", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_FALSE], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_FALSE long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_FALSE], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_1 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_1], + data: nil, + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_1", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_1], + data: make([]byte, 1), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_1 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_1], + data: make([]byte, 2), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_2 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_2], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_2", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_2], + data: make([]byte, 2), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_2 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_2], + data: make([]byte, 3), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_3 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_3], + data: make([]byte, 2), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_3", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_3], + data: make([]byte, 3), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_3 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_3], + data: make([]byte, 4), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_4 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_4], + data: make([]byte, 3), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_4", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_4], + data: make([]byte, 4), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_4 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_4], + data: make([]byte, 5), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_5 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_5], + data: make([]byte, 4), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_5", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_5], + data: make([]byte, 5), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_5 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_5], + data: make([]byte, 6), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_6 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_6], + data: make([]byte, 5), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_6", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_6], + data: make([]byte, 6), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_6 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_6], + data: make([]byte, 7), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_7 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_7], + data: make([]byte, 6), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_7", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_7], + data: make([]byte, 7), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_7 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_7], + data: make([]byte, 8), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_8 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_8], + data: make([]byte, 7), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_8", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_8], + data: make([]byte, 8), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_8 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_8], + data: make([]byte, 9), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_9 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_9], + data: make([]byte, 8), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_9", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_9], + data: make([]byte, 9), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_9 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_9], + data: make([]byte, 10), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_10 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_10], + data: make([]byte, 9), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_10", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_10], + data: make([]byte, 10), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_10 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_10], + data: make([]byte, 11), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_11 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_11], + data: make([]byte, 10), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_11", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_11], + data: make([]byte, 11), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_11 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_11], + data: make([]byte, 12), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_12 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_12], + data: make([]byte, 11), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_12", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_12], + data: make([]byte, 12), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_12 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_12], + data: make([]byte, 13), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_13 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_13], + data: make([]byte, 12), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_13", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_13], + data: make([]byte, 13), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_13 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_13], + data: make([]byte, 14), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_14 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_14], + data: make([]byte, 13), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_14", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_14], + data: make([]byte, 14), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_14 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_14], + data: make([]byte, 15), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_15 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_15], + data: make([]byte, 14), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_15", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_15], + data: make([]byte, 15), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_15 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_15], + data: make([]byte, 16), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_16 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_16], + data: make([]byte, 15), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_16", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_16], + data: make([]byte, 16), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_16 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_16], + data: make([]byte, 17), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_17 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_17], + data: make([]byte, 16), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_17", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_17], + data: make([]byte, 17), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_17 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_17], + data: make([]byte, 18), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_18 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_18], + data: make([]byte, 17), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_18", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_18], + data: make([]byte, 18), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_18 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_18], + data: make([]byte, 19), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_19 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_19], + data: make([]byte, 18), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_19", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_19], + data: make([]byte, 19), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_19 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_19], + data: make([]byte, 20), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_20 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_20], + data: make([]byte, 19), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_20", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_20], + data: make([]byte, 20), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_20 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_20], + data: make([]byte, 21), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_21 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_21], + data: make([]byte, 20), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_21", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_21], + data: make([]byte, 21), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_21 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_21], + data: make([]byte, 22), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_22 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_22], + data: make([]byte, 21), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_22", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_22], + data: make([]byte, 22), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_22 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_22], + data: make([]byte, 23), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_23 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_23], + data: make([]byte, 22), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_23", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_23], + data: make([]byte, 23), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_23 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_23], + data: make([]byte, 24), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_24 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_24], + data: make([]byte, 23), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_24", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_24], + data: make([]byte, 24), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_24 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_24], + data: make([]byte, 25), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_25 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_25], + data: make([]byte, 24), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_25", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_25], + data: make([]byte, 25), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_25 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_25], + data: make([]byte, 26), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_26 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_26], + data: make([]byte, 25), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_26", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_26], + data: make([]byte, 26), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_26 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_26], + data: make([]byte, 27), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_27 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_27], + data: make([]byte, 26), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_27", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_27], + data: make([]byte, 27), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_27 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_27], + data: make([]byte, 28), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_28 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_28], + data: make([]byte, 27), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_28", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_28], + data: make([]byte, 28), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_28 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_28], + data: make([]byte, 29), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_29 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_29], + data: make([]byte, 28), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_29", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_29], + data: make([]byte, 29), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_29 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_29], + data: make([]byte, 30), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_30 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_30], + data: make([]byte, 29), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_30", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_30], + data: make([]byte, 30), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_30 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_30], + data: make([]byte, 31), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_31 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_31], + data: make([]byte, 30), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_31", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_31], + data: make([]byte, 31), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_31 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_31], + data: make([]byte, 32), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_32 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_32], + data: make([]byte, 31), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_32", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_32], + data: make([]byte, 32), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_32 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_32], + data: make([]byte, 33), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_33 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_33], + data: make([]byte, 32), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_33", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_33], + data: make([]byte, 33), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_33 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_33], + data: make([]byte, 34), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_34 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_34], + data: make([]byte, 33), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_34", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_34], + data: make([]byte, 34), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_34 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_34], + data: make([]byte, 35), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_35 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_35], + data: make([]byte, 34), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_35", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_35], + data: make([]byte, 35), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_35 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_35], + data: make([]byte, 36), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_36 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_36], + data: make([]byte, 35), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_36", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_36], + data: make([]byte, 36), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_36 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_36], + data: make([]byte, 37), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_37 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_37], + data: make([]byte, 36), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_37", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_37], + data: make([]byte, 37), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_37 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_37], + data: make([]byte, 38), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_38 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_38], + data: make([]byte, 37), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_38", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_38], + data: make([]byte, 38), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_38 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_38], + data: make([]byte, 39), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_39 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_39], + data: make([]byte, 38), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_39", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_39], + data: make([]byte, 39), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_39 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_39], + data: make([]byte, 40), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_40 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_40], + data: make([]byte, 39), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_40", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_40], + data: make([]byte, 40), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_40 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_40], + data: make([]byte, 41), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_41 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_41], + data: make([]byte, 40), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_41", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_41], + data: make([]byte, 41), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_41 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_41], + data: make([]byte, 42), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_42 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_42], + data: make([]byte, 41), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_42", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_42], + data: make([]byte, 42), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_42 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_42], + data: make([]byte, 43), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_43 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_43], + data: make([]byte, 42), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_43", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_43], + data: make([]byte, 43), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_43 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_43], + data: make([]byte, 44), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_44 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_44], + data: make([]byte, 43), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_44", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_44], + data: make([]byte, 44), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_44 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_44], + data: make([]byte, 45), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_45 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_45], + data: make([]byte, 44), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_45", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_45], + data: make([]byte, 45), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_45 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_45], + data: make([]byte, 46), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_46 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_46], + data: make([]byte, 45), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_46", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_46], + data: make([]byte, 46), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_46 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_46], + data: make([]byte, 47), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_47 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_47], + data: make([]byte, 46), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_47", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_47], + data: make([]byte, 47), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_47 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_47], + data: make([]byte, 48), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_48 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_48], + data: make([]byte, 47), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_48", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_48], + data: make([]byte, 48), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_48 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_48], + data: make([]byte, 49), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_49 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_49], + data: make([]byte, 48), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_49", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_49], + data: make([]byte, 49), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_49 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_49], + data: make([]byte, 50), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_50 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_50], + data: make([]byte, 49), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_50", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_50], + data: make([]byte, 50), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_50 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_50], + data: make([]byte, 51), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_51 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_51], + data: make([]byte, 50), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_51", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_51], + data: make([]byte, 51), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_51 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_51], + data: make([]byte, 52), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_52 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_52], + data: make([]byte, 51), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_52", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_52], + data: make([]byte, 52), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_52 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_52], + data: make([]byte, 53), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_53 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_53], + data: make([]byte, 52), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_53", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_53], + data: make([]byte, 53), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_53 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_53], + data: make([]byte, 54), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_54 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_54], + data: make([]byte, 53), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_54", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_54], + data: make([]byte, 54), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_54 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_54], + data: make([]byte, 55), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_55 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_55], + data: make([]byte, 54), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_55", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_55], + data: make([]byte, 55), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_55 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_55], + data: make([]byte, 56), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_56 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_56], + data: make([]byte, 55), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_56", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_56], + data: make([]byte, 56), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_56 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_56], + data: make([]byte, 57), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_57 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_57], + data: make([]byte, 56), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_57", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_57], + data: make([]byte, 57), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_57 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_57], + data: make([]byte, 58), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_58 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_58], + data: make([]byte, 57), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_58", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_58], + data: make([]byte, 58), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_58 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_58], + data: make([]byte, 59), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_59 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_59], + data: make([]byte, 58), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_59", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_59], + data: make([]byte, 59), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_59 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_59], + data: make([]byte, 60), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_60 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_60], + data: make([]byte, 59), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_60", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_60], + data: make([]byte, 60), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_60 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_60], + data: make([]byte, 61), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_61 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_61], + data: make([]byte, 60), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_61", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_61], + data: make([]byte, 61), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_61 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_61], + data: make([]byte, 62), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_62 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_62], + data: make([]byte, 61), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_62", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_62], + data: make([]byte, 62), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_62 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_62], + data: make([]byte, 63), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_63 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_63], + data: make([]byte, 62), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_63", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_63], + data: make([]byte, 63), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_63 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_63], + data: make([]byte, 64), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_64 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_64], + data: make([]byte, 63), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_64", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_64], + data: make([]byte, 64), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_64 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_64], + data: make([]byte, 65), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_65 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_65], + data: make([]byte, 64), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_65", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_65], + data: make([]byte, 65), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_65 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_65], + data: make([]byte, 66), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_66 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_66], + data: make([]byte, 65), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_66", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_66], + data: make([]byte, 66), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_66 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_66], + data: make([]byte, 67), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_67 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_67], + data: make([]byte, 66), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_67", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_67], + data: make([]byte, 67), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_67 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_67], + data: make([]byte, 68), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_68 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_68], + data: make([]byte, 67), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_68", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_68], + data: make([]byte, 68), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_68 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_68], + data: make([]byte, 69), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_69 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_69], + data: make([]byte, 68), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_69", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_69], + data: make([]byte, 69), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_69 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_69], + data: make([]byte, 70), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_70 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_70], + data: make([]byte, 69), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_70", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_70], + data: make([]byte, 70), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_70 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_70], + data: make([]byte, 71), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_71 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_71], + data: make([]byte, 70), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_71", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_71], + data: make([]byte, 71), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_71 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_71], + data: make([]byte, 72), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_72 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_72], + data: make([]byte, 71), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_72", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_72], + data: make([]byte, 72), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_72 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_72], + data: make([]byte, 73), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_73 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_73], + data: make([]byte, 72), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_73", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_73], + data: make([]byte, 73), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_73 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_73], + data: make([]byte, 74), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_74 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_74], + data: make([]byte, 73), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_74", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_74], + data: make([]byte, 74), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_74 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_74], + data: make([]byte, 75), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_75 short", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_75], + data: make([]byte, 74), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DATA_75", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_75], + data: make([]byte, 75), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_75 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DATA_75], + data: make([]byte, 76), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_PUSHDATA1", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_PUSHDATA1], + data: []byte{0, 1, 2, 3, 4}, + }, + expectedErr: nil, + }, + { + name: "OP_PUSHDATA2", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_PUSHDATA2], + data: []byte{0, 1, 2, 3, 4}, + }, + expectedErr: nil, + }, + { + name: "OP_PUSHDATA4", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_PUSHDATA1], + data: []byte{0, 1, 2, 3, 4}, + }, + expectedErr: nil, + }, + { + name: "OP_1NEGATE", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_1NEGATE], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_1NEGATE long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_1NEGATE], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_RESERVED", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_RESERVED], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_RESERVED long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_RESERVED], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_TRUE", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_TRUE], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_TRUE long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_TRUE], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_2", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_2], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_2 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_2], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_2", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_2], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_2 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_2], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_3", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_3], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_3 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_3], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_4", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_4], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_4 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_4], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_5", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_5], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_5 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_5], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_6", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_6], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_6 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_6], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_7", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_7], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_7 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_7], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_8", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_8], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_8 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_8], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_9", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_9], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_9 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_9], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_10", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_10], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_10 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_10], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_11", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_11], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_11 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_11], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_12", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_12], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_12 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_12], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_13", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_13], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_13 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_13], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_14", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_14], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_14 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_14], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_15", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_15], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_15 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_15], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_16", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_16], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_16 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_16], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_NOP", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_NOP], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_NOP long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_NOP], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_VER", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_VER], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_VER long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_VER], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_IF", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_IF], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_IF long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_IF], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_NOTIF", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_NOTIF], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_NOTIF long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_NOTIF], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_VERIF", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_VERIF], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_VERIF long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_VERIF], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_VERNOTIF", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_VERNOTIF], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_VERNOTIF long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_VERNOTIF], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_ELSE", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_ELSE], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_ELSE long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_ELSE], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_ENDIF", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_ENDIF], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_ENDIF long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_ENDIF], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_VERIFY", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_VERIFY], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_VERIFY long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_VERIFY], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_RETURN", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_RETURN], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_RETURN long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_RETURN], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_TOALTSTACK", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_TOALTSTACK], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_TOALTSTACK long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_TOALTSTACK], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_FROMALTSTACK", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_FROMALTSTACK], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_FROMALTSTACK long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_FROMALTSTACK], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_2DROP", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_2DROP], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_2DROP long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_2DROP], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_2DUP", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_2DUP], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_2DUP long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_2DUP], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_3DUP", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_3DUP], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_3DUP long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_3DUP], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_2OVER", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_2OVER], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_2OVER long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_2OVER], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_2ROT", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_2ROT], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_2ROT long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_2ROT], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_2SWAP", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_2SWAP], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_2SWAP long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_2SWAP], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_IFDUP", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_IFDUP], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_IFDUP long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_IFDUP], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DEPTH", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DEPTH], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_DEPTH long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DEPTH], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DROP", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DROP], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_DROP long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DROP], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DUP", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DUP], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_DUP long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DUP], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_NIP", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_NIP], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_NIP long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_NIP], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_OVER", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_OVER], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_OVER long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_OVER], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_PICK", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_PICK], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_PICK long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_PICK], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_ROLL", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_ROLL], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_ROLL long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_ROLL], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_ROT", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_ROT], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_ROT long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_ROT], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_SWAP", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_SWAP], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_SWAP long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_SWAP], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_TUCK", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_TUCK], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_TUCK long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_TUCK], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_CAT", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_CAT], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_CAT long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_CAT], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_SUBSTR", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_SUBSTR], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_SUBSTR long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_SUBSTR], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_LEFT", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_LEFT], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_LEFT long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_LEFT], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_LEFT", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_LEFT], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_LEFT long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_LEFT], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_RIGHT", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_RIGHT], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_RIGHT long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_RIGHT], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_SIZE", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_SIZE], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_SIZE long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_SIZE], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_INVERT", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_INVERT], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_INVERT long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_INVERT], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_AND", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_AND], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_AND long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_AND], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_OR", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_OR], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_OR long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_OR], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_XOR", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_XOR], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_XOR long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_XOR], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_EQUAL", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_EQUAL], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_EQUAL long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_EQUAL], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_EQUALVERIFY", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_EQUALVERIFY], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_EQUALVERIFY long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_EQUALVERIFY], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_RESERVED1", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_RESERVED1], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_RESERVED1 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_RESERVED1], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_RESERVED2", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_RESERVED2], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_RESERVED2 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_RESERVED2], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_1ADD", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_1ADD], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_1ADD long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_1ADD], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_1SUB", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_1SUB], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_1SUB long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_1SUB], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_2MUL", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_2MUL], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_2MUL long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_2MUL], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_2DIV", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_2DIV], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_2DIV long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_2DIV], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_NEGATE", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_NEGATE], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_NEGATE long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_NEGATE], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_ABS", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_ABS], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_ABS long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_ABS], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_NOT", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_NOT], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_NOT long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_NOT], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_0NOTEQUAL", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_0NOTEQUAL], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_0NOTEQUAL long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_0NOTEQUAL], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_ADD", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_ADD], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_ADD long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_ADD], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_SUB", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_SUB], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_SUB long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_SUB], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_MUL", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_MUL], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_MUL long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_MUL], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_DIV", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DIV], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_DIV long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_DIV], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_MOD", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_MOD], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_MOD long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_MOD], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_LSHIFT", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_LSHIFT], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_LSHIFT long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_LSHIFT], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_RSHIFT", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_RSHIFT], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_RSHIFT long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_RSHIFT], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_BOOLAND", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_BOOLAND], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_BOOLAND long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_BOOLAND], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_BOOLOR", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_BOOLOR], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_BOOLOR long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_BOOLOR], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_NUMEQUAL", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_NUMEQUAL], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_NUMEQUAL long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_NUMEQUAL], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_NUMEQUALVERIFY", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_NUMEQUALVERIFY], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_NUMEQUALVERIFY long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_NUMEQUALVERIFY], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_NUMNOTEQUAL", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_NUMNOTEQUAL], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_NUMNOTEQUAL long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_NUMNOTEQUAL], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_LESSTHAN", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_LESSTHAN], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_LESSTHAN long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_LESSTHAN], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_GREATERTHAN", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_GREATERTHAN], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_GREATERTHAN long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_GREATERTHAN], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_LESSTHANOREQUAL", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_LESSTHANOREQUAL], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_LESSTHANOREQUAL long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_LESSTHANOREQUAL], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_GREATERTHANOREQUAL", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_GREATERTHANOREQUAL], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_GREATERTHANOREQUAL long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_GREATERTHANOREQUAL], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_MIN", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_MIN], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_MIN long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_MIN], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_MAX", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_MAX], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_MAX long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_MAX], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_WITHIN", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_WITHIN], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_WITHIN long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_WITHIN], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_RIPEMD160", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_RIPEMD160], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_RIPEMD160 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_RIPEMD160], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_SHA1", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_SHA1], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_SHA1 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_SHA1], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_SHA256", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_SHA256], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_SHA256 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_SHA256], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_HASH160", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_HASH160], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_HASH160 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_HASH160], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_HASH256", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_HASH256], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_HASH256 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_HASH256], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_CODESAPERATOR", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_CODESEPARATOR], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_CODESEPARATOR long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_CODESEPARATOR], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_CHECKSIG", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_CHECKSIG], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_CHECKSIG long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_CHECKSIG], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_CHECKSIGVERIFY", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_CHECKSIGVERIFY], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_CHECKSIGVERIFY long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_CHECKSIGVERIFY], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_CHECKMULTISIG", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_CHECKMULTISIG], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_CHECKMULTISIG long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_CHECKMULTISIG], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_CHECKMULTISIGVERIFY", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_CHECKMULTISIGVERIFY], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_CHECKMULTISIGVERIFY long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_CHECKMULTISIGVERIFY], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_NOP1", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_NOP1], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_NOP1 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_NOP1], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_NOP2", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_NOP2], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_NOP2 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_NOP2], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_NOP3", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_NOP3], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_NOP3 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_NOP3], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_NOP4", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_NOP4], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_NOP4 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_NOP4], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_NOP5", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_NOP5], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_NOP5 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_NOP5], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_NOP6", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_NOP6], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_NOP6 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_NOP6], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_NOP7", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_NOP7], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_NOP7 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_NOP7], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_NOP8", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_NOP8], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_NOP8 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_NOP8], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_NOP9", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_NOP9], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_NOP9 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_NOP9], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_NOP10", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_NOP10], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_NOP10 long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_NOP10], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_PUBKEYHASH", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_PUBKEYHASH], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_PUBKEYHASH long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_PUBKEYHASH], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_PUBKEY", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_PUBKEY], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_PUBKEY long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_PUBKEY], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, + { + name: "OP_INVALIDOPCODE", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_INVALIDOPCODE], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_INVALIDOPCODE long", + pop: &parsedOpcode{ + opcode: opcodemapPreinit[OP_INVALIDOPCODE], + data: make([]byte, 1), + }, + expectedErr: ErrStackInvalidOpcode, + }, +} + +func TestUnparsingInvalidOpcodes(t *testing.T) { + for _, test := range popTests { + _, err := test.pop.bytes() + if err != test.expectedErr { + t.Errorf("Parsed Opcode test '%s' failed", test.name) + t.Error(err, test.expectedErr) + } + } +} + +// parse hex string into a []byte. +func parseHex(tok string) ([]byte, error) { + if !strings.HasPrefix(tok, "0x") { + return nil, errors.New("not a hex number") + } + return hex.DecodeString(tok[2:]) +} + +// ParseShortForm parses a string as as used in the bitcoind reference tests +// into the script it came from. +func ParseShortForm(script string) ([]byte, error) { + ops := make(map[string]*opcode) + + // the format used for these tests is pretty simple if ad-hoc: + // - opcodes other than the push opcodes and unknown are present as + // either OP_NAME or just NAME + // - plain numbers are made into push operations + // - numbers beginning with 0x are inserted into the []byte as-is (so + // 0x14 is OP_DATA_20) + // - single quoted strings are pushed as data. + // - anything else is an error. + for _, op := range opcodemap { + if op.value < OP_NOP && op.value != OP_RESERVED { + continue + } + if strings.Contains(op.name, "OP_UNKNOWN") { + continue + } + ops[op.name] = op + ops[strings.TrimPrefix(op.name, "OP_")] = op + } + // do once, build map. + + // Split only does one separator so convert all \n and tab into space. + script = strings.Replace(script, "\n", " ", -1) + script = strings.Replace(script, "\t", " ", -1) + tokens := strings.Split(script, " ") + builder := NewScriptBuilder() + + for _, tok := range tokens { + if len(tok) == 0 { + continue + } + // if parses as a plain number + if num, err := strconv.ParseInt(tok, 10, 64); err == nil { + builder.AddInt64(num) + continue + } else if bts, err := parseHex(tok); err == nil { + // naughty... + builder.script = append(builder.script, bts...) + } else if len(tok) >= 2 && + tok[0] == '\'' && tok[len(tok)-1] == '\'' { + builder.AddFullData([]byte(tok[1 : len(tok)-1])) + } else if opcode, ok := ops[tok]; ok { + builder.AddOp(opcode.value) + } else { + return nil, fmt.Errorf("bad token \"%s\"", tok) + } + + } + return builder.Script() +} + +// createSpendTx generates a basic spending transaction given the passed +// signature and public key scripts. +func createSpendingTx(sigScript, pkScript []byte) (*btcwire.MsgTx, error) { + coinbaseTx := btcwire.NewMsgTx() + + outPoint := btcwire.NewOutPoint(&btcwire.ShaHash{}, ^uint32(0)) + txIn := btcwire.NewTxIn(outPoint, []byte{OP_0, OP_0}) + txOut := btcwire.NewTxOut(0, pkScript) + coinbaseTx.AddTxIn(txIn) + coinbaseTx.AddTxOut(txOut) + + spendingTx := btcwire.NewMsgTx() + coinbaseTxSha, err := coinbaseTx.TxSha() + if err != nil { + return nil, err + } + outPoint = btcwire.NewOutPoint(&coinbaseTxSha, 0) + txIn = btcwire.NewTxIn(outPoint, sigScript) + txOut = btcwire.NewTxOut(0, nil) + + spendingTx.AddTxIn(txIn) + spendingTx.AddTxOut(txOut) + + return spendingTx, nil +} + +func TestBitcoindInvalidTests(t *testing.T) { + file, err := ioutil.ReadFile("data/script_invalid.json") + if err != nil { + t.Errorf("TestBitcoindInvalidTests: %v\n", err) + return + } + + var tests [][]string + err = json.Unmarshal(file, &tests) + if err != nil { + t.Errorf("TestBitcoindInvalidTests couldn't Unmarshal: %v", + err) + return + } + for x, test := range tests { + // Skip comments + if len(test) == 1 { + continue + } + name, err := testName(test) + if err != nil { + t.Errorf("TestBitcoindInvalidTests: invalid test #%d", + x) + continue + } + scriptSig, err := ParseShortForm(test[0]) + if err != nil { + t.Errorf("%s: can't parse scriptSig; %v", name, err) + continue + } + scriptPubKey, err := ParseShortForm(test[1]) + if err != nil { + t.Errorf("%s: can't parse scriptPubkey; %v", name, err) + continue + } + flags, err := parseScriptFlags(test[2]) + if err != nil { + t.Errorf("%s: %v", name, err) + continue + } + tx, err := createSpendingTx(scriptSig, scriptPubKey) + if err != nil { + t.Errorf("createSpendingTx failed on test %s: %v", name, err) + continue + } + s, err := NewScript(scriptSig, scriptPubKey, 0, tx, flags) + if err == nil { + if err := s.Execute(); err == nil { + t.Errorf("%s test succeeded when it "+ + "should have failed\n", name) + } + continue + } + } +} + +func TestBitcoindValidTests(t *testing.T) { + file, err := ioutil.ReadFile("data/script_valid.json") + if err != nil { + t.Errorf("TestBitcoinValidTests: %v\n", err) + return + } + + var tests [][]string + err = json.Unmarshal(file, &tests) + if err != nil { + t.Errorf("TestBitcoindValidTests couldn't Unmarshal: %v", + err) + return + } + for x, test := range tests { + // Skip comments + if len(test) == 1 { + continue + } + name, err := testName(test) + if err != nil { + t.Errorf("TestBitcoindValidTests: invalid test #%d", + x) + continue + } + scriptSig, err := ParseShortForm(test[0]) + if err != nil { + t.Errorf("%s: can't parse scriptSig; %v", name, err) + continue + } + scriptPubKey, err := ParseShortForm(test[1]) + if err != nil { + t.Errorf("%s: can't parse scriptPubkey; %v", name, err) + continue + } + flags, err := parseScriptFlags(test[2]) + if err != nil { + t.Errorf("%s: %v", name, err) + continue + } + tx, err := createSpendingTx(scriptSig, scriptPubKey) + if err != nil { + t.Errorf("createSpendingTx failed on test %s: %v", name, err) + continue + } + s, err := NewScript(scriptSig, scriptPubKey, 0, tx, flags) + if err != nil { + t.Errorf("%s failed to create script: %v", name, err) + continue + } + err = s.Execute() + if err != nil { + t.Errorf("%s failed to execute: %v", name, err) + continue + } + } +} + +func TestBitcoindTxValidTests(t *testing.T) { + file, err := ioutil.ReadFile("data/tx_valid.json") + if err != nil { + t.Errorf("TestBitcoindInvalidTests: %v\n", err) + return + } + + var tests [][]interface{} + err = json.Unmarshal(file, &tests) + if err != nil { + t.Errorf("TestBitcoindInvalidTests couldn't Unmarshal: %v\n", + err) + return + } + + // form is either: + // ["this is a comment "] + // or: + // [[[previous hash, previous index, previous scriptPubKey]...,] + // serializedTransaction, verifyFlags] +testloop: + for i, test := range tests { + inputs, ok := test[0].([]interface{}) + if !ok { + continue + } + + if len(test) != 3 { + t.Errorf("bad test (bad length) %d: %v", i, test) + continue + } + serializedhex, ok := test[1].(string) + if !ok { + t.Errorf("bad test (arg 2 not string) %d: %v", i, test) + continue + } + serializedTx, err := hex.DecodeString(serializedhex) + if err != nil { + t.Errorf("bad test (arg 2 not hex %v) %d: %v", err, i, + test) + continue + } + + tx, err := btcutil.NewTxFromBytes(serializedTx) + if err != nil { + t.Errorf("bad test (arg 2 not msgtx %v) %d: %v", err, + i, test) + continue + } + + verifyFlags, ok := test[2].(string) + if !ok { + t.Errorf("bad test (arg 3 not string) %d: %v", i, test) + continue + } + + flags, err := parseScriptFlags(verifyFlags) + if err != nil { + t.Errorf("bad test %d: %v", i, err) + continue + } + + prevOuts := make(map[btcwire.OutPoint][]byte) + for j, iinput := range inputs { + input, ok := iinput.([]interface{}) + if !ok { + t.Errorf("bad test (%dth input not array)"+ + "%d: %v", j, i, test) + continue + } + + if len(input) != 3 { + t.Errorf("bad test (%dth input wrong length)"+ + "%d: %v", j, i, test) + continue + } + + previoustx, ok := input[0].(string) + if !ok { + t.Errorf("bad test (%dth input sha not string)"+ + "%d: %v", j, i, test) + continue + } + + prevhash, err := btcwire.NewShaHashFromStr(previoustx) + if err != nil { + t.Errorf("bad test (%dth input sha not sha %v)"+ + "%d: %v", j, err, i, test) + continue + } + + idxf, ok := input[1].(float64) + if !ok { + t.Errorf("bad test (%dth input idx not number)"+ + "%d: %v", j, i, test) + continue + } + + idx := uint32(idxf) // (floor(idxf) == idxf?) + + oscript, ok := input[2].(string) + if !ok { + t.Errorf("bad test (%dth input script not "+ + "string) %d: %v", j, i, test) + continue + } + + script, err := ParseShortForm(oscript) + if err != nil { + t.Errorf("bad test (%dth input script doesn't "+ + "parse %v) %d: %v", j, err, i, test) + continue + } + + prevOuts[*btcwire.NewOutPoint(prevhash, idx)] = script + } + + for k, txin := range tx.MsgTx().TxIn { + pkScript, ok := prevOuts[txin.PreviousOutPoint] + if !ok { + t.Errorf("bad test (missing %dth input) %d:%v", + k, i, test) + continue testloop + } + s, err := NewScript(txin.SignatureScript, pkScript, k, + tx.MsgTx(), flags) + if err != nil { + t.Errorf("test (%d:%v:%d) failed to create "+ + "script: %v", i, test, k, err) + continue + } + + err = s.Execute() + if err != nil { + t.Errorf("test (%d:%v:%d) failed to execute: "+ + "%v", i, test, k, err) + continue + } + } + } +} + +func TestBitcoindTxInvalidTests(t *testing.T) { + file, err := ioutil.ReadFile("data/tx_invalid.json") + if err != nil { + t.Errorf("TestBitcoindInvalidTests: %v\n", err) + return + } + + var tests [][]interface{} + err = json.Unmarshal(file, &tests) + if err != nil { + t.Errorf("TestBitcoindInvalidTests couldn't Unmarshal: %v\n", + err) + return + } + + // form is either: + // ["this is a comment "] + // or: + // [[[previous hash, previous index, previous scriptPubKey]...,] + // serializedTransaction, verifyFlags] +testloop: + for i, test := range tests { + inputs, ok := test[0].([]interface{}) + if !ok { + continue + } + + if len(test) != 3 { + t.Errorf("bad test (bad lenggh) %d: %v", i, test) + continue + + } + serializedhex, ok := test[1].(string) + if !ok { + t.Errorf("bad test (arg 2 not string) %d: %v", i, test) + continue + } + serializedTx, err := hex.DecodeString(serializedhex) + if err != nil { + t.Errorf("bad test (arg 2 not hex %v) %d: %v", err, i, + test) + continue + } + + tx, err := btcutil.NewTxFromBytes(serializedTx) + if err != nil { + t.Errorf("bad test (arg 2 not msgtx %v) %d: %v", err, + i, test) + continue + } + + verifyFlags, ok := test[2].(string) + if !ok { + t.Errorf("bad test (arg 3 not string) %d: %v", i, test) + continue + } + + flags, err := parseScriptFlags(verifyFlags) + if err != nil { + t.Errorf("bad test %d: %v", i, err) + continue + } + + prevOuts := make(map[btcwire.OutPoint][]byte) + for j, iinput := range inputs { + input, ok := iinput.([]interface{}) + if !ok { + t.Errorf("bad test (%dth input not array)"+ + "%d: %v", j, i, test) + continue testloop + } + + if len(input) != 3 { + t.Errorf("bad test (%dth input wrong length)"+ + "%d: %v", j, i, test) + continue testloop + } + + previoustx, ok := input[0].(string) + if !ok { + t.Errorf("bad test (%dth input sha not string)"+ + "%d: %v", j, i, test) + continue testloop + } + + prevhash, err := btcwire.NewShaHashFromStr(previoustx) + if err != nil { + t.Errorf("bad test (%dth input sha not sha %v)"+ + "%d: %v", j, err, i, test) + continue testloop + } + + idxf, ok := input[1].(float64) + if !ok { + t.Errorf("bad test (%dth input idx not number)"+ + "%d: %v", j, i, test) + continue testloop + } + + idx := uint32(idxf) // (floor(idxf) == idxf?) + + oscript, ok := input[2].(string) + if !ok { + t.Errorf("bad test (%dth input script not "+ + "string) %d: %v", j, i, test) + continue testloop + } + + script, err := ParseShortForm(oscript) + if err != nil { + t.Errorf("bad test (%dth input script doesn't "+ + "parse %v) %d: %v", j, err, i, test) + continue testloop + } + + prevOuts[*btcwire.NewOutPoint(prevhash, idx)] = script + } + + for k, txin := range tx.MsgTx().TxIn { + pkScript, ok := prevOuts[txin.PreviousOutPoint] + if !ok { + t.Errorf("bad test (missing %dth input) %d:%v", + k, i, test) + continue testloop + } + // These are meant to fail, so as soon as the first + // input fails the transaction has failed. (some of the + // test txns have good inputs, too.. + s, err := NewScript(txin.SignatureScript, pkScript, k, + tx.MsgTx(), flags) + if err != nil { + continue testloop + } + + err = s.Execute() + if err != nil { + continue testloop + } + + } + t.Errorf("test (%d:%v) succeeded when should fail", + i, test) + } +} + +func parseScriptFlags(flagStr string) (ScriptFlags, error) { + var flags ScriptFlags + + sFlags := strings.Split(flagStr, ",") + for _, flag := range sFlags { + switch flag { + case "DISCOURAGE_UPGRADABLE_NOPS": + flags |= ScriptDiscourageUpgradableNops + case "", "NONE": + // Nothing. + case "NULLDUMMY": + flags |= ScriptStrictMultiSig + case "P2SH": + flags |= ScriptBip16 + case "SIGPUSHONLY": + flags |= ScriptVerifySigPushOnly + case "STRICTENC": + // This is always set. + default: + return flags, fmt.Errorf("invalid flag: %s", flag) + } + } + return flags, nil +} + +func testName(test []string) (string, error) { + var name string + + if len(test) < 3 || len(test) > 4 { + return name, fmt.Errorf("invalid test length %d", len(test)) + } + + if len(test) == 4 { + name = fmt.Sprintf("test (%s)", test[3]) + } else { + name = fmt.Sprintf("test ([%s, %s, %s])", test[0], test[1], + test[2]) + } + return name, nil +} diff --git a/txscript/log.go b/txscript/log.go new file mode 100644 index 000000000..60d869264 --- /dev/null +++ b/txscript/log.go @@ -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) +} diff --git a/txscript/log_test.go b/txscript/log_test.go new file mode 100644 index 000000000..15f369c13 --- /dev/null +++ b/txscript/log_test.go @@ -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) + } + } + } +} diff --git a/txscript/opcode.go b/txscript/opcode.go new file mode 100644 index 000000000..6ae2f58c9 --- /dev/null +++ b/txscript/opcode.go @@ -0,0 +1,1977 @@ +// 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 ( + "bytes" + "crypto/sha1" + "encoding/binary" + "encoding/hex" + "fmt" + "hash" + "math/big" + + "golang.org/x/crypto/ripemd160" + + "github.com/btcsuite/btcec" + "github.com/btcsuite/btcwire" + "github.com/btcsuite/fastsha256" +) + +// An opcode defines the information related to a txscript opcode. +// opfunc if present is the function to call to perform the opcode on +// the script. The current script is passed in as a slice with the firs +// member being the opcode itself. +type opcode struct { + value byte + name string + length int + opfunc func(*parsedOpcode, *Script) error + parsefunc func(*opcode, *Script, []byte) error +} + +// These constants are the values of the official opcode used on the btc wiki, +// in bitcoind and in most if not all other references and software related to +// handling BTC scripts. +const ( + OP_FALSE = 0 // AKA OP_0 + OP_0 = 0 + OP_DATA_1 = 1 + OP_DATA_2 = 2 + OP_DATA_3 = 3 + OP_DATA_4 = 4 + OP_DATA_5 = 5 + OP_DATA_6 = 6 + OP_DATA_7 = 7 + OP_DATA_8 = 8 + OP_DATA_9 = 9 + OP_DATA_10 = 10 + OP_DATA_11 = 11 + OP_DATA_12 = 12 + OP_DATA_13 = 13 + OP_DATA_14 = 14 + OP_DATA_15 = 15 + OP_DATA_16 = 16 + OP_DATA_17 = 17 + OP_DATA_18 = 18 + OP_DATA_19 = 19 + OP_DATA_20 = 20 + OP_DATA_21 = 21 + OP_DATA_22 = 22 + OP_DATA_23 = 23 + OP_DATA_24 = 24 + OP_DATA_25 = 25 + OP_DATA_26 = 26 + OP_DATA_27 = 27 + OP_DATA_28 = 28 + OP_DATA_29 = 29 + OP_DATA_30 = 30 + OP_DATA_31 = 31 + OP_DATA_32 = 32 + OP_DATA_33 = 33 + OP_DATA_34 = 34 + OP_DATA_35 = 35 + OP_DATA_36 = 36 + OP_DATA_37 = 37 + OP_DATA_38 = 38 + OP_DATA_39 = 39 + OP_DATA_40 = 40 + OP_DATA_41 = 41 + OP_DATA_42 = 42 + OP_DATA_43 = 43 + OP_DATA_44 = 44 + OP_DATA_45 = 45 + OP_DATA_46 = 46 + OP_DATA_47 = 47 + OP_DATA_48 = 48 + OP_DATA_49 = 49 + OP_DATA_50 = 50 + OP_DATA_51 = 51 + OP_DATA_52 = 52 + OP_DATA_53 = 53 + OP_DATA_54 = 54 + OP_DATA_55 = 55 + OP_DATA_56 = 56 + OP_DATA_57 = 57 + OP_DATA_58 = 58 + OP_DATA_59 = 59 + OP_DATA_60 = 60 + OP_DATA_61 = 61 + OP_DATA_62 = 62 + OP_DATA_63 = 63 + OP_DATA_64 = 64 + OP_DATA_65 = 65 + OP_DATA_66 = 66 + OP_DATA_67 = 67 + OP_DATA_68 = 68 + OP_DATA_69 = 69 + OP_DATA_70 = 70 + OP_DATA_71 = 71 + OP_DATA_72 = 72 + OP_DATA_73 = 73 + OP_DATA_74 = 74 + OP_DATA_75 = 75 + OP_PUSHDATA1 = 76 + OP_PUSHDATA2 = 77 + OP_PUSHDATA4 = 78 + OP_1NEGATE = 79 + OP_RESERVED = 80 + OP_1 = 81 // AKA OP_TRUE + OP_TRUE = 81 + OP_2 = 82 + OP_3 = 83 + OP_4 = 84 + OP_5 = 85 + OP_6 = 86 + OP_7 = 87 + OP_8 = 88 + OP_9 = 89 + OP_10 = 90 + OP_11 = 91 + OP_12 = 92 + OP_13 = 93 + OP_14 = 94 + OP_15 = 95 + OP_16 = 96 + OP_NOP = 97 + OP_VER = 98 + OP_IF = 99 + OP_NOTIF = 100 + OP_VERIF = 101 + OP_VERNOTIF = 102 + OP_ELSE = 103 + OP_ENDIF = 104 + OP_VERIFY = 105 + OP_RETURN = 106 + OP_TOALTSTACK = 107 + OP_FROMALTSTACK = 108 + OP_2DROP = 109 + OP_2DUP = 110 + OP_3DUP = 111 + OP_2OVER = 112 + OP_2ROT = 113 + OP_2SWAP = 114 + OP_IFDUP = 115 + OP_DEPTH = 116 + OP_DROP = 117 + OP_DUP = 118 + OP_NIP = 119 + OP_OVER = 120 + OP_PICK = 121 + OP_ROLL = 122 + OP_ROT = 123 + OP_SWAP = 124 + OP_TUCK = 125 + OP_CAT = 126 + OP_SUBSTR = 127 + OP_LEFT = 128 + OP_RIGHT = 129 + OP_SIZE = 130 + OP_INVERT = 131 + OP_AND = 132 + OP_OR = 133 + OP_XOR = 134 + OP_EQUAL = 135 + OP_EQUALVERIFY = 136 + OP_RESERVED1 = 137 + OP_RESERVED2 = 138 + OP_1ADD = 139 + OP_1SUB = 140 + OP_2MUL = 141 + OP_2DIV = 142 + OP_NEGATE = 143 + OP_ABS = 144 + OP_NOT = 145 + OP_0NOTEQUAL = 146 + OP_ADD = 147 + OP_SUB = 148 + OP_MUL = 149 + OP_DIV = 150 + OP_MOD = 151 + OP_LSHIFT = 152 + OP_RSHIFT = 153 + OP_BOOLAND = 154 + OP_BOOLOR = 155 + OP_NUMEQUAL = 156 + OP_NUMEQUALVERIFY = 157 + OP_NUMNOTEQUAL = 158 + OP_LESSTHAN = 159 + OP_GREATERTHAN = 160 + OP_LESSTHANOREQUAL = 161 + OP_GREATERTHANOREQUAL = 162 + OP_MIN = 163 + OP_MAX = 164 + OP_WITHIN = 165 + OP_RIPEMD160 = 166 + OP_SHA1 = 167 + OP_SHA256 = 168 + OP_HASH160 = 169 + OP_HASH256 = 170 + OP_CODESEPARATOR = 171 + OP_CHECKSIG = 172 + OP_CHECKSIGVERIFY = 173 + OP_CHECKMULTISIG = 174 + OP_CHECKMULTISIGVERIFY = 175 + OP_NOP1 = 176 + OP_NOP2 = 177 + OP_NOP3 = 178 + OP_NOP4 = 179 + OP_NOP5 = 180 + OP_NOP6 = 181 + OP_NOP7 = 182 + OP_NOP8 = 183 + OP_NOP9 = 184 + OP_NOP10 = 185 + OP_UNKNOWN186 = 186 + OP_UNKNOWN187 = 187 + OP_UNKNOWN188 = 188 + OP_UNKNOWN189 = 189 + OP_UNKNOWN190 = 190 + OP_UNKNOWN191 = 191 + OP_UNKNOWN192 = 192 + OP_UNKNOWN193 = 193 + OP_UNKNOWN194 = 194 + OP_UNKNOWN195 = 195 + OP_UNKNOWN196 = 196 + OP_UNKNOWN197 = 197 + OP_UNKNOWN198 = 198 + OP_UNKNOWN199 = 199 + OP_UNKNOWN200 = 200 + OP_UNKNOWN201 = 201 + OP_UNKNOWN202 = 202 + OP_UNKNOWN203 = 203 + OP_UNKNOWN204 = 204 + OP_UNKNOWN205 = 205 + OP_UNKNOWN206 = 206 + OP_UNKNOWN207 = 207 + OP_UNKNOWN208 = 208 + OP_UNKNOWN209 = 209 + OP_UNKNOWN210 = 210 + OP_UNKNOWN211 = 211 + OP_UNKNOWN212 = 212 + OP_UNKNOWN213 = 213 + OP_UNKNOWN214 = 214 + OP_UNKNOWN215 = 215 + OP_UNKNOWN216 = 216 + OP_UNKNOWN217 = 217 + OP_UNKNOWN218 = 218 + OP_UNKNOWN219 = 219 + OP_UNKNOWN220 = 220 + OP_UNKNOWN221 = 221 + OP_UNKNOWN222 = 222 + OP_UNKNOWN223 = 223 + OP_UNKNOWN224 = 224 + OP_UNKNOWN225 = 225 + OP_UNKNOWN226 = 226 + OP_UNKNOWN227 = 227 + OP_UNKNOWN228 = 228 + OP_UNKNOWN229 = 229 + OP_UNKNOWN230 = 230 + OP_UNKNOWN231 = 231 + OP_UNKNOWN232 = 232 + OP_UNKNOWN233 = 233 + OP_UNKNOWN234 = 234 + OP_UNKNOWN235 = 235 + OP_UNKNOWN236 = 236 + OP_UNKNOWN237 = 237 + OP_UNKNOWN238 = 238 + OP_UNKNOWN239 = 239 + OP_UNKNOWN240 = 240 + OP_UNKNOWN241 = 241 + OP_UNKNOWN242 = 242 + OP_UNKNOWN243 = 243 + OP_UNKNOWN244 = 244 + OP_UNKNOWN245 = 245 + OP_UNKNOWN246 = 246 + OP_UNKNOWN247 = 247 + OP_UNKNOWN248 = 248 + OP_UNKNOWN249 = 249 + OP_UNKNOWN250 = 250 + OP_UNKNOWN251 = 251 + OP_UNKNOWN252 = 252 + OP_PUBKEYHASH = 253 // bitcoind internal, for completeness + OP_PUBKEY = 254 // bitcoind internal, for completeness + OP_INVALIDOPCODE = 255 // bitcoind internal, for completeness +) + +// conditional execution constants +const ( + OpCondFalse = 0 + OpCondTrue = 1 + OpCondSkip = 2 +) + +// Some of the functions in opcodemap call things that themselves then will +// reference the opcodemap to make decisions (things like op_checksig which +// needs to parse scripts to remove opcodes, for example). +// The go compiler is very conservative in this matter and will think there +// is an initialisation loop. In order to work around this we have the fake +// ``prevariable'' opcodemapPreinit and then set the real variable to the +// preinit in init() +var opcodemap map[byte]*opcode + +func init() { + opcodemap = opcodemapPreinit +} + +var opcodemapPreinit = map[byte]*opcode{ + OP_FALSE: {value: OP_FALSE, name: "OP_0", length: 1, + opfunc: opcodeFalse}, + OP_DATA_1: {value: OP_DATA_1, name: "OP_DATA_1", length: 2, + opfunc: opcodePushData}, + OP_DATA_2: {value: OP_DATA_2, name: "OP_DATA_2", length: 3, + opfunc: opcodePushData}, + OP_DATA_3: {value: OP_DATA_3, name: "OP_DATA_3", length: 4, + opfunc: opcodePushData}, + OP_DATA_4: {value: OP_DATA_4, name: "OP_DATA_4", length: 5, + opfunc: opcodePushData}, + OP_DATA_5: {value: OP_DATA_5, name: "OP_DATA_5", length: 6, + opfunc: opcodePushData}, + OP_DATA_6: {value: OP_DATA_6, name: "OP_DATA_6", length: 7, + opfunc: opcodePushData}, + OP_DATA_7: {value: OP_DATA_7, name: "OP_DATA_7", length: 8, + opfunc: opcodePushData}, + OP_DATA_8: {value: OP_DATA_8, name: "OP_DATA_8", length: 9, + opfunc: opcodePushData}, + OP_DATA_9: {value: OP_DATA_9, name: "OP_DATA_9", length: 10, + opfunc: opcodePushData}, + OP_DATA_10: {value: OP_DATA_10, name: "OP_DATA_10", length: 11, + opfunc: opcodePushData}, + OP_DATA_11: {value: OP_DATA_11, name: "OP_DATA_11", length: 12, + opfunc: opcodePushData}, + OP_DATA_12: {value: OP_DATA_12, name: "OP_DATA_12", length: 13, + opfunc: opcodePushData}, + OP_DATA_13: {value: OP_DATA_13, name: "OP_DATA_13", length: 14, + opfunc: opcodePushData}, + OP_DATA_14: {value: OP_DATA_14, name: "OP_DATA_14", length: 15, + opfunc: opcodePushData}, + OP_DATA_15: {value: OP_DATA_15, name: "OP_DATA_15", length: 16, + opfunc: opcodePushData}, + OP_DATA_16: {value: OP_DATA_16, name: "OP_DATA_16", length: 17, + opfunc: opcodePushData}, + OP_DATA_17: {value: OP_DATA_17, name: "OP_DATA_17", length: 18, + opfunc: opcodePushData}, + OP_DATA_18: {value: OP_DATA_18, name: "OP_DATA_18", length: 19, + opfunc: opcodePushData}, + OP_DATA_19: {value: OP_DATA_19, name: "OP_DATA_19", length: 20, + opfunc: opcodePushData}, + OP_DATA_20: {value: OP_DATA_20, name: "OP_DATA_20", length: 21, + opfunc: opcodePushData}, + OP_DATA_21: {value: OP_DATA_21, name: "OP_DATA_21", length: 22, + opfunc: opcodePushData}, + OP_DATA_22: {value: OP_DATA_22, name: "OP_DATA_22", length: 23, + opfunc: opcodePushData}, + OP_DATA_23: {value: OP_DATA_23, name: "OP_DATA_23", length: 24, + opfunc: opcodePushData}, + OP_DATA_24: {value: OP_DATA_24, name: "OP_DATA_24", length: 25, + opfunc: opcodePushData}, + OP_DATA_25: {value: OP_DATA_25, name: "OP_DATA_25", length: 26, + opfunc: opcodePushData}, + OP_DATA_26: {value: OP_DATA_26, name: "OP_DATA_26", length: 27, + opfunc: opcodePushData}, + OP_DATA_27: {value: OP_DATA_27, name: "OP_DATA_27", length: 28, + opfunc: opcodePushData}, + OP_DATA_28: {value: OP_DATA_28, name: "OP_DATA_28", length: 29, + opfunc: opcodePushData}, + OP_DATA_29: {value: OP_DATA_29, name: "OP_DATA_29", length: 30, + opfunc: opcodePushData}, + OP_DATA_30: {value: OP_DATA_30, name: "OP_DATA_30", length: 31, + opfunc: opcodePushData}, + OP_DATA_31: {value: OP_DATA_31, name: "OP_DATA_31", length: 32, + opfunc: opcodePushData}, + OP_DATA_32: {value: OP_DATA_32, name: "OP_DATA_32", length: 33, + opfunc: opcodePushData}, + OP_DATA_33: {value: OP_DATA_33, name: "OP_DATA_33", length: 34, + opfunc: opcodePushData}, + OP_DATA_34: {value: OP_DATA_34, name: "OP_DATA_34", length: 35, + opfunc: opcodePushData}, + OP_DATA_35: {value: OP_DATA_35, name: "OP_DATA_35", length: 36, + opfunc: opcodePushData}, + OP_DATA_36: {value: OP_DATA_36, name: "OP_DATA_36", length: 37, + opfunc: opcodePushData}, + OP_DATA_37: {value: OP_DATA_37, name: "OP_DATA_37", length: 38, + opfunc: opcodePushData}, + OP_DATA_38: {value: OP_DATA_38, name: "OP_DATA_38", length: 39, + opfunc: opcodePushData}, + OP_DATA_39: {value: OP_DATA_39, name: "OP_DATA_39", length: 40, + opfunc: opcodePushData}, + OP_DATA_40: {value: OP_DATA_40, name: "OP_DATA_40", length: 41, + opfunc: opcodePushData}, + OP_DATA_41: {value: OP_DATA_41, name: "OP_DATA_41", length: 42, + opfunc: opcodePushData}, + OP_DATA_42: {value: OP_DATA_42, name: "OP_DATA_42", length: 43, + opfunc: opcodePushData}, + OP_DATA_43: {value: OP_DATA_43, name: "OP_DATA_43", length: 44, + opfunc: opcodePushData}, + OP_DATA_44: {value: OP_DATA_44, name: "OP_DATA_44", length: 45, + opfunc: opcodePushData}, + OP_DATA_45: {value: OP_DATA_45, name: "OP_DATA_45", length: 46, + opfunc: opcodePushData}, + OP_DATA_46: {value: OP_DATA_46, name: "OP_DATA_46", length: 47, + opfunc: opcodePushData}, + OP_DATA_47: {value: OP_DATA_47, name: "OP_DATA_47", length: 48, + opfunc: opcodePushData}, + OP_DATA_48: {value: OP_DATA_48, name: "OP_DATA_48", length: 49, + opfunc: opcodePushData}, + OP_DATA_49: {value: OP_DATA_49, name: "OP_DATA_49", length: 50, + opfunc: opcodePushData}, + OP_DATA_50: {value: OP_DATA_50, name: "OP_DATA_50", length: 51, + opfunc: opcodePushData}, + OP_DATA_51: {value: OP_DATA_51, name: "OP_DATA_51", length: 52, + opfunc: opcodePushData}, + OP_DATA_52: {value: OP_DATA_52, name: "OP_DATA_52", length: 53, + opfunc: opcodePushData}, + OP_DATA_53: {value: OP_DATA_53, name: "OP_DATA_53", length: 54, + opfunc: opcodePushData}, + OP_DATA_54: {value: OP_DATA_54, name: "OP_DATA_54", length: 55, + opfunc: opcodePushData}, + OP_DATA_55: {value: OP_DATA_55, name: "OP_DATA_55", length: 56, + opfunc: opcodePushData}, + OP_DATA_56: {value: OP_DATA_56, name: "OP_DATA_56", length: 57, + opfunc: opcodePushData}, + OP_DATA_57: {value: OP_DATA_57, name: "OP_DATA_57", length: 58, + opfunc: opcodePushData}, + OP_DATA_58: {value: OP_DATA_58, name: "OP_DATA_58", length: 59, + opfunc: opcodePushData}, + OP_DATA_59: {value: OP_DATA_59, name: "OP_DATA_59", length: 60, + opfunc: opcodePushData}, + OP_DATA_60: {value: OP_DATA_60, name: "OP_DATA_60", length: 61, + opfunc: opcodePushData}, + OP_DATA_61: {value: OP_DATA_61, name: "OP_DATA_61", length: 62, + opfunc: opcodePushData}, + OP_DATA_62: {value: OP_DATA_62, name: "OP_DATA_62", length: 63, + opfunc: opcodePushData}, + OP_DATA_63: {value: OP_DATA_63, name: "OP_DATA_63", length: 64, + opfunc: opcodePushData}, + OP_DATA_64: {value: OP_DATA_64, name: "OP_DATA_64", length: 65, + opfunc: opcodePushData}, + OP_DATA_65: {value: OP_DATA_65, name: "OP_DATA_65", length: 66, + opfunc: opcodePushData}, + OP_DATA_66: {value: OP_DATA_66, name: "OP_DATA_66", length: 67, + opfunc: opcodePushData}, + OP_DATA_67: {value: OP_DATA_67, name: "OP_DATA_67", length: 68, + opfunc: opcodePushData}, + OP_DATA_68: {value: OP_DATA_68, name: "OP_DATA_68", length: 69, + opfunc: opcodePushData}, + OP_DATA_69: {value: OP_DATA_69, name: "OP_DATA_69", length: 70, + opfunc: opcodePushData}, + OP_DATA_70: {value: OP_DATA_70, name: "OP_DATA_70", length: 71, + opfunc: opcodePushData}, + OP_DATA_71: {value: OP_DATA_71, name: "OP_DATA_71", length: 72, + opfunc: opcodePushData}, + OP_DATA_72: {value: OP_DATA_72, name: "OP_DATA_72", length: 73, + opfunc: opcodePushData}, + OP_DATA_73: {value: OP_DATA_73, name: "OP_DATA_73", length: 74, + opfunc: opcodePushData}, + OP_DATA_74: {value: OP_DATA_74, name: "OP_DATA_74", length: 75, + opfunc: opcodePushData}, + OP_DATA_75: {value: OP_DATA_75, name: "OP_DATA_75", length: 76, + opfunc: opcodePushData}, + OP_PUSHDATA1: {value: OP_PUSHDATA1, name: "OP_PUSHDATA1", length: -1, + opfunc: opcodePushData}, + OP_PUSHDATA2: {value: OP_PUSHDATA2, name: "OP_PUSHDATA2", length: -2, + opfunc: opcodePushData}, + OP_PUSHDATA4: {value: OP_PUSHDATA4, name: "OP_PUSHDATA4", length: -4, + opfunc: opcodePushData}, + OP_1NEGATE: {value: OP_1NEGATE, name: "OP_1NEGATE", length: 1, + opfunc: opcode1Negate}, + OP_RESERVED: {value: OP_RESERVED, name: "OP_RESERVED", length: 1, + opfunc: opcodeReserved}, + OP_TRUE: {value: OP_TRUE, name: "OP_1", length: 1, + opfunc: opcodeN}, + OP_2: {value: OP_2, name: "OP_2", length: 1, + opfunc: opcodeN}, + OP_3: {value: OP_3, name: "OP_3", length: 1, + opfunc: opcodeN}, + OP_4: {value: OP_4, name: "OP_4", length: 1, + opfunc: opcodeN}, + OP_5: {value: OP_5, name: "OP_5", length: 1, + opfunc: opcodeN}, + OP_6: {value: OP_6, name: "OP_6", length: 1, + opfunc: opcodeN}, + OP_7: {value: OP_7, name: "OP_7", length: 1, + opfunc: opcodeN}, + OP_8: {value: OP_8, name: "OP_8", length: 1, + opfunc: opcodeN}, + OP_9: {value: OP_9, name: "OP_9", length: 1, + opfunc: opcodeN}, + OP_10: {value: OP_10, name: "OP_10", length: 1, + opfunc: opcodeN}, + OP_11: {value: OP_11, name: "OP_11", length: 1, + opfunc: opcodeN}, + OP_12: {value: OP_12, name: "OP_12", length: 1, + opfunc: opcodeN}, + OP_13: {value: OP_13, name: "OP_13", length: 1, + opfunc: opcodeN}, + OP_14: {value: OP_14, name: "OP_14", length: 1, + opfunc: opcodeN}, + OP_15: {value: OP_15, name: "OP_15", length: 1, + opfunc: opcodeN}, + OP_16: {value: OP_16, name: "OP_16", length: 1, + opfunc: opcodeN}, + OP_NOP: {value: OP_NOP, name: "OP_NOP", length: 1, + opfunc: opcodeNop}, + OP_VER: {value: OP_VER, name: "OP_VER", length: 1, + opfunc: opcodeReserved}, + OP_IF: {value: OP_IF, name: "OP_IF", length: 1, + opfunc: opcodeIf}, + OP_NOTIF: {value: OP_NOTIF, name: "OP_NOTIF", length: 1, + opfunc: opcodeNotIf}, + OP_VERIF: {value: OP_VERIF, name: "OP_VERIF", length: 1, + opfunc: opcodeReserved}, + OP_VERNOTIF: {value: OP_VERNOTIF, name: "OP_VERNOTIF", length: 1, + opfunc: opcodeReserved}, + OP_ELSE: {value: OP_ELSE, name: "OP_ELSE", length: 1, + opfunc: opcodeElse}, + OP_ENDIF: {value: OP_ENDIF, name: "OP_ENDIF", length: 1, + opfunc: opcodeEndif}, + OP_VERIFY: {value: OP_VERIFY, name: "OP_VERIFY", length: 1, + opfunc: opcodeVerify}, + OP_RETURN: {value: OP_RETURN, name: "OP_RETURN", length: 1, + opfunc: opcodeReturn}, + OP_TOALTSTACK: {value: OP_TOALTSTACK, name: "OP_TOALTSTACK", length: 1, + opfunc: opcodeToAltStack}, + OP_FROMALTSTACK: {value: OP_FROMALTSTACK, name: "OP_FROMALTSTACK", length: 1, + opfunc: opcodeFromAltStack}, + OP_2DROP: {value: OP_2DROP, name: "OP_2DROP", length: 1, + opfunc: opcode2Drop}, + OP_2DUP: {value: OP_2DUP, name: "OP_2DUP", length: 1, + opfunc: opcode2Dup}, + OP_3DUP: {value: OP_3DUP, name: "OP_3DUP", length: 1, + opfunc: opcode3Dup}, + OP_2OVER: {value: OP_2OVER, name: "OP_2OVER", length: 1, + opfunc: opcode2Over}, + OP_2ROT: {value: OP_2ROT, name: "OP_2ROT", length: 1, + opfunc: opcode2Rot}, + OP_2SWAP: {value: OP_2SWAP, name: "OP_2SWAP", length: 1, + opfunc: opcode2Swap}, + OP_IFDUP: {value: OP_IFDUP, name: "OP_IFDUP", length: 1, + opfunc: opcodeIfDup}, + OP_DEPTH: {value: OP_DEPTH, name: "OP_DEPTH", length: 1, + opfunc: opcodeDepth}, + OP_DROP: {value: OP_DROP, name: "OP_DROP", length: 1, + opfunc: opcodeDrop}, + OP_DUP: {value: OP_DUP, name: "OP_DUP", length: 1, + opfunc: opcodeDup}, + OP_NIP: {value: OP_NIP, name: "OP_NIP", length: 1, + opfunc: opcodeNip}, + OP_OVER: {value: OP_OVER, name: "OP_OVER", length: 1, + opfunc: opcodeOver}, + OP_PICK: {value: OP_PICK, name: "OP_PICK", length: 1, + opfunc: opcodePick}, + OP_ROLL: {value: OP_ROLL, name: "OP_ROLL", length: 1, + opfunc: opcodeRoll}, + OP_ROT: {value: OP_ROT, name: "OP_ROT", length: 1, + opfunc: opcodeRot}, + OP_SWAP: {value: OP_SWAP, name: "OP_SWAP", length: 1, + opfunc: opcodeSwap}, + OP_TUCK: {value: OP_TUCK, name: "OP_TUCK", length: 1, + opfunc: opcodeTuck}, + OP_CAT: {value: OP_CAT, name: "OP_CAT", length: 1, + opfunc: opcodeDisabled}, + OP_SUBSTR: {value: OP_SUBSTR, name: "OP_SUBSTR", length: 1, + opfunc: opcodeDisabled}, + OP_LEFT: {value: OP_LEFT, name: "OP_LEFT", length: 1, + opfunc: opcodeDisabled}, + OP_RIGHT: {value: OP_RIGHT, name: "OP_RIGHT", length: 1, + opfunc: opcodeDisabled}, + OP_SIZE: {value: OP_SIZE, name: "OP_SIZE", length: 1, + opfunc: opcodeSize}, + OP_INVERT: {value: OP_INVERT, name: "OP_INVERT", length: 1, + opfunc: opcodeDisabled}, + OP_AND: {value: OP_AND, name: "OP_AND", length: 1, + opfunc: opcodeDisabled}, + OP_OR: {value: OP_OR, name: "OP_OR", length: 1, + opfunc: opcodeDisabled}, + OP_XOR: {value: OP_XOR, name: "OP_XOR", length: 1, + opfunc: opcodeDisabled}, + OP_EQUAL: {value: OP_EQUAL, name: "OP_EQUAL", length: 1, + opfunc: opcodeEqual}, + OP_EQUALVERIFY: {value: OP_EQUALVERIFY, name: "OP_EQUALVERIFY", length: 1, + opfunc: opcodeEqualVerify}, + OP_RESERVED1: {value: OP_RESERVED1, name: "OP_RESERVED1", length: 1, + opfunc: opcodeReserved}, + OP_RESERVED2: {value: OP_RESERVED2, name: "OP_RESERVED2", length: 1, + opfunc: opcodeReserved}, + OP_1ADD: {value: OP_1ADD, name: "OP_1ADD", length: 1, + opfunc: opcode1Add}, + OP_1SUB: {value: OP_1SUB, name: "OP_1SUB", length: 1, + opfunc: opcode1Sub}, + OP_2MUL: {value: OP_2MUL, name: "OP_2MUL", length: 1, + opfunc: opcodeDisabled}, + OP_2DIV: {value: OP_2DIV, name: "OP_2DIV", length: 1, + opfunc: opcodeDisabled}, + OP_NEGATE: {value: OP_NEGATE, name: "OP_NEGATE", length: 1, + opfunc: opcodeNegate}, + OP_ABS: {value: OP_ABS, name: "OP_ABS", length: 1, + opfunc: opcodeAbs}, + OP_NOT: {value: OP_NOT, name: "OP_NOT", length: 1, + opfunc: opcodeNot}, + OP_0NOTEQUAL: {value: OP_0NOTEQUAL, name: "OP_0NOTEQUAL", length: 1, + opfunc: opcode0NotEqual}, + OP_ADD: {value: OP_ADD, name: "OP_ADD", length: 1, + opfunc: opcodeAdd}, + OP_SUB: {value: OP_SUB, name: "OP_SUB", length: 1, + opfunc: opcodeSub}, + OP_MUL: {value: OP_MUL, name: "OP_MUL", length: 1, + opfunc: opcodeDisabled}, + OP_DIV: {value: OP_DIV, name: "OP_DIV", length: 1, + opfunc: opcodeDisabled}, + OP_MOD: {value: OP_MOD, name: "OP_MOD", length: 1, + opfunc: opcodeDisabled}, + OP_LSHIFT: {value: OP_LSHIFT, name: "OP_LSHIFT", length: 1, + opfunc: opcodeDisabled}, + OP_RSHIFT: {value: OP_RSHIFT, name: "OP_RSHIFT", length: 1, + opfunc: opcodeDisabled}, + OP_BOOLAND: {value: OP_BOOLAND, name: "OP_BOOLAND", length: 1, + opfunc: opcodeBoolAnd}, + OP_BOOLOR: {value: OP_BOOLOR, name: "OP_BOOLOR", length: 1, + opfunc: opcodeBoolOr}, + OP_NUMEQUAL: {value: OP_NUMEQUAL, name: "OP_NUMEQUAL", length: 1, + opfunc: opcodeNumEqual}, + OP_NUMEQUALVERIFY: {value: OP_NUMEQUALVERIFY, name: "OP_NUMEQUALVERIFY", length: 1, + opfunc: opcodeNumEqualVerify}, + OP_NUMNOTEQUAL: {value: OP_NUMNOTEQUAL, name: "OP_NUMNOTEQUAL", length: 1, + opfunc: opcodeNumNotEqual}, + OP_LESSTHAN: {value: OP_LESSTHAN, name: "OP_LESSTHAN", length: 1, + opfunc: opcodeLessThan}, + OP_GREATERTHAN: {value: OP_GREATERTHAN, name: "OP_GREATERTHAN", length: 1, + opfunc: opcodeGreaterThan}, + OP_LESSTHANOREQUAL: {value: OP_LESSTHANOREQUAL, name: "OP_LESSTHANOREQUAL", length: 1, + opfunc: opcodeLessThanOrEqual}, + OP_GREATERTHANOREQUAL: {value: OP_GREATERTHANOREQUAL, name: "OP_GREATERTHANOREQUAL", length: 1, + opfunc: opcodeGreaterThanOrEqual}, + OP_MIN: {value: OP_MIN, name: "OP_MIN", length: 1, + opfunc: opcodeMin}, + OP_MAX: {value: OP_MAX, name: "OP_MAX", length: 1, + opfunc: opcodeMax}, + OP_WITHIN: {value: OP_WITHIN, name: "OP_WITHIN", length: 1, + opfunc: opcodeWithin}, + OP_RIPEMD160: {value: OP_RIPEMD160, name: "OP_RIPEMD160", length: 1, + opfunc: opcodeRipemd160}, + OP_SHA1: {value: OP_SHA1, name: "OP_SHA1", length: 1, + opfunc: opcodeSha1}, + OP_SHA256: {value: OP_SHA256, name: "OP_SHA256", length: 1, + opfunc: opcodeSha256}, + OP_HASH160: {value: OP_HASH160, name: "OP_HASH160", length: 1, + opfunc: opcodeHash160}, + OP_HASH256: {value: OP_HASH256, name: "OP_HASH256", length: 1, + opfunc: opcodeHash256}, + OP_CODESEPARATOR: {value: OP_CODESEPARATOR, name: "OP_CODESEPARATOR", length: 1, + opfunc: opcodeCodeSeparator}, + OP_CHECKSIG: {value: OP_CHECKSIG, name: "OP_CHECKSIG", length: 1, + opfunc: opcodeCheckSig}, + OP_CHECKSIGVERIFY: {value: OP_CHECKSIGVERIFY, name: "OP_CHECKSIGVERIFY", length: 1, + opfunc: opcodeCheckSigVerify}, + OP_CHECKMULTISIG: {value: OP_CHECKMULTISIG, name: "OP_CHECKMULTISIG", length: 1, + opfunc: opcodeCheckMultiSig}, + OP_CHECKMULTISIGVERIFY: {value: OP_CHECKMULTISIGVERIFY, name: "OP_CHECKMULTISIGVERIFY", length: 1, + + opfunc: opcodeCheckMultiSigVerify}, + OP_NOP1: {value: OP_NOP1, name: "OP_NOP1", length: 1, + opfunc: opcodeNop}, + OP_NOP2: {value: OP_NOP2, name: "OP_NOP2", length: 1, + opfunc: opcodeNop}, + OP_NOP3: {value: OP_NOP3, name: "OP_NOP3", length: 1, + opfunc: opcodeNop}, + OP_NOP4: {value: OP_NOP4, name: "OP_NOP4", length: 1, + opfunc: opcodeNop}, + OP_NOP5: {value: OP_NOP5, name: "OP_NOP5", length: 1, + opfunc: opcodeNop}, + OP_NOP6: {value: OP_NOP6, name: "OP_NOP6", length: 1, + opfunc: opcodeNop}, + OP_NOP7: {value: OP_NOP7, name: "OP_NOP7", length: 1, + opfunc: opcodeNop}, + OP_NOP8: {value: OP_NOP8, name: "OP_NOP8", length: 1, + opfunc: opcodeNop}, + OP_NOP9: {value: OP_NOP9, name: "OP_NOP9", length: 1, + opfunc: opcodeNop}, + OP_NOP10: {value: OP_NOP10, name: "OP_NOP10", length: 1, + opfunc: opcodeNop}, + OP_UNKNOWN186: {value: OP_UNKNOWN186, name: "OP_UNKNOWN186", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN187: {value: OP_UNKNOWN187, name: "OP_UNKNOWN187", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN188: {value: OP_UNKNOWN188, name: "OP_UNKNOWN188", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN189: {value: OP_UNKNOWN189, name: "OP_UNKNOWN189", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN190: {value: OP_UNKNOWN190, name: "OP_UNKNOWN190", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN191: {value: OP_UNKNOWN191, name: "OP_UNKNOWN191", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN192: {value: OP_UNKNOWN192, name: "OP_UNKNOWN192", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN193: {value: OP_UNKNOWN193, name: "OP_UNKNOWN193", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN194: {value: OP_UNKNOWN194, name: "OP_UNKNOWN194", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN195: {value: OP_UNKNOWN195, name: "OP_UNKNOWN195", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN196: {value: OP_UNKNOWN196, name: "OP_UNKNOWN196", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN197: {value: OP_UNKNOWN197, name: "OP_UNKNOWN197", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN198: {value: OP_UNKNOWN198, name: "OP_UNKNOWN198", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN199: {value: OP_UNKNOWN199, name: "OP_UNKNOWN199", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN200: {value: OP_UNKNOWN200, name: "OP_UNKNOWN200", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN201: {value: OP_UNKNOWN201, name: "OP_UNKNOWN201", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN202: {value: OP_UNKNOWN202, name: "OP_UNKNOWN202", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN203: {value: OP_UNKNOWN203, name: "OP_UNKNOWN203", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN204: {value: OP_UNKNOWN204, name: "OP_UNKNOWN204", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN205: {value: OP_UNKNOWN205, name: "OP_UNKNOWN205", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN206: {value: OP_UNKNOWN206, name: "OP_UNKNOWN206", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN207: {value: OP_UNKNOWN207, name: "OP_UNKNOWN207", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN208: {value: OP_UNKNOWN208, name: "OP_UNKNOWN208", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN209: {value: OP_UNKNOWN209, name: "OP_UNKNOWN209", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN210: {value: OP_UNKNOWN210, name: "OP_UNKNOWN210", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN211: {value: OP_UNKNOWN211, name: "OP_UNKNOWN211", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN212: {value: OP_UNKNOWN212, name: "OP_UNKNOWN212", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN213: {value: OP_UNKNOWN213, name: "OP_UNKNOWN213", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN214: {value: OP_UNKNOWN214, name: "OP_UNKNOWN214", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN215: {value: OP_UNKNOWN215, name: "OP_UNKNOWN215", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN216: {value: OP_UNKNOWN216, name: "OP_UNKNOWN216", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN217: {value: OP_UNKNOWN217, name: "OP_UNKNOWN217", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN218: {value: OP_UNKNOWN218, name: "OP_UNKNOWN218", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN219: {value: OP_UNKNOWN219, name: "OP_UNKNOWN219", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN220: {value: OP_UNKNOWN220, name: "OP_UNKNOWN220", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN221: {value: OP_UNKNOWN221, name: "OP_UNKNOWN221", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN222: {value: OP_UNKNOWN222, name: "OP_UNKNOWN222", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN223: {value: OP_UNKNOWN223, name: "OP_UNKNOWN223", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN224: {value: OP_UNKNOWN224, name: "OP_UNKNOWN224", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN225: {value: OP_UNKNOWN225, name: "OP_UNKNOWN225", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN226: {value: OP_UNKNOWN226, name: "OP_UNKNOWN226", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN227: {value: OP_UNKNOWN227, name: "OP_UNKNOWN227", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN228: {value: OP_UNKNOWN228, name: "OP_UNKNOWN228", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN229: {value: OP_UNKNOWN229, name: "OP_UNKNOWN229", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN230: {value: OP_UNKNOWN230, name: "OP_UNKNOWN230", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN231: {value: OP_UNKNOWN231, name: "OP_UNKNOWN231", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN232: {value: OP_UNKNOWN232, name: "OP_UNKNOWN232", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN233: {value: OP_UNKNOWN233, name: "OP_UNKNOWN233", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN234: {value: OP_UNKNOWN234, name: "OP_UNKNOWN234", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN235: {value: OP_UNKNOWN235, name: "OP_UNKNOWN235", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN236: {value: OP_UNKNOWN236, name: "OP_UNKNOWN236", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN237: {value: OP_UNKNOWN237, name: "OP_UNKNOWN237", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN238: {value: OP_UNKNOWN238, name: "OP_UNKNOWN238", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN239: {value: OP_UNKNOWN239, name: "OP_UNKNOWN239", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN240: {value: OP_UNKNOWN240, name: "OP_UNKNOWN240", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN241: {value: OP_UNKNOWN241, name: "OP_UNKNOWN241", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN242: {value: OP_UNKNOWN242, name: "OP_UNKNOWN242", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN243: {value: OP_UNKNOWN243, name: "OP_UNKNOWN243", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN244: {value: OP_UNKNOWN244, name: "OP_UNKNOWN244", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN245: {value: OP_UNKNOWN245, name: "OP_UNKNOWN245", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN246: {value: OP_UNKNOWN246, name: "OP_UNKNOWN246", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN247: {value: OP_UNKNOWN247, name: "OP_UNKNOWN247", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN248: {value: OP_UNKNOWN248, name: "OP_UNKNOWN248", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN249: {value: OP_UNKNOWN249, name: "OP_UNKNOWN249", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN250: {value: OP_UNKNOWN250, name: "OP_UNKNOWN250", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN251: {value: OP_UNKNOWN251, name: "OP_UNKNOWN251", length: 1, + opfunc: opcodeInvalid}, + OP_UNKNOWN252: {value: OP_UNKNOWN252, name: "OP_UNKNOWN252", length: 1, + opfunc: opcodeInvalid}, + OP_PUBKEYHASH: {value: OP_PUBKEYHASH, name: "OP_PUBKEYHASH", length: 1, + opfunc: opcodeInvalid}, + OP_PUBKEY: {value: OP_PUBKEY, name: "OP_PUBKEY", length: 1, + opfunc: opcodeInvalid}, + OP_INVALIDOPCODE: {value: OP_INVALIDOPCODE, name: "OP_INVALIDOPCODE", length: 1, + opfunc: opcodeInvalid}, +} + +// opcodeOnelineRepls defines opcode names which are replaced when doing a +// one-line disassembly. This is done to match the output of the reference +// implementation while not changing the opcode names in the nicer full +// disassembly. +var opcodeOnelineRepls = map[string]string{ + "OP_1NEGATE": "-1", + "OP_0": "0", + "OP_1": "1", + "OP_2": "2", + "OP_3": "3", + "OP_4": "4", + "OP_5": "5", + "OP_6": "6", + "OP_7": "7", + "OP_8": "8", + "OP_9": "9", + "OP_10": "10", + "OP_11": "11", + "OP_12": "12", + "OP_13": "13", + "OP_14": "14", + "OP_15": "15", + "OP_16": "16", +} + +type parsedOpcode struct { + opcode *opcode + data []byte + opfunc func(op parsedOpcode, s Script) error +} + +// The following opcodes are disabled and are thus always bad to see in the +// instruction stream (even if turned off by a conditional). +func (pop *parsedOpcode) disabled() bool { + switch pop.opcode.value { + case OP_CAT: + return true + case OP_SUBSTR: + return true + case OP_LEFT: + return true + case OP_RIGHT: + return true + case OP_INVERT: + return true + case OP_AND: + return true + case OP_OR: + return true + case OP_XOR: + return true + case OP_2MUL: + return true + case OP_2DIV: + return true + case OP_MUL: + return true + case OP_DIV: + return true + case OP_MOD: + return true + case OP_LSHIFT: + return true + case OP_RSHIFT: + return true + default: + return false + } +} + +// The following opcodes are always illegal when passed over by the program +// counter even if in a non-executed branch. (it isn't a coincidence that they +// are conditionals). +func (pop *parsedOpcode) alwaysIllegal() bool { + switch pop.opcode.value { + case OP_VERIF: + return true + case OP_VERNOTIF: + return true + default: + return false + } +} + +// The following opcode are conditional and thus change the conditional +// execution stack state when passed. +func (pop *parsedOpcode) conditional() bool { + switch pop.opcode.value { + case OP_IF: + return true + case OP_NOTIF: + return true + case OP_ELSE: + return true + case OP_ENDIF: + return true + default: + return false + } +} + +// exec peforms execution on the opcode. It takes into account whether or not +// it is hidden by conditionals, but some rules still must be tested in this +// case. +func (pop *parsedOpcode) exec(s *Script) error { + // Disabled opcodes are ``fail on program counter''. + if pop.disabled() { + return ErrStackOpDisabled + } + + // Always-illegal opcodes are ``fail on program counter''. + if pop.alwaysIllegal() { + return ErrStackReservedOpcode + } + + // Note that this includes OP_RESERVED which counts as a push operation. + if pop.opcode.value > OP_16 { + s.numOps++ + if s.numOps > MaxOpsPerScript { + return ErrStackTooManyOperations + } + + } else if len(pop.data) > MaxScriptElementSize { + return ErrStackElementTooBig + } + + // If we are not a conditional opcode and we aren't executing, then + // we are done now. + if s.condStack[0] != OpCondTrue && !pop.conditional() { + return nil + } + return pop.opcode.opfunc(pop, s) +} + +func (pop *parsedOpcode) print(oneline bool) string { + // The reference implementation one-line disassembly replaces opcodes + // which represent values (e.g. OP_0 through OP_16 and OP_1NEGATE) + // with the raw value. However, when not doing a one-line dissassembly, + // we prefer to show the actual opcode names. Thus, only replace the + // opcodes in question when the oneline flag is set. + opcodeName := pop.opcode.name + if oneline { + if replName, ok := opcodeOnelineRepls[opcodeName]; ok { + opcodeName = replName + } + } + + retString := opcodeName + if pop.opcode.length == 1 { + return retString + } + if oneline { + retString = "" + } + if !oneline && pop.opcode.length < 0 { + //add length to the end of retString + retString += fmt.Sprintf(" 0x%0*x", 2*-pop.opcode.length, + len(pop.data)) + } + for _, val := range pop.data { + if !oneline { + retString += " " + } + retString += fmt.Sprintf("%02x", val) + } + return retString +} + +func (pop *parsedOpcode) bytes() ([]byte, error) { + var retbytes []byte + if pop.opcode.length > 0 { + retbytes = make([]byte, 1, pop.opcode.length) + } else { + retbytes = make([]byte, 1, 1+len(pop.data)- + pop.opcode.length) + } + + retbytes[0] = pop.opcode.value + if pop.opcode.length == 1 { + if len(pop.data) != 0 { + return nil, ErrStackInvalidOpcode + } + return retbytes, nil + } + nbytes := pop.opcode.length + if pop.opcode.length < 0 { + l := len(pop.data) + // tempting just to hardcode to avoid the complexity here. + switch pop.opcode.length { + case -1: + retbytes = append(retbytes, byte(l)) + nbytes = int(retbytes[1]) + len(retbytes) + case -2: + retbytes = append(retbytes, byte(l&0xff), + byte(l>>8&0xff)) + nbytes = int(binary.LittleEndian.Uint16(retbytes[1:])) + + len(retbytes) + case -4: + retbytes = append(retbytes, byte(l&0xff), + byte((l>>8)&0xff), byte((l>>16)&0xff), + byte((l>>24)&0xff)) + nbytes = int(binary.LittleEndian.Uint32(retbytes[1:])) + + len(retbytes) + } + } + + retbytes = append(retbytes, pop.data...) + + if len(retbytes) != nbytes { + return nil, ErrStackInvalidOpcode + } + + return retbytes, nil +} + +// opcode implementation functions from here + +func opcodeDisabled(op *parsedOpcode, s *Script) error { + return ErrStackOpDisabled +} + +func opcodeReserved(op *parsedOpcode, s *Script) error { + return ErrStackReservedOpcode +} + +// Recognised opcode, but for bitcoind internal use only. +func opcodeInvalid(op *parsedOpcode, s *Script) error { + return ErrStackInvalidOpcode +} + +func opcodeFalse(op *parsedOpcode, s *Script) error { + s.dstack.PushByteArray([]byte("")) + + return nil +} + +func opcodePushData(op *parsedOpcode, s *Script) error { + s.dstack.PushByteArray(op.data) + return nil +} + +func opcode1Negate(op *parsedOpcode, s *Script) error { + s.dstack.PushInt(big.NewInt(-1)) + return nil +} + +func opcodeN(op *parsedOpcode, s *Script) error { + // 16 consecutive opcodes add increasing numbers to the stack. + s.dstack.PushInt(big.NewInt(int64(op.opcode.value - (OP_1 - 1)))) + return nil +} + +func opcodeNop(op *parsedOpcode, s *Script) error { + switch op.opcode.value { + case OP_NOP1, OP_NOP2, OP_NOP3, OP_NOP4, OP_NOP5, + OP_NOP6, OP_NOP7, OP_NOP8, OP_NOP9, OP_NOP10: + if s.discourageUpgradableNops { + return fmt.Errorf("%s reserved for soft-fork upgrades", opcodemap[op.opcode.value].name) + } + } + return nil +} + +// opcodeIf computes true/false based on the value on the stack and pushes +// the condition on the condStack (conditional execution stack) +func opcodeIf(op *parsedOpcode, s *Script) error { + // opcodeIf will be executed even if it is on the non-execute side + // of the conditional, this is so proper nesting is maintained + var condval int + if s.condStack[0] == OpCondTrue { + ok, err := s.dstack.PopBool() + if err != nil { + return err + } + if ok { + condval = OpCondTrue + } + } else { + condval = OpCondSkip + } + cond := []int{condval} + // push condition to the 'head' of the slice + s.condStack = append(cond, s.condStack...) + // TODO(drahn) check if a maximum condtitional stack limit exists + return nil +} + +// opcodeNotIf computes true/false based on the value on the stack and pushes +// the (inverted) condition on the condStack (conditional execution stack) +func opcodeNotIf(op *parsedOpcode, s *Script) error { + // opcodeIf will be executed even if it is on the non-execute side + // of the conditional, this is so proper nesting is maintained + var condval int + if s.condStack[0] == OpCondTrue { + ok, err := s.dstack.PopBool() + if err != nil { + return err + } + if !ok { + condval = OpCondTrue + } + } else { + condval = OpCondSkip + } + cond := []int{condval} + // push condition to the 'head' of the slice + s.condStack = append(cond, s.condStack...) + // TODO(drahn) check if a maximum condtitional stack limit exists + return nil +} + +// opcodeElse inverts conditional execution for other half of if/else/endif +func opcodeElse(op *parsedOpcode, s *Script) error { + if len(s.condStack) < 2 { + // intial true cannot be toggled, only pushed conditionals + return ErrStackNoIf + } + + switch s.condStack[0] { + case OpCondTrue: + s.condStack[0] = OpCondFalse + case OpCondFalse: + s.condStack[0] = OpCondTrue + case OpCondSkip: + // value doesn't change in skip + } + return nil +} + +// opcodeEndif terminates a conditional block, removing the value from the +// conditional execution stack. +func opcodeEndif(op *parsedOpcode, s *Script) error { + if len(s.condStack) < 2 { + // intial true cannot be popped, only pushed conditionals + return ErrStackNoIf + } + + stk := make([]int, len(s.condStack)-1, len(s.condStack)-1) + copy(stk, s.condStack[1:]) + s.condStack = stk + return nil +} + +func opcodeVerify(op *parsedOpcode, s *Script) error { + verified, err := s.dstack.PopBool() + if err != nil { + return err + } + + if verified != true { + return ErrStackVerifyFailed + } + return nil +} + +func opcodeReturn(op *parsedOpcode, s *Script) error { + return ErrStackEarlyReturn +} + +func opcodeToAltStack(op *parsedOpcode, s *Script) error { + so, err := s.dstack.PopByteArray() + if err != nil { + return err + } + s.astack.PushByteArray(so) + + return nil +} + +func opcodeFromAltStack(op *parsedOpcode, s *Script) error { + so, err := s.astack.PopByteArray() + if err != nil { + return err + } + s.dstack.PushByteArray(so) + + return nil +} + +func opcode2Drop(op *parsedOpcode, s *Script) error { + return s.dstack.DropN(2) +} + +func opcode2Dup(op *parsedOpcode, s *Script) error { + return s.dstack.DupN(2) +} + +func opcode3Dup(op *parsedOpcode, s *Script) error { + return s.dstack.DupN(3) +} + +func opcode2Over(op *parsedOpcode, s *Script) error { + return s.dstack.OverN(2) +} + +func opcode2Rot(op *parsedOpcode, s *Script) error { + return s.dstack.RotN(2) +} + +func opcode2Swap(op *parsedOpcode, s *Script) error { + return s.dstack.SwapN(2) +} + +func opcodeIfDup(op *parsedOpcode, s *Script) error { + val, err := s.dstack.PeekInt(0) + if err != nil { + return err + } + + // Push copy of data iff it isn't zero + if val.Sign() != 0 { + s.dstack.PushInt(val) + } + + return nil +} + +func opcodeDepth(op *parsedOpcode, s *Script) error { + s.dstack.PushInt(big.NewInt(int64(s.dstack.Depth()))) + return nil +} + +func opcodeDrop(op *parsedOpcode, s *Script) error { + return s.dstack.DropN(1) +} + +func opcodeDup(op *parsedOpcode, s *Script) error { + return s.dstack.DupN(1) +} + +func opcodeNip(op *parsedOpcode, s *Script) error { + return s.dstack.NipN(1) +} + +func opcodeOver(op *parsedOpcode, s *Script) error { + return s.dstack.OverN(1) +} + +// Copy object N items back in the stack to the top. Where N is the value in +// the top of the stack. +func opcodePick(op *parsedOpcode, s *Script) error { + pidx, err := s.dstack.PopInt() + if err != nil { + return err + } + + // PopInt promises that the int returned is 32 bit. + val := int(pidx.Int64()) + + return s.dstack.PickN(val) +} + +// Move object N items back in the stack to the top. Where N is the value in +// the top of the stack. +func opcodeRoll(op *parsedOpcode, s *Script) error { + ridx, err := s.dstack.PopInt() + if err != nil { + return err + } + + // PopInt promises that the int returned is 32 bit. + val := int(ridx.Int64()) + + return s.dstack.RollN(val) +} + +// Rotate top three items on the stack to the left. +// e.g. 1,2,3 -> 2,3,1 +func opcodeRot(op *parsedOpcode, s *Script) error { + return s.dstack.RotN(1) +} + +// Swap the top two items on the stack: 1,2 -> 2,1 +func opcodeSwap(op *parsedOpcode, s *Script) error { + return s.dstack.SwapN(1) +} + +// The item at the top of the stack is copied and inserted before the +// second-to-top item. e.g.: 2,1, -> 2,1,2 +func opcodeTuck(op *parsedOpcode, s *Script) error { + return s.dstack.Tuck() +} + +// Push the size of the item on top of the stack onto the stack. +func opcodeSize(op *parsedOpcode, s *Script) error { + i, err := s.dstack.PeekByteArray(0) + if err != nil { + return err + } + + s.dstack.PushInt(big.NewInt(int64(len(i)))) + return nil +} + +func opcodeEqual(op *parsedOpcode, s *Script) error { + a, err := s.dstack.PopByteArray() + if err != nil { + return err + } + b, err := s.dstack.PopByteArray() + if err != nil { + return err + } + + s.dstack.PushBool(bytes.Equal(a, b)) + return nil +} + +func opcodeEqualVerify(op *parsedOpcode, s *Script) error { + err := opcodeEqual(op, s) + if err == nil { + err = opcodeVerify(op, s) + } + return err +} + +func opcode1Add(op *parsedOpcode, s *Script) error { + m, err := s.dstack.PopInt() + if err != nil { + return err + } + + s.dstack.PushInt(new(big.Int).Add(m, big.NewInt(1))) + + return nil +} + +func opcode1Sub(op *parsedOpcode, s *Script) error { + m, err := s.dstack.PopInt() + if err != nil { + return err + } + s.dstack.PushInt(new(big.Int).Sub(m, big.NewInt(1))) + + return nil +} + +func opcodeNegate(op *parsedOpcode, s *Script) error { + // XXX when we remove types just flip the 0x80 bit of msb + m, err := s.dstack.PopInt() + if err != nil { + return err + } + + s.dstack.PushInt(new(big.Int).Neg(m)) + return nil +} + +func opcodeAbs(op *parsedOpcode, s *Script) error { + // XXX when we remove types just &= ~0x80 on msb + m, err := s.dstack.PopInt() + if err != nil { + return err + } + + s.dstack.PushInt(new(big.Int).Abs(m)) + + return nil +} + +// If then input is 0 or 1, it is flipped. Otherwise the output will be 0. +// (n.b. official client just has 1 is 0, else 0) +func opcodeNot(op *parsedOpcode, s *Script) error { + m, err := s.dstack.PopInt() + if err != nil { + return err + } + if m.Sign() == 0 { + s.dstack.PushInt(big.NewInt(1)) + } else { + s.dstack.PushInt(big.NewInt(0)) + } + return nil +} + +// opcode returns 0 if the input is 0, 1 otherwise. +func opcode0NotEqual(op *parsedOpcode, s *Script) error { + m, err := s.dstack.PopInt() + if err != nil { + return err + } + if m.Sign() != 0 { + m.SetInt64(1) + } + s.dstack.PushInt(m) + + return nil +} + +// Push result of adding top two entries on stack +func opcodeAdd(op *parsedOpcode, s *Script) error { + v0, err := s.dstack.PopInt() + if err != nil { + return err + } + + v1, err := s.dstack.PopInt() + if err != nil { + return err + } + + s.dstack.PushInt(new(big.Int).Add(v0, v1)) + return nil +} + +// Push result of subtracting 2nd entry on stack from first. +func opcodeSub(op *parsedOpcode, s *Script) error { + v0, err := s.dstack.PopInt() + if err != nil { + return err + } + + v1, err := s.dstack.PopInt() + if err != nil { + return err + } + + s.dstack.PushInt(new(big.Int).Sub(v1, v0)) + return nil +} + +// If both of the top two entries on the stack are not zero output is 1. +// Otherwise, 0. +func opcodeBoolAnd(op *parsedOpcode, s *Script) error { + v0, err := s.dstack.PopInt() + if err != nil { + return err + } + + v1, err := s.dstack.PopInt() + if err != nil { + return err + } + + if v0.Sign() != 0 && v1.Sign() != 0 { + s.dstack.PushInt(big.NewInt(1)) + } else { + s.dstack.PushInt(big.NewInt(0)) + } + + return nil +} + +// If either of the top two entries on the stack are not zero output is 1. +// Otherwise, 0. +func opcodeBoolOr(op *parsedOpcode, s *Script) error { + v0, err := s.dstack.PopInt() + if err != nil { + return err + } + + v1, err := s.dstack.PopInt() + if err != nil { + return err + } + + if v0.Sign() != 0 || v1.Sign() != 0 { + s.dstack.PushInt(big.NewInt(1)) + } else { + s.dstack.PushInt(big.NewInt(0)) + } + + return nil +} + +func opcodeNumEqual(op *parsedOpcode, s *Script) error { + v0, err := s.dstack.PopInt() + if err != nil { + return err + } + + v1, err := s.dstack.PopInt() + if err != nil { + return err + } + + if v0.Cmp(v1) == 0 { + s.dstack.PushInt(big.NewInt(1)) + } else { + s.dstack.PushInt(big.NewInt(0)) + } + + return nil +} + +func opcodeNumEqualVerify(op *parsedOpcode, s *Script) error { + err := opcodeNumEqual(op, s) + if err == nil { + err = opcodeVerify(op, s) + } + return err +} + +func opcodeNumNotEqual(op *parsedOpcode, s *Script) error { + v0, err := s.dstack.PopInt() + if err != nil { + return err + } + + v1, err := s.dstack.PopInt() + if err != nil { + return err + } + + if v0.Cmp(v1) != 0 { + s.dstack.PushInt(big.NewInt(1)) + } else { + s.dstack.PushInt(big.NewInt(0)) + } + + return nil +} + +func opcodeLessThan(op *parsedOpcode, s *Script) error { + v0, err := s.dstack.PopInt() + if err != nil { + return err + } + + v1, err := s.dstack.PopInt() + if err != nil { + return err + } + + if v1.Cmp(v0) == -1 { + s.dstack.PushInt(big.NewInt(1)) + } else { + s.dstack.PushInt(big.NewInt(0)) + } + + return nil +} + +func opcodeGreaterThan(op *parsedOpcode, s *Script) error { + v0, err := s.dstack.PopInt() + if err != nil { + return err + } + + v1, err := s.dstack.PopInt() + if err != nil { + return err + } + + if v1.Cmp(v0) == 1 { + s.dstack.PushInt(big.NewInt(1)) + } else { + s.dstack.PushInt(big.NewInt(0)) + } + return nil +} + +func opcodeLessThanOrEqual(op *parsedOpcode, s *Script) error { + v0, err := s.dstack.PopInt() + if err != nil { + return err + } + + v1, err := s.dstack.PopInt() + if err != nil { + return err + } + + if v1.Cmp(v0) <= 0 { + s.dstack.PushInt(big.NewInt(1)) + } else { + s.dstack.PushInt(big.NewInt(0)) + } + return nil +} + +func opcodeGreaterThanOrEqual(op *parsedOpcode, s *Script) error { + v0, err := s.dstack.PopInt() + if err != nil { + return err + } + + v1, err := s.dstack.PopInt() + if err != nil { + return err + } + + if v1.Cmp(v0) >= 0 { + s.dstack.PushInt(big.NewInt(1)) + } else { + s.dstack.PushInt(big.NewInt(0)) + } + + return nil +} + +func opcodeMin(op *parsedOpcode, s *Script) error { + v0, err := s.dstack.PopInt() + if err != nil { + return err + } + + v1, err := s.dstack.PopInt() + if err != nil { + return err + } + + if v1.Cmp(v0) == -1 { + s.dstack.PushInt(new(big.Int).Set(v1)) + } else { + s.dstack.PushInt(new(big.Int).Set(v0)) + } + + return nil +} + +func opcodeMax(op *parsedOpcode, s *Script) error { + v0, err := s.dstack.PopInt() + if err != nil { + return err + } + + v1, err := s.dstack.PopInt() + if err != nil { + return err + } + + if v1.Cmp(v0) == 1 { + s.dstack.PushInt(new(big.Int).Set(v1)) + } else { + s.dstack.PushInt(new(big.Int).Set(v0)) + } + + return nil +} + +// stack input: x, min, max. Returns 1 if x is within specified range +// (left inclusive), 0 otherwise +func opcodeWithin(op *parsedOpcode, s *Script) error { + maxVal, err := s.dstack.PopInt() + if err != nil { + return err + } + + minVal, err := s.dstack.PopInt() + if err != nil { + return err + } + + x, err := s.dstack.PopInt() + if err != nil { + return err + } + + if x.Cmp(minVal) >= 0 && x.Cmp(maxVal) == -1 { + s.dstack.PushInt(big.NewInt(1)) + } else { + s.dstack.PushInt(big.NewInt(0)) + } + return nil +} + +// Calculate the hash of hasher over buf. +func calcHash(buf []byte, hasher hash.Hash) []byte { + hasher.Write(buf) + return hasher.Sum(nil) +} + +// calculate hash160 which is ripemd160(sha256(data)) +func calcHash160(buf []byte) []byte { + return calcHash(calcHash(buf, fastsha256.New()), ripemd160.New()) +} + +func opcodeRipemd160(op *parsedOpcode, s *Script) error { + buf, err := s.dstack.PopByteArray() + if err != nil { + return err + } + + s.dstack.PushByteArray(calcHash(buf, ripemd160.New())) + return nil +} + +func opcodeSha1(op *parsedOpcode, s *Script) error { + buf, err := s.dstack.PopByteArray() + if err != nil { + return err + } + + s.dstack.PushByteArray(calcHash(buf, sha1.New())) + return nil +} + +func opcodeSha256(op *parsedOpcode, s *Script) error { + buf, err := s.dstack.PopByteArray() + if err != nil { + return err + } + + s.dstack.PushByteArray(calcHash(buf, fastsha256.New())) + return nil +} + +func opcodeHash160(op *parsedOpcode, s *Script) error { + buf, err := s.dstack.PopByteArray() + if err != nil { + return err + } + + s.dstack.PushByteArray(calcHash160(buf)) + return nil +} + +func opcodeHash256(op *parsedOpcode, s *Script) error { + buf, err := s.dstack.PopByteArray() + if err != nil { + return err + } + + s.dstack.PushByteArray(btcwire.DoubleSha256(buf)) + return nil +} + +func opcodeCodeSeparator(op *parsedOpcode, s *Script) error { + s.lastcodesep = s.scriptoff + + return nil +} + +func opcodeCheckSig(op *parsedOpcode, s *Script) error { + + pkStr, err := s.dstack.PopByteArray() + if err != nil { + return err + } + + sigStr, err := s.dstack.PopByteArray() + if err != nil { + return err + } + + // Signature actually needs needs to be longer than this, but we need + // at least 1 byte for the below. btcec will check full length upon + // parsing the signature. + if len(sigStr) < 1 { + s.dstack.PushBool(false) + return nil + } + + // Trim off hashtype from the signature string. + hashType := SigHashType(sigStr[len(sigStr)-1]) + sigStr = sigStr[:len(sigStr)-1] + + // Get script from the last OP_CODESEPARATOR and without any subsequent + // OP_CODESEPARATORs + subScript := s.subScript() + + // Unlikely to hit any cases here, but remove the signature from + // the script if present. + subScript = removeOpcodeByData(subScript, sigStr) + + hash := calcScriptHash(subScript, hashType, &s.tx, s.txidx) + + pubKey, err := btcec.ParsePubKey(pkStr, btcec.S256()) + if err != nil { + s.dstack.PushBool(false) + return nil + } + + var signature *btcec.Signature + if s.der { + signature, err = btcec.ParseDERSignature(sigStr, btcec.S256()) + } else { + signature, err = btcec.ParseSignature(sigStr, btcec.S256()) + } + if err != nil { + s.dstack.PushBool(false) + return nil + } + + log.Tracef("%v", newLogClosure(func() string { + return fmt.Sprintf("op_checksig\n"+ + "pubKey:\n%v"+ + "pubKey.X: %v\n"+ + "pubKey.Y: %v\n"+ + "signature.R: %v\n"+ + "signature.S: %v\n"+ + "checkScriptHash:\n%v", + hex.Dump(pkStr), pubKey.X, pubKey.Y, + signature.R, signature.S, hex.Dump(hash)) + })) + ok := signature.Verify(hash, pubKey) + s.dstack.PushBool(ok) + return nil +} + +func opcodeCheckSigVerify(op *parsedOpcode, s *Script) error { + err := opcodeCheckSig(op, s) + if err == nil { + err = opcodeVerify(op, s) + } + return err +} + +type sig struct { + s *btcec.Signature + ht byte +} + +// stack; sigs pubkeys +func opcodeCheckMultiSig(op *parsedOpcode, s *Script) error { + + numPubkeys, err := s.dstack.PopInt() + if err != nil { + return err + } + + // XXX arbitrary limits + // nore more than 20 pubkeys, or 201 operations + + // PopInt promises that the int returned is 32 bit. + npk := int(numPubkeys.Int64()) + if npk < 0 || npk > MaxPubKeysPerMultiSig { + return ErrStackTooManyPubkeys + } + s.numOps += npk + if s.numOps > MaxOpsPerScript { + return ErrStackTooManyOperations + } + pubKeyStrings := make([][]byte, npk) + pubKeys := make([]*btcec.PublicKey, npk) + for i := range pubKeys { + pubKeyStrings[i], err = s.dstack.PopByteArray() + if err != nil { + return err + } + } + + numSignatures, err := s.dstack.PopInt() + if err != nil { + return err + } + // PopInt promises that the int returned is 32 bit. + nsig := int(numSignatures.Int64()) + if nsig < 0 { + return fmt.Errorf("number of signatures %d is less than 0", nsig) + } + if nsig > npk { + return fmt.Errorf("more signatures than pubkeys: %d > %d", nsig, npk) + } + + sigStrings := make([][]byte, nsig) + signatures := make([]sig, 0, nsig) + for i := range sigStrings { + sigStrings[i], err = s.dstack.PopByteArray() + if err != nil { + return err + } + if len(sigStrings[i]) == 0 { + continue + } + sig := sig{} + sig.ht = sigStrings[i][len(sigStrings[i])-1] + // skip off the last byte for hashtype + if s.der { + sig.s, err = + btcec.ParseDERSignature( + sigStrings[i][:len(sigStrings[i])-1], + btcec.S256()) + } else { + sig.s, err = + btcec.ParseSignature( + sigStrings[i][:len(sigStrings[i])-1], + btcec.S256()) + } + if err == nil { + signatures = append(signatures, sig) + } + } + + // bug in bitcoind mean we pop one more stack value than should be used. + dummy, err := s.dstack.PopByteArray() + if err != nil { + return err + } + + if s.strictMultiSig && len(dummy) != 0 { + return fmt.Errorf("multisig dummy argument is not zero length: %d", + len(dummy)) + } + + if len(signatures) == 0 { + s.dstack.PushBool(nsig == 0) + return nil + } + + // Trim OP_CODESEPARATORs + script := s.subScript() + + // Remove any of the signatures that happen to be in the script. + // can't sign somthing containing the signature you're making, after + // all + for i := range sigStrings { + script = removeOpcodeByData(script, sigStrings[i]) + } + + curPk := 0 + for i := range signatures { + // check signatures. + success := false + + hash := calcScriptHash(script, SigHashType(signatures[i].ht), + &s.tx, s.txidx) + inner: + // Find first pubkey that successfully validates signature. + // we start off the search from the key that was successful + // last time. + for ; curPk < len(pubKeys); curPk++ { + if pubKeys[curPk] == nil { + pubKeys[curPk], err = + btcec.ParsePubKey(pubKeyStrings[curPk], + btcec.S256()) + if err != nil { + continue + } + } + success = signatures[i].s.Verify(hash, pubKeys[curPk]) + if success { + break inner + } + } + if success == false { + s.dstack.PushBool(false) + return nil + } + } + s.dstack.PushBool(true) + + return nil +} + +func opcodeCheckMultiSigVerify(op *parsedOpcode, s *Script) error { + err := opcodeCheckMultiSig(op, s) + if err == nil { + err = opcodeVerify(op, s) + } + return err +} diff --git a/txscript/opcode_test.go b/txscript/opcode_test.go new file mode 100644 index 000000000..b237df111 --- /dev/null +++ b/txscript/opcode_test.go @@ -0,0 +1,4452 @@ +// 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" + "github.com/btcsuite/btcwire" +) + +// TestScripts tests script execution for a wide variety of opcodes. All tests +// against a fake transaction with a single input and output. +func TestScripts(t *testing.T) { + t.Parallel() + + tests := []struct { + script []byte + canonical bool + shouldPass bool + shouldFail error + }{ + // does nothing, but doesn't put a true on the stack, should fail + {script: []byte{txscript.OP_NOP}, shouldPass: false}, + // should just put true on the stack, thus passes. + {script: []byte{txscript.OP_TRUE}, shouldPass: true}, + // should just put false on the stack, thus fails. + {script: []byte{txscript.OP_FALSE}, shouldPass: false}, + // tests OP_VERIFY (true). true is needed since else stack is empty. + {script: []byte{txscript.OP_TRUE, txscript.OP_VERIFY, + txscript.OP_TRUE}, shouldPass: true}, + // tests OP_VERIFY (false), will error out. + {script: []byte{txscript.OP_FALSE, txscript.OP_VERIFY, + txscript.OP_TRUE}, shouldPass: false}, + // tests OP_VERIFY with empty stack (errors) + {script: []byte{txscript.OP_VERIFY}, shouldPass: false}, + // test OP_RETURN immediately fails the script (empty stack) + {script: []byte{txscript.OP_RETURN}, shouldPass: false}, + // test OP_RETURN immediately fails the script (full stack) + {script: []byte{txscript.OP_TRUE, txscript.OP_RETURN}, + shouldPass: false}, + // tests numequal with a trivial example (passing) + {script: []byte{txscript.OP_TRUE, txscript.OP_TRUE, + txscript.OP_NUMEQUAL}, shouldPass: true}, + // tests numequal with a trivial example (failing) + {script: []byte{txscript.OP_TRUE, txscript.OP_FALSE, + txscript.OP_NUMEQUAL}, shouldPass: false}, + // tests numequal with insufficient arguments (1/2) + {script: []byte{txscript.OP_TRUE, txscript.OP_NUMEQUAL}, + shouldPass: false}, + // tests numequal with insufficient arguments (0/2) + {script: []byte{txscript.OP_NUMEQUAL}, shouldPass: false}, + // tests numnotequal with a trivial example (passing) + {script: []byte{txscript.OP_TRUE, txscript.OP_FALSE, + txscript.OP_NUMNOTEQUAL}, shouldPass: true}, + // tests numnotequal with a trivial example (failing) + {script: []byte{txscript.OP_TRUE, txscript.OP_TRUE, + txscript.OP_NUMNOTEQUAL}, shouldPass: false}, + // tests numnotequal with insufficient arguments (1/2) + {script: []byte{txscript.OP_TRUE, txscript.OP_NUMNOTEQUAL}, + shouldPass: false}, + // tests numnotequal with insufficient arguments (0/2) + {script: []byte{txscript.OP_NUMNOTEQUAL}, shouldPass: false}, + // test numequal_verify with a trivial example (passing) + {script: []byte{txscript.OP_TRUE, txscript.OP_TRUE, + txscript.OP_NUMEQUALVERIFY, txscript.OP_TRUE}, + shouldPass: true}, + // test numequal_verify with a trivial example (failing) + {script: []byte{txscript.OP_TRUE, txscript.OP_FALSE, + txscript.OP_NUMEQUALVERIFY, txscript.OP_TRUE}, + shouldPass: false}, + // test OP_1ADD by adding 1 to 0 + {script: []byte{txscript.OP_FALSE, txscript.OP_1ADD}, + shouldPass: true}, + // test OP_1ADD without args (should error) + {script: []byte{txscript.OP_1ADD}, shouldPass: false}, + // test OP_1NEGATE by adding 1 to -1 + {script: []byte{txscript.OP_1NEGATE, txscript.OP_1ADD}, + shouldPass: false}, + // test OP_1NEGATE by adding negating -1 + {script: []byte{txscript.OP_1NEGATE, txscript.OP_NEGATE}, + shouldPass: true}, + // test OP_NEGATE by adding 1 to -1 + {script: []byte{txscript.OP_TRUE, txscript.OP_NEGATE, + txscript.OP_1ADD}, shouldPass: false}, + // test OP_NEGATE with no args + {script: []byte{txscript.OP_NEGATE}, shouldPass: false}, + // test OP_1SUB -> 1 - 1 = 0 + {script: []byte{txscript.OP_TRUE, txscript.OP_1SUB}, + shouldPass: false}, + // test OP_1SUB -> negate(0 -1) = 1 + {script: []byte{txscript.OP_FALSE, txscript.OP_1SUB, + txscript.OP_NEGATE}, shouldPass: true}, + // test OP_1SUB with empty stack + {script: []byte{txscript.OP_1SUB}, shouldPass: false}, + // OP_DEPTH with empty stack, means 0 on stack at end + {script: []byte{txscript.OP_DEPTH}, shouldPass: false}, + // 1 +1 -1 = 1. tests depth + add + {script: []byte{txscript.OP_TRUE, txscript.OP_DEPTH, txscript.OP_ADD, + txscript.OP_1SUB}, shouldPass: true}, + // 1 +1 -1 = 0 . tests dept + add + {script: []byte{txscript.OP_TRUE, txscript.OP_DEPTH, + txscript.OP_ADD, txscript.OP_1SUB, txscript.OP_1SUB}, + shouldPass: false}, + // OP_ADD with only one thing on stack should error + {script: []byte{txscript.OP_TRUE, txscript.OP_ADD}, + shouldPass: false}, + // OP_ADD with nothing on stack should error + {script: []byte{txscript.OP_ADD}, shouldPass: false}, + // OP_SUB: 1-1=0 + {script: []byte{txscript.OP_TRUE, txscript.OP_TRUE, + txscript.OP_SUB}, shouldPass: false}, + // OP_SUB: 1+1-1=1 + {script: []byte{txscript.OP_TRUE, txscript.OP_TRUE, txscript.OP_TRUE, + txscript.OP_ADD, txscript.OP_SUB}, shouldPass: true}, + // OP_SUB with only one thing on stack should error + {script: []byte{txscript.OP_TRUE, txscript.OP_SUB}, + shouldPass: false}, + // OP_SUB with nothing on stack should error + {script: []byte{txscript.OP_SUB}, shouldPass: false}, + // OP_LESSTHAN 1 < 1 == false + {script: []byte{txscript.OP_TRUE, txscript.OP_TRUE, + txscript.OP_LESSTHAN}, shouldPass: false}, + // OP_LESSTHAN 1 < 0 == false + {script: []byte{txscript.OP_TRUE, txscript.OP_FALSE, + txscript.OP_LESSTHAN}, shouldPass: false}, + // OP_LESSTHAN 0 < 1 == true + {script: []byte{txscript.OP_FALSE, txscript.OP_TRUE, + txscript.OP_LESSTHAN}, shouldPass: true}, + // OP_LESSTHAN only one arg + {script: []byte{txscript.OP_TRUE, txscript.OP_LESSTHAN}, + shouldPass: false}, + // OP_LESSTHAN no args + {script: []byte{txscript.OP_LESSTHAN}, shouldPass: false}, + + // OP_LESSTHANOREQUAL 1 <= 1 == true + {script: []byte{txscript.OP_TRUE, txscript.OP_TRUE, + txscript.OP_LESSTHANOREQUAL}, shouldPass: true}, + // OP_LESSTHANOREQUAL 1 <= 0 == false + {script: []byte{txscript.OP_TRUE, txscript.OP_FALSE, + txscript.OP_LESSTHANOREQUAL}, shouldPass: false}, + // OP_LESSTHANOREQUAL 0 <= 1 == true + {script: []byte{txscript.OP_FALSE, txscript.OP_TRUE, + txscript.OP_LESSTHANOREQUAL}, shouldPass: true}, + // OP_LESSTHANOREQUAL only one arg + {script: []byte{txscript.OP_TRUE, txscript.OP_LESSTHANOREQUAL}, + shouldPass: false}, + // OP_LESSTHANOREQUAL no args + {script: []byte{txscript.OP_LESSTHANOREQUAL}, shouldPass: false}, + + // OP_GREATERTHAN 1 > 1 == false + {script: []byte{txscript.OP_TRUE, txscript.OP_TRUE, + txscript.OP_GREATERTHAN}, shouldPass: false}, + // OP_GREATERTHAN 1 > 0 == true + {script: []byte{txscript.OP_TRUE, txscript.OP_FALSE, + txscript.OP_GREATERTHAN}, shouldPass: true}, + // OP_GREATERTHAN 0 > 1 == false + {script: []byte{txscript.OP_FALSE, txscript.OP_TRUE, + txscript.OP_GREATERTHAN}, shouldPass: false}, + // OP_GREATERTHAN only one arg + {script: []byte{txscript.OP_TRUE, txscript.OP_GREATERTHAN}, + shouldPass: false}, + // OP_GREATERTHAN no args + {script: []byte{txscript.OP_GREATERTHAN}, shouldPass: false}, + + // OP_GREATERTHANOREQUAL 1 >= 1 == true + {script: []byte{txscript.OP_TRUE, txscript.OP_TRUE, + txscript.OP_GREATERTHANOREQUAL}, shouldPass: true}, + // OP_GREATERTHANOREQUAL 1 >= 0 == false + {script: []byte{txscript.OP_TRUE, txscript.OP_FALSE, + txscript.OP_GREATERTHANOREQUAL}, shouldPass: true}, + // OP_GREATERTHANOREQUAL 0 >= 1 == true + {script: []byte{txscript.OP_FALSE, txscript.OP_TRUE, + txscript.OP_GREATERTHANOREQUAL}, shouldPass: false}, + // OP_GREATERTHANOREQUAL only one arg + {script: []byte{txscript.OP_TRUE, txscript.OP_GREATERTHANOREQUAL}, + shouldPass: false}, + // OP_GREATERTHANOREQUAL no args + {script: []byte{txscript.OP_GREATERTHANOREQUAL}, shouldPass: false}, + + // OP_MIN basic functionality -> min(0,1) = 0 = min(1,0) + {script: []byte{txscript.OP_TRUE, txscript.OP_FALSE, + txscript.OP_MIN}, shouldPass: false}, + {script: []byte{txscript.OP_FALSE, txscript.OP_TRUE, + txscript.OP_MIN}, shouldPass: false}, + // OP_MIN -> 1 arg errors + {script: []byte{txscript.OP_TRUE, txscript.OP_MIN}, + shouldPass: false}, + // OP_MIN -> 0 arg errors + {script: []byte{txscript.OP_MIN}, shouldPass: false}, + // OP_MAX basic functionality -> max(0,1) = 1 = max(1,0) + {script: []byte{txscript.OP_TRUE, txscript.OP_FALSE, + txscript.OP_MAX}, shouldPass: true}, + {script: []byte{txscript.OP_FALSE, txscript.OP_TRUE, + txscript.OP_MAX}, shouldPass: true}, + // OP_MAX -> 1 arg errors + {script: []byte{txscript.OP_TRUE, txscript.OP_MAX}, + shouldPass: false}, + // OP_MAX -> 0 arg errors + {script: []byte{txscript.OP_MAX}, shouldPass: false}, + + // By this point we know a number of operations appear to be working + // correctly. we can use them to test the other number pushing + // operations + {script: []byte{txscript.OP_TRUE, txscript.OP_1ADD, txscript.OP_2, + txscript.OP_EQUAL}, shouldPass: true}, + {script: []byte{txscript.OP_2, txscript.OP_1ADD, txscript.OP_3, + txscript.OP_EQUAL}, shouldPass: true}, + {script: []byte{txscript.OP_3, txscript.OP_1ADD, txscript.OP_4, + txscript.OP_EQUAL}, shouldPass: true}, + {script: []byte{txscript.OP_4, txscript.OP_1ADD, txscript.OP_5, + txscript.OP_EQUAL}, shouldPass: true}, + {script: []byte{txscript.OP_5, txscript.OP_1ADD, txscript.OP_6, + txscript.OP_EQUAL}, shouldPass: true}, + {script: []byte{txscript.OP_6, txscript.OP_1ADD, txscript.OP_7, + txscript.OP_EQUAL}, shouldPass: true}, + {script: []byte{txscript.OP_7, txscript.OP_1ADD, txscript.OP_8, + txscript.OP_EQUAL}, shouldPass: true}, + {script: []byte{txscript.OP_8, txscript.OP_1ADD, txscript.OP_9, + txscript.OP_EQUAL}, shouldPass: true}, + {script: []byte{txscript.OP_9, txscript.OP_1ADD, txscript.OP_10, + txscript.OP_EQUAL}, shouldPass: true}, + {script: []byte{txscript.OP_10, txscript.OP_1ADD, txscript.OP_11, + txscript.OP_EQUAL}, shouldPass: true}, + {script: []byte{txscript.OP_11, txscript.OP_1ADD, txscript.OP_12, + txscript.OP_EQUAL}, shouldPass: true}, + {script: []byte{txscript.OP_12, txscript.OP_1ADD, txscript.OP_13, + txscript.OP_EQUAL}, shouldPass: true}, + {script: []byte{txscript.OP_13, txscript.OP_1ADD, txscript.OP_14, + txscript.OP_EQUAL}, shouldPass: true}, + {script: []byte{txscript.OP_14, txscript.OP_1ADD, txscript.OP_15, + txscript.OP_EQUAL}, shouldPass: true}, + {script: []byte{txscript.OP_15, txscript.OP_1ADD, txscript.OP_16, + txscript.OP_EQUAL}, shouldPass: true}, + + // Test OP_WITHIN x, min, max + // 0 <= 1 < 2 + {script: []byte{txscript.OP_TRUE, txscript.OP_FALSE, txscript.OP_2, + txscript.OP_WITHIN}, shouldPass: true}, + // 1 <= 0 < 2 FAIL + {script: []byte{txscript.OP_FALSE, txscript.OP_TRUE, txscript.OP_2, + txscript.OP_WITHIN}, shouldPass: false}, + // 1 <= 1 < 2 + {script: []byte{txscript.OP_TRUE, txscript.OP_TRUE, txscript.OP_2, + txscript.OP_WITHIN}, shouldPass: true}, + // 1 <= 2 < 2 FAIL + {script: []byte{txscript.OP_2, txscript.OP_TRUE, txscript.OP_2, + txscript.OP_WITHIN}, shouldPass: false}, + // only two arguments + {script: []byte{txscript.OP_TRUE, txscript.OP_FALSE, + txscript.OP_WITHIN}, shouldPass: false}, + // only one argument + {script: []byte{txscript.OP_TRUE, txscript.OP_WITHIN}, + shouldPass: false}, + // no arguments + {script: []byte{txscript.OP_WITHIN}, shouldPass: false}, + + // OP_BOOLAND + // 1 && 1 == 1 + {script: []byte{txscript.OP_TRUE, txscript.OP_TRUE, + txscript.OP_BOOLAND}, shouldPass: true}, + // 1 && 0 == 0 + {script: []byte{txscript.OP_TRUE, txscript.OP_FALSE, + txscript.OP_BOOLAND}, shouldPass: false}, + // 0 && 1 == 0 + {script: []byte{txscript.OP_FALSE, txscript.OP_TRUE, + txscript.OP_BOOLAND}, shouldPass: false}, + // 0 && 0 == 0 + {script: []byte{txscript.OP_FALSE, txscript.OP_FALSE, + txscript.OP_BOOLAND}, shouldPass: false}, + // 0 && - boom + {script: []byte{txscript.OP_TRUE, txscript.OP_BOOLAND}, + shouldPass: false}, + // && - boom + {script: []byte{txscript.OP_BOOLAND}, shouldPass: false}, + + // OP_BOOLOR + // 1 || 1 == 1 + {script: []byte{txscript.OP_TRUE, txscript.OP_TRUE, + txscript.OP_BOOLOR}, shouldPass: true}, + // 1 || 0 == 1 + {script: []byte{txscript.OP_TRUE, txscript.OP_FALSE, + txscript.OP_BOOLOR}, shouldPass: true}, + // 0 || 1 == 1 + {script: []byte{txscript.OP_FALSE, txscript.OP_TRUE, + txscript.OP_BOOLOR}, shouldPass: true}, + // 0 || 0 == 0 + {script: []byte{txscript.OP_FALSE, txscript.OP_FALSE, + txscript.OP_BOOLOR}, shouldPass: false}, + // 0 && - boom + {script: []byte{txscript.OP_TRUE, txscript.OP_BOOLOR}, + shouldPass: false}, + // && - boom + {script: []byte{txscript.OP_BOOLOR}, shouldPass: false}, + + // OP_0NOTEQUAL + // 1 with input != 0 XXX check output is actually 1. + {script: []byte{txscript.OP_TRUE, txscript.OP_0NOTEQUAL}, + shouldPass: true}, + {script: []byte{txscript.OP_2, txscript.OP_0NOTEQUAL}, + shouldPass: true}, + {script: []byte{txscript.OP_3, txscript.OP_0NOTEQUAL}, + shouldPass: true}, + {script: []byte{txscript.OP_4, txscript.OP_0NOTEQUAL}, + shouldPass: true}, + {script: []byte{txscript.OP_5, txscript.OP_0NOTEQUAL}, + shouldPass: true}, + {script: []byte{txscript.OP_6, txscript.OP_0NOTEQUAL}, + shouldPass: true}, + {script: []byte{txscript.OP_7, txscript.OP_0NOTEQUAL}, + shouldPass: true}, + {script: []byte{txscript.OP_8, txscript.OP_0NOTEQUAL}, + shouldPass: true}, + {script: []byte{txscript.OP_9, txscript.OP_0NOTEQUAL}, + shouldPass: true}, + {script: []byte{txscript.OP_10, txscript.OP_0NOTEQUAL}, + shouldPass: true}, + {script: []byte{txscript.OP_11, txscript.OP_0NOTEQUAL}, + shouldPass: true}, + {script: []byte{txscript.OP_12, txscript.OP_0NOTEQUAL}, + shouldPass: true}, + {script: []byte{txscript.OP_13, txscript.OP_0NOTEQUAL}, + shouldPass: true}, + {script: []byte{txscript.OP_14, txscript.OP_0NOTEQUAL}, + shouldPass: true}, + {script: []byte{txscript.OP_15, txscript.OP_0NOTEQUAL}, + shouldPass: true}, + {script: []byte{txscript.OP_16, txscript.OP_0NOTEQUAL}, + shouldPass: true}, + {script: []byte{txscript.OP_FALSE, txscript.OP_0NOTEQUAL}, shouldPass: false}, + // No arguments also blows up + {script: []byte{txscript.OP_0NOTEQUAL}, shouldPass: false}, + + // OP_NOT: 1 i input is 0, else 0 + {script: []byte{txscript.OP_TRUE, txscript.OP_NOT}, shouldPass: false}, + {script: []byte{txscript.OP_2, txscript.OP_NOT}, shouldPass: false}, + {script: []byte{txscript.OP_3, txscript.OP_NOT}, shouldPass: false}, + {script: []byte{txscript.OP_4, txscript.OP_NOT}, shouldPass: false}, + {script: []byte{txscript.OP_5, txscript.OP_NOT}, shouldPass: false}, + {script: []byte{txscript.OP_6, txscript.OP_NOT}, shouldPass: false}, + {script: []byte{txscript.OP_7, txscript.OP_NOT}, shouldPass: false}, + {script: []byte{txscript.OP_8, txscript.OP_NOT}, shouldPass: false}, + {script: []byte{txscript.OP_9, txscript.OP_NOT}, shouldPass: false}, + {script: []byte{txscript.OP_10, txscript.OP_NOT}, shouldPass: false}, + {script: []byte{txscript.OP_11, txscript.OP_NOT}, shouldPass: false}, + {script: []byte{txscript.OP_12, txscript.OP_NOT}, shouldPass: false}, + {script: []byte{txscript.OP_13, txscript.OP_NOT}, shouldPass: false}, + {script: []byte{txscript.OP_14, txscript.OP_NOT}, shouldPass: false}, + {script: []byte{txscript.OP_15, txscript.OP_NOT}, shouldPass: false}, + {script: []byte{txscript.OP_16, txscript.OP_NOT}, shouldPass: false}, + // check negative numbers too + {script: []byte{txscript.OP_TRUE, txscript.OP_NEGATE, + txscript.OP_NOT}, shouldPass: false}, + {script: []byte{txscript.OP_FALSE, txscript.OP_NOT}, + shouldPass: true}, + // No arguments also blows up + {script: []byte{txscript.OP_NOT}, shouldPass: false}, + + // Conditional Execution + {script: []byte{txscript.OP_0, txscript.OP_IF, txscript.OP_0, txscript.OP_ELSE, txscript.OP_2, txscript.OP_ENDIF}, shouldPass: true}, + {script: []byte{txscript.OP_1, txscript.OP_IF, txscript.OP_0, txscript.OP_ELSE, txscript.OP_2, txscript.OP_ENDIF}, shouldPass: false}, + {script: []byte{txscript.OP_1, txscript.OP_NOTIF, txscript.OP_0, txscript.OP_ELSE, txscript.OP_2, txscript.OP_ENDIF}, shouldPass: true}, + {script: []byte{txscript.OP_0, txscript.OP_NOTIF, txscript.OP_0, txscript.OP_ELSE, txscript.OP_2, txscript.OP_ENDIF}, shouldPass: false}, + {script: []byte{txscript.OP_0, txscript.OP_IF, txscript.OP_0, txscript.OP_ELSE, txscript.OP_2}, shouldFail: txscript.ErrStackMissingEndif}, + {script: []byte{txscript.OP_1, txscript.OP_NOTIF, txscript.OP_0, txscript.OP_ELSE, txscript.OP_2}, shouldFail: txscript.ErrStackMissingEndif}, + {script: []byte{txscript.OP_1, txscript.OP_1, txscript.OP_IF, txscript.OP_IF, txscript.OP_1, txscript.OP_ELSE, txscript.OP_0, txscript.OP_ENDIF, txscript.OP_ENDIF}, shouldPass: true}, + {script: []byte{txscript.OP_1, txscript.OP_IF, txscript.OP_IF, txscript.OP_1, txscript.OP_ELSE, txscript.OP_0, txscript.OP_ENDIF, txscript.OP_ENDIF}, shouldFail: txscript.ErrStackUnderflow}, + {script: []byte{txscript.OP_0, txscript.OP_IF, txscript.OP_IF, txscript.OP_0, txscript.OP_ELSE, txscript.OP_0, txscript.OP_ENDIF, txscript.OP_ELSE, txscript.OP_1, txscript.OP_ENDIF}, shouldPass: true}, + {script: []byte{txscript.OP_0, txscript.OP_IF, txscript.OP_NOTIF, txscript.OP_0, txscript.OP_ELSE, txscript.OP_0, txscript.OP_ENDIF, txscript.OP_ELSE, txscript.OP_1, txscript.OP_ENDIF}, shouldPass: true}, + {script: []byte{txscript.OP_NOTIF, txscript.OP_0, txscript.OP_ENDIF}, shouldFail: txscript.ErrStackUnderflow}, + {script: []byte{txscript.OP_ELSE, txscript.OP_0, txscript.OP_ENDIF}, shouldFail: txscript.ErrStackNoIf}, + {script: []byte{txscript.OP_ENDIF}, shouldFail: txscript.ErrStackNoIf}, + /* up here because error from sig parsing is undefined. */ + {script: []byte{txscript.OP_1, txscript.OP_1, txscript.OP_DATA_65, + 0x04, 0xae, 0x1a, 0x62, 0xfe, 0x09, 0xc5, 0xf5, 0x1b, 0x13, + 0x90, 0x5f, 0x07, 0xf0, 0x6b, 0x99, 0xa2, 0xf7, 0x15, 0x9b, + 0x22, 0x25, 0xf3, 0x74, 0xcd, 0x37, 0x8d, 0x71, 0x30, 0x2f, + 0xa2, 0x84, 0x14, 0xe7, 0xaa, 0xb3, 0x73, 0x97, 0xf5, 0x54, + 0xa7, 0xdf, 0x5f, 0x14, 0x2c, 0x21, 0xc1, 0xb7, 0x30, 0x3b, + 0x8a, 0x06, 0x26, 0xf1, 0xba, 0xde, 0xd5, 0xc7, 0x2a, 0x70, + 0x4f, 0x7e, 0x6c, 0xd8, 0x4c, + txscript.OP_1, txscript.OP_CHECKMULTISIG}, + canonical: false, + shouldPass: false}, + {script: []byte{txscript.OP_1, txscript.OP_1, txscript.OP_DATA_65, + 0x04, 0xae, 0x1a, 0x62, 0xfe, 0x09, 0xc5, 0xf5, 0x1b, 0x13, + 0x90, 0x5f, 0x07, 0xf0, 0x6b, 0x99, 0xa2, 0xf7, 0x15, 0x9b, + 0x22, 0x25, 0xf3, 0x74, 0xcd, 0x37, 0x8d, 0x71, 0x30, 0x2f, + 0xa2, 0x84, 0x14, 0xe7, 0xaa, 0xb3, 0x73, 0x97, 0xf5, 0x54, + 0xa7, 0xdf, 0x5f, 0x14, 0x2c, 0x21, 0xc1, 0xb7, 0x30, 0x3b, + 0x8a, 0x06, 0x26, 0xf1, 0xba, 0xde, 0xd5, 0xc7, 0x2a, 0x70, + 0x4f, 0x7e, 0x6c, 0xd8, 0x4c, + txscript.OP_1, txscript.OP_CHECKMULTISIG}, + canonical: true, + shouldPass: false}, + /* up here because no defined error case. */ + {script: []byte{txscript.OP_1, txscript.OP_1, txscript.OP_DATA_65, + 0x04, 0xae, 0x1a, 0x62, 0xfe, 0x09, 0xc5, 0xf5, 0x1b, 0x13, + 0x90, 0x5f, 0x07, 0xf0, 0x6b, 0x99, 0xa2, 0xf7, 0x15, 0x9b, + 0x22, 0x25, 0xf3, 0x74, 0xcd, 0x37, 0x8d, 0x71, 0x30, 0x2f, + 0xa2, 0x84, 0x14, 0xe7, 0xaa, 0xb3, 0x73, 0x97, 0xf5, 0x54, + 0xa7, 0xdf, 0x5f, 0x14, 0x2c, 0x21, 0xc1, 0xb7, 0x30, 0x3b, + 0x8a, 0x06, 0x26, 0xf1, 0xba, 0xde, 0xd5, 0xc7, 0x2a, 0x70, + 0x4f, 0x7e, 0x6c, 0xd8, 0x4c, + txscript.OP_1, txscript.OP_CHECKMULTISIGVERIFY}, + shouldPass: false}, + + // Invalid Opcodes + {script: []byte{186}, shouldPass: false}, + {script: []byte{187}, shouldPass: false}, + {script: []byte{188}, shouldPass: false}, + {script: []byte{189}, shouldPass: false}, + {script: []byte{190}, shouldPass: false}, + {script: []byte{191}, shouldPass: false}, + {script: []byte{192}, shouldPass: false}, + {script: []byte{193}, shouldPass: false}, + {script: []byte{194}, shouldPass: false}, + {script: []byte{195}, shouldPass: false}, + {script: []byte{195}, shouldPass: false}, + {script: []byte{196}, shouldPass: false}, + {script: []byte{197}, shouldPass: false}, + {script: []byte{198}, shouldPass: false}, + {script: []byte{199}, shouldPass: false}, + {script: []byte{200}, shouldPass: false}, + {script: []byte{201}, shouldPass: false}, + {script: []byte{202}, shouldPass: false}, + {script: []byte{203}, shouldPass: false}, + {script: []byte{204}, shouldPass: false}, + {script: []byte{205}, shouldPass: false}, + {script: []byte{206}, shouldPass: false}, + {script: []byte{207}, shouldPass: false}, + {script: []byte{208}, shouldPass: false}, + {script: []byte{209}, shouldPass: false}, + {script: []byte{210}, shouldPass: false}, + {script: []byte{211}, shouldPass: false}, + {script: []byte{212}, shouldPass: false}, + {script: []byte{213}, shouldPass: false}, + {script: []byte{214}, shouldPass: false}, + {script: []byte{215}, shouldPass: false}, + {script: []byte{216}, shouldPass: false}, + {script: []byte{217}, shouldPass: false}, + {script: []byte{218}, shouldPass: false}, + {script: []byte{219}, shouldPass: false}, + {script: []byte{220}, shouldPass: false}, + {script: []byte{221}, shouldPass: false}, + {script: []byte{222}, shouldPass: false}, + {script: []byte{223}, shouldPass: false}, + {script: []byte{224}, shouldPass: false}, + {script: []byte{225}, shouldPass: false}, + {script: []byte{226}, shouldPass: false}, + {script: []byte{227}, shouldPass: false}, + {script: []byte{228}, shouldPass: false}, + {script: []byte{229}, shouldPass: false}, + {script: []byte{230}, shouldPass: false}, + {script: []byte{231}, shouldPass: false}, + {script: []byte{232}, shouldPass: false}, + {script: []byte{233}, shouldPass: false}, + {script: []byte{234}, shouldPass: false}, + {script: []byte{235}, shouldPass: false}, + {script: []byte{236}, shouldPass: false}, + {script: []byte{237}, shouldPass: false}, + {script: []byte{238}, shouldPass: false}, + {script: []byte{239}, shouldPass: false}, + {script: []byte{240}, shouldPass: false}, + {script: []byte{241}, shouldPass: false}, + {script: []byte{242}, shouldPass: false}, + {script: []byte{243}, shouldPass: false}, + {script: []byte{244}, shouldPass: false}, + {script: []byte{245}, shouldPass: false}, + {script: []byte{246}, shouldPass: false}, + {script: []byte{247}, shouldPass: false}, + {script: []byte{248}, shouldPass: false}, + {script: []byte{249}, shouldPass: false}, + {script: []byte{250}, shouldPass: false}, + {script: []byte{251}, shouldPass: false}, + {script: []byte{252}, shouldPass: false}, + } + + // Mock up fake tx used during script execution. + mockTx := &btcwire.MsgTx{ + Version: 1, + TxIn: []*btcwire.TxIn{ + { + PreviousOutPoint: btcwire.OutPoint{ + Hash: btcwire.ShaHash{}, + Index: 0xffffffff, + }, + SignatureScript: []byte{txscript.OP_NOP}, + Sequence: 0xffffffff, + }, + }, + TxOut: []*btcwire.TxOut{ + { + Value: 0x12a05f200, + PkScript: []byte{}, + }, + }, + LockTime: 0, + } + + for i, test := range tests { + // Parse and execute the test script. + var flags txscript.ScriptFlags + if test.canonical { + flags = txscript.ScriptCanonicalSignatures + } + mockTx.TxOut[0].PkScript = test.script + sigScript := mockTx.TxIn[0].SignatureScript + engine, err := txscript.NewScript(sigScript, test.script, 0, + mockTx, flags) + if err == nil { + err = engine.Execute() + } + + if test.shouldFail != nil { + if err == nil { + t.Errorf("test %d passed should fail with %v", + i, test.shouldFail) + continue + } else if test.shouldFail != err { + t.Errorf("test %d failed with wrong error "+ + "[%v], expected [%v]", i, err, + test.shouldFail) + continue + } + } + if test.shouldPass && err != nil { + t.Errorf("test %d failed: %v", i, err) + continue + } else if !test.shouldPass && err == nil { + t.Errorf("test %d passed, should fail", i) + continue + } + } +} + +// Detailed tests for opcodes, we inspect machine state before and after the +// opcode and check that it has the effect on the state that we expect. +type detailedTest struct { + name string + before [][]byte + altbefore [][]byte + script []byte + expectedReturn error + after [][]byte + altafter [][]byte + disassembly string + disassemblyerr error + nSigOps int // should have same return as disassembly error + nPreciseSigOps int // should have same return as disassembly error +} + +var detailedTests = []detailedTest{ + { + name: "noop", + before: [][]byte{{1}, {2}, {3}, {4}, {5}}, + script: []byte{txscript.OP_NOP}, + after: [][]byte{{1}, {2}, {3}, {4}, {5}}, + disassembly: "OP_NOP", + }, + { + name: "dup", + before: [][]byte{{1}}, + script: []byte{txscript.OP_DUP}, + after: [][]byte{{1}, {1}}, + disassembly: "OP_DUP", + }, + { + name: "dup2", + before: [][]byte{{1}, {2}}, + script: []byte{txscript.OP_2DUP}, + after: [][]byte{{1}, {2}, {1}, {2}}, + disassembly: "OP_2DUP", + }, + { + name: "dup3", + before: [][]byte{{1}, {2}, {3}}, + script: []byte{txscript.OP_3DUP}, + after: [][]byte{{1}, {2}, {3}, {1}, {2}, {3}}, + disassembly: "OP_3DUP", + }, + { + name: "dup too much", + before: [][]byte{}, + script: []byte{txscript.OP_DUP}, + expectedReturn: txscript.ErrStackUnderflow, + after: [][]byte{}, + disassembly: "OP_DUP", + }, + { + name: "2dup too much", + before: [][]byte{{1}}, + script: []byte{txscript.OP_2DUP}, + expectedReturn: txscript.ErrStackUnderflow, + after: [][]byte{}, + disassembly: "OP_2DUP", + }, + { + name: "2dup way too much", + before: [][]byte{}, + script: []byte{txscript.OP_2DUP}, + expectedReturn: txscript.ErrStackUnderflow, + after: [][]byte{}, + disassembly: "OP_2DUP", + }, + { + name: "3dup too much", + before: [][]byte{{1}, {2}}, + script: []byte{txscript.OP_3DUP}, + expectedReturn: txscript.ErrStackUnderflow, + after: [][]byte{}, + disassembly: "OP_3DUP", + }, + { + name: "3dup kinda too much", + before: [][]byte{{1}}, + script: []byte{txscript.OP_3DUP}, + expectedReturn: txscript.ErrStackUnderflow, + after: [][]byte{}, + disassembly: "OP_3DUP", + }, + { + name: "3dup way too much", + before: [][]byte{}, + script: []byte{txscript.OP_3DUP}, + expectedReturn: txscript.ErrStackUnderflow, + after: [][]byte{}, + disassembly: "OP_3DUP", + }, + { + name: "Nip", + before: [][]byte{{1}, {2}, {3}}, + script: []byte{txscript.OP_NIP}, + after: [][]byte{{1}, {3}}, + disassembly: "OP_NIP", + }, + { + name: "Nip too much", + before: [][]byte{{1}}, + script: []byte{txscript.OP_NIP}, + expectedReturn: txscript.ErrStackUnderflow, + after: [][]byte{{2}, {3}}, + disassembly: "OP_NIP", + }, + { + name: "keep on tucking", + before: [][]byte{{1}, {2}, {3}}, + script: []byte{txscript.OP_TUCK}, + after: [][]byte{{1}, {3}, {2}, {3}}, + disassembly: "OP_TUCK", + }, + { + name: "a little tucked up", + before: [][]byte{{1}}, // too few arguments for tuck + script: []byte{txscript.OP_TUCK}, + expectedReturn: txscript.ErrStackUnderflow, + after: [][]byte{}, + disassembly: "OP_TUCK", + }, + { + name: "all tucked up", + before: [][]byte{}, // too few arguments for tuck + script: []byte{txscript.OP_TUCK}, + expectedReturn: txscript.ErrStackUnderflow, + disassembly: "OP_TUCK", + }, + { + name: "drop 1", + before: [][]byte{{1}, {2}, {3}, {4}}, + script: []byte{txscript.OP_DROP}, + after: [][]byte{{1}, {2}, {3}}, + disassembly: "OP_DROP", + }, + { + name: "drop 2", + before: [][]byte{{1}, {2}, {3}, {4}}, + script: []byte{txscript.OP_2DROP}, + after: [][]byte{{1}, {2}}, + disassembly: "OP_2DROP", + }, + { + name: "drop too much", + before: [][]byte{}, + script: []byte{txscript.OP_DROP}, + expectedReturn: txscript.ErrStackUnderflow, + disassembly: "OP_DROP", + }, + { + name: "2drop too much", + before: [][]byte{{1}}, + script: []byte{txscript.OP_2DROP}, + expectedReturn: txscript.ErrStackUnderflow, + disassembly: "OP_2DROP", + }, + { + name: "2drop far too much", + before: [][]byte{}, + script: []byte{txscript.OP_2DROP}, + expectedReturn: txscript.ErrStackUnderflow, + disassembly: "OP_2DROP", + }, + { + name: "Rot1", + before: [][]byte{{1}, {2}, {3}, {4}}, + script: []byte{txscript.OP_ROT}, + after: [][]byte{{1}, {3}, {4}, {2}}, + disassembly: "OP_ROT", + }, + { + name: "Rot2", + before: [][]byte{{1}, {2}, {3}, {4}, {5}, {6}}, + script: []byte{txscript.OP_2ROT}, + after: [][]byte{{3}, {4}, {5}, {6}, {1}, {2}}, + disassembly: "OP_2ROT", + }, + { + name: "Rot too little", + before: [][]byte{{1}, {2}}, + script: []byte{txscript.OP_ROT}, + expectedReturn: txscript.ErrStackUnderflow, + disassembly: "OP_ROT", + }, + { + name: "Swap1", + before: [][]byte{{1}, {2}, {3}, {4}}, + script: []byte{txscript.OP_SWAP}, + after: [][]byte{{1}, {2}, {4}, {3}}, + disassembly: "OP_SWAP", + }, + { + name: "Swap2", + before: [][]byte{{1}, {2}, {3}, {4}}, + script: []byte{txscript.OP_2SWAP}, + after: [][]byte{{3}, {4}, {1}, {2}}, + disassembly: "OP_2SWAP", + }, + { + name: "Swap too little", + before: [][]byte{{1}}, + script: []byte{txscript.OP_SWAP}, + expectedReturn: txscript.ErrStackUnderflow, + disassembly: "OP_SWAP", + }, + { + name: "Over1", + before: [][]byte{{1}, {2}, {3}, {4}}, + script: []byte{txscript.OP_OVER}, + after: [][]byte{{1}, {2}, {3}, {4}, {3}}, + disassembly: "OP_OVER", + }, + { + name: "Over2", + before: [][]byte{{1}, {2}, {3}, {4}}, + script: []byte{txscript.OP_2OVER}, + after: [][]byte{{1}, {2}, {3}, {4}, {1}, {2}}, + disassembly: "OP_2OVER", + }, + { + name: "Over too little", + before: [][]byte{{1}}, + script: []byte{txscript.OP_OVER}, + expectedReturn: txscript.ErrStackUnderflow, + disassembly: "OP_OVER", + }, + { + name: "Pick1", + before: [][]byte{{1}, {2}, {3}, {4}, {1}}, + script: []byte{txscript.OP_PICK}, + after: [][]byte{{1}, {2}, {3}, {4}, {3}}, + disassembly: "OP_PICK", + }, + { + name: "Pick2", + before: [][]byte{{1}, {2}, {3}, {4}, {2}}, + script: []byte{txscript.OP_PICK}, + after: [][]byte{{1}, {2}, {3}, {4}, {2}}, + disassembly: "OP_PICK", + }, + { + name: "Pick too little", + before: [][]byte{{1}, {1}}, + script: []byte{txscript.OP_PICK}, + expectedReturn: txscript.ErrStackUnderflow, + disassembly: "OP_PICK", + }, + { + name: "Pick nothing", + before: [][]byte{{}}, + script: []byte{txscript.OP_PICK}, + expectedReturn: txscript.ErrStackUnderflow, + disassembly: "OP_PICK", + }, + { + name: "Pick no args", + before: [][]byte{}, + script: []byte{txscript.OP_PICK}, + expectedReturn: txscript.ErrStackUnderflow, + disassembly: "OP_PICK", + }, + { + name: "Pick stupid numbers", + before: [][]byte{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, + script: []byte{txscript.OP_PICK}, + expectedReturn: txscript.ErrStackNumberTooBig, + disassembly: "OP_PICK", + }, + { + name: "Roll1", + before: [][]byte{{1}, {2}, {3}, {4}, {1}}, + script: []byte{txscript.OP_ROLL}, + after: [][]byte{{1}, {2}, {4}, {3}}, + disassembly: "OP_ROLL", + }, + { + name: "Roll2", + before: [][]byte{{1}, {2}, {3}, {4}, {2}}, + script: []byte{txscript.OP_ROLL}, + after: [][]byte{{1}, {3}, {4}, {2}}, + disassembly: "OP_ROLL", + }, + { + name: "Roll too little", + before: [][]byte{{1}, {1}}, + script: []byte{txscript.OP_ROLL}, + expectedReturn: txscript.ErrStackUnderflow, + disassembly: "OP_ROLL", + }, + { + name: "Roll nothing ", + before: [][]byte{{1}}, + script: []byte{txscript.OP_ROLL}, + expectedReturn: txscript.ErrStackUnderflow, + disassembly: "OP_ROLL", + }, + { + name: "Roll no args ", + before: [][]byte{}, + script: []byte{txscript.OP_ROLL}, + expectedReturn: txscript.ErrStackUnderflow, + disassembly: "OP_ROLL", + }, + { + name: "Roll stupid numbers", + before: [][]byte{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, + script: []byte{txscript.OP_ROLL}, + expectedReturn: txscript.ErrStackNumberTooBig, + disassembly: "OP_ROLL", + }, + { + name: "ifdup (positive)", + before: [][]byte{{1}}, + script: []byte{txscript.OP_IFDUP}, + after: [][]byte{{1}, {1}}, + disassembly: "OP_IFDUP", + }, + { + name: "ifdup (negative)", + before: [][]byte{{0}}, + script: []byte{txscript.OP_IFDUP}, + after: [][]byte{{0}}, + disassembly: "OP_IFDUP", + }, + { + name: "ifdup (empty)", + before: [][]byte{}, + script: []byte{txscript.OP_IFDUP}, + expectedReturn: txscript.ErrStackUnderflow, + after: [][]byte{{0}}, + disassembly: "OP_IFDUP", + }, + { + // alt stack is purged at the end of execution + name: "toaltstack", + before: [][]byte{{1}}, + altbefore: [][]byte{}, + script: []byte{txscript.OP_TOALTSTACK}, + after: [][]byte{}, + altafter: [][]byte{}, + disassembly: "OP_TOALTSTACK", + }, + { + name: "toaltastack (empty)", + before: [][]byte{}, + altbefore: [][]byte{}, + script: []byte{txscript.OP_TOALTSTACK}, + expectedReturn: txscript.ErrStackUnderflow, + disassembly: "OP_TOALTSTACK", + }, + { + name: "fromaltastack", + before: [][]byte{}, + altbefore: [][]byte{{1}}, + script: []byte{txscript.OP_FROMALTSTACK}, + after: [][]byte{{1}}, + altafter: [][]byte{}, + disassembly: "OP_FROMALTSTACK", + }, + { + name: "fromaltastack (empty)", + before: [][]byte{}, + altbefore: [][]byte{}, + script: []byte{txscript.OP_FROMALTSTACK}, + expectedReturn: txscript.ErrStackUnderflow, + disassembly: "OP_FROMALTSTACK", + }, + { + name: "op_size (1)", + before: [][]byte{{1}}, + script: []byte{txscript.OP_SIZE}, + after: [][]byte{{1}, {1}}, + disassembly: "OP_SIZE", + }, + { + name: "op_size (5)", + before: [][]byte{{1, 2, 3, 4, 5}}, + script: []byte{txscript.OP_SIZE}, + after: [][]byte{{1, 2, 3, 4, 5}, {5}}, + disassembly: "OP_SIZE", + }, + { + name: "op_size (0)", + before: [][]byte{{}}, + script: []byte{txscript.OP_SIZE}, + // pushInt(0) actually gives an empty array, still counts as 0 + after: [][]byte{{}, {}}, + disassembly: "OP_SIZE", + }, + { + name: "op_size (invalid)", + before: [][]byte{}, + script: []byte{txscript.OP_SIZE}, + expectedReturn: txscript.ErrStackUnderflow, + disassembly: "OP_SIZE", + }, + { + name: "OP_EQUAL (valid)", + before: [][]byte{{1, 2, 3, 4}, {1, 2, 3, 4}}, + script: []byte{txscript.OP_EQUAL}, + after: [][]byte{{1}}, + disassembly: "OP_EQUAL", + }, + { + name: "OP_EQUAL (invalid)", + before: [][]byte{{1, 2, 3, 4}, {1, 2, 3, 3}}, + script: []byte{txscript.OP_EQUAL}, + after: [][]byte{{0}}, + disassembly: "OP_EQUAL", + }, + { + name: "OP_EQUAL (one arg)", + before: [][]byte{{1, 2, 3, 4}}, + script: []byte{txscript.OP_EQUAL}, + expectedReturn: txscript.ErrStackUnderflow, + after: [][]byte{{0}}, + disassembly: "OP_EQUAL", + }, + { + name: "OP_EQUAL (no arg)", + before: [][]byte{}, + script: []byte{txscript.OP_EQUAL}, + expectedReturn: txscript.ErrStackUnderflow, + after: [][]byte{{0}}, + disassembly: "OP_EQUAL", + }, + { + name: "OP_EQUALVERIFY (valid)", + before: [][]byte{{1, 2, 3, 4}, {1, 2, 3, 4}}, + script: []byte{txscript.OP_EQUALVERIFY}, + after: [][]byte{}, + disassembly: "OP_EQUALVERIFY", + }, + { + name: "OP_EQUALVERIFY (invalid)", + before: [][]byte{{1, 2, 3, 4}, {1, 2, 3, 3}}, + script: []byte{txscript.OP_EQUALVERIFY}, + expectedReturn: txscript.ErrStackVerifyFailed, + after: [][]byte{}, + disassembly: "OP_EQUALVERIFY", + }, + { + name: "OP_EQUALVERIFY (one arg)", + before: [][]byte{{1, 2, 3, 4}}, + script: []byte{txscript.OP_EQUALVERIFY}, + expectedReturn: txscript.ErrStackUnderflow, + disassembly: "OP_EQUALVERIFY", + }, + { + name: "OP_EQUALVERIFY (no arg)", + before: [][]byte{}, + script: []byte{txscript.OP_EQUALVERIFY}, + expectedReturn: txscript.ErrStackUnderflow, + disassembly: "OP_EQUALVERIFY", + }, + { + name: "OP_1NEGATE", + before: [][]byte{}, + script: []byte{txscript.OP_1NEGATE}, + after: [][]byte{{0x81}}, + disassembly: "-1", + }, + { + name: "add one to minus one", + before: [][]byte{}, + script: []byte{txscript.OP_1NEGATE, txscript.OP_1ADD}, + after: [][]byte{{}}, // 0 + disassembly: "-1 OP_1ADD", + }, + { + name: "OP_ABS (positive)", + before: [][]byte{{1}}, + script: []byte{txscript.OP_ABS}, + after: [][]byte{{1}}, + disassembly: "OP_ABS", + }, + { + name: "OP_ABS (negative)", + before: [][]byte{{0x81}}, + script: []byte{txscript.OP_ABS}, + after: [][]byte{{1}}, + disassembly: "OP_ABS", + }, + { + name: "OP_ABS (empty)", + before: [][]byte{}, + script: []byte{txscript.OP_ABS}, + expectedReturn: txscript.ErrStackUnderflow, + disassembly: "OP_ABS", + }, + { + name: "op_data_1", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_1, 1}, + after: [][]byte{{1}}, + disassembly: "01", + }, + { + name: "op_data_2", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_2, 1, 2}, + after: [][]byte{{1, 2}}, + disassembly: "0102", + }, + { + name: "op_data_3", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_3, 1, 2, 3}, + after: [][]byte{{1, 2, 3}}, + disassembly: "010203", + }, + { + name: "op_data_4", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_4, 1, 2, 3, 4}, + after: [][]byte{{1, 2, 3, 4}}, + disassembly: "01020304", + }, + { + name: "op_data_5", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_5, 1, 2, 3, 4, 5}, + after: [][]byte{{1, 2, 3, 4, 5}}, + disassembly: "0102030405", + }, + { + name: "op_data_6", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_6, 1, 2, 3, 4, 5, 6}, + after: [][]byte{{1, 2, 3, 4, 5, 6}}, + disassembly: "010203040506", + }, + { + name: "op_data_7", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_7, 1, 2, 3, 4, 5, 6, 7}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7}}, + disassembly: "01020304050607", + }, + { + name: "op_data_8", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_8, 1, 2, 3, 4, 5, 6, 7, 8}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8}}, + disassembly: "0102030405060708", + }, + { + name: "op_data_9", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_9, 1, 2, 3, 4, 5, 6, 7, 8, 9}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9}}, + disassembly: "010203040506070809", + }, + { + name: "op_data_10", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}}, + disassembly: "0102030405060708090a", + }, + { + name: "op_data_11", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_11, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}}, + disassembly: "0102030405060708090a0b", + }, + { + name: "op_data_12", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_12, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}}, + disassembly: "0102030405060708090a0b0c", + }, + { + name: "op_data_13", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_13, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}}, + disassembly: "0102030405060708090a0b0c0d", + }, + { + name: "op_data_14", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_14, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}}, + disassembly: "0102030405060708090a0b0c0d0e", + }, + { + name: "op_data_15", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_15, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15}}, + disassembly: "0102030405060708090a0b0c0d0e0f", + }, + { + name: "op_data_16", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_16, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16}}, + disassembly: "0102030405060708090a0b0c0d0e0f10", + }, + { + name: "op_data_17", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_17, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17}}, + disassembly: "0102030405060708090a0b0c0d0e0f1011", + }, + { + name: "op_data_18", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_18, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112", + }, + { + name: "op_data_19", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_19, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19}}, + disassembly: "0102030405060708090a0b0c0d0e0f10111213", + }, + { + name: "op_data_20", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_20, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20}}, + disassembly: "0102030405060708090a0b0c0d0e0f1011121314", + }, + { + name: "op_data_21", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_21, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415", + }, + { + name: "op_data_22", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_22, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22}}, + disassembly: "0102030405060708090a0b0c0d0e0f10111213141516", + }, + { + name: "op_data_23", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_23, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23}}, + disassembly: "0102030405060708090a0b0c0d0e0f1011121314151617", + }, + { + name: "op_data_24", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_24, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718", + }, + { + name: "op_data_25", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_25, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25}}, + disassembly: "0102030405060708090a0b0c0d0e0f10111213141516171819", + }, + { + name: "op_data_26", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_26, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a", + }, + { + name: "op_data_27", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_27, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b", + }, + { + name: "op_data_28", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_28, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c", + }, + { + name: "op_data_29", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_29, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d", + }, + { + name: "op_data_30", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_30, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e", + }, + { + name: "op_data_31", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_31, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + }, + { + name: "op_data_32", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_32, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20", + }, + { + name: "op_data_33", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_33, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021", + }, + { + name: "op_data_34", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_34, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122", + }, + { + name: "op_data_35", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_35, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212223", + }, + { + name: "op_data_36", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_36, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324", + }, + { + name: "op_data_37", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_37, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425", + }, + { + name: "op_data_38", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_38, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212223242526", + }, + { + name: "op_data_39", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_39, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324252627", + }, + { + name: "op_data_40", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_40, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728", + }, + { + name: "op_data_41", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_41, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212223242526272829", + }, + { + name: "op_data_42", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_42, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a", + }, + { + name: "op_data_43", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_43, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b", + }, + { + name: "op_data_44", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_44, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c", + }, + { + name: "op_data_45", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_45, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d", + }, + { + name: "op_data_46", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_46, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e", + }, + { + name: "op_data_47", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_47, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f", + }, + { + name: "op_data_48", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_48, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f30", + }, + { + name: "op_data_49", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_49, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031", + }, + { + name: "op_data_50", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_50, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132", + }, + { + name: "op_data_51", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_51, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f30313233", + }, + { + name: "op_data_52", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_52, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334", + }, + { + name: "op_data_53", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_53, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435", + }, + { + name: "op_data_54", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_54, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f30313233343536", + }, + { + name: "op_data_55", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_55, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637", + }, + { + name: "op_data_56", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_56, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738", + }, + { + name: "op_data_57", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_57, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f30313233343536373839", + }, + { + name: "op_data_58", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_58, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a", + }, + { + name: "op_data_59", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_59, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b", + }, + { + name: "op_data_60", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_60, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c", + }, + { + name: "op_data_61", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_61, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d", + }, + { + name: "op_data_62", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_62, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e", + }, + { + name: "op_data_63", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_63, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + }, + { + name: "op_data_64", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_64, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40", + }, + { + name: "op_data_65", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_65, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f4041", + }, + { + name: "op_data_66", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_66, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142", + }, + { + name: "op_data_67", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_67, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66, 67}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40414243", + }, + { + name: "op_data_68", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_68, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f4041424344", + }, + { + name: "op_data_69", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_69, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445", + }, + { + name: "op_data_70", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_70, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 70}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40414243444546", + }, + { + name: "op_data_71", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_71, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 70, 71}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f4041424344454647", + }, + { + name: "op_data_72", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_72, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 70, 71, 72}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748", + }, + { + name: "op_data_73", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_73, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40414243444546474849", + }, + { + name: "op_data_74", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_74, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + }}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a", + }, + { + name: "op_data_75", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_75, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75}, + after: [][]byte{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75}}, + disassembly: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b", + }, + { + name: "op_data too short", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_2, 1}, + expectedReturn: txscript.ErrStackShortScript, + disassemblyerr: txscript.ErrStackShortScript, + }, + { + name: "op_pushdata_1", + before: [][]byte{}, + script: []byte{txscript.OP_PUSHDATA1, 1, 2}, + after: [][]byte{{2}}, + disassembly: "02", + }, + { + name: "op_pushdata_1 too short", + script: []byte{txscript.OP_PUSHDATA1, 1}, + expectedReturn: txscript.ErrStackShortScript, + disassemblyerr: txscript.ErrStackShortScript, + }, + { + name: "op_pushdata_2", + before: [][]byte{}, + script: []byte{txscript.OP_PUSHDATA2, 2, 0, 2, 4}, + after: [][]byte{{2, 4}}, + disassembly: "0204", + }, + { + name: "op_pushdata_2 too short", + script: []byte{txscript.OP_PUSHDATA2, 2, 0}, + expectedReturn: txscript.ErrStackShortScript, + disassemblyerr: txscript.ErrStackShortScript, + }, + { + name: "op_pushdata_4", + before: [][]byte{}, + script: []byte{txscript.OP_PUSHDATA4, 4, 0, 0, 0, 2, 4, 8, 16}, + after: [][]byte{{2, 4, 8, 16}}, + disassembly: "02040810", + }, + { + name: "op_pushdata_4 too short", + script: []byte{txscript.OP_PUSHDATA4, 4, 0, 0, 0}, + expectedReturn: txscript.ErrStackShortScript, + disassemblyerr: txscript.ErrStackShortScript, + }, + // XXX also pushdata cases where the pushed data isn't long enough, + // no real error type defined for that as of yet. + + { + name: "OP_SHA1 no args", + before: [][]byte{}, + script: []byte{txscript.OP_SHA1}, + expectedReturn: txscript.ErrStackUnderflow, + disassembly: "OP_SHA1", + }, + { + name: "OP_SHA1", + before: [][]byte{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}}, + script: []byte{txscript.OP_SHA1}, + after: [][]byte{{0x5d, 0x21, 0x1b, 0xad, 0x8f, 0x4e, + 0xe7, 0x0e, 0x16, 0xc7, 0xd3, 0x43, 0xa8, 0x38, 0xfc, + 0x34, 0x4a, 0x1e, 0xd9, 0x61}}, + disassembly: "OP_SHA1", + }, + { + name: "OP_SHA256 no args", + before: [][]byte{}, + script: []byte{txscript.OP_SHA256}, + expectedReturn: txscript.ErrStackUnderflow, + disassembly: "OP_SHA256", + }, + { + name: "OP_RIPEMD160 no args", + before: [][]byte{}, + script: []byte{txscript.OP_RIPEMD160}, + expectedReturn: txscript.ErrStackUnderflow, + disassembly: "OP_RIPEMD160", + }, + // data taken from transaction + // 4cbb6924e5f9788d7fcf0a1ce8c175bf9befa43eb5e23386b69bc4dce49da71c + // in block 103307 + // First do it in component parts to make sure the sha256 and ripemd160 + // opcodes work + { + name: "op_hash160 the hard way", + before: [][]byte{{0x04, 0x0f, 0xa4, 0x92, 0xe3, 0x59, 0xde, 0xe8, 0x4b, + 0x53, 0xfe, 0xc5, 0xe9, 0x18, 0xb7, 0xfd, 0x62, 0x1e, + 0xb7, 0xe5, 0x63, 0x38, 0xc5, 0xfb, 0xff, 0x71, 0xd9, + 0x1d, 0x17, 0x22, 0xda, 0x58, 0xf1, 0x0f, 0x9e, 0x8f, + 0x41, 0x2f, 0x39, 0x9c, 0xb3, 0x06, 0x70, 0xa7, 0x27, + 0xe9, 0x91, 0x94, 0xaa, 0x69, 0x27, 0xaf, 0xf2, 0x54, + 0x16, 0xec, 0x48, 0x9d, 0x45, 0x3a, 0x80, 0x7e, 0x03, + 0xc0, 0x83}}, + script: []byte{txscript.OP_SHA256, txscript.OP_RIPEMD160}, + after: [][]byte{{0x8b, 0xfa, 0x5c, 0x1f, 0x68, 0x5f, 0x13, 0x86, 0x3e, + 0x74, 0x2e, 0x1b, 0xaf, 0x15, 0xf1, 0x71, 0xad, 0x49, + 0x8b, 0x8f}}, + disassembly: "OP_SHA256 OP_RIPEMD160", + }, + // Then test it the ``normal'' way. + { + name: "op_hash160", + before: [][]byte{{0x04, 0x0f, 0xa4, 0x92, 0xe3, 0x59, 0xde, 0xe8, 0x4b, + 0x53, 0xfe, 0xc5, 0xe9, 0x18, 0xb7, 0xfd, 0x62, 0x1e, + 0xb7, 0xe5, 0x63, 0x38, 0xc5, 0xfb, 0xff, 0x71, 0xd9, + 0x1d, 0x17, 0x22, 0xda, 0x58, 0xf1, 0x0f, 0x9e, 0x8f, + 0x41, 0x2f, 0x39, 0x9c, 0xb3, 0x06, 0x70, 0xa7, 0x27, + 0xe9, 0x91, 0x94, 0xaa, 0x69, 0x27, 0xaf, 0xf2, 0x54, + 0x16, 0xec, 0x48, 0x9d, 0x45, 0x3a, 0x80, 0x7e, 0x03, + 0xc0, 0x83}}, + script: []byte{txscript.OP_HASH160}, + after: [][]byte{{0x8b, 0xfa, 0x5c, 0x1f, 0x68, 0x5f, 0x13, 0x86, 0x3e, + 0x74, 0x2e, 0x1b, 0xaf, 0x15, 0xf1, 0x71, 0xad, 0x49, + 0x8b, 0x8f}}, + disassembly: "OP_HASH160", + }, + // now with pushing. (mostly to check the disassembly) + { + name: "op_hash160 full script", + before: [][]byte{}, + script: []byte{txscript.OP_DATA_65, + 0x04, 0x0f, 0xa4, 0x92, 0xe3, 0x59, 0xde, 0xe8, 0x4b, + 0x53, 0xfe, 0xc5, 0xe9, 0x18, 0xb7, 0xfd, 0x62, 0x1e, + 0xb7, 0xe5, 0x63, 0x38, 0xc5, 0xfb, 0xff, 0x71, 0xd9, + 0x1d, 0x17, 0x22, 0xda, 0x58, 0xf1, 0x0f, 0x9e, 0x8f, + 0x41, 0x2f, 0x39, 0x9c, 0xb3, 0x06, 0x70, 0xa7, 0x27, + 0xe9, 0x91, 0x94, 0xaa, 0x69, 0x27, 0xaf, 0xf2, 0x54, + 0x16, 0xec, 0x48, 0x9d, 0x45, 0x3a, 0x80, 0x7e, 0x03, + 0xc0, 0x83, + txscript.OP_HASH160, txscript.OP_DATA_20, + 0x8b, 0xfa, 0x5c, 0x1f, 0x68, 0x5f, 0x13, 0x86, 0x3e, + 0x74, 0x2e, 0x1b, 0xaf, 0x15, 0xf1, 0x71, 0xad, 0x49, + 0x8b, 0x8f, + txscript.OP_EQUALVERIFY}, + after: [][]byte{}, + disassembly: "040fa492e359dee84b53fec5e918b7fd621eb7e56338c5fbff71d91d1722da58f10f9e8f412f399cb30670a727e99194aa6927aff25416ec489d453a807e03c083 OP_HASH160 8bfa5c1f685f13863e742e1baf15f171ad498b8f OP_EQUALVERIFY", + }, + { + name: "op_hash160 no args", + script: []byte{txscript.OP_HASH160}, + expectedReturn: txscript.ErrStackUnderflow, + disassembly: "OP_HASH160", + }, + // hash256 test taken from spend of: + // 09f691b2263260e71f363d1db51ff3100d285956a40cc0e4f8c8c2c4a80559b1 + { + name: "op_hash256", + before: [][]byte{{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3b, 0xa3, 0xed, 0xfd, 0x7a, 0x7b, 0x12, 0xb2, + 0x7a, 0xc7, 0x2c, 0x3e, 0x67, 0x76, 0x8f, 0x61, 0x7f, + 0xc8, 0x1b, 0xc3, 0x88, 0x8a, 0x51, 0x32, 0x3a, 0x9f, + 0xb8, 0xaa, 0x4b, 0x1e, 0x5e, 0x4a, 0x29, 0xab, 0x5f, + 0x49, 0xff, 0xff, 0x00, 0x1d, 0x1d, 0xac, 0x2b, 0x7c}}, + script: []byte{txscript.OP_HASH256}, + after: [][]byte{{0x6f, 0xe2, 0x8c, 0x0a, 0xb6, 0xf1, 0xb3, 0x72, 0xc1, + 0xa6, 0xa2, 0x46, 0xae, 0x63, 0xf7, 0x4f, 0x93, 0x1e, + 0x83, 0x65, 0xe1, 0x5a, 0x08, 0x9c, 0x68, 0xd6, 0x19, + 0x00, 0x00, 0x00, 0x00, 0x00}}, + disassembly: "OP_HASH256", + }, + { + name: "OP_HASH256 no args", + script: []byte{txscript.OP_HASH256}, + expectedReturn: txscript.ErrStackUnderflow, + disassembly: "OP_HASH256", + }, + // We need a more involved setup to test OP_CHECKSIG and + // OP_CHECKMULTISIG (see script_test.go) but we can test it with + // invalid arguments here quite easily. + { + name: "OP_CHECKSIG one arg", + script: []byte{txscript.OP_1, txscript.OP_CHECKSIG}, + expectedReturn: txscript.ErrStackUnderflow, + disassembly: "1 OP_CHECKSIG", + nSigOps: 1, + nPreciseSigOps: 1, + }, + { + name: "OP_CHECKSIG no arg", + script: []byte{txscript.OP_CHECKSIG}, + expectedReturn: txscript.ErrStackUnderflow, + disassembly: "OP_CHECKSIG", + nSigOps: 1, + nPreciseSigOps: 1, + }, + { + name: "OP_CHECKSIGVERIFY one arg", + script: []byte{txscript.OP_1, + txscript.OP_CHECKSIGVERIFY}, + expectedReturn: txscript.ErrStackUnderflow, + disassembly: "1 OP_CHECKSIGVERIFY", + nSigOps: 1, + nPreciseSigOps: 1, + }, + { + name: "OP_CHECKSIGVERIFY no arg", + script: []byte{txscript.OP_CHECKSIGVERIFY}, + expectedReturn: txscript.ErrStackUnderflow, + disassembly: "OP_CHECKSIGVERIFY", + nSigOps: 1, + nPreciseSigOps: 1, + }, + { + name: "OP_CHECKMULTISIG no args", + script: []byte{txscript.OP_CHECKMULTISIG}, + expectedReturn: txscript.ErrStackUnderflow, + disassembly: "OP_CHECKMULTISIG", + nSigOps: 20, + nPreciseSigOps: 20, + }, + { + name: "OP_CHECKMULTISIG huge number", + script: []byte{txscript.OP_PUSHDATA1, + 0x9, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, + txscript.OP_CHECKMULTISIG}, + expectedReturn: txscript.ErrStackNumberTooBig, + disassembly: "010203040506070809 OP_CHECKMULTISIG", + nSigOps: 20, + nPreciseSigOps: 20, + }, + { + name: "OP_CHECKMULTISIG too many keys", + script: []byte{txscript.OP_DATA_1, 21, + txscript.OP_CHECKMULTISIG}, + expectedReturn: txscript.ErrStackTooManyPubkeys, + disassembly: "15 OP_CHECKMULTISIG", + nSigOps: 20, + nPreciseSigOps: 20, + }, + { + name: "OP_CHECKMULTISIG lying about pubkeys", + script: []byte{txscript.OP_1, + txscript.OP_CHECKMULTISIG}, + expectedReturn: txscript.ErrStackUnderflow, + disassembly: "1 OP_CHECKMULTISIG", + nSigOps: 20, + nPreciseSigOps: 1, + }, + { + // pubkey comes from blockchain + name: "OP_CHECKMULTISIG no sigs", + script: []byte{ + txscript.OP_DATA_65, + 0x04, 0xae, 0x1a, 0x62, 0xfe, 0x09, 0xc5, 0xf5, 0x1b, + 0x13, 0x90, 0x5f, 0x07, 0xf0, 0x6b, 0x99, 0xa2, 0xf7, + 0x15, 0x9b, 0x22, 0x25, 0xf3, 0x74, 0xcd, 0x37, 0x8d, + 0x71, 0x30, 0x2f, 0xa2, 0x84, 0x14, 0xe7, 0xaa, 0xb3, + 0x73, 0x97, 0xf5, 0x54, 0xa7, 0xdf, 0x5f, 0x14, 0x2c, + 0x21, 0xc1, 0xb7, 0x30, 0x3b, 0x8a, 0x06, 0x26, 0xf1, + 0xba, 0xde, 0xd5, 0xc7, 0x2a, 0x70, 0x4f, 0x7e, 0x6c, + 0xd8, 0x4c, + txscript.OP_1, + txscript.OP_CHECKMULTISIG}, + expectedReturn: txscript.ErrStackUnderflow, + disassembly: "04ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84c 1 OP_CHECKMULTISIG", + nSigOps: 20, + nPreciseSigOps: 1, + }, + { + // pubkey comes from blockchain + name: "OP_CHECKMULTISIG sigs huge no", + script: []byte{ + txscript.OP_PUSHDATA1, + 0x9, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, + txscript.OP_DATA_65, + 0x04, 0xae, 0x1a, 0x62, 0xfe, 0x09, 0xc5, 0xf5, 0x1b, + 0x13, 0x90, 0x5f, 0x07, 0xf0, 0x6b, 0x99, 0xa2, 0xf7, + 0x15, 0x9b, 0x22, 0x25, 0xf3, 0x74, 0xcd, 0x37, 0x8d, + 0x71, 0x30, 0x2f, 0xa2, 0x84, 0x14, 0xe7, 0xaa, 0xb3, + 0x73, 0x97, 0xf5, 0x54, 0xa7, 0xdf, 0x5f, 0x14, 0x2c, + 0x21, 0xc1, 0xb7, 0x30, 0x3b, 0x8a, 0x06, 0x26, 0xf1, + 0xba, 0xde, 0xd5, 0xc7, 0x2a, 0x70, 0x4f, 0x7e, 0x6c, + 0xd8, 0x4c, + txscript.OP_1, + txscript.OP_CHECKMULTISIG}, + expectedReturn: txscript.ErrStackNumberTooBig, + disassembly: "010203040506070809 04ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84c 1 OP_CHECKMULTISIG", + nSigOps: 20, + nPreciseSigOps: 1, + }, + { + name: "OP_CHECKMULTISIG too few sigs", + script: []byte{txscript.OP_1, + txscript.OP_DATA_65, + 0x04, 0xae, 0x1a, 0x62, 0xfe, 0x09, 0xc5, 0xf5, 0x1b, + 0x13, 0x90, 0x5f, 0x07, 0xf0, 0x6b, 0x99, 0xa2, 0xf7, + 0x15, 0x9b, 0x22, 0x25, 0xf3, 0x74, 0xcd, 0x37, 0x8d, + 0x71, 0x30, 0x2f, 0xa2, 0x84, 0x14, 0xe7, 0xaa, 0xb3, + 0x73, 0x97, 0xf5, 0x54, 0xa7, 0xdf, 0x5f, 0x14, 0x2c, + 0x21, 0xc1, 0xb7, 0x30, 0x3b, 0x8a, 0x06, 0x26, 0xf1, + 0xba, 0xde, 0xd5, 0xc7, 0x2a, 0x70, 0x4f, 0x7e, 0x6c, + 0xd8, 0x4c, + txscript.OP_1, + txscript.OP_CHECKMULTISIG}, + expectedReturn: txscript.ErrStackUnderflow, + disassembly: "1 04ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84c 1 OP_CHECKMULTISIG", + nSigOps: 20, + nPreciseSigOps: 1, + }, + { + // pubkey and sig comes from blockchain, are unrelated + name: "OP_CHECKMULTISIG won't verify", + script: []byte{txscript.OP_1, + txscript.OP_DATA_71, + 0x30, 0x44, 0x02, 0x20, 0x4e, 0x45, 0xe1, 0x69, 0x32, + 0xb8, 0xaf, 0x51, 0x49, 0x61, 0xa1, 0xd3, 0xa1, 0xa2, + 0x5f, 0xdf, 0x3f, 0x4f, 0x77, 0x32, 0xe9, 0xd6, 0x24, + 0xc6, 0xc6, 0x15, 0x48, 0xab, 0x5f, 0xb8, 0xcd, 0x41, + 0x02, 0x20, 0x18, 0x15, 0x22, 0xec, 0x8e, 0xca, 0x07, + 0xde, 0x48, 0x60, 0xa4, 0xac, 0xdd, 0x12, 0x90, 0x9d, + 0x83, 0x1c, 0xc5, 0x6c, 0xbb, 0xac, 0x46, 0x22, 0x08, + 0x22, 0x21, 0xa8, 0x76, 0x8d, 0x1d, 0x09, 0x01, + txscript.OP_1, + txscript.OP_DATA_65, + 0x04, 0xae, 0x1a, 0x62, 0xfe, 0x09, 0xc5, 0xf5, 0x1b, + 0x13, 0x90, 0x5f, 0x07, 0xf0, 0x6b, 0x99, 0xa2, 0xf7, + 0x15, 0x9b, 0x22, 0x25, 0xf3, 0x74, 0xcd, 0x37, 0x8d, + 0x71, 0x30, 0x2f, 0xa2, 0x84, 0x14, 0xe7, 0xaa, 0xb3, + 0x73, 0x97, 0xf5, 0x54, 0xa7, 0xdf, 0x5f, 0x14, 0x2c, + 0x21, 0xc1, 0xb7, 0x30, 0x3b, 0x8a, 0x06, 0x26, 0xf1, + 0xba, 0xde, 0xd5, 0xc7, 0x2a, 0x70, 0x4f, 0x7e, 0x6c, + 0xd8, 0x4c, + txscript.OP_1, + txscript.OP_CHECKMULTISIG}, + after: [][]byte{{0}}, + disassembly: "1 304402204e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd410220181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d0901 1 04ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84c 1 OP_CHECKMULTISIG", + nSigOps: 20, + nPreciseSigOps: 1, + }, + { + // invalid pubkey means that it fails to validate, not an + // error. There are pubkeys in the blockchain that don't + // parse with any validity. + name: "OP_CHECKMULTISIG sigs bad pubkey", + script: []byte{txscript.OP_1, + txscript.OP_DATA_71, + 0x30, 0x44, 0x02, 0x20, 0x4e, 0x45, 0xe1, 0x69, 0x32, + 0xb8, 0xaf, 0x51, 0x49, 0x61, 0xa1, 0xd3, 0xa1, 0xa2, + 0x5f, 0xdf, 0x3f, 0x4f, 0x77, 0x32, 0xe9, 0xd6, 0x24, + 0xc6, 0xc6, 0x15, 0x48, 0xab, 0x5f, 0xb8, 0xcd, 0x41, + 0x02, 0x20, 0x18, 0x15, 0x22, 0xec, 0x8e, 0xca, 0x07, + 0xde, 0x48, 0x60, 0xa4, 0xac, 0xdd, 0x12, 0x90, 0x9d, + 0x83, 0x1c, 0xc5, 0x6c, 0xbb, 0xac, 0x46, 0x22, 0x08, + 0x22, 0x21, 0xa8, 0x76, 0x8d, 0x1d, 0x09, 0x01, + txscript.OP_1, + txscript.OP_1, txscript.OP_1, + txscript.OP_CHECKMULTISIG}, + after: [][]byte{{0}}, + disassembly: "1 304402204e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd410220181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d0901 1 1 1 OP_CHECKMULTISIG", + nSigOps: 20, + nPreciseSigOps: 1, + }, + // XXX(oga) Test multisig when extra arg is missing. needs valid sig. + // disabled opcodes + { + name: "OP_CHECKMULTISIGVERIFY no args", + script: []byte{txscript.OP_CHECKMULTISIGVERIFY}, + expectedReturn: txscript.ErrStackUnderflow, + disassembly: "OP_CHECKMULTISIGVERIFY", + nSigOps: 20, + nPreciseSigOps: 20, + }, + { + name: "OP_CHECKMULTISIGVERIFY huge number", + script: []byte{txscript.OP_PUSHDATA1, + 0x9, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, + txscript.OP_CHECKMULTISIGVERIFY}, + expectedReturn: txscript.ErrStackNumberTooBig, + disassembly: "010203040506070809 OP_CHECKMULTISIGVERIFY", + nSigOps: 20, + nPreciseSigOps: 20, + }, + { + name: "OP_CHECKMULTISIGVERIFY too many keys", + script: []byte{txscript.OP_DATA_1, 21, + txscript.OP_CHECKMULTISIGVERIFY}, + expectedReturn: txscript.ErrStackTooManyPubkeys, + disassembly: "15 OP_CHECKMULTISIGVERIFY", + nSigOps: 20, + nPreciseSigOps: 20, + }, + { + name: "OP_CHECKMULTISIGVERIFY lying about pubkeys", + script: []byte{txscript.OP_1, + txscript.OP_CHECKMULTISIGVERIFY}, + expectedReturn: txscript.ErrStackUnderflow, + disassembly: "1 OP_CHECKMULTISIGVERIFY", + nSigOps: 20, + nPreciseSigOps: 1, + }, + { + // pubkey comes from blockchain + name: "OP_CHECKMULTISIGVERIFY no sigs", + script: []byte{ + txscript.OP_DATA_65, + 0x04, 0xae, 0x1a, 0x62, 0xfe, 0x09, 0xc5, 0xf5, 0x1b, + 0x13, 0x90, 0x5f, 0x07, 0xf0, 0x6b, 0x99, 0xa2, 0xf7, + 0x15, 0x9b, 0x22, 0x25, 0xf3, 0x74, 0xcd, 0x37, 0x8d, + 0x71, 0x30, 0x2f, 0xa2, 0x84, 0x14, 0xe7, 0xaa, 0xb3, + 0x73, 0x97, 0xf5, 0x54, 0xa7, 0xdf, 0x5f, 0x14, 0x2c, + 0x21, 0xc1, 0xb7, 0x30, 0x3b, 0x8a, 0x06, 0x26, 0xf1, + 0xba, 0xde, 0xd5, 0xc7, 0x2a, 0x70, 0x4f, 0x7e, 0x6c, + 0xd8, 0x4c, + txscript.OP_1, + txscript.OP_CHECKMULTISIGVERIFY}, + expectedReturn: txscript.ErrStackUnderflow, + disassembly: "04ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84c 1 OP_CHECKMULTISIGVERIFY", + nSigOps: 20, + nPreciseSigOps: 1, + }, + { + name: "OP_CHECKMULTISIGVERIFY sigs huge no", + script: []byte{ + txscript.OP_PUSHDATA1, + 0x9, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, + txscript.OP_DATA_65, + 0x04, 0xae, 0x1a, 0x62, 0xfe, 0x09, 0xc5, 0xf5, 0x1b, + 0x13, 0x90, 0x5f, 0x07, 0xf0, 0x6b, 0x99, 0xa2, 0xf7, + 0x15, 0x9b, 0x22, 0x25, 0xf3, 0x74, 0xcd, 0x37, 0x8d, + 0x71, 0x30, 0x2f, 0xa2, 0x84, 0x14, 0xe7, 0xaa, 0xb3, + 0x73, 0x97, 0xf5, 0x54, 0xa7, 0xdf, 0x5f, 0x14, 0x2c, + 0x21, 0xc1, 0xb7, 0x30, 0x3b, 0x8a, 0x06, 0x26, 0xf1, + 0xba, 0xde, 0xd5, 0xc7, 0x2a, 0x70, 0x4f, 0x7e, 0x6c, + 0xd8, 0x4c, + txscript.OP_1, + txscript.OP_CHECKMULTISIGVERIFY}, + expectedReturn: txscript.ErrStackNumberTooBig, + disassembly: "010203040506070809 04ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84c 1 OP_CHECKMULTISIGVERIFY", + nSigOps: 20, + nPreciseSigOps: 1, + }, + { + name: "OP_CHECKMULTISIGVERIFY too few sigs", + script: []byte{txscript.OP_1, + txscript.OP_DATA_65, + 0x04, 0xae, 0x1a, 0x62, 0xfe, 0x09, 0xc5, 0xf5, 0x1b, + 0x13, 0x90, 0x5f, 0x07, 0xf0, 0x6b, 0x99, 0xa2, 0xf7, + 0x15, 0x9b, 0x22, 0x25, 0xf3, 0x74, 0xcd, 0x37, 0x8d, + 0x71, 0x30, 0x2f, 0xa2, 0x84, 0x14, 0xe7, 0xaa, 0xb3, + 0x73, 0x97, 0xf5, 0x54, 0xa7, 0xdf, 0x5f, 0x14, 0x2c, + 0x21, 0xc1, 0xb7, 0x30, 0x3b, 0x8a, 0x06, 0x26, 0xf1, + 0xba, 0xde, 0xd5, 0xc7, 0x2a, 0x70, 0x4f, 0x7e, 0x6c, + 0xd8, 0x4c, + txscript.OP_1, + txscript.OP_CHECKMULTISIGVERIFY}, + expectedReturn: txscript.ErrStackUnderflow, + disassembly: "1 04ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84c 1 OP_CHECKMULTISIGVERIFY", + nSigOps: 20, + nPreciseSigOps: 1, + }, + { + // pubkey and sig comes from blockchain, are unrelated + name: "OP_CHECKMULTISIGVERIFY won't verify", + script: []byte{txscript.OP_1, + txscript.OP_DATA_71, + 0x30, 0x44, 0x02, 0x20, 0x4e, 0x45, 0xe1, 0x69, 0x32, + 0xb8, 0xaf, 0x51, 0x49, 0x61, 0xa1, 0xd3, 0xa1, 0xa2, + 0x5f, 0xdf, 0x3f, 0x4f, 0x77, 0x32, 0xe9, 0xd6, 0x24, + 0xc6, 0xc6, 0x15, 0x48, 0xab, 0x5f, 0xb8, 0xcd, 0x41, + 0x02, 0x20, 0x18, 0x15, 0x22, 0xec, 0x8e, 0xca, 0x07, + 0xde, 0x48, 0x60, 0xa4, 0xac, 0xdd, 0x12, 0x90, 0x9d, + 0x83, 0x1c, 0xc5, 0x6c, 0xbb, 0xac, 0x46, 0x22, 0x08, + 0x22, 0x21, 0xa8, 0x76, 0x8d, 0x1d, 0x09, 0x01, + txscript.OP_1, + txscript.OP_DATA_65, + 0x04, 0xae, 0x1a, 0x62, 0xfe, 0x09, 0xc5, 0xf5, 0x1b, + 0x13, 0x90, 0x5f, 0x07, 0xf0, 0x6b, 0x99, 0xa2, 0xf7, + 0x15, 0x9b, 0x22, 0x25, 0xf3, 0x74, 0xcd, 0x37, 0x8d, + 0x71, 0x30, 0x2f, 0xa2, 0x84, 0x14, 0xe7, 0xaa, 0xb3, + 0x73, 0x97, 0xf5, 0x54, 0xa7, 0xdf, 0x5f, 0x14, 0x2c, + 0x21, 0xc1, 0xb7, 0x30, 0x3b, 0x8a, 0x06, 0x26, 0xf1, + 0xba, 0xde, 0xd5, 0xc7, 0x2a, 0x70, 0x4f, 0x7e, 0x6c, + 0xd8, 0x4c, + txscript.OP_1, + txscript.OP_CHECKMULTISIGVERIFY}, + expectedReturn: txscript.ErrStackVerifyFailed, + disassembly: "1 304402204e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd410220181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d0901 1 04ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84c 1 OP_CHECKMULTISIGVERIFY", + nSigOps: 20, + nPreciseSigOps: 1, + }, + { + // invalid pubkey means that it fails to validate, not an + // error. There are pubkeys in the blockchain that don't + // parse with any validity. + name: "OP_CHECKMULTISIGVERIFY sigs bad pubkey", + script: []byte{txscript.OP_1, + txscript.OP_DATA_71, + 0x30, 0x44, 0x02, 0x20, 0x4e, 0x45, 0xe1, 0x69, 0x32, + 0xb8, 0xaf, 0x51, 0x49, 0x61, 0xa1, 0xd3, 0xa1, 0xa2, + 0x5f, 0xdf, 0x3f, 0x4f, 0x77, 0x32, 0xe9, 0xd6, 0x24, + 0xc6, 0xc6, 0x15, 0x48, 0xab, 0x5f, 0xb8, 0xcd, 0x41, + 0x02, 0x20, 0x18, 0x15, 0x22, 0xec, 0x8e, 0xca, 0x07, + 0xde, 0x48, 0x60, 0xa4, 0xac, 0xdd, 0x12, 0x90, 0x9d, + 0x83, 0x1c, 0xc5, 0x6c, 0xbb, 0xac, 0x46, 0x22, 0x08, + 0x22, 0x21, 0xa8, 0x76, 0x8d, 0x1d, 0x09, 0x01, + txscript.OP_1, + txscript.OP_1, txscript.OP_1, + txscript.OP_CHECKMULTISIGVERIFY}, + expectedReturn: txscript.ErrStackVerifyFailed, + disassembly: "1 304402204e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd410220181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d0901 1 1 1 OP_CHECKMULTISIGVERIFY", + nSigOps: 20, + nPreciseSigOps: 1, + }, + { + // 201 operations + one push, should just fit limits + name: "max operations", + script: []byte{txscript.OP_1, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + }, + after: [][]byte{{1}, {1}}, + disassembly: "1 OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP", + }, + { + // 202 operations + one push + name: "too many operations", + script: []byte{txscript.OP_1, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + }, + expectedReturn: txscript.ErrStackTooManyOperations, + disassembly: "1 OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP", + }, + { + // 202 operations + one push + name: "too many operations multisig", + script: []byte{txscript.OP_1, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_DUP, + txscript.OP_DROP, + txscript.OP_1, + txscript.OP_1, + txscript.OP_1, + txscript.OP_1, + txscript.OP_2, + txscript.OP_CHECKMULTISIG, + }, + expectedReturn: txscript.ErrStackTooManyOperations, + disassembly: "1 OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP 1 1 1 1 2 OP_CHECKMULTISIG", + nSigOps: 20, + nPreciseSigOps: 2, + }, + { + name: "push largest", + // 521 bytes + before: [][]byte{}, + script: []byte{txscript.OP_PUSHDATA2, 0x08, 0x02, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}, + after: [][]byte{{ + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}}, + disassembly: "01020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607080901020304050607", + }, + { + name: "push too large", + // 521 bytes + script: []byte{txscript.OP_PUSHDATA2, 0x09, 0x02, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, + expectedReturn: txscript.ErrStackElementTooBig, + // element too big is a parse error. + disassembly: "0102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708090102030405060708", + }, + { + name: "OP_CAT disabled", + script: []byte{txscript.OP_CAT}, + expectedReturn: txscript.ErrStackOpDisabled, + disassembly: "OP_CAT", + }, + { + name: "OP_SUBSTR disabled", + script: []byte{txscript.OP_SUBSTR}, + expectedReturn: txscript.ErrStackOpDisabled, + disassembly: "OP_SUBSTR", + }, + { + name: "OP_LEFT disabled", + script: []byte{txscript.OP_LEFT}, + expectedReturn: txscript.ErrStackOpDisabled, + disassembly: "OP_LEFT", + }, + { + name: "OP_RIGHT disabled", + script: []byte{txscript.OP_RIGHT}, + expectedReturn: txscript.ErrStackOpDisabled, + disassembly: "OP_RIGHT", + }, + { + name: "OP_INVERT disabled", + script: []byte{txscript.OP_INVERT}, + expectedReturn: txscript.ErrStackOpDisabled, + disassembly: "OP_INVERT", + }, + { + name: "OP_AND disabled", + script: []byte{txscript.OP_AND}, + expectedReturn: txscript.ErrStackOpDisabled, + disassembly: "OP_AND", + }, + { + name: "OP_OR disabled", + script: []byte{txscript.OP_OR}, + expectedReturn: txscript.ErrStackOpDisabled, + disassembly: "OP_OR", + }, + { + name: "OP_XOR disabled", + script: []byte{txscript.OP_XOR}, + expectedReturn: txscript.ErrStackOpDisabled, + disassembly: "OP_XOR", + }, + { + name: "OP_2MUL disabled", + script: []byte{txscript.OP_2MUL}, + expectedReturn: txscript.ErrStackOpDisabled, + disassembly: "OP_2MUL", + }, + { + name: "OP_2DIV disabled", + script: []byte{txscript.OP_2DIV}, + expectedReturn: txscript.ErrStackOpDisabled, + disassembly: "OP_2DIV", + }, + { + name: "OP_2DIV disabled", + script: []byte{txscript.OP_2DIV}, + expectedReturn: txscript.ErrStackOpDisabled, + disassembly: "OP_2DIV", + }, + { + name: "OP_MUL disabled", + script: []byte{txscript.OP_MUL}, + expectedReturn: txscript.ErrStackOpDisabled, + disassembly: "OP_MUL", + }, + { + name: "OP_DIV disabled", + script: []byte{txscript.OP_DIV}, + expectedReturn: txscript.ErrStackOpDisabled, + disassembly: "OP_DIV", + }, + { + name: "OP_MOD disabled", + script: []byte{txscript.OP_MOD}, + expectedReturn: txscript.ErrStackOpDisabled, + disassembly: "OP_MOD", + }, + { + name: "OP_LSHIFT disabled", + script: []byte{txscript.OP_LSHIFT}, + expectedReturn: txscript.ErrStackOpDisabled, + disassembly: "OP_LSHIFT", + }, + { + name: "OP_RSHIFT disabled", + script: []byte{txscript.OP_RSHIFT}, + expectedReturn: txscript.ErrStackOpDisabled, + disassembly: "OP_RSHIFT", + }, + // Reserved opcodes + { + name: "OP_RESERVED reserved", + script: []byte{txscript.OP_RESERVED}, + expectedReturn: txscript.ErrStackReservedOpcode, + disassembly: "OP_RESERVED", + }, + { + name: "OP_VER reserved", + script: []byte{txscript.OP_VER}, + expectedReturn: txscript.ErrStackReservedOpcode, + disassembly: "OP_VER", + }, + { + name: "OP_VERIF reserved", + script: []byte{txscript.OP_VERIF}, + expectedReturn: txscript.ErrStackReservedOpcode, + disassembly: "OP_VERIF", + }, + { + name: "OP_VERNOTIF reserved", + script: []byte{txscript.OP_VERNOTIF}, + expectedReturn: txscript.ErrStackReservedOpcode, + disassembly: "OP_VERNOTIF", + }, + { + name: "OP_RESERVED1 reserved", + script: []byte{txscript.OP_RESERVED1}, + expectedReturn: txscript.ErrStackReservedOpcode, + disassembly: "OP_RESERVED1", + }, + { + name: "OP_RESERVED2 reserved", + script: []byte{txscript.OP_RESERVED2}, + expectedReturn: txscript.ErrStackReservedOpcode, + disassembly: "OP_RESERVED2", + }, + // Invalid Opcodes + { + name: "invalid opcode 186", + script: []byte{txscript.OP_UNKNOWN186}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN186", + }, + { + name: "invalid opcode 187", + script: []byte{txscript.OP_UNKNOWN187}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN187", + }, + { + name: "invalid opcode 188", + script: []byte{txscript.OP_UNKNOWN188}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN188", + }, + { + name: "invalid opcode 189", + script: []byte{txscript.OP_UNKNOWN189}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN189", + }, + { + name: "invalid opcode 190", + script: []byte{txscript.OP_UNKNOWN190}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN190", + }, + { + name: "invalid opcode 191", + script: []byte{txscript.OP_UNKNOWN191}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN191", + }, + { + name: "invalid opcode 192", + script: []byte{txscript.OP_UNKNOWN192}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN192", + }, + { + name: "invalid opcode 193", + script: []byte{txscript.OP_UNKNOWN193}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN193", + }, + { + name: "invalid opcode 194", + script: []byte{txscript.OP_UNKNOWN194}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN194", + }, + { + name: "invalid opcode 195", + script: []byte{txscript.OP_UNKNOWN195}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN195", + }, + { + name: "invalid opcode 196", + script: []byte{txscript.OP_UNKNOWN196}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN196", + }, + { + name: "invalid opcode 197", + script: []byte{txscript.OP_UNKNOWN197}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN197", + }, + { + name: "invalid opcode 198", + script: []byte{txscript.OP_UNKNOWN198}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN198", + }, + { + name: "invalid opcode 199", + script: []byte{txscript.OP_UNKNOWN199}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN199", + }, + { + name: "invalid opcode 200", + script: []byte{txscript.OP_UNKNOWN200}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN200", + }, + { + name: "invalid opcode 201", + script: []byte{txscript.OP_UNKNOWN201}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN201", + }, + { + name: "invalid opcode 202", + script: []byte{txscript.OP_UNKNOWN202}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN202", + }, + { + name: "invalid opcode 203", + script: []byte{txscript.OP_UNKNOWN203}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN203", + }, + { + name: "invalid opcode 204", + script: []byte{txscript.OP_UNKNOWN204}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN204", + }, + { + name: "invalid opcode 205", + script: []byte{txscript.OP_UNKNOWN205}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN205", + }, + { + name: "invalid opcode 206", + script: []byte{txscript.OP_UNKNOWN206}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN206", + }, + { + name: "invalid opcode 207", + script: []byte{txscript.OP_UNKNOWN207}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN207", + }, + { + name: "invalid opcode 208", + script: []byte{txscript.OP_UNKNOWN208}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN208", + }, + { + name: "invalid opcode 209", + script: []byte{txscript.OP_UNKNOWN209}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN209", + }, + { + name: "invalid opcode 210", + script: []byte{txscript.OP_UNKNOWN210}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN210", + }, + { + name: "invalid opcode 211", + script: []byte{txscript.OP_UNKNOWN211}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN211", + }, + { + name: "invalid opcode 212", + script: []byte{txscript.OP_UNKNOWN212}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN212", + }, + { + name: "invalid opcode 213", + script: []byte{txscript.OP_UNKNOWN213}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN213", + }, + { + name: "invalid opcode 214", + script: []byte{txscript.OP_UNKNOWN214}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN214", + }, + { + name: "invalid opcode 215", + script: []byte{txscript.OP_UNKNOWN215}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN215", + }, + { + name: "invalid opcode 216", + script: []byte{txscript.OP_UNKNOWN216}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN216", + }, + { + name: "invalid opcode 217", + script: []byte{txscript.OP_UNKNOWN217}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN217", + }, + { + name: "invalid opcode 218", + script: []byte{txscript.OP_UNKNOWN218}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN218", + }, + { + name: "invalid opcode 219", + script: []byte{txscript.OP_UNKNOWN219}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN219", + }, + { + name: "invalid opcode 220", + script: []byte{txscript.OP_UNKNOWN220}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN220", + }, + { + name: "invalid opcode 221", + script: []byte{txscript.OP_UNKNOWN221}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN221", + }, + { + name: "invalid opcode 222", + script: []byte{txscript.OP_UNKNOWN222}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN222", + }, + { + name: "invalid opcode 223", + script: []byte{txscript.OP_UNKNOWN223}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN223", + }, + { + name: "invalid opcode 224", + script: []byte{txscript.OP_UNKNOWN224}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN224", + }, + { + name: "invalid opcode 225", + script: []byte{txscript.OP_UNKNOWN225}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN225", + }, + { + name: "invalid opcode 226", + script: []byte{txscript.OP_UNKNOWN226}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN226", + }, + { + name: "invalid opcode 227", + script: []byte{txscript.OP_UNKNOWN227}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN227", + }, + { + name: "invalid opcode 228", + script: []byte{txscript.OP_UNKNOWN228}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN228", + }, + { + name: "invalid opcode 229", + script: []byte{txscript.OP_UNKNOWN229}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN229", + }, + { + name: "invalid opcode 230", + script: []byte{txscript.OP_UNKNOWN230}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN230", + }, + { + name: "invalid opcode 231", + script: []byte{txscript.OP_UNKNOWN231}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN231", + }, + { + name: "invalid opcode 232", + script: []byte{txscript.OP_UNKNOWN232}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN232", + }, + { + name: "invalid opcode 233", + script: []byte{txscript.OP_UNKNOWN233}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN233", + }, + { + name: "invalid opcode 234", + script: []byte{txscript.OP_UNKNOWN234}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN234", + }, + { + name: "invalid opcode 235", + script: []byte{txscript.OP_UNKNOWN235}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN235", + }, + { + name: "invalid opcode 236", + script: []byte{txscript.OP_UNKNOWN236}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN236", + }, + { + name: "invalid opcode 237", + script: []byte{txscript.OP_UNKNOWN237}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN237", + }, + { + name: "invalid opcode 238", + script: []byte{txscript.OP_UNKNOWN238}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN238", + }, + { + name: "invalid opcode 239", + script: []byte{txscript.OP_UNKNOWN239}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN239", + }, + { + name: "invalid opcode 240", + script: []byte{txscript.OP_UNKNOWN240}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN240", + }, + { + name: "invalid opcode 241", + script: []byte{txscript.OP_UNKNOWN241}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN241", + }, + { + name: "invalid opcode 242", + script: []byte{txscript.OP_UNKNOWN242}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN242", + }, + { + name: "invalid opcode 243", + script: []byte{txscript.OP_UNKNOWN243}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN243", + }, + { + name: "invalid opcode 244", + script: []byte{txscript.OP_UNKNOWN244}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN244", + }, + { + name: "invalid opcode 245", + script: []byte{txscript.OP_UNKNOWN245}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN245", + }, + { + name: "invalid opcode 246", + script: []byte{txscript.OP_UNKNOWN246}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN246", + }, + { + name: "invalid opcode 247", + script: []byte{txscript.OP_UNKNOWN247}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN247", + }, + { + name: "invalid opcode 248", + script: []byte{txscript.OP_UNKNOWN248}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN248", + }, + { + name: "invalid opcode 249", + script: []byte{txscript.OP_UNKNOWN249}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN249", + }, + { + name: "invalid opcode 250", + script: []byte{txscript.OP_UNKNOWN250}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN250", + }, + { + name: "invalid opcode 251", + script: []byte{txscript.OP_UNKNOWN251}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN251", + }, + { + name: "invalid opcode 252", + script: []byte{txscript.OP_UNKNOWN252}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_UNKNOWN252", + }, + + { + name: "invalid opcode 186 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN186, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN186 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 187 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN187, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN187 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 188 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN188, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN188 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 189 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN189, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN189 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 190 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN190, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN190 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 191 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN191, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN191 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 192 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN192, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN192 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 193 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN193, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN193 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 194 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN194, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN194 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 195 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN195, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN195 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 196 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN196, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN196 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 197 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN197, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN197 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 198 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN198, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN198 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 199 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN199, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN199 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 200 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN200, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN200 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 201 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN201, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN201 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 202 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN202, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN202 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 203 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN203, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN203 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 204 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN204, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN204 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 205 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN205, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN205 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 206 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN206, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN206 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 207 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN207, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN207 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 208 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN208, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN208 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 209 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN209, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN209 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 210 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN210, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN210 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 211 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN211, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN211 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 212 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN212, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN212 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 213 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN213, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN213 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 214 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN214, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN214 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 215 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN215, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN215 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 216 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN216, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN216 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 217 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN217, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN217 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 218 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN218, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN218 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 219 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN219, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN219 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 220 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN220, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN220 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 221 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN221, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN221 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 222 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN222, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN222 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 223 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN223, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN223 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 224 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN224, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN224 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 225 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN225, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN225 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 226 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN226, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN226 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 227 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN227, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN227 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 228 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN228, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN228 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 229 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN229, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN229 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 230 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN230, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN230 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 231 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN231, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN231 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 232 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN232, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN232 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 233 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN233, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN233 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 234 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN234, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN234 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 235 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN235, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN235 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 236 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN236, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN236 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 237 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN237, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN237 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 238 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN238, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN238 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 239 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN239, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN239 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 240 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN240, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN240 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 241 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN241, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN241 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 242 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN242, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN242 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 243 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN243, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN243 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 244 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN244, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN244 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 245 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN245, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN245 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 246 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN246, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN246 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 247 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN247, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN247 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 248 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN248, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN248 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 249 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN249, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN249 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 250 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN250, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN250 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 251 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN251, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN251 OP_ELSE 1 OP_ENDIF", + }, + { + name: "invalid opcode 252 if noexec", + script: []byte{txscript.OP_FALSE, txscript.OP_IF, txscript.OP_UNKNOWN252, txscript.OP_ELSE, txscript.OP_TRUE, txscript.OP_ENDIF}, + after: [][]byte{{0x01}}, + disassembly: "0 OP_IF OP_UNKNOWN252 OP_ELSE 1 OP_ENDIF", + }, + + { + name: "invalid opcode OP_PUBKEY", + script: []byte{txscript.OP_PUBKEY}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_PUBKEY", + }, + { + name: "invalid opcode OP_PUBKEYHASH", + script: []byte{txscript.OP_PUBKEYHASH}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_PUBKEYHASH", + }, + { + name: "invalid opcode OP_INVALIDOPCODE", + script: []byte{txscript.OP_INVALIDOPCODE}, + expectedReturn: txscript.ErrStackInvalidOpcode, + disassembly: "OP_INVALIDOPCODE", + }, +} + +func stacksEqual(a, b [][]byte) bool { + if len(a) != len(b) { + return false + } + + for i := range a { + if !bytes.Equal(a[i], b[i]) { + return false + } + } + return true +} + +func testOpcode(t *testing.T, test *detailedTest) { + // mock up fake tx. + tx := &btcwire.MsgTx{ + Version: 1, + TxIn: []*btcwire.TxIn{ + { + PreviousOutPoint: btcwire.OutPoint{ + Hash: btcwire.ShaHash{}, + Index: 0xffffffff, + }, + SignatureScript: []byte{}, + Sequence: 0xffffffff, + }, + }, + TxOut: []*btcwire.TxOut{ + { + Value: 0x12a05f200, + PkScript: []byte{}, + }, + }, + LockTime: 0, + } + + tx.TxOut[0].PkScript = test.script + + engine, err := txscript.NewScript(tx.TxIn[0].SignatureScript, + tx.TxOut[0].PkScript, 0, tx, 0) + if err != nil { + if err != test.expectedReturn { + t.Errorf("Error return not expected %s: %v %v", + test.name, test.expectedReturn, err) + return + } + return + } + engine.SetStack(test.before) + engine.SetAltStack(test.altbefore) + + // test disassembly engine. + // pc is at start of script 1, so check that DisasmScript matches + // DisasmPc. Only run this if we have a disassembly for the test. + // sine one of them have invalid instruction sequences and won't + // disassemble. + var disScript, disPC string + if test.disassembly != "" { + dis0, err := engine.DisasmScript(0) + if err != nil { + t.Errorf("%s: failed to disassemble script0: %v", + test.name, err) + } + if dis0 != "" { + t.Errorf("%s: disassembly of empty script gave \"%s\"", + test.name, dis0) + } + disScript, err = engine.DisasmScript(1) + if err != nil { + t.Errorf("%s: failed to disassemble script: %v", + test.name, err) + } + _, err = engine.DisasmScript(2) + if err != txscript.ErrStackInvalidIndex { + t.Errorf("%s: got unexpected error for invalid "+ + "disassembly index: \"%v\"", test.name, err) + } + } + + done := false + for !done { + if test.disassembly != "" { + disCurPC, err := engine.DisasmPC() + if err != nil { + t.Errorf("failed to disassemble pc for %s: %v", + test.name, err) + } + disPC += disCurPC + "\n" + } + + done, err = engine.Step() + if err != nil { + if err != test.expectedReturn { + t.Errorf("Error return not expected %s: %v %v", + test.name, test.expectedReturn, err) + return + } + return + } + } + if err != test.expectedReturn { + t.Errorf("Error return not expected %s: %v %v", + test.name, test.expectedReturn, err) + } + + if test.disassembly != "" { + if disScript != disPC { + t.Errorf("script disassembly doesn't match pc "+ + "disassembly for %s: pc: \"%s\" script: \"%s\"", + test.name, disScript, disPC) + } + } + + after := engine.GetStack() + if !stacksEqual(after, test.after) { + t.Errorf("Stacks not equal after %s:\ngot:\n%vexp:\n%v", + test.name, after, test.after) + } + altafter := engine.GetAltStack() + if !stacksEqual(altafter, test.altafter) { + t.Errorf("AltStacks not equal after %s:\n got:\n%vexp:\n%v", + test.name, altafter, test.altafter) + } +} + +func TestOpcodes(t *testing.T) { + t.Parallel() + + for i := range detailedTests { + testOpcode(t, &detailedTests[i]) + } +} + +func testDisasmString(t *testing.T, test *detailedTest) { + // mock up fake tx. + dis, err := txscript.DisasmString(test.script) + if err != nil { + if err != test.disassemblyerr { + t.Errorf("%s: disassembly got error %v expected %v", test.name, + err, test.disassemblyerr) + } + return + } + if test.disassemblyerr != nil { + t.Errorf("%s: expected error %v, got %s", test.name, + test.disassemblyerr, dis) + return + } + if dis != test.disassembly { + t.Errorf("Disassembly for %s doesn't match expected "+ + "got: \"%s\" expected: \"%s\"", test.name, dis, + test.disassembly) + } +} + +func TestDisasmStrings(t *testing.T) { + t.Parallel() + + for i := range detailedTests { + testDisasmString(t, &detailedTests[i]) + } +} + +// A basic test of GetSigOpCount for most opcodes, we do this by +// running the same test for every one of the detailed tests. Since +// disassembly errors are always parse errors, and so are +// sigops count errors we use the same error code. +// While this isn't as precise as using full transaction scripts, this gives +// us coverage over a wider range of opcodes. +func TestSigOps(t *testing.T) { + t.Parallel() + + for _, test := range detailedTests { + count := txscript.GetSigOpCount(test.script) + if count != test.nSigOps { + t.Errorf("%s: expected count of %d, got %d", test.name, + test.nSigOps, count) + + } + } +} + +// A basic test of GetPreciseSigOpCount for most opcodes, we do this by +// running the same test for every one of the detailed tests with a fake +// sigscript. Sicne disassembly errors are always parse errors, and so are +// sigops count errors we use the same error code. +// While this isn't as precise as using full transaction scripts, this gives +// us coverage over a wider range of opcodes. See script_test.go for tests +// using real transactions to provide a bit more coverage. +func TestPreciseSigOps(t *testing.T) { + t.Parallel() + + for _, test := range detailedTests { + count := txscript.GetPreciseSigOpCount( + []byte{txscript.OP_1}, test.script, false) + if count != test.nPreciseSigOps { + t.Errorf("%s: expected count of %d, got %d", test.name, + test.nPreciseSigOps, count) + + } + } +} diff --git a/txscript/script.go b/txscript/script.go new file mode 100644 index 000000000..5aa074b08 --- /dev/null +++ b/txscript/script.go @@ -0,0 +1,1666 @@ +// 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 ( + "bytes" + "encoding/binary" + "errors" + "fmt" + "time" + + "github.com/btcsuite/btcec" + "github.com/btcsuite/btcnet" + "github.com/btcsuite/btcutil" + "github.com/btcsuite/btcwire" +) + +var ( + // ErrStackShortScript is returned if the script has an opcode that is + // too long for the length of the script. + ErrStackShortScript = errors.New("execute past end of script") + + // ErrStackLongScript is returned if the script has an opcode that is + // too long for the length of the script. + ErrStackLongScript = errors.New("script is longer than maximum allowed") + + // ErrStackUnderflow is returned if an opcode requires more items on the + // stack than is present.f + ErrStackUnderflow = errors.New("stack underflow") + + // ErrStackInvalidArgs is returned if the argument for an opcode is out + // of acceptable range. + ErrStackInvalidArgs = errors.New("invalid argument") + + // ErrStackOpDisabled is returned when a disabled opcode is encountered + // in the script. + ErrStackOpDisabled = errors.New("Disabled Opcode") + + // ErrStackVerifyFailed is returned when one of the OP_VERIFY or + // OP_*VERIFY instructions is executed and the conditions fails. + ErrStackVerifyFailed = errors.New("Verify failed") + + // ErrStackNumberTooBig is returned when the argument for an opcode that + // should be an offset is obviously far too large. + ErrStackNumberTooBig = errors.New("number too big") + + // ErrStackInvalidOpcode is returned when an opcode marked as invalid or + // a completely undefined opcode is encountered. + ErrStackInvalidOpcode = errors.New("Invalid Opcode") + + // ErrStackReservedOpcode is returned when an opcode marked as reserved + // is encountered. + ErrStackReservedOpcode = errors.New("Reserved Opcode") + + // ErrStackEarlyReturn is returned when OP_RETURN is executed in the + // script. + ErrStackEarlyReturn = errors.New("Script returned early") + + // ErrStackNoIf is returned if an OP_ELSE or OP_ENDIF is encountered + // without first having an OP_IF or OP_NOTIF in the script. + ErrStackNoIf = errors.New("OP_ELSE or OP_ENDIF with no matching OP_IF") + + // ErrStackMissingEndif is returned if the end of a script is reached + // without and OP_ENDIF to correspond to a conditional expression. + ErrStackMissingEndif = fmt.Errorf("execute fail, in conditional execution") + + // ErrStackTooManyPubkeys is returned if an OP_CHECKMULTISIG is + // encountered with more than MaxPubKeysPerMultiSig pubkeys present. + ErrStackTooManyPubkeys = errors.New("Invalid pubkey count in OP_CHECKMULTISIG") + + // ErrStackTooManyOperations is returned if a script has more than + // MaxOpsPerScript opcodes that do not push data. + ErrStackTooManyOperations = errors.New("Too many operations in script") + + // ErrStackElementTooBig is returned if the size of an element to be + // pushed to the stack is over MaxScriptElementSize. + ErrStackElementTooBig = errors.New("Element in script too large") + + // ErrStackUnknownAddress is returned when ScriptToAddrHash does not + // recognise the pattern of the script and thus can not find the address + // for payment. + ErrStackUnknownAddress = errors.New("non-recognised address") + + // ErrStackScriptFailed is returned when at the end of a script the + // boolean on top of the stack is false signifying that the script has + // failed. + ErrStackScriptFailed = errors.New("execute fail, fail on stack") + + // ErrStackScriptUnfinished is returned when CheckErrorCondition is + // called on a script that has not finished executing. + ErrStackScriptUnfinished = errors.New("Error check when script unfinished") + + // ErrStackEmptyStack is returned when the stack is empty at the end of + // execution. Normal operation requires that a boolean is on top of the + // stack when the scripts have finished executing. + ErrStackEmptyStack = errors.New("Stack empty at end of execution") + + // ErrStackP2SHNonPushOnly is returned when a Pay-to-Script-Hash + // transaction is encountered and the ScriptSig does operations other + // than push data (in violation of bip16). + ErrStackP2SHNonPushOnly = errors.New("pay to script hash with non " + + "pushonly input") + + // ErrStackInvalidParseType is an internal error returned from + // ScriptToAddrHash ony if the internal data tables are wrong. + ErrStackInvalidParseType = errors.New("internal error: invalid parsetype found") + + // ErrStackInvalidAddrOffset is an internal error returned from + // ScriptToAddrHash ony if the internal data tables are wrong. + ErrStackInvalidAddrOffset = errors.New("internal error: invalid offset found") + + // ErrStackInvalidIndex is returned when an out-of-bounds index was + // passed to a function. + ErrStackInvalidIndex = errors.New("Invalid script index") + + // ErrStackNonPushOnly is returned when ScriptInfo is called with a + // pkScript that peforms operations other that pushing data to the stack. + ErrStackNonPushOnly = errors.New("SigScript is non pushonly") + + // ErrStackOverflow is returned when stack and altstack combined depth + // is over the limit. + ErrStackOverflow = errors.New("Stacks overflowed") +) + +const ( + // maxStackSize is the maximum combined height of stack and alt stack + // during execution. + maxStackSize = 1000 + + // maxScriptSize is the maximum allowed length of a raw script. + maxScriptSize = 10000 +) + +// ErrUnsupportedAddress is returned when a concrete type that implements +// a btcutil.Address is not a supported type. +var ErrUnsupportedAddress = errors.New("unsupported address type") + +// Bip16Activation is the timestamp where BIP0016 is valid to use in the +// blockchain. To be used to determine if BIP0016 should be called for or not. +// This timestamp corresponds to Sun Apr 1 00:00:00 UTC 2012. +var Bip16Activation = time.Unix(1333238400, 0) + +// SigHashType represents hash type bits at the end of a signature. +type SigHashType byte + +// Hash type bits from the end of a signature. +const ( + SigHashOld SigHashType = 0x0 + SigHashAll SigHashType = 0x1 + SigHashNone SigHashType = 0x2 + SigHashSingle SigHashType = 0x3 + SigHashAnyOneCanPay SigHashType = 0x80 +) + +// These are the constants specified for maximums in individual scripts. +const ( + MaxOpsPerScript = 201 // Max number of non-push operations. + MaxPubKeysPerMultiSig = 20 // Multisig can't have more sigs than this. + MaxScriptElementSize = 520 // Max bytes pushable to the stack. +) + +// ScriptClass is an enumeration for the list of standard types of script. +type ScriptClass byte + +// Classes of script payment known about in the blockchain. +const ( + NonStandardTy ScriptClass = iota // None of the recognized forms. + PubKeyTy // Pay pubkey. + PubKeyHashTy // Pay pubkey hash. + ScriptHashTy // Pay to script hash. + MultiSigTy // Multi signature. + NullDataTy // Empty data-only (provably prunable). +) + +var scriptClassToName = []string{ + NonStandardTy: "nonstandard", + PubKeyTy: "pubkey", + PubKeyHashTy: "pubkeyhash", + ScriptHashTy: "scripthash", + MultiSigTy: "multisig", + NullDataTy: "nulldata", +} + +// String implements the Stringer interface by returning the name of +// the enum script class. If the enum is invalid then "Invalid" will be +// returned. +func (t ScriptClass) String() string { + if int(t) > len(scriptClassToName) || int(t) < 0 { + return "Invalid" + } + return scriptClassToName[t] +} + +// Script is the virtual machine that executes scripts. +type Script struct { + scripts [][]parsedOpcode + scriptidx int + scriptoff int + lastcodesep int + dstack Stack // data stack + astack Stack // alt stack + tx btcwire.MsgTx + txidx int + condStack []int + numOps int + bip16 bool // treat execution as pay-to-script-hash + der bool // enforce DER encoding + strictMultiSig bool // verify multisig stack item is zero length + discourageUpgradableNops bool // NOP1 to NOP10 are reserved for future soft-fork upgrades + savedFirstStack [][]byte // stack from first script for bip16 scripts +} + +// isSmallInt returns whether or not the opcode is considered a small integer, +// which is an OP_0, or OP_1 through OP_16. +func isSmallInt(op *opcode) bool { + if op.value == OP_0 || (op.value >= OP_1 && op.value <= OP_16) { + return true + } + return false +} + +// isPubkey returns true if the script passed is a pubkey transaction, false +// otherwise. +func isPubkey(pops []parsedOpcode) bool { + // valid pubkeys are either 33 or 65 bytes + return len(pops) == 2 && + (len(pops[0].data) == 33 || len(pops[0].data) == 65) && + pops[1].opcode.value == OP_CHECKSIG +} + +// isPubkeyHash returns true if the script passed is a pubkey hash transaction, +// false otherwise. +func isPubkeyHash(pops []parsedOpcode) bool { + return len(pops) == 5 && + pops[0].opcode.value == OP_DUP && + pops[1].opcode.value == OP_HASH160 && + pops[2].opcode.value == OP_DATA_20 && + pops[3].opcode.value == OP_EQUALVERIFY && + pops[4].opcode.value == OP_CHECKSIG + +} + +// isScriptHash returns true if the script passed is a pay-to-script-hash (P2SH) +// transction, false otherwise. +func isScriptHash(pops []parsedOpcode) bool { + return len(pops) == 3 && + pops[0].opcode.value == OP_HASH160 && + pops[1].opcode.value == OP_DATA_20 && + pops[2].opcode.value == OP_EQUAL +} + +// IsPayToScriptHash returns true if the script is in the standard +// Pay-To-Script-Hash format, false otherwise. +func IsPayToScriptHash(script []byte) bool { + pops, err := parseScript(script) + if err != nil { + return false + } + return isScriptHash(pops) +} + +// isMultiSig returns true if the passed script is a multisig transaction, false +// otherwise. +func isMultiSig(pops []parsedOpcode) bool { + l := len(pops) + // absolute minimum is 1 pubkey so + // OP_0/OP_1-16, pubkey, OP_1, OP_CHECKMULTISIG + if l < 4 { + return false + } + if !isSmallInt(pops[0].opcode) { + return false + } + if !isSmallInt(pops[l-2].opcode) { + return false + } + if pops[l-1].opcode.value != OP_CHECKMULTISIG { + return false + } + for _, pop := range pops[1 : l-2] { + // valid pubkeys are either 65 or 33 bytes + if len(pop.data) != 33 && + len(pop.data) != 65 { + return false + } + } + return true +} + +// isNullData returns true if the passed script is a null data transaction, +// false otherwise. +func isNullData(pops []parsedOpcode) bool { + // A nulldata transaction is either a single OP_RETURN or an + // OP_RETURN SMALLDATA (where SMALLDATA is a push data up to 40 bytes). + l := len(pops) + if l == 1 && pops[0].opcode.value == OP_RETURN { + return true + } + + return l == 2 && + pops[0].opcode.value == OP_RETURN && + pops[1].opcode.value <= OP_PUSHDATA4 && + len(pops[1].data) <= 40 +} + +// isPushOnly returns true if the script only pushes data, false otherwise. +func isPushOnly(pops []parsedOpcode) bool { + // technically we cheat here, we don't look at opcodes + for _, pop := range pops { + // all opcodes up to OP_16 are data instructions. + if pop.opcode.value < OP_FALSE || + pop.opcode.value > OP_16 { + return false + } + } + return true +} + +// IsPushOnlyScript returns whether or not the passed script only pushes data. +// If the script does not parse false will be returned. +func IsPushOnlyScript(script []byte) bool { + pops, err := parseScript(script) + if err != nil { + return false + } + return isPushOnly(pops) +} + +// canonicalPush returns true if the object is either not a push instruction +// or the push instruction contained wherein is matches the canonical form +// or using the smallest instruction to do the job. False otherwise. +func canonicalPush(pop parsedOpcode) bool { + opcode := pop.opcode.value + data := pop.data + dataLen := len(pop.data) + if opcode > OP_16 { + return true + } + + if opcode < OP_PUSHDATA1 && opcode > OP_0 && (dataLen == 1 && data[0] <= 16) { + return false + } + if opcode == OP_PUSHDATA1 && dataLen < OP_PUSHDATA1 { + return false + } + if opcode == OP_PUSHDATA2 && dataLen <= 0xff { + return false + } + if opcode == OP_PUSHDATA4 && dataLen <= 0xffff { + return false + } + return true +} + +// HasCanonicalPushes returns whether or not the passed script only contains +// canonical data pushes. A canonical data push one where the fewest number of +// bytes possible to encode the size of the data being pushed is used. This +// includes using the small integer opcodes for single byte data that can be +// represented directly. +func HasCanonicalPushes(script []byte) bool { + pops, err := parseScript(script) + if err != nil { + return false + } + + for _, pop := range pops { + if !canonicalPush(pop) { + return false + } + } + + return true +} + +// GetScriptClass returns the class of the script passed. If the script does not +// parse then NonStandardTy will be returned. +func GetScriptClass(script []byte) ScriptClass { + pops, err := parseScript(script) + if err != nil { + return NonStandardTy + } + return typeOfScript(pops) +} + +// scriptType returns the type of the script being inspected from the known +// standard types. +func typeOfScript(pops []parsedOpcode) ScriptClass { + // XXX dubious optimisation: order these in order of popularity in the + // blockchain + if isPubkey(pops) { + return PubKeyTy + } else if isPubkeyHash(pops) { + return PubKeyHashTy + } else if isScriptHash(pops) { + return ScriptHashTy + } else if isMultiSig(pops) { + return MultiSigTy + } else if isNullData(pops) { + return NullDataTy + } + return NonStandardTy + +} + +// parseScript preparses the script in bytes into a list of parsedOpcodes while +// applying a number of sanity checks. +func parseScript(script []byte) ([]parsedOpcode, error) { + return parseScriptTemplate(script, opcodemap) +} + +// parseScriptTemplate is the same as parseScript but allows the passing of the +// template list for testing purposes. On error we return the list of parsed +// opcodes so far. +func parseScriptTemplate(script []byte, opcodemap map[byte]*opcode) ([]parsedOpcode, error) { + retScript := make([]parsedOpcode, 0, len(script)) + for i := 0; i < len(script); { + instr := script[i] + op, ok := opcodemap[instr] + if !ok { + return retScript, ErrStackInvalidOpcode + } + pop := parsedOpcode{opcode: op} + // parse data out of instruction. + switch { + case op.length == 1: + // no data, done here + i++ + case op.length > 1: + if len(script[i:]) < op.length { + return retScript, ErrStackShortScript + } + // slice out the data. + pop.data = script[i+1 : i+op.length] + i += op.length + case op.length < 0: + var l uint + off := i + 1 + + if len(script[off:]) < -op.length { + return retScript, ErrStackShortScript + } + + // Next -length bytes are little endian length of data. + switch op.length { + case -1: + l = uint(script[off]) + case -2: + l = ((uint(script[off+1]) << 8) | + uint(script[off])) + case -4: + l = ((uint(script[off+3]) << 24) | + (uint(script[off+2]) << 16) | + (uint(script[off+1]) << 8) | + uint(script[off])) + default: + return retScript, + fmt.Errorf("invalid opcode length %d", + op.length) + } + + off += -op.length // beginning of data + // Disallow entries that do not fit script or were + // sign extended. + if int(l) > len(script[off:]) || int(l) < 0 { + return retScript, ErrStackShortScript + } + pop.data = script[off : off+int(l)] + i += 1 - op.length + int(l) + } + retScript = append(retScript, pop) + } + return retScript, nil +} + +// unparseScript reversed the action of parseScript and returns the +// parsedOpcodes as a list of bytes +func unparseScript(pops []parsedOpcode) ([]byte, error) { + script := make([]byte, 0, len(pops)) + for _, pop := range pops { + b, err := pop.bytes() + if err != nil { + return nil, err + } + script = append(script, b...) + } + return script, nil +} + +// ScriptFlags is a bitmask defining additional operations or +// tests that will be done when executing a Script. +type ScriptFlags uint32 + +const ( + // ScriptBip16 defines whether the bip16 threshhold has passed and thus + // pay-to-script hash transactions will be fully validated. + ScriptBip16 ScriptFlags = 1 << iota + + // ScriptCanonicalSignatures defines whether additional canonical + // signature checks are performed when parsing a signature. + // + // Canonical (DER) signatures are not required in the tx rules for + // block acceptance, but are checked in recent versions of bitcoind + // when accepting transactions to the mempool. Non-canonical (valid + // BER but not valid DER) transactions can potentially be changed + // before mined into a block, either by adding extra padding or + // flipping the sign of the R or S value in the signature, creating a + // transaction that still validates and spends the inputs, but is not + // recognized by creator of the transaction. Performing a canonical + // check enforces script signatures use a unique DER format. + ScriptCanonicalSignatures + + // ScriptStrictMultiSig defines whether to verify the stack item + // used by CHECKMULTISIG is zero length. + ScriptStrictMultiSig + + // ScriptDiscourageUpgradableNops defines whether to verify that + // NOP1 through NOP10 are reserved for future soft-fork upgrades. This + // flag must not be used for consensus critical code nor applied to + // blocks as this flag is only for stricter standard transaction + // checks. This flag is only applied when the above opcodes are + // executed. + ScriptDiscourageUpgradableNops + + // ScriptVerifySigPushOnly defines that signature scripts must contain + // only pushed data. This is rule 2 of BIP0062. + ScriptVerifySigPushOnly +) + +// NewScript returns a new script engine for the provided tx and input idx with +// a signature script scriptSig and a pubkeyscript scriptPubKey. If bip16 is +// true then it will be treated as if the bip16 threshhold has passed and thus +// pay-to-script hash transactions will be fully validated. +func NewScript(scriptSig []byte, scriptPubKey []byte, txidx int, tx *btcwire.MsgTx, flags ScriptFlags) (*Script, error) { + var m Script + if flags&ScriptVerifySigPushOnly == ScriptVerifySigPushOnly && !IsPushOnlyScript(scriptSig) { + return nil, ErrStackNonPushOnly + } + + scripts := [][]byte{scriptSig, scriptPubKey} + m.scripts = make([][]parsedOpcode, len(scripts)) + for i, scr := range scripts { + if len(scr) > maxScriptSize { + return nil, ErrStackLongScript + } + var err error + m.scripts[i], err = parseScript(scr) + if err != nil { + return nil, err + } + + // If the first scripts(s) are empty, must start on later ones. + if i == 0 && len(scr) == 0 { + // This could end up seeing an invalid initial pc if + // all scripts were empty. However, that is an invalid + // case and should fail. + m.scriptidx = i + 1 + } + } + + // Parse flags. + bip16 := flags&ScriptBip16 == ScriptBip16 + if bip16 && isScriptHash(m.scripts[1]) { + // if we are pay to scripthash then we only accept input + // scripts that push data + if !isPushOnly(m.scripts[0]) { + return nil, ErrStackP2SHNonPushOnly + } + m.bip16 = true + } + if flags&ScriptCanonicalSignatures == ScriptCanonicalSignatures { + m.der = true + } + if flags&ScriptStrictMultiSig == ScriptStrictMultiSig { + m.strictMultiSig = true + } + if flags&ScriptDiscourageUpgradableNops == ScriptDiscourageUpgradableNops { + m.discourageUpgradableNops = true + } + + m.tx = *tx + m.txidx = txidx + m.condStack = []int{OpCondTrue} + + return &m, nil +} + +// Execute will execute all script in the script engine and return either nil +// for successful validation or an error if one occurred. +func (s *Script) Execute() (err error) { + done := false + for done != true { + log.Tracef("%v", newLogClosure(func() string { + dis, err := s.DisasmPC() + if err != nil { + return fmt.Sprintf("stepping (%v)", err) + } + return fmt.Sprintf("stepping %v", dis) + })) + + done, err = s.Step() + if err != nil { + return err + } + log.Tracef("%v", newLogClosure(func() string { + var dstr, astr string + + // if we're tracing, dump the stacks. + if s.dstack.Depth() != 0 { + dstr = "Stack:\n" + s.dstack.String() + } + if s.astack.Depth() != 0 { + astr = "AltStack:\n" + s.astack.String() + } + + return dstr + astr + })) + } + + return s.CheckErrorCondition() +} + +// CheckErrorCondition returns nil if the running script has ended and was +// successful, leaving a a true boolean on the stack. An error otherwise, +// including if the script has not finished. +func (s *Script) CheckErrorCondition() (err error) { + // Check we are actually done. if pc is past the end of script array + // then we have run out of scripts to run. + if s.scriptidx < len(s.scripts) { + return ErrStackScriptUnfinished + } + if s.dstack.Depth() < 1 { + return ErrStackEmptyStack + } + v, err := s.dstack.PopBool() + if err == nil && v == false { + // log interesting data. + log.Tracef("%v", newLogClosure(func() string { + dis0, _ := s.DisasmScript(0) + dis1, _ := s.DisasmScript(1) + return fmt.Sprintf("scripts failed: script0: %s\n"+ + "script1: %s", dis0, dis1) + })) + err = ErrStackScriptFailed + } + return err +} + +// Step will execute the next instruction and move the program counter to the +// next opcode in the script, or the next script if the curent has ended. Step +// will return true in the case that the last opcode was successfully executed. +// if an error is returned then the result of calling Step or any other method +// is undefined. +func (s *Script) Step() (done bool, err error) { + // verify that it is pointing to a valid script address + err = s.validPC() + if err != nil { + return true, err + } + opcode := s.scripts[s.scriptidx][s.scriptoff] + + err = opcode.exec(s) + if err != nil { + return true, err + } + + if s.dstack.Depth()+s.astack.Depth() > maxStackSize { + return false, ErrStackOverflow + } + + // prepare for next instruction + s.scriptoff++ + if s.scriptoff >= len(s.scripts[s.scriptidx]) { + // Illegal to have an `if' that straddles two scripts. + if err == nil && len(s.condStack) != 1 { + return false, ErrStackMissingEndif + } + + // alt stack doesn't persist. + _ = s.astack.DropN(s.astack.Depth()) + + s.numOps = 0 // number of ops is per script. + s.scriptoff = 0 + if s.scriptidx == 0 && s.bip16 { + s.scriptidx++ + s.savedFirstStack = s.GetStack() + } else if s.scriptidx == 1 && s.bip16 { + // Put us past the end for CheckErrorCondition() + s.scriptidx++ + // We check script ran ok, if so then we pull + // the script out of the first stack and executre that. + err := s.CheckErrorCondition() + if err != nil { + return false, err + } + + script := s.savedFirstStack[len(s.savedFirstStack)-1] + pops, err := parseScript(script) + if err != nil { + return false, err + } + s.scripts = append(s.scripts, pops) + // Set stack to be the stack from first script + // minus the script itself + s.SetStack(s.savedFirstStack[:len(s.savedFirstStack)-1]) + } else { + s.scriptidx++ + } + // there are zero length scripts in the wild + if s.scriptidx < len(s.scripts) && s.scriptoff >= len(s.scripts[s.scriptidx]) { + s.scriptidx++ + } + s.lastcodesep = 0 + if s.scriptidx >= len(s.scripts) { + return true, nil + } + } + return false, nil +} + +// curPC returns either the current script and offset, or an error if the +// position isn't valid. +func (s *Script) curPC() (script int, off int, err error) { + err = s.validPC() + if err != nil { + return 0, 0, err + } + return s.scriptidx, s.scriptoff, nil +} + +// validPC returns an error if the current script position is valid for +// execution, nil otherwise. +func (s *Script) validPC() error { + if s.scriptidx >= len(s.scripts) { + return fmt.Errorf("Past input scripts %v:%v %v:xxxx", s.scriptidx, s.scriptoff, len(s.scripts)) + } + if s.scriptoff >= len(s.scripts[s.scriptidx]) { + return fmt.Errorf("Past input scripts %v:%v %v:%04d", s.scriptidx, s.scriptoff, s.scriptidx, len(s.scripts[s.scriptidx])) + } + return nil +} + +// DisasmScript returns the disassembly string for the script at offset +// ``idx''. Where 0 is the scriptSig and 1 is the scriptPubKey. +func (s *Script) DisasmScript(idx int) (disstr string, err error) { + if idx >= len(s.scripts) { + return "", ErrStackInvalidIndex + } + for i := range s.scripts[idx] { + disstr = disstr + s.disasm(idx, i) + "\n" + } + return disstr, nil +} + +// DisasmPC returns the string for the disassembly of the opcode that will be +// next to execute when Step() is called. +func (s *Script) DisasmPC() (disstr string, err error) { + scriptidx, scriptoff, err := s.curPC() + if err != nil { + return "", err + } + return s.disasm(scriptidx, scriptoff), nil +} + +// disasm is a helper member to produce the output for DisasmPC and +// DisasmScript. It produces the opcode prefixed by the program counter at the +// provided position in the script. it does no error checking and leaves that +// to the caller to provide a valid offse. +func (s *Script) disasm(scriptidx int, scriptoff int) string { + return fmt.Sprintf("%02x:%04x: %s", scriptidx, scriptoff, + s.scripts[scriptidx][scriptoff].print(false)) +} + +// subScript will return the script since the last OP_CODESEPARATOR +func (s *Script) subScript() []parsedOpcode { + return s.scripts[s.scriptidx][s.lastcodesep:] +} + +// removeOpcode will remove any opcode matching ``opcode'' from the opcode +// stream in pkscript +func removeOpcode(pkscript []parsedOpcode, opcode byte) []parsedOpcode { + retScript := make([]parsedOpcode, 0, len(pkscript)) + for _, pop := range pkscript { + if pop.opcode.value != opcode { + retScript = append(retScript, pop) + } + } + return retScript +} + +// removeOpcodeByData will return the pkscript minus any opcodes that would +// push the data in ``data'' to the stack. +func removeOpcodeByData(pkscript []parsedOpcode, data []byte) []parsedOpcode { + retScript := make([]parsedOpcode, 0, len(pkscript)) + for _, pop := range pkscript { + if !canonicalPush(pop) || !bytes.Contains(pop.data, data) { + retScript = append(retScript, pop) + } + } + return retScript + +} + +// DisasmString formats a disassembled script for one line printing. When the +// script fails to parse, the returned string will contain the disassembled +// script up to the point the failure occurred along with the string '[error]' +// appended. In addition, the reason the script failed to parse is returned +// if the caller wants more information about the failure. +func DisasmString(buf []byte) (string, error) { + disbuf := "" + opcodes, err := parseScript(buf) + for _, pop := range opcodes { + disbuf += pop.print(true) + " " + } + if disbuf != "" { + disbuf = disbuf[:len(disbuf)-1] + } + if err != nil { + disbuf += "[error]" + } + return disbuf, err +} + +// calcScriptHash will, given the a script and hashtype for the current +// scriptmachine, calculate the doubleSha256 hash of the transaction and +// script to be used for signature signing and verification. +func calcScriptHash(script []parsedOpcode, hashType SigHashType, tx *btcwire.MsgTx, idx int) []byte { + + // remove all instances of OP_CODESEPARATOR still left in the script + script = removeOpcode(script, OP_CODESEPARATOR) + + // Make a deep copy of the transaction, zeroing out the script + // for all inputs that are not currently being processed. + txCopy := tx.Copy() + for i := range txCopy.TxIn { + var txIn btcwire.TxIn + txIn = *txCopy.TxIn[i] + txCopy.TxIn[i] = &txIn + if i == idx { + // unparseScript cannot fail here, because removeOpcode + // above only returns a valid script. + sigscript, _ := unparseScript(script) + txCopy.TxIn[idx].SignatureScript = sigscript + } else { + txCopy.TxIn[i].SignatureScript = []byte{} + } + } + // Default behaviour has all outputs set up. + for i := range txCopy.TxOut { + var txOut btcwire.TxOut + txOut = *txCopy.TxOut[i] + txCopy.TxOut[i] = &txOut + } + + switch hashType & 31 { + case SigHashNone: + txCopy.TxOut = txCopy.TxOut[0:0] // empty slice + for i := range txCopy.TxIn { + if i != idx { + txCopy.TxIn[i].Sequence = 0 + } + } + case SigHashSingle: + if idx >= len(txCopy.TxOut) { + // This was created by a buggy implementation. + // In this case we do the same as bitcoind and bitcoinj + // and return 1 (as a uint256 little endian) as an + // error. Unfortunately this was not checked anywhere + // and thus is treated as the actual + // hash. + hash := make([]byte, 32) + hash[0] = 0x01 + return hash + } + // Resize output array to up to and including requested index. + txCopy.TxOut = txCopy.TxOut[:idx+1] + // all but current output get zeroed out + for i := 0; i < idx; i++ { + txCopy.TxOut[i].Value = -1 + txCopy.TxOut[i].PkScript = []byte{} + } + // Sequence on all other inputs is 0, too. + for i := range txCopy.TxIn { + if i != idx { + txCopy.TxIn[i].Sequence = 0 + } + } + default: + // XXX bitcoind treats undefined hashtypes like normal + // SigHashAll for purposes of hash generation. + fallthrough + case SigHashOld: + fallthrough + case SigHashAll: + // nothing special here + } + if hashType&SigHashAnyOneCanPay != 0 { + txCopy.TxIn = txCopy.TxIn[idx : idx+1] + idx = 0 + } + + var wbuf bytes.Buffer + txCopy.Serialize(&wbuf) + // Append LE 4 bytes hash type + binary.Write(&wbuf, binary.LittleEndian, uint32(hashType)) + + return btcwire.DoubleSha256(wbuf.Bytes()) +} + +// getStack returns the contents of stack as a byte array bottom up +func getStack(stack *Stack) [][]byte { + array := make([][]byte, stack.Depth()) + for i := range array { + // PeekByteArry can't fail due to overflow, already checked + array[len(array)-i-1], _ = + stack.PeekByteArray(i) + } + return array +} + +// setStack sets the stack to the contents of the array where the last item in +// the array is the top item in the stack. +func setStack(stack *Stack, data [][]byte) { + // This can not error. Only errors are for invalid arguments. + _ = stack.DropN(stack.Depth()) + + for i := range data { + stack.PushByteArray(data[i]) + } +} + +// GetStack returns the contents of the primary stack as an array. where the +// last item in the array is the top of the stack. +func (s *Script) GetStack() [][]byte { + return getStack(&s.dstack) +} + +// SetStack sets the contents of the primary stack to the contents of the +// provided array where the last item in the array will be the top of the stack. +func (s *Script) SetStack(data [][]byte) { + setStack(&s.dstack, data) +} + +// GetAltStack returns the contents of the primary stack as an array. where the +// last item in the array is the top of the stack. +func (s *Script) GetAltStack() [][]byte { + return getStack(&s.astack) +} + +// SetAltStack sets the contents of the primary stack to the contents of the +// provided array where the last item in the array will be the top of the stack. +func (s *Script) SetAltStack(data [][]byte) { + setStack(&s.astack, data) +} + +// GetSigOpCount provides a quick count of the number of signature operations +// in a script. a CHECKSIG operations counts for 1, and a CHECK_MULTISIG for 20. +// If the script fails to parse, then the count up to the point of failure is +// returned. +func GetSigOpCount(script []byte) int { + // We don't check error since parseScript returns the parsed-up-to-error + // list of pops. + pops, _ := parseScript(script) + + return getSigOpCount(pops, false) +} + +// GetPreciseSigOpCount returns the number of signature operations in +// scriptPubKey. If bip16 is true then scriptSig may be searched for the +// Pay-To-Script-Hash script in order to find the precise number of signature +// operations in the transaction. If the script fails to parse, then the +// count up to the point of failure is returned. +func GetPreciseSigOpCount(scriptSig, scriptPubKey []byte, bip16 bool) int { + // We don't check error since parseScript returns the parsed-up-to-error + // list of pops. + pops, _ := parseScript(scriptPubKey) + // non P2SH transactions just treated as normal. + if !(bip16 && isScriptHash(pops)) { + return getSigOpCount(pops, true) + } + + // Ok so this is P2SH, get the contained script and count it.. + + sigPops, err := parseScript(scriptSig) + if err != nil { + return 0 + } + if !isPushOnly(sigPops) || len(sigPops) == 0 { + return 0 + } + + shScript := sigPops[len(sigPops)-1].data + // Means that sigPops is jus OP_1 - OP_16, no sigops there. + if shScript == nil { + return 0 + } + + shPops, _ := parseScript(shScript) + + return getSigOpCount(shPops, true) +} + +// getSigOpCount is the implementation function for counting the number of +// signature operations in the script provided by pops. If precise mode is +// requested then we attempt to count the number of operations for a multisig +// op. Otherwise we use the maximum. +func getSigOpCount(pops []parsedOpcode, precise bool) int { + nSigs := 0 + for i, pop := range pops { + switch pop.opcode.value { + case OP_CHECKSIG: + fallthrough + case OP_CHECKSIGVERIFY: + nSigs++ + case OP_CHECKMULTISIG: + fallthrough + case OP_CHECKMULTISIGVERIFY: + // If we are being precise then look for familiar + // patterns for multisig, for now all we recognise is + // OP_1 - OP_16 to signify the number of pubkeys. + // Otherwise, we use the max of 20. + if precise && i > 0 && + pops[i-1].opcode.value >= OP_1 && + pops[i-1].opcode.value <= OP_16 { + nSigs += int(pops[i-1].opcode.value - + (OP_1 - 1)) + } else { + nSigs += MaxPubKeysPerMultiSig + } + default: + // not a sigop. + } + } + + return nSigs +} + +// payToPubKeyHashScript creates a new script to pay a transaction +// output to a 20-byte pubkey hash. It is expected that the input is a valid +// hash. +func payToPubKeyHashScript(pubKeyHash []byte) ([]byte, error) { + return NewScriptBuilder().AddOp(OP_DUP).AddOp(OP_HASH160). + AddData(pubKeyHash).AddOp(OP_EQUALVERIFY).AddOp(OP_CHECKSIG). + Script() +} + +// payToScriptHashScript creates a new script to pay a transaction output to a +// script hash. It is expected that the input is a valid hash. +func payToScriptHashScript(scriptHash []byte) ([]byte, error) { + return NewScriptBuilder().AddOp(OP_HASH160).AddData(scriptHash). + AddOp(OP_EQUAL).Script() +} + +// payToPubkeyScript creates a new script to pay a transaction output to a +// public key. It is expected that the input is a valid pubkey. +func payToPubKeyScript(serializedPubKey []byte) ([]byte, error) { + return NewScriptBuilder().AddData(serializedPubKey). + AddOp(OP_CHECKSIG).Script() +} + +// PayToAddrScript creates a new script to pay a transaction output to a the +// specified address. +func PayToAddrScript(addr btcutil.Address) ([]byte, error) { + switch addr := addr.(type) { + case *btcutil.AddressPubKeyHash: + if addr == nil { + return nil, ErrUnsupportedAddress + } + return payToPubKeyHashScript(addr.ScriptAddress()) + + case *btcutil.AddressScriptHash: + if addr == nil { + return nil, ErrUnsupportedAddress + } + return payToScriptHashScript(addr.ScriptAddress()) + + case *btcutil.AddressPubKey: + if addr == nil { + return nil, ErrUnsupportedAddress + } + return payToPubKeyScript(addr.ScriptAddress()) + } + + return nil, ErrUnsupportedAddress +} + +// ErrBadNumRequired is returned from MultiSigScript when nrequired is larger +// than the number of provided public keys. +var ErrBadNumRequired = errors.New("more signatures required than keys present") + +// MultiSigScript returns a valid script for a multisignature redemption where +// nrequired of the keys in pubkeys are required to have signed the transaction +// for success. An ErrBadNumRequired will be returned if nrequired is larger than +// the number of keys provided. +func MultiSigScript(pubkeys []*btcutil.AddressPubKey, nrequired int) ([]byte, error) { + if len(pubkeys) < nrequired { + return nil, ErrBadNumRequired + } + + builder := NewScriptBuilder().AddInt64(int64(nrequired)) + for _, key := range pubkeys { + builder.AddData(key.ScriptAddress()) + } + builder.AddInt64(int64(len(pubkeys))) + builder.AddOp(OP_CHECKMULTISIG) + + return builder.Script() +} + +// SignatureScript creates an input signature script for tx to spend +// BTC sent from a previous output to the owner of privKey. tx must +// include all transaction inputs and outputs, however txin scripts are +// allowed to be filled or empty. The returned script is calculated to +// be used as the idx'th txin sigscript for tx. subscript is the PkScript +// of the previous output being used as the idx'th input. privKey is +// serialized in either a compressed or uncompressed format based on +// compress. This format must match the same format used to generate +// the payment address, or the script validation will fail. +func SignatureScript(tx *btcwire.MsgTx, idx int, subscript []byte, hashType SigHashType, privKey *btcec.PrivateKey, compress bool) ([]byte, error) { + sig, err := RawTxInSignature(tx, idx, subscript, hashType, privKey) + if err != nil { + return nil, err + } + + pk := (*btcec.PublicKey)(&privKey.PublicKey) + var pkData []byte + if compress { + pkData = pk.SerializeCompressed() + } else { + pkData = pk.SerializeUncompressed() + } + + return NewScriptBuilder().AddData(sig).AddData(pkData).Script() +} + +// RawTxInSignature returns the serialized ECDSA signature for the input +// idx of the given transaction, with hashType appended to it. +func RawTxInSignature(tx *btcwire.MsgTx, idx int, subScript []byte, + hashType SigHashType, key *btcec.PrivateKey) ([]byte, error) { + parsedScript, err := parseScript(subScript) + if err != nil { + return nil, fmt.Errorf("cannot parse output script: %v", err) + } + hash := calcScriptHash(parsedScript, hashType, tx, idx) + signature, err := key.Sign(hash) + if err != nil { + return nil, fmt.Errorf("cannot sign tx input: %s", err) + } + + return append(signature.Serialize(), byte(hashType)), nil +} + +func p2pkSignatureScript(tx *btcwire.MsgTx, idx int, subScript []byte, hashType SigHashType, privKey *btcec.PrivateKey) ([]byte, error) { + sig, err := RawTxInSignature(tx, idx, subScript, hashType, privKey) + if err != nil { + return nil, err + } + + return NewScriptBuilder().AddData(sig).Script() +} + +// signMultiSig signs as many of the outputs in the provided multisig script as +// possible. It returns the generated script and a boolean if the script fulfils +// the contract (i.e. nrequired signatures are provided). Since it is arguably +// legal to not be able to sign any of the outputs, no error is returned. +func signMultiSig(tx *btcwire.MsgTx, idx int, subScript []byte, hashType SigHashType, + addresses []btcutil.Address, nRequired int, kdb KeyDB) ([]byte, bool) { + // We start with a single OP_FALSE to work around the (now standard) + // but in the reference implementation that causes a spurious pop at + // the end of OP_CHECKMULTISIG. + builder := NewScriptBuilder().AddOp(OP_FALSE) + signed := 0 + for _, addr := range addresses { + key, _, err := kdb.GetKey(addr) + if err != nil { + continue + } + sig, err := RawTxInSignature(tx, idx, subScript, hashType, key) + if err != nil { + continue + } + + builder.AddData(sig) + signed++ + if signed == nRequired { + break + } + + } + + script, _ := builder.Script() + return script, signed == nRequired +} + +func sign(net *btcnet.Params, tx *btcwire.MsgTx, idx int, subScript []byte, + hashType SigHashType, kdb KeyDB, sdb ScriptDB) ([]byte, ScriptClass, + []btcutil.Address, int, error) { + + class, addresses, nrequired, err := ExtractPkScriptAddrs(subScript, net) + if err != nil { + return nil, NonStandardTy, nil, 0, err + } + + switch class { + case PubKeyTy: + // look up key for address + key, _, err := kdb.GetKey(addresses[0]) + if err != nil { + return nil, class, nil, 0, err + } + + script, err := p2pkSignatureScript(tx, idx, subScript, hashType, + key) + if err != nil { + return nil, class, nil, 0, err + } + + return script, class, addresses, nrequired, nil + case PubKeyHashTy: + // look up key for address + key, compressed, err := kdb.GetKey(addresses[0]) + if err != nil { + return nil, class, nil, 0, err + } + + script, err := SignatureScript(tx, idx, subScript, hashType, + key, compressed) + if err != nil { + return nil, class, nil, 0, err + } + + return script, class, addresses, nrequired, nil + case ScriptHashTy: + script, err := sdb.GetScript(addresses[0]) + if err != nil { + return nil, class, nil, 0, err + } + + return script, class, addresses, nrequired, nil + case MultiSigTy: + script, _ := signMultiSig(tx, idx, subScript, hashType, + addresses, nrequired, kdb) + return script, class, addresses, nrequired, nil + case NullDataTy: + return nil, class, nil, 0, + errors.New("can't sign NULLDATA transactions") + default: + return nil, class, nil, 0, + errors.New("can't sign unknown transactions") + } +} + +// mergeScripts merges sigScript and prevScript assuming they are both +// partial solutions for pkScript spending output idx of tx. class, addresses +// and nrequired are the result of extracting the addresses from pkscript. +// The return value is the best effort merging of the two scripts. Calling this +// function with addresses, class and nrequired that do not match pkScript is +// an error and results in undefined behaviour. +func mergeScripts(net *btcnet.Params, tx *btcwire.MsgTx, idx int, + pkScript []byte, class ScriptClass, addresses []btcutil.Address, + nRequired int, sigScript, prevScript []byte) []byte { + + // TODO(oga) the scripthash and multisig paths here are overly + // inefficient in that they will recompute already known data. + // some internal refactoring could probably make this avoid needless + // extra calculations. + switch class { + case ScriptHashTy: + // Remove the last push in the script and then recurse. + // this could be a lot less inefficient. + sigPops, err := parseScript(sigScript) + if err != nil || len(sigPops) == 0 { + return prevScript + } + prevPops, err := parseScript(prevScript) + if err != nil || len(prevPops) == 0 { + return sigScript + } + + // assume that script in sigPops is the correct one, we just + // made it. + script := sigPops[len(sigPops)-1].data + + // We already know this information somewhere up the stack. + class, addresses, nrequired, err := + ExtractPkScriptAddrs(script, net) + + // regenerate scripts. + sigScript, _ := unparseScript(sigPops) + prevScript, _ := unparseScript(prevPops) + + // Merge + mergedScript := mergeScripts(net, tx, idx, script, class, + addresses, nrequired, sigScript, prevScript) + + // Reappend the script and return the result. + builder := NewScriptBuilder() + builder.script = mergedScript + builder.AddData(script) + finalScript, _ := builder.Script() + return finalScript + case MultiSigTy: + return mergeMultiSig(tx, idx, addresses, nRequired, pkScript, + sigScript, prevScript) + + // It doesn't actualy make sense to merge anything other than multiig + // and scripthash (because it could contain multisig). Everything else + // has either zero signature, can't be spent, or has a single signature + // which is either present or not. The other two cases are handled + // above. In the conflict case here we just assume the longest is + // correct (this matches behaviour of the reference implementation). + default: + if len(sigScript) > len(prevScript) { + return sigScript + } + return prevScript + } +} + +// mergeMultiSig combines the two signature scripts sigScript and prevScript +// that both provide signatures for pkScript in output idx of tx. addresses +// and nRequired should be the results from extracting the addresses from +// pkScript. Since this function is internal only we assume that the arguments +// have come from other functions internally and thus are all consistent with +// each other, behaviour is undefined if this contract is broken. +func mergeMultiSig(tx *btcwire.MsgTx, idx int, addresses []btcutil.Address, + nRequired int, pkScript, sigScript, prevScript []byte) []byte { + + // This is an internal only function and we already parsed this script + // as ok for multisig (this is how we got here), so if this fails then + // all assumptions are broken and who knows which way is up? + pkPops, _ := parseScript(pkScript) + + sigPops, err := parseScript(sigScript) + if err != nil || len(sigPops) == 0 { + return prevScript + } + + prevPops, err := parseScript(prevScript) + if err != nil || len(prevPops) == 0 { + return sigScript + } + + // Convenience function to avoid duplication. + extractSigs := func(pops []parsedOpcode, sigs [][]byte) [][]byte { + for _, pop := range pops { + if len(pop.data) != 0 { + sigs = append(sigs, pop.data) + } + } + return sigs + } + + possibleSigs := make([][]byte, 0, len(sigPops)+len(prevPops)) + possibleSigs = extractSigs(sigPops, possibleSigs) + possibleSigs = extractSigs(prevPops, possibleSigs) + + // Now we need to match the signatures to pubkeys, the only real way to + // do that is to try to verify them all and match it to the pubkey + // that verifies it. we then can go through the addresses in order + // to build our script. Anything that doesn't parse or doesn't verify we + // throw away. + addrToSig := make(map[string][]byte) +sigLoop: + for _, sig := range possibleSigs { + + // can't have a valid signature that doesn't at least have a + // hashtype, in practise it is even longer than this. but + // that'll be checked next. + if len(sig) < 1 { + continue + } + tSig := sig[:len(sig)-1] + hashType := SigHashType(sig[len(sig)-1]) + + pSig, err := btcec.ParseDERSignature(tSig, btcec.S256()) + if err != nil { + continue + } + + // We have to do this each round since hash types may vary + // between signatures and so the hash will vary. We can, + // however, assume no sigs etc are in the script since that + // would make the transaction nonstandard and thus not + // MultiSigTy, so we just need to hash the full thing. + hash := calcScriptHash(pkPops, hashType, tx, idx) + + for _, addr := range addresses { + // All multisig addresses should be pubkey addreses + // it is an error to call this internal function with + // bad input. + pkaddr := addr.(*btcutil.AddressPubKey) + + pubKey := pkaddr.PubKey() + + // If it matches we put it in the map. We only + // can take one signature per public key so if we + // already have one, we can throw this away. + if pSig.Verify(hash, pubKey) { + aStr := addr.EncodeAddress() + if _, ok := addrToSig[aStr]; !ok { + addrToSig[aStr] = sig + } + continue sigLoop + } + } + } + + // Extra opcode to handle the extra arg consumed (due to previous bugs + // in the reference implementation). + builder := NewScriptBuilder().AddOp(OP_FALSE) + doneSigs := 0 + // This assumes that addresses are in the same order as in the script. + for _, addr := range addresses { + sig, ok := addrToSig[addr.EncodeAddress()] + if !ok { + continue + } + builder.AddData(sig) + doneSigs++ + if doneSigs == nRequired { + break + } + } + + // padding for missing ones. + for i := doneSigs; i < nRequired; i++ { + builder.AddOp(OP_0) + } + + script, _ := builder.Script() + return script +} + +// KeyDB is an interface type provided to SignTxOutput, it encapsulates +// any user state required to get the private keys for an address. +type KeyDB interface { + GetKey(btcutil.Address) (*btcec.PrivateKey, bool, error) +} + +// KeyClosure implements ScriptDB with a closure +type KeyClosure func(btcutil.Address) (*btcec.PrivateKey, bool, error) + +// GetKey implements KeyDB by returning the result of calling the closure +func (kc KeyClosure) GetKey(address btcutil.Address) (*btcec.PrivateKey, + bool, error) { + return kc(address) +} + +// ScriptDB is an interface type provided to SignTxOutput, it encapsulates +// any user state required to get the scripts for an pay-to-script-hash address. +type ScriptDB interface { + GetScript(btcutil.Address) ([]byte, error) +} + +// ScriptClosure implements ScriptDB with a closure +type ScriptClosure func(btcutil.Address) ([]byte, error) + +// GetScript implements ScriptDB by returning the result of calling the closure +func (sc ScriptClosure) GetScript(address btcutil.Address) ([]byte, error) { + return sc(address) +} + +// SignTxOutput signs output idx of the given tx to resolve the script given in +// pkScript with a signature type of hashType. Any keys required will be +// looked up by calling getKey() with the string of the given address. +// Any pay-to-script-hash signatures will be similarly looked up by calling +// getScript. If previousScript is provided then the results in previousScript +// will be merged in a type-dependant manner with the newly generated. +// signature script. +func SignTxOutput(net *btcnet.Params, tx *btcwire.MsgTx, idx int, + pkScript []byte, hashType SigHashType, kdb KeyDB, sdb ScriptDB, + previousScript []byte) ([]byte, error) { + + sigScript, class, addresses, nrequired, err := sign(net, tx, idx, + pkScript, hashType, kdb, sdb) + if err != nil { + return nil, err + } + + if class == ScriptHashTy { + // TODO keep the sub addressed and pass down to merge. + realSigScript, _, _, _, err := sign(net, tx, idx, sigScript, + hashType, kdb, sdb) + if err != nil { + return nil, err + } + + // This is a bad thing. Append the p2sh script as the last + // push in the script. + builder := NewScriptBuilder() + builder.script = realSigScript + builder.AddData(sigScript) + + sigScript, _ = builder.Script() + // TODO keep a copy of the script for merging. + } + + // Merge scripts. with any previous data, if any. + mergedScript := mergeScripts(net, tx, idx, pkScript, class, addresses, + nrequired, sigScript, previousScript) + if err != nil { + return nil, err + } + + return mergedScript, nil +} + +// expectedInputs returns the number of arguments required by a script. +// If the script is of unnown type such that the number can not be determined +// then -1 is returned. We are an internal function and thus assume that class +// is the real class of pops (and we can thus assume things that were +// determined while finding out the type). +func expectedInputs(pops []parsedOpcode, class ScriptClass) int { + // count needed inputs. + switch class { + case PubKeyTy: + return 1 + case PubKeyHashTy: + return 2 + case ScriptHashTy: + // Not including script, handled below. + return 1 + case MultiSigTy: + // Standard multisig has a push a small number for the number + // of sigs and number of keys. Check the first push instruction + // to see how many arguments are expected. typeOfScript already + // checked this so we know it'll be a small int. Also, due to + // the original bitcoind bug where OP_CHECKMULTISIG pops an + // additional item from the stack, add an extra expected input + // for the extra push that is required to compensate. + return asSmallInt(pops[0].opcode) + 1 + case NullDataTy: + fallthrough + default: + return -1 + } +} + +// ScriptInfo houses information about a script pair that is determined by +// CalcScriptInfo. +type ScriptInfo struct { + // The class of the sigscript, equivalent to calling GetScriptClass + // on the sigScript. + PkScriptClass ScriptClass + + // NumInputs is the number of inputs provided by the pkScript. + NumInputs int + + // ExpectedInputs is the number of outputs required by sigScript and any + // pay-to-script-hash scripts. The number will be -1 if unknown. + ExpectedInputs int + + // SigOps is the nubmer of signature operations in the script pair. + SigOps int +} + +// CalcScriptInfo returns a structure providing data about the scriptpair that +// are provided as arguments. It will error if the pair is in someway invalid +// such that they can not be analysed, i.e. if they do not parse or the +// pkScript is not a push-only script +func CalcScriptInfo(sigscript, pkscript []byte, bip16 bool) (*ScriptInfo, error) { + si := new(ScriptInfo) + // parse both scripts. + sigPops, err := parseScript(sigscript) + if err != nil { + return nil, err + } + + pkPops, err := parseScript(pkscript) + if err != nil { + return nil, err + } + + // push only sigScript makes little sense. + si.PkScriptClass = typeOfScript(pkPops) + + // Can't have a pkScript that doesn't just push data. + if !isPushOnly(sigPops) { + return nil, ErrStackNonPushOnly + } + + si.ExpectedInputs = expectedInputs(pkPops, si.PkScriptClass) + // all entries push to stack (or are OP_RESERVED and exec will fail). + si.NumInputs = len(sigPops) + + if si.PkScriptClass == ScriptHashTy && bip16 { + // grab the last push instruction in the script and pull out the + // data. + script := sigPops[len(sigPops)-1].data + // check for existance and error else. + shPops, err := parseScript(script) + if err != nil { + return nil, err + } + + shClass := typeOfScript(shPops) + + shInputs := expectedInputs(shPops, shClass) + if shInputs == -1 { + // We have no fucking clue, then. + si.ExpectedInputs = -1 + } else { + si.ExpectedInputs += shInputs + } + si.SigOps = getSigOpCount(shPops, true) + } else { + si.SigOps = getSigOpCount(pkPops, true) + } + + return si, nil +} + +// asSmallInt returns the passed opcode, which must be true according to +// isSmallInt(), as an integer. +func asSmallInt(op *opcode) int { + if op.value == OP_0 { + return 0 + } + + return int(op.value - (OP_1 - 1)) +} + +// CalcMultiSigStats returns the number of public keys and signatures from +// a multi-signature transaction script. The passed script MUST already be +// known to be a multi-signature script. +func CalcMultiSigStats(script []byte) (int, int, error) { + pops, err := parseScript(script) + if err != nil { + return 0, 0, err + } + + // A multi-signature script is of the pattern: + // NUM_SIGS PUBKEY PUBKEY PUBKEY... NUM_PUBKEYS OP_CHECKMULTISIG + // Therefore the number of signatures is the oldest item on the stack + // and the number of pubkeys is the 2nd to last. Also, the absolute + // minimum for a multi-signature script is 1 pubkey, so at least 4 + // items must be on the stack per: + // OP_1 PUBKEY OP_1 OP_CHECKMULTISIG + if len(pops) < 4 { + return 0, 0, ErrStackUnderflow + } + + numSigs := asSmallInt(pops[0].opcode) + numPubKeys := asSmallInt(pops[len(pops)-2].opcode) + return numPubKeys, numSigs, nil +} + +// PushedData returns an array of byte slices containing any pushed data found +// in the passed script. This includes OP_0, but not OP_1 - OP_16. +func PushedData(script []byte) ([][]byte, error) { + pops, err := parseScript(script) + if err != nil { + return nil, err + } + var data [][]byte + for _, pop := range pops { + if pop.data != nil { + data = append(data, pop.data) + } else if pop.opcode.value == OP_0 { + data = append(data, []byte{}) + } + } + return data, nil +} diff --git a/txscript/script_test.go b/txscript/script_test.go new file mode 100644 index 000000000..b4c7959d0 --- /dev/null +++ b/txscript/script_test.go @@ -0,0 +1,4784 @@ +// 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" + "errors" + "fmt" + "testing" + + "github.com/btcsuite/btcd/txscript" + "github.com/btcsuite/btcec" + "github.com/btcsuite/btcnet" + "github.com/btcsuite/btcutil" + "github.com/btcsuite/btcwire" +) + +// builderScript is a convenience function which is used in the tests. It +// allows access to the script from a known good script built with the builder. +// Any errors are converted to a panic since it is only, and must only, be used +// with hard coded, and therefore, known good, scripts. +func builderScript(builder *txscript.ScriptBuilder) []byte { + script, err := builder.Script() + if err != nil { + panic(err) + } + return script +} + +func TestPushedData(t *testing.T) { + t.Parallel() + + var tests = []struct { + in []byte + out [][]byte + valid bool + }{ + { + []byte{txscript.OP_0, txscript.OP_IF, txscript.OP_0, txscript.OP_ELSE, txscript.OP_2, txscript.OP_ENDIF}, + [][]byte{{}, {}}, + true, + }, + { + builderScript(txscript.NewScriptBuilder().AddInt64(16777216).AddInt64(10000000)), + [][]byte{ + {0x00, 0x00, 0x00, 0x01}, // 16777216 + {0x80, 0x96, 0x98, 0x00}, // 10000000 + }, + true, + }, + { + builderScript(txscript.NewScriptBuilder().AddOp(txscript.OP_DUP).AddOp(txscript.OP_HASH160). + AddData([]byte("17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhem")).AddOp(txscript.OP_EQUALVERIFY). + AddOp(txscript.OP_CHECKSIG)), + [][]byte{ + // 17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhem + { + 0x31, 0x37, 0x56, 0x5a, 0x4e, 0x58, 0x31, 0x53, 0x4e, 0x35, + 0x4e, 0x74, 0x4b, 0x61, 0x38, 0x55, 0x51, 0x46, 0x78, 0x77, + 0x51, 0x62, 0x46, 0x65, 0x46, 0x63, 0x33, 0x69, 0x71, 0x52, + 0x59, 0x68, 0x65, 0x6d, + }, + }, + true, + }, + { + builderScript(txscript.NewScriptBuilder().AddOp(txscript.OP_PUSHDATA4).AddInt64(1000). + AddOp(txscript.OP_EQUAL)), + [][]byte{}, + false, + }, + } + + for x, test := range tests { + pushedData, err := txscript.PushedData(test.in) + if test.valid && err != nil { + t.Errorf("TestPushedData failed test #%d: %v\n", x, err) + continue + } else if !test.valid && err == nil { + t.Errorf("TestPushedData failed test #%d: test should be invalid\n", x) + continue + } + for x, data := range pushedData { + if !bytes.Equal(data, test.out[x]) { + t.Errorf("TestPushedData failed test #%d: want: %x got: %x\n", + x, test.out[x], data) + } + } + } +} + +func TestStandardPushes(t *testing.T) { + t.Parallel() + + for i := 0; i < 65535; i++ { + builder := txscript.NewScriptBuilder() + builder.AddInt64(int64(i)) + script, err := builder.Script() + if err != nil { + t.Errorf("StandardPushesTests test #%d unexpected error: %v\n", i, err) + continue + } + if result := txscript.IsPushOnlyScript(script); !result { + t.Errorf("StandardPushesTests IsPushOnlyScript test #%d failed: %x\n", i, script) + continue + } + if result := txscript.HasCanonicalPushes(script); !result { + t.Errorf("StandardPushesTests HasCanonicalPushes test #%d failed: %x\n", i, script) + continue + } + } + for i := 0; i <= txscript.MaxScriptElementSize; i++ { + builder := txscript.NewScriptBuilder() + builder.AddData(bytes.Repeat([]byte{0x49}, i)) + script, err := builder.Script() + if err != nil { + t.Errorf("StandardPushesTests test #%d unexpected error: %v\n", i, err) + continue + } + if result := txscript.IsPushOnlyScript(script); !result { + t.Errorf("StandardPushesTests IsPushOnlyScript test #%d failed: %x\n", i, script) + continue + } + if result := txscript.HasCanonicalPushes(script); !result { + t.Errorf("StandardPushesTests HasCanonicalPushes test #%d failed: %x\n", i, script) + continue + } + } +} + +type txTest struct { + name string + tx *btcwire.MsgTx + pkScript []byte // output script of previous tx + idx int // tx idx to be run. + bip16 bool // is bip16 active? + canonicalSigs bool // should signatures be validated as canonical? + parseErr error // failure of NewScript + err error // Failure of Executre + shouldFail bool // Execute should fail with nonspecified error. + nSigOps int // result of GetPreciseSigOpsCount + scriptInfo txscript.ScriptInfo // result of ScriptInfo + scriptInfoErr error // error return of ScriptInfo +} + +var txTests = []txTest{ + // tx 0437cd7f8525ceed2324359c2d0ba26006d92d85. the first tx in the + // blockchain that verifies signatures. + { + name: "CheckSig", + tx: &btcwire.MsgTx{ + Version: 1, + TxIn: []*btcwire.TxIn{ + { + PreviousOutPoint: btcwire.OutPoint{ + Hash: btcwire.ShaHash([32]byte{ + 0xc9, 0x97, 0xa5, 0xe5, + 0x6e, 0x10, 0x41, 0x02, + 0xfa, 0x20, 0x9c, 0x6a, + 0x85, 0x2d, 0xd9, 0x06, + 0x60, 0xa2, 0x0b, 0x2d, + 0x9c, 0x35, 0x24, 0x23, + 0xed, 0xce, 0x25, 0x85, + 0x7f, 0xcd, 0x37, 0x04, + }), + Index: 0, + }, + SignatureScript: []uint8{ + txscript.OP_DATA_71, + 0x30, 0x44, 0x02, 0x20, 0x4e, + 0x45, 0xe1, 0x69, 0x32, 0xb8, + 0xaf, 0x51, 0x49, 0x61, 0xa1, + 0xd3, 0xa1, 0xa2, 0x5f, 0xdf, + 0x3f, 0x4f, 0x77, 0x32, 0xe9, + 0xd6, 0x24, 0xc6, 0xc6, 0x15, + 0x48, 0xab, 0x5f, 0xb8, 0xcd, + 0x41, 0x02, 0x20, 0x18, 0x15, + 0x22, 0xec, 0x8e, 0xca, 0x07, + 0xde, 0x48, 0x60, 0xa4, 0xac, + 0xdd, 0x12, 0x90, 0x9d, 0x83, + 0x1c, 0xc5, 0x6c, 0xbb, 0xac, + 0x46, 0x22, 0x08, 0x22, 0x21, + 0xa8, 0x76, 0x8d, 0x1d, 0x09, + 0x01, + }, + + Sequence: 4294967295, + }, + }, + TxOut: []*btcwire.TxOut{ + { + Value: 1000000000, + PkScript: []byte{ + txscript.OP_DATA_65, + 0x04, 0xae, 0x1a, 0x62, 0xfe, + 0x09, 0xc5, 0xf5, 0x1b, 0x13, + 0x90, 0x5f, 0x07, 0xf0, 0x6b, + 0x99, 0xa2, 0xf7, 0x15, 0x9b, + 0x22, 0x25, 0xf3, 0x74, 0xcd, + 0x37, 0x8d, 0x71, 0x30, 0x2f, + 0xa2, 0x84, 0x14, 0xe7, 0xaa, + 0xb3, 0x73, 0x97, 0xf5, 0x54, + 0xa7, 0xdf, 0x5f, 0x14, 0x2c, + 0x21, 0xc1, 0xb7, 0x30, 0x3b, + 0x8a, 0x06, 0x26, 0xf1, 0xba, + 0xde, 0xd5, 0xc7, 0x2a, 0x70, + 0x4f, 0x7e, 0x6c, 0xd8, 0x4c, + txscript.OP_CHECKSIG, + }, + }, + { + Value: 4000000000, + PkScript: []byte{ + txscript.OP_DATA_65, + 0x04, 0x11, 0xdb, 0x93, 0xe1, + 0xdc, 0xdb, 0x8a, 0x01, 0x6b, + 0x49, 0x84, 0x0f, 0x8c, 0x53, + 0xbc, 0x1e, 0xb6, 0x8a, 0x38, + 0x2e, 0x97, 0xb1, 0x48, 0x2e, + 0xca, 0xd7, 0xb1, 0x48, 0xa6, + 0x90, 0x9a, 0x5c, 0xb2, 0xe0, + 0xea, 0xdd, 0xfb, 0x84, 0xcc, + 0xf9, 0x74, 0x44, 0x64, 0xf8, + 0x2e, 0x16, 0x0b, 0xfa, 0x9b, + 0x8b, 0x64, 0xf9, 0xd4, 0xc0, + 0x3f, 0x99, 0x9b, 0x86, 0x43, + 0xf6, 0x56, 0xb4, 0x12, 0xa3, + txscript.OP_CHECKSIG, + }, + }, + }, + LockTime: 0, + }, + pkScript: []byte{ + txscript.OP_DATA_65, + 0x04, 0x11, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a, 0x01, + 0x6b, 0x49, 0x84, 0x0f, 0x8c, 0x53, 0xbc, 0x1e, 0xb6, + 0x8a, 0x38, 0x2e, 0x97, 0xb1, 0x48, 0x2e, 0xca, 0xd7, + 0xb1, 0x48, 0xa6, 0x90, 0x9a, 0x5c, 0xb2, 0xe0, 0xea, + 0xdd, 0xfb, 0x84, 0xcc, 0xf9, 0x74, 0x44, 0x64, 0xf8, + 0x2e, 0x16, 0x0b, 0xfa, 0x9b, 0x8b, 0x64, 0xf9, 0xd4, + 0xc0, 0x3f, 0x99, 0x9b, 0x86, 0x43, 0xf6, 0x56, 0xb4, + 0x12, 0xa3, txscript.OP_CHECKSIG, + }, + idx: 0, + nSigOps: 1, + scriptInfo: txscript.ScriptInfo{ + PkScriptClass: txscript.PubKeyTy, + NumInputs: 1, + ExpectedInputs: 1, + SigOps: 1, + }, + }, + // Previous test with the value of one output changed. + { + name: "CheckSig Failure", + tx: &btcwire.MsgTx{ + Version: 1, + TxIn: []*btcwire.TxIn{ + { + PreviousOutPoint: btcwire.OutPoint{ + Hash: btcwire.ShaHash([32]byte{ + 0xc9, 0x97, 0xa5, 0xe5, + 0x6e, 0x10, 0x41, 0x02, + 0xfa, 0x20, 0x9c, 0x6a, + 0x85, 0x2d, 0xd9, 0x06, + 0x60, 0xa2, 0x0b, 0x2d, + 0x9c, 0x35, 0x24, 0x23, + 0xed, 0xce, 0x25, 0x85, + 0x7f, 0xcd, 0x37, 0x04, + }), + Index: 0, + }, + SignatureScript: []uint8{ + txscript.OP_DATA_71, + 0x30, 0x44, 0x02, 0x20, 0x4e, + 0x45, 0xe1, 0x69, 0x32, 0xb8, + 0xaf, 0x51, 0x49, 0x61, 0xa1, + 0xd3, 0xa1, 0xa2, 0x5f, 0xdf, + 0x3f, 0x4f, 0x77, 0x32, 0xe9, + 0xd6, 0x24, 0xc6, 0xc6, 0x15, + 0x48, 0xab, 0x5f, 0xb8, 0xcd, + 0x41, 0x02, 0x20, 0x18, 0x15, + 0x22, 0xec, 0x8e, 0xca, 0x07, + 0xde, 0x48, 0x60, 0xa4, 0xac, + 0xdd, 0x12, 0x90, 0x9d, 0x83, + 0x1c, 0xc5, 0x6c, 0xbb, 0xac, + 0x46, 0x22, 0x08, 0x22, 0x21, + 0xa8, 0x76, 0x8d, 0x1d, 0x09, + 0x01, + }, + + Sequence: 4294967295, + }, + }, + TxOut: []*btcwire.TxOut{ + { + Value: 1000000000, + PkScript: []byte{ + txscript.OP_DATA_65, + 0x04, 0xae, 0x1a, 0x62, 0xfe, + 0x09, 0xc5, 0xf5, 0x1b, 0x13, + 0x90, 0x5f, 0x07, 0xf0, 0x6b, + 0x99, 0xa2, 0xf7, 0x15, 0x9b, + 0x22, 0x25, 0xf3, 0x74, 0xcd, + 0x37, 0x8d, 0x71, 0x30, 0x2f, + 0xa2, 0x84, 0x14, 0xe7, 0xaa, + 0xb3, 0x73, 0x97, 0xf5, 0x54, + 0xa7, 0xdf, 0x5f, 0x14, 0x2c, + 0x21, 0xc1, 0xb7, 0x30, 0x3b, + 0x8a, 0x06, 0x26, 0xf1, 0xba, + 0xde, 0xd5, 0xc7, 0x2a, 0x70, + 0x4f, 0x7e, 0x6c, 0xd8, 0x4c, + txscript.OP_CHECKSIG, + }, + }, + { + Value: 5000000000, + PkScript: []byte{ + txscript.OP_DATA_65, + 0x04, 0x11, 0xdb, 0x93, 0xe1, + 0xdc, 0xdb, 0x8a, 0x01, 0x6b, + 0x49, 0x84, 0x0f, 0x8c, 0x53, + 0xbc, 0x1e, 0xb6, 0x8a, 0x38, + 0x2e, 0x97, 0xb1, 0x48, 0x2e, + 0xca, 0xd7, 0xb1, 0x48, 0xa6, + 0x90, 0x9a, 0x5c, 0xb2, 0xe0, + 0xea, 0xdd, 0xfb, 0x84, 0xcc, + 0xf9, 0x74, 0x44, 0x64, 0xf8, + 0x2e, 0x16, 0x0b, 0xfa, 0x9b, + 0x8b, 0x64, 0xf9, 0xd4, 0xc0, + 0x3f, 0x99, 0x9b, 0x86, 0x43, + 0xf6, 0x56, 0xb4, 0x12, 0xa3, + txscript.OP_CHECKSIG, + }, + }, + }, + LockTime: 0, + }, + pkScript: []byte{ + txscript.OP_DATA_65, + 0x04, 0x11, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a, 0x01, + 0x6b, 0x49, 0x84, 0x0f, 0x8c, 0x53, 0xbc, 0x1e, 0xb6, + 0x8a, 0x38, 0x2e, 0x97, 0xb1, 0x48, 0x2e, 0xca, 0xd7, + 0xb1, 0x48, 0xa6, 0x90, 0x9a, 0x5c, 0xb2, 0xe0, 0xea, + 0xdd, 0xfb, 0x84, 0xcc, 0xf9, 0x74, 0x44, 0x64, 0xf8, + 0x2e, 0x16, 0x0b, 0xfa, 0x9b, 0x8b, 0x64, 0xf9, 0xd4, + 0xc0, 0x3f, 0x99, 0x9b, 0x86, 0x43, 0xf6, 0x56, 0xb4, + 0x12, 0xa3, txscript.OP_CHECKSIG, + }, + idx: 0, + err: txscript.ErrStackScriptFailed, + nSigOps: 1, + scriptInfo: txscript.ScriptInfo{ + PkScriptClass: txscript.PubKeyTy, + NumInputs: 1, + ExpectedInputs: 1, + SigOps: 1, + }, + }, + { + name: "CheckSig invalid signature", + tx: &btcwire.MsgTx{ + Version: 1, + TxIn: []*btcwire.TxIn{ + { + PreviousOutPoint: btcwire.OutPoint{ + Hash: btcwire.ShaHash([32]byte{ + 0xc9, 0x97, 0xa5, 0xe5, + 0x6e, 0x10, 0x41, 0x02, + 0xfa, 0x20, 0x9c, 0x6a, + 0x85, 0x2d, 0xd9, 0x06, + 0x60, 0xa2, 0x0b, 0x2d, + 0x9c, 0x35, 0x24, 0x23, + 0xed, 0xce, 0x25, 0x85, + 0x7f, 0xcd, 0x37, 0x04, + }), + Index: 0, + }, + // Signature has length fiddled to + // fail parsing. + SignatureScript: []uint8{ + txscript.OP_DATA_71, + 0x30, 0x45, 0x02, 0x20, 0x4e, + 0x45, 0xe1, 0x69, 0x32, 0xb8, + 0xaf, 0x51, 0x49, 0x61, 0xa1, + 0xd3, 0xa1, 0xa2, 0x5f, 0xdf, + 0x3f, 0x4f, 0x77, 0x32, 0xe9, + 0xd6, 0x24, 0xc6, 0xc6, 0x15, + 0x48, 0xab, 0x5f, 0xb8, 0xcd, + 0x41, 0x02, 0x20, 0x18, 0x15, + 0x22, 0xec, 0x8e, 0xca, 0x07, + 0xde, 0x48, 0x60, 0xa4, 0xac, + 0xdd, 0x12, 0x90, 0x9d, 0x83, + 0x1c, 0xc5, 0x6c, 0xbb, 0xac, + 0x46, 0x22, 0x08, 0x22, 0x21, + 0xa8, 0x76, 0x8d, 0x1d, 0x09, + 0x01, + }, + + Sequence: 4294967295, + }, + }, + TxOut: []*btcwire.TxOut{ + { + Value: 1000000000, + PkScript: []byte{ + txscript.OP_DATA_65, + 0x04, 0xae, 0x1a, 0x62, 0xfe, + 0x09, 0xc5, 0xf5, 0x1b, 0x13, + 0x90, 0x5f, 0x07, 0xf0, 0x6b, + 0x99, 0xa2, 0xf7, 0x15, 0x9b, + 0x22, 0x25, 0xf3, 0x74, 0xcd, + 0x37, 0x8d, 0x71, 0x30, 0x2f, + 0xa2, 0x84, 0x14, 0xe7, 0xaa, + 0xb3, 0x73, 0x97, 0xf5, 0x54, + 0xa7, 0xdf, 0x5f, 0x14, 0x2c, + 0x21, 0xc1, 0xb7, 0x30, 0x3b, + 0x8a, 0x06, 0x26, 0xf1, 0xba, + 0xde, 0xd5, 0xc7, 0x2a, 0x70, + 0x4f, 0x7e, 0x6c, 0xd8, 0x4c, + txscript.OP_CHECKSIG, + }, + }, + { + Value: 4000000000, + PkScript: []byte{ + txscript.OP_DATA_65, + 0x04, 0x11, 0xdb, 0x93, 0xe1, + 0xdc, 0xdb, 0x8a, 0x01, 0x6b, + 0x49, 0x84, 0x0f, 0x8c, 0x53, + 0xbc, 0x1e, 0xb6, 0x8a, 0x38, + 0x2e, 0x97, 0xb1, 0x48, 0x2e, + 0xca, 0xd7, 0xb1, 0x48, 0xa6, + 0x90, 0x9a, 0x5c, 0xb2, 0xe0, + 0xea, 0xdd, 0xfb, 0x84, 0xcc, + 0xf9, 0x74, 0x44, 0x64, 0xf8, + 0x2e, 0x16, 0x0b, 0xfa, 0x9b, + 0x8b, 0x64, 0xf9, 0xd4, 0xc0, + 0x3f, 0x99, 0x9b, 0x86, 0x43, + 0xf6, 0x56, 0xb4, 0x12, 0xa3, + txscript.OP_CHECKSIG, + }, + }, + }, + LockTime: 0, + }, + pkScript: []byte{ + txscript.OP_DATA_65, + 0x04, 0x11, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a, 0x01, + 0x6b, 0x49, 0x84, 0x0f, 0x8c, 0x53, 0xbc, 0x1e, 0xb6, + 0x8a, 0x38, 0x2e, 0x97, 0xb1, 0x48, 0x2e, 0xca, 0xd7, + 0xb1, 0x48, 0xa6, 0x90, 0x9a, 0x5c, 0xb2, 0xe0, 0xea, + 0xdd, 0xfb, 0x84, 0xcc, 0xf9, 0x74, 0x44, 0x64, 0xf8, + 0x2e, 0x16, 0x0b, 0xfa, 0x9b, 0x8b, 0x64, 0xf9, 0xd4, + 0xc0, 0x3f, 0x99, 0x9b, 0x86, 0x43, 0xf6, 0x56, 0xb4, + 0x12, 0xa3, txscript.OP_CHECKSIG, + }, + idx: 0, + shouldFail: true, + nSigOps: 1, + scriptInfo: txscript.ScriptInfo{ + PkScriptClass: txscript.PubKeyTy, + NumInputs: 1, + ExpectedInputs: 1, + SigOps: 1, + }, + }, + { + name: "CheckSig invalid pubkey", + tx: &btcwire.MsgTx{ + Version: 1, + TxIn: []*btcwire.TxIn{ + { + PreviousOutPoint: btcwire.OutPoint{ + Hash: btcwire.ShaHash([32]byte{ + 0xc9, 0x97, 0xa5, 0xe5, + 0x6e, 0x10, 0x41, 0x02, + 0xfa, 0x20, 0x9c, 0x6a, + 0x85, 0x2d, 0xd9, 0x06, + 0x60, 0xa2, 0x0b, 0x2d, + 0x9c, 0x35, 0x24, 0x23, + 0xed, 0xce, 0x25, 0x85, + 0x7f, 0xcd, 0x37, 0x04, + }), + Index: 0, + }, + SignatureScript: []uint8{ + txscript.OP_DATA_71, + 0x30, 0x44, 0x02, 0x20, 0x4e, + 0x45, 0xe1, 0x69, 0x32, 0xb8, + 0xaf, 0x51, 0x49, 0x61, 0xa1, + 0xd3, 0xa1, 0xa2, 0x5f, 0xdf, + 0x3f, 0x4f, 0x77, 0x32, 0xe9, + 0xd6, 0x24, 0xc6, 0xc6, 0x15, + 0x48, 0xab, 0x5f, 0xb8, 0xcd, + 0x41, 0x02, 0x20, 0x18, 0x15, + 0x22, 0xec, 0x8e, 0xca, 0x07, + 0xde, 0x48, 0x60, 0xa4, 0xac, + 0xdd, 0x12, 0x90, 0x9d, 0x83, + 0x1c, 0xc5, 0x6c, 0xbb, 0xac, + 0x46, 0x22, 0x08, 0x22, 0x21, + 0xa8, 0x76, 0x8d, 0x1d, 0x09, + 0x01, + }, + + Sequence: 4294967295, + }, + }, + TxOut: []*btcwire.TxOut{ + { + Value: 1000000000, + PkScript: []byte{ + txscript.OP_DATA_65, + 0x04, 0xae, 0x1a, 0x62, 0xfe, + 0x09, 0xc5, 0xf5, 0x1b, 0x13, + 0x90, 0x5f, 0x07, 0xf0, 0x6b, + 0x99, 0xa2, 0xf7, 0x15, 0x9b, + 0x22, 0x25, 0xf3, 0x74, 0xcd, + 0x37, 0x8d, 0x71, 0x30, 0x2f, + 0xa2, 0x84, 0x14, 0xe7, 0xaa, + 0xb3, 0x73, 0x97, 0xf5, 0x54, + 0xa7, 0xdf, 0x5f, 0x14, 0x2c, + 0x21, 0xc1, 0xb7, 0x30, 0x3b, + 0x8a, 0x06, 0x26, 0xf1, 0xba, + 0xde, 0xd5, 0xc7, 0x2a, 0x70, + 0x4f, 0x7e, 0x6c, 0xd8, 0x4c, + txscript.OP_CHECKSIG, + }, + }, + { + Value: 4000000000, + PkScript: []byte{ + txscript.OP_DATA_65, + 0x04, 0x11, 0xdb, 0x93, 0xe1, + 0xdc, 0xdb, 0x8a, 0x01, 0x6b, + 0x49, 0x84, 0x0f, 0x8c, 0x53, + 0xbc, 0x1e, 0xb6, 0x8a, 0x38, + 0x2e, 0x97, 0xb1, 0x48, 0x2e, + 0xca, 0xd7, 0xb1, 0x48, 0xa6, + 0x90, 0x9a, 0x5c, 0xb2, 0xe0, + 0xea, 0xdd, 0xfb, 0x84, 0xcc, + 0xf9, 0x74, 0x44, 0x64, 0xf8, + 0x2e, 0x16, 0x0b, 0xfa, 0x9b, + 0x8b, 0x64, 0xf9, 0xd4, 0xc0, + 0x3f, 0x99, 0x9b, 0x86, 0x43, + 0xf6, 0x56, 0xb4, 0x12, 0xa3, + txscript.OP_CHECKSIG, + }, + }, + }, + LockTime: 0, + }, + // pubkey header magic byte has been changed to parse wrong. + pkScript: []byte{ + txscript.OP_DATA_65, + 0x02, 0x11, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a, 0x01, + 0x6b, 0x49, 0x84, 0x0f, 0x8c, 0x53, 0xbc, 0x1e, 0xb6, + 0x8a, 0x38, 0x2e, 0x97, 0xb1, 0x48, 0x2e, 0xca, 0xd7, + 0xb1, 0x48, 0xa6, 0x90, 0x9a, 0x5c, 0xb2, 0xe0, 0xea, + 0xdd, 0xfb, 0x84, 0xcc, 0xf9, 0x74, 0x44, 0x64, 0xf8, + 0x2e, 0x16, 0x0b, 0xfa, 0x9b, 0x8b, 0x64, 0xf9, 0xd4, + 0xc0, 0x3f, 0x99, 0x9b, 0x86, 0x43, 0xf6, 0x56, 0xb4, + 0x12, 0xa3, txscript.OP_CHECKSIG, + }, + idx: 0, + shouldFail: true, + nSigOps: 1, + scriptInfo: txscript.ScriptInfo{ + PkScriptClass: txscript.PubKeyTy, + NumInputs: 1, + ExpectedInputs: 1, + SigOps: 1, + }, + }, + // tx 599e47a8114fe098103663029548811d2651991b62397e057f0c863c2bc9f9ea + // uses checksig with SigHashNone. + { + name: "CheckSigHashNone", + tx: &btcwire.MsgTx{ + Version: 1, + TxIn: []*btcwire.TxIn{ + { + PreviousOutPoint: btcwire.OutPoint{ + Hash: btcwire.ShaHash([32]byte{ + 0x5f, 0x38, 0x6c, 0x8a, + 0x38, 0x42, 0xc9, 0xa9, + 0xdc, 0xfa, 0x9b, 0x78, + 0xbe, 0x78, 0x5a, 0x40, + 0xa7, 0xbd, 0xa0, 0x8b, + 0x64, 0x64, 0x6b, 0xe3, + 0x65, 0x43, 0x01, 0xea, + 0xcc, 0xfc, 0x8d, 0x5e, + }), + Index: 1, + }, + SignatureScript: []byte{ + txscript.OP_DATA_71, + 0x30, 0x44, 0x02, 0x20, 0xbb, + 0x4f, 0xbc, 0x49, 0x5a, 0xa2, + 0x3b, 0xab, 0xb2, 0xc2, 0xbe, + 0x4e, 0x3f, 0xb4, 0xa5, 0xdf, + 0xfe, 0xfe, 0x20, 0xc8, 0xef, + 0xf5, 0x94, 0x0f, 0x13, 0x56, + 0x49, 0xc3, 0xea, 0x96, 0x44, + 0x4a, 0x02, 0x20, 0x04, 0xaf, + 0xcd, 0xa9, 0x66, 0xc8, 0x07, + 0xbb, 0x97, 0x62, 0x2d, 0x3e, + 0xef, 0xea, 0x82, 0x8f, 0x62, + 0x3a, 0xf3, 0x06, 0xef, 0x2b, + 0x75, 0x67, 0x82, 0xee, 0x6f, + 0x8a, 0x22, 0xa9, 0x59, 0xa2, + 0x02, + txscript.OP_DATA_65, + 0x04, 0xf1, 0x93, 0x9a, 0xe6, + 0xb0, 0x1e, 0x84, 0x9b, 0xf0, + 0x5d, 0x0e, 0xd5, 0x1f, 0xd5, + 0xb9, 0x2b, 0x79, 0xa0, 0xe3, + 0x13, 0xe3, 0xf3, 0x89, 0xc7, + 0x26, 0xf1, 0x1f, 0xa3, 0xe1, + 0x44, 0xd9, 0x22, 0x7b, 0x07, + 0xe8, 0xa8, 0x7c, 0x0e, 0xe3, + 0x63, 0x72, 0xe9, 0x67, 0xe0, + 0x90, 0xd1, 0x1b, 0x77, 0x77, + 0x07, 0xaa, 0x73, 0xef, 0xac, + 0xab, 0xff, 0xff, 0xa2, 0x85, + 0xc0, 0x0b, 0x36, 0x22, 0xd6, + }, + Sequence: 4294967295, + }, + }, + TxOut: []*btcwire.TxOut{ + { + Value: 1000000, + PkScript: []byte{ + txscript.OP_DUP, + txscript.OP_HASH160, + txscript.OP_DATA_20, + 0x66, 0x0d, 0x4e, 0xf3, 0xa7, + 0x43, 0xe3, 0xe6, 0x96, 0xad, + 0x99, 0x03, 0x64, 0xe5, 0x55, + 0xc2, 0x71, 0xad, 0x50, 0x4b, + txscript.OP_EQUALVERIFY, + txscript.OP_CHECKSIG, + }, + }, + { + Value: 29913632, + PkScript: []byte{ + txscript.OP_DUP, + txscript.OP_HASH160, + txscript.OP_DATA_20, + 0x21, 0xc4, 0x3c, 0xe4, 0x00, + 0x90, 0x13, 0x12, 0xa6, 0x03, + 0xe4, 0x20, 0x7a, 0xad, 0xfd, + 0x74, 0x2b, 0xe8, 0xe7, 0xda, + txscript.OP_EQUALVERIFY, + txscript.OP_CHECKSIG, + }, + }, + }, + LockTime: 0, + }, + pkScript: []byte{ + txscript.OP_DUP, + txscript.OP_HASH160, + txscript.OP_DATA_20, + 0x21, 0xc4, 0x3c, 0xe4, 0x00, 0x90, 0x13, 0x12, 0xa6, + 0x03, 0xe4, 0x20, 0x7a, 0xad, 0xfd, 0x74, 0x2b, 0xe8, + 0xe7, 0xda, + txscript.OP_EQUALVERIFY, + txscript.OP_CHECKSIG, + }, + idx: 0, + bip16: true, // after threshold + nSigOps: 1, + scriptInfo: txscript.ScriptInfo{ + PkScriptClass: txscript.PubKeyHashTy, + NumInputs: 2, + ExpectedInputs: 2, + SigOps: 1, + }, + }, + { + name: "Non-canonical signature: R value negative", + tx: &btcwire.MsgTx{ + Version: 1, + TxIn: []*btcwire.TxIn{ + { + PreviousOutPoint: btcwire.OutPoint{ + Hash: btcwire.ShaHash([32]byte{ + 0xfe, 0x15, 0x62, 0xc4, + 0x8b, 0x3a, 0xa6, 0x37, + 0x3f, 0x42, 0xe9, 0x61, + 0x51, 0x89, 0xcf, 0x73, + 0x32, 0xd7, 0x33, 0x5c, + 0xbe, 0xa7, 0x80, 0xbe, + 0x69, 0x6a, 0xc6, 0xc6, + 0x50, 0xfd, 0xda, 0x4a, + }), + Index: 1, + }, + SignatureScript: []byte{ + txscript.OP_DATA_71, + 0x30, 0x44, 0x02, 0x20, 0xa0, + 0x42, 0xde, 0xe5, 0x52, 0x6b, + 0xf2, 0x29, 0x4d, 0x3f, 0x3e, + 0xb9, 0x5a, 0xa7, 0x73, 0x19, + 0xd3, 0xff, 0x56, 0x7b, 0xcf, + 0x36, 0x46, 0x07, 0x0c, 0x81, + 0x12, 0x33, 0x01, 0xca, 0xce, + 0xa9, 0x02, 0x20, 0xea, 0x48, + 0xae, 0x58, 0xf5, 0x54, 0x10, + 0x96, 0x3f, 0xa7, 0x03, 0xdb, + 0x56, 0xf0, 0xba, 0xb2, 0x70, + 0xb1, 0x08, 0x22, 0xc5, 0x1c, + 0x68, 0x02, 0x6a, 0x97, 0x5c, + 0x7d, 0xae, 0x11, 0x2e, 0x4f, + 0x01, + txscript.OP_DATA_65, + 0x04, 0x49, 0x45, 0x33, 0x18, + 0xbd, 0x5e, 0xcf, 0xea, 0x5f, + 0x86, 0x32, 0x8c, 0x6d, 0x8e, + 0xd4, 0x12, 0xb4, 0xde, 0x2c, + 0xab, 0xd7, 0xb8, 0x56, 0x51, + 0x2f, 0x8c, 0xb7, 0xfd, 0x25, + 0xf6, 0x03, 0xb0, 0x55, 0xc5, + 0xdf, 0xe6, 0x22, 0x4b, 0xc4, + 0xfd, 0xbb, 0x6a, 0x7a, 0xa0, + 0x58, 0xd7, 0x5d, 0xad, 0x92, + 0x99, 0x45, 0x4f, 0x62, 0x1a, + 0x95, 0xb4, 0xb0, 0x21, 0x0e, + 0xc4, 0x09, 0x2b, 0xe5, 0x27, + }, + Sequence: 4294967295, + }, + { + PreviousOutPoint: btcwire.OutPoint{ + Hash: btcwire.ShaHash([32]byte{ + 0x2a, 0xc7, 0xee, 0xf8, + 0xa9, 0x62, 0x2d, 0xda, + 0xec, 0x18, 0x3b, 0xba, + 0xa9, 0x92, 0xb0, 0x7a, + 0x70, 0x3b, 0x48, 0x86, + 0x27, 0x9c, 0x46, 0xac, + 0x25, 0xeb, 0x91, 0xec, + 0x4c, 0x86, 0xd2, 0x9c, + }), + Index: 1, + }, + SignatureScript: []byte{ + txscript.OP_DATA_71, + 0x30, 0x44, 0x02, 0x20, 0xc3, + 0x02, 0x3b, 0xed, 0x85, 0x0d, + 0x94, 0x27, 0x8e, 0x06, 0xd2, + 0x37, 0x92, 0x21, 0x55, 0x28, + 0xdd, 0xdb, 0x63, 0xa4, 0xb6, + 0x88, 0x33, 0x92, 0x06, 0xdd, + 0xf9, 0xee, 0x72, 0x97, 0xa3, + 0x08, 0x02, 0x20, 0x25, 0x00, + 0x42, 0x8b, 0x26, 0x36, 0x45, + 0x54, 0xcb, 0x11, 0xd3, 0x3e, + 0x85, 0x35, 0x23, 0x49, 0x65, + 0x82, 0x8e, 0x33, 0x6e, 0x1a, + 0x4a, 0x72, 0x73, 0xeb, 0x5b, + 0x8d, 0x1d, 0xd7, 0x02, 0xcc, + 0x01, + txscript.OP_DATA_65, + 0x04, 0x49, 0x5c, 0x8f, 0x66, + 0x90, 0x0d, 0xb7, 0x62, 0x69, + 0x0b, 0x54, 0x49, 0xa1, 0xf4, + 0xe7, 0xc2, 0xed, 0x1f, 0x4b, + 0x34, 0x70, 0xfd, 0x42, 0x79, + 0x68, 0xa1, 0x31, 0x76, 0x0c, + 0x25, 0xf9, 0x12, 0x63, 0xad, + 0x51, 0x73, 0x8e, 0x19, 0xb6, + 0x07, 0xf5, 0xcf, 0x5f, 0x94, + 0x27, 0x4a, 0x8b, 0xbc, 0x74, + 0xba, 0x4b, 0x56, 0x0c, 0xe0, + 0xb3, 0x08, 0x8f, 0x7f, 0x5c, + 0x5f, 0xcf, 0xd6, 0xa0, 0x4b, + }, + Sequence: 4294967295, + }, + }, + TxOut: []*btcwire.TxOut{ + { + Value: 630320000, + PkScript: []byte{ + txscript.OP_DUP, + txscript.OP_HASH160, + txscript.OP_DATA_20, + 0x43, 0xdc, 0x32, 0x1b, 0x66, + 0x00, 0x51, 0x1f, 0xe0, 0xa9, + 0x6a, 0x97, 0xc2, 0x59, 0x3a, + 0x90, 0x54, 0x29, 0x74, 0xd6, + txscript.OP_EQUALVERIFY, + txscript.OP_CHECKSIG, + }, + }, + { + Value: 100000181, + PkScript: []byte{ + txscript.OP_DUP, + txscript.OP_HASH160, + txscript.OP_DATA_20, + 0xa4, 0x05, 0xea, 0x18, 0x09, + 0x14, 0xa9, 0x11, 0xd0, 0xb8, + 0x07, 0x99, 0x19, 0x2b, 0x0b, + 0x84, 0xae, 0x80, 0x1e, 0xbd, + txscript.OP_EQUALVERIFY, + txscript.OP_CHECKSIG, + }, + }, + { + Value: 596516343, + PkScript: []byte{ + txscript.OP_DUP, + txscript.OP_HASH160, + txscript.OP_DATA_20, + 0x24, 0x56, 0x76, 0x45, 0x4f, + 0x6f, 0xff, 0x28, 0x88, 0x39, + 0x47, 0xea, 0x70, 0x23, 0x86, + 0x9b, 0x8a, 0x71, 0xa3, 0x05, + txscript.OP_EQUALVERIFY, + txscript.OP_CHECKSIG, + }, + }, + }, + LockTime: 0, + }, + // Test input 0 + pkScript: []byte{ + txscript.OP_DUP, + txscript.OP_HASH160, + txscript.OP_DATA_20, + 0xfd, 0xf6, 0xea, 0xe7, 0x10, + 0xa0, 0xc4, 0x49, 0x7a, 0x8d, + 0x0f, 0xd2, 0x9a, 0xf6, 0x6b, + 0xac, 0x94, 0xaf, 0x6c, 0x98, + txscript.OP_EQUALVERIFY, + txscript.OP_CHECKSIG, + }, + idx: 0, + canonicalSigs: true, + shouldFail: true, + nSigOps: 1, + scriptInfo: txscript.ScriptInfo{ + PkScriptClass: txscript.PubKeyHashTy, + NumInputs: 2, + ExpectedInputs: 2, + SigOps: 1, + }, + }, + + // tx 51bf528ecf3c161e7c021224197dbe84f9a8564212f6207baa014c01a1668e1e + // first instance of an AnyoneCanPay signature in the blockchain + { + name: "CheckSigHashAnyoneCanPay", + tx: &btcwire.MsgTx{ + Version: 1, + TxIn: []*btcwire.TxIn{ + { + PreviousOutPoint: btcwire.OutPoint{ + Hash: btcwire.ShaHash([32]byte{ + 0xf6, 0x04, 0x4c, 0x0a, + 0xd4, 0x85, 0xf6, 0x33, + 0xb4, 0x1f, 0x97, 0xd0, + 0xd7, 0x93, 0xeb, 0x28, + 0x37, 0xae, 0x40, 0xf7, + 0x38, 0xff, 0x6d, 0x5f, + 0x50, 0xfd, 0xfd, 0x10, + 0x52, 0x8c, 0x1d, 0x76, + }), + Index: 1, + }, + SignatureScript: []byte{ + txscript.OP_DATA_72, + 0x30, 0x45, 0x02, 0x20, 0x58, + 0x53, 0xc7, 0xf1, 0x39, 0x57, + 0x85, 0xbf, 0xab, 0xb0, 0x3c, + 0x57, 0xe9, 0x62, 0xeb, 0x07, + 0x6f, 0xf2, 0x4d, 0x8e, 0x4e, + 0x57, 0x3b, 0x04, 0xdb, 0x13, + 0xb4, 0x5e, 0xd3, 0xed, 0x6e, + 0xe2, 0x02, 0x21, 0x00, 0x9d, + 0xc8, 0x2a, 0xe4, 0x3b, 0xe9, + 0xd4, 0xb1, 0xfe, 0x28, 0x47, + 0x75, 0x4e, 0x1d, 0x36, 0xda, + 0xd4, 0x8b, 0xa8, 0x01, 0x81, + 0x7d, 0x48, 0x5d, 0xc5, 0x29, + 0xaf, 0xc5, 0x16, 0xc2, 0xdd, + 0xb4, 0x81, + txscript.OP_DATA_33, + 0x03, 0x05, 0x58, 0x49, 0x80, + 0x36, 0x7b, 0x32, 0x1f, 0xad, + 0x7f, 0x1c, 0x1f, 0x4d, 0x5d, + 0x72, 0x3d, 0x0a, 0xc8, 0x0c, + 0x1d, 0x80, 0xc8, 0xba, 0x12, + 0x34, 0x39, 0x65, 0xb4, 0x83, + 0x64, 0x53, 0x7a, + }, + Sequence: 4294967295, + }, + { + PreviousOutPoint: btcwire.OutPoint{ + Hash: btcwire.ShaHash([32]byte{ + 0x9c, 0x6a, 0xf0, 0xdf, + 0x66, 0x69, 0xbc, 0xde, + 0xd1, 0x9e, 0x31, 0x7e, + 0x25, 0xbe, 0xbc, 0x8c, + 0x78, 0xe4, 0x8d, 0xf8, + 0xae, 0x1f, 0xe0, 0x2a, + 0x7f, 0x03, 0x08, 0x18, + 0xe7, 0x1e, 0xcd, 0x40, + }), + Index: 1, + }, + SignatureScript: []byte{ + txscript.OP_DATA_73, + 0x30, 0x46, 0x02, 0x21, 0x00, + 0x82, 0x69, 0xc9, 0xd7, 0xba, + 0x0a, 0x7e, 0x73, 0x0d, 0xd1, + 0x6f, 0x40, 0x82, 0xd2, 0x9e, + 0x36, 0x84, 0xfb, 0x74, 0x63, + 0xba, 0x06, 0x4f, 0xd0, 0x93, + 0xaf, 0xc1, 0x70, 0xad, 0x6e, + 0x03, 0x88, 0x02, 0x21, 0x00, + 0xbc, 0x6d, 0x76, 0x37, 0x39, + 0x16, 0xa3, 0xff, 0x6e, 0xe4, + 0x1b, 0x2c, 0x75, 0x20, 0x01, + 0xfd, 0xa3, 0xc9, 0xe0, 0x48, + 0xbc, 0xff, 0x0d, 0x81, 0xd0, + 0x5b, 0x39, 0xff, 0x0f, 0x42, + 0x17, 0xb2, 0x81, + txscript.OP_DATA_33, + 0x03, 0xaa, 0xe3, 0x03, 0xd8, + 0x25, 0x42, 0x15, 0x45, 0xc5, + 0xbc, 0x7c, 0xcd, 0x5a, 0xc8, + 0x7d, 0xd5, 0xad, 0xd3, 0xbc, + 0xc3, 0xa4, 0x32, 0xba, 0x7a, + 0xa2, 0xf2, 0x66, 0x16, 0x99, + 0xf9, 0xf6, 0x59, + }, + Sequence: 4294967295, + }, + }, + TxOut: []*btcwire.TxOut{ + { + Value: 300000, + PkScript: []byte{ + txscript.OP_DUP, + txscript.OP_HASH160, + txscript.OP_DATA_20, + 0x5c, 0x11, 0xf9, 0x17, 0x88, + 0x3b, 0x92, 0x7e, 0xef, 0x77, + 0xdc, 0x57, 0x70, 0x7a, 0xeb, + 0x85, 0x3f, 0x6d, 0x38, 0x94, + txscript.OP_EQUALVERIFY, + txscript.OP_CHECKSIG, + }, + }, + }, + LockTime: 0, + }, + pkScript: []byte{ + txscript.OP_DUP, + txscript.OP_HASH160, + txscript.OP_DATA_20, + 0x85, 0x51, 0xe4, 0x8a, 0x53, 0xde, 0xcd, 0x1c, 0xfc, + 0x63, 0x07, 0x9a, 0x45, 0x81, 0xbc, 0xcc, 0xfa, 0xd1, + 0xa9, 0x3c, + txscript.OP_EQUALVERIFY, + txscript.OP_CHECKSIG, + }, + idx: 0, + bip16: true, // after threshold + nSigOps: 1, + scriptInfo: txscript.ScriptInfo{ + PkScriptClass: txscript.PubKeyHashTy, + NumInputs: 2, + ExpectedInputs: 2, + SigOps: 1, + }, + }, + // tx 6d36bc17e947ce00bb6f12f8e7a56a1585c5a36188ffa2b05e10b4743273a74b + // Uses OP_CODESEPARATOR and OP_CHECKMULTISIG + { + name: "CheckMultiSig", + tx: &btcwire.MsgTx{ + Version: 1, + TxIn: []*btcwire.TxIn{ + { + PreviousOutPoint: btcwire.OutPoint{ + Hash: btcwire.ShaHash([32]byte{ + 0x37, 0xb1, 0x7d, 0x76, + 0x38, 0x51, 0xcd, 0x1a, + 0xb0, 0x4a, 0x42, 0x44, + 0x63, 0xd4, 0x13, 0xc4, + 0xee, 0x5c, 0xf6, 0x13, + 0x04, 0xc7, 0xfd, 0x76, + 0x97, 0x7b, 0xea, 0x7f, + 0xce, 0x07, 0x57, 0x05, + }), + Index: 0, + }, + SignatureScript: []byte{ + txscript.OP_DATA_71, + 0x30, 0x44, 0x02, 0x20, 0x02, + 0xdb, 0xe4, 0xb5, 0xa2, 0xfb, + 0xb5, 0x21, 0xe4, 0xdc, 0x5f, + 0xbe, 0xc7, 0x5f, 0xd9, 0x60, + 0x65, 0x1a, 0x27, 0x54, 0xb0, + 0x3d, 0x08, 0x71, 0xb8, 0xc9, + 0x65, 0x46, 0x9b, 0xe5, 0x0f, + 0xa7, 0x02, 0x20, 0x6d, 0x97, + 0x42, 0x1f, 0xb7, 0xea, 0x93, + 0x59, 0xb6, 0x3e, 0x48, 0xc2, + 0x10, 0x82, 0x23, 0x28, 0x4b, + 0x9a, 0x71, 0x56, 0x0b, 0xd8, + 0x18, 0x24, 0x69, 0xb9, 0x03, + 0x92, 0x28, 0xd7, 0xb3, 0xd7, + 0x01, 0x21, 0x02, 0x95, 0xbf, + 0x72, 0x71, 0x11, 0xac, 0xde, + 0xab, 0x87, 0x78, 0x28, 0x4f, + 0x02, 0xb7, 0x68, 0xd1, 0xe2, + 0x1a, 0xcb, 0xcb, 0xae, 0x42, + }, + Sequence: 4294967295, + }, + { + PreviousOutPoint: btcwire.OutPoint{ + Hash: btcwire.ShaHash([32]byte{ + 0x37, 0xb1, 0x7d, 0x76, + 0x38, 0x51, 0xcd, 0x1a, + 0xb0, 0x4a, 0x42, 0x44, + 0x63, 0xd4, 0x13, 0xc4, + 0xee, 0x5c, 0xf6, 0x13, + 0x04, 0xc7, 0xfd, 0x76, + 0x97, 0x7b, 0xea, 0x7f, + 0xce, 0x07, 0x57, 0x05, + }), + Index: 1, + }, + SignatureScript: []uint8{ + txscript.OP_FALSE, + txscript.OP_DATA_72, + 0x30, 0x45, 0x02, 0x20, 0x10, + 0x6a, 0x3e, 0x4e, 0xf0, 0xb5, + 0x1b, 0x76, 0x4a, 0x28, 0x87, + 0x22, 0x62, 0xff, 0xef, 0x55, + 0x84, 0x65, 0x14, 0xda, 0xcb, + 0xdc, 0xbb, 0xdd, 0x65, 0x2c, + 0x84, 0x9d, 0x39, 0x5b, 0x43, + 0x84, 0x02, 0x21, 0x00, 0xe0, + 0x3a, 0xe5, 0x54, 0xc3, 0xcb, + 0xb4, 0x06, 0x00, 0xd3, 0x1d, + 0xd4, 0x6f, 0xc3, 0x3f, 0x25, + 0xe4, 0x7b, 0xf8, 0x52, 0x5b, + 0x1f, 0xe0, 0x72, 0x82, 0xe3, + 0xb6, 0xec, 0xb5, 0xf3, 0xbb, + 0x28, 0x01, + txscript.OP_CODESEPARATOR, + txscript.OP_TRUE, + txscript.OP_DATA_33, + 0x02, 0x32, 0xab, 0xdc, 0x89, + 0x3e, 0x7f, 0x06, 0x31, 0x36, + 0x4d, 0x7f, 0xd0, 0x1c, 0xb3, + 0x3d, 0x24, 0xda, 0x45, 0x32, + 0x9a, 0x00, 0x35, 0x7b, 0x3a, + 0x78, 0x86, 0x21, 0x1a, 0xb4, + 0x14, 0xd5, 0x5a, + txscript.OP_TRUE, + txscript.OP_CHECKMULTISIG, + }, + Sequence: 4294967295, + }, + }, + TxOut: []*btcwire.TxOut{ + { + Value: 4800000, + PkScript: []byte{ + txscript.OP_DUP, + txscript.OP_HASH160, + txscript.OP_DATA_20, + 0x0d, 0x77, 0x13, 0x64, 0x9f, + 0x9a, 0x06, 0x78, 0xf4, 0xe8, + 0x80, 0xb4, 0x0f, 0x86, 0xb9, + 0x32, 0x89, 0xd1, 0xbb, 0x27, + txscript.OP_EQUALVERIFY, + txscript.OP_CHECKSIG, + }, + }, + }, + LockTime: 0, + }, + // This is a very weird script... + pkScript: []byte{ + txscript.OP_DATA_20, + 0x2a, 0x9b, 0xc5, 0x44, 0x7d, 0x66, 0x4c, 0x1d, 0x01, + 0x41, 0x39, 0x2a, 0x84, 0x2d, 0x23, 0xdb, 0xa4, 0x5c, + 0x4f, 0x13, + txscript.OP_NOP2, txscript.OP_DROP, + }, + idx: 1, + bip16: false, + nSigOps: 0, // multisig is in the pkScript! + scriptInfoErr: txscript.ErrStackNonPushOnly, + }, + // same as previous but with one byte changed to make signature fail + { + name: "CheckMultiSig fail", + tx: &btcwire.MsgTx{ + Version: 1, + TxIn: []*btcwire.TxIn{ + { + PreviousOutPoint: btcwire.OutPoint{ + Hash: btcwire.ShaHash([32]byte{ + 0x37, 0xb1, 0x7d, 0x76, + 0x38, 0x51, 0xcd, 0x1a, + 0xb0, 0x4a, 0x42, 0x44, + 0x63, 0xd4, 0x13, 0xc4, + 0xee, 0x5c, 0xf6, 0x13, + 0x04, 0xc7, 0xfd, 0x76, + 0x97, 0x7b, 0xea, 0x7f, + 0xce, 0x07, 0x57, 0x05, + }), + Index: 0, + }, + SignatureScript: []byte{ + txscript.OP_DATA_71, + 0x30, 0x44, 0x02, 0x20, 0x02, + 0xdb, 0xe4, 0xb5, 0xa2, 0xfb, + 0xb5, 0x21, 0xe4, 0xdc, 0x5f, + 0xbe, 0xc7, 0x5f, 0xd9, 0x60, + 0x65, 0x1a, 0x27, 0x54, 0xb0, + 0x3d, 0x08, 0x71, 0xb8, 0xc9, + 0x65, 0x46, 0x9b, 0xe5, 0x0f, + 0xa7, 0x02, 0x20, 0x6d, 0x97, + 0x42, 0x1f, 0xb7, 0xea, 0x93, + 0x59, 0xb6, 0x3e, 0x48, 0xc2, + 0x10, 0x82, 0x23, 0x28, 0x4b, + 0x9a, 0x71, 0x56, 0x0b, 0xd8, + 0x18, 0x24, 0x69, 0xb9, 0x03, + 0x92, 0x28, 0xd7, 0xb3, 0xd7, + 0x01, 0x21, 0x02, 0x95, 0xbf, + 0x72, 0x71, 0x11, 0xac, 0xde, + 0xab, 0x87, 0x78, 0x28, 0x4f, + 0x02, 0xb7, 0x68, 0xd1, 0xe2, + 0x1a, 0xcb, 0xcb, 0xae, 0x42, + }, + Sequence: 4294967295, + }, + { + PreviousOutPoint: btcwire.OutPoint{ + Hash: btcwire.ShaHash([32]byte{ + 0x37, 0xb1, 0x7d, 0x76, + 0x38, 0x51, 0xcd, 0x1a, + 0xb0, 0x4a, 0x42, 0x44, + 0x63, 0xd4, 0x13, 0xc4, + 0xee, 0x5c, 0xf6, 0x13, + 0x04, 0xc7, 0xfd, 0x76, + 0x97, 0x7b, 0xea, 0x7f, + 0xce, 0x07, 0x57, 0x05, + }), + Index: 1, + }, + SignatureScript: []uint8{ + txscript.OP_FALSE, + txscript.OP_DATA_72, + 0x30, 0x45, 0x02, 0x20, 0x10, + 0x6a, 0x3e, 0x4e, 0xf0, 0xb5, + 0x1b, 0x76, 0x4a, 0x28, 0x87, + 0x22, 0x62, 0xff, 0xef, 0x55, + 0x84, 0x65, 0x14, 0xda, 0xcb, + 0xdc, 0xbb, 0xdd, 0x65, 0x2c, + 0x84, 0x9d, 0x39, 0x5b, 0x43, + 0x84, 0x02, 0x21, 0x00, 0xe0, + 0x3a, 0xe5, 0x54, 0xc3, 0xcb, + 0xb4, 0x06, 0x00, 0xd3, 0x1d, + 0xd4, 0x6f, 0xc3, 0x3f, 0x25, + 0xe4, 0x7b, 0xf8, 0x52, 0x5b, + 0x1f, 0xe0, 0x72, 0x82, 0xe3, + 0xb6, 0xec, 0xb5, 0xf3, 0xbb, + 0x28, 0x01, + txscript.OP_CODESEPARATOR, + txscript.OP_TRUE, + txscript.OP_DATA_33, + 0x02, 0x32, 0xab, 0xdc, 0x89, + 0x3e, 0x7f, 0x06, 0x31, 0x36, + 0x4d, 0x7f, 0xd0, 0x1c, 0xb3, + 0x3d, 0x24, 0xda, 0x45, 0x32, + 0x9a, 0x00, 0x35, 0x7b, 0x3a, + 0x78, 0x86, 0x21, 0x1a, 0xb4, + 0x14, 0xd5, 0x5a, + txscript.OP_TRUE, + txscript.OP_CHECKMULTISIG, + }, + Sequence: 4294967295, + }, + }, + TxOut: []*btcwire.TxOut{ + { + Value: 5800000, + PkScript: []byte{ + txscript.OP_DUP, + txscript.OP_HASH160, + txscript.OP_DATA_20, + 0x0d, 0x77, 0x13, 0x64, 0x9f, + 0x9a, 0x06, 0x78, 0xf4, 0xe8, + 0x80, 0xb4, 0x0f, 0x86, 0xb9, + 0x32, 0x89, 0xd1, 0xbb, 0x27, + txscript.OP_EQUALVERIFY, + txscript.OP_CHECKSIG, + }, + }, + }, + LockTime: 0, + }, + // This is a very weird script... + pkScript: []byte{ + txscript.OP_DATA_20, + 0x2a, 0x9b, 0xc5, 0x44, 0x7d, 0x66, 0x4c, 0x1d, 0x01, + 0x41, 0x39, 0x2a, 0x84, 0x2d, 0x23, 0xdb, 0xa4, 0x5c, + 0x4f, 0x13, + txscript.OP_NOP2, txscript.OP_DROP, + }, + idx: 1, + bip16: false, + err: txscript.ErrStackScriptFailed, + nSigOps: 0, // multisig is in the pkScript! + scriptInfoErr: txscript.ErrStackNonPushOnly, + }, + // taken from tx b2d93dfd0b2c1a380e55e76a8d9cb3075dec9f4474e9485be008c337fd62c1f7 + // on testnet + // multisig with zero required signatures + { + name: "CheckMultiSig zero required signatures", + tx: &btcwire.MsgTx{ + Version: 1, + TxIn: []*btcwire.TxIn{ + { + PreviousOutPoint: btcwire.OutPoint{ + Hash: btcwire.ShaHash([32]byte{ + 0x37, 0xb1, 0x7d, 0x76, + 0x38, 0x51, 0xcd, 0x1a, + 0xb0, 0x4a, 0x42, 0x44, + 0x63, 0xd4, 0x13, 0xc4, + 0xee, 0x5c, 0xf6, 0x13, + 0x04, 0xc7, 0xfd, 0x76, + 0x97, 0x7b, 0xea, 0x7f, + 0xce, 0x07, 0x57, 0x05, + }), + Index: 0, + }, + SignatureScript: []byte{ + txscript.OP_0, + txscript.OP_DATA_37, + txscript.OP_0, + txscript.OP_DATA_33, + 0x02, 0x4a, 0xb3, 0x3c, 0x3a, + 0x54, 0x7a, 0x37, 0x29, 0x3e, + 0xb8, 0x75, 0xb4, 0xbb, 0xdb, + 0xd4, 0x73, 0xe9, 0xd4, 0xba, + 0xfd, 0xf3, 0x56, 0x87, 0xe7, + 0x97, 0x44, 0xdc, 0xd7, 0x0f, + 0x6e, 0x4d, 0xe2, + txscript.OP_1, + txscript.OP_CHECKMULTISIG, + }, + Sequence: 4294967295, + }, + }, + TxOut: []*btcwire.TxOut{}, + LockTime: 0, + }, + pkScript: []byte{ + txscript.OP_HASH160, + txscript.OP_DATA_20, + 0x2c, 0x6b, 0x10, 0x7f, 0xdf, 0x10, 0x6f, 0x22, 0x6f, + 0x3f, 0xa3, 0x27, 0xba, 0x36, 0xd6, 0xe3, 0xca, 0xc7, + 0x3d, 0xf0, + txscript.OP_EQUAL, + }, + idx: 0, + bip16: true, + nSigOps: 1, + scriptInfo: txscript.ScriptInfo{ + PkScriptClass: txscript.ScriptHashTy, + NumInputs: 2, + ExpectedInputs: 2, + SigOps: 1, + }, + }, + // tx e5779b9e78f9650debc2893fd9636d827b26b4ddfa6a8172fe8708c924f5c39d + // First P2SH transaction in the blockchain + { + name: "P2SH", + tx: &btcwire.MsgTx{ + Version: 1, + TxIn: []*btcwire.TxIn{ + { + PreviousOutPoint: btcwire.OutPoint{ + Hash: btcwire.ShaHash([32]byte{ + 0x6d, 0x58, 0xf8, 0xa3, + 0xaa, 0x43, 0x0b, 0x84, + 0x78, 0x52, 0x3a, 0x65, + 0xc2, 0x03, 0xa2, 0x7b, + 0xb8, 0x81, 0x17, 0x8c, + 0xb1, 0x23, 0x13, 0xaf, + 0xde, 0x29, 0xf9, 0x2e, + 0xd7, 0x56, 0xaa, 0x7e, + }), + Index: 0, + }, + SignatureScript: []byte{ + txscript.OP_DATA_2, + // OP_3 OP_7 + 0x53, 0x57, + }, + Sequence: 4294967295, + }, + }, + TxOut: []*btcwire.TxOut{ + { + Value: 1000000, + PkScript: []byte{ + txscript.OP_DUP, + txscript.OP_HASH160, + txscript.OP_DATA_20, + 0x5b, 0x69, 0xd8, 0xb9, 0xdf, + 0xa6, 0xe4, 0x12, 0x26, 0x47, + 0xe1, 0x79, 0x4e, 0xaa, 0x3b, + 0xfc, 0x11, 0x1f, 0x70, 0xef, + txscript.OP_EQUALVERIFY, + txscript.OP_CHECKSIG, + }, + }, + }, + LockTime: 0, + }, + pkScript: []byte{ + txscript.OP_HASH160, + txscript.OP_DATA_20, + 0x43, 0x3e, 0xc2, 0xac, 0x1f, 0xfa, 0x1b, 0x7b, 0x7d, + 0x02, 0x7f, 0x56, 0x45, 0x29, 0xc5, 0x71, 0x97, 0xf9, + 0xae, 0x88, + txscript.OP_EQUAL, + }, + idx: 0, + bip16: true, + nSigOps: 0, // no signature ops in the pushed script. + scriptInfo: txscript.ScriptInfo{ + PkScriptClass: txscript.ScriptHashTy, + NumInputs: 1, + ExpectedInputs: -1, // p2sh script is non standard + SigOps: 0, + }, + }, + // next few tests are modified versions of previous to hit p2sh error + // cases. + { + // sigscript changed so that pkscript hash will not match. + name: "P2SH - bad hash", + tx: &btcwire.MsgTx{ + Version: 1, + TxIn: []*btcwire.TxIn{ + { + PreviousOutPoint: btcwire.OutPoint{ + Hash: btcwire.ShaHash([32]byte{ + 0x6d, 0x58, 0xf8, 0xa3, + 0xaa, 0x43, 0x0b, 0x84, + 0x78, 0x52, 0x3a, 0x65, + 0xc2, 0x03, 0xa2, 0x7b, + 0xb8, 0x81, 0x17, 0x8c, + 0xb1, 0x23, 0x13, 0xaf, + 0xde, 0x29, 0xf9, 0x2e, + 0xd7, 0x56, 0xaa, 0x7e, + }), + Index: 0, + }, + SignatureScript: []byte{ + txscript.OP_DATA_2, + // OP_3 OP_8 + 0x53, 0x58, + }, + Sequence: 4294967295, + }, + }, + TxOut: []*btcwire.TxOut{ + { + Value: 1000000, + PkScript: []byte{ + txscript.OP_DUP, + txscript.OP_HASH160, + txscript.OP_DATA_20, + 0x5b, 0x69, 0xd8, 0xb9, 0xdf, + 0xa6, 0xe4, 0x12, 0x26, 0x47, + 0xe1, 0x79, 0x4e, 0xaa, 0x3b, + 0xfc, 0x11, 0x1f, 0x70, 0xef, + txscript.OP_EQUALVERIFY, + txscript.OP_CHECKSIG, + }, + }, + }, + LockTime: 0, + }, + pkScript: []byte{ + txscript.OP_HASH160, + txscript.OP_DATA_20, + 0x43, 0x3e, 0xc2, 0xac, 0x1f, 0xfa, 0x1b, 0x7b, 0x7d, + 0x02, 0x7f, 0x56, 0x45, 0x29, 0xc5, 0x71, 0x97, 0xf9, + 0xae, 0x88, + txscript.OP_EQUAL, + }, + idx: 0, + err: txscript.ErrStackScriptFailed, + bip16: true, + nSigOps: 0, // no signature ops in the pushed script. + scriptInfo: txscript.ScriptInfo{ + PkScriptClass: txscript.ScriptHashTy, + NumInputs: 1, + ExpectedInputs: -1, // p2sh script is non standard + SigOps: 0, + }, + }, + { + // sigscript changed so that pkscript hash will not match. + name: "P2SH - doesn't parse", + tx: &btcwire.MsgTx{ + Version: 1, + TxIn: []*btcwire.TxIn{ + { + PreviousOutPoint: btcwire.OutPoint{ + Hash: btcwire.ShaHash([32]byte{ + 0x6d, 0x58, 0xf8, 0xa3, + 0xaa, 0x43, 0x0b, 0x84, + 0x78, 0x52, 0x3a, 0x65, + 0xc2, 0x03, 0xa2, 0x7b, + 0xb8, 0x81, 0x17, 0x8c, + 0xb1, 0x23, 0x13, 0xaf, + 0xde, 0x29, 0xf9, 0x2e, + 0xd7, 0x56, 0xaa, 0x7e, + }), + Index: 0, + }, + SignatureScript: []byte{ + txscript.OP_DATA_2, + // pushed script. + txscript.OP_DATA_2, 0x1, + }, + Sequence: 4294967295, + }, + }, + TxOut: []*btcwire.TxOut{ + { + Value: 1000000, + PkScript: []byte{ + txscript.OP_DUP, + txscript.OP_HASH160, + txscript.OP_DATA_20, + 0x5b, 0x69, 0xd8, 0xb9, 0xdf, + 0xa6, 0xe4, 0x12, 0x26, 0x47, + 0xe1, 0x79, 0x4e, 0xaa, 0x3b, + 0xfc, 0x11, 0x1f, 0x70, 0xef, + txscript.OP_EQUALVERIFY, + txscript.OP_CHECKSIG, + }, + }, + }, + LockTime: 0, + }, + pkScript: []byte{ + txscript.OP_HASH160, + txscript.OP_DATA_20, + 0xd4, 0x8c, 0xe8, 0x6c, 0x69, 0x8f, 0x24, 0x68, 0x29, + 0x92, 0x1b, 0xa9, 0xfb, 0x2a, 0x84, 0x4a, 0xe2, 0xad, + 0xba, 0x67, + txscript.OP_EQUAL, + }, + idx: 0, + err: txscript.ErrStackShortScript, + bip16: true, + scriptInfoErr: txscript.ErrStackShortScript, + }, + { + // sigscript changed so to be non pushonly. + name: "P2SH - non pushonly", + tx: &btcwire.MsgTx{ + Version: 1, + TxIn: []*btcwire.TxIn{ + { + PreviousOutPoint: btcwire.OutPoint{ + Hash: btcwire.ShaHash([32]byte{ + 0x6d, 0x58, 0xf8, 0xa3, + 0xaa, 0x43, 0x0b, 0x84, + 0x78, 0x52, 0x3a, 0x65, + 0xc2, 0x03, 0xa2, 0x7b, + 0xb8, 0x81, 0x17, 0x8c, + 0xb1, 0x23, 0x13, 0xaf, + 0xde, 0x29, 0xf9, 0x2e, + 0xd7, 0x56, 0xaa, 0x7e, + }), + Index: 0, + }, + // doesn't have to match signature. + // will never run. + SignatureScript: []byte{ + + txscript.OP_DATA_2, + // pushed script. + txscript.OP_DATA_1, 0x1, + txscript.OP_DUP, + }, + Sequence: 4294967295, + }, + }, + TxOut: []*btcwire.TxOut{ + { + Value: 1000000, + PkScript: []byte{ + txscript.OP_DUP, + txscript.OP_HASH160, + txscript.OP_DATA_20, + 0x5b, 0x69, 0xd8, 0xb9, 0xdf, + 0xa6, 0xe4, 0x12, 0x26, 0x47, + 0xe1, 0x79, 0x4e, 0xaa, 0x3b, + 0xfc, 0x11, 0x1f, 0x70, 0xef, + txscript.OP_EQUALVERIFY, + txscript.OP_CHECKSIG, + }, + }, + }, + LockTime: 0, + }, + pkScript: []byte{ + txscript.OP_HASH160, + txscript.OP_DATA_20, + 0x43, 0x3e, 0xc2, 0xac, 0x1f, 0xfa, 0x1b, 0x7b, 0x7d, + 0x02, 0x7f, 0x56, 0x45, 0x29, 0xc5, 0x71, 0x97, 0xf9, + 0xae, 0x88, + txscript.OP_EQUAL, + }, + idx: 0, + parseErr: txscript.ErrStackP2SHNonPushOnly, + bip16: true, + nSigOps: 0, // no signature ops in the pushed script. + scriptInfoErr: txscript.ErrStackNonPushOnly, + }, + { + // sigscript changed so to be non pushonly. + name: "empty pkScript", + tx: &btcwire.MsgTx{ + Version: 1, + TxIn: []*btcwire.TxIn{ + { + PreviousOutPoint: btcwire.OutPoint{ + Hash: btcwire.ShaHash([32]byte{ + 0x6d, 0x58, 0xf8, 0xa3, + 0xaa, 0x43, 0x0b, 0x84, + 0x78, 0x52, 0x3a, 0x65, + 0xc2, 0x03, 0xa2, 0x7b, + 0xb8, 0x81, 0x17, 0x8c, + 0xb1, 0x23, 0x13, 0xaf, + 0xde, 0x29, 0xf9, 0x2e, + 0xd7, 0x56, 0xaa, 0x7e, + }), + Index: 0, + }, + // doesn't have to match signature. + // will never run. + SignatureScript: []byte{ + txscript.OP_TRUE, + }, + Sequence: 4294967295, + }, + }, + TxOut: []*btcwire.TxOut{ + { + Value: 1000000, + PkScript: []byte{ + txscript.OP_DUP, + txscript.OP_HASH160, + txscript.OP_DATA_20, + 0x5b, 0x69, 0xd8, 0xb9, 0xdf, + 0xa6, 0xe4, 0x12, 0x26, 0x47, + 0xe1, 0x79, 0x4e, 0xaa, 0x3b, + 0xfc, 0x11, 0x1f, 0x70, 0xef, + txscript.OP_EQUALVERIFY, + txscript.OP_CHECKSIG, + }, + }, + }, + LockTime: 0, + }, + pkScript: []byte{}, + idx: 0, + bip16: true, + nSigOps: 0, // no signature ops in the pushed script. + scriptInfo: txscript.ScriptInfo{ + PkScriptClass: txscript.NonStandardTy, + NumInputs: 1, + ExpectedInputs: -1, + SigOps: 0, + }, + }, +} + +// Test a number of tx from the blockchain to test otherwise difficult to test +// opcodes (i.e. those that involve signatures). Being from the blockchain, +// these transactions are known good. +// TODO(oga) For signatures we currently do not test SigHashSingle because +// nothing in the blockchain that we have yet seen uses them, making it hard +// to confirm we implemented the spec correctly. +func testTx(t *testing.T, test txTest) { + var flags txscript.ScriptFlags + if test.bip16 { + flags |= txscript.ScriptBip16 + } + if test.canonicalSigs { + flags |= txscript.ScriptCanonicalSignatures + } + engine, err := txscript.NewScript( + test.tx.TxIn[test.idx].SignatureScript, test.pkScript, + test.idx, test.tx, flags) + if err != nil { + if err != test.parseErr { + t.Errorf("Failed to parse %s: got \"%v\" expected "+ + "\"%v\"", test.name, err, test.parseErr) + } + return + } + if test.parseErr != nil { + t.Errorf("%s: parse succeeded when expecting \"%v\"", test.name, + test.parseErr) + } + + err = engine.Execute() + if err != nil { + // failed means no specified error + if test.shouldFail == true { + return + } + if err != test.err { + t.Errorf("Failed to validate %s tx: %v expected %v", + test.name, err, test.err) + } + return + } + if test.err != nil || test.shouldFail == true { + t.Errorf("%s: expected failure: %v, succeeded", test.name, + test.err) + } +} + +func TestTX(t *testing.T) { + t.Parallel() + + for i := range txTests { + testTx(t, txTests[i]) + } +} + +func TestGetPreciseSignOps(t *testing.T) { + t.Parallel() + + // First we go over the range of tests in testTx and count the sigops in + // them. + for _, test := range txTests { + count := txscript.GetPreciseSigOpCount( + test.tx.TxIn[test.idx].SignatureScript, test.pkScript, + test.bip16) + if count != test.nSigOps { + t.Errorf("%s: expected count of %d, got %d", test.name, + test.nSigOps, count) + + } + } + + // Now we go over a number of tests to hit the more awkward error + // conditions in the P2SH cases.. + + type psocTest struct { + name string + scriptSig []byte + nSigOps int + err error + } + psocTests := []psocTest{ + { + name: "scriptSig doesn't parse", + scriptSig: []byte{txscript.OP_PUSHDATA1, 2}, + err: txscript.ErrStackShortScript, + }, + { + name: "scriptSig isn't push only", + scriptSig: []byte{txscript.OP_1, txscript.OP_DUP}, + nSigOps: 0, + }, + { + name: "scriptSig length 0", + scriptSig: []byte{}, + nSigOps: 0, + }, + { + name: "No script at the end", + // No script at end but still push only. + scriptSig: []byte{txscript.OP_1, txscript.OP_1}, + nSigOps: 0, + }, + // pushed script doesn't parse. + { + name: "pushed script doesn't parse", + scriptSig: []byte{txscript.OP_DATA_2, + txscript.OP_PUSHDATA1, 2}, + err: txscript.ErrStackShortScript, + }, + } + // The signature in the p2sh script is nonsensical for the tests since + // this script will never be executed. What matters is that it matches + // the right pattern. + pkScript := []byte{ + txscript.OP_HASH160, + txscript.OP_DATA_20, + 0x43, 0x3e, 0xc2, 0xac, 0x1f, 0xfa, 0x1b, 0x7b, 0x7d, + 0x02, 0x7f, 0x56, 0x45, 0x29, 0xc5, 0x71, 0x97, 0xf9, + 0xae, 0x88, + txscript.OP_EQUAL, + } + for _, test := range psocTests { + count := txscript.GetPreciseSigOpCount( + test.scriptSig, pkScript, true) + if count != test.nSigOps { + t.Errorf("%s: expected count of %d, got %d", test.name, + test.nSigOps, count) + + } + } +} + +type scriptInfoTest struct { + name string + sigScript []byte + pkScript []byte + bip16 bool + scriptInfo txscript.ScriptInfo + scriptInfoErr error +} + +func TestScriptInfo(t *testing.T) { + t.Parallel() + + for _, test := range txTests { + si, err := txscript.CalcScriptInfo( + test.tx.TxIn[test.idx].SignatureScript, + test.pkScript, test.bip16) + if err != nil { + if err != test.scriptInfoErr { + t.Errorf("scriptinfo test \"%s\": got \"%v\""+ + "expected \"%v\"", test.name, err, + test.scriptInfoErr) + } + continue + } + if test.scriptInfoErr != nil { + t.Errorf("%s: succeeded when expecting \"%v\"", + test.name, test.scriptInfoErr) + continue + } + if *si != test.scriptInfo { + t.Errorf("%s: scriptinfo doesn't match expected. "+ + "got: \"%v\" expected \"%v\"", test.name, + *si, test.scriptInfo) + continue + } + } + + extraTests := []scriptInfoTest{ + { + // Invented scripts, the hashes do not match + name: "pkscript doesn't parse", + sigScript: []byte{txscript.OP_TRUE, + txscript.OP_DATA_1, 81, + txscript.OP_DATA_8, + txscript.OP_2DUP, txscript.OP_EQUAL, + txscript.OP_NOT, txscript.OP_VERIFY, + txscript.OP_ABS, txscript.OP_SWAP, + txscript.OP_ABS, txscript.OP_EQUAL, + }, + // truncated version of test below: + pkScript: []byte{txscript.OP_HASH160, + txscript.OP_DATA_20, + 0xfe, 0x44, 0x10, 0x65, 0xb6, 0x53, 0x22, 0x31, + 0xde, 0x2f, 0xac, 0x56, 0x31, 0x52, 0x20, 0x5e, + 0xc4, 0xf5, 0x9c, + }, + bip16: true, + scriptInfoErr: txscript.ErrStackShortScript, + }, + { + name: "sigScript doesn't parse", + // Truncated version of p2sh script below. + sigScript: []byte{txscript.OP_TRUE, + txscript.OP_DATA_1, 81, + txscript.OP_DATA_8, + txscript.OP_2DUP, txscript.OP_EQUAL, + txscript.OP_NOT, txscript.OP_VERIFY, + txscript.OP_ABS, txscript.OP_SWAP, + txscript.OP_ABS, + }, + pkScript: []byte{txscript.OP_HASH160, + txscript.OP_DATA_20, + 0xfe, 0x44, 0x10, 0x65, 0xb6, 0x53, 0x22, 0x31, + 0xde, 0x2f, 0xac, 0x56, 0x31, 0x52, 0x20, 0x5e, + 0xc4, 0xf5, 0x9c, 0x74, txscript.OP_EQUAL, + }, + bip16: true, + scriptInfoErr: txscript.ErrStackShortScript, + }, + { + // Invented scripts, the hashes do not match + name: "p2sh standard script", + sigScript: []byte{txscript.OP_TRUE, + txscript.OP_DATA_1, 81, + txscript.OP_DATA_25, + txscript.OP_DUP, txscript.OP_HASH160, + txscript.OP_DATA_20, 0x1, 0x2, 0x3, 0x4, 0x5, + 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, + 0xf, 0x10, 0x11, 0x12, 0x13, 0x14, + txscript.OP_EQUALVERIFY, txscript.OP_CHECKSIG, + }, + pkScript: []byte{txscript.OP_HASH160, + txscript.OP_DATA_20, + 0xfe, 0x44, 0x10, 0x65, 0xb6, 0x53, 0x22, 0x31, + 0xde, 0x2f, 0xac, 0x56, 0x31, 0x52, 0x20, 0x5e, + 0xc4, 0xf5, 0x9c, 0x74, txscript.OP_EQUAL, + }, + bip16: true, + scriptInfo: txscript.ScriptInfo{ + PkScriptClass: txscript.ScriptHashTy, + NumInputs: 3, + ExpectedInputs: 3, // nonstandard p2sh. + SigOps: 1, + }, + }, + { + // from 567a53d1ce19ce3d07711885168484439965501536d0d0294c5d46d46c10e53b + // from the blockchain. + name: "p2sh nonstandard script", + sigScript: []byte{txscript.OP_TRUE, + txscript.OP_DATA_1, 81, + txscript.OP_DATA_8, + txscript.OP_2DUP, txscript.OP_EQUAL, + txscript.OP_NOT, txscript.OP_VERIFY, + txscript.OP_ABS, txscript.OP_SWAP, + txscript.OP_ABS, txscript.OP_EQUAL, + }, + pkScript: []byte{txscript.OP_HASH160, + txscript.OP_DATA_20, + 0xfe, 0x44, 0x10, 0x65, 0xb6, 0x53, 0x22, 0x31, + 0xde, 0x2f, 0xac, 0x56, 0x31, 0x52, 0x20, 0x5e, + 0xc4, 0xf5, 0x9c, 0x74, txscript.OP_EQUAL, + }, + bip16: true, + scriptInfo: txscript.ScriptInfo{ + PkScriptClass: txscript.ScriptHashTy, + NumInputs: 3, + ExpectedInputs: -1, // nonstandard p2sh. + SigOps: 0, + }, + }, + { + // Script is invented, numbers all fake. + name: "multisig script", + sigScript: []byte{txscript.OP_TRUE, + txscript.OP_TRUE, txscript.OP_TRUE, + txscript.OP_0, // Extra arg for OP_CHECKMULTISIG bug + }, + pkScript: []byte{ + txscript.OP_3, txscript.OP_DATA_33, + 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, + 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, + 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, + 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, + txscript.OP_DATA_33, + 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, + 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, + 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, + 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, + txscript.OP_DATA_33, + 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, + 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, + 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, + 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, + txscript.OP_3, txscript.OP_CHECKMULTISIG, + }, + bip16: true, + scriptInfo: txscript.ScriptInfo{ + PkScriptClass: txscript.MultiSigTy, + NumInputs: 4, + ExpectedInputs: 4, + SigOps: 3, + }, + }, + } + + for _, test := range extraTests { + si, err := txscript.CalcScriptInfo(test.sigScript, + test.pkScript, test.bip16) + if err != nil { + if err != test.scriptInfoErr { + t.Errorf("scriptinfo test \"%s\": got \"%v\""+ + "expected \"%v\"", test.name, err, + test.scriptInfoErr) + } + continue + } + if test.scriptInfoErr != nil { + t.Errorf("%s: succeeded when expecting \"%v\"", + test.name, test.scriptInfoErr) + continue + } + if *si != test.scriptInfo { + t.Errorf("%s: scriptinfo doesn't match expected. "+ + "got: \"%v\" expected \"%v\"", test.name, + *si, test.scriptInfo) + continue + } + } + +} + +type removeOpcodeTest struct { + name string + before []byte + remove byte + err error + after []byte +} + +var removeOpcodeTests = []removeOpcodeTest{ + // Nothing to remove. + { + name: "nothing to remove", + before: []byte{txscript.OP_NOP}, + remove: txscript.OP_CODESEPARATOR, + after: []byte{txscript.OP_NOP}, + }, + // Test basic opcode removal + { + name: "codeseparator 1", + before: []byte{txscript.OP_NOP, txscript.OP_CODESEPARATOR, + txscript.OP_TRUE}, + remove: txscript.OP_CODESEPARATOR, + after: []byte{txscript.OP_NOP, txscript.OP_TRUE}, + }, + // The opcode in question is actually part of the data in a previous + // opcode + { + name: "codeseparator by coincidence", + before: []byte{txscript.OP_NOP, txscript.OP_DATA_1, txscript.OP_CODESEPARATOR, + txscript.OP_TRUE}, + remove: txscript.OP_CODESEPARATOR, + after: []byte{txscript.OP_NOP, txscript.OP_DATA_1, txscript.OP_CODESEPARATOR, + txscript.OP_TRUE}, + }, + { + name: "invalid opcode", + before: []byte{txscript.OP_UNKNOWN186}, + remove: txscript.OP_CODESEPARATOR, + after: []byte{txscript.OP_UNKNOWN186}, + }, + { + name: "invalid length (insruction)", + before: []byte{txscript.OP_PUSHDATA1}, + remove: txscript.OP_CODESEPARATOR, + err: txscript.ErrStackShortScript, + }, + { + name: "invalid length (data)", + before: []byte{txscript.OP_PUSHDATA1, 255, 254}, + remove: txscript.OP_CODESEPARATOR, + err: txscript.ErrStackShortScript, + }, +} + +func testRemoveOpcode(t *testing.T, test *removeOpcodeTest) { + result, err := txscript.TstRemoveOpcode(test.before, test.remove) + if test.err != nil { + if err != test.err { + t.Errorf("%s: got unexpected error. exp: \"%v\" "+ + "got: \"%v\"", test.name, test.err, err) + } + return + } + if err != nil { + t.Errorf("%s: unexpected failure: \"%v\"", test.name, err) + return + } + if !bytes.Equal(test.after, result) { + t.Errorf("%s: value does not equal expected: exp: \"%v\""+ + " got: \"%v\"", test.name, test.after, result) + } +} + +func TestRemoveOpcodes(t *testing.T) { + t.Parallel() + + for i := range removeOpcodeTests { + testRemoveOpcode(t, &removeOpcodeTests[i]) + } +} + +type removeOpcodeByDataTest struct { + name string + before []byte + remove []byte + err error + after []byte +} + +var removeOpcodeByDataTests = []removeOpcodeByDataTest{ + { + name: "nothing to do", + before: []byte{txscript.OP_NOP}, + remove: []byte{1, 2, 3, 4}, + after: []byte{txscript.OP_NOP}, + }, + { + name: "simple case", + before: []byte{txscript.OP_DATA_4, 1, 2, 3, 4}, + remove: []byte{1, 2, 3, 4}, + after: []byte{}, + }, + { + name: "simple case (miss)", + before: []byte{txscript.OP_DATA_4, 1, 2, 3, 4}, + remove: []byte{1, 2, 3, 5}, + after: []byte{txscript.OP_DATA_4, 1, 2, 3, 4}, + }, + { + // padded to keep it canonical. + name: "simple case (pushdata1)", + before: append(append([]byte{txscript.OP_PUSHDATA1, 76}, + bytes.Repeat([]byte{0}, 72)...), []byte{1, 2, 3, 4}...), + remove: []byte{1, 2, 3, 4}, + after: []byte{}, + }, + { + name: "simple case (pushdata1 miss)", + before: append(append([]byte{txscript.OP_PUSHDATA1, 76}, + bytes.Repeat([]byte{0}, 72)...), []byte{1, 2, 3, 4}...), + remove: []byte{1, 2, 3, 5}, + after: append(append([]byte{txscript.OP_PUSHDATA1, 76}, + bytes.Repeat([]byte{0}, 72)...), []byte{1, 2, 3, 4}...), + }, + { + name: "simple case (pushdata1 miss noncanonical)", + before: []byte{txscript.OP_PUSHDATA1, 4, 1, 2, 3, 4}, + remove: []byte{1, 2, 3, 4}, + after: []byte{txscript.OP_PUSHDATA1, 4, 1, 2, 3, 4}, + }, + { + name: "simple case (pushdata2)", + before: append(append([]byte{txscript.OP_PUSHDATA2, 0, 1}, + bytes.Repeat([]byte{0}, 252)...), []byte{1, 2, 3, 4}...), + remove: []byte{1, 2, 3, 4}, + after: []byte{}, + }, + { + name: "simple case (pushdata2 miss)", + before: append(append([]byte{txscript.OP_PUSHDATA2, 0, 1}, + bytes.Repeat([]byte{0}, 252)...), []byte{1, 2, 3, 4}...), + remove: []byte{1, 2, 3, 4, 5}, + after: append(append([]byte{txscript.OP_PUSHDATA2, 0, 1}, + bytes.Repeat([]byte{0}, 252)...), []byte{1, 2, 3, 4}...), + }, + { + name: "simple case (pushdata2 miss noncanonical)", + before: []byte{txscript.OP_PUSHDATA2, 4, 0, 1, 2, 3, 4}, + remove: []byte{1, 2, 3, 4}, + after: []byte{txscript.OP_PUSHDATA2, 4, 0, 1, 2, 3, 4}, + }, + { + // This is padded to make the push canonical. + name: "simple case (pushdata4)", + before: append(append([]byte{txscript.OP_PUSHDATA4, 0, 0, 1, 0}, + bytes.Repeat([]byte{0}, 65532)...), []byte{1, 2, 3, 4}...), + remove: []byte{1, 2, 3, 4}, + after: []byte{}, + }, + { + name: "simple case (pushdata4 miss noncanonical)", + before: []byte{txscript.OP_PUSHDATA4, 4, 0, 0, 0, 1, 2, 3, 4}, + remove: []byte{1, 2, 3, 4}, + after: []byte{txscript.OP_PUSHDATA4, 4, 0, 0, 0, 1, 2, 3, 4}, + }, + { + // This is padded to make the push canonical. + name: "simple case (pushdata4 miss)", + before: append(append([]byte{txscript.OP_PUSHDATA4, 0, 0, 1, 0}, + bytes.Repeat([]byte{0}, 65532)...), []byte{1, 2, 3, 4}...), + remove: []byte{1, 2, 3, 4, 5}, + after: append(append([]byte{txscript.OP_PUSHDATA4, 0, 0, 1, 0}, + bytes.Repeat([]byte{0}, 65532)...), []byte{1, 2, 3, 4}...), + }, + { + name: "invalid opcode ", + before: []byte{txscript.OP_UNKNOWN187}, + remove: []byte{1, 2, 3, 4}, + after: []byte{txscript.OP_UNKNOWN187}, + }, + { + name: "invalid length (instruction)", + before: []byte{txscript.OP_PUSHDATA1}, + remove: []byte{1, 2, 3, 4}, + err: txscript.ErrStackShortScript, + }, + { + name: "invalid length (data)", + before: []byte{txscript.OP_PUSHDATA1, 255, 254}, + remove: []byte{1, 2, 3, 4}, + err: txscript.ErrStackShortScript, + }, +} + +func testRemoveOpcodeByData(t *testing.T, test *removeOpcodeByDataTest) { + result, err := txscript.TstRemoveOpcodeByData(test.before, + test.remove) + if test.err != nil { + if err != test.err { + t.Errorf("%s: got unexpected error. exp: \"%v\" "+ + "got: \"%v\"", test.name, test.err, err) + } + return + } + if err != nil { + t.Errorf("%s: unexpected failure: \"%v\"", test.name, err) + return + } + if !bytes.Equal(test.after, result) { + t.Errorf("%s: value does not equal expected: exp: \"%v\""+ + " got: \"%v\"", test.name, test.after, result) + } +} +func TestRemoveOpcodeByDatas(t *testing.T) { + t.Parallel() + + for i := range removeOpcodeByDataTests { + testRemoveOpcodeByData(t, &removeOpcodeByDataTests[i]) + } +} + +// Tests for the script type logic + +type scriptTypeTest struct { + name string + script []byte + scripttype txscript.ScriptClass +} + +var scriptTypeTests = []scriptTypeTest{ + // tx 0437cd7f8525ceed2324359c2d0ba26006d92d85. + { + name: "Pay Pubkey", + script: []byte{ + txscript.OP_DATA_65, + 0x04, 0x11, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a, 0x01, + 0x6b, 0x49, 0x84, 0x0f, 0x8c, 0x53, 0xbc, 0x1e, 0xb6, + 0x8a, 0x38, 0x2e, 0x97, 0xb1, 0x48, 0x2e, 0xca, 0xd7, + 0xb1, 0x48, 0xa6, 0x90, 0x9a, 0x5c, 0xb2, 0xe0, 0xea, + 0xdd, 0xfb, 0x84, 0xcc, 0xf9, 0x74, 0x44, 0x64, 0xf8, + 0x2e, 0x16, 0x0b, 0xfa, 0x9b, 0x8b, 0x64, 0xf9, 0xd4, + 0xc0, 0x3f, 0x99, 0x9b, 0x86, 0x43, 0xf6, 0x56, 0xb4, + 0x12, 0xa3, + txscript.OP_CHECKSIG, + }, + scripttype: txscript.PubKeyTy, + }, + // tx 599e47a8114fe098103663029548811d2651991b62397e057f0c863c2bc9f9ea + { + name: "Pay PubkeyHash", + script: []byte{ + txscript.OP_DUP, + txscript.OP_HASH160, + txscript.OP_DATA_20, + 0x66, 0x0d, 0x4e, 0xf3, 0xa7, 0x43, 0xe3, 0xe6, 0x96, + 0xad, 0x99, 0x03, 0x64, 0xe5, 0x55, 0xc2, 0x71, 0xad, + 0x50, 0x4b, + txscript.OP_EQUALVERIFY, + txscript.OP_CHECKSIG, + }, + scripttype: txscript.PubKeyHashTy, + }, + // part of tx 6d36bc17e947ce00bb6f12f8e7a56a1585c5a36188ffa2b05e10b4743273a74b + // codeseparator parts have been elided. (bitcoind's checks for multisig + // type doesn't have codesep etc either. + { + name: "multisig", + script: []byte{ + txscript.OP_TRUE, + txscript.OP_DATA_33, + 0x02, 0x32, 0xab, 0xdc, 0x89, 0x3e, 0x7f, 0x06, 0x31, + 0x36, 0x4d, 0x7f, 0xd0, 0x1c, 0xb3, 0x3d, 0x24, 0xda, + 0x45, 0x32, 0x9a, 0x00, 0x35, 0x7b, 0x3a, 0x78, 0x86, + 0x21, 0x1a, 0xb4, 0x14, 0xd5, 0x5a, + txscript.OP_TRUE, + txscript.OP_CHECKMULTISIG, + }, + scripttype: txscript.MultiSigTy, + }, + // tx e5779b9e78f9650debc2893fd9636d827b26b4ddfa6a8172fe8708c924f5c39d + // P2SH + { + name: "P2SH", + script: []byte{ + txscript.OP_HASH160, + txscript.OP_DATA_20, + 0x43, 0x3e, 0xc2, 0xac, 0x1f, 0xfa, 0x1b, 0x7b, 0x7d, + 0x02, 0x7f, 0x56, 0x45, 0x29, 0xc5, 0x71, 0x97, 0xf9, + 0xae, 0x88, + txscript.OP_EQUAL, + }, + scripttype: txscript.ScriptHashTy, + }, + // Nulldata with no data at all. + { + name: "nulldata", + script: []byte{ + txscript.OP_RETURN, + }, + scripttype: txscript.NullDataTy, + }, + // Nulldata with small data. + { + name: "nulldata2", + script: []byte{ + txscript.OP_RETURN, + txscript.OP_DATA_8, + 0x04, 0x67, 0x08, 0xaf, 0xdb, 0x0f, 0xe5, 0x54, + }, + scripttype: txscript.NullDataTy, + }, + // Nulldata with max allowed data. + { + name: "nulldata3", + script: []byte{ + txscript.OP_RETURN, + txscript.OP_PUSHDATA1, + 0x28, // 40 + 0x04, 0x67, 0x08, 0xaf, 0xdb, 0x0f, 0xe5, 0x54, + 0x82, 0x71, 0x96, 0x7f, 0x1a, 0x67, 0x13, 0x0b, + 0x71, 0x05, 0xcd, 0x6a, 0x82, 0x8e, 0x03, 0x90, + 0x9a, 0x67, 0x96, 0x2e, 0x0e, 0xa1, 0xf6, 0x1d, + 0xeb, 0x64, 0x9f, 0x6b, 0xc3, 0xf4, 0xce, 0xf3, + }, + scripttype: txscript.NullDataTy, + }, + // Nulldata with more than max allowed data (so therefore nonstandard) + { + name: "nulldata4", + script: []byte{ + txscript.OP_RETURN, + txscript.OP_PUSHDATA1, + 0x29, // 41 + 0x04, 0x67, 0x08, 0xaf, 0xdb, 0x0f, 0xe5, 0x54, + 0x82, 0x71, 0x96, 0x7f, 0x1a, 0x67, 0x13, 0x0b, + 0x71, 0x05, 0xcd, 0x6a, 0x82, 0x8e, 0x03, 0x90, + 0x9a, 0x67, 0x96, 0x2e, 0x0e, 0xa1, 0xf6, 0x1d, + 0xeb, 0x64, 0x9f, 0x6b, 0xc3, 0xf4, 0xce, 0xf3, + 0x08, + }, + scripttype: txscript.NonStandardTy, + }, + // Almost nulldata, but add an additional opcode after the data to make + // it nonstandard. + { + name: "nulldata5", + script: []byte{ + txscript.OP_RETURN, + txscript.OP_DATA_1, + 0x04, + txscript.OP_TRUE, + }, + scripttype: txscript.NonStandardTy, + }, // The next few are almost multisig (it is the more complex script type) + // but with various changes to make it fail. + { + // multisig but funny nsigs.. + name: "strange 1", + script: []byte{ + txscript.OP_DUP, + txscript.OP_DATA_33, + 0x02, 0x32, 0xab, 0xdc, 0x89, 0x3e, 0x7f, 0x06, 0x31, + 0x36, 0x4d, 0x7f, 0xd0, 0x1c, 0xb3, 0x3d, 0x24, 0xda, + 0x45, 0x32, 0x9a, 0x00, 0x35, 0x7b, 0x3a, 0x78, 0x86, + 0x21, 0x1a, 0xb4, 0x14, 0xd5, 0x5a, + txscript.OP_TRUE, + txscript.OP_CHECKMULTISIG, + }, + scripttype: txscript.NonStandardTy, + }, + { + name: "strange 2", + // multisig but funny pubkey. + script: []byte{ + txscript.OP_TRUE, + txscript.OP_TRUE, + txscript.OP_TRUE, + txscript.OP_CHECKMULTISIG, + }, + scripttype: txscript.NonStandardTy, + }, + { + name: "strange 3", + // multisig but no matching npubkeys opcode. + script: []byte{ + txscript.OP_TRUE, + txscript.OP_DATA_33, + 0x02, 0x32, 0xab, 0xdc, 0x89, 0x3e, 0x7f, 0x06, 0x31, + 0x36, 0x4d, 0x7f, 0xd0, 0x1c, 0xb3, 0x3d, 0x24, 0xda, + 0x45, 0x32, 0x9a, 0x00, 0x35, 0x7b, 0x3a, 0x78, 0x86, + 0x21, 0x1a, 0xb4, 0x14, 0xd5, 0x5a, + txscript.OP_DATA_33, + 0x02, 0x32, 0xab, 0xdc, 0x89, 0x3e, 0x7f, 0x06, 0x31, + 0x36, 0x4d, 0x7f, 0xd0, 0x1c, 0xb3, 0x3d, 0x24, 0xda, + 0x45, 0x32, 0x9a, 0x00, 0x35, 0x7b, 0x3a, 0x78, 0x86, + 0x21, 0x1a, 0xb4, 0x14, 0xd5, 0x5a, + // No number. + txscript.OP_CHECKMULTISIG, + }, + scripttype: txscript.NonStandardTy, + }, + { + name: "strange 4", + // multisig but with multisigverify + script: []byte{ + txscript.OP_TRUE, + txscript.OP_DATA_33, + 0x02, 0x32, 0xab, 0xdc, 0x89, 0x3e, 0x7f, 0x06, 0x31, + 0x36, 0x4d, 0x7f, 0xd0, 0x1c, 0xb3, 0x3d, 0x24, 0xda, + 0x45, 0x32, 0x9a, 0x00, 0x35, 0x7b, 0x3a, 0x78, 0x86, + 0x21, 0x1a, 0xb4, 0x14, 0xd5, 0x5a, + txscript.OP_TRUE, + txscript.OP_CHECKMULTISIGVERIFY, + }, + scripttype: txscript.NonStandardTy, + }, + { + name: "strange 5", + // multisig but wrong length. + script: []byte{ + txscript.OP_TRUE, + txscript.OP_CHECKMULTISIG, + }, + scripttype: txscript.NonStandardTy, + }, + { + name: "doesn't parse", + script: []byte{ + txscript.OP_DATA_5, 0x1, 0x2, 0x3, 0x4, + }, + scripttype: txscript.NonStandardTy, + }, +} + +func testScriptType(t *testing.T, test *scriptTypeTest) { + scripttype := txscript.GetScriptClass(test.script) + if scripttype != test.scripttype { + t.Errorf("%s: expected %s got %s", test.name, test.scripttype, + scripttype) + } +} + +func TestScriptTypes(t *testing.T) { + t.Parallel() + + for i := range scriptTypeTests { + testScriptType(t, &scriptTypeTests[i]) + } +} + +func TestIsPayToScriptHash(t *testing.T) { + t.Parallel() + + for _, test := range scriptTypeTests { + shouldBe := (test.scripttype == txscript.ScriptHashTy) + p2sh := txscript.IsPayToScriptHash(test.script) + if p2sh != shouldBe { + t.Errorf("%s: epxected p2sh %v, got %v", test.name, + shouldBe, p2sh) + } + } +} + +// This test sets the pc to a deliberately bad result then confirms that Step() +// and Disasm fail correctly. +func TestBadPC(t *testing.T) { + t.Parallel() + + type pcTest struct { + script, off int + } + pcTests := []pcTest{ + { + script: 2, + off: 0, + }, + { + script: 0, + off: 2, + }, + } + // tx with almost empty scripts. + tx := &btcwire.MsgTx{ + Version: 1, + TxIn: []*btcwire.TxIn{ + { + PreviousOutPoint: btcwire.OutPoint{ + Hash: btcwire.ShaHash([32]byte{ + 0xc9, 0x97, 0xa5, 0xe5, + 0x6e, 0x10, 0x41, 0x02, + 0xfa, 0x20, 0x9c, 0x6a, + 0x85, 0x2d, 0xd9, 0x06, + 0x60, 0xa2, 0x0b, 0x2d, + 0x9c, 0x35, 0x24, 0x23, + 0xed, 0xce, 0x25, 0x85, + 0x7f, 0xcd, 0x37, 0x04, + }), + Index: 0, + }, + SignatureScript: []uint8{txscript.OP_NOP}, + Sequence: 4294967295, + }, + }, + TxOut: []*btcwire.TxOut{ + { + Value: 1000000000, + PkScript: []byte{}, + }, + }, + LockTime: 0, + } + pkScript := []byte{txscript.OP_NOP} + + for _, test := range pcTests { + engine, err := txscript.NewScript(tx.TxIn[0].SignatureScript, + pkScript, 0, tx, 0) + if err != nil { + t.Errorf("Failed to create script: %v", err) + } + + // set to after all scripts + engine.TstSetPC(test.script, test.off) + + _, err = engine.Step() + if err == nil { + t.Errorf("Step with invalid pc (%v) succeeds!", test) + continue + } + + _, err = engine.DisasmPC() + if err == nil { + t.Errorf("DisasmPC with invalid pc (%v) succeeds!", + test) + } + } +} + +// Most codepaths in CheckErrorCondition() are testd elsewhere, this tests +// the execute early test. +func TestCheckErrorCondition(t *testing.T) { + t.Parallel() + + // tx with almost empty scripts. + tx := &btcwire.MsgTx{ + Version: 1, + TxIn: []*btcwire.TxIn{ + { + PreviousOutPoint: btcwire.OutPoint{ + Hash: btcwire.ShaHash([32]byte{ + 0xc9, 0x97, 0xa5, 0xe5, + 0x6e, 0x10, 0x41, 0x02, + 0xfa, 0x20, 0x9c, 0x6a, + 0x85, 0x2d, 0xd9, 0x06, + 0x60, 0xa2, 0x0b, 0x2d, + 0x9c, 0x35, 0x24, 0x23, + 0xed, 0xce, 0x25, 0x85, + 0x7f, 0xcd, 0x37, 0x04, + }), + Index: 0, + }, + SignatureScript: []uint8{}, + Sequence: 4294967295, + }, + }, + TxOut: []*btcwire.TxOut{ + { + Value: 1000000000, + PkScript: []byte{}, + }, + }, + LockTime: 0, + } + pkScript := []byte{ + txscript.OP_NOP, + txscript.OP_NOP, + txscript.OP_NOP, + txscript.OP_NOP, + txscript.OP_NOP, + txscript.OP_NOP, + txscript.OP_NOP, + txscript.OP_NOP, + txscript.OP_NOP, + txscript.OP_NOP, + txscript.OP_TRUE, + } + + engine, err := txscript.NewScript(tx.TxIn[0].SignatureScript, pkScript, + 0, tx, 0) + if err != nil { + t.Errorf("failed to create script: %v", err) + } + + for i := 0; i < len(pkScript)-1; i++ { + done, err := engine.Step() + if err != nil { + t.Errorf("failed to step %dth time: %v", i, err) + return + } + if done { + t.Errorf("finshed early on %dth time", i) + return + } + + err = engine.CheckErrorCondition() + if err != txscript.ErrStackScriptUnfinished { + t.Errorf("got unexepected error %v on %dth iteration", + err, i) + return + } + } + done, err := engine.Step() + if err != nil { + t.Errorf("final step failed %v", err) + return + } + if !done { + t.Errorf("final step isn't done!") + return + } + + err = engine.CheckErrorCondition() + if err != nil { + t.Errorf("unexpected error %v on final check", err) + } +} + +type TstSigScript struct { + name string + inputs []TstInput + hashType txscript.SigHashType + compress bool + scriptAtWrongIndex bool +} + +type TstInput struct { + txout *btcwire.TxOut + sigscriptGenerates bool + inputValidates bool + indexOutOfRange bool +} + +var coinbaseOutPoint = &btcwire.OutPoint{ + Index: (1 << 32) - 1, +} + +// Pregenerated private key, with associated public key and pkScripts +// for the uncompressed and compressed hash160. +var ( + privKeyD = []byte{0x6b, 0x0f, 0xd8, 0xda, 0x54, 0x22, 0xd0, 0xb7, + 0xb4, 0xfc, 0x4e, 0x55, 0xd4, 0x88, 0x42, 0xb3, 0xa1, 0x65, + 0xac, 0x70, 0x7f, 0x3d, 0xa4, 0x39, 0x5e, 0xcb, 0x3b, 0xb0, + 0xd6, 0x0e, 0x06, 0x92} + pubkeyX = []byte{0xb2, 0x52, 0xf0, 0x49, 0x85, 0x78, 0x03, 0x03, 0xc8, + 0x7d, 0xce, 0x51, 0x7f, 0xa8, 0x69, 0x0b, 0x91, 0x95, 0xf4, + 0xf3, 0x5c, 0x26, 0x73, 0x05, 0x05, 0xa2, 0xee, 0xbc, 0x09, + 0x38, 0x34, 0x3a} + pubkeyY = []byte{0xb7, 0xc6, 0x7d, 0xb2, 0xe1, 0xff, 0xc8, 0x43, 0x1f, + 0x63, 0x32, 0x62, 0xaa, 0x60, 0xc6, 0x83, 0x30, 0xbd, 0x24, + 0x7e, 0xef, 0xdb, 0x6f, 0x2e, 0x8d, 0x56, 0xf0, 0x3c, 0x9f, + 0x6d, 0xb6, 0xf8} + uncompressedPkScript = []byte{0x76, 0xa9, 0x14, 0xd1, 0x7c, 0xb5, + 0xeb, 0xa4, 0x02, 0xcb, 0x68, 0xe0, 0x69, 0x56, 0xbf, 0x32, + 0x53, 0x90, 0x0e, 0x0a, 0x86, 0xc9, 0xfa, 0x88, 0xac} + compressedPkScript = []byte{0x76, 0xa9, 0x14, 0x27, 0x4d, 0x9f, 0x7f, + 0x61, 0x7e, 0x7c, 0x7a, 0x1c, 0x1f, 0xb2, 0x75, 0x79, 0x10, + 0x43, 0x65, 0x68, 0x27, 0x9d, 0x86, 0x88, 0xac} + shortPkScript = []byte{0x76, 0xa9, 0x14, 0xd1, 0x7c, 0xb5, + 0xeb, 0xa4, 0x02, 0xcb, 0x68, 0xe0, 0x69, 0x56, 0xbf, 0x32, + 0x53, 0x90, 0x0e, 0x0a, 0x88, 0xac} + uncompressedAddrStr = "1L6fd93zGmtzkK6CsZFVVoCwzZV3MUtJ4F" + compressedAddrStr = "14apLppt9zTq6cNw8SDfiJhk9PhkZrQtYZ" +) + +// Pretend output amounts. +const coinbaseVal = 2500000000 +const fee = 5000000 + +var SigScriptTests = []TstSigScript{ + { + name: "one input uncompressed", + inputs: []TstInput{ + { + txout: btcwire.NewTxOut(coinbaseVal, uncompressedPkScript), + sigscriptGenerates: true, + inputValidates: true, + indexOutOfRange: false, + }, + }, + hashType: txscript.SigHashAll, + compress: false, + scriptAtWrongIndex: false, + }, + { + name: "two inputs uncompressed", + inputs: []TstInput{ + { + txout: btcwire.NewTxOut(coinbaseVal, uncompressedPkScript), + sigscriptGenerates: true, + inputValidates: true, + indexOutOfRange: false, + }, + { + txout: btcwire.NewTxOut(coinbaseVal+fee, uncompressedPkScript), + sigscriptGenerates: true, + inputValidates: true, + indexOutOfRange: false, + }, + }, + hashType: txscript.SigHashAll, + compress: false, + scriptAtWrongIndex: false, + }, + { + name: "one input compressed", + inputs: []TstInput{ + { + txout: btcwire.NewTxOut(coinbaseVal, compressedPkScript), + sigscriptGenerates: true, + inputValidates: true, + indexOutOfRange: false, + }, + }, + hashType: txscript.SigHashAll, + compress: true, + scriptAtWrongIndex: false, + }, + { + name: "two inputs compressed", + inputs: []TstInput{ + { + txout: btcwire.NewTxOut(coinbaseVal, compressedPkScript), + sigscriptGenerates: true, + inputValidates: true, + indexOutOfRange: false, + }, + { + txout: btcwire.NewTxOut(coinbaseVal+fee, compressedPkScript), + sigscriptGenerates: true, + inputValidates: true, + indexOutOfRange: false, + }, + }, + hashType: txscript.SigHashAll, + compress: true, + scriptAtWrongIndex: false, + }, + { + name: "hashType SigHashNone", + inputs: []TstInput{ + { + txout: btcwire.NewTxOut(coinbaseVal, uncompressedPkScript), + sigscriptGenerates: true, + inputValidates: true, + indexOutOfRange: false, + }, + }, + hashType: txscript.SigHashNone, + compress: false, + scriptAtWrongIndex: false, + }, + { + name: "hashType SigHashSingle", + inputs: []TstInput{ + { + txout: btcwire.NewTxOut(coinbaseVal, uncompressedPkScript), + sigscriptGenerates: true, + inputValidates: true, + indexOutOfRange: false, + }, + }, + hashType: txscript.SigHashSingle, + compress: false, + scriptAtWrongIndex: false, + }, + { + name: "hashType SigHashAnyoneCanPay", + inputs: []TstInput{ + { + txout: btcwire.NewTxOut(coinbaseVal, uncompressedPkScript), + sigscriptGenerates: true, + inputValidates: true, + indexOutOfRange: false, + }, + }, + hashType: txscript.SigHashAnyOneCanPay, + compress: false, + scriptAtWrongIndex: false, + }, + { + name: "hashType non-standard", + inputs: []TstInput{ + { + txout: btcwire.NewTxOut(coinbaseVal, uncompressedPkScript), + sigscriptGenerates: true, + inputValidates: true, + indexOutOfRange: false, + }, + }, + hashType: 0x04, + compress: false, + scriptAtWrongIndex: false, + }, + { + name: "invalid compression", + inputs: []TstInput{ + { + txout: btcwire.NewTxOut(coinbaseVal, uncompressedPkScript), + sigscriptGenerates: true, + inputValidates: false, + indexOutOfRange: false, + }, + }, + hashType: txscript.SigHashAll, + compress: true, + scriptAtWrongIndex: false, + }, + { + name: "short PkScript", + inputs: []TstInput{ + { + txout: btcwire.NewTxOut(coinbaseVal, shortPkScript), + sigscriptGenerates: false, + indexOutOfRange: false, + }, + }, + hashType: txscript.SigHashAll, + compress: false, + scriptAtWrongIndex: false, + }, + { + name: "valid script at wrong index", + inputs: []TstInput{ + { + txout: btcwire.NewTxOut(coinbaseVal, uncompressedPkScript), + sigscriptGenerates: true, + inputValidates: true, + indexOutOfRange: false, + }, + { + txout: btcwire.NewTxOut(coinbaseVal+fee, uncompressedPkScript), + sigscriptGenerates: true, + inputValidates: true, + indexOutOfRange: false, + }, + }, + hashType: txscript.SigHashAll, + compress: false, + scriptAtWrongIndex: true, + }, + { + name: "index out of range", + inputs: []TstInput{ + { + txout: btcwire.NewTxOut(coinbaseVal, uncompressedPkScript), + sigscriptGenerates: true, + inputValidates: true, + indexOutOfRange: false, + }, + { + txout: btcwire.NewTxOut(coinbaseVal+fee, uncompressedPkScript), + sigscriptGenerates: true, + inputValidates: true, + indexOutOfRange: false, + }, + }, + hashType: txscript.SigHashAll, + compress: false, + scriptAtWrongIndex: true, + }, +} + +// Test the sigscript generation for valid and invalid inputs, all +// hashTypes, and with and without compression. This test creates +// sigscripts to spend fake coinbase inputs, as sigscripts cannot be +// created for the MsgTxs in txTests, since they come from the blockchain +// and we don't have the private keys. +func TestSignatureScript(t *testing.T) { + t.Parallel() + + privKey, _ := btcec.PrivKeyFromBytes(btcec.S256(), privKeyD) + +nexttest: + for i := range SigScriptTests { + tx := btcwire.NewMsgTx() + + output := btcwire.NewTxOut(500, []byte{txscript.OP_RETURN}) + tx.AddTxOut(output) + + for _ = range SigScriptTests[i].inputs { + txin := btcwire.NewTxIn(coinbaseOutPoint, nil) + tx.AddTxIn(txin) + } + + var script []byte + var err error + for j := range tx.TxIn { + var idx int + if SigScriptTests[i].inputs[j].indexOutOfRange { + t.Errorf("at test %v", SigScriptTests[i].name) + idx = len(SigScriptTests[i].inputs) + } else { + idx = j + } + script, err = txscript.SignatureScript(tx, idx, + SigScriptTests[i].inputs[j].txout.PkScript, + SigScriptTests[i].hashType, privKey, + SigScriptTests[i].compress) + + if (err == nil) != SigScriptTests[i].inputs[j].sigscriptGenerates { + if err == nil { + t.Errorf("passed test '%v' incorrectly", + SigScriptTests[i].name) + } else { + t.Errorf("failed test '%v': %v", + SigScriptTests[i].name, err) + } + continue nexttest + } + if !SigScriptTests[i].inputs[j].sigscriptGenerates { + // done with this test + continue nexttest + } + + tx.TxIn[j].SignatureScript = script + } + + // If testing using a correct sigscript but for an incorrect + // index, use last input script for first input. Requires > 0 + // inputs for test. + if SigScriptTests[i].scriptAtWrongIndex { + tx.TxIn[0].SignatureScript = script + SigScriptTests[i].inputs[0].inputValidates = false + } + + // Validate tx input scripts + scriptFlags := txscript.ScriptBip16 | txscript.ScriptCanonicalSignatures + for j, txin := range tx.TxIn { + engine, err := txscript.NewScript(txin.SignatureScript, + SigScriptTests[i].inputs[j].txout.PkScript, + j, tx, scriptFlags) + if err != nil { + t.Errorf("cannot create script vm for test %v: %v", + SigScriptTests[i].name, err) + continue nexttest + } + err = engine.Execute() + if (err == nil) != SigScriptTests[i].inputs[j].inputValidates { + if err == nil { + t.Errorf("passed test '%v' validation incorrectly: %v", + SigScriptTests[i].name, err) + } else { + t.Errorf("failed test '%v' validation: %v", + SigScriptTests[i].name, err) + } + continue nexttest + } + } + } +} + +func TestStringifyClass(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + scriptclass txscript.ScriptClass + stringed string + }{ + { + name: "nonstandardty", + scriptclass: txscript.NonStandardTy, + stringed: "nonstandard", + }, + { + name: "pubkey", + scriptclass: txscript.PubKeyTy, + stringed: "pubkey", + }, + { + name: "pubkeyhash", + scriptclass: txscript.PubKeyHashTy, + stringed: "pubkeyhash", + }, + { + name: "scripthash", + scriptclass: txscript.ScriptHashTy, + stringed: "scripthash", + }, + { + name: "multisigty", + scriptclass: txscript.MultiSigTy, + stringed: "multisig", + }, + { + name: "nulldataty", + scriptclass: txscript.NullDataTy, + stringed: "nulldata", + }, + { + name: "broken", + scriptclass: txscript.ScriptClass(255), + stringed: "Invalid", + }, + } + + for _, test := range tests { + typeString := test.scriptclass.String() + if typeString != test.stringed { + t.Errorf("%s: got \"%s\" expected \"%s\"", test.name, + typeString, test.stringed) + } + } +} + +// bogusAddress implements the btcutil.Address interface so the tests can ensure +// unsupported address types are handled properly. +type bogusAddress struct{} + +// EncodeAddress simply returns an empty string. It exists to satsify the +// btcutil.Address interface. +func (b *bogusAddress) EncodeAddress() string { + return "" +} + +// ScriptAddress simply returns an empty byte slice. It exists to satsify the +// btcutil.Address interface. +func (b *bogusAddress) ScriptAddress() []byte { + return []byte{} +} + +// IsForNet lies blatantly to satisfy the btcutil.Address interface. +func (b *bogusAddress) IsForNet(net *btcnet.Params) bool { + return true // why not? +} + +// String simply returns an empty string. It exists to satsify the +// btcutil.Address interface. +func (b *bogusAddress) String() string { + return "" +} + +func TestPayToAddrScript(t *testing.T) { + t.Parallel() + + // 1MirQ9bwyQcGVJPwKUgapu5ouK2E2Ey4gX + p2pkhMain, err := btcutil.NewAddressPubKeyHash([]byte{ + 0xe3, 0x4c, 0xce, 0x70, 0xc8, 0x63, 0x73, 0x27, 0x3e, 0xfc, + 0xc5, 0x4c, 0xe7, 0xd2, 0xa4, 0x91, 0xbb, 0x4a, 0x0e, 0x84, + }, &btcnet.MainNetParams) + if err != nil { + t.Errorf("Unable to create public key hash address: %v", err) + return + } + + // Taken from transaction: + // b0539a45de13b3e0403909b8bd1a555b8cbe45fd4e3f3fda76f3a5f52835c29d + p2shMain, _ := btcutil.NewAddressScriptHashFromHash([]byte{ + 0xe8, 0xc3, 0x00, 0xc8, 0x79, 0x86, 0xef, 0xa8, 0x4c, 0x37, + 0xc0, 0x51, 0x99, 0x29, 0x01, 0x9e, 0xf8, 0x6e, 0xb5, 0xb4, + }, &btcnet.MainNetParams) + if err != nil { + t.Errorf("Unable to create script hash address: %v", err) + return + } + + // mainnet p2pk 13CG6SJ3yHUXo4Cr2RY4THLLJrNFuG3gUg + p2pkCompressedMain, err := btcutil.NewAddressPubKey([]byte{ + 0x02, 0x19, 0x2d, 0x74, 0xd0, 0xcb, 0x94, 0x34, 0x4c, 0x95, + 0x69, 0xc2, 0xe7, 0x79, 0x01, 0x57, 0x3d, 0x8d, 0x79, 0x03, + 0xc3, 0xeb, 0xec, 0x3a, 0x95, 0x77, 0x24, 0x89, 0x5d, 0xca, + 0x52, 0xc6, 0xb4}, &btcnet.MainNetParams) + if err != nil { + t.Errorf("Unable to create pubkey address (compressed): %v", + err) + return + } + p2pkCompressed2Main, err := btcutil.NewAddressPubKey([]byte{ + 0x03, 0xb0, 0xbd, 0x63, 0x42, 0x34, 0xab, 0xbb, 0x1b, 0xa1, + 0xe9, 0x86, 0xe8, 0x84, 0x18, 0x5c, 0x61, 0xcf, 0x43, 0xe0, + 0x01, 0xf9, 0x13, 0x7f, 0x23, 0xc2, 0xc4, 0x09, 0x27, 0x3e, + 0xb1, 0x6e, 0x65}, &btcnet.MainNetParams) + if err != nil { + t.Errorf("Unable to create pubkey address (compressed 2): %v", + err) + return + } + + p2pkUncompressedMain, err := btcutil.NewAddressPubKey([]byte{ + 0x04, 0x11, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a, 0x01, 0x6b, + 0x49, 0x84, 0x0f, 0x8c, 0x53, 0xbc, 0x1e, 0xb6, 0x8a, 0x38, + 0x2e, 0x97, 0xb1, 0x48, 0x2e, 0xca, 0xd7, 0xb1, 0x48, 0xa6, + 0x90, 0x9a, 0x5c, 0xb2, 0xe0, 0xea, 0xdd, 0xfb, 0x84, 0xcc, + 0xf9, 0x74, 0x44, 0x64, 0xf8, 0x2e, 0x16, 0x0b, 0xfa, 0x9b, + 0x8b, 0x64, 0xf9, 0xd4, 0xc0, 0x3f, 0x99, 0x9b, 0x86, 0x43, + 0xf6, 0x56, 0xb4, 0x12, 0xa3}, &btcnet.MainNetParams) + if err != nil { + t.Errorf("Unable to create pubkey address (uncompressed): %v", + err) + return + } + + tests := []struct { + in btcutil.Address + expected []byte + err error + }{ + // pay-to-pubkey-hash address on mainnet + { + p2pkhMain, + []byte{ + 0x76, 0xa9, 0x14, 0xe3, 0x4c, 0xce, 0x70, 0xc8, + 0x63, 0x73, 0x27, 0x3e, 0xfc, 0xc5, 0x4c, 0xe7, + 0xd2, 0xa4, 0x91, 0xbb, 0x4a, 0x0e, 0x84, 0x88, + 0xac, + }, + nil, + }, + // pay-to-script-hash address on mainnet + { + p2shMain, + []byte{ + 0xa9, 0x14, 0xe8, 0xc3, 0x00, 0xc8, 0x79, 0x86, + 0xef, 0xa8, 0x4c, 0x37, 0xc0, 0x51, 0x99, 0x29, + 0x01, 0x9e, 0xf8, 0x6e, 0xb5, 0xb4, 0x87, + }, + nil, + }, + // pay-to-pubkey address on mainnet. compressed key. + { + p2pkCompressedMain, + []byte{ + txscript.OP_DATA_33, + 0x02, 0x19, 0x2d, 0x74, 0xd0, 0xcb, 0x94, 0x34, + 0x4c, 0x95, 0x69, 0xc2, 0xe7, 0x79, 0x01, 0x57, + 0x3d, 0x8d, 0x79, 0x03, 0xc3, 0xeb, 0xec, 0x3a, + 0x95, 0x77, 0x24, 0x89, 0x5d, 0xca, 0x52, 0xc6, + 0xb4, txscript.OP_CHECKSIG, + }, + nil, + }, + // pay-to-pubkey address on mainnet. compressed key (other way). + { + p2pkCompressed2Main, + []byte{ + txscript.OP_DATA_33, + 0x03, 0xb0, 0xbd, 0x63, 0x42, 0x34, 0xab, 0xbb, + 0x1b, 0xa1, 0xe9, 0x86, 0xe8, 0x84, 0x18, 0x5c, + 0x61, 0xcf, 0x43, 0xe0, 0x01, 0xf9, 0x13, 0x7f, + 0x23, 0xc2, 0xc4, 0x09, 0x27, 0x3e, 0xb1, 0x6e, + 0x65, txscript.OP_CHECKSIG, + }, + nil, + }, + // pay-to-pubkey address on mainnet. uncompressed key. + { + p2pkUncompressedMain, + []byte{ + txscript.OP_DATA_65, + 0x04, 0x11, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a, + 0x01, 0x6b, 0x49, 0x84, 0x0f, 0x8c, 0x53, 0xbc, + 0x1e, 0xb6, 0x8a, 0x38, 0x2e, 0x97, 0xb1, 0x48, + 0x2e, 0xca, 0xd7, 0xb1, 0x48, 0xa6, 0x90, 0x9a, + 0x5c, 0xb2, 0xe0, 0xea, 0xdd, 0xfb, 0x84, 0xcc, + 0xf9, 0x74, 0x44, 0x64, 0xf8, 0x2e, 0x16, 0x0b, + 0xfa, 0x9b, 0x8b, 0x64, 0xf9, 0xd4, 0xc0, 0x3f, + 0x99, 0x9b, 0x86, 0x43, 0xf6, 0x56, 0xb4, 0x12, + 0xa3, txscript.OP_CHECKSIG, + }, + nil, + }, + + // Supported address types with nil pointers. + {(*btcutil.AddressPubKeyHash)(nil), []byte{}, txscript.ErrUnsupportedAddress}, + {(*btcutil.AddressScriptHash)(nil), []byte{}, txscript.ErrUnsupportedAddress}, + {(*btcutil.AddressPubKey)(nil), []byte{}, txscript.ErrUnsupportedAddress}, + + // Unsupported address type. + {&bogusAddress{}, []byte{}, txscript.ErrUnsupportedAddress}, + } + + t.Logf("Running %d tests", len(tests)) + for i, test := range tests { + pkScript, err := txscript.PayToAddrScript(test.in) + if err != test.err { + t.Errorf("PayToAddrScript #%d unexpected error - "+ + "got %v, want %v", i, err, test.err) + continue + } + + if !bytes.Equal(pkScript, test.expected) { + t.Errorf("PayToAddrScript #%d got: %x\nwant: %x", + i, pkScript, test.expected) + continue + } + } +} + +func TestMultiSigScript(t *testing.T) { + t.Parallel() + + // mainnet p2pk 13CG6SJ3yHUXo4Cr2RY4THLLJrNFuG3gUg + p2pkCompressedMain, err := btcutil.NewAddressPubKey([]byte{ + 0x02, 0x19, 0x2d, 0x74, 0xd0, 0xcb, 0x94, 0x34, 0x4c, 0x95, + 0x69, 0xc2, 0xe7, 0x79, 0x01, 0x57, 0x3d, 0x8d, 0x79, 0x03, + 0xc3, 0xeb, 0xec, 0x3a, 0x95, 0x77, 0x24, 0x89, 0x5d, 0xca, + 0x52, 0xc6, 0xb4}, &btcnet.MainNetParams) + if err != nil { + t.Errorf("Unable to create pubkey address (compressed): %v", + err) + return + } + p2pkCompressed2Main, err := btcutil.NewAddressPubKey([]byte{ + 0x03, 0xb0, 0xbd, 0x63, 0x42, 0x34, 0xab, 0xbb, 0x1b, 0xa1, + 0xe9, 0x86, 0xe8, 0x84, 0x18, 0x5c, 0x61, 0xcf, 0x43, 0xe0, + 0x01, 0xf9, 0x13, 0x7f, 0x23, 0xc2, 0xc4, 0x09, 0x27, 0x3e, + 0xb1, 0x6e, 0x65}, &btcnet.MainNetParams) + if err != nil { + t.Errorf("Unable to create pubkey address (compressed 2): %v", + err) + return + } + + p2pkUncompressedMain, err := btcutil.NewAddressPubKey([]byte{ + 0x04, 0x11, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a, 0x01, 0x6b, + 0x49, 0x84, 0x0f, 0x8c, 0x53, 0xbc, 0x1e, 0xb6, 0x8a, 0x38, + 0x2e, 0x97, 0xb1, 0x48, 0x2e, 0xca, 0xd7, 0xb1, 0x48, 0xa6, + 0x90, 0x9a, 0x5c, 0xb2, 0xe0, 0xea, 0xdd, 0xfb, 0x84, 0xcc, + 0xf9, 0x74, 0x44, 0x64, 0xf8, 0x2e, 0x16, 0x0b, 0xfa, 0x9b, + 0x8b, 0x64, 0xf9, 0xd4, 0xc0, 0x3f, 0x99, 0x9b, 0x86, 0x43, + 0xf6, 0x56, 0xb4, 0x12, 0xa3}, &btcnet.MainNetParams) + if err != nil { + t.Errorf("Unable to create pubkey address (uncompressed): %v", + err) + return + } + + tests := []struct { + keys []*btcutil.AddressPubKey + nrequired int + expected []byte + err error + }{ + { + []*btcutil.AddressPubKey{ + p2pkCompressedMain, + p2pkCompressed2Main, + }, + 1, + []byte{ + txscript.OP_1, + txscript.OP_DATA_33, + 0x02, 0x19, 0x2d, 0x74, 0xd0, 0xcb, 0x94, 0x34, + 0x4c, 0x95, 0x69, 0xc2, 0xe7, 0x79, 0x01, 0x57, + 0x3d, 0x8d, 0x79, 0x03, 0xc3, 0xeb, 0xec, 0x3a, + 0x95, 0x77, 0x24, 0x89, 0x5d, 0xca, 0x52, 0xc6, + 0xb4, + txscript.OP_DATA_33, + 0x03, 0xb0, 0xbd, 0x63, 0x42, 0x34, 0xab, 0xbb, + 0x1b, 0xa1, 0xe9, 0x86, 0xe8, 0x84, 0x18, 0x5c, + 0x61, 0xcf, 0x43, 0xe0, 0x01, 0xf9, 0x13, 0x7f, + 0x23, 0xc2, 0xc4, 0x09, 0x27, 0x3e, 0xb1, 0x6e, + 0x65, + txscript.OP_2, txscript.OP_CHECKMULTISIG, + }, + nil, + }, + { + []*btcutil.AddressPubKey{ + p2pkCompressedMain, + p2pkCompressed2Main, + }, + 2, + []byte{ + txscript.OP_2, + txscript.OP_DATA_33, + 0x02, 0x19, 0x2d, 0x74, 0xd0, 0xcb, 0x94, 0x34, + 0x4c, 0x95, 0x69, 0xc2, 0xe7, 0x79, 0x01, 0x57, + 0x3d, 0x8d, 0x79, 0x03, 0xc3, 0xeb, 0xec, 0x3a, + 0x95, 0x77, 0x24, 0x89, 0x5d, 0xca, 0x52, 0xc6, + 0xb4, + txscript.OP_DATA_33, + 0x03, 0xb0, 0xbd, 0x63, 0x42, 0x34, 0xab, 0xbb, + 0x1b, 0xa1, 0xe9, 0x86, 0xe8, 0x84, 0x18, 0x5c, + 0x61, 0xcf, 0x43, 0xe0, 0x01, 0xf9, 0x13, 0x7f, + 0x23, 0xc2, 0xc4, 0x09, 0x27, 0x3e, 0xb1, 0x6e, + 0x65, + txscript.OP_2, txscript.OP_CHECKMULTISIG, + }, + nil, + }, + { + []*btcutil.AddressPubKey{ + p2pkCompressedMain, + p2pkCompressed2Main, + }, + 3, + []byte{}, + txscript.ErrBadNumRequired, + }, + { + []*btcutil.AddressPubKey{ + p2pkUncompressedMain, + }, + 1, + []byte{ + txscript.OP_1, txscript.OP_DATA_65, + 0x04, 0x11, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a, + 0x01, 0x6b, 0x49, 0x84, 0x0f, 0x8c, 0x53, 0xbc, + 0x1e, 0xb6, 0x8a, 0x38, 0x2e, 0x97, 0xb1, 0x48, + 0x2e, 0xca, 0xd7, 0xb1, 0x48, 0xa6, 0x90, 0x9a, + 0x5c, 0xb2, 0xe0, 0xea, 0xdd, 0xfb, 0x84, 0xcc, + 0xf9, 0x74, 0x44, 0x64, 0xf8, 0x2e, 0x16, 0x0b, + 0xfa, 0x9b, 0x8b, 0x64, 0xf9, 0xd4, 0xc0, 0x3f, + 0x99, 0x9b, 0x86, 0x43, 0xf6, 0x56, 0xb4, 0x12, + 0xa3, + txscript.OP_1, txscript.OP_CHECKMULTISIG, + }, + nil, + }, + { + []*btcutil.AddressPubKey{ + p2pkUncompressedMain, + }, + 2, + []byte{}, + txscript.ErrBadNumRequired, + }, + } + + t.Logf("Running %d tests", len(tests)) + for i, test := range tests { + script, err := txscript.MultiSigScript(test.keys, + test.nrequired) + if err != test.err { + t.Errorf("MultiSigScript #%d unexpected error - "+ + "got %v, want %v", i, err, test.err) + continue + } + + if !bytes.Equal(script, test.expected) { + t.Errorf("MultiSigScript #%d got: %x\nwant: %x", + i, script, test.expected) + continue + } + } +} + +func signAndCheck(msg string, tx *btcwire.MsgTx, idx int, pkScript []byte, + hashType txscript.SigHashType, kdb txscript.KeyDB, sdb txscript.ScriptDB, + previousScript []byte) error { + + sigScript, err := txscript.SignTxOutput( + &btcnet.TestNet3Params, tx, idx, pkScript, hashType, + kdb, sdb, []byte{}) + if err != nil { + return fmt.Errorf("failed to sign output %s: %v", msg, err) + } + + return checkScripts(msg, tx, idx, sigScript, pkScript) +} + +func checkScripts(msg string, tx *btcwire.MsgTx, idx int, + sigScript, pkScript []byte) error { + engine, err := txscript.NewScript(sigScript, pkScript, idx, tx, + txscript.ScriptBip16| + txscript.ScriptCanonicalSignatures) + if err != nil { + return fmt.Errorf("failed to make script engine for %s: %v", + msg, err) + } + + err = engine.Execute() + if err != nil { + return fmt.Errorf("invalid script signature for %s: %v", msg, + err) + } + + return nil +} + +type addressToKey struct { + key *btcec.PrivateKey + compressed bool +} + +func mkGetKey(keys map[string]addressToKey) txscript.KeyDB { + if keys == nil { + return txscript.KeyClosure(func(addr btcutil.Address) (*btcec.PrivateKey, + bool, error) { + return nil, false, errors.New("nope") + }) + } + return txscript.KeyClosure(func(addr btcutil.Address) (*btcec.PrivateKey, + bool, error) { + a2k, ok := keys[addr.EncodeAddress()] + if !ok { + return nil, false, errors.New("nope") + } + return a2k.key, a2k.compressed, nil + }) +} + +func mkGetScript(scripts map[string][]byte) txscript.ScriptDB { + if scripts == nil { + return txscript.ScriptClosure(func(addr btcutil.Address) ( + []byte, error) { + return nil, errors.New("nope") + }) + } + return txscript.ScriptClosure(func(addr btcutil.Address) ([]byte, + error) { + script, ok := scripts[addr.EncodeAddress()] + if !ok { + return nil, errors.New("nope") + } + return script, nil + }) +} + +func TestSignTxOutput(t *testing.T) { + t.Parallel() + + // make key + // make script based on key. + // sign with magic pixie dust. + hashTypes := []txscript.SigHashType{ + txscript.SigHashOld, // no longer used but should act like all + txscript.SigHashAll, + txscript.SigHashNone, + txscript.SigHashSingle, + txscript.SigHashAll | txscript.SigHashAnyOneCanPay, + txscript.SigHashNone | txscript.SigHashAnyOneCanPay, + txscript.SigHashSingle | txscript.SigHashAnyOneCanPay, + } + tx := &btcwire.MsgTx{ + Version: 1, + TxIn: []*btcwire.TxIn{ + &btcwire.TxIn{ + PreviousOutPoint: btcwire.OutPoint{ + Hash: btcwire.ShaHash{}, + Index: 0, + }, + Sequence: 4294967295, + }, + &btcwire.TxIn{ + PreviousOutPoint: btcwire.OutPoint{ + Hash: btcwire.ShaHash{}, + Index: 1, + }, + Sequence: 4294967295, + }, + &btcwire.TxIn{ + PreviousOutPoint: btcwire.OutPoint{ + Hash: btcwire.ShaHash{}, + Index: 2, + }, + Sequence: 4294967295, + }, + }, + TxOut: []*btcwire.TxOut{ + &btcwire.TxOut{ + Value: 1, + }, + &btcwire.TxOut{ + Value: 2, + }, + &btcwire.TxOut{ + Value: 3, + }, + }, + LockTime: 0, + } + + // Pay to Pubkey Hash (uncompressed) + for _, hashType := range hashTypes { + for i := range tx.TxIn { + msg := fmt.Sprintf("%d:%d", hashType, i) + key, err := btcec.NewPrivateKey(btcec.S256()) + if err != nil { + t.Errorf("failed to make privKey for %s: %v", + msg, err) + break + } + + pk := (*btcec.PublicKey)(&key.PublicKey). + SerializeUncompressed() + address, err := btcutil.NewAddressPubKeyHash( + btcutil.Hash160(pk), &btcnet.TestNet3Params) + if err != nil { + t.Errorf("failed to make address for %s: %v", + msg, err) + break + } + + pkScript, err := txscript.PayToAddrScript(address) + if err != nil { + t.Errorf("failed to make pkscript "+ + "for %s: %v", msg, err) + } + + if err := signAndCheck(msg, tx, i, pkScript, hashType, + mkGetKey(map[string]addressToKey{ + address.EncodeAddress(): {key, false}, + }), mkGetScript(nil), []byte{}); err != nil { + t.Error(err) + break + } + } + } + + // Pay to Pubkey Hash (uncompressed) (merging with correct) + for _, hashType := range hashTypes { + for i := range tx.TxIn { + msg := fmt.Sprintf("%d:%d", hashType, i) + key, err := btcec.NewPrivateKey(btcec.S256()) + if err != nil { + t.Errorf("failed to make privKey for %s: %v", + msg, err) + break + } + + pk := (*btcec.PublicKey)(&key.PublicKey). + SerializeUncompressed() + address, err := btcutil.NewAddressPubKeyHash( + btcutil.Hash160(pk), &btcnet.TestNet3Params) + if err != nil { + t.Errorf("failed to make address for %s: %v", + msg, err) + break + } + + pkScript, err := txscript.PayToAddrScript(address) + if err != nil { + t.Errorf("failed to make pkscript "+ + "for %s: %v", msg, err) + } + + sigScript, err := txscript.SignTxOutput( + &btcnet.TestNet3Params, tx, i, pkScript, + hashType, mkGetKey(map[string]addressToKey{ + address.EncodeAddress(): {key, false}, + }), mkGetScript(nil), []byte{}) + if err != nil { + t.Errorf("failed to sign output %s: %v", msg, + err) + break + } + + // by the above loop, this should be valid, now sign + // again and merge. + sigScript, err = txscript.SignTxOutput( + &btcnet.TestNet3Params, tx, i, pkScript, + hashType, mkGetKey(map[string]addressToKey{ + address.EncodeAddress(): {key, false}, + }), mkGetScript(nil), sigScript) + if err != nil { + t.Errorf("failed to sign output %s a "+ + "second time: %v", msg, err) + break + } + + err = checkScripts(msg, tx, i, sigScript, pkScript) + if err != nil { + t.Errorf("twice signed script invalid for "+ + "%s: %v", msg, err) + break + } + } + } + + // Pay to Pubkey Hash (compressed) + for _, hashType := range hashTypes { + for i := range tx.TxIn { + msg := fmt.Sprintf("%d:%d", hashType, i) + + key, err := btcec.NewPrivateKey(btcec.S256()) + if err != nil { + t.Errorf("failed to make privKey for %s: %v", + msg, err) + break + } + + pk := (*btcec.PublicKey)(&key.PublicKey). + SerializeCompressed() + address, err := btcutil.NewAddressPubKeyHash( + btcutil.Hash160(pk), &btcnet.TestNet3Params) + if err != nil { + t.Errorf("failed to make address for %s: %v", + msg, err) + break + } + + pkScript, err := txscript.PayToAddrScript(address) + if err != nil { + t.Errorf("failed to make pkscript "+ + "for %s: %v", msg, err) + } + + if err := signAndCheck(msg, tx, i, pkScript, hashType, + mkGetKey(map[string]addressToKey{ + address.EncodeAddress(): {key, true}, + }), mkGetScript(nil), []byte{}); err != nil { + t.Error(err) + break + } + } + } + + // Pay to Pubkey Hash (compressed) with duplicate merge + for _, hashType := range hashTypes { + for i := range tx.TxIn { + msg := fmt.Sprintf("%d:%d", hashType, i) + + key, err := btcec.NewPrivateKey(btcec.S256()) + if err != nil { + t.Errorf("failed to make privKey for %s: %v", + msg, err) + break + } + + pk := (*btcec.PublicKey)(&key.PublicKey). + SerializeCompressed() + address, err := btcutil.NewAddressPubKeyHash( + btcutil.Hash160(pk), &btcnet.TestNet3Params) + if err != nil { + t.Errorf("failed to make address for %s: %v", + msg, err) + break + } + + pkScript, err := txscript.PayToAddrScript(address) + if err != nil { + t.Errorf("failed to make pkscript "+ + "for %s: %v", msg, err) + } + + sigScript, err := txscript.SignTxOutput( + &btcnet.TestNet3Params, tx, i, pkScript, + hashType, mkGetKey(map[string]addressToKey{ + address.EncodeAddress(): {key, true}, + }), mkGetScript(nil), []byte{}) + if err != nil { + t.Errorf("failed to sign output %s: %v", msg, + err) + break + } + + // by the above loop, this should be valid, now sign + // again and merge. + sigScript, err = txscript.SignTxOutput( + &btcnet.TestNet3Params, tx, i, pkScript, + hashType, mkGetKey(map[string]addressToKey{ + address.EncodeAddress(): {key, true}, + }), mkGetScript(nil), sigScript) + if err != nil { + t.Errorf("failed to sign output %s a "+ + "second time: %v", msg, err) + break + } + + err = checkScripts(msg, tx, i, sigScript, pkScript) + if err != nil { + t.Errorf("twice signed script invalid for "+ + "%s: %v", msg, err) + break + } + } + } + + // Pay to PubKey (uncompressed) + for _, hashType := range hashTypes { + for i := range tx.TxIn { + msg := fmt.Sprintf("%d:%d", hashType, i) + + key, err := btcec.NewPrivateKey(btcec.S256()) + if err != nil { + t.Errorf("failed to make privKey for %s: %v", + msg, err) + break + } + + pk := (*btcec.PublicKey)(&key.PublicKey). + SerializeUncompressed() + address, err := btcutil.NewAddressPubKey(pk, + &btcnet.TestNet3Params) + if err != nil { + t.Errorf("failed to make address for %s: %v", + msg, err) + break + } + + pkScript, err := txscript.PayToAddrScript(address) + if err != nil { + t.Errorf("failed to make pkscript "+ + "for %s: %v", msg, err) + } + + if err := signAndCheck(msg, tx, i, pkScript, hashType, + mkGetKey(map[string]addressToKey{ + address.EncodeAddress(): {key, false}, + }), mkGetScript(nil), []byte{}); err != nil { + t.Error(err) + break + } + } + } + + // Pay to PubKey (uncompressed) + for _, hashType := range hashTypes { + for i := range tx.TxIn { + msg := fmt.Sprintf("%d:%d", hashType, i) + + key, err := btcec.NewPrivateKey(btcec.S256()) + if err != nil { + t.Errorf("failed to make privKey for %s: %v", + msg, err) + break + } + + pk := (*btcec.PublicKey)(&key.PublicKey). + SerializeUncompressed() + address, err := btcutil.NewAddressPubKey(pk, + &btcnet.TestNet3Params) + if err != nil { + t.Errorf("failed to make address for %s: %v", + msg, err) + break + } + + pkScript, err := txscript.PayToAddrScript(address) + if err != nil { + t.Errorf("failed to make pkscript "+ + "for %s: %v", msg, err) + } + + sigScript, err := txscript.SignTxOutput( + &btcnet.TestNet3Params, tx, i, pkScript, + hashType, mkGetKey(map[string]addressToKey{ + address.EncodeAddress(): {key, false}, + }), mkGetScript(nil), []byte{}) + if err != nil { + t.Errorf("failed to sign output %s: %v", msg, + err) + break + } + + // by the above loop, this should be valid, now sign + // again and merge. + sigScript, err = txscript.SignTxOutput( + &btcnet.TestNet3Params, tx, i, pkScript, + hashType, mkGetKey(map[string]addressToKey{ + address.EncodeAddress(): {key, false}, + }), mkGetScript(nil), sigScript) + if err != nil { + t.Errorf("failed to sign output %s a "+ + "second time: %v", msg, err) + break + } + + err = checkScripts(msg, tx, i, sigScript, pkScript) + if err != nil { + t.Errorf("twice signed script invalid for "+ + "%s: %v", msg, err) + break + } + } + } + + // Pay to PubKey (compressed) + for _, hashType := range hashTypes { + for i := range tx.TxIn { + msg := fmt.Sprintf("%d:%d", hashType, i) + + key, err := btcec.NewPrivateKey(btcec.S256()) + if err != nil { + t.Errorf("failed to make privKey for %s: %v", + msg, err) + break + } + + pk := (*btcec.PublicKey)(&key.PublicKey). + SerializeCompressed() + address, err := btcutil.NewAddressPubKey(pk, + &btcnet.TestNet3Params) + if err != nil { + t.Errorf("failed to make address for %s: %v", + msg, err) + break + } + + pkScript, err := txscript.PayToAddrScript(address) + if err != nil { + t.Errorf("failed to make pkscript "+ + "for %s: %v", msg, err) + } + + if err := signAndCheck(msg, tx, i, pkScript, hashType, + mkGetKey(map[string]addressToKey{ + address.EncodeAddress(): {key, true}, + }), mkGetScript(nil), []byte{}); err != nil { + t.Error(err) + break + } + } + } + + // Pay to PubKey (compressed) with duplicate merge + for _, hashType := range hashTypes { + for i := range tx.TxIn { + msg := fmt.Sprintf("%d:%d", hashType, i) + + key, err := btcec.NewPrivateKey(btcec.S256()) + if err != nil { + t.Errorf("failed to make privKey for %s: %v", + msg, err) + break + } + + pk := (*btcec.PublicKey)(&key.PublicKey). + SerializeCompressed() + address, err := btcutil.NewAddressPubKey(pk, + &btcnet.TestNet3Params) + if err != nil { + t.Errorf("failed to make address for %s: %v", + msg, err) + break + } + + pkScript, err := txscript.PayToAddrScript(address) + if err != nil { + t.Errorf("failed to make pkscript "+ + "for %s: %v", msg, err) + } + + sigScript, err := txscript.SignTxOutput( + &btcnet.TestNet3Params, tx, i, pkScript, + hashType, mkGetKey(map[string]addressToKey{ + address.EncodeAddress(): {key, true}, + }), mkGetScript(nil), []byte{}) + if err != nil { + t.Errorf("failed to sign output %s: %v", msg, + err) + break + } + + // by the above loop, this should be valid, now sign + // again and merge. + sigScript, err = txscript.SignTxOutput( + &btcnet.TestNet3Params, tx, i, pkScript, + hashType, mkGetKey(map[string]addressToKey{ + address.EncodeAddress(): {key, true}, + }), mkGetScript(nil), sigScript) + if err != nil { + t.Errorf("failed to sign output %s a "+ + "second time: %v", msg, err) + break + } + + err = checkScripts(msg, tx, i, sigScript, pkScript) + if err != nil { + t.Errorf("twice signed script invalid for "+ + "%s: %v", msg, err) + break + } + } + } + + // As before, but with p2sh now. + // Pay to Pubkey Hash (uncompressed) + for _, hashType := range hashTypes { + for i := range tx.TxIn { + msg := fmt.Sprintf("%d:%d", hashType, i) + key, err := btcec.NewPrivateKey(btcec.S256()) + if err != nil { + t.Errorf("failed to make privKey for %s: %v", + msg, err) + break + } + + pk := (*btcec.PublicKey)(&key.PublicKey). + SerializeUncompressed() + address, err := btcutil.NewAddressPubKeyHash( + btcutil.Hash160(pk), &btcnet.TestNet3Params) + if err != nil { + t.Errorf("failed to make address for %s: %v", + msg, err) + break + } + + pkScript, err := txscript.PayToAddrScript(address) + if err != nil { + t.Errorf("failed to make pkscript "+ + "for %s: %v", msg, err) + break + } + + scriptAddr, err := btcutil.NewAddressScriptHash( + pkScript, &btcnet.TestNet3Params) + if err != nil { + t.Errorf("failed to make p2sh addr for %s: %v", + msg, err) + break + } + + scriptPkScript, err := txscript.PayToAddrScript( + scriptAddr) + if err != nil { + t.Errorf("failed to make script pkscript for "+ + "%s: %v", msg, err) + break + } + + if err := signAndCheck(msg, tx, i, scriptPkScript, + hashType, + mkGetKey(map[string]addressToKey{ + address.EncodeAddress(): {key, false}, + }), mkGetScript(map[string][]byte{ + scriptAddr.EncodeAddress(): pkScript, + }), []byte{}); err != nil { + t.Error(err) + break + } + } + } + + // Pay to Pubkey Hash (uncompressed) with duplicate merge + for _, hashType := range hashTypes { + for i := range tx.TxIn { + msg := fmt.Sprintf("%d:%d", hashType, i) + key, err := btcec.NewPrivateKey(btcec.S256()) + if err != nil { + t.Errorf("failed to make privKey for %s: %v", + msg, err) + break + } + + pk := (*btcec.PublicKey)(&key.PublicKey). + SerializeUncompressed() + address, err := btcutil.NewAddressPubKeyHash( + btcutil.Hash160(pk), &btcnet.TestNet3Params) + if err != nil { + t.Errorf("failed to make address for %s: %v", + msg, err) + break + } + + pkScript, err := txscript.PayToAddrScript(address) + if err != nil { + t.Errorf("failed to make pkscript "+ + "for %s: %v", msg, err) + break + } + + scriptAddr, err := btcutil.NewAddressScriptHash( + pkScript, &btcnet.TestNet3Params) + if err != nil { + t.Errorf("failed to make p2sh addr for %s: %v", + msg, err) + break + } + + scriptPkScript, err := txscript.PayToAddrScript( + scriptAddr) + if err != nil { + t.Errorf("failed to make script pkscript for "+ + "%s: %v", msg, err) + break + } + + sigScript, err := txscript.SignTxOutput( + &btcnet.TestNet3Params, tx, i, scriptPkScript, + hashType, mkGetKey(map[string]addressToKey{ + address.EncodeAddress(): {key, false}, + }), mkGetScript(map[string][]byte{ + scriptAddr.EncodeAddress(): pkScript, + }), []byte{}) + if err != nil { + t.Errorf("failed to sign output %s: %v", msg, + err) + break + } + + // by the above loop, this should be valid, now sign + // again and merge. + sigScript, err = txscript.SignTxOutput( + &btcnet.TestNet3Params, tx, i, scriptPkScript, + hashType, mkGetKey(map[string]addressToKey{ + address.EncodeAddress(): {key, false}, + }), mkGetScript(map[string][]byte{ + scriptAddr.EncodeAddress(): pkScript, + }), []byte{}) + if err != nil { + t.Errorf("failed to sign output %s a "+ + "second time: %v", msg, err) + break + } + + err = checkScripts(msg, tx, i, sigScript, scriptPkScript) + if err != nil { + t.Errorf("twice signed script invalid for "+ + "%s: %v", msg, err) + break + } + } + } + + // Pay to Pubkey Hash (compressed) + for _, hashType := range hashTypes { + for i := range tx.TxIn { + msg := fmt.Sprintf("%d:%d", hashType, i) + + key, err := btcec.NewPrivateKey(btcec.S256()) + if err != nil { + t.Errorf("failed to make privKey for %s: %v", + msg, err) + break + } + + pk := (*btcec.PublicKey)(&key.PublicKey). + SerializeCompressed() + address, err := btcutil.NewAddressPubKeyHash( + btcutil.Hash160(pk), &btcnet.TestNet3Params) + if err != nil { + t.Errorf("failed to make address for %s: %v", + msg, err) + break + } + + pkScript, err := txscript.PayToAddrScript(address) + if err != nil { + t.Errorf("failed to make pkscript "+ + "for %s: %v", msg, err) + } + + scriptAddr, err := btcutil.NewAddressScriptHash( + pkScript, &btcnet.TestNet3Params) + if err != nil { + t.Errorf("failed to make p2sh addr for %s: %v", + msg, err) + break + } + + scriptPkScript, err := txscript.PayToAddrScript( + scriptAddr) + if err != nil { + t.Errorf("failed to make script pkscript for "+ + "%s: %v", msg, err) + break + } + + if err := signAndCheck(msg, tx, i, scriptPkScript, + hashType, + mkGetKey(map[string]addressToKey{ + address.EncodeAddress(): {key, true}, + }), mkGetScript(map[string][]byte{ + scriptAddr.EncodeAddress(): pkScript, + }), []byte{}); err != nil { + t.Error(err) + break + } + } + } + + // Pay to Pubkey Hash (compressed) with duplicate merge + for _, hashType := range hashTypes { + for i := range tx.TxIn { + msg := fmt.Sprintf("%d:%d", hashType, i) + + key, err := btcec.NewPrivateKey(btcec.S256()) + if err != nil { + t.Errorf("failed to make privKey for %s: %v", + msg, err) + break + } + + pk := (*btcec.PublicKey)(&key.PublicKey). + SerializeCompressed() + address, err := btcutil.NewAddressPubKeyHash( + btcutil.Hash160(pk), &btcnet.TestNet3Params) + if err != nil { + t.Errorf("failed to make address for %s: %v", + msg, err) + break + } + + pkScript, err := txscript.PayToAddrScript(address) + if err != nil { + t.Errorf("failed to make pkscript "+ + "for %s: %v", msg, err) + } + + scriptAddr, err := btcutil.NewAddressScriptHash( + pkScript, &btcnet.TestNet3Params) + if err != nil { + t.Errorf("failed to make p2sh addr for %s: %v", + msg, err) + break + } + + scriptPkScript, err := txscript.PayToAddrScript( + scriptAddr) + if err != nil { + t.Errorf("failed to make script pkscript for "+ + "%s: %v", msg, err) + break + } + + sigScript, err := txscript.SignTxOutput( + &btcnet.TestNet3Params, tx, i, scriptPkScript, + hashType, mkGetKey(map[string]addressToKey{ + address.EncodeAddress(): {key, true}, + }), mkGetScript(map[string][]byte{ + scriptAddr.EncodeAddress(): pkScript, + }), []byte{}) + if err != nil { + t.Errorf("failed to sign output %s: %v", msg, + err) + break + } + + // by the above loop, this should be valid, now sign + // again and merge. + sigScript, err = txscript.SignTxOutput( + &btcnet.TestNet3Params, tx, i, scriptPkScript, + hashType, mkGetKey(map[string]addressToKey{ + address.EncodeAddress(): {key, true}, + }), mkGetScript(map[string][]byte{ + scriptAddr.EncodeAddress(): pkScript, + }), []byte{}) + if err != nil { + t.Errorf("failed to sign output %s a "+ + "second time: %v", msg, err) + break + } + + err = checkScripts(msg, tx, i, sigScript, scriptPkScript) + if err != nil { + t.Errorf("twice signed script invalid for "+ + "%s: %v", msg, err) + break + } + } + } + + // Pay to PubKey (uncompressed) + for _, hashType := range hashTypes { + for i := range tx.TxIn { + msg := fmt.Sprintf("%d:%d", hashType, i) + + key, err := btcec.NewPrivateKey(btcec.S256()) + if err != nil { + t.Errorf("failed to make privKey for %s: %v", + msg, err) + break + } + + pk := (*btcec.PublicKey)(&key.PublicKey). + SerializeUncompressed() + address, err := btcutil.NewAddressPubKey(pk, + &btcnet.TestNet3Params) + if err != nil { + t.Errorf("failed to make address for %s: %v", + msg, err) + break + } + + pkScript, err := txscript.PayToAddrScript(address) + if err != nil { + t.Errorf("failed to make pkscript "+ + "for %s: %v", msg, err) + } + + scriptAddr, err := btcutil.NewAddressScriptHash( + pkScript, &btcnet.TestNet3Params) + if err != nil { + t.Errorf("failed to make p2sh addr for %s: %v", + msg, err) + break + } + + scriptPkScript, err := txscript.PayToAddrScript( + scriptAddr) + if err != nil { + t.Errorf("failed to make script pkscript for "+ + "%s: %v", msg, err) + break + } + + if err := signAndCheck(msg, tx, i, scriptPkScript, + hashType, + mkGetKey(map[string]addressToKey{ + address.EncodeAddress(): {key, false}, + }), mkGetScript(map[string][]byte{ + scriptAddr.EncodeAddress(): pkScript, + }), []byte{}); err != nil { + t.Error(err) + break + } + } + } + + // Pay to PubKey (uncompressed) with duplicate merge + for _, hashType := range hashTypes { + for i := range tx.TxIn { + msg := fmt.Sprintf("%d:%d", hashType, i) + + key, err := btcec.NewPrivateKey(btcec.S256()) + if err != nil { + t.Errorf("failed to make privKey for %s: %v", + msg, err) + break + } + + pk := (*btcec.PublicKey)(&key.PublicKey). + SerializeUncompressed() + address, err := btcutil.NewAddressPubKey(pk, + &btcnet.TestNet3Params) + if err != nil { + t.Errorf("failed to make address for %s: %v", + msg, err) + break + } + + pkScript, err := txscript.PayToAddrScript(address) + if err != nil { + t.Errorf("failed to make pkscript "+ + "for %s: %v", msg, err) + } + + scriptAddr, err := btcutil.NewAddressScriptHash( + pkScript, &btcnet.TestNet3Params) + if err != nil { + t.Errorf("failed to make p2sh addr for %s: %v", + msg, err) + break + } + + scriptPkScript, err := txscript.PayToAddrScript( + scriptAddr) + if err != nil { + t.Errorf("failed to make script pkscript for "+ + "%s: %v", msg, err) + break + } + + sigScript, err := txscript.SignTxOutput( + &btcnet.TestNet3Params, tx, i, scriptPkScript, + hashType, mkGetKey(map[string]addressToKey{ + address.EncodeAddress(): {key, false}, + }), mkGetScript(map[string][]byte{ + scriptAddr.EncodeAddress(): pkScript, + }), []byte{}) + if err != nil { + t.Errorf("failed to sign output %s: %v", msg, + err) + break + } + + // by the above loop, this should be valid, now sign + // again and merge. + sigScript, err = txscript.SignTxOutput( + &btcnet.TestNet3Params, tx, i, scriptPkScript, + hashType, mkGetKey(map[string]addressToKey{ + address.EncodeAddress(): {key, false}, + }), mkGetScript(map[string][]byte{ + scriptAddr.EncodeAddress(): pkScript, + }), []byte{}) + if err != nil { + t.Errorf("failed to sign output %s a "+ + "second time: %v", msg, err) + break + } + + err = checkScripts(msg, tx, i, sigScript, scriptPkScript) + if err != nil { + t.Errorf("twice signed script invalid for "+ + "%s: %v", msg, err) + break + } + } + } + + // Pay to PubKey (compressed) + for _, hashType := range hashTypes { + for i := range tx.TxIn { + msg := fmt.Sprintf("%d:%d", hashType, i) + + key, err := btcec.NewPrivateKey(btcec.S256()) + if err != nil { + t.Errorf("failed to make privKey for %s: %v", + msg, err) + break + } + + pk := (*btcec.PublicKey)(&key.PublicKey). + SerializeCompressed() + address, err := btcutil.NewAddressPubKey(pk, + &btcnet.TestNet3Params) + if err != nil { + t.Errorf("failed to make address for %s: %v", + msg, err) + break + } + + pkScript, err := txscript.PayToAddrScript(address) + if err != nil { + t.Errorf("failed to make pkscript "+ + "for %s: %v", msg, err) + } + + scriptAddr, err := btcutil.NewAddressScriptHash( + pkScript, &btcnet.TestNet3Params) + if err != nil { + t.Errorf("failed to make p2sh addr for %s: %v", + msg, err) + break + } + + scriptPkScript, err := txscript.PayToAddrScript( + scriptAddr) + if err != nil { + t.Errorf("failed to make script pkscript for "+ + "%s: %v", msg, err) + break + } + + if err := signAndCheck(msg, tx, i, scriptPkScript, + hashType, + mkGetKey(map[string]addressToKey{ + address.EncodeAddress(): {key, true}, + }), mkGetScript(map[string][]byte{ + scriptAddr.EncodeAddress(): pkScript, + }), []byte{}); err != nil { + t.Error(err) + break + } + } + } + + // Pay to PubKey (compressed) + for _, hashType := range hashTypes { + for i := range tx.TxIn { + msg := fmt.Sprintf("%d:%d", hashType, i) + + key, err := btcec.NewPrivateKey(btcec.S256()) + if err != nil { + t.Errorf("failed to make privKey for %s: %v", + msg, err) + break + } + + pk := (*btcec.PublicKey)(&key.PublicKey). + SerializeCompressed() + address, err := btcutil.NewAddressPubKey(pk, + &btcnet.TestNet3Params) + if err != nil { + t.Errorf("failed to make address for %s: %v", + msg, err) + break + } + + pkScript, err := txscript.PayToAddrScript(address) + if err != nil { + t.Errorf("failed to make pkscript "+ + "for %s: %v", msg, err) + } + + scriptAddr, err := btcutil.NewAddressScriptHash( + pkScript, &btcnet.TestNet3Params) + if err != nil { + t.Errorf("failed to make p2sh addr for %s: %v", + msg, err) + break + } + + scriptPkScript, err := txscript.PayToAddrScript( + scriptAddr) + if err != nil { + t.Errorf("failed to make script pkscript for "+ + "%s: %v", msg, err) + break + } + + sigScript, err := txscript.SignTxOutput( + &btcnet.TestNet3Params, tx, i, scriptPkScript, + hashType, mkGetKey(map[string]addressToKey{ + address.EncodeAddress(): {key, true}, + }), mkGetScript(map[string][]byte{ + scriptAddr.EncodeAddress(): pkScript, + }), []byte{}) + if err != nil { + t.Errorf("failed to sign output %s: %v", msg, + err) + break + } + + // by the above loop, this should be valid, now sign + // again and merge. + sigScript, err = txscript.SignTxOutput( + &btcnet.TestNet3Params, tx, i, scriptPkScript, + hashType, mkGetKey(map[string]addressToKey{ + address.EncodeAddress(): {key, true}, + }), mkGetScript(map[string][]byte{ + scriptAddr.EncodeAddress(): pkScript, + }), []byte{}) + if err != nil { + t.Errorf("failed to sign output %s a "+ + "second time: %v", msg, err) + break + } + + err = checkScripts(msg, tx, i, sigScript, scriptPkScript) + if err != nil { + t.Errorf("twice signed script invalid for "+ + "%s: %v", msg, err) + break + } + } + } + + // Basic Multisig + for _, hashType := range hashTypes { + for i := range tx.TxIn { + msg := fmt.Sprintf("%d:%d", hashType, i) + + key1, err := btcec.NewPrivateKey(btcec.S256()) + if err != nil { + t.Errorf("failed to make privKey for %s: %v", + msg, err) + break + } + + pk1 := (*btcec.PublicKey)(&key1.PublicKey). + SerializeCompressed() + address1, err := btcutil.NewAddressPubKey(pk1, + &btcnet.TestNet3Params) + if err != nil { + t.Errorf("failed to make address for %s: %v", + msg, err) + break + } + + key2, err := btcec.NewPrivateKey(btcec.S256()) + if err != nil { + t.Errorf("failed to make privKey 2 for %s: %v", + msg, err) + break + } + + pk2 := (*btcec.PublicKey)(&key2.PublicKey). + SerializeCompressed() + address2, err := btcutil.NewAddressPubKey(pk2, + &btcnet.TestNet3Params) + if err != nil { + t.Errorf("failed to make address 2 for %s: %v", + msg, err) + break + } + + pkScript, err := txscript.MultiSigScript( + []*btcutil.AddressPubKey{address1, address2}, + 2) + if err != nil { + t.Errorf("failed to make pkscript "+ + "for %s: %v", msg, err) + } + + scriptAddr, err := btcutil.NewAddressScriptHash( + pkScript, &btcnet.TestNet3Params) + if err != nil { + t.Errorf("failed to make p2sh addr for %s: %v", + msg, err) + break + } + + scriptPkScript, err := txscript.PayToAddrScript( + scriptAddr) + if err != nil { + t.Errorf("failed to make script pkscript for "+ + "%s: %v", msg, err) + break + } + + if err := signAndCheck(msg, tx, i, scriptPkScript, + hashType, + mkGetKey(map[string]addressToKey{ + address1.EncodeAddress(): {key1, true}, + address2.EncodeAddress(): {key2, true}, + }), mkGetScript(map[string][]byte{ + scriptAddr.EncodeAddress(): pkScript, + }), []byte{}); err != nil { + t.Error(err) + break + } + } + } + + // Two part multisig, sign with one key then the other. + for _, hashType := range hashTypes { + for i := range tx.TxIn { + msg := fmt.Sprintf("%d:%d", hashType, i) + + key1, err := btcec.NewPrivateKey(btcec.S256()) + if err != nil { + t.Errorf("failed to make privKey for %s: %v", + msg, err) + break + } + + pk1 := (*btcec.PublicKey)(&key1.PublicKey). + SerializeCompressed() + address1, err := btcutil.NewAddressPubKey(pk1, + &btcnet.TestNet3Params) + if err != nil { + t.Errorf("failed to make address for %s: %v", + msg, err) + break + } + + key2, err := btcec.NewPrivateKey(btcec.S256()) + if err != nil { + t.Errorf("failed to make privKey 2 for %s: %v", + msg, err) + break + } + + pk2 := (*btcec.PublicKey)(&key2.PublicKey). + SerializeCompressed() + address2, err := btcutil.NewAddressPubKey(pk2, + &btcnet.TestNet3Params) + if err != nil { + t.Errorf("failed to make address 2 for %s: %v", + msg, err) + break + } + + pkScript, err := txscript.MultiSigScript( + []*btcutil.AddressPubKey{address1, address2}, + 2) + if err != nil { + t.Errorf("failed to make pkscript "+ + "for %s: %v", msg, err) + } + + scriptAddr, err := btcutil.NewAddressScriptHash( + pkScript, &btcnet.TestNet3Params) + if err != nil { + t.Errorf("failed to make p2sh addr for %s: %v", + msg, err) + break + } + + scriptPkScript, err := txscript.PayToAddrScript( + scriptAddr) + if err != nil { + t.Errorf("failed to make script pkscript for "+ + "%s: %v", msg, err) + break + } + + sigScript, err := txscript.SignTxOutput( + &btcnet.TestNet3Params, tx, i, scriptPkScript, + hashType, mkGetKey(map[string]addressToKey{ + address1.EncodeAddress(): {key1, true}, + }), mkGetScript(map[string][]byte{ + scriptAddr.EncodeAddress(): pkScript, + }), []byte{}) + if err != nil { + t.Errorf("failed to sign output %s: %v", msg, + err) + break + } + + // Only 1 out of 2 signed, this *should* fail. + if checkScripts(msg, tx, i, sigScript, + scriptPkScript) == nil { + t.Errorf("part signed script valid for %s", msg) + break + } + + // Sign with the other key and merge + sigScript, err = txscript.SignTxOutput( + &btcnet.TestNet3Params, tx, i, scriptPkScript, + hashType, mkGetKey(map[string]addressToKey{ + address2.EncodeAddress(): {key2, true}, + }), mkGetScript(map[string][]byte{ + scriptAddr.EncodeAddress(): pkScript, + }), sigScript) + if err != nil { + t.Errorf("failed to sign output %s: %v", msg, err) + break + } + + err = checkScripts(msg, tx, i, sigScript, + scriptPkScript) + if err != nil { + t.Errorf("fully signed script invalid for "+ + "%s: %v", msg, err) + break + } + } + } + + // Two part multisig, sign with one key then both, check key dedup + // correctly. + for _, hashType := range hashTypes { + for i := range tx.TxIn { + msg := fmt.Sprintf("%d:%d", hashType, i) + + key1, err := btcec.NewPrivateKey(btcec.S256()) + if err != nil { + t.Errorf("failed to make privKey for %s: %v", + msg, err) + break + } + + pk1 := (*btcec.PublicKey)(&key1.PublicKey). + SerializeCompressed() + address1, err := btcutil.NewAddressPubKey(pk1, + &btcnet.TestNet3Params) + if err != nil { + t.Errorf("failed to make address for %s: %v", + msg, err) + break + } + + key2, err := btcec.NewPrivateKey(btcec.S256()) + if err != nil { + t.Errorf("failed to make privKey 2 for %s: %v", + msg, err) + break + } + + pk2 := (*btcec.PublicKey)(&key2.PublicKey). + SerializeCompressed() + address2, err := btcutil.NewAddressPubKey(pk2, + &btcnet.TestNet3Params) + if err != nil { + t.Errorf("failed to make address 2 for %s: %v", + msg, err) + break + } + + pkScript, err := txscript.MultiSigScript( + []*btcutil.AddressPubKey{address1, address2}, + 2) + if err != nil { + t.Errorf("failed to make pkscript "+ + "for %s: %v", msg, err) + } + + scriptAddr, err := btcutil.NewAddressScriptHash( + pkScript, &btcnet.TestNet3Params) + if err != nil { + t.Errorf("failed to make p2sh addr for %s: %v", + msg, err) + break + } + + scriptPkScript, err := txscript.PayToAddrScript( + scriptAddr) + if err != nil { + t.Errorf("failed to make script pkscript for "+ + "%s: %v", msg, err) + break + } + + sigScript, err := txscript.SignTxOutput( + &btcnet.TestNet3Params, tx, i, scriptPkScript, + hashType, mkGetKey(map[string]addressToKey{ + address1.EncodeAddress(): {key1, true}, + }), mkGetScript(map[string][]byte{ + scriptAddr.EncodeAddress(): pkScript, + }), []byte{}) + if err != nil { + t.Errorf("failed to sign output %s: %v", msg, + err) + break + } + + // Only 1 out of 2 signed, this *should* fail. + if checkScripts(msg, tx, i, sigScript, + scriptPkScript) == nil { + t.Errorf("part signed script valid for %s", msg) + break + } + + // Sign with the other key and merge + sigScript, err = txscript.SignTxOutput( + &btcnet.TestNet3Params, tx, i, scriptPkScript, + hashType, mkGetKey(map[string]addressToKey{ + address1.EncodeAddress(): {key1, true}, + address2.EncodeAddress(): {key2, true}, + }), mkGetScript(map[string][]byte{ + scriptAddr.EncodeAddress(): pkScript, + }), sigScript) + if err != nil { + t.Errorf("failed to sign output %s: %v", msg, err) + break + } + + // Now we should pass. + err = checkScripts(msg, tx, i, sigScript, + scriptPkScript) + if err != nil { + t.Errorf("fully signed script invalid for "+ + "%s: %v", msg, err) + break + } + } + } +} + +func TestCalcMultiSigStats(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + script []byte + expected error + }{ + { + name: "short script", + script: []byte{ + 0x04, 0x67, 0x08, 0xaf, 0xdb, 0x0f, 0xe5, 0x54, + 0x82, 0x71, 0x96, 0x7f, 0x1a, 0x67, 0x13, 0x0b, + 0x71, 0x05, 0xcd, 0x6a, 0x82, 0x8e, 0x03, 0x90, + 0x9a, 0x67, 0x96, 0x2e, 0x0e, 0xa1, 0xf6, 0x1d, + }, + expected: txscript.ErrStackShortScript, + }, + { + name: "stack underflow", + script: []byte{ + txscript.OP_RETURN, + txscript.OP_PUSHDATA1, + 0x29, + 0x04, 0x67, 0x08, 0xaf, 0xdb, 0x0f, 0xe5, 0x54, + 0x82, 0x71, 0x96, 0x7f, 0x1a, 0x67, 0x13, 0x0b, + 0x71, 0x05, 0xcd, 0x6a, 0x82, 0x8e, 0x03, 0x90, + 0x9a, 0x67, 0x96, 0x2e, 0x0e, 0xa1, 0xf6, 0x1d, + 0xeb, 0x64, 0x9f, 0x6b, 0xc3, 0xf4, 0xce, 0xf3, + 0x08, + }, + expected: txscript.ErrStackUnderflow, + }, + { + name: "multisig script", + script: []uint8{ + txscript.OP_FALSE, + txscript.OP_DATA_72, + 0x30, 0x45, 0x02, 0x20, 0x10, + 0x6a, 0x3e, 0x4e, 0xf0, 0xb5, + 0x1b, 0x76, 0x4a, 0x28, 0x87, + 0x22, 0x62, 0xff, 0xef, 0x55, + 0x84, 0x65, 0x14, 0xda, 0xcb, + 0xdc, 0xbb, 0xdd, 0x65, 0x2c, + 0x84, 0x9d, 0x39, 0x5b, 0x43, + 0x84, 0x02, 0x21, 0x00, 0xe0, + 0x3a, 0xe5, 0x54, 0xc3, 0xcb, + 0xb4, 0x06, 0x00, 0xd3, 0x1d, + 0xd4, 0x6f, 0xc3, 0x3f, 0x25, + 0xe4, 0x7b, 0xf8, 0x52, 0x5b, + 0x1f, 0xe0, 0x72, 0x82, 0xe3, + 0xb6, 0xec, 0xb5, 0xf3, 0xbb, + 0x28, 0x01, + txscript.OP_CODESEPARATOR, + txscript.OP_TRUE, + txscript.OP_DATA_33, + 0x02, 0x32, 0xab, 0xdc, 0x89, + 0x3e, 0x7f, 0x06, 0x31, 0x36, + 0x4d, 0x7f, 0xd0, 0x1c, 0xb3, + 0x3d, 0x24, 0xda, 0x45, 0x32, + 0x9a, 0x00, 0x35, 0x7b, 0x3a, + 0x78, 0x86, 0x21, 0x1a, 0xb4, + 0x14, 0xd5, 0x5a, + txscript.OP_TRUE, + txscript.OP_CHECKMULTISIG, + }, + expected: nil, + }, + } + + for i, test := range tests { + if _, _, err := txscript.CalcMultiSigStats(test.script); err != test.expected { + t.Errorf("CalcMultiSigStats #%d (%s) wrong result\n"+ + "got: %x\nwant: %x", i, test.name, err, + test.expected) + } + } +} + +func TestHasCanonicalPushes(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + script []byte + expected bool + }{ + { + name: "does not parse", + script: []byte{ + 0x04, 0x67, 0x08, 0xaf, 0xdb, 0x0f, 0xe5, 0x54, + 0x82, 0x71, 0x96, 0x7f, 0x1a, 0x67, 0x13, 0x0b, + 0x71, 0x05, 0xcd, 0x6a, 0x82, 0x8e, 0x03, 0x90, + 0x9a, 0x67, 0x96, 0x2e, 0x0e, 0xa1, 0xf6, 0x1d, + }, + expected: false, + }, + { + name: "non-canonical push", + script: []byte{txscript.OP_PUSHDATA1, 4, 1, 2, 3, 4}, + expected: false, + }, + } + + for i, test := range tests { + if txscript.HasCanonicalPushes(test.script) != test.expected { + t.Errorf("HasCanonicalPushes #%d (%s) wrong result\n"+ + "got: %v\nwant: %v", i, test.name, true, + test.expected) + } + } +} + +func TestIsPushOnlyScript(t *testing.T) { + t.Parallel() + + test := struct { + name string + script []byte + expected bool + }{ + name: "does not parse", + script: []byte{ + 0x04, 0x67, 0x08, 0xaf, 0xdb, 0x0f, 0xe5, 0x54, + 0x82, 0x71, 0x96, 0x7f, 0x1a, 0x67, 0x13, 0x0b, + 0x71, 0x05, 0xcd, 0x6a, 0x82, 0x8e, 0x03, 0x90, + 0x9a, 0x67, 0x96, 0x2e, 0x0e, 0xa1, 0xf6, 0x1d, + }, + expected: false, + } + + if txscript.IsPushOnlyScript(test.script) != test.expected { + t.Errorf("IsPushOnlyScript (%s) wrong result\n"+ + "got: %v\nwant: %v", test.name, true, + test.expected) + } +} diff --git a/txscript/scriptbuilder.go b/txscript/scriptbuilder.go new file mode 100644 index 000000000..3149b8d79 --- /dev/null +++ b/txscript/scriptbuilder.go @@ -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), + } +} diff --git a/txscript/scriptbuilder_test.go b/txscript/scriptbuilder_test.go new file mode 100644 index 000000000..296a13428 --- /dev/null +++ b/txscript/scriptbuilder_test.go @@ -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") + } +} diff --git a/txscript/stack.go b/txscript/stack.go new file mode 100644 index 000000000..c2fdba4a9 --- /dev/null +++ b/txscript/stack.go @@ -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 +} diff --git a/txscript/stack_test.go b/txscript/stack_test.go new file mode 100644 index 000000000..63dab4888 --- /dev/null +++ b/txscript/stack_test.go @@ -0,0 +1,1005 @@ +// 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" + "errors" + "fmt" + "math/big" + "testing" + + "github.com/btcsuite/btcd/txscript" +) + +// TestStack tests that all of the stack operations work as expected. +func TestStack(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + before [][]byte + operation func(*txscript.Stack) error + expectedReturn error + after [][]byte + }{ + { + "noop", + [][]byte{{1}, {2}, {3}, {4}, {5}}, + func(stack *txscript.Stack) error { + return nil + }, + nil, + [][]byte{{1}, {2}, {3}, {4}, {5}}, + }, + { + "peek underflow (byte)", + [][]byte{{1}, {2}, {3}, {4}, {5}}, + func(stack *txscript.Stack) error { + _, err := stack.PeekByteArray(5) + return err + }, + txscript.ErrStackUnderflow, + [][]byte{}, + }, + { + "peek underflow (int)", + [][]byte{{1}, {2}, {3}, {4}, {5}}, + func(stack *txscript.Stack) error { + _, err := stack.PeekInt(5) + return err + }, + txscript.ErrStackUnderflow, + [][]byte{}, + }, + { + "peek underflow (bool)", + [][]byte{{1}, {2}, {3}, {4}, {5}}, + func(stack *txscript.Stack) error { + _, err := stack.PeekBool(5) + return err + }, + txscript.ErrStackUnderflow, + [][]byte{}, + }, + { + "pop", + [][]byte{{1}, {2}, {3}, {4}, {5}}, + func(stack *txscript.Stack) error { + val, err := stack.PopByteArray() + if err != nil { + return err + } + if !bytes.Equal(val, []byte{5}) { + return errors.New("not equal!") + } + return err + }, + nil, + [][]byte{{1}, {2}, {3}, {4}}, + }, + { + "pop", + [][]byte{{1}, {2}, {3}, {4}, {5}}, + func(stack *txscript.Stack) error { + val, err := stack.PopByteArray() + if err != nil { + return err + } + if !bytes.Equal(val, []byte{5}) { + return errors.New("not equal!") + } + return err + }, + nil, + [][]byte{{1}, {2}, {3}, {4}}, + }, + { + "pop everything", + [][]byte{{1}, {2}, {3}, {4}, {5}}, + func(stack *txscript.Stack) error { + for i := 0; i < 5; i++ { + _, err := stack.PopByteArray() + if err != nil { + return err + } + } + return nil + }, + nil, + [][]byte{}, + }, + { + "pop underflow", + [][]byte{{1}, {2}, {3}, {4}, {5}}, + func(stack *txscript.Stack) error { + for i := 0; i < 6; i++ { + _, err := stack.PopByteArray() + if err != nil { + return err + } + } + return nil + }, + txscript.ErrStackUnderflow, + [][]byte{}, + }, + { + "pop bool", + [][]byte{{0}}, + func(stack *txscript.Stack) error { + val, err := stack.PopBool() + if err != nil { + return err + } + + if val != false { + return errors.New("unexpected value") + } + return nil + }, + nil, + [][]byte{}, + }, + { + "pop bool", + [][]byte{{1}}, + func(stack *txscript.Stack) error { + val, err := stack.PopBool() + if err != nil { + return err + } + + if val != true { + return errors.New("unexpected value") + } + return nil + }, + nil, + [][]byte{}, + }, + { + "pop bool", + [][]byte{}, + func(stack *txscript.Stack) error { + _, err := stack.PopBool() + if err != nil { + return err + } + + return nil + }, + txscript.ErrStackUnderflow, + [][]byte{}, + }, + { + "popInt 0", + [][]byte{{0x0}}, + func(stack *txscript.Stack) error { + v, err := stack.PopInt() + if err != nil { + return err + } + if v.Sign() != 0 { + return errors.New("0 != 0 on popInt") + } + return nil + }, + nil, + [][]byte{}, + }, + { + "popInt -0", + [][]byte{{0x80}}, + func(stack *txscript.Stack) error { + v, err := stack.PopInt() + if err != nil { + return err + } + if v.Sign() != 0 { + return errors.New("-0 != 0 on popInt") + } + return nil + }, + nil, + [][]byte{}, + }, + { + "popInt 1", + [][]byte{{0x01}}, + func(stack *txscript.Stack) error { + v, err := stack.PopInt() + if err != nil { + return err + } + if v.Cmp(big.NewInt(1)) != 0 { + return errors.New("1 != 1 on popInt") + } + return nil + }, + nil, + [][]byte{}, + }, + { + "popInt 1 leading 0", + [][]byte{{0x01, 0x00, 0x00, 0x00}}, + func(stack *txscript.Stack) error { + v, err := stack.PopInt() + if err != nil { + return err + } + if v.Cmp(big.NewInt(1)) != 0 { + fmt.Printf("%v != %v\n", v, big.NewInt(1)) + return errors.New("1 != 1 on popInt") + } + return nil + }, + nil, + [][]byte{}, + }, + { + "popInt -1", + [][]byte{{0x81}}, + func(stack *txscript.Stack) error { + v, err := stack.PopInt() + if err != nil { + return err + } + if v.Cmp(big.NewInt(-1)) != 0 { + return errors.New("1 != 1 on popInt") + } + return nil + }, + nil, + [][]byte{}, + }, + { + "popInt -1 leading 0", + [][]byte{{0x01, 0x00, 0x00, 0x80}}, + func(stack *txscript.Stack) error { + v, err := stack.PopInt() + if err != nil { + return err + } + if v.Cmp(big.NewInt(-1)) != 0 { + fmt.Printf("%v != %v\n", v, big.NewInt(-1)) + return errors.New("-1 != -1 on popInt") + } + return nil + }, + nil, + [][]byte{}, + }, + // Triggers the multibyte case in asInt + { + "popInt -513", + [][]byte{{0x1, 0x82}}, + func(stack *txscript.Stack) error { + v, err := stack.PopInt() + if err != nil { + return err + } + if v.Cmp(big.NewInt(-513)) != 0 { + fmt.Printf("%v != %v\n", v, big.NewInt(-513)) + return errors.New("1 != 1 on popInt") + } + return nil + }, + nil, + [][]byte{}, + }, + // Confirm that the asInt code doesn't modify the base data. + { + "peekint nomodify -1", + [][]byte{{0x01, 0x00, 0x00, 0x80}}, + func(stack *txscript.Stack) error { + v, err := stack.PeekInt(0) + if err != nil { + return err + } + if v.Cmp(big.NewInt(-1)) != 0 { + fmt.Printf("%v != %v\n", v, big.NewInt(-1)) + return errors.New("-1 != -1 on popInt") + } + return nil + }, + nil, + [][]byte{{0x01, 0x00, 0x00, 0x80}}, + }, + { + "PushInt 0", + [][]byte{}, + func(stack *txscript.Stack) error { + stack.PushInt(big.NewInt(0)) + return nil + }, + nil, + [][]byte{{}}, + }, + { + "PushInt 1", + [][]byte{}, + func(stack *txscript.Stack) error { + stack.PushInt(big.NewInt(1)) + return nil + }, + nil, + [][]byte{{0x1}}, + }, + { + "PushInt -1", + [][]byte{}, + func(stack *txscript.Stack) error { + stack.PushInt(big.NewInt(-1)) + return nil + }, + nil, + [][]byte{{0x81}}, + }, + { + "PushInt two bytes", + [][]byte{}, + func(stack *txscript.Stack) error { + stack.PushInt(big.NewInt(256)) + return nil + }, + nil, + // little endian.. *sigh* + [][]byte{{0x00, 0x01}}, + }, + { + "PushInt leading zeros", + [][]byte{}, + func(stack *txscript.Stack) error { + // this will have the highbit set + stack.PushInt(big.NewInt(128)) + return nil + }, + nil, + [][]byte{{0x80, 0x00}}, + }, + { + "dup", + [][]byte{{1}}, + func(stack *txscript.Stack) error { + err := stack.DupN(1) + if err != nil { + return err + } + + return nil + }, + nil, + [][]byte{{1}, {1}}, + }, + { + "dup2", + [][]byte{{1}, {2}}, + func(stack *txscript.Stack) error { + err := stack.DupN(2) + if err != nil { + return err + } + + return nil + }, + nil, + [][]byte{{1}, {2}, {1}, {2}}, + }, + { + "dup3", + [][]byte{{1}, {2}, {3}}, + func(stack *txscript.Stack) error { + err := stack.DupN(3) + if err != nil { + return err + } + + return nil + }, + nil, + [][]byte{{1}, {2}, {3}, {1}, {2}, {3}}, + }, + { + "dup0", + [][]byte{{1}}, + func(stack *txscript.Stack) error { + err := stack.DupN(0) + if err != nil { + return err + } + + return nil + }, + txscript.ErrStackInvalidArgs, + [][]byte{}, + }, + { + "dup-1", + [][]byte{{1}}, + func(stack *txscript.Stack) error { + err := stack.DupN(-1) + if err != nil { + return err + } + + return nil + }, + txscript.ErrStackInvalidArgs, + [][]byte{}, + }, + { + "dup too much", + [][]byte{{1}}, + func(stack *txscript.Stack) error { + err := stack.DupN(2) + if err != nil { + return err + } + + return nil + }, + txscript.ErrStackUnderflow, + [][]byte{}, + }, + { + "dup-1", + [][]byte{{1}}, + func(stack *txscript.Stack) error { + err := stack.DupN(-1) + if err != nil { + return err + } + + return nil + }, + txscript.ErrStackInvalidArgs, + [][]byte{}, + }, + { + "PushBool true", + [][]byte{}, + func(stack *txscript.Stack) error { + stack.PushBool(true) + + return nil + }, + nil, + [][]byte{{1}}, + }, + { + "PushBool false", + [][]byte{}, + func(stack *txscript.Stack) error { + stack.PushBool(false) + + return nil + }, + nil, + [][]byte{{0}}, + }, + { + "PushBool PopBool", + [][]byte{}, + func(stack *txscript.Stack) error { + stack.PushBool(true) + val, err := stack.PopBool() + if err != nil { + return err + } + if val != true { + return errors.New("unexpected value") + } + + return nil + }, + nil, + [][]byte{}, + }, + { + "PushBool PopBool 2", + [][]byte{}, + func(stack *txscript.Stack) error { + stack.PushBool(false) + val, err := stack.PopBool() + if err != nil { + return err + } + if val != false { + return errors.New("unexpected value") + } + + return nil + }, + nil, + [][]byte{}, + }, + { + "PushInt PopBool", + [][]byte{}, + func(stack *txscript.Stack) error { + stack.PushInt(big.NewInt(1)) + val, err := stack.PopBool() + if err != nil { + return err + } + if val != true { + return errors.New("unexpected value") + } + + return nil + }, + nil, + [][]byte{}, + }, + { + "PushInt PopBool 2", + [][]byte{}, + func(stack *txscript.Stack) error { + stack.PushInt(big.NewInt(0)) + val, err := stack.PopBool() + if err != nil { + return err + } + if val != false { + return errors.New("unexpected value") + } + + return nil + }, + nil, + [][]byte{}, + }, + { + "PushInt PopBool 2", + [][]byte{}, + func(stack *txscript.Stack) error { + stack.PushInt(big.NewInt(0)) + val, err := stack.PopBool() + if err != nil { + return err + } + if val != false { + return errors.New("unexpected value") + } + + return nil + }, + nil, + [][]byte{}, + }, + { + "Nip top", + [][]byte{{1}, {2}, {3}}, + func(stack *txscript.Stack) error { + return stack.NipN(0) + }, + nil, + [][]byte{{1}, {2}}, + }, + { + "Nip middle", + [][]byte{{1}, {2}, {3}}, + func(stack *txscript.Stack) error { + return stack.NipN(1) + }, + nil, + [][]byte{{1}, {3}}, + }, + { + "Nip low", + [][]byte{{1}, {2}, {3}}, + func(stack *txscript.Stack) error { + return stack.NipN(2) + }, + nil, + [][]byte{{2}, {3}}, + }, + { + "Nip too much", + [][]byte{{1}, {2}, {3}}, + func(stack *txscript.Stack) error { + // bite off more than we can chew + return stack.NipN(3) + }, + txscript.ErrStackUnderflow, + [][]byte{{2}, {3}}, + }, + { + "Nip too much", + [][]byte{{1}, {2}, {3}}, + func(stack *txscript.Stack) error { + // bite off more than we can chew + return stack.NipN(3) + }, + txscript.ErrStackUnderflow, + [][]byte{{2}, {3}}, + }, + { + "keep on tucking", + [][]byte{{1}, {2}, {3}}, + func(stack *txscript.Stack) error { + return stack.Tuck() + }, + nil, + [][]byte{{1}, {3}, {2}, {3}}, + }, + { + "a little tucked up", + [][]byte{{1}}, // too few arguments for tuck + func(stack *txscript.Stack) error { + return stack.Tuck() + }, + txscript.ErrStackUnderflow, + [][]byte{}, + }, + { + "all tucked up", + [][]byte{}, // too few arguments for tuck + func(stack *txscript.Stack) error { + return stack.Tuck() + }, + txscript.ErrStackUnderflow, + [][]byte{}, + }, + { + "drop 1", + [][]byte{{1}, {2}, {3}, {4}}, + func(stack *txscript.Stack) error { + return stack.DropN(1) + }, + nil, + [][]byte{{1}, {2}, {3}}, + }, + { + "drop 2", + [][]byte{{1}, {2}, {3}, {4}}, + func(stack *txscript.Stack) error { + return stack.DropN(2) + }, + nil, + [][]byte{{1}, {2}}, + }, + { + "drop 3", + [][]byte{{1}, {2}, {3}, {4}}, + func(stack *txscript.Stack) error { + return stack.DropN(3) + }, + nil, + [][]byte{{1}}, + }, + { + "drop 4", + [][]byte{{1}, {2}, {3}, {4}}, + func(stack *txscript.Stack) error { + return stack.DropN(4) + }, + nil, + [][]byte{}, + }, + { + "drop 4/5", + [][]byte{{1}, {2}, {3}, {4}}, + func(stack *txscript.Stack) error { + return stack.DropN(5) + }, + txscript.ErrStackUnderflow, + [][]byte{}, + }, + { + "drop invalid", + [][]byte{{1}, {2}, {3}, {4}}, + func(stack *txscript.Stack) error { + return stack.DropN(0) + }, + txscript.ErrStackInvalidArgs, + [][]byte{}, + }, + { + "Rot1", + [][]byte{{1}, {2}, {3}, {4}}, + func(stack *txscript.Stack) error { + return stack.RotN(1) + }, + nil, + [][]byte{{1}, {3}, {4}, {2}}, + }, + { + "Rot2", + [][]byte{{1}, {2}, {3}, {4}, {5}, {6}}, + func(stack *txscript.Stack) error { + return stack.RotN(2) + }, + nil, + [][]byte{{3}, {4}, {5}, {6}, {1}, {2}}, + }, + { + "Rot too little", + [][]byte{{1}, {2}}, + func(stack *txscript.Stack) error { + return stack.RotN(1) + }, + txscript.ErrStackUnderflow, + [][]byte{}, + }, + { + "Rot0", + [][]byte{{1}, {2}, {3}}, + func(stack *txscript.Stack) error { + return stack.RotN(0) + }, + txscript.ErrStackInvalidArgs, + [][]byte{}, + }, + { + "Swap1", + [][]byte{{1}, {2}, {3}, {4}}, + func(stack *txscript.Stack) error { + return stack.SwapN(1) + }, + nil, + [][]byte{{1}, {2}, {4}, {3}}, + }, + { + "Swap2", + [][]byte{{1}, {2}, {3}, {4}}, + func(stack *txscript.Stack) error { + return stack.SwapN(2) + }, + nil, + [][]byte{{3}, {4}, {1}, {2}}, + }, + { + "Swap too little", + [][]byte{{1}}, + func(stack *txscript.Stack) error { + return stack.SwapN(1) + }, + txscript.ErrStackUnderflow, + [][]byte{}, + }, + { + "Swap0", + [][]byte{{1}, {2}, {3}}, + func(stack *txscript.Stack) error { + return stack.SwapN(0) + }, + txscript.ErrStackInvalidArgs, + [][]byte{}, + }, + { + "Over1", + [][]byte{{1}, {2}, {3}, {4}}, + func(stack *txscript.Stack) error { + return stack.OverN(1) + }, + nil, + [][]byte{{1}, {2}, {3}, {4}, {3}}, + }, + { + "Over2", + [][]byte{{1}, {2}, {3}, {4}}, + func(stack *txscript.Stack) error { + return stack.OverN(2) + }, + nil, + [][]byte{{1}, {2}, {3}, {4}, {1}, {2}}, + }, + { + "Over too little", + [][]byte{{1}}, + func(stack *txscript.Stack) error { + return stack.OverN(1) + }, + txscript.ErrStackUnderflow, + [][]byte{}, + }, + { + "Over0", + [][]byte{{1}, {2}, {3}}, + func(stack *txscript.Stack) error { + return stack.OverN(0) + }, + txscript.ErrStackInvalidArgs, + [][]byte{}, + }, + { + "Pick1", + [][]byte{{1}, {2}, {3}, {4}}, + func(stack *txscript.Stack) error { + return stack.PickN(1) + }, + nil, + [][]byte{{1}, {2}, {3}, {4}, {3}}, + }, + { + "Pick2", + [][]byte{{1}, {2}, {3}, {4}}, + func(stack *txscript.Stack) error { + return stack.PickN(2) + }, + nil, + [][]byte{{1}, {2}, {3}, {4}, {2}}, + }, + { + "Pick too little", + [][]byte{{1}}, + func(stack *txscript.Stack) error { + return stack.PickN(1) + }, + txscript.ErrStackUnderflow, + [][]byte{}, + }, + { + "Roll1", + [][]byte{{1}, {2}, {3}, {4}}, + func(stack *txscript.Stack) error { + return stack.RollN(1) + }, + nil, + [][]byte{{1}, {2}, {4}, {3}}, + }, + { + "Roll2", + [][]byte{{1}, {2}, {3}, {4}}, + func(stack *txscript.Stack) error { + return stack.RollN(2) + }, + nil, + [][]byte{{1}, {3}, {4}, {2}}, + }, + { + "Roll too little", + [][]byte{{1}}, + func(stack *txscript.Stack) error { + return stack.RollN(1) + }, + txscript.ErrStackUnderflow, + [][]byte{}, + }, + { + "Peek bool", + [][]byte{{1}}, + func(stack *txscript.Stack) error { + // Peek bool is otherwise pretty well tested, + // just check it works. + val, err := stack.PeekBool(0) + if err != nil { + return err + } + if val != true { + return errors.New("invalid result") + } + return nil + }, + nil, + [][]byte{{1}}, + }, + { + "Peek bool 2", + [][]byte{{0}}, + func(stack *txscript.Stack) error { + // Peek bool is otherwise pretty well tested, + // just check it works. + val, err := stack.PeekBool(0) + if err != nil { + return err + } + if val != false { + return errors.New("invalid result") + } + return nil + }, + nil, + [][]byte{{0}}, + }, + { + "Peek int", + [][]byte{{1}}, + func(stack *txscript.Stack) error { + // Peek int is otherwise pretty well tested, + // just check it works. + val, err := stack.PeekInt(0) + if err != nil { + return err + } + if val.Cmp(big.NewInt(1)) != 0 { + return errors.New("invalid result") + } + return nil + }, + nil, + [][]byte{{1}}, + }, + { + "Peek int 2", + [][]byte{{0}}, + func(stack *txscript.Stack) error { + // Peek int is otherwise pretty well tested, + // just check it works. + val, err := stack.PeekInt(0) + if err != nil { + return err + } + if val.Cmp(big.NewInt(0)) != 0 { + return errors.New("invalid result") + } + return nil + }, + nil, + [][]byte{{0}}, + }, + { + "pop int", + [][]byte{}, + func(stack *txscript.Stack) error { + stack.PushInt(big.NewInt(1)) + // Peek int is otherwise pretty well tested, + // just check it works. + val, err := stack.PopInt() + if err != nil { + return err + } + if val.Cmp(big.NewInt(1)) != 0 { + return errors.New("invalid result") + } + return nil + }, + nil, + [][]byte{}, + }, + { + "pop empty", + [][]byte{}, + func(stack *txscript.Stack) error { + // Peek int is otherwise pretty well tested, + // just check it works. + _, err := stack.PopInt() + return err + }, + txscript.ErrStackUnderflow, + [][]byte{}, + }, + } + + for _, test := range tests { + stack := txscript.Stack{} + + for i := range test.before { + stack.PushByteArray(test.before[i]) + } + err := test.operation(&stack) + if err != test.expectedReturn { + t.Errorf("%s: operation return not what expected: %v "+ + "vs %v", test.name, err, test.expectedReturn) + } + if err != nil { + continue + } + + if len(test.after) != stack.Depth() { + t.Errorf("%s: stack depth doesn't match expected: %v "+ + "vs %v", test.name, len(test.after), + stack.Depth()) + } + + for i := range test.after { + val, err := stack.PeekByteArray(stack.Depth() - i - 1) + if err != nil { + t.Errorf("%s: can't peek %dth stack entry: %v", + test.name, i, err) + break + } + + if !bytes.Equal(val, test.after[i]) { + t.Errorf("%s: %dth stack entry doesn't match "+ + "expected: %v vs %v", test.name, i, val, + test.after[i]) + break + } + } + } +}