You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
472 lines
14 KiB
472 lines
14 KiB
// Copyright (c) 2013-2015 The btcsuite developers |
|
// 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" |
|
"fmt" |
|
"time" |
|
|
|
"github.com/btcsuite/btcd/wire" |
|
) |
|
|
|
// 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 |
|
|
|
// sigHashMask defines the number of bits of the hash type which is used |
|
// to identify which outputs are signed. |
|
sigHashMask = 0x1f |
|
) |
|
|
|
// 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. |
|
) |
|
|
|
// 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 |
|
} |
|
|
|
// isScriptHash returns true if the script passed is a pay-to-script-hash |
|
// transaction, 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 (P2SH) format, false otherwise. |
|
func IsPayToScriptHash(script []byte) bool { |
|
pops, err := parseScript(script) |
|
if err != nil { |
|
return false |
|
} |
|
return isScriptHash(pops) |
|
} |
|
|
|
// isPushOnly returns true if the script only pushes data, false otherwise. |
|
func isPushOnly(pops []parsedOpcode) bool { |
|
// 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. |
|
|
|
for _, pop := range pops { |
|
// 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 { |
|
return false |
|
} |
|
} |
|
return true |
|
} |
|
|
|
// IsPushOnlyScript returns whether or not the passed script only pushes data. |
|
// |
|
// False will be returned when the script does not parse. |
|
func IsPushOnlyScript(script []byte) bool { |
|
pops, err := parseScript(script) |
|
if err != nil { |
|
return false |
|
} |
|
return isPushOnly(pops) |
|
} |
|
|
|
// 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. |
|
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} |
|
|
|
// Parse data out of instruction. |
|
switch { |
|
// No additional data. Note that some of the opcodes, notably |
|
// OP_1NEGATE, OP_0, and OP_[1-16] represent the data |
|
// themselves. |
|
case op.length == 1: |
|
i++ |
|
|
|
// Data pushes of specific lengths -- OP_DATA_[1-75]. |
|
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 |
|
|
|
// Data pushes with parsed lengths -- OP_PUSHDATAP{1,2,4}. |
|
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) |
|
} |
|
|
|
// Move offset to beginning of the data. |
|
off += -op.length |
|
|
|
// 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 |
|
} |
|
|
|
// 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) |
|
} |
|
|
|
// 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 |
|
} |
|
|
|
// 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 |
|
} |
|
|
|
// 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 |
|
} |
|
|
|
// 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. |
|
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 |
|
|
|
} |
|
|
|
// calcSignatureHash will, given a script and hash type for the current script |
|
// engine instance, calculate the signature hash to be used for signing and |
|
// verification. |
|
func calcSignatureHash(script []parsedOpcode, hashType SigHashType, tx *wire.MsgTx, idx int) []byte { |
|
// The SigHashSingle signature type signs only the corresponding input |
|
// and output (the output with the same index number as the input). |
|
// |
|
// Since transactions can have more inputs than outputs, this means it |
|
// is improper to use SigHashSingle on input indices that don't have a |
|
// corresponding output. |
|
// |
|
// A bug in the original Satoshi client implementation means specifying |
|
// an index that is out of range results in a signature hash of 1 (as a |
|
// uint256 little endian). The original intent appeared to be to |
|
// indicate failure, but unfortunately, it was never checked and thus is |
|
// treated as the actual signature hash. This buggy behavior is now |
|
// part of the consensus and a hard fork would be required to fix it. |
|
// |
|
// Due to this, care must be taken by software that creates transactions |
|
// which make use of SigHashSingle because it can lead to an extremely |
|
// dangerous situation where the invalid inputs will end up signing a |
|
// hash of 1. This in turn presents an opportunity for attackers to |
|
// cleverly construct transactions which can steal those coins provided |
|
// they can reuse signatures. |
|
if hashType&sigHashMask == SigHashSingle && idx >= len(tx.TxOut) { |
|
var hash wire.ShaHash |
|
hash[0] = 0x01 |
|
return hash[:] |
|
} |
|
|
|
// Remove all instances of OP_CODESEPARATOR from 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 { |
|
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 = nil |
|
} |
|
} |
|
|
|
switch hashType & sigHashMask { |
|
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: |
|
// 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 = nil |
|
} |
|
|
|
// Sequence on all other inputs is 0, too. |
|
for i := range txCopy.TxIn { |
|
if i != idx { |
|
txCopy.TxIn[i].Sequence = 0 |
|
} |
|
} |
|
|
|
default: |
|
// Consensus 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 |
|
} |
|
|
|
// The final hash is the double sha256 of both the serialized modified |
|
// transaction and the hash type (encoded as a 4-byte little-endian |
|
// value) appended. |
|
var wbuf bytes.Buffer |
|
txCopy.Serialize(&wbuf) |
|
binary.Write(&wbuf, binary.LittleEndian, uint32(hashType)) |
|
return wire.DoubleSha256(wbuf.Bytes()) |
|
} |
|
|
|
// 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)) |
|
} |
|
|
|
// 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 += asSmallInt(pops[i-1].opcode) |
|
} else { |
|
nSigs += MaxPubKeysPerMultiSig |
|
} |
|
default: |
|
// Not a sigop. |
|
} |
|
} |
|
|
|
return nSigs |
|
} |
|
|
|
// 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 { |
|
// 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 { |
|
// 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) |
|
} |
|
|
|
// IsUnspendable returns whether the passed public key script is unspendable, or |
|
// guaranteed to fail at execution. This allows inputs to be pruned instantly |
|
// when entering the UTXO set. |
|
func IsUnspendable(pkScript []byte) bool { |
|
pops, err := parseScript(pkScript) |
|
if err != nil { |
|
return true |
|
} |
|
|
|
return len(pops) > 0 && pops[0].opcode.value == OP_RETURN |
|
}
|
|
|