|
14 | 14 | #include "main.h" // For CheckTransaction
|
15 | 15 | #include "policy/policy.h"
|
16 | 16 | #include "script/script.h"
|
| 17 | +#include "script/sign.h" |
17 | 18 | #include "script/script_error.h"
|
| 19 | +#include "script/standard.h" |
18 | 20 | #include "utilstrencodings.h"
|
19 | 21 |
|
20 | 22 | #include <map>
|
|
25 | 27 | #include <boost/assign/list_of.hpp>
|
26 | 28 | #include <boost/test/unit_test.hpp>
|
27 | 29 | #include <boost/assign/list_of.hpp>
|
| 30 | +#include <boost/foreach.hpp> |
28 | 31 |
|
29 | 32 | #include <univalue.h>
|
30 | 33 |
|
31 | 34 | using namespace std;
|
32 | 35 |
|
| 36 | +typedef vector<unsigned char> valtype; |
| 37 | + |
33 | 38 | // In script_tests.cpp
|
34 | 39 | extern UniValue read_json(const std::string& jsondata);
|
35 | 40 |
|
@@ -315,6 +320,277 @@ BOOST_AUTO_TEST_CASE(test_Get)
|
315 | 320 | BOOST_CHECK_EQUAL(coins.GetValueIn(t1), (50+21+22)*CENT);
|
316 | 321 | }
|
317 | 322 |
|
| 323 | +void CreateCreditAndSpend(const CKeyStore& keystore, const CScript& outscript, CTransaction& output, CMutableTransaction& input, bool success = true) |
| 324 | +{ |
| 325 | + CMutableTransaction outputm; |
| 326 | + outputm.nVersion = 1; |
| 327 | + outputm.vin.resize(1); |
| 328 | + outputm.vin[0].prevout.SetNull(); |
| 329 | + outputm.vin[0].scriptSig = CScript(); |
| 330 | + outputm.wit.vtxinwit.resize(1); |
| 331 | + outputm.vout.resize(1); |
| 332 | + outputm.vout[0].nValue = 1; |
| 333 | + outputm.vout[0].scriptPubKey = outscript; |
| 334 | + CDataStream ssout(SER_NETWORK, PROTOCOL_VERSION); |
| 335 | + ssout << outputm; |
| 336 | + ssout >> output; |
| 337 | + assert(output.vin.size() == 1); |
| 338 | + assert(output.vin[0] == outputm.vin[0]); |
| 339 | + assert(output.vout.size() == 1); |
| 340 | + assert(output.vout[0] == outputm.vout[0]); |
| 341 | + assert(output.wit.vtxinwit.size() == 0); |
| 342 | + |
| 343 | + CMutableTransaction inputm; |
| 344 | + inputm.nVersion = 1; |
| 345 | + inputm.vin.resize(1); |
| 346 | + inputm.vin[0].prevout.hash = output.GetHash(); |
| 347 | + inputm.vin[0].prevout.n = 0; |
| 348 | + inputm.wit.vtxinwit.resize(1); |
| 349 | + inputm.vout.resize(1); |
| 350 | + inputm.vout[0].nValue = 1; |
| 351 | + inputm.vout[0].scriptPubKey = CScript(); |
| 352 | + bool ret = SignSignature(keystore, output, inputm, 0, SIGHASH_ALL); |
| 353 | + assert(ret == success); |
| 354 | + CDataStream ssin(SER_NETWORK, PROTOCOL_VERSION); |
| 355 | + ssin << inputm; |
| 356 | + ssin >> input; |
| 357 | + assert(input.vin.size() == 1); |
| 358 | + assert(input.vin[0] == inputm.vin[0]); |
| 359 | + assert(input.vout.size() == 1); |
| 360 | + assert(input.vout[0] == inputm.vout[0]); |
| 361 | + if (inputm.wit.IsNull()) { |
| 362 | + assert(input.wit.IsNull()); |
| 363 | + } else { |
| 364 | + assert(!input.wit.IsNull()); |
| 365 | + assert(input.wit.vtxinwit.size() == 1); |
| 366 | + assert(input.wit.vtxinwit[0].scriptWitness.stack == inputm.wit.vtxinwit[0].scriptWitness.stack); |
| 367 | + } |
| 368 | +} |
| 369 | + |
| 370 | +void CheckWithFlag(const CTransaction& output, const CMutableTransaction& input, int flags, bool success) |
| 371 | +{ |
| 372 | + ScriptError error; |
| 373 | + CTransaction inputi(input); |
| 374 | + bool ret = VerifyScript(inputi.vin[0].scriptSig, output.vout[0].scriptPubKey, inputi.wit.vtxinwit.size() > 0 ? &inputi.wit.vtxinwit[0].scriptWitness : NULL, flags, TransactionSignatureChecker(&inputi, 0, output.vout[0].nValue), &error); |
| 375 | + assert(ret == success); |
| 376 | +} |
| 377 | + |
| 378 | +static CScript PushAll(const vector<valtype>& values) |
| 379 | +{ |
| 380 | + CScript result; |
| 381 | + BOOST_FOREACH(const valtype& v, values) { |
| 382 | + if (v.size() == 0) { |
| 383 | + result << OP_0; |
| 384 | + } else if (v.size() == 1 && v[0] >= 1 && v[0] <= 16) { |
| 385 | + result << CScript::EncodeOP_N(v[0]); |
| 386 | + } else { |
| 387 | + result << v; |
| 388 | + } |
| 389 | + } |
| 390 | + return result; |
| 391 | +} |
| 392 | + |
| 393 | +void ReplaceRedeemScript(CScript& script, const CScript& redeemScript) |
| 394 | +{ |
| 395 | + vector<valtype> stack; |
| 396 | + EvalScript(stack, script, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker(), SIGVERSION_BASE); |
| 397 | + assert(stack.size() > 0); |
| 398 | + stack.back() = std::vector<unsigned char>(redeemScript.begin(), redeemScript.end()); |
| 399 | + script = PushAll(stack); |
| 400 | +} |
| 401 | + |
| 402 | +BOOST_AUTO_TEST_CASE(test_witness) |
| 403 | +{ |
| 404 | + CBasicKeyStore keystore, keystore2; |
| 405 | + CKey key1, key2, key3, key1L, key2L; |
| 406 | + CPubKey pubkey1, pubkey2, pubkey3, pubkey1L, pubkey2L; |
| 407 | + key1.MakeNewKey(true); |
| 408 | + key2.MakeNewKey(true); |
| 409 | + key3.MakeNewKey(true); |
| 410 | + key1L.MakeNewKey(false); |
| 411 | + key2L.MakeNewKey(false); |
| 412 | + pubkey1 = key1.GetPubKey(); |
| 413 | + pubkey2 = key2.GetPubKey(); |
| 414 | + pubkey3 = key3.GetPubKey(); |
| 415 | + pubkey1L = key1L.GetPubKey(); |
| 416 | + pubkey2L = key2L.GetPubKey(); |
| 417 | + keystore.AddKeyPubKey(key1, pubkey1); |
| 418 | + keystore.AddKeyPubKey(key2, pubkey2); |
| 419 | + keystore.AddKeyPubKey(key1L, pubkey1L); |
| 420 | + keystore.AddKeyPubKey(key2L, pubkey2L); |
| 421 | + CScript scriptPubkey1, scriptPubkey2, scriptPubkey1L, scriptPubkey2L, scriptMulti; |
| 422 | + scriptPubkey1 << ToByteVector(pubkey1) << OP_CHECKSIG; |
| 423 | + scriptPubkey2 << ToByteVector(pubkey2) << OP_CHECKSIG; |
| 424 | + scriptPubkey1L << ToByteVector(pubkey1L) << OP_CHECKSIG; |
| 425 | + scriptPubkey2L << ToByteVector(pubkey2L) << OP_CHECKSIG; |
| 426 | + std::vector<CPubKey> oneandthree; |
| 427 | + oneandthree.push_back(pubkey1); |
| 428 | + oneandthree.push_back(pubkey3); |
| 429 | + scriptMulti = GetScriptForMultisig(2, oneandthree); |
| 430 | + keystore.AddCScript(scriptPubkey1); |
| 431 | + keystore.AddCScript(scriptPubkey2); |
| 432 | + keystore.AddCScript(scriptPubkey1L); |
| 433 | + keystore.AddCScript(scriptPubkey2L); |
| 434 | + keystore.AddCScript(scriptMulti); |
| 435 | + keystore.AddCScript(GetScriptForWitness(scriptPubkey1)); |
| 436 | + keystore.AddCScript(GetScriptForWitness(scriptPubkey2)); |
| 437 | + keystore.AddCScript(GetScriptForWitness(scriptPubkey1L)); |
| 438 | + keystore.AddCScript(GetScriptForWitness(scriptPubkey2L)); |
| 439 | + keystore.AddCScript(GetScriptForWitness(scriptMulti)); |
| 440 | + keystore2.AddCScript(scriptMulti); |
| 441 | + keystore2.AddCScript(GetScriptForWitness(scriptMulti)); |
| 442 | + keystore2.AddKeyPubKey(key3, pubkey3); |
| 443 | + |
| 444 | + CTransaction output1, output2; |
| 445 | + CMutableTransaction input1, input2; |
| 446 | + SignatureData sigdata; |
| 447 | + |
| 448 | + // Normal pay-to-compressed-pubkey. |
| 449 | + CreateCreditAndSpend(keystore, scriptPubkey1, output1, input1); |
| 450 | + CreateCreditAndSpend(keystore, scriptPubkey2, output2, input2); |
| 451 | + CheckWithFlag(output1, input1, 0, true); |
| 452 | + CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, true); |
| 453 | + CheckWithFlag(output1, input1, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true); |
| 454 | + CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true); |
| 455 | + CheckWithFlag(output1, input2, 0, false); |
| 456 | + CheckWithFlag(output1, input2, SCRIPT_VERIFY_P2SH, false); |
| 457 | + CheckWithFlag(output1, input2, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false); |
| 458 | + CheckWithFlag(output1, input2, STANDARD_SCRIPT_VERIFY_FLAGS, false); |
| 459 | + |
| 460 | + // P2SH pay-to-compressed-pubkey. |
| 461 | + CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(scriptPubkey1)), output1, input1); |
| 462 | + CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(scriptPubkey2)), output2, input2); |
| 463 | + ReplaceRedeemScript(input2.vin[0].scriptSig, scriptPubkey1); |
| 464 | + CheckWithFlag(output1, input1, 0, true); |
| 465 | + CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, true); |
| 466 | + CheckWithFlag(output1, input1, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true); |
| 467 | + CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true); |
| 468 | + CheckWithFlag(output1, input2, 0, true); |
| 469 | + CheckWithFlag(output1, input2, SCRIPT_VERIFY_P2SH, false); |
| 470 | + CheckWithFlag(output1, input2, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false); |
| 471 | + CheckWithFlag(output1, input2, STANDARD_SCRIPT_VERIFY_FLAGS, false); |
| 472 | + |
| 473 | + // Witness pay-to-compressed-pubkey (v0). |
| 474 | + CreateCreditAndSpend(keystore, GetScriptForWitness(scriptPubkey1), output1, input1); |
| 475 | + CreateCreditAndSpend(keystore, GetScriptForWitness(scriptPubkey2), output2, input2); |
| 476 | + CheckWithFlag(output1, input1, 0, true); |
| 477 | + CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, true); |
| 478 | + CheckWithFlag(output1, input1, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true); |
| 479 | + CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true); |
| 480 | + CheckWithFlag(output1, input2, 0, true); |
| 481 | + CheckWithFlag(output1, input2, SCRIPT_VERIFY_P2SH, true); |
| 482 | + CheckWithFlag(output1, input2, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false); |
| 483 | + CheckWithFlag(output1, input2, STANDARD_SCRIPT_VERIFY_FLAGS, false); |
| 484 | + |
| 485 | + // P2SH witness pay-to-compressed-pubkey (v0). |
| 486 | + CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(GetScriptForWitness(scriptPubkey1))), output1, input1); |
| 487 | + CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(GetScriptForWitness(scriptPubkey2))), output2, input2); |
| 488 | + ReplaceRedeemScript(input2.vin[0].scriptSig, GetScriptForWitness(scriptPubkey1)); |
| 489 | + CheckWithFlag(output1, input1, 0, true); |
| 490 | + CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, true); |
| 491 | + CheckWithFlag(output1, input1, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true); |
| 492 | + CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true); |
| 493 | + CheckWithFlag(output1, input2, 0, true); |
| 494 | + CheckWithFlag(output1, input2, SCRIPT_VERIFY_P2SH, true); |
| 495 | + CheckWithFlag(output1, input2, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false); |
| 496 | + CheckWithFlag(output1, input2, STANDARD_SCRIPT_VERIFY_FLAGS, false); |
| 497 | + |
| 498 | + // Normal pay-to-uncompressed-pubkey. |
| 499 | + CreateCreditAndSpend(keystore, scriptPubkey1L, output1, input1); |
| 500 | + CreateCreditAndSpend(keystore, scriptPubkey2L, output2, input2); |
| 501 | + CheckWithFlag(output1, input1, 0, true); |
| 502 | + CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, true); |
| 503 | + CheckWithFlag(output1, input1, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true); |
| 504 | + CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true); |
| 505 | + CheckWithFlag(output1, input2, 0, false); |
| 506 | + CheckWithFlag(output1, input2, SCRIPT_VERIFY_P2SH, false); |
| 507 | + CheckWithFlag(output1, input2, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false); |
| 508 | + CheckWithFlag(output1, input2, STANDARD_SCRIPT_VERIFY_FLAGS, false); |
| 509 | + |
| 510 | + // P2SH pay-to-uncompressed-pubkey. |
| 511 | + CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(scriptPubkey1L)), output1, input1); |
| 512 | + CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(scriptPubkey2L)), output2, input2); |
| 513 | + ReplaceRedeemScript(input2.vin[0].scriptSig, scriptPubkey1L); |
| 514 | + CheckWithFlag(output1, input1, 0, true); |
| 515 | + CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, true); |
| 516 | + CheckWithFlag(output1, input1, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true); |
| 517 | + CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true); |
| 518 | + CheckWithFlag(output1, input2, 0, true); |
| 519 | + CheckWithFlag(output1, input2, SCRIPT_VERIFY_P2SH, false); |
| 520 | + CheckWithFlag(output1, input2, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false); |
| 521 | + CheckWithFlag(output1, input2, STANDARD_SCRIPT_VERIFY_FLAGS, false); |
| 522 | + |
| 523 | + // Witness pay-to-uncompressed-pubkey (v1). |
| 524 | + CreateCreditAndSpend(keystore, GetScriptForWitness(scriptPubkey1L), output1, input1); |
| 525 | + CreateCreditAndSpend(keystore, GetScriptForWitness(scriptPubkey2L), output2, input2); |
| 526 | + CheckWithFlag(output1, input1, 0, true); |
| 527 | + CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, true); |
| 528 | + CheckWithFlag(output1, input1, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true); |
| 529 | + CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true); |
| 530 | + CheckWithFlag(output1, input2, 0, true); |
| 531 | + CheckWithFlag(output1, input2, SCRIPT_VERIFY_P2SH, true); |
| 532 | + CheckWithFlag(output1, input2, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false); |
| 533 | + CheckWithFlag(output1, input2, STANDARD_SCRIPT_VERIFY_FLAGS, false); |
| 534 | + |
| 535 | + // P2SH witness pay-to-uncompressed-pubkey (v1). |
| 536 | + CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(GetScriptForWitness(scriptPubkey1L))), output1, input1); |
| 537 | + CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(GetScriptForWitness(scriptPubkey2L))), output2, input2); |
| 538 | + ReplaceRedeemScript(input2.vin[0].scriptSig, GetScriptForWitness(scriptPubkey1L)); |
| 539 | + CheckWithFlag(output1, input1, 0, true); |
| 540 | + CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, true); |
| 541 | + CheckWithFlag(output1, input1, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true); |
| 542 | + CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true); |
| 543 | + CheckWithFlag(output1, input2, 0, true); |
| 544 | + CheckWithFlag(output1, input2, SCRIPT_VERIFY_P2SH, true); |
| 545 | + CheckWithFlag(output1, input2, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false); |
| 546 | + CheckWithFlag(output1, input2, STANDARD_SCRIPT_VERIFY_FLAGS, false); |
| 547 | + |
| 548 | + // Normal 2-of-2 multisig |
| 549 | + CreateCreditAndSpend(keystore, scriptMulti, output1, input1, false); |
| 550 | + CheckWithFlag(output1, input1, 0, false); |
| 551 | + CreateCreditAndSpend(keystore2, scriptMulti, output2, input2, false); |
| 552 | + CheckWithFlag(output2, input2, 0, false); |
| 553 | + BOOST_CHECK(output1 == output2); |
| 554 | + UpdateTransaction(input1, 0, CombineSignatures(output1.vout[0].scriptPubKey, MutableTransactionSignatureChecker(&input1, 0, output1.vout[0].nValue), DataFromTransaction(input1, 0), DataFromTransaction(input2, 0))); |
| 555 | + CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true); |
| 556 | + |
| 557 | + // P2SH 2-of-2 multisig |
| 558 | + CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(scriptMulti)), output1, input1, false); |
| 559 | + CheckWithFlag(output1, input1, 0, true); |
| 560 | + CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, false); |
| 561 | + CreateCreditAndSpend(keystore2, GetScriptForDestination(CScriptID(scriptMulti)), output2, input2, false); |
| 562 | + CheckWithFlag(output2, input2, 0, true); |
| 563 | + CheckWithFlag(output2, input2, SCRIPT_VERIFY_P2SH, false); |
| 564 | + BOOST_CHECK(output1 == output2); |
| 565 | + UpdateTransaction(input1, 0, CombineSignatures(output1.vout[0].scriptPubKey, MutableTransactionSignatureChecker(&input1, 0, output1.vout[0].nValue), DataFromTransaction(input1, 0), DataFromTransaction(input2, 0))); |
| 566 | + CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, true); |
| 567 | + CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true); |
| 568 | + |
| 569 | + // Witness 2-of-2 multisig |
| 570 | + CreateCreditAndSpend(keystore, GetScriptForWitness(scriptMulti), output1, input1, false); |
| 571 | + CheckWithFlag(output1, input1, 0, true); |
| 572 | + CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, false); |
| 573 | + CreateCreditAndSpend(keystore2, GetScriptForWitness(scriptMulti), output2, input2, false); |
| 574 | + CheckWithFlag(output2, input2, 0, true); |
| 575 | + CheckWithFlag(output2, input2, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, false); |
| 576 | + BOOST_CHECK(output1 == output2); |
| 577 | + UpdateTransaction(input1, 0, CombineSignatures(output1.vout[0].scriptPubKey, MutableTransactionSignatureChecker(&input1, 0, output1.vout[0].nValue), DataFromTransaction(input1, 0), DataFromTransaction(input2, 0))); |
| 578 | + CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true); |
| 579 | + CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true); |
| 580 | + |
| 581 | + // P2SH witness 2-of-2 multisig |
| 582 | + CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(GetScriptForWitness(scriptMulti))), output1, input1, false); |
| 583 | + CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, true); |
| 584 | + CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, false); |
| 585 | + CreateCreditAndSpend(keystore2, GetScriptForDestination(CScriptID(GetScriptForWitness(scriptMulti))), output2, input2, false); |
| 586 | + CheckWithFlag(output2, input2, SCRIPT_VERIFY_P2SH, true); |
| 587 | + CheckWithFlag(output2, input2, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, false); |
| 588 | + BOOST_CHECK(output1 == output2); |
| 589 | + UpdateTransaction(input1, 0, CombineSignatures(output1.vout[0].scriptPubKey, MutableTransactionSignatureChecker(&input1, 0, output1.vout[0].nValue), DataFromTransaction(input1, 0), DataFromTransaction(input2, 0))); |
| 590 | + CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true); |
| 591 | + CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true); |
| 592 | +} |
| 593 | + |
318 | 594 | BOOST_AUTO_TEST_CASE(test_IsStandard)
|
319 | 595 | {
|
320 | 596 | LOCK(cs_main);
|
|
0 commit comments