engine_test.go raw

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