txscript: Correct nulldata standardness check.

This corrects the isNullData standard transaction type test to work
properly with canonically-encoded data pushes.  In particular, single
byte data pushes that are small integers (0-16) are converted to the
equivalent numeric opcodes when canonically encoded and the code failed
to detect them properly.

It also adds several tests to ensure that both canonical and
non-canonical nulldata scripts are recognized properly and modifies the
test failure print to include the script that failed.

This does not affect consensus since it is just a standardness check.
This commit is contained in:
Dave Collins 2016-10-19 22:50:53 -05:00
parent 07e1e308f1
commit b60e3547d2
2 changed files with 53 additions and 21 deletions

View file

@ -138,7 +138,8 @@ func isNullData(pops []parsedOpcode) bool {
return l == 2 && return l == 2 &&
pops[0].opcode.value == OP_RETURN && pops[0].opcode.value == OP_RETURN &&
pops[1].opcode.value <= OP_PUSHDATA4 && (isSmallInt(pops[1].opcode) || pops[1].opcode.value <=
OP_PUSHDATA4) &&
len(pops[1].data) <= MaxDataCarrierSize len(pops[1].data) <= MaxDataCarrierSize
} }

View file

@ -804,19 +804,15 @@ func TestCalcMultiSigStats(t *testing.T) {
} }
} }
// scriptClassTest houses a test used to ensure various scripts have the
// expected class.
type scriptClassTest struct {
name string
script string
class txscript.ScriptClass
}
// scriptClassTests houses several test scripts used to ensure various class // scriptClassTests houses several test scripts used to ensure various class
// determination is working as expected. It's defined as a test global versus // determination is working as expected. It's defined as a test global versus
// inside a function scope since this spans both the standard tests and the // inside a function scope since this spans both the standard tests and the
// consensus tests (pay-to-script-hash is part of consensus). // consensus tests (pay-to-script-hash is part of consensus).
var scriptClassTests = []scriptClassTest{ var scriptClassTests = []struct {
name string
script string
class txscript.ScriptClass
}{
{ {
name: "Pay Pubkey", name: "Pay Pubkey",
script: "DATA_65 0x0411db93e1dcdb8a016b49840f8c53bc1eb68a382e" + script: "DATA_65 0x0411db93e1dcdb8a016b49840f8c53bc1eb68a382e" +
@ -847,21 +843,56 @@ var scriptClassTests = []scriptClassTest{
"9ae88 EQUAL", "9ae88 EQUAL",
class: txscript.ScriptHashTy, class: txscript.ScriptHashTy,
}, },
{ {
// Nulldata with no data at all. // Nulldata with no data at all.
name: "nulldata", name: "nulldata no data",
script: "RETURN", script: "RETURN",
class: txscript.NullDataTy, class: txscript.NullDataTy,
}, },
{ {
// Nulldata with small data. // Nulldata with single zero push.
name: "nulldata2", name: "nulldata zero",
script: "RETURN 0",
class: txscript.NullDataTy,
},
{
// Nulldata with small integer push.
name: "nulldata small int",
script: "RETURN 1",
class: txscript.NullDataTy,
},
{
// Nulldata with max small integer push.
name: "nulldata max small int",
script: "RETURN 16",
class: txscript.NullDataTy,
},
{
// Nulldata with small data push.
name: "nulldata small data",
script: "RETURN DATA_8 0x046708afdb0fe554", script: "RETURN DATA_8 0x046708afdb0fe554",
class: txscript.NullDataTy, class: txscript.NullDataTy,
}, },
{ {
// Nulldata with max allowed data. // Canonical nulldata with 60-byte data push.
name: "nulldata3", name: "canonical nulldata 60-byte push",
script: "RETURN 0x3c 0x046708afdb0fe5548271967f1a67130b7105cd" +
"6a828e03909a67962e0ea1f61deb649f6bc3f4cef3046708afdb" +
"0fe5548271967f1a67130b7105cd6a",
class: txscript.NullDataTy,
},
{
// Non-canonical nulldata with 60-byte data push.
name: "non-canonical nulldata 60-byte push",
script: "RETURN PUSHDATA1 0x3c 0x046708afdb0fe5548271967f1a67" +
"130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3" +
"046708afdb0fe5548271967f1a67130b7105cd6a",
class: txscript.NullDataTy,
},
{
// Nulldata with max allowed data to be considered standard.
name: "nulldata max standard push",
script: "RETURN PUSHDATA1 0x50 0x046708afdb0fe5548271967f1a67" + script: "RETURN PUSHDATA1 0x50 0x046708afdb0fe5548271967f1a67" +
"130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3" + "130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3" +
"046708afdb0fe5548271967f1a67130b7105cd6a828e03909a67" + "046708afdb0fe5548271967f1a67130b7105cd6a828e03909a67" +
@ -869,9 +900,9 @@ var scriptClassTests = []scriptClassTest{
class: txscript.NullDataTy, class: txscript.NullDataTy,
}, },
{ {
// Nulldata with more than max allowed data (so therefore // Nulldata with more than max allowed data to be considered
// nonstandard) // standard (so therefore nonstandard)
name: "nulldata4", name: "nulldata exceed max standard push",
script: "RETURN PUSHDATA1 0x51 0x046708afdb0fe5548271967f1a67" + script: "RETURN PUSHDATA1 0x51 0x046708afdb0fe5548271967f1a67" +
"130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3" + "130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3" +
"046708afdb0fe5548271967f1a67130b7105cd6a828e03909a67" + "046708afdb0fe5548271967f1a67130b7105cd6a828e03909a67" +
@ -881,7 +912,7 @@ var scriptClassTests = []scriptClassTest{
{ {
// Almost nulldata, but add an additional opcode after the data // Almost nulldata, but add an additional opcode after the data
// to make it nonstandard. // to make it nonstandard.
name: "nulldata5", name: "almost nulldata",
script: "RETURN 4 TRUE", script: "RETURN 4 TRUE",
class: txscript.NonStandardTy, class: txscript.NonStandardTy,
}, },
@ -951,8 +982,8 @@ func TestScriptClass(t *testing.T) {
script := mustParseShortForm(test.script) script := mustParseShortForm(test.script)
class := txscript.GetScriptClass(script) class := txscript.GetScriptClass(script)
if class != test.class { if class != test.class {
t.Errorf("%s: expected %s got %s", test.name, t.Errorf("%s: expected %s got %s (script %x)", test.name,
test.class, class) test.class, class, script)
return return
} }
} }