github.com/BlockABC/godash@v0.0.0-20191112120524-f4aa3a32c566/policy_test.go (about)

     1  // Copyright (c) 2013-2015 The btcsuite developers
     2  // Copyright (c) 2016 The Dash developers
     3  // Use of this source code is governed by an ISC
     4  // license that can be found in the LICENSE file.
     5  
     6  package main
     7  
     8  import (
     9  	"bytes"
    10  	"testing"
    11  
    12  	"github.com/BlockABC/godash/blockchain"
    13  	"github.com/BlockABC/godash/btcec"
    14  	"github.com/BlockABC/godash/chaincfg"
    15  	"github.com/BlockABC/godash/txscript"
    16  	"github.com/BlockABC/godash/wire"
    17  	"github.com/BlockABC/godashutil"
    18  )
    19  
    20  // TestCalcMinRequiredTxRelayFee tests the calcMinRequiredTxRelayFee API.
    21  func TestCalcMinRequiredTxRelayFee(t *testing.T) {
    22  	tests := []struct {
    23  		name     string            // test description.
    24  		size     int64             // Transaction size in bytes.
    25  		relayFee godashutil.Amount // minimum relay transaction fee.
    26  		want     int64             // Expected fee.
    27  	}{
    28  		{
    29  			// Ensure combination of size and fee that are less than 1000
    30  			// produce a non-zero fee.
    31  			"250 bytes with relay fee of 3",
    32  			250,
    33  			3,
    34  			3,
    35  		},
    36  		{
    37  			"100 bytes with default minimum relay fee",
    38  			100,
    39  			defaultMinRelayTxFee,
    40  			100,
    41  		},
    42  		{
    43  			"max standard tx size with default minimum relay fee",
    44  			maxStandardTxSize,
    45  			defaultMinRelayTxFee,
    46  			100000,
    47  		},
    48  		{
    49  			"max standard tx size with max satoshi relay fee",
    50  			maxStandardTxSize,
    51  			godashutil.MaxSatoshi,
    52  			godashutil.MaxSatoshi,
    53  		},
    54  		{
    55  			"1500 bytes with 5000 relay fee",
    56  			1500,
    57  			5000,
    58  			7500,
    59  		},
    60  		{
    61  			"1500 bytes with 3000 relay fee",
    62  			1500,
    63  			3000,
    64  			4500,
    65  		},
    66  		{
    67  			"782 bytes with 5000 relay fee",
    68  			782,
    69  			5000,
    70  			3910,
    71  		},
    72  		{
    73  			"782 bytes with 3000 relay fee",
    74  			782,
    75  			3000,
    76  			2346,
    77  		},
    78  		{
    79  			"782 bytes with 2550 relay fee",
    80  			782,
    81  			2550,
    82  			1994,
    83  		},
    84  	}
    85  
    86  	for _, test := range tests {
    87  		got := calcMinRequiredTxRelayFee(test.size, test.relayFee)
    88  		if got != test.want {
    89  			t.Errorf("TestCalcMinRequiredTxRelayFee test '%s' "+
    90  				"failed: got %v want %v", test.name, got,
    91  				test.want)
    92  			continue
    93  		}
    94  	}
    95  }
    96  
    97  // TestCheckPkScriptStandard tests the checkPkScriptStandard API.
    98  func TestCheckPkScriptStandard(t *testing.T) {
    99  	var pubKeys [][]byte
   100  	for i := 0; i < 4; i++ {
   101  		pk, err := btcec.NewPrivateKey(btcec.S256())
   102  		if err != nil {
   103  			t.Fatalf("TestCheckPkScriptStandard NewPrivateKey failed: %v",
   104  				err)
   105  			return
   106  		}
   107  		pubKeys = append(pubKeys, pk.PubKey().SerializeCompressed())
   108  	}
   109  
   110  	tests := []struct {
   111  		name       string // test description.
   112  		script     *txscript.ScriptBuilder
   113  		isStandard bool
   114  	}{
   115  		{
   116  			"key1 and key2",
   117  			txscript.NewScriptBuilder().AddOp(txscript.OP_2).
   118  				AddData(pubKeys[0]).AddData(pubKeys[1]).
   119  				AddOp(txscript.OP_2).AddOp(txscript.OP_CHECKMULTISIG),
   120  			true,
   121  		},
   122  		{
   123  			"key1 or key2",
   124  			txscript.NewScriptBuilder().AddOp(txscript.OP_1).
   125  				AddData(pubKeys[0]).AddData(pubKeys[1]).
   126  				AddOp(txscript.OP_2).AddOp(txscript.OP_CHECKMULTISIG),
   127  			true,
   128  		},
   129  		{
   130  			"escrow",
   131  			txscript.NewScriptBuilder().AddOp(txscript.OP_2).
   132  				AddData(pubKeys[0]).AddData(pubKeys[1]).
   133  				AddData(pubKeys[2]).
   134  				AddOp(txscript.OP_3).AddOp(txscript.OP_CHECKMULTISIG),
   135  			true,
   136  		},
   137  		{
   138  			"one of four",
   139  			txscript.NewScriptBuilder().AddOp(txscript.OP_1).
   140  				AddData(pubKeys[0]).AddData(pubKeys[1]).
   141  				AddData(pubKeys[2]).AddData(pubKeys[3]).
   142  				AddOp(txscript.OP_4).AddOp(txscript.OP_CHECKMULTISIG),
   143  			false,
   144  		},
   145  		{
   146  			"malformed1",
   147  			txscript.NewScriptBuilder().AddOp(txscript.OP_3).
   148  				AddData(pubKeys[0]).AddData(pubKeys[1]).
   149  				AddOp(txscript.OP_2).AddOp(txscript.OP_CHECKMULTISIG),
   150  			false,
   151  		},
   152  		{
   153  			"malformed2",
   154  			txscript.NewScriptBuilder().AddOp(txscript.OP_2).
   155  				AddData(pubKeys[0]).AddData(pubKeys[1]).
   156  				AddOp(txscript.OP_3).AddOp(txscript.OP_CHECKMULTISIG),
   157  			false,
   158  		},
   159  		{
   160  			"malformed3",
   161  			txscript.NewScriptBuilder().AddOp(txscript.OP_0).
   162  				AddData(pubKeys[0]).AddData(pubKeys[1]).
   163  				AddOp(txscript.OP_2).AddOp(txscript.OP_CHECKMULTISIG),
   164  			false,
   165  		},
   166  		{
   167  			"malformed4",
   168  			txscript.NewScriptBuilder().AddOp(txscript.OP_1).
   169  				AddData(pubKeys[0]).AddData(pubKeys[1]).
   170  				AddOp(txscript.OP_0).AddOp(txscript.OP_CHECKMULTISIG),
   171  			false,
   172  		},
   173  		{
   174  			"malformed5",
   175  			txscript.NewScriptBuilder().AddOp(txscript.OP_1).
   176  				AddData(pubKeys[0]).AddData(pubKeys[1]).
   177  				AddOp(txscript.OP_CHECKMULTISIG),
   178  			false,
   179  		},
   180  		{
   181  			"malformed6",
   182  			txscript.NewScriptBuilder().AddOp(txscript.OP_1).
   183  				AddData(pubKeys[0]).AddData(pubKeys[1]),
   184  			false,
   185  		},
   186  	}
   187  
   188  	for _, test := range tests {
   189  		script, err := test.script.Script()
   190  		if err != nil {
   191  			t.Fatalf("TestCheckPkScriptStandard test '%s' "+
   192  				"failed: %v", test.name, err)
   193  			continue
   194  		}
   195  		scriptClass := txscript.GetScriptClass(script)
   196  		got := checkPkScriptStandard(script, scriptClass)
   197  		if (test.isStandard && got != nil) ||
   198  			(!test.isStandard && got == nil) {
   199  
   200  			t.Fatalf("TestCheckPkScriptStandard test '%s' failed",
   201  				test.name)
   202  			return
   203  		}
   204  	}
   205  }
   206  
   207  // TestDust tests the isDust API.
   208  func TestDust(t *testing.T) {
   209  	pkScript := []byte{0x76, 0xa9, 0x21, 0x03, 0x2f, 0x7e, 0x43,
   210  		0x0a, 0xa4, 0xc9, 0xd1, 0x59, 0x43, 0x7e, 0x84, 0xb9,
   211  		0x75, 0xdc, 0x76, 0xd9, 0x00, 0x3b, 0xf0, 0x92, 0x2c,
   212  		0xf3, 0xaa, 0x45, 0x28, 0x46, 0x4b, 0xab, 0x78, 0x0d,
   213  		0xba, 0x5e, 0x88, 0xac}
   214  
   215  	tests := []struct {
   216  		name     string // test description
   217  		txOut    wire.TxOut
   218  		relayFee godashutil.Amount // minimum relay transaction fee.
   219  		isDust   bool
   220  	}{
   221  		{
   222  			// Any value is allowed with a zero relay fee.
   223  			"zero value with zero relay fee",
   224  			wire.TxOut{Value: 0, PkScript: pkScript},
   225  			0,
   226  			false,
   227  		},
   228  		{
   229  			// Zero value is dust with any relay fee"
   230  			"zero value with very small tx fee",
   231  			wire.TxOut{Value: 0, PkScript: pkScript},
   232  			1,
   233  			true,
   234  		},
   235  		{
   236  			"38 byte public key script with value 584",
   237  			wire.TxOut{Value: 584, PkScript: pkScript},
   238  			1000,
   239  			true,
   240  		},
   241  		{
   242  			"38 byte public key script with value 585",
   243  			wire.TxOut{Value: 585, PkScript: pkScript},
   244  			1000,
   245  			false,
   246  		},
   247  		{
   248  			// Maximum allowed value is never dust.
   249  			"max satoshi amount is never dust",
   250  			wire.TxOut{Value: godashutil.MaxSatoshi, PkScript: pkScript},
   251  			godashutil.MaxSatoshi,
   252  			false,
   253  		},
   254  		{
   255  			// Maximum int64 value causes overflow.
   256  			"maximum int64 value",
   257  			wire.TxOut{Value: 1<<63 - 1, PkScript: pkScript},
   258  			1<<63 - 1,
   259  			true,
   260  		},
   261  		{
   262  			// Unspendable pkScript due to an invalid public key
   263  			// script.
   264  			"unspendable pkScript",
   265  			wire.TxOut{Value: 5000, PkScript: []byte{0x01}},
   266  			0, // no relay fee
   267  			true,
   268  		},
   269  	}
   270  	for _, test := range tests {
   271  		res := isDust(&test.txOut, test.relayFee)
   272  		if res != test.isDust {
   273  			t.Fatalf("Dust test '%s' failed: want %v got %v",
   274  				test.name, test.isDust, res)
   275  			continue
   276  		}
   277  	}
   278  }
   279  
   280  // TestCheckTransactionStandard tests the checkTransactionStandard API.
   281  func TestCheckTransactionStandard(t *testing.T) {
   282  	// Create some dummy, but otherwise standard, data for transactions.
   283  	prevOutHash, err := wire.NewShaHashFromStr("01")
   284  	if err != nil {
   285  		t.Fatalf("NewShaHashFromStr: unexpected error: %v", err)
   286  	}
   287  	dummyPrevOut := wire.OutPoint{Hash: *prevOutHash, Index: 1}
   288  	dummySigScript := bytes.Repeat([]byte{0x00}, 65)
   289  	dummyTxIn := wire.TxIn{
   290  		PreviousOutPoint: dummyPrevOut,
   291  		SignatureScript:  dummySigScript,
   292  		Sequence:         wire.MaxTxInSequenceNum,
   293  	}
   294  	addrHash := [20]byte{0x01}
   295  	addr, err := godashutil.NewAddressPubKeyHash(addrHash[:],
   296  		&chaincfg.TestNet3Params)
   297  	if err != nil {
   298  		t.Fatalf("NewAddressPubKeyHash: unexpected error: %v", err)
   299  	}
   300  	dummyPkScript, err := txscript.PayToAddrScript(addr)
   301  	if err != nil {
   302  		t.Fatalf("PayToAddrScript: unexpected error: %v", err)
   303  	}
   304  	dummyTxOut := wire.TxOut{
   305  		Value:    100000000, // 1 BTC
   306  		PkScript: dummyPkScript,
   307  	}
   308  
   309  	tests := []struct {
   310  		name       string
   311  		tx         wire.MsgTx
   312  		height     int32
   313  		isStandard bool
   314  		code       wire.RejectCode
   315  	}{
   316  		{
   317  			name: "Typical pay-to-pubkey-hash transaction",
   318  			tx: wire.MsgTx{
   319  				Version:  1,
   320  				TxIn:     []*wire.TxIn{&dummyTxIn},
   321  				TxOut:    []*wire.TxOut{&dummyTxOut},
   322  				LockTime: 0,
   323  			},
   324  			height:     300000,
   325  			isStandard: true,
   326  		},
   327  		{
   328  			name: "Transaction version too high",
   329  			tx: wire.MsgTx{
   330  				Version:  wire.TxVersion + 1,
   331  				TxIn:     []*wire.TxIn{&dummyTxIn},
   332  				TxOut:    []*wire.TxOut{&dummyTxOut},
   333  				LockTime: 0,
   334  			},
   335  			height:     300000,
   336  			isStandard: false,
   337  			code:       wire.RejectNonstandard,
   338  		},
   339  		{
   340  			name: "Transaction is not finalized",
   341  			tx: wire.MsgTx{
   342  				Version: 1,
   343  				TxIn: []*wire.TxIn{{
   344  					PreviousOutPoint: dummyPrevOut,
   345  					SignatureScript:  dummySigScript,
   346  					Sequence:         0,
   347  				}},
   348  				TxOut:    []*wire.TxOut{&dummyTxOut},
   349  				LockTime: 300001,
   350  			},
   351  			height:     300000,
   352  			isStandard: false,
   353  			code:       wire.RejectNonstandard,
   354  		},
   355  		{
   356  			name: "Transaction size is too large",
   357  			tx: wire.MsgTx{
   358  				Version: 1,
   359  				TxIn:    []*wire.TxIn{&dummyTxIn},
   360  				TxOut: []*wire.TxOut{{
   361  					Value: 0,
   362  					PkScript: bytes.Repeat([]byte{0x00},
   363  						maxStandardTxSize+1),
   364  				}},
   365  				LockTime: 0,
   366  			},
   367  			height:     300000,
   368  			isStandard: false,
   369  			code:       wire.RejectNonstandard,
   370  		},
   371  		{
   372  			name: "Signature script size is too large",
   373  			tx: wire.MsgTx{
   374  				Version: 1,
   375  				TxIn: []*wire.TxIn{{
   376  					PreviousOutPoint: dummyPrevOut,
   377  					SignatureScript: bytes.Repeat([]byte{0x00},
   378  						maxStandardSigScriptSize+1),
   379  					Sequence: wire.MaxTxInSequenceNum,
   380  				}},
   381  				TxOut:    []*wire.TxOut{&dummyTxOut},
   382  				LockTime: 0,
   383  			},
   384  			height:     300000,
   385  			isStandard: false,
   386  			code:       wire.RejectNonstandard,
   387  		},
   388  		{
   389  			name: "Signature script that does more than push data",
   390  			tx: wire.MsgTx{
   391  				Version: 1,
   392  				TxIn: []*wire.TxIn{{
   393  					PreviousOutPoint: dummyPrevOut,
   394  					SignatureScript: []byte{
   395  						txscript.OP_CHECKSIGVERIFY},
   396  					Sequence: wire.MaxTxInSequenceNum,
   397  				}},
   398  				TxOut:    []*wire.TxOut{&dummyTxOut},
   399  				LockTime: 0,
   400  			},
   401  			height:     300000,
   402  			isStandard: false,
   403  			code:       wire.RejectNonstandard,
   404  		},
   405  		{
   406  			name: "Valid but non standard public key script",
   407  			tx: wire.MsgTx{
   408  				Version: 1,
   409  				TxIn:    []*wire.TxIn{&dummyTxIn},
   410  				TxOut: []*wire.TxOut{{
   411  					Value:    100000000,
   412  					PkScript: []byte{txscript.OP_TRUE},
   413  				}},
   414  				LockTime: 0,
   415  			},
   416  			height:     300000,
   417  			isStandard: false,
   418  			code:       wire.RejectNonstandard,
   419  		},
   420  		{
   421  			name: "More than one nulldata output",
   422  			tx: wire.MsgTx{
   423  				Version: 1,
   424  				TxIn:    []*wire.TxIn{&dummyTxIn},
   425  				TxOut: []*wire.TxOut{{
   426  					Value:    0,
   427  					PkScript: []byte{txscript.OP_RETURN},
   428  				}, {
   429  					Value:    0,
   430  					PkScript: []byte{txscript.OP_RETURN},
   431  				}},
   432  				LockTime: 0,
   433  			},
   434  			height:     300000,
   435  			isStandard: false,
   436  			code:       wire.RejectNonstandard,
   437  		},
   438  		{
   439  			name: "Dust output",
   440  			tx: wire.MsgTx{
   441  				Version: 1,
   442  				TxIn:    []*wire.TxIn{&dummyTxIn},
   443  				TxOut: []*wire.TxOut{{
   444  					Value:    0,
   445  					PkScript: dummyPkScript,
   446  				}},
   447  				LockTime: 0,
   448  			},
   449  			height:     300000,
   450  			isStandard: false,
   451  			code:       wire.RejectDust,
   452  		},
   453  		{
   454  			name: "One nulldata output with 0 amount (standard)",
   455  			tx: wire.MsgTx{
   456  				Version: 1,
   457  				TxIn:    []*wire.TxIn{&dummyTxIn},
   458  				TxOut: []*wire.TxOut{{
   459  					Value:    0,
   460  					PkScript: []byte{txscript.OP_RETURN},
   461  				}},
   462  				LockTime: 0,
   463  			},
   464  			height:     300000,
   465  			isStandard: true,
   466  		},
   467  	}
   468  
   469  	timeSource := blockchain.NewMedianTime()
   470  	for _, test := range tests {
   471  		// Ensure standardness is as expected.
   472  		err := checkTransactionStandard(godashutil.NewTx(&test.tx),
   473  			test.height, timeSource, defaultMinRelayTxFee)
   474  		if err == nil && test.isStandard {
   475  			// Test passes since function returned standard for a
   476  			// transaction which is intended to be standard.
   477  			continue
   478  		}
   479  		if err == nil && !test.isStandard {
   480  			t.Errorf("checkTransactionStandard (%s): standard when "+
   481  				"it should not be", test.name)
   482  			continue
   483  		}
   484  		if err != nil && test.isStandard {
   485  			t.Errorf("checkTransactionStandard (%s): nonstandard "+
   486  				"when it should not be: %v", test.name, err)
   487  			continue
   488  		}
   489  
   490  		// Ensure error type is a TxRuleError inside of a RuleError.
   491  		rerr, ok := err.(RuleError)
   492  		if !ok {
   493  			t.Errorf("checkTransactionStandard (%s): unexpected "+
   494  				"error type - got %T", test.name, err)
   495  			continue
   496  		}
   497  		txrerr, ok := rerr.Err.(TxRuleError)
   498  		if !ok {
   499  			t.Errorf("checkTransactionStandard (%s): unexpected "+
   500  				"error type - got %T", test.name, rerr.Err)
   501  			continue
   502  		}
   503  
   504  		// Ensure the reject code is the expected one.
   505  		if txrerr.RejectCode != test.code {
   506  			t.Errorf("checkTransactionStandard (%s): unexpected "+
   507  				"error code - got %v, want %v", test.name,
   508  				txrerr.RejectCode, test.code)
   509  			continue
   510  		}
   511  	}
   512  }