From 0c5f3d72bdbb2c57737e57fa4edb5aa39843742d Mon Sep 17 00:00:00 2001 From: Svarog Date: Sun, 16 Jun 2019 16:31:38 +0300 Subject: [PATCH] [NOD-223] Removed Nulldata as standard tx type (#329) * [NOD-223] Removed Nulldata as standard tx type * [NOD-223] Removed redundant space --- blockdag/compress_test.go | 13 +-- mempool/policy.go | 17 +--- mempool/policy_test.go | 18 +---- txscript/error.go | 5 -- txscript/error_test.go | 1 - txscript/sign.go | 3 - txscript/standard.go | 45 ----------- txscript/standard_test.go | 161 +------------------------------------- 8 files changed, 8 insertions(+), 255 deletions(-) diff --git a/blockdag/compress_test.go b/blockdag/compress_test.go index bfa261036..6f8abddf4 100644 --- a/blockdag/compress_test.go +++ b/blockdag/compress_test.go @@ -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, diff --git a/mempool/policy.go b/mempool/policy.go index ea20e26b8..bd86185cb 100644 --- a/mempool/policy.go +++ b/mempool/policy.go @@ -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 } diff --git a/mempool/policy_test.go b/mempool/policy_test.go index 7adbc6ea6..eb593a74c 100644 --- a/mempool/policy_test.go +++ b/mempool/policy_test.go @@ -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, }, } diff --git a/txscript/error.go b/txscript/error.go index c0f286e1c..84d12757f 100644 --- a/txscript/error.go +++ b/txscript/error.go @@ -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", diff --git a/txscript/error_test.go b/txscript/error_test.go index 9e82f9a89..b1512b2c7 100644 --- a/txscript/error_test.go +++ b/txscript/error_test.go @@ -21,7 +21,6 @@ func TestErrorCodeStringer(t *testing.T) { {ErrInvalidIndex, "ErrInvalidIndex"}, {ErrUnsupportedAddress, "ErrUnsupportedAddress"}, {ErrTooManyRequiredSigs, "ErrTooManyRequiredSigs"}, - {ErrTooMuchNullData, "ErrTooMuchNullData"}, {ErrNotMultisigScript, "ErrNotMultisigScript"}, {ErrEarlyReturn, "ErrEarlyReturn"}, {ErrEmptyStack, "ErrEmptyStack"}, diff --git a/txscript/sign.go b/txscript/sign.go index 2e8930689..1fa81afd1 100644 --- a/txscript/sign.go +++ b/txscript/sign.go @@ -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") diff --git a/txscript/standard.go b/txscript/standard.go index 2e446fc98..be3515947 100644 --- a/txscript/standard.go +++ b/txscript/standard.go @@ -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. diff --git a/txscript/standard_test.go b/txscript/standard_test.go index a4aea57fe..12308c42c 100644 --- a/txscript/standard_test.go +++ b/txscript/standard_test.go @@ -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 - } - } -}