github.com/BlockABC/godash@v0.0.0-20191112120524-f4aa3a32c566/txscript/script_test.go (about) 1 // Copyright (c) 2013-2015 The btcsuite developers 2 // Copyright (c) 2016 The Dash developers 3 // Use of this source code is governed by an ISC 4 // license that can be found in the LICENSE file. 5 6 package txscript_test 7 8 import ( 9 "bytes" 10 "reflect" 11 "testing" 12 13 "github.com/BlockABC/godash/txscript" 14 ) 15 16 // TestPushedData ensured the PushedData function extracts the expected data out 17 // of various scripts. 18 func TestPushedData(t *testing.T) { 19 t.Parallel() 20 21 var tests = []struct { 22 script string 23 out [][]byte 24 valid bool 25 }{ 26 { 27 "0 IF 0 ELSE 2 ENDIF", 28 [][]byte{nil, nil}, 29 true, 30 }, 31 { 32 "16777216 10000000", 33 [][]byte{ 34 {0x00, 0x00, 0x00, 0x01}, // 16777216 35 {0x80, 0x96, 0x98, 0x00}, // 10000000 36 }, 37 true, 38 }, 39 { 40 "DUP HASH160 '17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhem' EQUALVERIFY CHECKSIG", 41 [][]byte{ 42 // 17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhem 43 { 44 0x31, 0x37, 0x56, 0x5a, 0x4e, 0x58, 0x31, 0x53, 0x4e, 0x35, 45 0x4e, 0x74, 0x4b, 0x61, 0x38, 0x55, 0x51, 0x46, 0x78, 0x77, 46 0x51, 0x62, 0x46, 0x65, 0x46, 0x63, 0x33, 0x69, 0x71, 0x52, 47 0x59, 0x68, 0x65, 0x6d, 48 }, 49 }, 50 true, 51 }, 52 { 53 "PUSHDATA4 1000 EQUAL", 54 nil, 55 false, 56 }, 57 } 58 59 for i, test := range tests { 60 script := mustParseShortForm(test.script) 61 data, err := txscript.PushedData(script) 62 if test.valid && err != nil { 63 t.Errorf("TestPushedData failed test #%d: %v\n", i, err) 64 continue 65 } else if !test.valid && err == nil { 66 t.Errorf("TestPushedData failed test #%d: test should "+ 67 "be invalid\n", i) 68 continue 69 } 70 if !reflect.DeepEqual(data, test.out) { 71 t.Errorf("TestPushedData failed test #%d: want: %x "+ 72 "got: %x\n", i, test.out, data) 73 } 74 } 75 } 76 77 // TestHasCanonicalPush ensures the canonicalPush function works as expected. 78 func TestHasCanonicalPush(t *testing.T) { 79 t.Parallel() 80 81 for i := 0; i < 65535; i++ { 82 builder := txscript.NewScriptBuilder() 83 builder.AddInt64(int64(i)) 84 script, err := builder.Script() 85 if err != nil { 86 t.Errorf("Script: test #%d unexpected error: %v\n", i, 87 err) 88 continue 89 } 90 if result := txscript.IsPushOnlyScript(script); !result { 91 t.Errorf("IsPushOnlyScript: test #%d failed: %x\n", i, 92 script) 93 continue 94 } 95 pops, err := txscript.TstParseScript(script) 96 if err != nil { 97 t.Errorf("TstParseScript: #%d failed: %v", i, err) 98 continue 99 } 100 for _, pop := range pops { 101 if result := txscript.TstHasCanonicalPushes(pop); !result { 102 t.Errorf("TstHasCanonicalPushes: test #%d "+ 103 "failed: %x\n", i, script) 104 break 105 } 106 } 107 } 108 for i := 0; i <= txscript.MaxScriptElementSize; i++ { 109 builder := txscript.NewScriptBuilder() 110 builder.AddData(bytes.Repeat([]byte{0x49}, i)) 111 script, err := builder.Script() 112 if err != nil { 113 t.Errorf("StandardPushesTests test #%d unexpected error: %v\n", i, err) 114 continue 115 } 116 if result := txscript.IsPushOnlyScript(script); !result { 117 t.Errorf("StandardPushesTests IsPushOnlyScript test #%d failed: %x\n", i, script) 118 continue 119 } 120 pops, err := txscript.TstParseScript(script) 121 if err != nil { 122 t.Errorf("StandardPushesTests #%d failed to TstParseScript: %v", i, err) 123 continue 124 } 125 for _, pop := range pops { 126 if result := txscript.TstHasCanonicalPushes(pop); !result { 127 t.Errorf("StandardPushesTests TstHasCanonicalPushes test #%d failed: %x\n", i, script) 128 break 129 } 130 } 131 } 132 } 133 134 // TestGetPreciseSigOps ensures the more precise signature operation counting 135 // mechanism which includes signatures in P2SH scripts works as expected. 136 func TestGetPreciseSigOps(t *testing.T) { 137 t.Parallel() 138 139 tests := []struct { 140 name string 141 scriptSig []byte 142 nSigOps int 143 err error 144 }{ 145 { 146 name: "scriptSig doesn't parse", 147 scriptSig: []byte{txscript.OP_PUSHDATA1, 2}, 148 err: txscript.ErrStackShortScript, 149 }, 150 { 151 name: "scriptSig isn't push only", 152 scriptSig: []byte{txscript.OP_1, txscript.OP_DUP}, 153 nSigOps: 0, 154 }, 155 { 156 name: "scriptSig length 0", 157 scriptSig: nil, 158 nSigOps: 0, 159 }, 160 { 161 name: "No script at the end", 162 // No script at end but still push only. 163 scriptSig: []byte{txscript.OP_1, txscript.OP_1}, 164 nSigOps: 0, 165 }, 166 { 167 name: "pushed script doesn't parse", 168 scriptSig: []byte{txscript.OP_DATA_2, 169 txscript.OP_PUSHDATA1, 2}, 170 err: txscript.ErrStackShortScript, 171 }, 172 } 173 174 // The signature in the p2sh script is nonsensical for the tests since 175 // this script will never be executed. What matters is that it matches 176 // the right pattern. 177 pkScript := mustParseShortForm("HASH160 DATA_20 0x433ec2ac1ffa1b7b7d0" + 178 "27f564529c57197f9ae88 EQUAL") 179 for _, test := range tests { 180 count := txscript.GetPreciseSigOpCount(test.scriptSig, pkScript, 181 true) 182 if count != test.nSigOps { 183 t.Errorf("%s: expected count of %d, got %d", test.name, 184 test.nSigOps, count) 185 186 } 187 } 188 } 189 190 // TestRemoveOpcodes ensures that removing opcodes from scripts behaves as 191 // expected. 192 func TestRemoveOpcodes(t *testing.T) { 193 t.Parallel() 194 195 tests := []struct { 196 name string 197 before string 198 remove byte 199 err error 200 after string 201 }{ 202 { 203 // Nothing to remove. 204 name: "nothing to remove", 205 before: "NOP", 206 remove: txscript.OP_CODESEPARATOR, 207 after: "NOP", 208 }, 209 { 210 // Test basic opcode removal. 211 name: "codeseparator 1", 212 before: "NOP CODESEPARATOR TRUE", 213 remove: txscript.OP_CODESEPARATOR, 214 after: "NOP TRUE", 215 }, 216 { 217 // The opcode in question is actually part of the data 218 // in a previous opcode. 219 name: "codeseparator by coincidence", 220 before: "NOP DATA_1 CODESEPARATOR TRUE", 221 remove: txscript.OP_CODESEPARATOR, 222 after: "NOP DATA_1 CODESEPARATOR TRUE", 223 }, 224 { 225 name: "invalid opcode", 226 before: "CAT", 227 remove: txscript.OP_CODESEPARATOR, 228 after: "CAT", 229 }, 230 { 231 name: "invalid length (insruction)", 232 before: "PUSHDATA1", 233 remove: txscript.OP_CODESEPARATOR, 234 err: txscript.ErrStackShortScript, 235 }, 236 { 237 name: "invalid length (data)", 238 before: "PUSHDATA1 0xff 0xfe", 239 remove: txscript.OP_CODESEPARATOR, 240 err: txscript.ErrStackShortScript, 241 }, 242 } 243 244 for _, test := range tests { 245 before := mustParseShortForm(test.before) 246 after := mustParseShortForm(test.after) 247 result, err := txscript.TstRemoveOpcode(before, test.remove) 248 if test.err != nil { 249 if err != test.err { 250 t.Errorf("%s: got unexpected error. exp: \"%v\" "+ 251 "got: \"%v\"", test.name, test.err, err) 252 } 253 return 254 } 255 if err != nil { 256 t.Errorf("%s: unexpected failure: \"%v\"", test.name, err) 257 return 258 } 259 if !bytes.Equal(after, result) { 260 t.Errorf("%s: value does not equal expected: exp: \"%v\""+ 261 " got: \"%v\"", test.name, after, result) 262 } 263 } 264 } 265 266 // TestRemoveOpcodeByData ensures that removing data carrying opcodes based on 267 // the data they contain works as expected. 268 func TestRemoveOpcodeByData(t *testing.T) { 269 t.Parallel() 270 271 tests := []struct { 272 name string 273 before []byte 274 remove []byte 275 err error 276 after []byte 277 }{ 278 { 279 name: "nothing to do", 280 before: []byte{txscript.OP_NOP}, 281 remove: []byte{1, 2, 3, 4}, 282 after: []byte{txscript.OP_NOP}, 283 }, 284 { 285 name: "simple case", 286 before: []byte{txscript.OP_DATA_4, 1, 2, 3, 4}, 287 remove: []byte{1, 2, 3, 4}, 288 after: nil, 289 }, 290 { 291 name: "simple case (miss)", 292 before: []byte{txscript.OP_DATA_4, 1, 2, 3, 4}, 293 remove: []byte{1, 2, 3, 5}, 294 after: []byte{txscript.OP_DATA_4, 1, 2, 3, 4}, 295 }, 296 { 297 // padded to keep it canonical. 298 name: "simple case (pushdata1)", 299 before: append(append([]byte{txscript.OP_PUSHDATA1, 76}, 300 bytes.Repeat([]byte{0}, 72)...), 301 []byte{1, 2, 3, 4}...), 302 remove: []byte{1, 2, 3, 4}, 303 after: nil, 304 }, 305 { 306 name: "simple case (pushdata1 miss)", 307 before: append(append([]byte{txscript.OP_PUSHDATA1, 76}, 308 bytes.Repeat([]byte{0}, 72)...), 309 []byte{1, 2, 3, 4}...), 310 remove: []byte{1, 2, 3, 5}, 311 after: append(append([]byte{txscript.OP_PUSHDATA1, 76}, 312 bytes.Repeat([]byte{0}, 72)...), 313 []byte{1, 2, 3, 4}...), 314 }, 315 { 316 name: "simple case (pushdata1 miss noncanonical)", 317 before: []byte{txscript.OP_PUSHDATA1, 4, 1, 2, 3, 4}, 318 remove: []byte{1, 2, 3, 4}, 319 after: []byte{txscript.OP_PUSHDATA1, 4, 1, 2, 3, 4}, 320 }, 321 { 322 name: "simple case (pushdata2)", 323 before: append(append([]byte{txscript.OP_PUSHDATA2, 0, 1}, 324 bytes.Repeat([]byte{0}, 252)...), 325 []byte{1, 2, 3, 4}...), 326 remove: []byte{1, 2, 3, 4}, 327 after: nil, 328 }, 329 { 330 name: "simple case (pushdata2 miss)", 331 before: append(append([]byte{txscript.OP_PUSHDATA2, 0, 1}, 332 bytes.Repeat([]byte{0}, 252)...), 333 []byte{1, 2, 3, 4}...), 334 remove: []byte{1, 2, 3, 4, 5}, 335 after: append(append([]byte{txscript.OP_PUSHDATA2, 0, 1}, 336 bytes.Repeat([]byte{0}, 252)...), 337 []byte{1, 2, 3, 4}...), 338 }, 339 { 340 name: "simple case (pushdata2 miss noncanonical)", 341 before: []byte{txscript.OP_PUSHDATA2, 4, 0, 1, 2, 3, 4}, 342 remove: []byte{1, 2, 3, 4}, 343 after: []byte{txscript.OP_PUSHDATA2, 4, 0, 1, 2, 3, 4}, 344 }, 345 { 346 // This is padded to make the push canonical. 347 name: "simple case (pushdata4)", 348 before: append(append([]byte{txscript.OP_PUSHDATA4, 0, 0, 1, 0}, 349 bytes.Repeat([]byte{0}, 65532)...), 350 []byte{1, 2, 3, 4}...), 351 remove: []byte{1, 2, 3, 4}, 352 after: nil, 353 }, 354 { 355 name: "simple case (pushdata4 miss noncanonical)", 356 before: []byte{txscript.OP_PUSHDATA4, 4, 0, 0, 0, 1, 2, 3, 4}, 357 remove: []byte{1, 2, 3, 4}, 358 after: []byte{txscript.OP_PUSHDATA4, 4, 0, 0, 0, 1, 2, 3, 4}, 359 }, 360 { 361 // This is padded to make the push canonical. 362 name: "simple case (pushdata4 miss)", 363 before: append(append([]byte{txscript.OP_PUSHDATA4, 0, 0, 1, 0}, 364 bytes.Repeat([]byte{0}, 65532)...), []byte{1, 2, 3, 4}...), 365 remove: []byte{1, 2, 3, 4, 5}, 366 after: append(append([]byte{txscript.OP_PUSHDATA4, 0, 0, 1, 0}, 367 bytes.Repeat([]byte{0}, 65532)...), []byte{1, 2, 3, 4}...), 368 }, 369 { 370 name: "invalid opcode ", 371 before: []byte{txscript.OP_UNKNOWN187}, 372 remove: []byte{1, 2, 3, 4}, 373 after: []byte{txscript.OP_UNKNOWN187}, 374 }, 375 { 376 name: "invalid length (instruction)", 377 before: []byte{txscript.OP_PUSHDATA1}, 378 remove: []byte{1, 2, 3, 4}, 379 err: txscript.ErrStackShortScript, 380 }, 381 { 382 name: "invalid length (data)", 383 before: []byte{txscript.OP_PUSHDATA1, 255, 254}, 384 remove: []byte{1, 2, 3, 4}, 385 err: txscript.ErrStackShortScript, 386 }, 387 } 388 389 for _, test := range tests { 390 result, err := txscript.TstRemoveOpcodeByData(test.before, 391 test.remove) 392 if test.err != nil { 393 if err != test.err { 394 t.Errorf("%s: got unexpected error. exp: \"%v\" "+ 395 "got: \"%v\"", test.name, test.err, err) 396 } 397 return 398 } 399 if err != nil { 400 t.Errorf("%s: unexpected failure: \"%v\"", test.name, err) 401 return 402 } 403 if !bytes.Equal(test.after, result) { 404 t.Errorf("%s: value does not equal expected: exp: \"%v\""+ 405 " got: \"%v\"", test.name, test.after, result) 406 } 407 } 408 } 409 410 // TestIsPayToScriptHash ensures the IsPayToScriptHash function returns the 411 // expected results for all the scripts in scriptClassTests. 412 func TestIsPayToScriptHash(t *testing.T) { 413 t.Parallel() 414 415 for _, test := range scriptClassTests { 416 script := mustParseShortForm(test.script) 417 shouldBe := (test.class == txscript.ScriptHashTy) 418 p2sh := txscript.IsPayToScriptHash(script) 419 if p2sh != shouldBe { 420 t.Errorf("%s: epxected p2sh %v, got %v", test.name, 421 shouldBe, p2sh) 422 } 423 } 424 } 425 426 // TestHasCanonicalPushes ensures the canonicalPush function properly determines 427 // what is considered a canonical push for the purposes of removeOpcodeByData. 428 func TestHasCanonicalPushes(t *testing.T) { 429 t.Parallel() 430 431 tests := []struct { 432 name string 433 script string 434 expected bool 435 }{ 436 { 437 name: "does not parse", 438 script: "0x046708afdb0fe5548271967f1a67130b7105cd6a82" + 439 "8e03909a67962e0ea1f61d", 440 expected: false, 441 }, 442 { 443 name: "non-canonical push", 444 script: "PUSHDATA1 0x04 0x01020304", 445 expected: false, 446 }, 447 } 448 449 for i, test := range tests { 450 script := mustParseShortForm(test.script) 451 pops, err := txscript.TstParseScript(script) 452 if err != nil { 453 if test.expected { 454 t.Errorf("TstParseScript #%d failed: %v", i, err) 455 } 456 continue 457 } 458 for _, pop := range pops { 459 if txscript.TstHasCanonicalPushes(pop) != test.expected { 460 t.Errorf("TstHasCanonicalPushes: #%d (%s) "+ 461 "wrong result\ngot: %v\nwant: %v", i, 462 test.name, true, test.expected) 463 break 464 } 465 } 466 } 467 } 468 469 // TestIsPushOnlyScript ensures the IsPushOnlyScript function returns the 470 // expected results. 471 func TestIsPushOnlyScript(t *testing.T) { 472 t.Parallel() 473 474 test := struct { 475 name string 476 script []byte 477 expected bool 478 }{ 479 name: "does not parse", 480 script: mustParseShortForm("0x046708afdb0fe5548271967f1a67130" + 481 "b7105cd6a828e03909a67962e0ea1f61d"), 482 expected: false, 483 } 484 485 if txscript.IsPushOnlyScript(test.script) != test.expected { 486 t.Errorf("IsPushOnlyScript (%s) wrong result\ngot: %v\nwant: "+ 487 "%v", test.name, true, test.expected) 488 } 489 } 490 491 // TestIsUnspendable ensures the IsUnspendable function returns the expected 492 // results. 493 func TestIsUnspendable(t *testing.T) { 494 t.Parallel() 495 496 tests := []struct { 497 name string 498 pkScript []byte 499 expected bool 500 }{ 501 { 502 // Unspendable 503 pkScript: []byte{0x6a, 0x04, 0x74, 0x65, 0x73, 0x74}, 504 expected: true, 505 }, 506 { 507 // Spendable 508 pkScript: []byte{0x76, 0xa9, 0x14, 0x29, 0x95, 0xa0, 509 0xfe, 0x68, 0x43, 0xfa, 0x9b, 0x95, 0x45, 510 0x97, 0xf0, 0xdc, 0xa7, 0xa4, 0x4d, 0xf6, 511 0xfa, 0x0b, 0x5c, 0x88, 0xac}, 512 expected: false, 513 }, 514 } 515 516 for i, test := range tests { 517 res := txscript.IsUnspendable(test.pkScript) 518 if res != test.expected { 519 t.Errorf("TestIsUnspendable #%d failed: got %v want %v", 520 i, res, test.expected) 521 continue 522 } 523 } 524 }