github.com/BlockABC/godash@v0.0.0-20191112120524-f4aa3a32c566/txscript/script_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 txscript_test
     7  
     8  import (
     9  	"bytes"
    10  	"reflect"
    11  	"testing"
    12  
    13  	"github.com/BlockABC/godash/txscript"
    14  )
    15  
    16  // TestPushedData ensured the PushedData function extracts the expected data out
    17  // of various scripts.
    18  func TestPushedData(t *testing.T) {
    19  	t.Parallel()
    20  
    21  	var tests = []struct {
    22  		script string
    23  		out    [][]byte
    24  		valid  bool
    25  	}{
    26  		{
    27  			"0 IF 0 ELSE 2 ENDIF",
    28  			[][]byte{nil, nil},
    29  			true,
    30  		},
    31  		{
    32  			"16777216 10000000",
    33  			[][]byte{
    34  				{0x00, 0x00, 0x00, 0x01}, // 16777216
    35  				{0x80, 0x96, 0x98, 0x00}, // 10000000
    36  			},
    37  			true,
    38  		},
    39  		{
    40  			"DUP HASH160 '17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhem' EQUALVERIFY CHECKSIG",
    41  			[][]byte{
    42  				// 17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhem
    43  				{
    44  					0x31, 0x37, 0x56, 0x5a, 0x4e, 0x58, 0x31, 0x53, 0x4e, 0x35,
    45  					0x4e, 0x74, 0x4b, 0x61, 0x38, 0x55, 0x51, 0x46, 0x78, 0x77,
    46  					0x51, 0x62, 0x46, 0x65, 0x46, 0x63, 0x33, 0x69, 0x71, 0x52,
    47  					0x59, 0x68, 0x65, 0x6d,
    48  				},
    49  			},
    50  			true,
    51  		},
    52  		{
    53  			"PUSHDATA4 1000 EQUAL",
    54  			nil,
    55  			false,
    56  		},
    57  	}
    58  
    59  	for i, test := range tests {
    60  		script := mustParseShortForm(test.script)
    61  		data, err := txscript.PushedData(script)
    62  		if test.valid && err != nil {
    63  			t.Errorf("TestPushedData failed test #%d: %v\n", i, err)
    64  			continue
    65  		} else if !test.valid && err == nil {
    66  			t.Errorf("TestPushedData failed test #%d: test should "+
    67  				"be invalid\n", i)
    68  			continue
    69  		}
    70  		if !reflect.DeepEqual(data, test.out) {
    71  			t.Errorf("TestPushedData failed test #%d: want: %x "+
    72  				"got: %x\n", i, test.out, data)
    73  		}
    74  	}
    75  }
    76  
    77  // TestHasCanonicalPush ensures the canonicalPush function works as expected.
    78  func TestHasCanonicalPush(t *testing.T) {
    79  	t.Parallel()
    80  
    81  	for i := 0; i < 65535; i++ {
    82  		builder := txscript.NewScriptBuilder()
    83  		builder.AddInt64(int64(i))
    84  		script, err := builder.Script()
    85  		if err != nil {
    86  			t.Errorf("Script: test #%d unexpected error: %v\n", i,
    87  				err)
    88  			continue
    89  		}
    90  		if result := txscript.IsPushOnlyScript(script); !result {
    91  			t.Errorf("IsPushOnlyScript: test #%d failed: %x\n", i,
    92  				script)
    93  			continue
    94  		}
    95  		pops, err := txscript.TstParseScript(script)
    96  		if err != nil {
    97  			t.Errorf("TstParseScript: #%d failed: %v", i, err)
    98  			continue
    99  		}
   100  		for _, pop := range pops {
   101  			if result := txscript.TstHasCanonicalPushes(pop); !result {
   102  				t.Errorf("TstHasCanonicalPushes: test #%d "+
   103  					"failed: %x\n", i, script)
   104  				break
   105  			}
   106  		}
   107  	}
   108  	for i := 0; i <= txscript.MaxScriptElementSize; i++ {
   109  		builder := txscript.NewScriptBuilder()
   110  		builder.AddData(bytes.Repeat([]byte{0x49}, i))
   111  		script, err := builder.Script()
   112  		if err != nil {
   113  			t.Errorf("StandardPushesTests test #%d unexpected error: %v\n", i, err)
   114  			continue
   115  		}
   116  		if result := txscript.IsPushOnlyScript(script); !result {
   117  			t.Errorf("StandardPushesTests IsPushOnlyScript test #%d failed: %x\n", i, script)
   118  			continue
   119  		}
   120  		pops, err := txscript.TstParseScript(script)
   121  		if err != nil {
   122  			t.Errorf("StandardPushesTests #%d failed to TstParseScript: %v", i, err)
   123  			continue
   124  		}
   125  		for _, pop := range pops {
   126  			if result := txscript.TstHasCanonicalPushes(pop); !result {
   127  				t.Errorf("StandardPushesTests TstHasCanonicalPushes test #%d failed: %x\n", i, script)
   128  				break
   129  			}
   130  		}
   131  	}
   132  }
   133  
   134  // TestGetPreciseSigOps ensures the more precise signature operation counting
   135  // mechanism which includes signatures in P2SH scripts works as expected.
   136  func TestGetPreciseSigOps(t *testing.T) {
   137  	t.Parallel()
   138  
   139  	tests := []struct {
   140  		name      string
   141  		scriptSig []byte
   142  		nSigOps   int
   143  		err       error
   144  	}{
   145  		{
   146  			name:      "scriptSig doesn't parse",
   147  			scriptSig: []byte{txscript.OP_PUSHDATA1, 2},
   148  			err:       txscript.ErrStackShortScript,
   149  		},
   150  		{
   151  			name:      "scriptSig isn't push only",
   152  			scriptSig: []byte{txscript.OP_1, txscript.OP_DUP},
   153  			nSigOps:   0,
   154  		},
   155  		{
   156  			name:      "scriptSig length 0",
   157  			scriptSig: nil,
   158  			nSigOps:   0,
   159  		},
   160  		{
   161  			name: "No script at the end",
   162  			// No script at end but still push only.
   163  			scriptSig: []byte{txscript.OP_1, txscript.OP_1},
   164  			nSigOps:   0,
   165  		},
   166  		{
   167  			name: "pushed script doesn't parse",
   168  			scriptSig: []byte{txscript.OP_DATA_2,
   169  				txscript.OP_PUSHDATA1, 2},
   170  			err: txscript.ErrStackShortScript,
   171  		},
   172  	}
   173  
   174  	// The signature in the p2sh script is nonsensical for the tests since
   175  	// this script will never be executed.  What matters is that it matches
   176  	// the right pattern.
   177  	pkScript := mustParseShortForm("HASH160 DATA_20 0x433ec2ac1ffa1b7b7d0" +
   178  		"27f564529c57197f9ae88 EQUAL")
   179  	for _, test := range tests {
   180  		count := txscript.GetPreciseSigOpCount(test.scriptSig, pkScript,
   181  			true)
   182  		if count != test.nSigOps {
   183  			t.Errorf("%s: expected count of %d, got %d", test.name,
   184  				test.nSigOps, count)
   185  
   186  		}
   187  	}
   188  }
   189  
   190  // TestRemoveOpcodes ensures that removing opcodes from scripts behaves as
   191  // expected.
   192  func TestRemoveOpcodes(t *testing.T) {
   193  	t.Parallel()
   194  
   195  	tests := []struct {
   196  		name   string
   197  		before string
   198  		remove byte
   199  		err    error
   200  		after  string
   201  	}{
   202  		{
   203  			// Nothing to remove.
   204  			name:   "nothing to remove",
   205  			before: "NOP",
   206  			remove: txscript.OP_CODESEPARATOR,
   207  			after:  "NOP",
   208  		},
   209  		{
   210  			// Test basic opcode removal.
   211  			name:   "codeseparator 1",
   212  			before: "NOP CODESEPARATOR TRUE",
   213  			remove: txscript.OP_CODESEPARATOR,
   214  			after:  "NOP TRUE",
   215  		},
   216  		{
   217  			// The opcode in question is actually part of the data
   218  			// in a previous opcode.
   219  			name:   "codeseparator by coincidence",
   220  			before: "NOP DATA_1 CODESEPARATOR TRUE",
   221  			remove: txscript.OP_CODESEPARATOR,
   222  			after:  "NOP DATA_1 CODESEPARATOR TRUE",
   223  		},
   224  		{
   225  			name:   "invalid opcode",
   226  			before: "CAT",
   227  			remove: txscript.OP_CODESEPARATOR,
   228  			after:  "CAT",
   229  		},
   230  		{
   231  			name:   "invalid length (insruction)",
   232  			before: "PUSHDATA1",
   233  			remove: txscript.OP_CODESEPARATOR,
   234  			err:    txscript.ErrStackShortScript,
   235  		},
   236  		{
   237  			name:   "invalid length (data)",
   238  			before: "PUSHDATA1 0xff 0xfe",
   239  			remove: txscript.OP_CODESEPARATOR,
   240  			err:    txscript.ErrStackShortScript,
   241  		},
   242  	}
   243  
   244  	for _, test := range tests {
   245  		before := mustParseShortForm(test.before)
   246  		after := mustParseShortForm(test.after)
   247  		result, err := txscript.TstRemoveOpcode(before, test.remove)
   248  		if test.err != nil {
   249  			if err != test.err {
   250  				t.Errorf("%s: got unexpected error. exp: \"%v\" "+
   251  					"got: \"%v\"", test.name, test.err, err)
   252  			}
   253  			return
   254  		}
   255  		if err != nil {
   256  			t.Errorf("%s: unexpected failure: \"%v\"", test.name, err)
   257  			return
   258  		}
   259  		if !bytes.Equal(after, result) {
   260  			t.Errorf("%s: value does not equal expected: exp: \"%v\""+
   261  				" got: \"%v\"", test.name, after, result)
   262  		}
   263  	}
   264  }
   265  
   266  // TestRemoveOpcodeByData ensures that removing data carrying opcodes based on
   267  // the data they contain works as expected.
   268  func TestRemoveOpcodeByData(t *testing.T) {
   269  	t.Parallel()
   270  
   271  	tests := []struct {
   272  		name   string
   273  		before []byte
   274  		remove []byte
   275  		err    error
   276  		after  []byte
   277  	}{
   278  		{
   279  			name:   "nothing to do",
   280  			before: []byte{txscript.OP_NOP},
   281  			remove: []byte{1, 2, 3, 4},
   282  			after:  []byte{txscript.OP_NOP},
   283  		},
   284  		{
   285  			name:   "simple case",
   286  			before: []byte{txscript.OP_DATA_4, 1, 2, 3, 4},
   287  			remove: []byte{1, 2, 3, 4},
   288  			after:  nil,
   289  		},
   290  		{
   291  			name:   "simple case (miss)",
   292  			before: []byte{txscript.OP_DATA_4, 1, 2, 3, 4},
   293  			remove: []byte{1, 2, 3, 5},
   294  			after:  []byte{txscript.OP_DATA_4, 1, 2, 3, 4},
   295  		},
   296  		{
   297  			// padded to keep it canonical.
   298  			name: "simple case (pushdata1)",
   299  			before: append(append([]byte{txscript.OP_PUSHDATA1, 76},
   300  				bytes.Repeat([]byte{0}, 72)...),
   301  				[]byte{1, 2, 3, 4}...),
   302  			remove: []byte{1, 2, 3, 4},
   303  			after:  nil,
   304  		},
   305  		{
   306  			name: "simple case (pushdata1 miss)",
   307  			before: append(append([]byte{txscript.OP_PUSHDATA1, 76},
   308  				bytes.Repeat([]byte{0}, 72)...),
   309  				[]byte{1, 2, 3, 4}...),
   310  			remove: []byte{1, 2, 3, 5},
   311  			after: append(append([]byte{txscript.OP_PUSHDATA1, 76},
   312  				bytes.Repeat([]byte{0}, 72)...),
   313  				[]byte{1, 2, 3, 4}...),
   314  		},
   315  		{
   316  			name:   "simple case (pushdata1 miss noncanonical)",
   317  			before: []byte{txscript.OP_PUSHDATA1, 4, 1, 2, 3, 4},
   318  			remove: []byte{1, 2, 3, 4},
   319  			after:  []byte{txscript.OP_PUSHDATA1, 4, 1, 2, 3, 4},
   320  		},
   321  		{
   322  			name: "simple case (pushdata2)",
   323  			before: append(append([]byte{txscript.OP_PUSHDATA2, 0, 1},
   324  				bytes.Repeat([]byte{0}, 252)...),
   325  				[]byte{1, 2, 3, 4}...),
   326  			remove: []byte{1, 2, 3, 4},
   327  			after:  nil,
   328  		},
   329  		{
   330  			name: "simple case (pushdata2 miss)",
   331  			before: append(append([]byte{txscript.OP_PUSHDATA2, 0, 1},
   332  				bytes.Repeat([]byte{0}, 252)...),
   333  				[]byte{1, 2, 3, 4}...),
   334  			remove: []byte{1, 2, 3, 4, 5},
   335  			after: append(append([]byte{txscript.OP_PUSHDATA2, 0, 1},
   336  				bytes.Repeat([]byte{0}, 252)...),
   337  				[]byte{1, 2, 3, 4}...),
   338  		},
   339  		{
   340  			name:   "simple case (pushdata2 miss noncanonical)",
   341  			before: []byte{txscript.OP_PUSHDATA2, 4, 0, 1, 2, 3, 4},
   342  			remove: []byte{1, 2, 3, 4},
   343  			after:  []byte{txscript.OP_PUSHDATA2, 4, 0, 1, 2, 3, 4},
   344  		},
   345  		{
   346  			// This is padded to make the push canonical.
   347  			name: "simple case (pushdata4)",
   348  			before: append(append([]byte{txscript.OP_PUSHDATA4, 0, 0, 1, 0},
   349  				bytes.Repeat([]byte{0}, 65532)...),
   350  				[]byte{1, 2, 3, 4}...),
   351  			remove: []byte{1, 2, 3, 4},
   352  			after:  nil,
   353  		},
   354  		{
   355  			name:   "simple case (pushdata4 miss noncanonical)",
   356  			before: []byte{txscript.OP_PUSHDATA4, 4, 0, 0, 0, 1, 2, 3, 4},
   357  			remove: []byte{1, 2, 3, 4},
   358  			after:  []byte{txscript.OP_PUSHDATA4, 4, 0, 0, 0, 1, 2, 3, 4},
   359  		},
   360  		{
   361  			// This is padded to make the push canonical.
   362  			name: "simple case (pushdata4 miss)",
   363  			before: append(append([]byte{txscript.OP_PUSHDATA4, 0, 0, 1, 0},
   364  				bytes.Repeat([]byte{0}, 65532)...), []byte{1, 2, 3, 4}...),
   365  			remove: []byte{1, 2, 3, 4, 5},
   366  			after: append(append([]byte{txscript.OP_PUSHDATA4, 0, 0, 1, 0},
   367  				bytes.Repeat([]byte{0}, 65532)...), []byte{1, 2, 3, 4}...),
   368  		},
   369  		{
   370  			name:   "invalid opcode ",
   371  			before: []byte{txscript.OP_UNKNOWN187},
   372  			remove: []byte{1, 2, 3, 4},
   373  			after:  []byte{txscript.OP_UNKNOWN187},
   374  		},
   375  		{
   376  			name:   "invalid length (instruction)",
   377  			before: []byte{txscript.OP_PUSHDATA1},
   378  			remove: []byte{1, 2, 3, 4},
   379  			err:    txscript.ErrStackShortScript,
   380  		},
   381  		{
   382  			name:   "invalid length (data)",
   383  			before: []byte{txscript.OP_PUSHDATA1, 255, 254},
   384  			remove: []byte{1, 2, 3, 4},
   385  			err:    txscript.ErrStackShortScript,
   386  		},
   387  	}
   388  
   389  	for _, test := range tests {
   390  		result, err := txscript.TstRemoveOpcodeByData(test.before,
   391  			test.remove)
   392  		if test.err != nil {
   393  			if err != test.err {
   394  				t.Errorf("%s: got unexpected error. exp: \"%v\" "+
   395  					"got: \"%v\"", test.name, test.err, err)
   396  			}
   397  			return
   398  		}
   399  		if err != nil {
   400  			t.Errorf("%s: unexpected failure: \"%v\"", test.name, err)
   401  			return
   402  		}
   403  		if !bytes.Equal(test.after, result) {
   404  			t.Errorf("%s: value does not equal expected: exp: \"%v\""+
   405  				" got: \"%v\"", test.name, test.after, result)
   406  		}
   407  	}
   408  }
   409  
   410  // TestIsPayToScriptHash ensures the IsPayToScriptHash function returns the
   411  // expected results for all the scripts in scriptClassTests.
   412  func TestIsPayToScriptHash(t *testing.T) {
   413  	t.Parallel()
   414  
   415  	for _, test := range scriptClassTests {
   416  		script := mustParseShortForm(test.script)
   417  		shouldBe := (test.class == txscript.ScriptHashTy)
   418  		p2sh := txscript.IsPayToScriptHash(script)
   419  		if p2sh != shouldBe {
   420  			t.Errorf("%s: epxected p2sh %v, got %v", test.name,
   421  				shouldBe, p2sh)
   422  		}
   423  	}
   424  }
   425  
   426  // TestHasCanonicalPushes ensures the canonicalPush function properly determines
   427  // what is considered a canonical push for the purposes of removeOpcodeByData.
   428  func TestHasCanonicalPushes(t *testing.T) {
   429  	t.Parallel()
   430  
   431  	tests := []struct {
   432  		name     string
   433  		script   string
   434  		expected bool
   435  	}{
   436  		{
   437  			name: "does not parse",
   438  			script: "0x046708afdb0fe5548271967f1a67130b7105cd6a82" +
   439  				"8e03909a67962e0ea1f61d",
   440  			expected: false,
   441  		},
   442  		{
   443  			name:     "non-canonical push",
   444  			script:   "PUSHDATA1 0x04 0x01020304",
   445  			expected: false,
   446  		},
   447  	}
   448  
   449  	for i, test := range tests {
   450  		script := mustParseShortForm(test.script)
   451  		pops, err := txscript.TstParseScript(script)
   452  		if err != nil {
   453  			if test.expected {
   454  				t.Errorf("TstParseScript #%d failed: %v", i, err)
   455  			}
   456  			continue
   457  		}
   458  		for _, pop := range pops {
   459  			if txscript.TstHasCanonicalPushes(pop) != test.expected {
   460  				t.Errorf("TstHasCanonicalPushes: #%d (%s) "+
   461  					"wrong result\ngot: %v\nwant: %v", i,
   462  					test.name, true, test.expected)
   463  				break
   464  			}
   465  		}
   466  	}
   467  }
   468  
   469  // TestIsPushOnlyScript ensures the IsPushOnlyScript function returns the
   470  // expected results.
   471  func TestIsPushOnlyScript(t *testing.T) {
   472  	t.Parallel()
   473  
   474  	test := struct {
   475  		name     string
   476  		script   []byte
   477  		expected bool
   478  	}{
   479  		name: "does not parse",
   480  		script: mustParseShortForm("0x046708afdb0fe5548271967f1a67130" +
   481  			"b7105cd6a828e03909a67962e0ea1f61d"),
   482  		expected: false,
   483  	}
   484  
   485  	if txscript.IsPushOnlyScript(test.script) != test.expected {
   486  		t.Errorf("IsPushOnlyScript (%s) wrong result\ngot: %v\nwant: "+
   487  			"%v", test.name, true, test.expected)
   488  	}
   489  }
   490  
   491  // TestIsUnspendable ensures the IsUnspendable function returns the expected
   492  // results.
   493  func TestIsUnspendable(t *testing.T) {
   494  	t.Parallel()
   495  
   496  	tests := []struct {
   497  		name     string
   498  		pkScript []byte
   499  		expected bool
   500  	}{
   501  		{
   502  			// Unspendable
   503  			pkScript: []byte{0x6a, 0x04, 0x74, 0x65, 0x73, 0x74},
   504  			expected: true,
   505  		},
   506  		{
   507  			// Spendable
   508  			pkScript: []byte{0x76, 0xa9, 0x14, 0x29, 0x95, 0xa0,
   509  				0xfe, 0x68, 0x43, 0xfa, 0x9b, 0x95, 0x45,
   510  				0x97, 0xf0, 0xdc, 0xa7, 0xa4, 0x4d, 0xf6,
   511  				0xfa, 0x0b, 0x5c, 0x88, 0xac},
   512  			expected: false,
   513  		},
   514  	}
   515  
   516  	for i, test := range tests {
   517  		res := txscript.IsUnspendable(test.pkScript)
   518  		if res != test.expected {
   519  			t.Errorf("TestIsUnspendable #%d failed: got %v want %v",
   520  				i, res, test.expected)
   521  			continue
   522  		}
   523  	}
   524  }