diff --git a/txscript/engine.go b/txscript/engine.go index 3b30b666..3fd7d5d9 100644 --- a/txscript/engine.go +++ b/txscript/engine.go @@ -259,7 +259,7 @@ func (vm *Engine) verifyWitnessProgram(witness [][]byte) error { if len(witness) != 2 { err := fmt.Sprintf("should have exactly two "+ "items in witness, instead have %v", len(witness)) - return scriptError(ErrWitnessScriptMismatch, err) + return scriptError(ErrWitnessProgramMismatch, err) } // Now we'll resume execution as if it were a regular @@ -280,7 +280,6 @@ func (vm *Engine) verifyWitnessProgram(witness [][]byte) error { vm.SetStack(witness) case payToWitnessScriptHashDataSize: // P2WSH - // Additionally, The witness stack MUST NOT be empty at // this point. if len(witness) == 0 { @@ -303,7 +302,7 @@ func (vm *Engine) verifyWitnessProgram(witness [][]byte) error { // the witness stack matches the witness program. witnessHash := sha256.Sum256(witnessScript) if !bytes.Equal(witnessHash[:], vm.witnessProgram) { - return scriptError(ErrWitnessScriptMismatch, + return scriptError(ErrWitnessProgramMismatch, "witness program hash mismatch") } @@ -330,8 +329,9 @@ func (vm *Engine) verifyWitnessProgram(witness [][]byte) error { return scriptError(ErrWitnessProgramWrongLength, errStr) } } else if vm.hasFlag(ScriptVerifyDiscourageUpgradeableWitnessProgram) { - return fmt.Errorf("new witness program versions invalid: %v", - vm.witnessVersion) + errStr := fmt.Sprintf("new witness program versions "+ + "invalid: %v", vm.witnessProgram) + return scriptError(ErrDiscourageUpgradableWitnessProgram, errStr) } else { // If we encounter an unknown witness program version and we // aren't discouraging future unknown witness based soft-forks, diff --git a/txscript/error.go b/txscript/error.go index a47b9436..08013882 100644 --- a/txscript/error.go +++ b/txscript/error.go @@ -209,6 +209,15 @@ const ( // operations. ErrNullFail + // ErrWitnessMalleated is returned if ScriptVerifyWitness is set and a + // native p2wsh program is encountered which has a non-empty sigScript. + ErrWitnessMalleated + + // ErrWitnessMalleatedP2SH is returned if ScriptVerifyWitness if set + // and the validation logic for nested p2sh encounters a sigScript + // which isn't *exactyl* a datapush of the witness program. + ErrWitnessMalleatedP2SH + // ------------------------------- // Failures related to soft forks. // ------------------------------- @@ -227,34 +236,46 @@ const ( // reached. ErrUnsatisfiedLockTime + // ErrMinimalIf is returned if ScriptVerifyWitness is set and the + // operand of an OP_IF/OP_NOF_IF are not either an empty vector or + // [0x01]. + ErrMinimalIf + + // ErrDiscourageUpgradableWitnessProgram is returned if + // ScriptVerifyWitness is set and the versino of an executing witness + // program is outside the set of currently defined witness program + // vesions. + ErrDiscourageUpgradableWitnessProgram + + // ---------------------------------------- + // Failures related to segregated witness. + // ---------------------------------------- + // ErrWitnessProgramEmpty is returned if ScriptVerifyWitness is set and // the witness stack itself is empty. ErrWitnessProgramEmpty - // ErrWitnessScriptMismatch is returned if ScriptVerifyWitness is set + // ErrWitnessProgramMismatch is returned if ScriptVerifyWitness is set // and the witness itself for a p2wkh witness program isn't *exactly* 2 - // items. - ErrWitnessScriptMismatch + // items or if the witness for a p2wsh isn't the sha255 of the witness + // script. + ErrWitnessProgramMismatch // ErrWitnessProgramWrongLength is returned if ScriptVerifyWitness is // set and the length of the witness program violates the length as // dictated by the current witness version. ErrWitnessProgramWrongLength - // ErrWitnessMalleated is returned if ScriptVerifyWitness is set and a - // native p2wsh program is encountered which has a non-empty sigScript. - ErrWitnessMalleated - - // ErrWitnessMalleatedP2SH is returned if ScriptVerifyWitness if set - // and the validation logic for nested p2sh encounters a sigScript - // which isn't *exactyl* a datapush of the witness program. - ErrWitnessMalleatedP2SH - // ErrWitnessUnexpected is returned if ScriptVerifyWitness is set and a // transaction includes witness data but doesn't spend an which is a // witness program (nested or native). ErrWitnessUnexpected + // ErrWitnessPubKeyType is returned if ScriptVerifyWitness is set and + // the public key used in either a check-sig or check-multi-sig isn't + // serialized in a compressed format. + ErrWitnessPubKeyType + // numErrorCodes is the maximum error code number used in tests. This // entry MUST be the last entry in the enum. numErrorCodes @@ -262,47 +283,56 @@ const ( // Map of ErrorCode values back to their constant names for pretty printing. var errorCodeStrings = map[ErrorCode]string{ - ErrInternal: "ErrInternal", - ErrInvalidFlags: "ErrInvalidFlags", - ErrInvalidIndex: "ErrInvalidIndex", - ErrUnsupportedAddress: "ErrUnsupportedAddress", - ErrNotMultisigScript: "ErrNotMultisigScript", - ErrTooManyRequiredSigs: "ErrTooManyRequiredSigs", - ErrTooMuchNullData: "ErrTooMuchNullData", - ErrEarlyReturn: "ErrEarlyReturn", - ErrEmptyStack: "ErrEmptyStack", - ErrEvalFalse: "ErrEvalFalse", - ErrScriptUnfinished: "ErrScriptUnfinished", - ErrInvalidProgramCounter: "ErrInvalidProgramCounter", - ErrScriptTooBig: "ErrScriptTooBig", - ErrElementTooBig: "ErrElementTooBig", - ErrTooManyOperations: "ErrTooManyOperations", - ErrStackOverflow: "ErrStackOverflow", - ErrInvalidPubKeyCount: "ErrInvalidPubKeyCount", - ErrInvalidSignatureCount: "ErrInvalidSignatureCount", - ErrNumberTooBig: "ErrNumberTooBig", - ErrVerify: "ErrVerify", - ErrEqualVerify: "ErrEqualVerify", - ErrNumEqualVerify: "ErrNumEqualVerify", - ErrCheckSigVerify: "ErrCheckSigVerify", - ErrCheckMultiSigVerify: "ErrCheckMultiSigVerify", - ErrDisabledOpcode: "ErrDisabledOpcode", - ErrReservedOpcode: "ErrReservedOpcode", - ErrMalformedPush: "ErrMalformedPush", - ErrInvalidStackOperation: "ErrInvalidStackOperation", - ErrUnbalancedConditional: "ErrUnbalancedConditional", - ErrMinimalData: "ErrMinimalData", - ErrInvalidSigHashType: "ErrInvalidSigHashType", - ErrSigDER: "ErrSigDER", - ErrSigHighS: "ErrSigHighS", - ErrNotPushOnly: "ErrNotPushOnly", - ErrSigNullDummy: "ErrSigNullDummy", - ErrPubKeyType: "ErrPubKeyType", - ErrCleanStack: "ErrCleanStack", - ErrNullFail: "ErrNullFail", - ErrDiscourageUpgradableNOPs: "ErrDiscourageUpgradableNOPs", - ErrNegativeLockTime: "ErrNegativeLockTime", - ErrUnsatisfiedLockTime: "ErrUnsatisfiedLockTime", + ErrInternal: "ErrInternal", + ErrInvalidFlags: "ErrInvalidFlags", + ErrInvalidIndex: "ErrInvalidIndex", + ErrUnsupportedAddress: "ErrUnsupportedAddress", + ErrNotMultisigScript: "ErrNotMultisigScript", + ErrTooManyRequiredSigs: "ErrTooManyRequiredSigs", + ErrTooMuchNullData: "ErrTooMuchNullData", + ErrEarlyReturn: "ErrEarlyReturn", + ErrEmptyStack: "ErrEmptyStack", + ErrEvalFalse: "ErrEvalFalse", + ErrScriptUnfinished: "ErrScriptUnfinished", + ErrInvalidProgramCounter: "ErrInvalidProgramCounter", + ErrScriptTooBig: "ErrScriptTooBig", + ErrElementTooBig: "ErrElementTooBig", + ErrTooManyOperations: "ErrTooManyOperations", + ErrStackOverflow: "ErrStackOverflow", + ErrInvalidPubKeyCount: "ErrInvalidPubKeyCount", + ErrInvalidSignatureCount: "ErrInvalidSignatureCount", + ErrNumberTooBig: "ErrNumberTooBig", + ErrVerify: "ErrVerify", + ErrEqualVerify: "ErrEqualVerify", + ErrNumEqualVerify: "ErrNumEqualVerify", + ErrCheckSigVerify: "ErrCheckSigVerify", + ErrCheckMultiSigVerify: "ErrCheckMultiSigVerify", + ErrDisabledOpcode: "ErrDisabledOpcode", + ErrReservedOpcode: "ErrReservedOpcode", + ErrMalformedPush: "ErrMalformedPush", + ErrInvalidStackOperation: "ErrInvalidStackOperation", + ErrUnbalancedConditional: "ErrUnbalancedConditional", + ErrMinimalData: "ErrMinimalData", + ErrInvalidSigHashType: "ErrInvalidSigHashType", + ErrSigDER: "ErrSigDER", + ErrSigHighS: "ErrSigHighS", + ErrNotPushOnly: "ErrNotPushOnly", + ErrSigNullDummy: "ErrSigNullDummy", + ErrPubKeyType: "ErrPubKeyType", + ErrCleanStack: "ErrCleanStack", + ErrNullFail: "ErrNullFail", + ErrDiscourageUpgradableNOPs: "ErrDiscourageUpgradableNOPs", + ErrNegativeLockTime: "ErrNegativeLockTime", + ErrUnsatisfiedLockTime: "ErrUnsatisfiedLockTime", + ErrWitnessProgramEmpty: "ErrWitnessProgramEmpty", + ErrWitnessProgramMismatch: "ErrWitnessProgramMismatch", + ErrWitnessProgramWrongLength: "ErrWitnessProgramWrongLength", + ErrWitnessMalleated: "ErrWitnessMalleated", + ErrWitnessMalleatedP2SH: "ErrWitnessMalleatedP2SH", + ErrWitnessUnexpected: "ErrWitnessUnexpected", + ErrMinimalIf: "ErrMinimalIf", + ErrWitnessPubKeyType: "ErrWitnessPubKeyType", + ErrDiscourageUpgradableWitnessProgram: "ErrDiscourageUpgradableWitnessProgram", } // String returns the ErrorCode as a human-readable name. diff --git a/txscript/error_test.go b/txscript/error_test.go index 65731146..74dd9aa8 100644 --- a/txscript/error_test.go +++ b/txscript/error_test.go @@ -57,6 +57,15 @@ func TestErrorCodeStringer(t *testing.T) { {ErrDiscourageUpgradableNOPs, "ErrDiscourageUpgradableNOPs"}, {ErrNegativeLockTime, "ErrNegativeLockTime"}, {ErrUnsatisfiedLockTime, "ErrUnsatisfiedLockTime"}, + {ErrWitnessProgramEmpty, "ErrWitnessProgramEmpty"}, + {ErrWitnessProgramMismatch, "ErrWitnessProgramMismatch"}, + {ErrWitnessProgramWrongLength, "ErrWitnessProgramWrongLength"}, + {ErrWitnessMalleated, "ErrWitnessMalleated"}, + {ErrWitnessMalleatedP2SH, "ErrWitnessMalleatedP2SH"}, + {ErrWitnessUnexpected, "ErrWitnessUnexpected"}, + {ErrMinimalIf, "ErrMinimalIf"}, + {ErrWitnessPubKeyType, "ErrWitnessPubKeyType"}, + {ErrDiscourageUpgradableWitnessProgram, "ErrDiscourageUpgradableWitnessProgram"}, {0xffff, "Unknown ErrorCode (65535)"}, } diff --git a/txscript/standard.go b/txscript/standard.go index 23aaa630..4c31506a 100644 --- a/txscript/standard.go +++ b/txscript/standard.go @@ -446,12 +446,14 @@ func PayToAddrScript(addr btcutil.Address) ([]byte, error) { case *btcutil.AddressWitnessPubKeyHash: if addr == nil { - return nil, ErrUnsupportedAddress + return nil, scriptError(ErrUnsupportedAddress, + nilAddrErrStr) } return payToWitnessPubKeyHashScript(addr.ScriptAddress()) case *btcutil.AddressWitnessScriptHash: if addr == nil { - return nil, ErrUnsupportedAddress + return nil, scriptError(ErrUnsupportedAddress, + nilAddrErrStr) } return payToWitnessScriptHashScript(addr.ScriptAddress()) }