txscript: Implement ScriptVerifyNullFail
ScriptVerifyNullFail defines that signatures must be empty if a CHECKSIG or CHECKMULTISIG operation fails. This commit also enables ScriptVerifyNullFail at the mempool policy level.
This commit is contained in:
parent
153dca5c1e
commit
0efea24aa6
7 changed files with 53 additions and 1 deletions
|
@ -1492,6 +1492,20 @@
|
||||||
"OK",
|
"OK",
|
||||||
"BIP66 example 4, with DERSIG, non-null DER-compliant signature"
|
"BIP66 example 4, with DERSIG, non-null DER-compliant signature"
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
"0",
|
||||||
|
"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT",
|
||||||
|
"DERSIG,NULLFAIL",
|
||||||
|
"OK",
|
||||||
|
"BIP66 example 4, with DERSIG and NULLFAIL"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"0x09 0x300602010102010101",
|
||||||
|
"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT",
|
||||||
|
"DERSIG,NULLFAIL",
|
||||||
|
"NULLFAIL",
|
||||||
|
"BIP66 example 4, with DERSIG and NULLFAIL, non-null DER-compliant signature"
|
||||||
|
],
|
||||||
[
|
[
|
||||||
"1",
|
"1",
|
||||||
"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",
|
"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",
|
||||||
|
@ -1844,5 +1858,15 @@
|
||||||
["4294967296", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY", "UNSATISFIED_LOCKTIME",
|
["4294967296", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY", "UNSATISFIED_LOCKTIME",
|
||||||
"CSV fails if stack top bit 1 << 31 is not set, and tx version < 2"],
|
"CSV fails if stack top bit 1 << 31 is not set, and tx version < 2"],
|
||||||
|
|
||||||
|
["NULLFAIL should cover all signatures and signatures only"],
|
||||||
|
["0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0", "0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT", "DERSIG", "OK", "BIP66 and NULLFAIL-compliant"],
|
||||||
|
["0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0", "0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT", "DERSIG,NULLFAIL", "OK", "BIP66 and NULLFAIL-compliant"],
|
||||||
|
["1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0", "0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT", "DERSIG,NULLFAIL", "OK", "BIP66 and NULLFAIL-compliant, not NULLDUMMY-compliant"],
|
||||||
|
["1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0", "0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT", "DERSIG,NULLFAIL,NULLDUMMY", "SIG_NULLDUMMY", "BIP66 and NULLFAIL-compliant, not NULLDUMMY-compliant"],
|
||||||
|
["0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0x09 0x300602010102010101", "0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT", "DERSIG", "OK", "BIP66-compliant but not NULLFAIL-compliant"],
|
||||||
|
["0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0x09 0x300602010102010101", "0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT", "DERSIG,NULLFAIL", "NULLFAIL", "BIP66-compliant but not NULLFAIL-compliant"],
|
||||||
|
["0 0x09 0x300602010102010101 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0", "0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT", "DERSIG", "OK", "BIP66-compliant but not NULLFAIL-compliant"],
|
||||||
|
["0 0x09 0x300602010102010101 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0", "0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT", "DERSIG,NULLFAIL", "NULLFAIL", "BIP66-compliant but not NULLFAIL-compliant"],
|
||||||
|
|
||||||
["The End"]
|
["The End"]
|
||||||
]
|
]
|
||||||
|
|
|
@ -62,6 +62,10 @@ const (
|
||||||
// push operator. This is both rules 3 and 4 of BIP0062.
|
// push operator. This is both rules 3 and 4 of BIP0062.
|
||||||
ScriptVerifyMinimalData
|
ScriptVerifyMinimalData
|
||||||
|
|
||||||
|
// ScriptVerifyNullFail defines that signatures must be empty if
|
||||||
|
// a CHECKSIG or CHECKMULTISIG operation fails.
|
||||||
|
ScriptVerifyNullFail
|
||||||
|
|
||||||
// ScriptVerifySigPushOnly defines that signature scripts must contain
|
// ScriptVerifySigPushOnly defines that signature scripts must contain
|
||||||
// only pushed data. This is rule 2 of BIP0062.
|
// only pushed data. This is rule 2 of BIP0062.
|
||||||
ScriptVerifySigPushOnly
|
ScriptVerifySigPushOnly
|
||||||
|
|
|
@ -204,6 +204,11 @@ const (
|
||||||
// single element.
|
// single element.
|
||||||
ErrCleanStack
|
ErrCleanStack
|
||||||
|
|
||||||
|
// ErrNullFail is returned when the ScriptVerifyNullFail flag is
|
||||||
|
// set and signatures are not empty on failed checksig or checkmultisig
|
||||||
|
// operations.
|
||||||
|
ErrNullFail
|
||||||
|
|
||||||
// -------------------------------
|
// -------------------------------
|
||||||
// Failures related to soft forks.
|
// Failures related to soft forks.
|
||||||
// -------------------------------
|
// -------------------------------
|
||||||
|
@ -266,6 +271,7 @@ var errorCodeStrings = map[ErrorCode]string{
|
||||||
ErrSigNullDummy: "ErrSigNullDummy",
|
ErrSigNullDummy: "ErrSigNullDummy",
|
||||||
ErrPubKeyType: "ErrPubKeyType",
|
ErrPubKeyType: "ErrPubKeyType",
|
||||||
ErrCleanStack: "ErrCleanStack",
|
ErrCleanStack: "ErrCleanStack",
|
||||||
|
ErrNullFail: "ErrNullFail",
|
||||||
ErrDiscourageUpgradableNOPs: "ErrDiscourageUpgradableNOPs",
|
ErrDiscourageUpgradableNOPs: "ErrDiscourageUpgradableNOPs",
|
||||||
ErrNegativeLockTime: "ErrNegativeLockTime",
|
ErrNegativeLockTime: "ErrNegativeLockTime",
|
||||||
ErrUnsatisfiedLockTime: "ErrUnsatisfiedLockTime",
|
ErrUnsatisfiedLockTime: "ErrUnsatisfiedLockTime",
|
||||||
|
|
|
@ -53,6 +53,7 @@ func TestErrorCodeStringer(t *testing.T) {
|
||||||
{ErrSigNullDummy, "ErrSigNullDummy"},
|
{ErrSigNullDummy, "ErrSigNullDummy"},
|
||||||
{ErrPubKeyType, "ErrPubKeyType"},
|
{ErrPubKeyType, "ErrPubKeyType"},
|
||||||
{ErrCleanStack, "ErrCleanStack"},
|
{ErrCleanStack, "ErrCleanStack"},
|
||||||
|
{ErrNullFail, "ErrNullFail"},
|
||||||
{ErrDiscourageUpgradableNOPs, "ErrDiscourageUpgradableNOPs"},
|
{ErrDiscourageUpgradableNOPs, "ErrDiscourageUpgradableNOPs"},
|
||||||
{ErrNegativeLockTime, "ErrNegativeLockTime"},
|
{ErrNegativeLockTime, "ErrNegativeLockTime"},
|
||||||
{ErrUnsatisfiedLockTime, "ErrUnsatisfiedLockTime"},
|
{ErrUnsatisfiedLockTime, "ErrUnsatisfiedLockTime"},
|
||||||
|
|
|
@ -2084,6 +2084,11 @@ func opcodeCheckSig(op *parsedOpcode, vm *Engine) error {
|
||||||
valid = signature.Verify(hash, pubKey)
|
valid = signature.Verify(hash, pubKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !valid && vm.hasFlag(ScriptVerifyNullFail) && len(sigBytes) > 0 {
|
||||||
|
str := "signature not empty on failed checksig"
|
||||||
|
return scriptError(ErrNullFail, str)
|
||||||
|
}
|
||||||
|
|
||||||
vm.dstack.PushBool(valid)
|
vm.dstack.PushBool(valid)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -2318,6 +2323,15 @@ func opcodeCheckMultiSig(op *parsedOpcode, vm *Engine) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !success && vm.hasFlag(ScriptVerifyNullFail) {
|
||||||
|
for _, sig := range signatures {
|
||||||
|
if len(sig.signature) > 0 {
|
||||||
|
str := "not all signatures empty on failed checkmultisig"
|
||||||
|
return scriptError(ErrNullFail, str)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
vm.dstack.PushBool(success)
|
vm.dstack.PushBool(success)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -160,6 +160,8 @@ func parseScriptFlags(flagStr string) (ScriptFlags, error) {
|
||||||
// Nothing.
|
// Nothing.
|
||||||
case "NULLDUMMY":
|
case "NULLDUMMY":
|
||||||
flags |= ScriptStrictMultiSig
|
flags |= ScriptStrictMultiSig
|
||||||
|
case "NULLFAIL":
|
||||||
|
flags |= ScriptVerifyNullFail
|
||||||
case "P2SH":
|
case "P2SH":
|
||||||
flags |= ScriptBip16
|
flags |= ScriptBip16
|
||||||
case "SIGPUSHONLY":
|
case "SIGPUSHONLY":
|
||||||
|
@ -191,7 +193,7 @@ func parseExpectedResult(expected string) ([]ErrorCode, error) {
|
||||||
case "EQUALVERIFY":
|
case "EQUALVERIFY":
|
||||||
return []ErrorCode{ErrEqualVerify}, nil
|
return []ErrorCode{ErrEqualVerify}, nil
|
||||||
case "NULLFAIL":
|
case "NULLFAIL":
|
||||||
return []ErrorCode{ErrSigNullDummy}, nil
|
return []ErrorCode{ErrNullFail}, nil
|
||||||
case "SIG_HIGH_S":
|
case "SIG_HIGH_S":
|
||||||
return []ErrorCode{ErrSigHighS}, nil
|
return []ErrorCode{ErrSigHighS}, nil
|
||||||
case "SIG_HASHTYPE":
|
case "SIG_HASHTYPE":
|
||||||
|
|
|
@ -33,6 +33,7 @@ const (
|
||||||
ScriptStrictMultiSig |
|
ScriptStrictMultiSig |
|
||||||
ScriptDiscourageUpgradableNops |
|
ScriptDiscourageUpgradableNops |
|
||||||
ScriptVerifyCleanStack |
|
ScriptVerifyCleanStack |
|
||||||
|
ScriptVerifyNullFail |
|
||||||
ScriptVerifyCheckLockTimeVerify |
|
ScriptVerifyCheckLockTimeVerify |
|
||||||
ScriptVerifyCheckSequenceVerify |
|
ScriptVerifyCheckSequenceVerify |
|
||||||
ScriptVerifyLowS
|
ScriptVerifyLowS
|
||||||
|
|
Loading…
Reference in a new issue