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

     1  package txscript
     2  
     3  import (
     4  	"bytes"
     5  	"testing"
     6  
     7  	"github.com/lbryio/lbcd/wire"
     8  )
     9  
    10  // TestParsePkScript ensures that the supported script types can be parsed
    11  // correctly and re-derived into its raw byte representation.
    12  func TestParsePkScript(t *testing.T) {
    13  	t.Parallel()
    14  
    15  	tests := []struct {
    16  		name     string
    17  		pkScript []byte
    18  		valid    bool
    19  	}{
    20  		{
    21  			name:     "empty output script",
    22  			pkScript: []byte{},
    23  			valid:    false,
    24  		},
    25  		{
    26  			name: "valid P2PKH",
    27  			pkScript: []byte{
    28  				// OP_DUP
    29  				0x76,
    30  				// OP_HASH160
    31  				0xa9,
    32  				// OP_DATA_20
    33  				0x14,
    34  				// <20-byte pubkey hash>
    35  				0xf0, 0x7a, 0xb8, 0xce, 0x72, 0xda, 0x4e, 0x76,
    36  				0x0b, 0x74, 0x7d, 0x48, 0xd6, 0x65, 0xec, 0x96,
    37  				0xad, 0xf0, 0x24, 0xf5,
    38  				// OP_EQUALVERIFY
    39  				0x88,
    40  				// OP_CHECKSIG
    41  				0xac,
    42  			},
    43  			valid: true,
    44  		},
    45  		// Invalid P2PKH - same as above but replaced OP_CHECKSIG with
    46  		// OP_CHECKSIGVERIFY.
    47  		{
    48  			name: "invalid P2PKH",
    49  			pkScript: []byte{
    50  				// OP_DUP
    51  				0x76,
    52  				// OP_HASH160
    53  				0xa9,
    54  				// OP_DATA_20
    55  				0x14,
    56  				// <20-byte pubkey hash>
    57  				0xf0, 0x7a, 0xb8, 0xce, 0x72, 0xda, 0x4e, 0x76,
    58  				0x0b, 0x74, 0x7d, 0x48, 0xd6, 0x65, 0xec, 0x96,
    59  				0xad, 0xf0, 0x24, 0xf5,
    60  				// OP_EQUALVERIFY
    61  				0x88,
    62  				// OP_CHECKSIGVERIFY
    63  				0xad,
    64  			},
    65  			valid: false,
    66  		},
    67  		{
    68  			name: "valid P2SH",
    69  			pkScript: []byte{
    70  				// OP_HASH160
    71  				0xA9,
    72  				// OP_DATA_20
    73  				0x14,
    74  				// <20-byte script hash>
    75  				0xec, 0x6f, 0x7a, 0x5a, 0xa8, 0xf2, 0xb1, 0x0c,
    76  				0xa5, 0x15, 0x04, 0x52, 0x3a, 0x60, 0xd4, 0x03,
    77  				0x06, 0xf6, 0x96, 0xcd,
    78  				// OP_EQUAL
    79  				0x87,
    80  			},
    81  			valid: true,
    82  		},
    83  		// Invalid P2SH - same as above but replaced OP_EQUAL with
    84  		// OP_EQUALVERIFY.
    85  		{
    86  			name: "invalid P2SH",
    87  			pkScript: []byte{
    88  				// OP_HASH160
    89  				0xA9,
    90  				// OP_DATA_20
    91  				0x14,
    92  				// <20-byte script hash>
    93  				0xec, 0x6f, 0x7a, 0x5a, 0xa8, 0xf2, 0xb1, 0x0c,
    94  				0xa5, 0x15, 0x04, 0x52, 0x3a, 0x60, 0xd4, 0x03,
    95  				0x06, 0xf6, 0x96, 0xcd,
    96  				// OP_EQUALVERIFY
    97  				0x88,
    98  			},
    99  			valid: false,
   100  		},
   101  		{
   102  			name: "valid v0 P2WSH",
   103  			pkScript: []byte{
   104  				// OP_0
   105  				0x00,
   106  				// OP_DATA_32
   107  				0x20,
   108  				// <32-byte script hash>
   109  				0xec, 0x6f, 0x7a, 0x5a, 0xa8, 0xf2, 0xb1, 0x0c,
   110  				0xa5, 0x15, 0x04, 0x52, 0x3a, 0x60, 0xd4, 0x03,
   111  				0x06, 0xf6, 0x96, 0xcd, 0x06, 0xf6, 0x96, 0xcd,
   112  				0x06, 0xf6, 0x96, 0xcd, 0x06, 0xf6, 0x96, 0xcd,
   113  			},
   114  			valid: true,
   115  		},
   116  		// Invalid v0 P2WSH - same as above but missing one byte.
   117  		{
   118  			name: "invalid v0 P2WSH",
   119  			pkScript: []byte{
   120  				// OP_0
   121  				0x00,
   122  				// OP_DATA_32
   123  				0x20,
   124  				// <32-byte script hash>
   125  				0xec, 0x6f, 0x7a, 0x5a, 0xa8, 0xf2, 0xb1, 0x0c,
   126  				0xa5, 0x15, 0x04, 0x52, 0x3a, 0x60, 0xd4, 0x03,
   127  				0x06, 0xf6, 0x96, 0xcd, 0x06, 0xf6, 0x96, 0xcd,
   128  				0x06, 0xf6, 0x96, 0xcd, 0x06, 0xf6, 0x96,
   129  			},
   130  			valid: false,
   131  		},
   132  		{
   133  			name: "valid v0 P2WPKH",
   134  			pkScript: []byte{
   135  				// OP_0
   136  				0x00,
   137  				// OP_DATA_20
   138  				0x14,
   139  				// <20-byte pubkey hash>
   140  				0xec, 0x6f, 0x7a, 0x5a, 0xa8, 0xf2, 0xb1, 0x0c,
   141  				0xa5, 0x15, 0x04, 0x52, 0x3a, 0x60, 0xd4, 0x03,
   142  				0x06, 0xf6, 0x96, 0xcd,
   143  			},
   144  			valid: true,
   145  		},
   146  		// Invalid v0 P2WPKH - same as above but missing one byte.
   147  		{
   148  			name: "invalid v0 P2WPKH",
   149  			pkScript: []byte{
   150  				// OP_0
   151  				0x00,
   152  				// OP_DATA_20
   153  				0x14,
   154  				// <20-byte pubkey hash>
   155  				0xec, 0x6f, 0x7a, 0x5a, 0xa8, 0xf2, 0xb1, 0x0c,
   156  				0xa5, 0x15, 0x04, 0x52, 0x3a, 0x60, 0xd4, 0x03,
   157  				0x06, 0xf6, 0x96,
   158  			},
   159  			valid: false,
   160  		},
   161  	}
   162  
   163  	for _, test := range tests {
   164  		t.Run(test.name, func(t *testing.T) {
   165  			pkScript, err := ParsePkScript(test.pkScript)
   166  			switch {
   167  			case err != nil && test.valid:
   168  				t.Fatalf("unable to parse valid pkScript=%x: %v",
   169  					test.pkScript, err)
   170  			case err == nil && !test.valid:
   171  				t.Fatalf("successfully parsed invalid pkScript=%x",
   172  					test.pkScript)
   173  			}
   174  
   175  			if !test.valid {
   176  				return
   177  			}
   178  
   179  			if !bytes.Equal(pkScript.Script(), test.pkScript) {
   180  				t.Fatalf("expected to re-derive pkScript=%x, "+
   181  					"got pkScript=%x", test.pkScript,
   182  					pkScript.Script())
   183  			}
   184  		})
   185  	}
   186  }
   187  
   188  // TestComputePkScript ensures that we can correctly re-derive an output's
   189  // pkScript by looking at the input's signature script/witness attempting to
   190  // spend it.
   191  func TestComputePkScript(t *testing.T) {
   192  	t.Parallel()
   193  
   194  	tests := []struct {
   195  		name      string
   196  		sigScript []byte
   197  		witness   wire.TxWitness
   198  		class     ScriptClass
   199  		pkScript  []byte
   200  	}{
   201  		{
   202  			name:      "empty sigScript and witness",
   203  			sigScript: nil,
   204  			witness:   nil,
   205  			class:     NonStandardTy,
   206  			pkScript:  nil,
   207  		},
   208  		{
   209  			name: "P2PKH sigScript",
   210  			sigScript: []byte{
   211  				// OP_DATA_73,
   212  				0x49,
   213  				// <73-byte sig>
   214  				0x30, 0x44, 0x02, 0x20, 0x65, 0x92, 0xd8, 0x8e,
   215  				0x1d, 0x0a, 0x4a, 0x3c, 0xc5, 0x9f, 0x92, 0xae,
   216  				0xfe, 0x62, 0x54, 0x74, 0xa9, 0x4d, 0x13, 0xa5,
   217  				0x9f, 0x84, 0x97, 0x78, 0xfc, 0xe7, 0xdf, 0x4b,
   218  				0xe0, 0xc2, 0x28, 0xd8, 0x02, 0x20, 0x2d, 0xea,
   219  				0x36, 0x96, 0x19, 0x1f, 0xb7, 0x00, 0xc5, 0xa7,
   220  				0x7e, 0x22, 0xd9, 0xfb, 0x6b, 0x42, 0x67, 0x42,
   221  				0xa4, 0x2c, 0xac, 0xdb, 0x74, 0xa2, 0x7c, 0x43,
   222  				0xcd, 0x89, 0xa0, 0xf9, 0x44, 0x54, 0x12, 0x74,
   223  				0x01,
   224  				// OP_DATA_33
   225  				0x21,
   226  				// <33-byte compressed pubkey>
   227  				0x02, 0x7d, 0x56, 0x12, 0x09, 0x75, 0x31, 0xc2,
   228  				0x17, 0xfd, 0xd4, 0xd2, 0xe1, 0x7a, 0x35, 0x4b,
   229  				0x17, 0xf2, 0x7a, 0xef, 0x30, 0x9f, 0xb2, 0x7f,
   230  				0x1f, 0x1f, 0x7b, 0x73, 0x7d, 0x9a, 0x24, 0x49,
   231  				0x90,
   232  			},
   233  			witness: nil,
   234  			class:   PubKeyHashTy,
   235  			pkScript: []byte{
   236  				// OP_DUP
   237  				0x76,
   238  				// OP_HASH160
   239  				0xa9,
   240  				// OP_DATA_20
   241  				0x14,
   242  				// <20-byte pubkey hash>
   243  				0xf0, 0x7a, 0xb8, 0xce, 0x72, 0xda, 0x4e, 0x76,
   244  				0x0b, 0x74, 0x7d, 0x48, 0xd6, 0x65, 0xec, 0x96,
   245  				0xad, 0xf0, 0x24, 0xf5,
   246  				// OP_EQUALVERIFY
   247  				0x88,
   248  				// OP_CHECKSIG
   249  				0xac,
   250  			},
   251  		},
   252  		{
   253  			name: "NP2WPKH sigScript",
   254  			// Since this is a NP2PKH output, the sigScript is a
   255  			// data push of a serialized v0 P2WPKH script.
   256  			sigScript: []byte{
   257  				// OP_DATA_16
   258  				0x16,
   259  				// <22-byte redeem script>
   260  				0x00, 0x14, 0x1d, 0x7c, 0xd6, 0xc7, 0x5c, 0x2e,
   261  				0x86, 0xf4, 0xcb, 0xf9, 0x8e, 0xae, 0xd2, 0x21,
   262  				0xb3, 0x0b, 0xd9, 0xa0, 0xb9, 0x28,
   263  			},
   264  			// NP2PKH outputs include a witness, but it is not
   265  			// needed to reconstruct the pkScript.
   266  			witness: nil,
   267  			class:   ScriptHashTy,
   268  			pkScript: []byte{
   269  				// OP_HASH160
   270  				0xa9,
   271  				// OP_DATA_20
   272  				0x14,
   273  				// <20-byte script hash>
   274  				0x90, 0x1c, 0x86, 0x94, 0xc0, 0x3f, 0xaf, 0xd5,
   275  				0x52, 0x28, 0x10, 0xe0, 0x33, 0x0f, 0x26, 0xe6,
   276  				0x7a, 0x85, 0x33, 0xcd,
   277  				// OP_EQUAL
   278  				0x87,
   279  			},
   280  		},
   281  		{
   282  			name: "P2SH sigScript",
   283  			sigScript: []byte{
   284  				0x00, 0x49, 0x30, 0x46, 0x02, 0x21, 0x00, 0xda,
   285  				0xe6, 0xb6, 0x14, 0x1b, 0xa7, 0x24, 0x4f, 0x54,
   286  				0x62, 0xb6, 0x2a, 0x3b, 0x27, 0x59, 0xde, 0xe4,
   287  				0x46, 0x76, 0x19, 0x4e, 0x6c, 0x56, 0x8d, 0x5b,
   288  				0x1c, 0xda, 0x96, 0x2d, 0x4f, 0x6d, 0x79, 0x02,
   289  				0x21, 0x00, 0xa6, 0x6f, 0x60, 0x34, 0x46, 0x09,
   290  				0x0a, 0x22, 0x3c, 0xec, 0x30, 0x33, 0xd9, 0x86,
   291  				0x24, 0xd2, 0x73, 0xa8, 0x91, 0x55, 0xa5, 0xe6,
   292  				0x96, 0x66, 0x0b, 0x6a, 0x50, 0xa3, 0x46, 0x45,
   293  				0xbb, 0x67, 0x01, 0x48, 0x30, 0x45, 0x02, 0x21,
   294  				0x00, 0xe2, 0x73, 0x49, 0xdb, 0x93, 0x82, 0xe1,
   295  				0xf8, 0x8d, 0xae, 0x97, 0x5c, 0x71, 0x19, 0xb7,
   296  				0x79, 0xb6, 0xda, 0x43, 0xa8, 0x4f, 0x16, 0x05,
   297  				0x87, 0x11, 0x9f, 0xe8, 0x12, 0x1d, 0x85, 0xae,
   298  				0xee, 0x02, 0x20, 0x6f, 0x23, 0x2d, 0x0a, 0x7b,
   299  				0x4b, 0xfa, 0xcd, 0x56, 0xa0, 0x72, 0xcc, 0x2a,
   300  				0x44, 0x81, 0x31, 0xd1, 0x0d, 0x73, 0x35, 0xf9,
   301  				0xa7, 0x54, 0x8b, 0xee, 0x1f, 0x70, 0xc5, 0x71,
   302  				0x0b, 0x37, 0x9e, 0x01, 0x47, 0x52, 0x21, 0x03,
   303  				0xab, 0x11, 0x5d, 0xa6, 0xdf, 0x4f, 0x54, 0x0b,
   304  				0xd6, 0xc9, 0xc4, 0xbe, 0x5f, 0xdd, 0xcc, 0x24,
   305  				0x58, 0x8e, 0x7c, 0x2c, 0xaf, 0x13, 0x82, 0x28,
   306  				0xdd, 0x0f, 0xce, 0x29, 0xfd, 0x65, 0xb8, 0x7c,
   307  				0x21, 0x02, 0x15, 0xe8, 0xb7, 0xbf, 0xfe, 0x8d,
   308  				0x9b, 0xbd, 0x45, 0x81, 0xf9, 0xc3, 0xb6, 0xf1,
   309  				0x6d, 0x67, 0x08, 0x36, 0xc3, 0x0b, 0xb2, 0xe0,
   310  				0x3e, 0xfd, 0x9d, 0x41, 0x03, 0xb5, 0x59, 0xeb,
   311  				0x67, 0xcd, 0x52, 0xae,
   312  			},
   313  			witness: nil,
   314  			class:   ScriptHashTy,
   315  			pkScript: []byte{
   316  				// OP_HASH160
   317  				0xA9,
   318  				// OP_DATA_20
   319  				0x14,
   320  				// <20-byte script hash>
   321  				0x12, 0xd6, 0x9c, 0xd3, 0x38, 0xa3, 0x8d, 0x0d,
   322  				0x77, 0x83, 0xcf, 0x22, 0x64, 0x97, 0x63, 0x3d,
   323  				0x3c, 0x20, 0x79, 0xea,
   324  				// OP_EQUAL
   325  				0x87,
   326  			},
   327  		},
   328  		// Invalid P2SH (non push-data only script).
   329  		{
   330  			name:      "invalid P2SH sigScript",
   331  			sigScript: []byte{0x6b, 0x65, 0x6b}, // kek
   332  			witness:   nil,
   333  			class:     NonStandardTy,
   334  			pkScript:  nil,
   335  		},
   336  		{
   337  			name:      "P2WSH witness",
   338  			sigScript: nil,
   339  			witness: [][]byte{
   340  				{},
   341  				// Witness script.
   342  				{
   343  					0x21, 0x03, 0x82, 0x62, 0xa6, 0xc6,
   344  					0xce, 0xc9, 0x3c, 0x2d, 0x3e, 0xcd,
   345  					0x6c, 0x60, 0x72, 0xef, 0xea, 0x86,
   346  					0xd0, 0x2f, 0xf8, 0xe3, 0x32, 0x8b,
   347  					0xbd, 0x02, 0x42, 0xb2, 0x0a, 0xf3,
   348  					0x42, 0x59, 0x90, 0xac, 0xac,
   349  				},
   350  			},
   351  			class: WitnessV0ScriptHashTy,
   352  			pkScript: []byte{
   353  				// OP_0
   354  				0x00,
   355  				// OP_DATA_32
   356  				0x20,
   357  				// <32-byte script hash>
   358  				0x01, 0xd5, 0xd9, 0x2e, 0xff, 0xa6, 0xff, 0xba,
   359  				0x3e, 0xfa, 0x37, 0x9f, 0x98, 0x30, 0xd0, 0xf7,
   360  				0x56, 0x18, 0xb1, 0x33, 0x93, 0x82, 0x71, 0x52,
   361  				0xd2, 0x6e, 0x43, 0x09, 0x00, 0x0e, 0x88, 0xb1,
   362  			},
   363  		},
   364  		{
   365  			name:      "P2WPKH witness",
   366  			sigScript: nil,
   367  			witness: [][]byte{
   368  				// Signature is not needed to re-derive the
   369  				// pkScript.
   370  				{},
   371  				// Compressed pubkey.
   372  				{
   373  					0x03, 0x82, 0x62, 0xa6, 0xc6, 0xce,
   374  					0xc9, 0x3c, 0x2d, 0x3e, 0xcd, 0x6c,
   375  					0x60, 0x72, 0xef, 0xea, 0x86, 0xd0,
   376  					0x2f, 0xf8, 0xe3, 0x32, 0x8b, 0xbd,
   377  					0x02, 0x42, 0xb2, 0x0a, 0xf3, 0x42,
   378  					0x59, 0x90, 0xac,
   379  				},
   380  			},
   381  			class: WitnessV0PubKeyHashTy,
   382  			pkScript: []byte{
   383  				// OP_0
   384  				0x00,
   385  				// OP_DATA_20
   386  				0x14,
   387  				// <20-byte pubkey hash>
   388  				0x1d, 0x7c, 0xd6, 0xc7, 0x5c, 0x2e, 0x86, 0xf4,
   389  				0xcb, 0xf9, 0x8e, 0xae, 0xd2, 0x21, 0xb3, 0x0b,
   390  				0xd9, 0xa0, 0xb9, 0x28,
   391  			},
   392  		},
   393  		// Invalid v0 P2WPKH - same as above but missing a byte on the
   394  		// public key.
   395  		{
   396  			name:      "invalid P2WPKH witness",
   397  			sigScript: nil,
   398  			witness: [][]byte{
   399  				// Signature is not needed to re-derive the
   400  				// pkScript.
   401  				{},
   402  				// Malformed compressed pubkey.
   403  				{
   404  					0x03, 0x82, 0x62, 0xa6, 0xc6, 0xce,
   405  					0xc9, 0x3c, 0x2d, 0x3e, 0xcd, 0x6c,
   406  					0x60, 0x72, 0xef, 0xea, 0x86, 0xd0,
   407  					0x2f, 0xf8, 0xe3, 0x32, 0x8b, 0xbd,
   408  					0x02, 0x42, 0xb2, 0x0a, 0xf3, 0x42,
   409  					0x59, 0x90,
   410  				},
   411  			},
   412  			class:    WitnessV0PubKeyHashTy,
   413  			pkScript: nil,
   414  		},
   415  	}
   416  
   417  	for _, test := range tests {
   418  		t.Run(test.name, func(t *testing.T) {
   419  			valid := test.pkScript != nil
   420  			pkScript, err := ComputePkScript(
   421  				test.sigScript, test.witness,
   422  			)
   423  			if err != nil && valid {
   424  				t.Fatalf("unable to compute pkScript: %v", err)
   425  			}
   426  
   427  			if !valid {
   428  				return
   429  			}
   430  
   431  			if pkScript.Class() != test.class {
   432  				t.Fatalf("expected pkScript of type %v, got %v",
   433  					test.class, pkScript.Class())
   434  			}
   435  			if !bytes.Equal(pkScript.Script(), test.pkScript) {
   436  				t.Fatalf("expected pkScript=%x, got pkScript=%x",
   437  					test.pkScript, pkScript.Script())
   438  			}
   439  		})
   440  	}
   441  }