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 }