github.com/palcoin-project/palcd@v1.0.0/txscript/pkscript_test.go (about) 1 package txscript 2 3 import ( 4 "bytes" 5 "testing" 6 7 "github.com/palcoin-project/palcd/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 }