[NOD-223] Removed Nulldata as standard tx type (#329)

* [NOD-223] Removed Nulldata as standard tx type

* [NOD-223] Removed redundant space
This commit is contained in:
Svarog 2019-06-16 16:31:38 +03:00 committed by Ori Newman
parent ffd886498a
commit 0c5f3d72bd
8 changed files with 8 additions and 255 deletions

View File

@ -162,11 +162,6 @@ func TestScriptCompression(t *testing.T) {
uncompressed: hexToBytes("3302aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaac"),
compressed: hexToBytes("293302aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaac"),
},
{
name: "null data",
uncompressed: hexToBytes("6a200102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20"),
compressed: hexToBytes("286a200102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20"),
},
{
name: "requires 2 size bytes - data push 200 bytes",
uncompressed: append(hexToBytes("4cc8"), bytes.Repeat([]byte{0x00}, 200)...),
@ -265,7 +260,7 @@ func TestAmountCompression(t *testing.T) {
compressed uint64
}{
{
name: "0 BTC (sometimes used in nulldata)",
name: "0 BTC",
uncompressed: 0,
compressed: 0,
},
@ -343,12 +338,6 @@ func TestCompressedTxOut(t *testing.T) {
pkScript []byte
compressed []byte
}{
{
name: "nulldata with 0 BTC",
amount: 0,
pkScript: hexToBytes("6a200102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20"),
compressed: hexToBytes("00286a200102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20"),
},
{
name: "pay-to-pubkey-hash dust",
amount: 546,

View File

@ -303,8 +303,7 @@ func checkTransactionStandard(tx *util.Tx, blueScore uint64,
}
// None of the output public key scripts can be a non-standard script or
// be "dust" (except when the script is a null data script).
numNullDataOutputs := 0
// be "dust".
for i, txOut := range msgTx.TxOut {
scriptClass := txscript.GetScriptClass(txOut.PkScript)
err := checkPkScriptStandard(txOut.PkScript, scriptClass)
@ -320,24 +319,12 @@ func checkTransactionStandard(tx *util.Tx, blueScore uint64,
return txRuleError(rejectCode, str)
}
// Accumulate the number of outputs which only carry data. For
// all other script types, ensure the output value is not
// "dust".
if scriptClass == txscript.NullDataTy {
numNullDataOutputs++
} else if isDust(txOut, policy.MinRelayTxFee) {
if isDust(txOut, policy.MinRelayTxFee) {
str := fmt.Sprintf("transaction output %d: payment "+
"of %d is dust", i, txOut.Value)
return txRuleError(wire.RejectDust, str)
}
}
// A standard transaction must not have more than one output script that
// only carries data.
if numNullDataOutputs > 1 {
str := "more than one transaction output in a nulldata script"
return txRuleError(wire.RejectNonstandard, str)
}
return nil
}

View File

@ -380,19 +380,6 @@ func TestCheckTransactionStandard(t *testing.T) {
isStandard: false,
code: wire.RejectNonstandard,
},
{
name: "More than one nulldata output",
tx: wire.NewNativeMsgTx(1, []*wire.TxIn{&dummyTxIn}, []*wire.TxOut{{
Value: 0,
PkScript: []byte{txscript.OpReturn},
}, {
Value: 0,
PkScript: []byte{txscript.OpReturn},
}}),
height: 300000,
isStandard: false,
code: wire.RejectNonstandard,
},
{
name: "Dust output",
tx: wire.NewNativeMsgTx(1, []*wire.TxIn{&dummyTxIn}, []*wire.TxOut{{
@ -404,13 +391,14 @@ func TestCheckTransactionStandard(t *testing.T) {
code: wire.RejectDust,
},
{
name: "One nulldata output with 0 amount (standard)",
name: "Nulldata transaction",
tx: wire.NewNativeMsgTx(1, []*wire.TxIn{&dummyTxIn}, []*wire.TxOut{{
Value: 0,
PkScript: []byte{txscript.OpReturn},
}}),
height: 300000,
isStandard: true,
isStandard: false,
code: wire.RejectNonstandard,
},
}

View File

@ -43,10 +43,6 @@ const (
// provided public keys.
ErrTooManyRequiredSigs
// ErrTooMuchNullData is returned from NullDataScript when the length of
// the provided data exceeds MaxDataCarrierSize.
ErrTooMuchNullData
// ------------------------------------------
// Failures related to final execution state.
// ------------------------------------------
@ -239,7 +235,6 @@ var errorCodeStrings = map[ErrorCode]string{
ErrUnsupportedAddress: "ErrUnsupportedAddress",
ErrNotMultisigScript: "ErrNotMultisigScript",
ErrTooManyRequiredSigs: "ErrTooManyRequiredSigs",
ErrTooMuchNullData: "ErrTooMuchNullData",
ErrEarlyReturn: "ErrEarlyReturn",
ErrEmptyStack: "ErrEmptyStack",
ErrEvalFalse: "ErrEvalFalse",

View File

@ -21,7 +21,6 @@ func TestErrorCodeStringer(t *testing.T) {
{ErrInvalidIndex, "ErrInvalidIndex"},
{ErrUnsupportedAddress, "ErrUnsupportedAddress"},
{ErrTooManyRequiredSigs, "ErrTooManyRequiredSigs"},
{ErrTooMuchNullData, "ErrTooMuchNullData"},
{ErrNotMultisigScript, "ErrNotMultisigScript"},
{ErrEarlyReturn, "ErrEarlyReturn"},
{ErrEmptyStack, "ErrEmptyStack"},

View File

@ -146,9 +146,6 @@ func sign(chainParams *dagconfig.Params, tx *wire.MsgTx, idx int,
signedScript, _ := signMultiSig(tx, idx, script, hashType,
addresses, nrequired, kdb)
return signedScript, class, addresses, nrequired, nil
case NullDataTy:
return nil, class, nil, 0,
errors.New("can't sign NULLDATA transactions")
default:
return nil, class, nil, 0,
errors.New("can't sign unknown transactions")

View File

@ -12,10 +12,6 @@ import (
)
const (
// MaxDataCarrierSize is the maximum number of bytes allowed in pushed
// data to be considered a nulldata transaction
MaxDataCarrierSize = 80
// StandardVerifyFlags are the script flags which are used when
// executing transaction scripts to enforce additional checks which
// are required for the script to be considered standard. These checks
@ -39,7 +35,6 @@ const (
PubKeyHashTy // Pay pubkey hash.
ScriptHashTy // Pay to script hash.
MultiSigTy // Multi signature.
NullDataTy // Empty data-only (provably prunable).
)
// scriptClassToName houses the human-readable strings which describe each
@ -50,7 +45,6 @@ var scriptClassToName = []string{
PubKeyHashTy: "pubkeyhash",
ScriptHashTy: "scripthash",
MultiSigTy: "multisig",
NullDataTy: "nulldata",
}
// String implements the Stringer interface by returning the name of
@ -118,24 +112,6 @@ func isMultiSig(pops []parsedOpcode) bool {
return true
}
// isNullData returns true if the passed script is a null data transaction,
// false otherwise.
func isNullData(pops []parsedOpcode) bool {
// A nulldata transaction is either a single OP_RETURN or an
// OP_RETURN SMALLDATA (where SMALLDATA is a data push up to
// MaxDataCarrierSize bytes).
l := len(pops)
if l == 1 && pops[0].opcode.value == OpReturn {
return true
}
return l == 2 &&
pops[0].opcode.value == OpReturn &&
(isSmallInt(pops[1].opcode) || pops[1].opcode.value <=
OpPushData4) &&
len(pops[1].data) <= MaxDataCarrierSize
}
// scriptType returns the type of the script being inspected from the known
// standard types.
func typeOfScript(pops []parsedOpcode) ScriptClass {
@ -147,8 +123,6 @@ func typeOfScript(pops []parsedOpcode) ScriptClass {
return ScriptHashTy
} else if isMultiSig(pops) {
return MultiSigTy
} else if isNullData(pops) {
return NullDataTy
}
return NonStandardTy
}
@ -191,8 +165,6 @@ func expectedInputs(pops []parsedOpcode, class ScriptClass) int {
// for the extra push that is required to compensate.
return asSmallInt(pops[0].opcode) + 1
case NullDataTy:
fallthrough
default:
return -1
}
@ -376,19 +348,6 @@ func PayToScriptHashSignatureScript(redeemScript []byte, signature []byte) ([]by
return signatureScript, nil
}
// NullDataScript creates a provably-prunable script containing OP_RETURN
// followed by the passed data. An Error with the error code ErrTooMuchNullData
// will be returned if the length of the passed data exceeds MaxDataCarrierSize.
func NullDataScript(data []byte) ([]byte, error) {
if len(data) > MaxDataCarrierSize {
str := fmt.Sprintf("data size %d is larger than max "+
"allowed size %d", len(data), MaxDataCarrierSize)
return nil, scriptError(ErrTooMuchNullData, str)
}
return NewScriptBuilder().AddOp(OpReturn).AddData(data).Script()
}
// MultiSigScript returns a valid script for a multisignature redemption where
// nrequired of the keys in pubkeys are required to have signed the transaction
// for success. An Error with the error code ErrTooManyRequiredSigs will be
@ -500,10 +459,6 @@ func ExtractPkScriptAddrs(pkScript []byte, chainParams *dagconfig.Params) (Scrip
}
}
case NullDataTy:
// Null data transactions have no addresses or required
// signatures.
case NonStandardTy:
// Don't attempt to extract addresses or required signatures for
// nonstandard transactions.

View File

@ -817,75 +817,9 @@ var scriptClassTests = []struct {
},
{
// Nulldata with no data at all.
name: "nulldata no data",
script: "RETURN",
class: NullDataTy,
},
{
// Nulldata with single zero push.
name: "nulldata zero",
// Nulldata. It is standard in BTC but not in DAGCoin
name: "nulldata",
script: "RETURN 0",
class: NullDataTy,
},
{
// Nulldata with small integer push.
name: "nulldata small int",
script: "RETURN 1",
class: NullDataTy,
},
{
// Nulldata with max small integer push.
name: "nulldata max small int",
script: "RETURN 16",
class: NullDataTy,
},
{
// Nulldata with small data push.
name: "nulldata small data",
script: "RETURN DATA_8 0x046708afdb0fe554",
class: NullDataTy,
},
{
// Canonical nulldata with 60-byte data push.
name: "canonical nulldata 60-byte push",
script: "RETURN 0x3c 0x046708afdb0fe5548271967f1a67130b7105cd" +
"6a828e03909a67962e0ea1f61deb649f6bc3f4cef3046708afdb" +
"0fe5548271967f1a67130b7105cd6a",
class: NullDataTy,
},
{
// Non-canonical nulldata with 60-byte data push.
name: "non-canonical nulldata 60-byte push",
script: "RETURN PUSHDATA1 0x3c 0x046708afdb0fe5548271967f1a67" +
"130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3" +
"046708afdb0fe5548271967f1a67130b7105cd6a",
class: NullDataTy,
},
{
// Nulldata with max allowed data to be considered standard.
name: "nulldata max standard push",
script: "RETURN PUSHDATA1 0x50 0x046708afdb0fe5548271967f1a67" +
"130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3" +
"046708afdb0fe5548271967f1a67130b7105cd6a828e03909a67" +
"962e0ea1f61deb649f6bc3f4cef3",
class: NullDataTy,
},
{
// Nulldata with more than max allowed data to be considered
// standard (so therefore nonstandard)
name: "nulldata exceed max standard push",
script: "RETURN PUSHDATA1 0x51 0x046708afdb0fe5548271967f1a67" +
"130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3" +
"046708afdb0fe5548271967f1a67130b7105cd6a828e03909a67" +
"962e0ea1f61deb649f6bc3f4cef308",
class: NonStandardTy,
},
{
// Almost nulldata, but add an additional opcode after the data
// to make it nonstandard.
name: "almost nulldata",
script: "RETURN 4 TRUE",
class: NonStandardTy,
},
@ -996,11 +930,6 @@ func TestStringifyClass(t *testing.T) {
class: MultiSigTy,
stringed: "multisig",
},
{
name: "nulldataty",
class: NullDataTy,
stringed: "nulldata",
},
{
name: "broken",
class: ScriptClass(255),
@ -1016,89 +945,3 @@ func TestStringifyClass(t *testing.T) {
}
}
}
// TestNullDataScript tests whether NullDataScript returns a valid script.
func TestNullDataScript(t *testing.T) {
tests := []struct {
name string
data []byte
expected []byte
err error
class ScriptClass
}{
{
name: "small int",
data: hexToBytes("01"),
expected: mustParseShortForm("RETURN 1"),
err: nil,
class: NullDataTy,
},
{
name: "max small int",
data: hexToBytes("10"),
expected: mustParseShortForm("RETURN 16"),
err: nil,
class: NullDataTy,
},
{
name: "data of size before OP_PUSHDATA1 is needed",
data: hexToBytes("0102030405060708090a0b0c0d0e0f10111" +
"2131415161718"),
expected: mustParseShortForm("RETURN 0x18 0x01020304" +
"05060708090a0b0c0d0e0f101112131415161718"),
err: nil,
class: NullDataTy,
},
{
name: "just right",
data: hexToBytes("000102030405060708090a0b0c0d0e0f101" +
"112131415161718191a1b1c1d1e1f202122232425262" +
"728292a2b2c2d2e2f303132333435363738393a3b3c3" +
"d3e3f404142434445464748494a4b4c4d4e4f"),
expected: mustParseShortForm("RETURN PUSHDATA1 0x50 " +
"0x000102030405060708090a0b0c0d0e0f101112131" +
"415161718191a1b1c1d1e1f20212223242526272829" +
"2a2b2c2d2e2f303132333435363738393a3b3c3d3e3" +
"f404142434445464748494a4b4c4d4e4f"),
err: nil,
class: NullDataTy,
},
{
name: "too big",
data: hexToBytes("000102030405060708090a0b0c0d0e0f101" +
"112131415161718191a1b1c1d1e1f202122232425262" +
"728292a2b2c2d2e2f303132333435363738393a3b3c3" +
"d3e3f404142434445464748494a4b4c4d4e4f50"),
expected: nil,
err: scriptError(ErrTooMuchNullData, ""),
class: NonStandardTy,
},
}
for i, test := range tests {
script, err := NullDataScript(test.data)
if e := checkScriptError(err, test.err); e != nil {
t.Errorf("NullDataScript: #%d (%s): %v", i, test.name,
e)
continue
}
// Check that the expected result was returned.
if !bytes.Equal(script, test.expected) {
t.Errorf("NullDataScript: #%d (%s) wrong result\n"+
"got: %x\nwant: %x", i, test.name, script,
test.expected)
continue
}
// Check that the script has the correct type.
scriptType := GetScriptClass(script)
if scriptType != test.class {
t.Errorf("GetScriptClass: #%d (%s) wrong result -- "+
"got: %v, want: %v", i, test.name, scriptType,
test.class)
continue
}
}
}