2018-06-29 16:58:31 +00:00
|
|
|
// Copyright (c) 2013-2017 The btcsuite developers
|
2019-03-13 06:11:09 +00:00
|
|
|
// Copyright (c) 2015-2019 The Decred developers
|
2013-06-12 21:35:27 +00:00
|
|
|
// Use of this source code is governed by an ISC
|
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
2015-01-30 06:03:01 +00:00
|
|
|
package txscript
|
2013-06-12 21:35:27 +00:00
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bytes"
|
|
|
|
|
"fmt"
|
2019-03-13 06:11:05 +00:00
|
|
|
"strings"
|
2013-06-12 21:35:27 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// These are the constants specified for maximums in individual scripts.
|
|
|
|
|
const (
|
2016-01-20 21:46:42 +00:00
|
|
|
MaxOpsPerScript = 255 // Max number of non-push operations.
|
|
|
|
|
MaxPubKeysPerMultiSig = 20 // Multisig can't have more sigs than this.
|
|
|
|
|
MaxScriptElementSize = 2048 // Max bytes pushable to the stack.
|
2013-06-12 21:35:27 +00:00
|
|
|
)
|
|
|
|
|
|
2014-02-19 22:17:02 +00:00
|
|
|
// isSmallInt returns whether or not the opcode is considered a small integer,
|
|
|
|
|
// which is an OP_0, or OP_1 through OP_16.
|
2019-03-13 06:11:09 +00:00
|
|
|
//
|
|
|
|
|
// NOTE: This function is only valid for version 0 opcodes. Since the function
|
|
|
|
|
// does not accept a script version, the results are undefined for other script
|
|
|
|
|
// versions.
|
|
|
|
|
func isSmallInt(op byte) bool {
|
|
|
|
|
return op == OP_0 || (op >= OP_1 && op <= OP_16)
|
2014-02-19 22:17:02 +00:00
|
|
|
}
|
|
|
|
|
|
2013-06-26 23:32:11 +00:00
|
|
|
// IsPayToScriptHash returns true if the script is in the standard
|
2015-04-29 18:08:56 +00:00
|
|
|
// pay-to-script-hash (P2SH) format, false otherwise.
|
2019-03-13 06:11:14 +00:00
|
|
|
//
|
|
|
|
|
// WARNING: This function always treats the passed script as version 0. Great
|
|
|
|
|
// care must be taken if introducing a new script version because it is used in
|
|
|
|
|
// consensus which, unfortunately as of the time of this writing, does not check
|
|
|
|
|
// script versions before determining if the script is a P2SH which means nodes
|
|
|
|
|
// on existing rules will analyze new version scripts as if they were version 0.
|
2013-06-26 23:32:11 +00:00
|
|
|
func IsPayToScriptHash(script []byte) bool {
|
2019-03-13 06:11:14 +00:00
|
|
|
return isScriptHashScript(script)
|
2013-06-26 23:32:11 +00:00
|
|
|
}
|
|
|
|
|
|
2013-06-12 21:35:27 +00:00
|
|
|
// isPushOnly returns true if the script only pushes data, false otherwise.
|
2019-03-13 06:11:26 +00:00
|
|
|
//
|
|
|
|
|
// DEPRECATED. Use IsPushOnlyScript instead.
|
2013-06-12 21:35:27 +00:00
|
|
|
func isPushOnly(pops []parsedOpcode) bool {
|
2015-04-29 18:08:56 +00:00
|
|
|
// NOTE: This function does NOT verify opcodes directly since it is
|
|
|
|
|
// internal and is only called with parsed opcodes for scripts that did
|
|
|
|
|
// not have any parse errors. Thus, consensus is properly maintained.
|
|
|
|
|
|
2013-06-12 21:35:27 +00:00
|
|
|
for _, pop := range pops {
|
2015-04-29 18:08:56 +00:00
|
|
|
// All opcodes up to OP_16 are data push instructions.
|
|
|
|
|
// NOTE: This does consider OP_RESERVED to be a data push
|
|
|
|
|
// instruction, but execution of OP_RESERVED will fail anyways
|
|
|
|
|
// and matches the behavior required by consensus.
|
|
|
|
|
if pop.opcode.value > OP_16 {
|
2013-06-12 21:35:27 +00:00
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-13 06:11:26 +00:00
|
|
|
// IsPushOnlyScript returns whether or not the passed script only pushes data
|
|
|
|
|
// according to the consensus definition of pushing data.
|
2015-04-29 18:08:56 +00:00
|
|
|
//
|
2019-03-13 06:11:26 +00:00
|
|
|
// WARNING: This function always treats the passed script as version 0. Great
|
|
|
|
|
// care must be taken if introducing a new script version because it is used in
|
|
|
|
|
// consensus which, unfortunately as of the time of this writing, does not check
|
|
|
|
|
// script versions before checking if it is a push only script which means nodes
|
|
|
|
|
// on existing rules will treat new version scripts as if they were version 0.
|
2013-09-27 01:34:25 +00:00
|
|
|
func IsPushOnlyScript(script []byte) bool {
|
2019-03-13 06:11:26 +00:00
|
|
|
const scriptVersion = 0
|
|
|
|
|
tokenizer := MakeScriptTokenizer(scriptVersion, script)
|
|
|
|
|
for tokenizer.Next() {
|
|
|
|
|
// All opcodes up to OP_16 are data push instructions.
|
|
|
|
|
// NOTE: This does consider OP_RESERVED to be a data push instruction,
|
|
|
|
|
// but execution of OP_RESERVED will fail anyway and matches the
|
|
|
|
|
// behavior required by consensus.
|
|
|
|
|
if tokenizer.Opcode() > OP_16 {
|
|
|
|
|
return false
|
|
|
|
|
}
|
2013-09-27 01:34:25 +00:00
|
|
|
}
|
2019-03-13 06:11:26 +00:00
|
|
|
return tokenizer.Err() == nil
|
2013-09-27 01:34:25 +00:00
|
|
|
}
|
|
|
|
|
|
2018-06-29 16:58:08 +00:00
|
|
|
// isStakeOpcode returns whether or not the opcode is one of the stake tagging
|
|
|
|
|
// opcodes.
|
2019-03-13 06:11:12 +00:00
|
|
|
func isStakeOpcode(op byte) bool {
|
|
|
|
|
return op >= OP_SSTX && op <= OP_SSTXCHANGE
|
2018-06-29 16:58:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// isScriptHash returns whether or not the passed script is a regular
|
|
|
|
|
// pay-to-script-hash script.
|
2019-03-13 06:11:14 +00:00
|
|
|
//
|
|
|
|
|
// DEPRECATED. Use isScriptHashScript or extractScriptHash instead.
|
2018-06-29 16:58:08 +00:00
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-13 06:11:14 +00:00
|
|
|
// extractScriptHash extracts the script hash from the passed script if it is a
|
|
|
|
|
// standard pay-to-script-hash script. It will return nil otherwise.
|
|
|
|
|
//
|
|
|
|
|
// NOTE: This function is only valid for version 0 opcodes. Since the function
|
|
|
|
|
// does not accept a script version, the results are undefined for other script
|
|
|
|
|
// versions.
|
|
|
|
|
func extractScriptHash(script []byte) []byte {
|
|
|
|
|
// A pay-to-script-hash script is of the form:
|
|
|
|
|
// OP_HASH160 <20-byte scripthash> OP_EQUAL
|
|
|
|
|
if len(script) == 23 &&
|
|
|
|
|
script[0] == OP_HASH160 &&
|
|
|
|
|
script[1] == OP_DATA_20 &&
|
|
|
|
|
script[22] == OP_EQUAL {
|
|
|
|
|
|
|
|
|
|
return script[2:22]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// isScriptHashScript returns whether or not the passed script is a standard
|
|
|
|
|
// pay-to-script-hash script.
|
|
|
|
|
func isScriptHashScript(script []byte) bool {
|
|
|
|
|
return extractScriptHash(script) != nil
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-13 06:11:24 +00:00
|
|
|
// isStakeScriptHashScript returns whether or not the passed script is a
|
|
|
|
|
// stake-tagged pay-to-script-hash script.
|
|
|
|
|
func isStakeScriptHashScript(script []byte) bool {
|
|
|
|
|
return len(script) == 24 &&
|
|
|
|
|
isStakeOpcode(script[0]) &&
|
|
|
|
|
script[1] == OP_HASH160 &&
|
|
|
|
|
script[2] == OP_DATA_20 &&
|
|
|
|
|
script[23] == OP_EQUAL
|
2018-06-29 16:58:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// isAnyKindOfScriptHash returns whether or not the passed script is either a
|
2019-03-13 06:11:24 +00:00
|
|
|
// regular pay-to-script-hash script or a stake-tagged pay-to-script-hash
|
|
|
|
|
// script.
|
|
|
|
|
func isAnyKindOfScriptHash(script []byte) bool {
|
|
|
|
|
return isScriptHashScript(script) || isStakeScriptHashScript(script)
|
2018-06-29 16:58:08 +00:00
|
|
|
}
|
|
|
|
|
|
2016-02-08 23:29:57 +00:00
|
|
|
// HasP2SHScriptSigStakeOpCodes returns an error is the p2sh script has either
|
|
|
|
|
// stake opcodes or if the pkscript cannot be retrieved.
|
2019-03-13 06:10:57 +00:00
|
|
|
//
|
|
|
|
|
// DEPRECATED. This will be removed in the next major version bump.
|
2018-06-29 16:58:31 +00:00
|
|
|
func HasP2SHScriptSigStakeOpCodes(version uint16, scriptSig, scriptPubKey []byte) error {
|
2016-01-20 21:46:42 +00:00
|
|
|
class := GetScriptClass(version, scriptPubKey)
|
|
|
|
|
if IsStakeOutput(scriptPubKey) {
|
|
|
|
|
class, _ = GetStakeOutSubclass(scriptPubKey)
|
|
|
|
|
}
|
|
|
|
|
if class == ScriptHashTy {
|
|
|
|
|
// Obtain the embedded pkScript from the scriptSig of the
|
|
|
|
|
// current transaction. Then, ensure that it does not use
|
|
|
|
|
// any stake tagging OP codes.
|
2017-08-17 19:42:04 +00:00
|
|
|
pData, err := PushedData(scriptSig)
|
2016-01-20 21:46:42 +00:00
|
|
|
if err != nil {
|
2018-06-29 16:58:31 +00:00
|
|
|
return err
|
2017-08-17 19:42:04 +00:00
|
|
|
}
|
|
|
|
|
if len(pData) == 0 {
|
2018-06-29 16:58:31 +00:00
|
|
|
str := "script has no pushed data"
|
|
|
|
|
return scriptError(ErrNotPushOnly, str)
|
2016-01-20 21:46:42 +00:00
|
|
|
}
|
|
|
|
|
|
2017-08-17 19:42:04 +00:00
|
|
|
// The pay-to-hash-script is the final data push of the
|
|
|
|
|
// signature script.
|
|
|
|
|
shScript := pData[len(pData)-1]
|
|
|
|
|
|
2016-01-20 21:46:42 +00:00
|
|
|
hasStakeOpCodes, err := ContainsStakeOpCodes(shScript)
|
|
|
|
|
if err != nil {
|
2018-06-29 16:58:31 +00:00
|
|
|
return err
|
2016-01-20 21:46:42 +00:00
|
|
|
}
|
|
|
|
|
if hasStakeOpCodes {
|
2018-06-29 16:58:31 +00:00
|
|
|
str := "stake opcodes were found in a p2sh script"
|
|
|
|
|
return scriptError(ErrP2SHStakeOpCodes, str)
|
2016-01-20 21:46:42 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 23:46:34 +00:00
|
|
|
// parseScriptTemplate is the same as parseScript but allows the passing of the
|
2015-04-29 18:08:56 +00:00
|
|
|
// template list for testing purposes. When there are parse errors, it returns
|
|
|
|
|
// the list of parsed opcodes up to the point of failure along with the error.
|
2018-06-29 16:58:31 +00:00
|
|
|
func parseScriptTemplate(script []byte, opcodes *[256]opcode) ([]parsedOpcode, error) {
|
2013-09-25 16:38:20 +00:00
|
|
|
retScript := make([]parsedOpcode, 0, len(script))
|
2013-06-12 21:35:27 +00:00
|
|
|
for i := 0; i < len(script); {
|
|
|
|
|
instr := script[i]
|
2016-04-25 21:17:07 +00:00
|
|
|
op := &opcodes[instr]
|
|
|
|
|
pop := parsedOpcode{opcode: op}
|
2015-04-29 18:08:56 +00:00
|
|
|
|
|
|
|
|
// Parse data out of instruction.
|
2013-06-12 21:35:27 +00:00
|
|
|
switch {
|
2015-04-29 18:08:56 +00:00
|
|
|
// No additional data. Note that some of the opcodes, notably
|
|
|
|
|
// OP_1NEGATE, OP_0, and OP_[1-16] represent the data
|
|
|
|
|
// themselves.
|
2013-06-12 21:35:27 +00:00
|
|
|
case op.length == 1:
|
|
|
|
|
i++
|
2015-04-29 18:08:56 +00:00
|
|
|
|
|
|
|
|
// Data pushes of specific lengths -- OP_DATA_[1-75].
|
2013-06-12 21:35:27 +00:00
|
|
|
case op.length > 1:
|
|
|
|
|
if len(script[i:]) < op.length {
|
2018-06-29 16:58:31 +00:00
|
|
|
str := fmt.Sprintf("opcode %s requires %d "+
|
|
|
|
|
"bytes, but script only has %d remaining",
|
|
|
|
|
op.name, op.length, len(script[i:]))
|
|
|
|
|
return retScript, scriptError(ErrMalformedPush,
|
|
|
|
|
str)
|
2013-06-12 21:35:27 +00:00
|
|
|
}
|
2015-04-29 18:08:56 +00:00
|
|
|
|
|
|
|
|
// Slice out the data.
|
2013-06-12 21:35:27 +00:00
|
|
|
pop.data = script[i+1 : i+op.length]
|
|
|
|
|
i += op.length
|
2015-04-29 18:08:56 +00:00
|
|
|
|
|
|
|
|
// Data pushes with parsed lengths -- OP_PUSHDATAP{1,2,4}.
|
2013-06-12 21:35:27 +00:00
|
|
|
case op.length < 0:
|
|
|
|
|
var l uint
|
|
|
|
|
off := i + 1
|
2014-03-14 20:59:43 +00:00
|
|
|
|
|
|
|
|
if len(script[off:]) < -op.length {
|
2018-06-29 16:58:31 +00:00
|
|
|
str := fmt.Sprintf("opcode %s requires %d "+
|
|
|
|
|
"bytes, but script only has %d remaining",
|
|
|
|
|
op.name, -op.length, len(script[off:]))
|
|
|
|
|
return retScript, scriptError(ErrMalformedPush,
|
|
|
|
|
str)
|
2014-03-14 20:59:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Next -length bytes are little endian length of data.
|
2013-06-12 21:35:27 +00:00
|
|
|
switch op.length {
|
|
|
|
|
case -1:
|
2014-03-14 20:59:43 +00:00
|
|
|
l = uint(script[off])
|
2013-06-12 21:35:27 +00:00
|
|
|
case -2:
|
2014-03-14 20:59:43 +00:00
|
|
|
l = ((uint(script[off+1]) << 8) |
|
|
|
|
|
uint(script[off]))
|
2013-06-12 21:35:27 +00:00
|
|
|
case -4:
|
2014-03-14 20:59:43 +00:00
|
|
|
l = ((uint(script[off+3]) << 24) |
|
|
|
|
|
(uint(script[off+2]) << 16) |
|
|
|
|
|
(uint(script[off+1]) << 8) |
|
|
|
|
|
uint(script[off]))
|
2013-06-12 21:35:27 +00:00
|
|
|
default:
|
2018-06-29 16:58:31 +00:00
|
|
|
str := fmt.Sprintf("invalid opcode length %d",
|
|
|
|
|
op.length)
|
|
|
|
|
return retScript, scriptError(ErrMalformedPush,
|
|
|
|
|
str)
|
2013-06-12 21:35:27 +00:00
|
|
|
}
|
|
|
|
|
|
2015-04-29 18:08:56 +00:00
|
|
|
// Move offset to beginning of the data.
|
|
|
|
|
off += -op.length
|
|
|
|
|
|
2013-10-08 22:21:40 +00:00
|
|
|
// Disallow entries that do not fit script or were
|
|
|
|
|
// sign extended.
|
2013-10-09 00:27:19 +00:00
|
|
|
if int(l) > len(script[off:]) || int(l) < 0 {
|
2018-06-29 16:58:31 +00:00
|
|
|
str := fmt.Sprintf("opcode %s pushes %d bytes, "+
|
|
|
|
|
"but script only has %d remaining",
|
|
|
|
|
op.name, int(l), len(script[off:]))
|
|
|
|
|
return retScript, scriptError(ErrMalformedPush,
|
|
|
|
|
str)
|
2013-06-12 21:35:27 +00:00
|
|
|
}
|
2015-04-29 18:08:56 +00:00
|
|
|
|
2013-06-12 21:35:27 +00:00
|
|
|
pop.data = script[off : off+int(l)]
|
|
|
|
|
i += 1 - op.length + int(l)
|
|
|
|
|
}
|
2015-04-29 18:08:56 +00:00
|
|
|
|
2013-06-12 21:35:27 +00:00
|
|
|
retScript = append(retScript, pop)
|
|
|
|
|
}
|
2015-04-29 18:08:56 +00:00
|
|
|
|
2013-06-12 21:35:27 +00:00
|
|
|
return retScript, nil
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-29 18:08:56 +00:00
|
|
|
// 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, &opcodeArray)
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-12 21:35:27 +00:00
|
|
|
// unparseScript reversed the action of parseScript and returns the
|
|
|
|
|
// parsedOpcodes as a list of bytes
|
2013-09-10 15:39:29 +00:00
|
|
|
func unparseScript(pops []parsedOpcode) ([]byte, error) {
|
2013-09-25 16:38:20 +00:00
|
|
|
script := make([]byte, 0, len(pops))
|
2013-06-12 21:35:27 +00:00
|
|
|
for _, pop := range pops {
|
2013-09-10 15:39:29 +00:00
|
|
|
b, err := pop.bytes()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
script = append(script, b...)
|
2013-06-12 21:35:27 +00:00
|
|
|
}
|
2013-09-10 15:39:29 +00:00
|
|
|
return script, nil
|
2013-06-12 21:35:27 +00:00
|
|
|
}
|
|
|
|
|
|
2015-04-29 18:08:56 +00:00
|
|
|
// 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.
|
2019-03-13 06:11:05 +00:00
|
|
|
//
|
|
|
|
|
// NOTE: This function is only valid for version 0 scripts. Since the function
|
|
|
|
|
// does not accept a script version, the results are undefined for other script
|
|
|
|
|
// versions.
|
|
|
|
|
func DisasmString(script []byte) (string, error) {
|
|
|
|
|
const scriptVersion = 0
|
|
|
|
|
|
|
|
|
|
var disbuf strings.Builder
|
|
|
|
|
tokenizer := MakeScriptTokenizer(scriptVersion, script)
|
|
|
|
|
if tokenizer.Next() {
|
|
|
|
|
disasmOpcode(&disbuf, tokenizer.op, tokenizer.Data(), true)
|
2015-04-29 18:08:56 +00:00
|
|
|
}
|
2019-03-13 06:11:05 +00:00
|
|
|
for tokenizer.Next() {
|
|
|
|
|
disbuf.WriteByte(' ')
|
|
|
|
|
disasmOpcode(&disbuf, tokenizer.op, tokenizer.Data(), true)
|
2015-04-29 18:08:56 +00:00
|
|
|
}
|
2019-03-13 06:11:05 +00:00
|
|
|
if tokenizer.Err() != nil {
|
|
|
|
|
if tokenizer.ByteIndex() != 0 {
|
|
|
|
|
disbuf.WriteByte(' ')
|
|
|
|
|
}
|
2015-09-28 17:56:25 +00:00
|
|
|
disbuf.WriteString("[error]")
|
2015-04-29 18:08:56 +00:00
|
|
|
}
|
2019-03-13 06:11:05 +00:00
|
|
|
return disbuf.String(), tokenizer.Err()
|
2015-04-29 18:08:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// removeOpcodeByData will return the script minus any opcodes that would push
|
|
|
|
|
// the passed data to the stack.
|
2013-06-12 21:35:27 +00:00
|
|
|
func removeOpcodeByData(pkscript []parsedOpcode, data []byte) []parsedOpcode {
|
2013-09-25 16:38:20 +00:00
|
|
|
retScript := make([]parsedOpcode, 0, len(pkscript))
|
2013-06-12 21:35:27 +00:00
|
|
|
for _, pop := range pkscript {
|
2014-03-18 17:54:29 +00:00
|
|
|
if !canonicalPush(pop) || !bytes.Contains(pop.data, data) {
|
2013-06-12 21:35:27 +00:00
|
|
|
retScript = append(retScript, pop)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return retScript
|
|
|
|
|
|
|
|
|
|
}
|
2016-05-13 22:30:56 +00:00
|
|
|
|
2015-04-29 18:08:56 +00:00
|
|
|
// asSmallInt returns the passed opcode, which must be true according to
|
|
|
|
|
// isSmallInt(), as an integer.
|
2019-03-13 06:11:11 +00:00
|
|
|
func asSmallInt(op byte) int {
|
|
|
|
|
if op == OP_0 {
|
2013-07-25 13:27:58 +00:00
|
|
|
return 0
|
2013-06-20 17:07:44 +00:00
|
|
|
}
|
|
|
|
|
|
2019-03-13 06:11:11 +00:00
|
|
|
return int(op - (OP_1 - 1))
|
2013-06-20 17:07:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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.
|
2019-03-13 06:11:20 +00:00
|
|
|
//
|
|
|
|
|
// DEPRECATED. Use countSigOpsV0 instead.
|
2013-06-20 17:07:44 +00:00
|
|
|
func getSigOpCount(pops []parsedOpcode, precise bool) int {
|
|
|
|
|
nSigs := 0
|
|
|
|
|
for i, pop := range pops {
|
|
|
|
|
switch pop.opcode.value {
|
|
|
|
|
case OP_CHECKSIG:
|
2013-06-21 00:33:56 +00:00
|
|
|
fallthrough
|
2013-06-20 17:07:44 +00:00
|
|
|
case OP_CHECKSIGVERIFY:
|
2016-01-20 21:46:42 +00:00
|
|
|
fallthrough
|
|
|
|
|
case OP_CHECKSIGALT:
|
|
|
|
|
fallthrough
|
|
|
|
|
case OP_CHECKSIGALTVERIFY:
|
2013-06-20 17:07:44 +00:00
|
|
|
nSigs++
|
2014-01-04 21:13:29 +00:00
|
|
|
case OP_CHECKMULTISIG:
|
2013-06-21 00:33:56 +00:00
|
|
|
fallthrough
|
2013-06-20 17:07:44 +00:00
|
|
|
case OP_CHECKMULTISIGVERIFY:
|
|
|
|
|
// If we are being precise then look for familiar
|
2016-02-25 17:17:12 +00:00
|
|
|
// patterns for multisig, for now all we recognize is
|
2013-06-21 00:33:56 +00:00
|
|
|
// OP_1 - OP_16 to signify the number of pubkeys.
|
2013-06-20 17:07:44 +00:00
|
|
|
// Otherwise, we use the max of 20.
|
|
|
|
|
if precise && i > 0 &&
|
2013-06-21 00:33:56 +00:00
|
|
|
pops[i-1].opcode.value >= OP_1 &&
|
|
|
|
|
pops[i-1].opcode.value <= OP_16 {
|
2019-03-13 06:11:11 +00:00
|
|
|
nSigs += asSmallInt(pops[i-1].opcode.value)
|
2013-06-20 17:07:44 +00:00
|
|
|
} else {
|
|
|
|
|
nSigs += MaxPubKeysPerMultiSig
|
|
|
|
|
}
|
|
|
|
|
default:
|
2015-04-29 18:08:56 +00:00
|
|
|
// Not a sigop.
|
2013-06-20 17:07:44 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nSigs
|
|
|
|
|
}
|
2013-09-10 15:39:29 +00:00
|
|
|
|
2019-03-13 06:11:20 +00:00
|
|
|
// countSigOpsV0 returns the number of signature operations in the provided
|
|
|
|
|
// script up to the point of the first parse failure or the entire script when
|
|
|
|
|
// there are no parse failures. The precise flag attempts to accurately count
|
|
|
|
|
// the number of operations for a multisig operation versus using the maximum
|
|
|
|
|
// allowed.
|
|
|
|
|
//
|
|
|
|
|
// WARNING: This function always treats the passed script as version 0. Great
|
|
|
|
|
// care must be taken if introducing a new script version because it is used in
|
|
|
|
|
// consensus which, unfortunately as of the time of this writing, does not check
|
|
|
|
|
// script versions before counting their signature operations which means nodes
|
|
|
|
|
// on existing rules will count new version scripts as if they were version 0.
|
|
|
|
|
func countSigOpsV0(script []byte, precise bool) int {
|
|
|
|
|
const scriptVersion = 0
|
|
|
|
|
|
|
|
|
|
numSigOps := 0
|
|
|
|
|
tokenizer := MakeScriptTokenizer(scriptVersion, script)
|
|
|
|
|
prevOp := byte(OP_INVALIDOPCODE)
|
|
|
|
|
for tokenizer.Next() {
|
|
|
|
|
switch tokenizer.Opcode() {
|
|
|
|
|
case OP_CHECKSIG, OP_CHECKSIGVERIFY, OP_CHECKSIGALT,
|
|
|
|
|
OP_CHECKSIGALTVERIFY:
|
|
|
|
|
|
|
|
|
|
numSigOps++
|
|
|
|
|
|
|
|
|
|
case OP_CHECKMULTISIG, OP_CHECKMULTISIGVERIFY:
|
|
|
|
|
// Note that OP_0 is treated as the max number of sigops here in
|
|
|
|
|
// precise mode despite it being a valid small integer in order to
|
|
|
|
|
// highly discourage multisigs with zero pubkeys.
|
|
|
|
|
//
|
|
|
|
|
// Also, even though this is referred to as "precise" counting, it's
|
|
|
|
|
// not really precise at all due to the small int opcodes only
|
|
|
|
|
// covering 1 through 16 pubkeys, which means this will count any
|
|
|
|
|
// more than that value (e.g. 17, 18 19) as the maximum number of
|
|
|
|
|
// allowed pubkeys. This was inherited from bitcoin and is,
|
|
|
|
|
// unfortunately, now part of the consensus rules. This could be
|
|
|
|
|
// made more correct with a new script version, however, ideally all
|
|
|
|
|
// multisignaure operations in new script versions should move to
|
|
|
|
|
// aggregated schemes such as Schnorr instead.
|
|
|
|
|
if precise && prevOp >= OP_1 && prevOp <= OP_16 {
|
|
|
|
|
numSigOps += asSmallInt(prevOp)
|
|
|
|
|
} else {
|
|
|
|
|
numSigOps += MaxPubKeysPerMultiSig
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
// Not a sigop.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
prevOp = tokenizer.Opcode()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return numSigOps
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-29 18:08:56 +00:00
|
|
|
// 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.
|
2019-03-13 06:11:20 +00:00
|
|
|
//
|
|
|
|
|
// WARNING: This function always treats the passed script as version 0. Great
|
|
|
|
|
// care must be taken if introducing a new script version because it is used in
|
|
|
|
|
// consensus which, unfortunately as of the time of this writing, does not check
|
|
|
|
|
// script versions before counting their signature operations which means nodes
|
|
|
|
|
// on existing rules will count new version scripts as if they were version 0.
|
2015-04-29 18:08:56 +00:00
|
|
|
func GetSigOpCount(script []byte) int {
|
2019-03-13 06:11:20 +00:00
|
|
|
return countSigOpsV0(script, false)
|
2015-04-29 18:08:56 +00:00
|
|
|
}
|
|
|
|
|
|
2019-03-13 06:11:18 +00:00
|
|
|
// finalOpcodeData returns the data associated with the final opcode in the
|
|
|
|
|
// script. It will return nil if the script fails to parse.
|
|
|
|
|
func finalOpcodeData(scriptVersion uint16, script []byte) []byte {
|
|
|
|
|
// Avoid unnecessary work.
|
|
|
|
|
if len(script) == 0 {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var data []byte
|
|
|
|
|
tokenizer := MakeScriptTokenizer(scriptVersion, script)
|
|
|
|
|
for tokenizer.Next() {
|
|
|
|
|
data = tokenizer.Data()
|
|
|
|
|
}
|
|
|
|
|
if tokenizer.Err() != nil {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
return data
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-29 18:08:56 +00:00
|
|
|
// 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 {
|
|
|
|
|
// Don't check error since parseScript returns the parsed-up-to-error
|
|
|
|
|
// list of pops.
|
|
|
|
|
pops, _ := parseScript(scriptPubKey)
|
|
|
|
|
|
|
|
|
|
// Treat non P2SH transactions as normal.
|
|
|
|
|
if !(bip16 && isScriptHash(pops)) {
|
|
|
|
|
return getSigOpCount(pops, true)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The public key script is a pay-to-script-hash, so parse the signature
|
|
|
|
|
// script to get the final item. Scripts that fail to fully parse count
|
|
|
|
|
// as 0 signature operations.
|
|
|
|
|
sigPops, err := parseScript(scriptSig)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The signature script must only push data to the stack for P2SH to be
|
|
|
|
|
// a valid pair, so the signature operation count is 0 when that is not
|
|
|
|
|
// the case.
|
|
|
|
|
if !isPushOnly(sigPops) || len(sigPops) == 0 {
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The P2SH script is the last item the signature script pushes to the
|
|
|
|
|
// stack. When the script is empty, there are no signature operations.
|
|
|
|
|
shScript := sigPops[len(sigPops)-1].data
|
|
|
|
|
if len(shScript) == 0 {
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Parse the P2SH script and don't check the error since parseScript
|
|
|
|
|
// returns the parsed-up-to-error list of pops and the consensus rules
|
|
|
|
|
// dictate signature operations are counted up to the first parse
|
|
|
|
|
// failure.
|
|
|
|
|
shPops, _ := parseScript(shScript)
|
|
|
|
|
return getSigOpCount(shPops, true)
|
|
|
|
|
}
|
2015-08-01 14:43:06 +00:00
|
|
|
|
2019-03-13 06:11:07 +00:00
|
|
|
// checkScriptParses returns an error if the provided script fails to parse.
|
|
|
|
|
func checkScriptParses(scriptVersion uint16, script []byte) error {
|
|
|
|
|
tokenizer := MakeScriptTokenizer(scriptVersion, script)
|
|
|
|
|
for tokenizer.Next() {
|
|
|
|
|
// Nothing to do.
|
|
|
|
|
}
|
|
|
|
|
return tokenizer.Err()
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-01 14:43:06 +00:00
|
|
|
// IsUnspendable returns whether the passed public key script is unspendable, or
|
|
|
|
|
// guaranteed to fail at execution. This allows inputs to be pruned instantly
|
2015-08-26 04:03:18 +00:00
|
|
|
// when entering the UTXO set. In Decred, all zero value outputs are unspendable.
|
|
|
|
|
func IsUnspendable(amount int64, pkScript []byte) bool {
|
|
|
|
|
if amount == 0 {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-01 14:43:06 +00:00
|
|
|
pops, err := parseScript(pkScript)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return len(pops) > 0 && pops[0].opcode.value == OP_RETURN
|
|
|
|
|
}
|