github.com/dashpay/godash@v0.0.0-20160726055534-e038a21e0e3d/txscript/reference_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 "encoding/hex" 11 "encoding/json" 12 "errors" 13 "fmt" 14 "io/ioutil" 15 "strconv" 16 "strings" 17 "testing" 18 19 . "github.com/dashpay/godash/txscript" 20 "github.com/dashpay/godash/wire" 21 "github.com/dashpay/godashutil" 22 ) 23 24 // testName returns a descriptive test name for the given reference test data. 25 func testName(test []string) (string, error) { 26 var name string 27 28 if len(test) < 3 || len(test) > 4 { 29 return name, fmt.Errorf("invalid test length %d", len(test)) 30 } 31 32 if len(test) == 4 { 33 name = fmt.Sprintf("test (%s)", test[3]) 34 } else { 35 name = fmt.Sprintf("test ([%s, %s, %s])", test[0], test[1], 36 test[2]) 37 } 38 return name, nil 39 } 40 41 // parse hex string into a []byte. 42 func parseHex(tok string) ([]byte, error) { 43 if !strings.HasPrefix(tok, "0x") { 44 return nil, errors.New("not a hex number") 45 } 46 return hex.DecodeString(tok[2:]) 47 } 48 49 // shortFormOps holds a map of opcode names to values for use in short form 50 // parsing. It is declared here so it only needs to be created once. 51 var shortFormOps map[string]byte 52 53 // parseShortForm parses a string as as used in the Bitcoin Core reference tests 54 // into the script it came from. 55 // 56 // The format used for these tests is pretty simple if ad-hoc: 57 // - Opcodes other than the push opcodes and unknown are present as 58 // either OP_NAME or just NAME 59 // - Plain numbers are made into push operations 60 // - Numbers beginning with 0x are inserted into the []byte as-is (so 61 // 0x14 is OP_DATA_20) 62 // - Single quoted strings are pushed as data 63 // - Anything else is an error 64 func parseShortForm(script string) ([]byte, error) { 65 // Only create the short form opcode map once. 66 if shortFormOps == nil { 67 ops := make(map[string]byte) 68 for opcodeName, opcodeValue := range OpcodeByName { 69 if strings.Contains(opcodeName, "OP_UNKNOWN") { 70 continue 71 } 72 ops[opcodeName] = opcodeValue 73 74 // The opcodes named OP_# can't have the OP_ prefix 75 // stripped or they would conflict with the plain 76 // numbers. Also, since OP_FALSE and OP_TRUE are 77 // aliases for the OP_0, and OP_1, respectively, they 78 // have the same value, so detect those by name and 79 // allow them. 80 if (opcodeName == "OP_FALSE" || opcodeName == "OP_TRUE") || 81 (opcodeValue != OP_0 && (opcodeValue < OP_1 || 82 opcodeValue > OP_16)) { 83 84 ops[strings.TrimPrefix(opcodeName, "OP_")] = opcodeValue 85 } 86 } 87 shortFormOps = ops 88 } 89 90 // Split only does one separator so convert all \n and tab into space. 91 script = strings.Replace(script, "\n", " ", -1) 92 script = strings.Replace(script, "\t", " ", -1) 93 tokens := strings.Split(script, " ") 94 builder := NewScriptBuilder() 95 96 for _, tok := range tokens { 97 if len(tok) == 0 { 98 continue 99 } 100 // if parses as a plain number 101 if num, err := strconv.ParseInt(tok, 10, 64); err == nil { 102 builder.AddInt64(num) 103 continue 104 } else if bts, err := parseHex(tok); err == nil { 105 builder.TstConcatRawScript(bts) 106 } else if len(tok) >= 2 && 107 tok[0] == '\'' && tok[len(tok)-1] == '\'' { 108 builder.AddFullData([]byte(tok[1 : len(tok)-1])) 109 } else if opcode, ok := shortFormOps[tok]; ok { 110 builder.AddOp(opcode) 111 } else { 112 return nil, fmt.Errorf("bad token \"%s\"", tok) 113 } 114 115 } 116 return builder.Script() 117 } 118 119 // parseScriptFlags parses the provided flags string from the format used in the 120 // reference tests into ScriptFlags suitable for use in the script engine. 121 func parseScriptFlags(flagStr string) (ScriptFlags, error) { 122 var flags ScriptFlags 123 124 sFlags := strings.Split(flagStr, ",") 125 for _, flag := range sFlags { 126 switch flag { 127 case "": 128 // Nothing. 129 case "CHECKLOCKTIMEVERIFY": 130 flags |= ScriptVerifyCheckLockTimeVerify 131 case "CLEANSTACK": 132 flags |= ScriptVerifyCleanStack 133 case "DERSIG": 134 flags |= ScriptVerifyDERSignatures 135 case "DISCOURAGE_UPGRADABLE_NOPS": 136 flags |= ScriptDiscourageUpgradableNops 137 case "LOW_S": 138 flags |= ScriptVerifyLowS 139 case "MINIMALDATA": 140 flags |= ScriptVerifyMinimalData 141 case "NONE": 142 // Nothing. 143 case "NULLDUMMY": 144 flags |= ScriptStrictMultiSig 145 case "P2SH": 146 flags |= ScriptBip16 147 case "SIGPUSHONLY": 148 flags |= ScriptVerifySigPushOnly 149 case "STRICTENC": 150 flags |= ScriptVerifyStrictEncoding 151 default: 152 return flags, fmt.Errorf("invalid flag: %s", flag) 153 } 154 } 155 return flags, nil 156 } 157 158 // createSpendTx generates a basic spending transaction given the passed 159 // signature and public key scripts. 160 func createSpendingTx(sigScript, pkScript []byte) *wire.MsgTx { 161 coinbaseTx := wire.NewMsgTx() 162 163 outPoint := wire.NewOutPoint(&wire.ShaHash{}, ^uint32(0)) 164 txIn := wire.NewTxIn(outPoint, []byte{OP_0, OP_0}) 165 txOut := wire.NewTxOut(0, pkScript) 166 coinbaseTx.AddTxIn(txIn) 167 coinbaseTx.AddTxOut(txOut) 168 169 spendingTx := wire.NewMsgTx() 170 coinbaseTxSha := coinbaseTx.TxSha() 171 outPoint = wire.NewOutPoint(&coinbaseTxSha, 0) 172 txIn = wire.NewTxIn(outPoint, sigScript) 173 txOut = wire.NewTxOut(0, nil) 174 175 spendingTx.AddTxIn(txIn) 176 spendingTx.AddTxOut(txOut) 177 178 return spendingTx 179 } 180 181 // TestScriptInvalidTests ensures all of the tests in script_invalid.json fail 182 // as expected. 183 func TestScriptInvalidTests(t *testing.T) { 184 file, err := ioutil.ReadFile("data/script_invalid.json") 185 if err != nil { 186 t.Errorf("TestBitcoindInvalidTests: %v\n", err) 187 return 188 } 189 190 var tests [][]string 191 err = json.Unmarshal(file, &tests) 192 if err != nil { 193 t.Errorf("TestBitcoindInvalidTests couldn't Unmarshal: %v", 194 err) 195 return 196 } 197 sigCache := NewSigCache(10) 198 199 sigCacheToggle := []bool{true, false} 200 for _, useSigCache := range sigCacheToggle { 201 for i, test := range tests { 202 // Skip comments 203 if len(test) == 1 { 204 continue 205 } 206 name, err := testName(test) 207 if err != nil { 208 t.Errorf("TestBitcoindInvalidTests: invalid test #%d", 209 i) 210 continue 211 } 212 scriptSig, err := parseShortForm(test[0]) 213 if err != nil { 214 t.Errorf("%s: can't parse scriptSig; %v", name, err) 215 continue 216 } 217 scriptPubKey, err := parseShortForm(test[1]) 218 if err != nil { 219 t.Errorf("%s: can't parse scriptPubkey; %v", name, err) 220 continue 221 } 222 flags, err := parseScriptFlags(test[2]) 223 if err != nil { 224 t.Errorf("%s: %v", name, err) 225 continue 226 } 227 tx := createSpendingTx(scriptSig, scriptPubKey) 228 229 var vm *Engine 230 if useSigCache { 231 vm, err = NewEngine(scriptPubKey, tx, 0, flags, sigCache) 232 } else { 233 vm, err = NewEngine(scriptPubKey, tx, 0, flags, nil) 234 } 235 236 if err == nil { 237 if err := vm.Execute(); err == nil { 238 t.Errorf("%s test succeeded when it "+ 239 "should have failed\n", name) 240 } 241 continue 242 } 243 } 244 } 245 } 246 247 // TestScriptValidTests ensures all of the tests in script_valid.json pass as 248 // expected. 249 func TestScriptValidTests(t *testing.T) { 250 file, err := ioutil.ReadFile("data/script_valid.json") 251 if err != nil { 252 t.Errorf("TestBitcoinValidTests: %v\n", err) 253 return 254 } 255 256 var tests [][]string 257 err = json.Unmarshal(file, &tests) 258 if err != nil { 259 t.Errorf("TestBitcoindValidTests couldn't Unmarshal: %v", 260 err) 261 return 262 } 263 264 sigCache := NewSigCache(10) 265 266 sigCacheToggle := []bool{true, false} 267 for _, useSigCache := range sigCacheToggle { 268 for i, test := range tests { 269 // Skip comments 270 if len(test) == 1 { 271 continue 272 } 273 name, err := testName(test) 274 if err != nil { 275 t.Errorf("TestBitcoindValidTests: invalid test #%d", 276 i) 277 continue 278 } 279 scriptSig, err := parseShortForm(test[0]) 280 if err != nil { 281 t.Errorf("%s: can't parse scriptSig; %v", name, err) 282 continue 283 } 284 scriptPubKey, err := parseShortForm(test[1]) 285 if err != nil { 286 t.Errorf("%s: can't parse scriptPubkey; %v", name, err) 287 continue 288 } 289 flags, err := parseScriptFlags(test[2]) 290 if err != nil { 291 t.Errorf("%s: %v", name, err) 292 continue 293 } 294 tx := createSpendingTx(scriptSig, scriptPubKey) 295 296 var vm *Engine 297 if useSigCache { 298 vm, err = NewEngine(scriptPubKey, tx, 0, flags, sigCache) 299 } else { 300 vm, err = NewEngine(scriptPubKey, tx, 0, flags, nil) 301 } 302 303 if err != nil { 304 t.Errorf("%s failed to create script: %v", name, err) 305 continue 306 } 307 err = vm.Execute() 308 if err != nil { 309 t.Errorf("%s failed to execute: %v", name, err) 310 continue 311 } 312 } 313 } 314 } 315 316 // testVecF64ToUint32 properly handles conversion of float64s read from the JSON 317 // test data to unsigned 32-bit integers. This is necessary because some of the 318 // test data uses -1 as a shortcut to mean max uint32 and direct conversion of a 319 // negative float to an unsigned int is implementation dependent and therefore 320 // doesn't result in the expected value on all platforms. This function woks 321 // around that limitation by converting to a 32-bit signed integer first and 322 // then to a 32-bit unsigned integer which results in the expected behavior on 323 // all platforms. 324 func testVecF64ToUint32(f float64) uint32 { 325 return uint32(int32(f)) 326 } 327 328 // TestTxInvalidTests ensures all of the tests in tx_invalid.json fail as 329 // expected. 330 func TestTxInvalidTests(t *testing.T) { 331 file, err := ioutil.ReadFile("data/tx_invalid.json") 332 if err != nil { 333 t.Errorf("TestTxInvalidTests: %v\n", err) 334 return 335 } 336 337 var tests [][]interface{} 338 err = json.Unmarshal(file, &tests) 339 if err != nil { 340 t.Errorf("TestTxInvalidTests couldn't Unmarshal: %v\n", err) 341 return 342 } 343 344 // form is either: 345 // ["this is a comment "] 346 // or: 347 // [[[previous hash, previous index, previous scriptPubKey]...,] 348 // serializedTransaction, verifyFlags] 349 testloop: 350 for i, test := range tests { 351 inputs, ok := test[0].([]interface{}) 352 if !ok { 353 continue 354 } 355 356 if len(test) != 3 { 357 t.Errorf("bad test (bad length) %d: %v", i, test) 358 continue 359 360 } 361 serializedhex, ok := test[1].(string) 362 if !ok { 363 t.Errorf("bad test (arg 2 not string) %d: %v", i, test) 364 continue 365 } 366 serializedTx, err := hex.DecodeString(serializedhex) 367 if err != nil { 368 t.Errorf("bad test (arg 2 not hex %v) %d: %v", err, i, 369 test) 370 continue 371 } 372 373 tx, err := godashutil.NewTxFromBytes(serializedTx) 374 if err != nil { 375 t.Errorf("bad test (arg 2 not msgtx %v) %d: %v", err, 376 i, test) 377 continue 378 } 379 380 verifyFlags, ok := test[2].(string) 381 if !ok { 382 t.Errorf("bad test (arg 3 not string) %d: %v", i, test) 383 continue 384 } 385 386 flags, err := parseScriptFlags(verifyFlags) 387 if err != nil { 388 t.Errorf("bad test %d: %v", i, err) 389 continue 390 } 391 392 prevOuts := make(map[wire.OutPoint][]byte) 393 for j, iinput := range inputs { 394 input, ok := iinput.([]interface{}) 395 if !ok { 396 t.Errorf("bad test (%dth input not array)"+ 397 "%d: %v", j, i, test) 398 continue testloop 399 } 400 401 if len(input) != 3 { 402 t.Errorf("bad test (%dth input wrong length)"+ 403 "%d: %v", j, i, test) 404 continue testloop 405 } 406 407 previoustx, ok := input[0].(string) 408 if !ok { 409 t.Errorf("bad test (%dth input sha not string)"+ 410 "%d: %v", j, i, test) 411 continue testloop 412 } 413 414 prevhash, err := wire.NewShaHashFromStr(previoustx) 415 if err != nil { 416 t.Errorf("bad test (%dth input sha not sha %v)"+ 417 "%d: %v", j, err, i, test) 418 continue testloop 419 } 420 421 idxf, ok := input[1].(float64) 422 if !ok { 423 t.Errorf("bad test (%dth input idx not number)"+ 424 "%d: %v", j, i, test) 425 continue testloop 426 } 427 idx := testVecF64ToUint32(idxf) 428 429 oscript, ok := input[2].(string) 430 if !ok { 431 t.Errorf("bad test (%dth input script not "+ 432 "string) %d: %v", j, i, test) 433 continue testloop 434 } 435 436 script, err := parseShortForm(oscript) 437 if err != nil { 438 t.Errorf("bad test (%dth input script doesn't "+ 439 "parse %v) %d: %v", j, err, i, test) 440 continue testloop 441 } 442 443 prevOuts[*wire.NewOutPoint(prevhash, idx)] = script 444 } 445 446 for k, txin := range tx.MsgTx().TxIn { 447 pkScript, ok := prevOuts[txin.PreviousOutPoint] 448 if !ok { 449 t.Errorf("bad test (missing %dth input) %d:%v", 450 k, i, test) 451 continue testloop 452 } 453 // These are meant to fail, so as soon as the first 454 // input fails the transaction has failed. (some of the 455 // test txns have good inputs, too.. 456 vm, err := NewEngine(pkScript, tx.MsgTx(), k, flags, nil) 457 if err != nil { 458 continue testloop 459 } 460 461 err = vm.Execute() 462 if err != nil { 463 continue testloop 464 } 465 466 } 467 t.Errorf("test (%d:%v) succeeded when should fail", 468 i, test) 469 } 470 } 471 472 // TestTxValidTests ensures all of the tests in tx_valid.json pass as expected. 473 func TestTxValidTests(t *testing.T) { 474 file, err := ioutil.ReadFile("data/tx_valid.json") 475 if err != nil { 476 t.Errorf("TestTxValidTests: %v\n", err) 477 return 478 } 479 480 var tests [][]interface{} 481 err = json.Unmarshal(file, &tests) 482 if err != nil { 483 t.Errorf("TestTxValidTests couldn't Unmarshal: %v\n", err) 484 return 485 } 486 487 // form is either: 488 // ["this is a comment "] 489 // or: 490 // [[[previous hash, previous index, previous scriptPubKey]...,] 491 // serializedTransaction, verifyFlags] 492 testloop: 493 for i, test := range tests { 494 inputs, ok := test[0].([]interface{}) 495 if !ok { 496 continue 497 } 498 499 if len(test) != 3 { 500 t.Errorf("bad test (bad length) %d: %v", i, test) 501 continue 502 } 503 serializedhex, ok := test[1].(string) 504 if !ok { 505 t.Errorf("bad test (arg 2 not string) %d: %v", i, test) 506 continue 507 } 508 serializedTx, err := hex.DecodeString(serializedhex) 509 if err != nil { 510 t.Errorf("bad test (arg 2 not hex %v) %d: %v", err, i, 511 test) 512 continue 513 } 514 515 tx, err := godashutil.NewTxFromBytes(serializedTx) 516 if err != nil { 517 t.Errorf("bad test (arg 2 not msgtx %v) %d: %v", err, 518 i, test) 519 continue 520 } 521 522 verifyFlags, ok := test[2].(string) 523 if !ok { 524 t.Errorf("bad test (arg 3 not string) %d: %v", i, test) 525 continue 526 } 527 528 flags, err := parseScriptFlags(verifyFlags) 529 if err != nil { 530 t.Errorf("bad test %d: %v", i, err) 531 continue 532 } 533 534 prevOuts := make(map[wire.OutPoint][]byte) 535 for j, iinput := range inputs { 536 input, ok := iinput.([]interface{}) 537 if !ok { 538 t.Errorf("bad test (%dth input not array)"+ 539 "%d: %v", j, i, test) 540 continue 541 } 542 543 if len(input) != 3 { 544 t.Errorf("bad test (%dth input wrong length)"+ 545 "%d: %v", j, i, test) 546 continue 547 } 548 549 previoustx, ok := input[0].(string) 550 if !ok { 551 t.Errorf("bad test (%dth input sha not string)"+ 552 "%d: %v", j, i, test) 553 continue 554 } 555 556 prevhash, err := wire.NewShaHashFromStr(previoustx) 557 if err != nil { 558 t.Errorf("bad test (%dth input sha not sha %v)"+ 559 "%d: %v", j, err, i, test) 560 continue 561 } 562 563 idxf, ok := input[1].(float64) 564 if !ok { 565 t.Errorf("bad test (%dth input idx not number)"+ 566 "%d: %v", j, i, test) 567 continue 568 } 569 idx := testVecF64ToUint32(idxf) 570 571 oscript, ok := input[2].(string) 572 if !ok { 573 t.Errorf("bad test (%dth input script not "+ 574 "string) %d: %v", j, i, test) 575 continue 576 } 577 578 script, err := parseShortForm(oscript) 579 if err != nil { 580 t.Errorf("bad test (%dth input script doesn't "+ 581 "parse %v) %d: %v", j, err, i, test) 582 continue 583 } 584 585 prevOuts[*wire.NewOutPoint(prevhash, idx)] = script 586 } 587 588 for k, txin := range tx.MsgTx().TxIn { 589 pkScript, ok := prevOuts[txin.PreviousOutPoint] 590 if !ok { 591 t.Errorf("bad test (missing %dth input) %d:%v", 592 k, i, test) 593 continue testloop 594 } 595 vm, err := NewEngine(pkScript, tx.MsgTx(), k, flags, nil) 596 if err != nil { 597 t.Errorf("test (%d:%v:%d) failed to create "+ 598 "script: %v", i, test, k, err) 599 continue 600 } 601 602 err = vm.Execute() 603 if err != nil { 604 t.Errorf("test (%d:%v:%d) failed to execute: "+ 605 "%v", i, test, k, err) 606 continue 607 } 608 } 609 } 610 } 611 612 // TestCalcSignatureHash runs the Bitcoin Core signature hash calculation tests 613 // in sighash.json. 614 // https://github.com/bitcoin/bitcoin/blob/master/src/test/data/sighash.json 615 func TestCalcSignatureHash(t *testing.T) { 616 file, err := ioutil.ReadFile("data/sighash.json") 617 if err != nil { 618 t.Errorf("TestCalcSignatureHash: %v\n", err) 619 return 620 } 621 622 var tests [][]interface{} 623 err = json.Unmarshal(file, &tests) 624 if err != nil { 625 t.Errorf("TestCalcSignatureHash couldn't Unmarshal: %v\n", 626 err) 627 return 628 } 629 630 for i, test := range tests { 631 if i == 0 { 632 // Skip first line -- contains comments only. 633 continue 634 } 635 if len(test) != 5 { 636 t.Fatalf("TestCalcSignatureHash: Test #%d has "+ 637 "wrong length.", i) 638 } 639 tx := wire.NewMsgTx() 640 rawTx, _ := hex.DecodeString(test[0].(string)) 641 err := tx.Deserialize(bytes.NewReader(rawTx)) 642 if err != nil { 643 t.Errorf("TestCalcSignatureHash failed test #%d: "+ 644 "Failed to parse transaction: %v", i, err) 645 continue 646 } 647 648 subScript, _ := hex.DecodeString(test[1].(string)) 649 parsedScript, err := TstParseScript(subScript) 650 if err != nil { 651 t.Errorf("TestCalcSignatureHash failed test #%d: "+ 652 "Failed to parse sub-script: %v", i, err) 653 continue 654 } 655 656 hashType := SigHashType(testVecF64ToUint32(test[3].(float64))) 657 hash := TstCalcSignatureHash(parsedScript, hashType, tx, 658 int(test[2].(float64))) 659 660 expectedHash, _ := wire.NewShaHashFromStr(test[4].(string)) 661 if !bytes.Equal(hash, expectedHash.Bytes()) { 662 t.Errorf("TestCalcSignatureHash failed test #%d: "+ 663 "Signature hash mismatch.", i) 664 } 665 } 666 }