func parseScriptTemplate(script []byte, opcodes *[256]Opcode) ([]ParsedOpcode, error) {
	retScript := make([]ParsedOpcode, 0, len(script))
	for i := 0; i < len(script); {
		instr := script[i]
		op := &opcodes[instr]
		pop := ParsedOpcode{Opcode: op}
		switch {
		case op.Length == 1:
			i++
		case op.Length > 1:
			if len(script[i:]) < op.Length {
				str := fmt.Sprintf("Opcode %s requires %d "+
					"bytes, but script only has %d remaining",
					op.Name, op.Length, len(script[i:]))
				return nil, errors.New(str)
			}
			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 {
				str := fmt.Sprintf("Opcode %s requires %d "+
					"bytes, but script only has %d remaining",
					op.Name, -op.Length, len(script[off:]))
				return nil, errors.New(str)
			}
			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:
				str := fmt.Sprintf("invalid Opcode Length %d",
					op.Length)
				return nil, errors.New(str)
			}
			off += -op.Length
			if int(l) > len(script[off:]) || int(l) < 0 {
				str := fmt.Sprintf("Opcode %s pushes %d bytes, "+
					"but script only has %d remaining",
					op.Name, int(l), len(script[off:]))
				return nil, errors.New(str)
			}
			pop.Data = script[off : off+int(l)]
			i += 1 - op.Length + int(l)
		}
		retScript = append(retScript, pop)
	}
	return retScript, nil
}
parseScriptTemplate is the same as parseScript but allows the passing of the
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.
package address
import (
	"errors"
	"fmt"
	"github.com/btcsuite/btcd/txscript"
)
type ScriptClass byte
const (
	NonStandardTy         ScriptClass = iota  
	PubKeyTy                                  
	PubKeyHashTy                              
	WitnessV0PubKeyHashTy                     
	ScriptHashTy                              
	WitnessV0ScriptHashTy                     
	MultiSigTy                                
	NullDataTy                                
)
const (
	MaxDataCarrierSize = 80
)
func ParseScript(script []byte) ([]ParsedOpcode, error) {
	return parseScriptTemplate(script, &opcodeArray)
}
func TypeOfScript(pops []ParsedOpcode) ScriptClass {
	if IsPubkey(pops) {
		return PubKeyTy
	} else if IsPubkeyHash(pops) {
		return PubKeyHashTy
	} else if IsWitnessPubKeyHash(pops) {
		return WitnessV0PubKeyHashTy
	} else if IsScriptHash(pops) {
		return ScriptHashTy
	} else if IsWitnessScriptHash(pops) {
		return WitnessV0ScriptHashTy
	} else if IsMultiSig(pops) {
		return MultiSigTy
	} else if isNullData(pops) {
		return NullDataTy
	}
	return NonStandardTy
}
func IsPubkey(pops []ParsedOpcode) bool {
	return len(pops) == 2 &&
		(len(pops[0].Data) == 33 || len(pops[0].Data) == 65) &&
		pops[1].Opcode.Value == txscript.OP_CHECKSIG
}
func IsPubkeyHash(pops []ParsedOpcode) bool {
	return len(pops) == 5 &&
		pops[0].Opcode.Value == txscript.OP_DUP &&
		pops[1].Opcode.Value == txscript.OP_HASH160 &&
		pops[2].Opcode.Value == txscript.OP_DATA_20 &&
		pops[3].Opcode.Value == txscript.OP_EQUALVERIFY &&
		pops[4].Opcode.Value == txscript.OP_CHECKSIG
}
func IsMultiSig(pops []ParsedOpcode) bool {
	l := len(pops)
	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 != txscript.OP_CHECKMULTISIG {
		return false
	}
	if l-2-1 != asSmallInt(pops[l-2].Opcode) {
		return false
	}
	for _, pop := range pops[1 : l-2] {
		if len(pop.Data) != 33 && len(pop.Data) != 65 {
			return false
		}
	}
	return true
}
func IsWitnessPubKeyHash(pops []ParsedOpcode) bool {
	return len(pops) == 2 &&
		pops[0].Opcode.Value == txscript.OP_0 &&
		pops[1].Opcode.Value == txscript.OP_DATA_20
}
func isSmallInt(op *Opcode) bool {
	if op.Value == txscript.OP_0 || (op.Value >= txscript.OP_1 && op.Value <= txscript.OP_16) {
		return true
	}
	return false
}
func IsScriptHash(pops []ParsedOpcode) bool {
	return len(pops) == 3 &&
		pops[0].Opcode.Value == txscript.OP_HASH160 &&
		pops[1].Opcode.Value == txscript.OP_DATA_20 &&
		pops[2].Opcode.Value == txscript.OP_EQUAL
}
func IsWitnessScriptHash(pops []ParsedOpcode) bool {
	return len(pops) == 2 &&
		pops[0].Opcode.Value == txscript.OP_0 &&
		pops[1].Opcode.Value == txscript.OP_DATA_32
}
func isNullData(pops []ParsedOpcode) bool {
	l := len(pops)
	if l == 1 && pops[0].Opcode.Value == txscript.OP_RETURN {
		return true
	}
	return l == 2 &&
		pops[0].Opcode.Value == txscript.OP_RETURN &&
		(isSmallInt(pops[1].Opcode) || pops[1].Opcode.Value <=
			txscript.OP_PUSHDATA4) &&
		len(pops[1].Data) <= MaxDataCarrierSize
}
func asSmallInt(op *Opcode) int {
	if op.Value == txscript.OP_0 {
		return 0
	}
	return int(op.Value - (txscript.OP_1 - 1))
}