github.com/lbryio/lbcd@v0.22.119/txscript/engine_test.go (about)

     1  // Copyright (c) 2013-2017 The btcsuite developers
     2  // Copyright (c) 2015-2019 The Decred 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
     7  
     8  import (
     9  	"testing"
    10  
    11  	"github.com/lbryio/lbcd/chaincfg/chainhash"
    12  	"github.com/lbryio/lbcd/wire"
    13  )
    14  
    15  // TestBadPC sets the pc to a deliberately bad result then confirms that Step
    16  // and Disasm fail correctly.
    17  func TestBadPC(t *testing.T) {
    18  	t.Parallel()
    19  
    20  	tests := []struct {
    21  		scriptIdx int
    22  	}{
    23  		{scriptIdx: 2},
    24  		{scriptIdx: 3},
    25  	}
    26  
    27  	// tx with almost empty scripts.
    28  	tx := &wire.MsgTx{
    29  		Version: 1,
    30  		TxIn: []*wire.TxIn{
    31  			{
    32  				PreviousOutPoint: wire.OutPoint{
    33  					Hash: chainhash.Hash([32]byte{
    34  						0xc9, 0x97, 0xa5, 0xe5,
    35  						0x6e, 0x10, 0x41, 0x02,
    36  						0xfa, 0x20, 0x9c, 0x6a,
    37  						0x85, 0x2d, 0xd9, 0x06,
    38  						0x60, 0xa2, 0x0b, 0x2d,
    39  						0x9c, 0x35, 0x24, 0x23,
    40  						0xed, 0xce, 0x25, 0x85,
    41  						0x7f, 0xcd, 0x37, 0x04,
    42  					}),
    43  					Index: 0,
    44  				},
    45  				SignatureScript: mustParseShortForm("NOP"),
    46  				Sequence:        4294967295,
    47  			},
    48  		},
    49  		TxOut: []*wire.TxOut{{
    50  			Value:    1000000000,
    51  			PkScript: nil,
    52  		}},
    53  		LockTime: 0,
    54  	}
    55  	pkScript := mustParseShortForm("NOP")
    56  
    57  	for _, test := range tests {
    58  		vm, err := NewEngine(pkScript, tx, 0, 0, nil, nil, -1)
    59  		if err != nil {
    60  			t.Errorf("Failed to create script: %v", err)
    61  		}
    62  
    63  		// Set to after all scripts.
    64  		vm.scriptIdx = test.scriptIdx
    65  
    66  		// Ensure attempting to step fails.
    67  		_, err = vm.Step()
    68  		if err == nil {
    69  			t.Errorf("Step with invalid pc (%v) succeeds!", test)
    70  			continue
    71  		}
    72  
    73  		// Ensure attempting to disassemble the current program counter fails.
    74  		_, err = vm.DisasmPC()
    75  		if err == nil {
    76  			t.Errorf("DisasmPC with invalid pc (%v) succeeds!", test)
    77  		}
    78  	}
    79  }
    80  
    81  // TestCheckErrorCondition tests the execute early test in CheckErrorCondition()
    82  // since most code paths are tested elsewhere.
    83  func TestCheckErrorCondition(t *testing.T) {
    84  	t.Parallel()
    85  
    86  	// tx with almost empty scripts.
    87  	tx := &wire.MsgTx{
    88  		Version: 1,
    89  		TxIn: []*wire.TxIn{{
    90  			PreviousOutPoint: wire.OutPoint{
    91  				Hash: chainhash.Hash([32]byte{
    92  					0xc9, 0x97, 0xa5, 0xe5,
    93  					0x6e, 0x10, 0x41, 0x02,
    94  					0xfa, 0x20, 0x9c, 0x6a,
    95  					0x85, 0x2d, 0xd9, 0x06,
    96  					0x60, 0xa2, 0x0b, 0x2d,
    97  					0x9c, 0x35, 0x24, 0x23,
    98  					0xed, 0xce, 0x25, 0x85,
    99  					0x7f, 0xcd, 0x37, 0x04,
   100  				}),
   101  				Index: 0,
   102  			},
   103  			SignatureScript: nil,
   104  			Sequence:        4294967295,
   105  		}},
   106  		TxOut: []*wire.TxOut{{
   107  			Value:    1000000000,
   108  			PkScript: nil,
   109  		}},
   110  		LockTime: 0,
   111  	}
   112  	pkScript := mustParseShortForm("NOP NOP NOP NOP NOP NOP NOP NOP NOP" +
   113  		" NOP TRUE")
   114  
   115  	vm, err := NewEngine(pkScript, tx, 0, 0, nil, nil, 0)
   116  	if err != nil {
   117  		t.Errorf("failed to create script: %v", err)
   118  	}
   119  
   120  	for i := 0; i < len(pkScript)-1; i++ {
   121  		done, err := vm.Step()
   122  		if err != nil {
   123  			t.Fatalf("failed to step %dth time: %v", i, err)
   124  		}
   125  		if done {
   126  			t.Fatalf("finshed early on %dth time", i)
   127  		}
   128  
   129  		err = vm.CheckErrorCondition(false)
   130  		if !IsErrorCode(err, ErrScriptUnfinished) {
   131  			t.Fatalf("got unexepected error %v on %dth iteration",
   132  				err, i)
   133  		}
   134  	}
   135  	done, err := vm.Step()
   136  	if err != nil {
   137  		t.Fatalf("final step failed %v", err)
   138  	}
   139  	if !done {
   140  		t.Fatalf("final step isn't done!")
   141  	}
   142  
   143  	err = vm.CheckErrorCondition(false)
   144  	if err != nil {
   145  		t.Errorf("unexpected error %v on final check", err)
   146  	}
   147  }
   148  
   149  // TestInvalidFlagCombinations ensures the script engine returns the expected
   150  // error when disallowed flag combinations are specified.
   151  func TestInvalidFlagCombinations(t *testing.T) {
   152  	t.Parallel()
   153  
   154  	tests := []ScriptFlags{
   155  		ScriptVerifyCleanStack,
   156  	}
   157  
   158  	// tx with almost empty scripts.
   159  	tx := &wire.MsgTx{
   160  		Version: 1,
   161  		TxIn: []*wire.TxIn{
   162  			{
   163  				PreviousOutPoint: wire.OutPoint{
   164  					Hash: chainhash.Hash([32]byte{
   165  						0xc9, 0x97, 0xa5, 0xe5,
   166  						0x6e, 0x10, 0x41, 0x02,
   167  						0xfa, 0x20, 0x9c, 0x6a,
   168  						0x85, 0x2d, 0xd9, 0x06,
   169  						0x60, 0xa2, 0x0b, 0x2d,
   170  						0x9c, 0x35, 0x24, 0x23,
   171  						0xed, 0xce, 0x25, 0x85,
   172  						0x7f, 0xcd, 0x37, 0x04,
   173  					}),
   174  					Index: 0,
   175  				},
   176  				SignatureScript: []uint8{OP_NOP},
   177  				Sequence:        4294967295,
   178  			},
   179  		},
   180  		TxOut: []*wire.TxOut{
   181  			{
   182  				Value:    1000000000,
   183  				PkScript: nil,
   184  			},
   185  		},
   186  		LockTime: 0,
   187  	}
   188  	pkScript := []byte{OP_NOP}
   189  
   190  	for i, test := range tests {
   191  		_, err := NewEngine(pkScript, tx, 0, test, nil, nil, -1)
   192  		if !IsErrorCode(err, ErrInvalidFlags) {
   193  			t.Fatalf("TestInvalidFlagCombinations #%d unexpected "+
   194  				"error: %v", i, err)
   195  		}
   196  	}
   197  }
   198  
   199  // TestCheckPubKeyEncoding ensures the internal checkPubKeyEncoding function
   200  // works as expected.
   201  func TestCheckPubKeyEncoding(t *testing.T) {
   202  	t.Parallel()
   203  
   204  	tests := []struct {
   205  		name    string
   206  		key     []byte
   207  		isValid bool
   208  	}{
   209  		{
   210  			name: "uncompressed ok",
   211  			key: hexToBytes("0411db93e1dcdb8a016b49840f8c53bc1eb68" +
   212  				"a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf" +
   213  				"9744464f82e160bfa9b8b64f9d4c03f999b8643f656b" +
   214  				"412a3"),
   215  			isValid: true,
   216  		},
   217  		{
   218  			name: "compressed ok",
   219  			key: hexToBytes("02ce0b14fb842b1ba549fdd675c98075f12e9" +
   220  				"c510f8ef52bd021a9a1f4809d3b4d"),
   221  			isValid: true,
   222  		},
   223  		{
   224  			name: "compressed ok",
   225  			key: hexToBytes("032689c7c2dab13309fb143e0e8fe39634252" +
   226  				"1887e976690b6b47f5b2a4b7d448e"),
   227  			isValid: true,
   228  		},
   229  		{
   230  			name: "hybrid",
   231  			key: hexToBytes("0679be667ef9dcbbac55a06295ce870b07029" +
   232  				"bfcdb2dce28d959f2815b16f81798483ada7726a3c46" +
   233  				"55da4fbfc0e1108a8fd17b448a68554199c47d08ffb1" +
   234  				"0d4b8"),
   235  			isValid: false,
   236  		},
   237  		{
   238  			name:    "empty",
   239  			key:     nil,
   240  			isValid: false,
   241  		},
   242  	}
   243  
   244  	vm := Engine{flags: ScriptVerifyStrictEncoding}
   245  	for _, test := range tests {
   246  		err := vm.checkPubKeyEncoding(test.key)
   247  		if err != nil && test.isValid {
   248  			t.Errorf("checkSignatureEncoding test '%s' failed "+
   249  				"when it should have succeeded: %v", test.name,
   250  				err)
   251  		} else if err == nil && !test.isValid {
   252  			t.Errorf("checkSignatureEncooding test '%s' succeeded "+
   253  				"when it should have failed", test.name)
   254  		}
   255  	}
   256  
   257  }
   258  
   259  // TestCheckSignatureEncoding ensures the internal checkSignatureEncoding
   260  // function works as expected.
   261  func TestCheckSignatureEncoding(t *testing.T) {
   262  	t.Parallel()
   263  
   264  	tests := []struct {
   265  		name    string
   266  		sig     []byte
   267  		isValid bool
   268  	}{
   269  		{
   270  			name: "valid signature",
   271  			sig: hexToBytes("304402204e45e16932b8af514961a1d3a1a25" +
   272  				"fdf3f4f7732e9d624c6c61548ab5fb8cd41022018152" +
   273  				"2ec8eca07de4860a4acdd12909d831cc56cbbac46220" +
   274  				"82221a8768d1d09"),
   275  			isValid: true,
   276  		},
   277  		{
   278  			name:    "empty.",
   279  			sig:     nil,
   280  			isValid: false,
   281  		},
   282  		{
   283  			name: "bad magic",
   284  			sig: hexToBytes("314402204e45e16932b8af514961a1d3a1a25" +
   285  				"fdf3f4f7732e9d624c6c61548ab5fb8cd41022018152" +
   286  				"2ec8eca07de4860a4acdd12909d831cc56cbbac46220" +
   287  				"82221a8768d1d09"),
   288  			isValid: false,
   289  		},
   290  		{
   291  			name: "bad 1st int marker magic",
   292  			sig: hexToBytes("304403204e45e16932b8af514961a1d3a1a25" +
   293  				"fdf3f4f7732e9d624c6c61548ab5fb8cd41022018152" +
   294  				"2ec8eca07de4860a4acdd12909d831cc56cbbac46220" +
   295  				"82221a8768d1d09"),
   296  			isValid: false,
   297  		},
   298  		{
   299  			name: "bad 2nd int marker",
   300  			sig: hexToBytes("304402204e45e16932b8af514961a1d3a1a25" +
   301  				"fdf3f4f7732e9d624c6c61548ab5fb8cd41032018152" +
   302  				"2ec8eca07de4860a4acdd12909d831cc56cbbac46220" +
   303  				"82221a8768d1d09"),
   304  			isValid: false,
   305  		},
   306  		{
   307  			name: "short len",
   308  			sig: hexToBytes("304302204e45e16932b8af514961a1d3a1a25" +
   309  				"fdf3f4f7732e9d624c6c61548ab5fb8cd41022018152" +
   310  				"2ec8eca07de4860a4acdd12909d831cc56cbbac46220" +
   311  				"82221a8768d1d09"),
   312  			isValid: false,
   313  		},
   314  		{
   315  			name: "long len",
   316  			sig: hexToBytes("304502204e45e16932b8af514961a1d3a1a25" +
   317  				"fdf3f4f7732e9d624c6c61548ab5fb8cd41022018152" +
   318  				"2ec8eca07de4860a4acdd12909d831cc56cbbac46220" +
   319  				"82221a8768d1d09"),
   320  			isValid: false,
   321  		},
   322  		{
   323  			name: "long X",
   324  			sig: hexToBytes("304402424e45e16932b8af514961a1d3a1a25" +
   325  				"fdf3f4f7732e9d624c6c61548ab5fb8cd41022018152" +
   326  				"2ec8eca07de4860a4acdd12909d831cc56cbbac46220" +
   327  				"82221a8768d1d09"),
   328  			isValid: false,
   329  		},
   330  		{
   331  			name: "long Y",
   332  			sig: hexToBytes("304402204e45e16932b8af514961a1d3a1a25" +
   333  				"fdf3f4f7732e9d624c6c61548ab5fb8cd41022118152" +
   334  				"2ec8eca07de4860a4acdd12909d831cc56cbbac46220" +
   335  				"82221a8768d1d09"),
   336  			isValid: false,
   337  		},
   338  		{
   339  			name: "short Y",
   340  			sig: hexToBytes("304402204e45e16932b8af514961a1d3a1a25" +
   341  				"fdf3f4f7732e9d624c6c61548ab5fb8cd41021918152" +
   342  				"2ec8eca07de4860a4acdd12909d831cc56cbbac46220" +
   343  				"82221a8768d1d09"),
   344  			isValid: false,
   345  		},
   346  		{
   347  			name: "trailing crap",
   348  			sig: hexToBytes("304402204e45e16932b8af514961a1d3a1a25" +
   349  				"fdf3f4f7732e9d624c6c61548ab5fb8cd41022018152" +
   350  				"2ec8eca07de4860a4acdd12909d831cc56cbbac46220" +
   351  				"82221a8768d1d0901"),
   352  			isValid: false,
   353  		},
   354  		{
   355  			name: "X == N ",
   356  			sig: hexToBytes("30440220fffffffffffffffffffffffffffff" +
   357  				"ffebaaedce6af48a03bbfd25e8cd0364141022018152" +
   358  				"2ec8eca07de4860a4acdd12909d831cc56cbbac46220" +
   359  				"82221a8768d1d09"),
   360  			isValid: false,
   361  		},
   362  		{
   363  			name: "X == N ",
   364  			sig: hexToBytes("30440220fffffffffffffffffffffffffffff" +
   365  				"ffebaaedce6af48a03bbfd25e8cd0364142022018152" +
   366  				"2ec8eca07de4860a4acdd12909d831cc56cbbac46220" +
   367  				"82221a8768d1d09"),
   368  			isValid: false,
   369  		},
   370  		{
   371  			name: "Y == N",
   372  			sig: hexToBytes("304402204e45e16932b8af514961a1d3a1a25" +
   373  				"fdf3f4f7732e9d624c6c61548ab5fb8cd410220fffff" +
   374  				"ffffffffffffffffffffffffffebaaedce6af48a03bb" +
   375  				"fd25e8cd0364141"),
   376  			isValid: false,
   377  		},
   378  		{
   379  			name: "Y > N",
   380  			sig: hexToBytes("304402204e45e16932b8af514961a1d3a1a25" +
   381  				"fdf3f4f7732e9d624c6c61548ab5fb8cd410220fffff" +
   382  				"ffffffffffffffffffffffffffebaaedce6af48a03bb" +
   383  				"fd25e8cd0364142"),
   384  			isValid: false,
   385  		},
   386  		{
   387  			name: "0 len X",
   388  			sig: hexToBytes("302402000220181522ec8eca07de4860a4acd" +
   389  				"d12909d831cc56cbbac4622082221a8768d1d09"),
   390  			isValid: false,
   391  		},
   392  		{
   393  			name: "0 len Y",
   394  			sig: hexToBytes("302402204e45e16932b8af514961a1d3a1a25" +
   395  				"fdf3f4f7732e9d624c6c61548ab5fb8cd410200"),
   396  			isValid: false,
   397  		},
   398  		{
   399  			name: "extra R padding",
   400  			sig: hexToBytes("30450221004e45e16932b8af514961a1d3a1a" +
   401  				"25fdf3f4f7732e9d624c6c61548ab5fb8cd410220181" +
   402  				"522ec8eca07de4860a4acdd12909d831cc56cbbac462" +
   403  				"2082221a8768d1d09"),
   404  			isValid: false,
   405  		},
   406  		{
   407  			name: "extra S padding",
   408  			sig: hexToBytes("304502204e45e16932b8af514961a1d3a1a25" +
   409  				"fdf3f4f7732e9d624c6c61548ab5fb8cd41022100181" +
   410  				"522ec8eca07de4860a4acdd12909d831cc56cbbac462" +
   411  				"2082221a8768d1d09"),
   412  			isValid: false,
   413  		},
   414  	}
   415  
   416  	vm := Engine{flags: ScriptVerifyStrictEncoding}
   417  	for _, test := range tests {
   418  		err := vm.checkSignatureEncoding(test.sig)
   419  		if err != nil && test.isValid {
   420  			t.Errorf("checkSignatureEncoding test '%s' failed "+
   421  				"when it should have succeeded: %v", test.name,
   422  				err)
   423  		} else if err == nil && !test.isValid {
   424  			t.Errorf("checkSignatureEncooding test '%s' succeeded "+
   425  				"when it should have failed", test.name)
   426  		}
   427  	}
   428  }