Allow multi-sig scripts with zero signatures.
This commit builds off the previous commit which fixed the execution of multi-signature scripts with zero required signatures. It introduces the concept of a "small int" which is one of OP_0 or OP_1 - OP_16. All areas of code that deal with multi-sig transactions now make use of these to ensure consistent handling. This fixes a few issues surrounding multi-sig zero required signature transactions included proper detection as a multi-sig script, signature counting for script statistics, and ok @owainga
This commit is contained in:
parent
1d360509f4
commit
37a45ec683
2 changed files with 30 additions and 13 deletions
|
@ -65,8 +65,8 @@ func ExtractPkScriptAddrs(pkScript []byte, net btcwire.BitcoinNet) (ScriptClass,
|
|||
// 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 = int(pops[0].opcode.value - (OP_1 - 1))
|
||||
numPubKeys := int(pops[len(pops)-2].opcode.value - (OP_1 - 1))
|
||||
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)
|
||||
|
|
39
script.go
39
script.go
|
@ -192,6 +192,15 @@ type Script struct {
|
|||
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 {
|
||||
|
@ -237,16 +246,14 @@ func IsPayToScriptHash(script []byte) bool {
|
|||
func isMultiSig(pops []parsedOpcode) bool {
|
||||
l := len(pops)
|
||||
// absolute minimum is 1 pubkey so
|
||||
// OP_1-16, pubkey, OP_1, OP_CHECKMULTISIG
|
||||
// OP_0/OP_1-16, pubkey, OP_1, OP_CHECKMULTISIG
|
||||
if l < 4 {
|
||||
return false
|
||||
}
|
||||
if pops[0].opcode.value < OP_1 ||
|
||||
pops[0].opcode.value > OP_16 {
|
||||
if !isSmallInt(pops[0].opcode) {
|
||||
return false
|
||||
}
|
||||
if pops[l-2].opcode.value < OP_1 ||
|
||||
pops[l-2].opcode.value > OP_16 {
|
||||
if !isSmallInt(pops[l-2].opcode) {
|
||||
return false
|
||||
}
|
||||
if pops[l-1].opcode.value != OP_CHECKMULTISIG {
|
||||
|
@ -1096,10 +1103,10 @@ func expectedInputs(pops []parsedOpcode, class ScriptClass) int {
|
|||
case MultiSigTy:
|
||||
// Standard multisig has a push a small number for the number
|
||||
// of sigs and number of keys.
|
||||
// Check the first push instrution to see how many arguments are
|
||||
// expected. typoeOfScript already checked this so that we know
|
||||
// it'll be one of OP_1 - OP_16.
|
||||
return int(pops[0].opcode.value - (OP_1 - 1))
|
||||
// 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.
|
||||
return asSmallInt(pops[0].opcode)
|
||||
case NullDataTy:
|
||||
fallthrough
|
||||
default:
|
||||
|
@ -1176,6 +1183,16 @@ func CalcScriptInfo(sigscript, pkscript []byte, bip16 bool) (*ScriptInfo, error)
|
|||
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.
|
||||
|
@ -1196,7 +1213,7 @@ func CalcMultiSigStats(script []byte) (int, int, error) {
|
|||
return 0, 0, StackErrUnderflow
|
||||
}
|
||||
|
||||
numSigs := int(pops[0].opcode.value - (OP_1 - 1))
|
||||
numPubKeys := int(pops[len(pops)-2].opcode.value - (OP_1 - 1))
|
||||
numSigs := asSmallInt(pops[0].opcode)
|
||||
numPubKeys := asSmallInt(pops[len(pops)-2].opcode)
|
||||
return numPubKeys, numSigs, nil
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue