// checkPkScriptStandard performs a series of checks on a transaction ouput // script (public key script) to ensure it is a "standard" public key script. // A standard public key script is one that is a recognized form, and for // multi-signature scripts, only contains from 1 to maxStandardMultiSigKeys // public keys. func checkPkScriptStandard(version uint16, pkScript []byte, scriptClass txscript.ScriptClass) error { // Only default Bitcoin-style script is standard except for // null data outputs. if version != wire.DefaultPkScriptVersion { str := fmt.Sprintf("versions other than default pkscript version " + "are currently non-standard except for provably unspendable " + "outputs") return txRuleError(wire.RejectNonstandard, str) } switch scriptClass { case txscript.MultiSigTy: numPubKeys, numSigs, err := txscript.CalcMultiSigStats(pkScript) if err != nil { str := fmt.Sprintf("multi-signature script parse "+ "failure: %v", err) return txRuleError(wire.RejectNonstandard, str) } // A standard multi-signature public key script must contain // from 1 to maxStandardMultiSigKeys public keys. if numPubKeys < 1 { str := "multi-signature script with no pubkeys" return txRuleError(wire.RejectNonstandard, str) } if numPubKeys > maxStandardMultiSigKeys { str := fmt.Sprintf("multi-signature script with %d "+ "public keys which is more than the allowed "+ "max of %d", numPubKeys, maxStandardMultiSigKeys) return txRuleError(wire.RejectNonstandard, str) } // A standard multi-signature public key script must have at // least 1 signature and no more signatures than available // public keys. if numSigs < 1 { return txRuleError(wire.RejectNonstandard, "multi-signature script with no signatures") } if numSigs > numPubKeys { str := fmt.Sprintf("multi-signature script with %d "+ "signatures which is more than the available "+ "%d public keys", numSigs, numPubKeys) return txRuleError(wire.RejectNonstandard, str) } case txscript.NonStandardTy: return txRuleError(wire.RejectNonstandard, "non-standard script form") } return nil }
// TestCalcMultiSigStats ensures the CalcMutliSigStats function returns the // expected errors. func TestCalcMultiSigStats(t *testing.T) { t.Parallel() tests := []struct { name string script string err error }{ { name: "short script", script: "0x046708afdb0fe5548271967f1a67130b7105cd6a828" + "e03909a67962e0ea1f61d", err: txscript.ErrStackShortScript, }, { name: "stack underflow", script: "RETURN DATA_41 0x046708afdb0fe5548271967f1a" + "67130b7105cd6a828e03909a67962e0ea1f61deb649f6" + "bc3f4cef308", err: txscript.ErrStackUnderflow, }, { name: "multisig script", script: "0 DATA_72 0x30450220106a3e4ef0b51b764a2887226" + "2ffef55846514dacbdcbbdd652c849d395b4384022100" + "e03ae554c3cbb40600d31dd46fc33f25e47bf8525b1fe" + "07282e3b6ecb5f3bb2801 CODESEPARATOR 1 DATA_33 " + "0x0232abdc893e7f0631364d7fd01cb33d24da45329a0" + "0357b3a7886211ab414d55a 1 CHECKMULTISIG", err: nil, }, } for i, test := range tests { script := mustParseShortForm(test.script) if _, _, err := txscript.CalcMultiSigStats(script); err != test.err { t.Errorf("CalcMultiSigStats #%d (%s) unexpected "+ "error\ngot: %v\nwant: %v", i, test.name, err, test.err) } } }