github.com/decred/dcrlnd@v0.7.6/chainscan/pkscript_test.go (about)

     1  package chainscan
     2  
     3  import (
     4  	"bytes"
     5  	"testing"
     6  
     7  	"github.com/decred/dcrd/txscript/v4/stdscript"
     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  
   103  	scriptVersion := uint16(0)
   104  
   105  	for _, test := range tests {
   106  		t.Run(test.name, func(t *testing.T) {
   107  			pkScript, err := ParsePkScript(
   108  				scriptVersion, test.pkScript,
   109  			)
   110  			switch {
   111  			case err != nil && test.valid:
   112  				t.Fatalf("unable to parse valid pkScript=%x: %v",
   113  					test.pkScript, err)
   114  			case err == nil && !test.valid:
   115  				t.Fatalf("successfully parsed invalid pkScript=%x",
   116  					test.pkScript)
   117  			}
   118  
   119  			if !test.valid {
   120  				return
   121  			}
   122  
   123  			if !bytes.Equal(pkScript.Script(), test.pkScript) {
   124  				t.Fatalf("expected to re-derive pkScript=%x, "+
   125  					"got pkScript=%x", test.pkScript,
   126  					pkScript.Script())
   127  			}
   128  		})
   129  	}
   130  }
   131  
   132  // TestComputePkScript ensures that we can correctly re-derive an output's
   133  // pkScript by looking at the input's signature script/witness attempting to
   134  // spend it.
   135  func TestComputePkScript(t *testing.T) {
   136  	t.Parallel()
   137  
   138  	tests := []struct {
   139  		name      string
   140  		sigScript []byte
   141  		class     stdscript.ScriptType
   142  		pkScript  []byte
   143  	}{
   144  		{
   145  			name:      "empty sigScript and witness",
   146  			sigScript: nil,
   147  			class:     stdscript.STNonStandard,
   148  			pkScript:  nil,
   149  		},
   150  		{
   151  			name: "P2PKH sigScript",
   152  			sigScript: []byte{
   153  				// OP_DATA_71,
   154  				0x47,
   155  				// <71-byte sig>
   156  				0x30, 0x44, 0x02, 0x20, 0x65, 0x92, 0xd8, 0x8e,
   157  				0x1d, 0x0a, 0x4a, 0x3c, 0xc5, 0x9f, 0x92, 0xae,
   158  				0xfe, 0x62, 0x54, 0x74, 0xa9, 0x4d, 0x13, 0xa5,
   159  				0x9f, 0x84, 0x97, 0x78, 0xfc, 0xe7, 0xdf, 0x4b,
   160  				0xe0, 0xc2, 0x28, 0xd8, 0x02, 0x20, 0x2d, 0xea,
   161  				0x36, 0x96, 0x19, 0x1f, 0xb7, 0x00, 0xc5, 0xa7,
   162  				0x7e, 0x22, 0xd9, 0xfb, 0x6b, 0x42, 0x67, 0x42,
   163  				0xa4, 0x2c, 0xac, 0xdb, 0x74, 0xa2, 0x7c, 0x43,
   164  				0xcd, 0x89, 0xa0, 0xf9, 0x44, 0x54, 0x01,
   165  				// OP_DATA_33
   166  				0x21,
   167  				// <33-byte compressed pubkey>
   168  				0x02, 0x7d, 0x56, 0x12, 0x09, 0x75, 0x31, 0xc2,
   169  				0x17, 0xfd, 0xd4, 0xd2, 0xe1, 0x7a, 0x35, 0x4b,
   170  				0x17, 0xf2, 0x7a, 0xef, 0x30, 0x9f, 0xb2, 0x7f,
   171  				0x1f, 0x1f, 0x7b, 0x73, 0x7d, 0x9a, 0x24, 0x49,
   172  				0x90,
   173  			},
   174  			class: stdscript.STPubKeyHashEcdsaSecp256k1,
   175  			pkScript: []byte{
   176  				// OP_DUP
   177  				0x76,
   178  				// OP_HASH160
   179  				0xa9,
   180  				// OP_DATA_20
   181  				0x14,
   182  				// <20-byte pubkey hash>
   183  				0x05, 0x4c, 0xe3, 0xc9, 0x05, 0xa1, 0x90, 0x64,
   184  				0x58, 0x72, 0x7c, 0x39, 0x2c, 0xdc, 0xea, 0x2d,
   185  				0xf2, 0xb4, 0x3a, 0xec,
   186  				// OP_EQUALVERIFY
   187  				0x88,
   188  				// OP_CHECKSIG
   189  				0xac,
   190  			},
   191  		},
   192  		{
   193  			name: "P2PKH sigScript with smaller sig",
   194  			sigScript: []byte{
   195  				// OP_DATA_69
   196  				0x45,
   197  				// <69-byte-sig>
   198  				0x30, 0x42, 0x2, 0x1f, 0x4, 0x9, 0x38, 0x43,
   199  				0x27, 0x29, 0x24, 0x6f, 0x30, 0x1a, 0x67, 0x65,
   200  				0x4, 0x34, 0xb4, 0x27, 0xaa, 0x5c, 0x3a, 0x28,
   201  				0x36, 0xa3, 0x70, 0x6, 0xd5, 0xf0, 0x26, 0x97,
   202  				0xb1, 0x63, 0x10, 0x2, 0x1f, 0xe, 0xbf, 0xe0,
   203  				0x83, 0xcf, 0x50, 0xfe, 0xdf, 0xec, 0x62, 0x7f,
   204  				0x82, 0x58, 0xf0, 0x20, 0xe3, 0x5d, 0xb, 0xf8,
   205  				0x8a, 0x60, 0xb0, 0x37, 0x70, 0x8b, 0x33, 0xa1,
   206  				0xb3, 0xab, 0xcf, 0x9f, 0x1,
   207  				// OP_DATA_33
   208  				0x21,
   209  				// <33-byte-compressed pubkey>
   210  				0x3, 0xc9, 0x38, 0xac, 0xde, 0x89, 0x9e, 0x70,
   211  				0x80, 0xad, 0x60, 0xd3, 0x7, 0xe6, 0x75, 0xf,
   212  				0xd, 0xb9, 0x68, 0xed, 0x5d, 0xca, 0x32, 0x38,
   213  				0xcb, 0x4f, 0x53, 0x6d, 0xbd, 0x1, 0x16, 0x40,
   214  				0x28,
   215  			},
   216  			class: stdscript.STPubKeyHashEcdsaSecp256k1,
   217  			pkScript: []byte{
   218  				// OP_DUP
   219  				0x76,
   220  				// OP_HASH160
   221  				0xa9,
   222  				// OP_DATA_20
   223  				0x14,
   224  				// <20-byte pubkey hash>
   225  				0x96, 0x49, 0xeb, 0xb1, 0x5e, 0x79, 0xa4, 0xa0,
   226  				0x6b, 0x39, 0x53, 0xc3, 0x9b, 0x36, 0x49, 0xcf,
   227  				0xeb, 0xb8, 0xe4, 0xe9,
   228  				// OP_EQUALVERIFY
   229  				0x88,
   230  				// OP_CHECKSIG
   231  				0xac,
   232  			},
   233  		},
   234  		{
   235  			name: "P2PKH sigScript with smallest sig",
   236  			sigScript: []byte{
   237  				// OP_DATA_08
   238  				0x08,
   239  				// <69-byte-sig>
   240  				0x30, 0x42, 0x2, 0x1f, 0x4, 0x9, 0x38, 0x43,
   241  				// OP_DATA_33
   242  				0x21,
   243  				// <33-byte-compressed pubkey>
   244  				0x3, 0xc9, 0x38, 0xac, 0xde, 0x89, 0x9e, 0x70,
   245  				0x80, 0xad, 0x60, 0xd3, 0x7, 0xe6, 0x75, 0xf,
   246  				0xd, 0xb9, 0x68, 0xed, 0x5d, 0xca, 0x32, 0x38,
   247  				0xcb, 0x4f, 0x53, 0x6d, 0xbd, 0x1, 0x16, 0x40,
   248  				0x28,
   249  			},
   250  			class: stdscript.STPubKeyHashEcdsaSecp256k1,
   251  			pkScript: []byte{
   252  				// OP_DUP
   253  				0x76,
   254  				// OP_HASH160
   255  				0xa9,
   256  				// OP_DATA_20
   257  				0x14,
   258  				// <20-byte pubkey hash>
   259  				0x96, 0x49, 0xeb, 0xb1, 0x5e, 0x79, 0xa4, 0xa0,
   260  				0x6b, 0x39, 0x53, 0xc3, 0x9b, 0x36, 0x49, 0xcf,
   261  				0xeb, 0xb8, 0xe4, 0xe9,
   262  				// OP_EQUALVERIFY
   263  				0x88,
   264  				// OP_CHECKSIG
   265  				0xac,
   266  			},
   267  		},
   268  
   269  		{
   270  			name: "P2SH sigScript",
   271  			sigScript: []byte{
   272  				// OP_DATA_73
   273  				0x49,
   274  				// 73 byte data push
   275  				0x30, 0x46, 0x02, 0x21, 0x00, 0xda,
   276  				0xe6, 0xb6, 0x14, 0x1b, 0xa7, 0x24, 0x4f, 0x54,
   277  				0x62, 0xb6, 0x2a, 0x3b, 0x27, 0x59, 0xde, 0xe4,
   278  				0x46, 0x76, 0x19, 0x4e, 0x6c, 0x56, 0x8d, 0x5b,
   279  				0x1c, 0xda, 0x96, 0x2d, 0x4f, 0x6d, 0x79, 0x02,
   280  				0x21, 0x00, 0xa6, 0x6f, 0x60, 0x34, 0x46, 0x09,
   281  				0x0a, 0x22, 0x3c, 0xec, 0x30, 0x33, 0xd9, 0x86,
   282  				0x24, 0xd2, 0x73, 0xa8, 0x91, 0x55, 0xa5, 0xe6,
   283  				0x96, 0x66, 0x0b, 0x6a, 0x50, 0xa3, 0x46, 0x45,
   284  				0xbb, 0x67, 0x01,
   285  				// OP_DATA_72
   286  				0x48,
   287  				// 72 byte data push
   288  				0x30, 0x45, 0x02, 0x21,
   289  				0x00, 0xe2, 0x73, 0x49, 0xdb, 0x93, 0x82, 0xe1,
   290  				0xf8, 0x8d, 0xae, 0x97, 0x5c, 0x71, 0x19, 0xb7,
   291  				0x79, 0xb6, 0xda, 0x43, 0xa8, 0x4f, 0x16, 0x05,
   292  				0x87, 0x11, 0x9f, 0xe8, 0x12, 0x1d, 0x85, 0xae,
   293  				0xee, 0x02, 0x20, 0x6f, 0x23, 0x2d, 0x0a, 0x7b,
   294  				0x4b, 0xfa, 0xcd, 0x56, 0xa0, 0x72, 0xcc, 0x2a,
   295  				0x44, 0x81, 0x31, 0xd1, 0x0d, 0x73, 0x35, 0xf9,
   296  				0xa7, 0x54, 0x8b, 0xee, 0x1f, 0x70, 0xc5, 0x71,
   297  				0x0b, 0x37, 0x9e, 0x01,
   298  				// OP_DATA_71
   299  				0x47,
   300  				// 71 byte data push (final redeem script)
   301  				0x52, 0x21, 0x03,
   302  				0xab, 0x11, 0x5d, 0xa6, 0xdf, 0x4f, 0x54, 0x0b,
   303  				0xd6, 0xc9, 0xc4, 0xbe, 0x5f, 0xdd, 0xcc, 0x24,
   304  				0x58, 0x8e, 0x7c, 0x2c, 0xaf, 0x13, 0x82, 0x28,
   305  				0xdd, 0x0f, 0xce, 0x29, 0xfd, 0x65, 0xb8, 0x7c,
   306  				0x21, 0x02, 0x15, 0xe8, 0xb7, 0xbf, 0xfe, 0x8d,
   307  				0x9b, 0xbd, 0x45, 0x81, 0xf9, 0xc3, 0xb6, 0xf1,
   308  				0x6d, 0x67, 0x08, 0x36, 0xc3, 0x0b, 0xb2, 0xe0,
   309  				0x3e, 0xfd, 0x9d, 0x41, 0x03, 0xb5, 0x59, 0xeb,
   310  				0x67, 0xcd, 0x52, 0xae,
   311  			},
   312  			class: stdscript.STScriptHash,
   313  			pkScript: []byte{
   314  				// OP_HASH160
   315  				0xA9,
   316  				// OP_DATA_20
   317  				0x14,
   318  				// <20-byte script hash>
   319  				0xab, 0x82, 0xa2, 0x58, 0x8c, 0x0f, 0x78, 0xb8,
   320  				0x4e, 0x2b, 0xbb, 0xdb, 0xf0, 0x72, 0x1a, 0x0d,
   321  				0xce, 0x4a, 0xff, 0xb9,
   322  				// OP_EQUAL
   323  				0x87,
   324  			},
   325  		},
   326  		// Invalid P2SH (non push-data only script).
   327  		{
   328  			name:      "invalid P2SH sigScript",
   329  			sigScript: []byte{0x6b, 0x65, 0x6b}, // kek
   330  			class:     stdscript.STNonStandard,
   331  			pkScript:  nil,
   332  		},
   333  	}
   334  
   335  	scriptVersion := uint16(0)
   336  
   337  	for _, test := range tests {
   338  		t.Run(test.name, func(t *testing.T) {
   339  			valid := test.pkScript != nil
   340  			pkScript, err := ComputePkScript(
   341  				scriptVersion, test.sigScript,
   342  			)
   343  			if err != nil && valid {
   344  				t.Fatalf("unable to compute pkScript: %v", err)
   345  			}
   346  
   347  			if !valid {
   348  				return
   349  			}
   350  
   351  			if pkScript.Class() != test.class {
   352  				t.Fatalf("expected pkScript of type %v, got %v",
   353  					test.class, pkScript.Class())
   354  			}
   355  			if !bytes.Equal(pkScript.Script(), test.pkScript) {
   356  				t.Fatalf("expected pkScript=%x, got pkScript=%x",
   357  					test.pkScript, pkScript.Script())
   358  			}
   359  		})
   360  	}
   361  }