diff --git a/src/script/sign.cpp b/src/script/sign.cpp index 68ed83b68..65c16519f 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -1,389 +1,389 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "script/sign.h" #include "key.h" #include "keystore.h" #include "policy/policy.h" #include "primitives/transaction.h" #include "script/standard.h" #include "uint256.h" typedef std::vector valtype; TransactionSignatureCreator::TransactionSignatureCreator( const CKeyStore *keystoreIn, const CTransaction *txToIn, unsigned int nInIn, const Amount amountIn, SigHashType sigHashTypeIn) : BaseSignatureCreator(keystoreIn), txTo(txToIn), nIn(nInIn), amount(amountIn), sigHashType(sigHashTypeIn), checker(txTo, nIn, amountIn) {} bool TransactionSignatureCreator::CreateSig(std::vector &vchSig, const CKeyID &address, const CScript &scriptCode) const { CKey key; if (!keystore->GetKey(address, key)) { return false; } uint256 hash = SignatureHash(scriptCode, *txTo, nIn, sigHashType, amount); if (!key.Sign(hash, vchSig)) { return false; } vchSig.push_back(uint8_t(sigHashType.getRawSigHashType())); return true; } static bool Sign1(const CKeyID &address, const BaseSignatureCreator &creator, const CScript &scriptCode, std::vector &ret) { std::vector vchSig; if (!creator.CreateSig(vchSig, address, scriptCode)) { return false; } ret.push_back(vchSig); return true; } static bool SignN(const std::vector &multisigdata, const BaseSignatureCreator &creator, const CScript &scriptCode, std::vector &ret) { int nSigned = 0; int nRequired = multisigdata.front()[0]; for (size_t i = 1; i < multisigdata.size() - 1 && nSigned < nRequired; i++) { const valtype &pubkey = multisigdata[i]; CKeyID keyID = CPubKey(pubkey).GetID(); if (Sign1(keyID, creator, scriptCode, ret)) { ++nSigned; } } return nSigned == nRequired; } /** * Sign scriptPubKey using signature made with creator. * Signatures are returned in scriptSigRet (or returns false if scriptPubKey * can't be signed), unless whichTypeRet is TX_SCRIPTHASH, in which case * scriptSigRet is the redemption script. * Returns false if scriptPubKey could not be completely satisfied. */ static bool SignStep(const BaseSignatureCreator &creator, const CScript &scriptPubKey, std::vector &ret, txnouttype &whichTypeRet) { CScript scriptRet; uint160 h160; ret.clear(); std::vector vSolutions; if (!Solver(scriptPubKey, whichTypeRet, vSolutions)) { return false; } CKeyID keyID; switch (whichTypeRet) { case TX_NONSTANDARD: case TX_NULL_DATA: return false; case TX_PUBKEY: keyID = CPubKey(vSolutions[0]).GetID(); return Sign1(keyID, creator, scriptPubKey, ret); case TX_PUBKEYHASH: { keyID = CKeyID(uint160(vSolutions[0])); if (!Sign1(keyID, creator, scriptPubKey, ret)) { return false; } CPubKey vch; creator.KeyStore().GetPubKey(keyID, vch); ret.push_back(ToByteVector(vch)); return true; } case TX_SCRIPTHASH: if (creator.KeyStore().GetCScript(uint160(vSolutions[0]), scriptRet)) { ret.push_back( std::vector(scriptRet.begin(), scriptRet.end())); return true; } return false; case TX_MULTISIG: // workaround CHECKMULTISIG bug ret.push_back(valtype()); return (SignN(vSolutions, creator, scriptPubKey, ret)); default: return false; } } static CScript PushAll(const std::vector &values) { CScript result; for (const valtype &v : values) { if (v.size() == 0) { result << OP_0; } else if (v.size() == 1 && v[0] >= 1 && v[0] <= 16) { result << CScript::EncodeOP_N(v[0]); } else { result << v; } } return result; } bool ProduceSignature(const BaseSignatureCreator &creator, const CScript &fromPubKey, SignatureData &sigdata) { CScript script = fromPubKey; bool solved = true; std::vector result; txnouttype whichType; solved = SignStep(creator, script, result, whichType); CScript subscript; if (solved && whichType == TX_SCRIPTHASH) { // Solver returns the subscript that needs to be evaluated; the final // scriptSig is the signatures from that and then the serialized // subscript: script = subscript = CScript(result[0].begin(), result[0].end()); solved = solved && SignStep(creator, script, result, whichType) && whichType != TX_SCRIPTHASH; result.push_back( std::vector(subscript.begin(), subscript.end())); } sigdata.scriptSig = PushAll(result); // Test solution return solved && VerifyScript(sigdata.scriptSig, fromPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, creator.Checker()); } SignatureData DataFromTransaction(const CMutableTransaction &tx, unsigned int nIn) { SignatureData data; assert(tx.vin.size() > nIn); data.scriptSig = tx.vin[nIn].scriptSig; return data; } void UpdateTransaction(CMutableTransaction &tx, unsigned int nIn, const SignatureData &data) { assert(tx.vin.size() > nIn); tx.vin[nIn].scriptSig = data.scriptSig; } bool SignSignature(const CKeyStore &keystore, const CScript &fromPubKey, CMutableTransaction &txTo, unsigned int nIn, const Amount amount, SigHashType sigHashType) { assert(nIn < txTo.vin.size()); CTransaction txToConst(txTo); TransactionSignatureCreator creator(&keystore, &txToConst, nIn, amount, sigHashType); SignatureData sigdata; bool ret = ProduceSignature(creator, fromPubKey, sigdata); UpdateTransaction(txTo, nIn, sigdata); return ret; } bool SignSignature(const CKeyStore &keystore, const CTransaction &txFrom, CMutableTransaction &txTo, unsigned int nIn, SigHashType sigHashType) { assert(nIn < txTo.vin.size()); CTxIn &txin = txTo.vin[nIn]; - assert(txin.prevout.n < txFrom.vout.size()); - const CTxOut &txout = txFrom.vout[txin.prevout.n]; + assert(txin.prevout.GetN() < txFrom.vout.size()); + const CTxOut &txout = txFrom.vout[txin.prevout.GetN()]; return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, txout.nValue, sigHashType); } static std::vector CombineMultisig( const CScript &scriptPubKey, const BaseSignatureChecker &checker, const std::vector &vSolutions, const std::vector &sigs1, const std::vector &sigs2) { // Combine all the signatures we've got: std::set allsigs; for (const valtype &v : sigs1) { if (!v.empty()) { allsigs.insert(v); } } for (const valtype &v : sigs2) { if (!v.empty()) { allsigs.insert(v); } } // Build a map of pubkey -> signature by matching sigs to pubkeys: assert(vSolutions.size() > 1); unsigned int nSigsRequired = vSolutions.front()[0]; unsigned int nPubKeys = vSolutions.size() - 2; std::map sigs; for (const valtype &sig : allsigs) { for (unsigned int i = 0; i < nPubKeys; i++) { const valtype &pubkey = vSolutions[i + 1]; // Already got a sig for this pubkey if (sigs.count(pubkey)) { continue; } if (checker.CheckSig(sig, pubkey, scriptPubKey, STANDARD_SCRIPT_VERIFY_FLAGS)) { sigs[pubkey] = sig; break; } } } // Now build a merged CScript: unsigned int nSigsHave = 0; // pop-one-too-many workaround std::vector result; result.push_back(valtype()); for (unsigned int i = 0; i < nPubKeys && nSigsHave < nSigsRequired; i++) { if (sigs.count(vSolutions[i + 1])) { result.push_back(sigs[vSolutions[i + 1]]); ++nSigsHave; } } // Fill any missing with OP_0: for (unsigned int i = nSigsHave; i < nSigsRequired; i++) { result.push_back(valtype()); } return result; } namespace { struct Stacks { std::vector script; Stacks() {} explicit Stacks(const std::vector &scriptSigStack_) : script(scriptSigStack_) {} explicit Stacks(const SignatureData &data) { EvalScript(script, data.scriptSig, MANDATORY_SCRIPT_VERIFY_FLAGS, BaseSignatureChecker()); } SignatureData Output() const { SignatureData result; result.scriptSig = PushAll(script); return result; } }; } // namespace static Stacks CombineSignatures(const CScript &scriptPubKey, const BaseSignatureChecker &checker, const txnouttype txType, const std::vector &vSolutions, Stacks sigs1, Stacks sigs2) { switch (txType) { case TX_NONSTANDARD: case TX_NULL_DATA: // Don't know anything about this, assume bigger one is correct: if (sigs1.script.size() >= sigs2.script.size()) { return sigs1; } return sigs2; case TX_PUBKEY: case TX_PUBKEYHASH: // Signatures are bigger than placeholders or empty scripts: if (sigs1.script.empty() || sigs1.script[0].empty()) { return sigs2; } return sigs1; case TX_SCRIPTHASH: { if (sigs1.script.empty() || sigs1.script.back().empty()) { return sigs2; } if (sigs2.script.empty() || sigs2.script.back().empty()) { return sigs1; } // Recur to combine: valtype spk = sigs1.script.back(); CScript pubKey2(spk.begin(), spk.end()); txnouttype txType2; std::vector> vSolutions2; Solver(pubKey2, txType2, vSolutions2); sigs1.script.pop_back(); sigs2.script.pop_back(); Stacks result = CombineSignatures(pubKey2, checker, txType2, vSolutions2, sigs1, sigs2); result.script.push_back(spk); return result; } case TX_MULTISIG: return Stacks(CombineMultisig(scriptPubKey, checker, vSolutions, sigs1.script, sigs2.script)); default: return Stacks(); } } SignatureData CombineSignatures(const CScript &scriptPubKey, const BaseSignatureChecker &checker, const SignatureData &scriptSig1, const SignatureData &scriptSig2) { txnouttype txType; std::vector> vSolutions; Solver(scriptPubKey, txType, vSolutions); return CombineSignatures(scriptPubKey, checker, txType, vSolutions, Stacks(scriptSig1), Stacks(scriptSig2)) .Output(); } namespace { /** Dummy signature checker which accepts all signatures. */ class DummySignatureChecker : public BaseSignatureChecker { public: DummySignatureChecker() {} bool CheckSig(const std::vector &scriptSig, const std::vector &vchPubKey, const CScript &scriptCode, uint32_t flags) const override { return true; } }; const DummySignatureChecker dummyChecker; } // namespace const BaseSignatureChecker &DummySignatureCreator::Checker() const { return dummyChecker; } bool DummySignatureCreator::CreateSig(std::vector &vchSig, const CKeyID &keyid, const CScript &scriptCode) const { // Create a dummy signature that is a valid DER-encoding vchSig.assign(72, '\000'); vchSig[0] = 0x30; vchSig[1] = 69; vchSig[2] = 0x02; vchSig[3] = 33; vchSig[4] = 0x01; vchSig[4 + 33] = 0x02; vchSig[5 + 33] = 32; vchSig[6 + 33] = 0x01; vchSig[6 + 33 + 32] = SIGHASH_ALL | SIGHASH_FORKID; return true; } diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp index 42c11be1f..5f49e4add 100644 --- a/src/test/script_P2SH_tests.cpp +++ b/src/test/script_P2SH_tests.cpp @@ -1,444 +1,439 @@ // Copyright (c) 2012-2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "core_io.h" #include "key.h" #include "keystore.h" #include "policy/policy.h" #include "script/ismine.h" #include "script/script.h" #include "script/script_error.h" #include "script/sign.h" #include "test/test_bitcoin.h" #include "validation.h" #include #include // Helpers: static std::vector Serialize(const CScript &s) { std::vector sSerialized(s.begin(), s.end()); return sSerialized; } static bool Verify(const CScript &scriptSig, const CScript &scriptPubKey, bool fStrict, ScriptError &err) { // Create dummy to/from transactions: CMutableTransaction txFrom; txFrom.vout.resize(1); txFrom.vout[0].scriptPubKey = scriptPubKey; CMutableTransaction txTo; txTo.vin.resize(1); txTo.vout.resize(1); - txTo.vin[0].prevout.n = 0; - txTo.vin[0].prevout.hash = txFrom.GetId(); + txTo.vin[0].prevout = COutPoint(txFrom.GetId(), 0); txTo.vin[0].scriptSig = scriptSig; txTo.vout[0].nValue = Amount(1); return VerifyScript( scriptSig, scriptPubKey, (fStrict ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE) | SCRIPT_ENABLE_SIGHASH_FORKID, MutableTransactionSignatureChecker(&txTo, 0, txFrom.vout[0].nValue), &err); } BOOST_FIXTURE_TEST_SUITE(script_P2SH_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(sign) { LOCK(cs_main); // Pay-to-script-hash looks like this: // scriptSig: // scriptPubKey: HASH160 EQUAL // Test SignSignature() (and therefore the version of Solver() that signs // transactions) CBasicKeyStore keystore; CKey key[4]; for (int i = 0; i < 4; i++) { key[i].MakeNewKey(true); keystore.AddKey(key[i]); } // 8 Scripts: checking all combinations of // different keys, straight/P2SH, pubkey/pubkeyhash CScript standardScripts[4]; standardScripts[0] << ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG; standardScripts[1] = GetScriptForDestination(key[1].GetPubKey().GetID()); standardScripts[2] << ToByteVector(key[1].GetPubKey()) << OP_CHECKSIG; standardScripts[3] = GetScriptForDestination(key[2].GetPubKey().GetID()); CScript evalScripts[4]; for (int i = 0; i < 4; i++) { keystore.AddCScript(standardScripts[i]); evalScripts[i] = GetScriptForDestination(CScriptID(standardScripts[i])); } CMutableTransaction txFrom; // Funding transaction: std::string reason; txFrom.vout.resize(8); for (int i = 0; i < 4; i++) { txFrom.vout[i].scriptPubKey = evalScripts[i]; txFrom.vout[i].nValue = COIN; txFrom.vout[i + 4].scriptPubKey = standardScripts[i]; txFrom.vout[i + 4].nValue = COIN; } BOOST_CHECK(IsStandardTx(CTransaction(txFrom), reason)); CMutableTransaction txTo[8]; // Spending transactions for (int i = 0; i < 8; i++) { txTo[i].vin.resize(1); txTo[i].vout.resize(1); - txTo[i].vin[0].prevout.n = i; - txTo[i].vin[0].prevout.hash = txFrom.GetId(); + txTo[i].vin[0].prevout = COutPoint(txFrom.GetId(), i); txTo[i].vout[0].nValue = Amount(1); BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey), strprintf("IsMine %d", i)); } for (int i = 0; i < 8; i++) { BOOST_CHECK_MESSAGE(SignSignature(keystore, CTransaction(txFrom), txTo[i], 0, SigHashType().withForkId()), strprintf("SignSignature %d", i)); } // All of the above should be OK, and the txTos have valid signatures // Check to make sure signature verification fails if we use the wrong // ScriptSig: for (int i = 0; i < 8; i++) { CTransaction tx(txTo[i]); PrecomputedTransactionData txdata(tx); for (int j = 0; j < 8; j++) { CScript sigSave = txTo[i].vin[0].scriptSig; txTo[i].vin[0].scriptSig = txTo[j].vin[0].scriptSig; - const CTxOut &output = txFrom.vout[txTo[i].vin[0].prevout.n]; + const CTxOut &output = txFrom.vout[txTo[i].vin[0].prevout.GetN()]; bool sigOK = CScriptCheck( output.scriptPubKey, output.nValue, CTransaction(txTo[i]), 0, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC | SCRIPT_ENABLE_SIGHASH_FORKID, false, txdata)(); if (i == j) { BOOST_CHECK_MESSAGE(sigOK, strprintf("VerifySignature %d %d", i, j)); } else { BOOST_CHECK_MESSAGE(!sigOK, strprintf("VerifySignature %d %d", i, j)); } txTo[i].vin[0].scriptSig = sigSave; } } } BOOST_AUTO_TEST_CASE(norecurse) { ScriptError err; // Make sure only the outer pay-to-script-hash does the // extra-validation thing: CScript invalidAsScript; invalidAsScript << OP_INVALIDOPCODE << OP_INVALIDOPCODE; CScript p2sh = GetScriptForDestination(CScriptID(invalidAsScript)); CScript scriptSig; scriptSig << Serialize(invalidAsScript); // Should not verify, because it will try to execute OP_INVALIDOPCODE BOOST_CHECK(!Verify(scriptSig, p2sh, true, err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_BAD_OPCODE, ScriptErrorString(err)); // Try to recur, and verification should succeed because // the inner HASH160 <> EQUAL should only check the hash: CScript p2sh2 = GetScriptForDestination(CScriptID(p2sh)); CScript scriptSig2; scriptSig2 << Serialize(invalidAsScript) << Serialize(p2sh); BOOST_CHECK(Verify(scriptSig2, p2sh2, true, err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); } BOOST_AUTO_TEST_CASE(set) { LOCK(cs_main); // Test the CScript::Set* methods CBasicKeyStore keystore; CKey key[4]; std::vector keys; for (int i = 0; i < 4; i++) { key[i].MakeNewKey(true); keystore.AddKey(key[i]); keys.push_back(key[i].GetPubKey()); } CScript inner[4]; inner[0] = GetScriptForDestination(key[0].GetPubKey().GetID()); inner[1] = GetScriptForMultisig( 2, std::vector(keys.begin(), keys.begin() + 2)); inner[2] = GetScriptForMultisig( 1, std::vector(keys.begin(), keys.begin() + 2)); inner[3] = GetScriptForMultisig( 2, std::vector(keys.begin(), keys.begin() + 3)); CScript outer[4]; for (int i = 0; i < 4; i++) { outer[i] = GetScriptForDestination(CScriptID(inner[i])); keystore.AddCScript(inner[i]); } // Funding transaction: CMutableTransaction txFrom; std::string reason; txFrom.vout.resize(4); for (int i = 0; i < 4; i++) { txFrom.vout[i].scriptPubKey = outer[i]; txFrom.vout[i].nValue = CENT; } BOOST_CHECK(IsStandardTx(CTransaction(txFrom), reason)); // Spending transactions CMutableTransaction txTo[4]; for (int i = 0; i < 4; i++) { txTo[i].vin.resize(1); txTo[i].vout.resize(1); - txTo[i].vin[0].prevout.n = i; - txTo[i].vin[0].prevout.hash = txFrom.GetId(); + txTo[i].vin[0].prevout = COutPoint(txFrom.GetId(), i); txTo[i].vout[0].nValue = 1 * CENT; txTo[i].vout[0].scriptPubKey = inner[i]; BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey), strprintf("IsMine %d", i)); } for (int i = 0; i < 4; i++) { BOOST_CHECK_MESSAGE(SignSignature(keystore, CTransaction(txFrom), txTo[i], 0, SigHashType().withForkId()), strprintf("SignSignature %d", i)); BOOST_CHECK_MESSAGE(IsStandardTx(CTransaction(txTo[i]), reason), strprintf("txTo[%d].IsStandard", i)); } } BOOST_AUTO_TEST_CASE(is) { // Test CScript::IsPayToScriptHash() uint160 dummy; CScript p2sh; p2sh << OP_HASH160 << ToByteVector(dummy) << OP_EQUAL; BOOST_CHECK(p2sh.IsPayToScriptHash()); // Not considered pay-to-script-hash if using one of the OP_PUSHDATA // opcodes: static const uint8_t direct[] = {OP_HASH160, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, OP_EQUAL}; BOOST_CHECK(CScript(direct, direct + sizeof(direct)).IsPayToScriptHash()); static const uint8_t pushdata1[] = {OP_HASH160, OP_PUSHDATA1, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, OP_EQUAL}; BOOST_CHECK( !CScript(pushdata1, pushdata1 + sizeof(pushdata1)).IsPayToScriptHash()); static const uint8_t pushdata2[] = {OP_HASH160, OP_PUSHDATA2, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, OP_EQUAL}; BOOST_CHECK( !CScript(pushdata2, pushdata2 + sizeof(pushdata2)).IsPayToScriptHash()); static const uint8_t pushdata4[] = {OP_HASH160, OP_PUSHDATA4, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, OP_EQUAL}; BOOST_CHECK( !CScript(pushdata4, pushdata4 + sizeof(pushdata4)).IsPayToScriptHash()); CScript not_p2sh; BOOST_CHECK(!not_p2sh.IsPayToScriptHash()); not_p2sh.clear(); not_p2sh << OP_HASH160 << ToByteVector(dummy) << ToByteVector(dummy) << OP_EQUAL; BOOST_CHECK(!not_p2sh.IsPayToScriptHash()); not_p2sh.clear(); not_p2sh << OP_NOP << ToByteVector(dummy) << OP_EQUAL; BOOST_CHECK(!not_p2sh.IsPayToScriptHash()); not_p2sh.clear(); not_p2sh << OP_HASH160 << ToByteVector(dummy) << OP_CHECKSIG; BOOST_CHECK(!not_p2sh.IsPayToScriptHash()); } BOOST_AUTO_TEST_CASE(switchover) { // Test switch over code CScript notValid; ScriptError err; notValid << OP_11 << OP_12 << OP_EQUALVERIFY; CScript scriptSig; scriptSig << Serialize(notValid); CScript fund = GetScriptForDestination(CScriptID(notValid)); // Validation should succeed under old rules (hash is correct): BOOST_CHECK(Verify(scriptSig, fund, false, err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); // Fail under new: BOOST_CHECK(!Verify(scriptSig, fund, true, err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EQUALVERIFY, ScriptErrorString(err)); } BOOST_AUTO_TEST_CASE(AreInputsStandard) { LOCK(cs_main); CCoinsView coinsDummy; CCoinsViewCache coins(&coinsDummy); CBasicKeyStore keystore; CKey key[6]; std::vector keys; for (int i = 0; i < 6; i++) { key[i].MakeNewKey(true); keystore.AddKey(key[i]); } for (int i = 0; i < 3; i++) keys.push_back(key[i].GetPubKey()); CMutableTransaction txFrom; txFrom.vout.resize(7); // First three are standard: CScript pay1 = GetScriptForDestination(key[0].GetPubKey().GetID()); keystore.AddCScript(pay1); CScript pay1of3 = GetScriptForMultisig(1, keys); // P2SH (OP_CHECKSIG) txFrom.vout[0].scriptPubKey = GetScriptForDestination(CScriptID(pay1)); txFrom.vout[0].nValue = Amount(1000); // ordinary OP_CHECKSIG txFrom.vout[1].scriptPubKey = pay1; txFrom.vout[1].nValue = Amount(2000); // ordinary OP_CHECKMULTISIG txFrom.vout[2].scriptPubKey = pay1of3; txFrom.vout[2].nValue = Amount(3000); // vout[3] is complicated 1-of-3 AND 2-of-3 // ... that is OK if wrapped in P2SH: CScript oneAndTwo; oneAndTwo << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()); oneAndTwo << OP_3 << OP_CHECKMULTISIGVERIFY; oneAndTwo << OP_2 << ToByteVector(key[3].GetPubKey()) << ToByteVector(key[4].GetPubKey()) << ToByteVector(key[5].GetPubKey()); oneAndTwo << OP_3 << OP_CHECKMULTISIG; keystore.AddCScript(oneAndTwo); txFrom.vout[3].scriptPubKey = GetScriptForDestination(CScriptID(oneAndTwo)); txFrom.vout[3].nValue = Amount(4000); // vout[4] is max sigops: CScript fifteenSigops; fifteenSigops << OP_1; for (unsigned i = 0; i < MAX_P2SH_SIGOPS; i++) fifteenSigops << ToByteVector(key[i % 3].GetPubKey()); fifteenSigops << OP_15 << OP_CHECKMULTISIG; keystore.AddCScript(fifteenSigops); txFrom.vout[4].scriptPubKey = GetScriptForDestination(CScriptID(fifteenSigops)); txFrom.vout[4].nValue = Amount(5000); // vout[5/6] are non-standard because they exceed MAX_P2SH_SIGOPS CScript sixteenSigops; sixteenSigops << OP_16 << OP_CHECKMULTISIG; keystore.AddCScript(sixteenSigops); txFrom.vout[5].scriptPubKey = GetScriptForDestination(CScriptID(fifteenSigops)); txFrom.vout[5].nValue = Amount(5000); CScript twentySigops; twentySigops << OP_CHECKMULTISIG; keystore.AddCScript(twentySigops); txFrom.vout[6].scriptPubKey = GetScriptForDestination(CScriptID(twentySigops)); txFrom.vout[6].nValue = Amount(6000); AddCoins(coins, CTransaction(txFrom), 0); CMutableTransaction txTo; txTo.vout.resize(1); txTo.vout[0].scriptPubKey = GetScriptForDestination(key[1].GetPubKey().GetID()); txTo.vin.resize(5); for (int i = 0; i < 5; i++) { - txTo.vin[i].prevout.n = i; - txTo.vin[i].prevout.hash = txFrom.GetId(); + txTo.vin[i].prevout = COutPoint(txFrom.GetId(), i); } + BOOST_CHECK(SignSignature(keystore, CTransaction(txFrom), txTo, 0, SigHashType().withForkId())); BOOST_CHECK(SignSignature(keystore, CTransaction(txFrom), txTo, 1, SigHashType().withForkId())); BOOST_CHECK(SignSignature(keystore, CTransaction(txFrom), txTo, 2, SigHashType().withForkId())); // SignSignature doesn't know how to sign these. We're not testing // validating signatures, so just create dummy signatures that DO include // the correct P2SH scripts: txTo.vin[3].scriptSig << OP_11 << OP_11 << std::vector(oneAndTwo.begin(), oneAndTwo.end()); txTo.vin[4].scriptSig << std::vector(fifteenSigops.begin(), fifteenSigops.end()); BOOST_CHECK(::AreInputsStandard(CTransaction(txTo), coins)); // 22 P2SH sigops for all inputs (1 for vin[0], 6 for vin[3], 15 for vin[4] BOOST_CHECK_EQUAL(GetP2SHSigOpCount(CTransaction(txTo), coins), 22U); CMutableTransaction txToNonStd1; txToNonStd1.vout.resize(1); txToNonStd1.vout[0].scriptPubKey = GetScriptForDestination(key[1].GetPubKey().GetID()); txToNonStd1.vout[0].nValue = Amount(1000); txToNonStd1.vin.resize(1); - txToNonStd1.vin[0].prevout.n = 5; - txToNonStd1.vin[0].prevout.hash = txFrom.GetId(); + txToNonStd1.vin[0].prevout = COutPoint(txFrom.GetId(), 5); txToNonStd1.vin[0].scriptSig << std::vector(sixteenSigops.begin(), sixteenSigops.end()); BOOST_CHECK(!::AreInputsStandard(CTransaction(txToNonStd1), coins)); BOOST_CHECK_EQUAL(GetP2SHSigOpCount(CTransaction(txToNonStd1), coins), 16U); CMutableTransaction txToNonStd2; txToNonStd2.vout.resize(1); txToNonStd2.vout[0].scriptPubKey = GetScriptForDestination(key[1].GetPubKey().GetID()); txToNonStd2.vout[0].nValue = Amount(1000); txToNonStd2.vin.resize(1); - txToNonStd2.vin[0].prevout.n = 6; - txToNonStd2.vin[0].prevout.hash = txFrom.GetId(); + txToNonStd2.vin[0].prevout = COutPoint(txFrom.GetId(), 6); txToNonStd2.vin[0].scriptSig << std::vector(twentySigops.begin(), twentySigops.end()); BOOST_CHECK(!::AreInputsStandard(CTransaction(txToNonStd2), coins)); BOOST_CHECK_EQUAL(GetP2SHSigOpCount(CTransaction(txToNonStd2), coins), 20U); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/script_antireplay_tests.cpp b/src/test/script_antireplay_tests.cpp index d05a79956..37b81453a 100644 --- a/src/test/script_antireplay_tests.cpp +++ b/src/test/script_antireplay_tests.cpp @@ -1,158 +1,157 @@ // Copyright (c) 2017 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "script/script.h" #include "test/test_bitcoin.h" #include "chainparams.h" #include "config.h" #include "consensus/validation.h" #include "validation.h" #include #include #include BOOST_FIXTURE_TEST_SUITE(script_antireplay_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(test_is_commitment) { std::vector data{}; // Empty commitment. auto s = CScript() << OP_RETURN << data; BOOST_CHECK(s.IsCommitment(data)); // Commitment to a value of the wrong size. data.push_back(42); BOOST_CHECK(!s.IsCommitment(data)); // Not a commitment. s = CScript() << data; BOOST_CHECK(!s.IsCommitment(data)); // Non empty commitment. s = CScript() << OP_RETURN << data; BOOST_CHECK(s.IsCommitment(data)); // Commitment to the wrong value. data[0] = 0x42; BOOST_CHECK(!s.IsCommitment(data)); // Commitment to a larger value. std::string str = "Bitcoin: A peer-to-peer Electronic Cash System"; data = std::vector(str.begin(), str.end()); BOOST_CHECK(!s.IsCommitment(data)); s = CScript() << OP_RETURN << data; BOOST_CHECK(s.IsCommitment(data)); // 64 bytes commitment, still valid. data.resize(64); s = CScript() << OP_RETURN << data; BOOST_CHECK(s.IsCommitment(data)); // Commitment is too large. data.push_back(23); s = CScript() << OP_RETURN << data; BOOST_CHECK(!s.IsCommitment(data)); // Check with the actual replay commitment we are going to use. SelectParams(CBaseChainParams::MAIN); const Consensus::Params ¶ms = Params().GetConsensus(); s = CScript() << OP_RETURN << params.antiReplayOpReturnCommitment; BOOST_CHECK(s.IsCommitment(params.antiReplayOpReturnCommitment)); } BOOST_AUTO_TEST_CASE(test_antireplay) { SelectParams(CBaseChainParams::MAIN); GlobalConfig config; const Consensus::Params ¶ms = config.GetChainParams().GetConsensus(); // The anti replay rule start at uahfHeight and stops at // antiReplayOpReturnSunsetHeight. const int nUAHFHeight = params.uahfHeight; const int nSunsetHeight = params.antiReplayOpReturnSunsetHeight; const int64_t nUAHFStartTime = 123456; CMutableTransaction tx; tx.nVersion = 1; tx.vin.resize(1); - tx.vin[0].prevout.hash = InsecureRand256(); - tx.vin[0].prevout.n = 0; + tx.vin[0].prevout = COutPoint(InsecureRand256(), 0); tx.vin[0].scriptSig = CScript(); tx.vout.resize(1); tx.vout[0].nValue = Amount(1); tx.vout[0].scriptPubKey = CScript(); { // Base transaction is valid. CValidationState state; BOOST_CHECK(ContextualCheckTransaction(config, CTransaction(tx), state, nSunsetHeight, nUAHFStartTime)); } { // Base transaction is still valid after sunset. CValidationState state; BOOST_CHECK(ContextualCheckTransaction(config, CTransaction(tx), state, nSunsetHeight + 1, nUAHFStartTime)); } { // Base transaction is valid before the fork. CValidationState state; BOOST_CHECK(ContextualCheckTransaction(config, CTransaction(tx), state, nUAHFHeight - 1, nUAHFStartTime - 1)); } tx.vout[0].scriptPubKey = CScript() << OP_RETURN << OP_0; { // Wrong commitment, still valid. CValidationState state; BOOST_CHECK(ContextualCheckTransaction(config, CTransaction(tx), state, nSunsetHeight, nUAHFStartTime)); } tx.vout[0].scriptPubKey = CScript() << OP_RETURN << params.antiReplayOpReturnCommitment; { // Anti replay commitment, not valid anymore. CValidationState state; BOOST_CHECK(!ContextualCheckTransaction(config, CTransaction(tx), state, nUAHFHeight, nUAHFStartTime)); BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-txn-replay"); } { // Anti replay commitment, not valid anymore. CValidationState state; BOOST_CHECK(!ContextualCheckTransaction(config, CTransaction(tx), state, nSunsetHeight, nUAHFStartTime)); BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-txn-replay"); } { // Anti replay commitment, disabled before start time. CValidationState state; BOOST_CHECK(ContextualCheckTransaction( config, CTransaction(tx), state, nUAHFHeight - 1, nUAHFStartTime)); } { // Anti replay commitment, disabled after sunset. CValidationState state; BOOST_CHECK(ContextualCheckTransaction(config, CTransaction(tx), state, nSunsetHeight + 1, nUAHFStartTime)); } } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index d335b9c4f..60a126d34 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -1,1838 +1,1837 @@ // Copyright (c) 2011-2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "data/script_tests.json.h" #include "core_io.h" #include "key.h" #include "keystore.h" #include "rpc/server.h" #include "script/script.h" #include "script/script_error.h" #include "script/sighashtype.h" #include "script/sign.h" #include "test/jsonutil.h" #include "test/scriptflags.h" #include "test/sigutil.h" #include "test/test_bitcoin.h" #include "util.h" #include "utilstrencodings.h" #if defined(HAVE_CONSENSUS_LIB) #include "script/bitcoinconsensus.h" #endif #include #include #include #include #include #include // Uncomment if you want to output updated JSON tests. // #define UPDATE_JSON_TESTS static const unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC; struct ScriptErrorDesc { ScriptError_t err; const char *name; }; static ScriptErrorDesc script_errors[] = { {SCRIPT_ERR_OK, "OK"}, {SCRIPT_ERR_UNKNOWN_ERROR, "UNKNOWN_ERROR"}, {SCRIPT_ERR_EVAL_FALSE, "EVAL_FALSE"}, {SCRIPT_ERR_OP_RETURN, "OP_RETURN"}, {SCRIPT_ERR_SCRIPT_SIZE, "SCRIPT_SIZE"}, {SCRIPT_ERR_PUSH_SIZE, "PUSH_SIZE"}, {SCRIPT_ERR_OP_COUNT, "OP_COUNT"}, {SCRIPT_ERR_STACK_SIZE, "STACK_SIZE"}, {SCRIPT_ERR_SIG_COUNT, "SIG_COUNT"}, {SCRIPT_ERR_PUBKEY_COUNT, "PUBKEY_COUNT"}, {SCRIPT_ERR_INVALID_OPERAND_SIZE, "OPERAND_SIZE"}, {SCRIPT_ERR_INVALID_NUMBER_RANGE, "INVALID_NUMBER_RANGE"}, {SCRIPT_ERR_INVALID_SPLIT_RANGE, "SPLIT_RANGE"}, {SCRIPT_ERR_VERIFY, "VERIFY"}, {SCRIPT_ERR_EQUALVERIFY, "EQUALVERIFY"}, {SCRIPT_ERR_CHECKMULTISIGVERIFY, "CHECKMULTISIGVERIFY"}, {SCRIPT_ERR_CHECKSIGVERIFY, "CHECKSIGVERIFY"}, {SCRIPT_ERR_NUMEQUALVERIFY, "NUMEQUALVERIFY"}, {SCRIPT_ERR_BAD_OPCODE, "BAD_OPCODE"}, {SCRIPT_ERR_DISABLED_OPCODE, "DISABLED_OPCODE"}, {SCRIPT_ERR_INVALID_STACK_OPERATION, "INVALID_STACK_OPERATION"}, {SCRIPT_ERR_INVALID_ALTSTACK_OPERATION, "INVALID_ALTSTACK_OPERATION"}, {SCRIPT_ERR_UNBALANCED_CONDITIONAL, "UNBALANCED_CONDITIONAL"}, {SCRIPT_ERR_NEGATIVE_LOCKTIME, "NEGATIVE_LOCKTIME"}, {SCRIPT_ERR_UNSATISFIED_LOCKTIME, "UNSATISFIED_LOCKTIME"}, {SCRIPT_ERR_SIG_HASHTYPE, "SIG_HASHTYPE"}, {SCRIPT_ERR_SIG_DER, "SIG_DER"}, {SCRIPT_ERR_MINIMALDATA, "MINIMALDATA"}, {SCRIPT_ERR_SIG_PUSHONLY, "SIG_PUSHONLY"}, {SCRIPT_ERR_SIG_HIGH_S, "SIG_HIGH_S"}, {SCRIPT_ERR_SIG_NULLDUMMY, "SIG_NULLDUMMY"}, {SCRIPT_ERR_PUBKEYTYPE, "PUBKEYTYPE"}, {SCRIPT_ERR_CLEANSTACK, "CLEANSTACK"}, {SCRIPT_ERR_MINIMALIF, "MINIMALIF"}, {SCRIPT_ERR_SIG_NULLFAIL, "NULLFAIL"}, {SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS, "DISCOURAGE_UPGRADABLE_NOPS"}, {SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM, "DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM"}, {SCRIPT_ERR_NONCOMPRESSED_PUBKEY, "NONCOMPRESSED_PUBKEY"}, {SCRIPT_ERR_ILLEGAL_FORKID, "ILLEGAL_FORKID"}, {SCRIPT_ERR_MUST_USE_FORKID, "MISSING_FORKID"}, {SCRIPT_ERR_DIV_BY_ZERO, "DIV_BY_ZERO"}, {SCRIPT_ERR_MOD_BY_ZERO, "MOD_BY_ZERO"}, }; const char *FormatScriptError(ScriptError_t err) { for (size_t i = 0; i < ARRAYLEN(script_errors); ++i) { if (script_errors[i].err == err) { return script_errors[i].name; } } BOOST_ERROR("Unknown scripterror enumeration value, update script_errors " "in script_tests.cpp."); return ""; } ScriptError_t ParseScriptError(const std::string &name) { for (size_t i = 0; i < ARRAYLEN(script_errors); ++i) { if (script_errors[i].name == name) { return script_errors[i].err; } } BOOST_ERROR("Unknown scripterror \"" << name << "\" in test description"); return SCRIPT_ERR_UNKNOWN_ERROR; } BOOST_FIXTURE_TEST_SUITE(script_tests, BasicTestingSetup) static CMutableTransaction BuildCreditingTransaction(const CScript &scriptPubKey, const Amount nValue) { CMutableTransaction txCredit; txCredit.nVersion = 1; txCredit.nLockTime = 0; txCredit.vin.resize(1); txCredit.vout.resize(1); txCredit.vin[0].prevout.SetNull(); txCredit.vin[0].scriptSig = CScript() << CScriptNum(0) << CScriptNum(0); txCredit.vin[0].nSequence = CTxIn::SEQUENCE_FINAL; txCredit.vout[0].scriptPubKey = scriptPubKey; txCredit.vout[0].nValue = nValue; return txCredit; } static CMutableTransaction BuildSpendingTransaction(const CScript &scriptSig, const CMutableTransaction &txCredit) { CMutableTransaction txSpend; txSpend.nVersion = 1; txSpend.nLockTime = 0; txSpend.vin.resize(1); txSpend.vout.resize(1); - txSpend.vin[0].prevout.hash = txCredit.GetId(); - txSpend.vin[0].prevout.n = 0; + txSpend.vin[0].prevout = COutPoint(txCredit.GetId(), 0); txSpend.vin[0].scriptSig = scriptSig; txSpend.vin[0].nSequence = CTxIn::SEQUENCE_FINAL; txSpend.vout[0].scriptPubKey = CScript(); txSpend.vout[0].nValue = txCredit.vout[0].nValue; return txSpend; } static void DoTest(const CScript &scriptPubKey, const CScript &scriptSig, int flags, const std::string &message, int scriptError, const Amount nValue) { bool expect = (scriptError == SCRIPT_ERR_OK); if (flags & SCRIPT_VERIFY_CLEANSTACK) { flags |= SCRIPT_VERIFY_P2SH; } ScriptError err; CMutableTransaction txCredit = BuildCreditingTransaction(scriptPubKey, nValue); CMutableTransaction tx = BuildSpendingTransaction(scriptSig, txCredit); CMutableTransaction tx2 = tx; BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, flags, MutableTransactionSignatureChecker( &tx, 0, txCredit.vout[0].nValue), &err) == expect, message); BOOST_CHECK_MESSAGE( err == scriptError, std::string(FormatScriptError(err)) + " where " + std::string(FormatScriptError((ScriptError_t)scriptError)) + " expected: " + message); #if defined(HAVE_CONSENSUS_LIB) CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); stream << tx2; int libconsensus_flags = flags & bitcoinconsensus_SCRIPT_FLAGS_VERIFY_ALL; if (libconsensus_flags == flags) { if (flags & bitcoinconsensus_SCRIPT_ENABLE_SIGHASH_FORKID) { BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script_with_amount( scriptPubKey.data(), scriptPubKey.size(), txCredit.vout[0].nValue.GetSatoshis(), (const uint8_t *)&stream[0], stream.size(), 0, libconsensus_flags, nullptr) == expect, message); } else { BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script_with_amount( scriptPubKey.data(), scriptPubKey.size(), 0, (const uint8_t *)&stream[0], stream.size(), 0, libconsensus_flags, nullptr) == expect, message); BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script( scriptPubKey.data(), scriptPubKey.size(), (const uint8_t *)&stream[0], stream.size(), 0, libconsensus_flags, nullptr) == expect, message); } } #endif } namespace { const uint8_t vchKey0[32] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}; const uint8_t vchKey1[32] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}; const uint8_t vchKey2[32] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}; struct KeyData { CKey key0, key0C, key1, key1C, key2, key2C; CPubKey pubkey0, pubkey0C, pubkey0H; CPubKey pubkey1, pubkey1C; CPubKey pubkey2, pubkey2C; KeyData() { key0.Set(vchKey0, vchKey0 + 32, false); key0C.Set(vchKey0, vchKey0 + 32, true); pubkey0 = key0.GetPubKey(); pubkey0H = key0.GetPubKey(); pubkey0C = key0C.GetPubKey(); *const_cast(&pubkey0H[0]) = 0x06 | (pubkey0H[64] & 1); key1.Set(vchKey1, vchKey1 + 32, false); key1C.Set(vchKey1, vchKey1 + 32, true); pubkey1 = key1.GetPubKey(); pubkey1C = key1C.GetPubKey(); key2.Set(vchKey2, vchKey2 + 32, false); key2C.Set(vchKey2, vchKey2 + 32, true); pubkey2 = key2.GetPubKey(); pubkey2C = key2C.GetPubKey(); } }; class TestBuilder { private: //! Actually executed script CScript script; //! The P2SH redeemscript CScript redeemscript; CTransactionRef creditTx; CMutableTransaction spendTx; bool havePush; std::vector push; std::string comment; int flags; int scriptError; Amount nValue; void DoPush() { if (havePush) { spendTx.vin[0].scriptSig << push; havePush = false; } } void DoPush(const std::vector &data) { DoPush(); push = data; havePush = true; } public: TestBuilder(const CScript &script_, const std::string &comment_, int flags_, bool P2SH = false, Amount nValue_ = Amount(0)) : script(script_), havePush(false), comment(comment_), flags(flags_), scriptError(SCRIPT_ERR_OK), nValue(nValue_) { CScript scriptPubKey = script; if (P2SH) { redeemscript = scriptPubKey; scriptPubKey = CScript() << OP_HASH160 << ToByteVector(CScriptID(redeemscript)) << OP_EQUAL; } creditTx = MakeTransactionRef(BuildCreditingTransaction(scriptPubKey, nValue)); spendTx = BuildSpendingTransaction(CScript(), *creditTx); } TestBuilder &ScriptError(ScriptError_t err) { scriptError = err; return *this; } TestBuilder &Add(const CScript &_script) { DoPush(); spendTx.vin[0].scriptSig += _script; return *this; } TestBuilder &Num(int num) { DoPush(); spendTx.vin[0].scriptSig << num; return *this; } TestBuilder &Push(const std::string &hex) { DoPush(ParseHex(hex)); return *this; } TestBuilder &Push(const CScript &_script) { DoPush(std::vector(_script.begin(), _script.end())); return *this; } TestBuilder &PushSig(const CKey &key, SigHashType sigHashType = SigHashType(), unsigned int lenR = 32, unsigned int lenS = 32, Amount amount = Amount(0), uint32_t flags = SCRIPT_ENABLE_SIGHASH_FORKID) { uint256 hash = SignatureHash(script, CTransaction(spendTx), 0, sigHashType, amount, nullptr, flags); std::vector vchSig, r, s; uint32_t iter = 0; do { key.Sign(hash, vchSig, iter++); if ((lenS == 33) != (vchSig[5 + vchSig[3]] == 33)) { NegateSignatureS(vchSig); } r = std::vector(vchSig.begin() + 4, vchSig.begin() + 4 + vchSig[3]); s = std::vector(vchSig.begin() + 6 + vchSig[3], vchSig.begin() + 6 + vchSig[3] + vchSig[5 + vchSig[3]]); } while (lenR != r.size() || lenS != s.size()); vchSig.push_back(static_cast(sigHashType.getRawSigHashType())); DoPush(vchSig); return *this; } TestBuilder &Push(const CPubKey &pubkey) { DoPush(std::vector(pubkey.begin(), pubkey.end())); return *this; } TestBuilder &PushRedeem() { DoPush(std::vector(redeemscript.begin(), redeemscript.end())); return *this; } TestBuilder &EditPush(unsigned int pos, const std::string &hexin, const std::string &hexout) { assert(havePush); std::vector datain = ParseHex(hexin); std::vector dataout = ParseHex(hexout); assert(pos + datain.size() <= push.size()); BOOST_CHECK_MESSAGE( std::vector(push.begin() + pos, push.begin() + pos + datain.size()) == datain, comment); push.erase(push.begin() + pos, push.begin() + pos + datain.size()); push.insert(push.begin() + pos, dataout.begin(), dataout.end()); return *this; } TestBuilder &DamagePush(unsigned int pos) { assert(havePush); assert(pos < push.size()); push[pos] ^= 1; return *this; } TestBuilder &Test() { // Make a copy so we can rollback the push. TestBuilder copy = *this; DoPush(); DoTest(creditTx->vout[0].scriptPubKey, spendTx.vin[0].scriptSig, flags, comment, scriptError, nValue); *this = copy; return *this; } UniValue GetJSON() { DoPush(); UniValue array(UniValue::VARR); if (nValue != Amount(0)) { UniValue amount(UniValue::VARR); amount.push_back(ValueFromAmount(nValue)); array.push_back(amount); } array.push_back(FormatScript(spendTx.vin[0].scriptSig)); array.push_back(FormatScript(creditTx->vout[0].scriptPubKey)); array.push_back(FormatScriptFlags(flags)); array.push_back(FormatScriptError((ScriptError_t)scriptError)); array.push_back(comment); return array; } std::string GetComment() { return comment; } const CScript &GetScriptPubKey() { return creditTx->vout[0].scriptPubKey; } }; std::string JSONPrettyPrint(const UniValue &univalue) { std::string ret = univalue.write(4); // Workaround for libunivalue pretty printer, which puts a space between // commas and newlines size_t pos = 0; while ((pos = ret.find(" \n", pos)) != std::string::npos) { ret.replace(pos, 2, "\n"); pos++; } return ret; } } // namespace BOOST_AUTO_TEST_CASE(script_build) { const KeyData keys; std::vector tests; tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2PK", 0) .PushSig(keys.key0)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2PK, bad sig", 0) .PushSig(keys.key0) .DamagePush(10) .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey1C.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG, "P2PKH", 0) .PushSig(keys.key1) .Push(keys.pubkey1C)); tests.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey2C.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG, "P2PKH, bad pubkey", 0) .PushSig(keys.key2) .Push(keys.pubkey2C) .DamagePush(5) .ScriptError(SCRIPT_ERR_EQUALVERIFY)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG, "P2PK anyonecanpay", 0) .PushSig(keys.key1, SigHashType().withAnyoneCanPay())); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG, "P2PK anyonecanpay marked with normal hashtype", 0) .PushSig(keys.key1, SigHashType().withAnyoneCanPay()) .EditPush(70, "81", "01") .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0C) << OP_CHECKSIG, "P2SH(P2PK)", SCRIPT_VERIFY_P2SH, true) .PushSig(keys.key0) .PushRedeem()); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0C) << OP_CHECKSIG, "P2SH(P2PK), bad redeemscript", SCRIPT_VERIFY_P2SH, true) .PushSig(keys.key0) .PushRedeem() .DamagePush(10) .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey0.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG, "P2SH(P2PKH)", SCRIPT_VERIFY_P2SH, true) .PushSig(keys.key0) .Push(keys.pubkey0) .PushRedeem()); tests.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey1.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG, "P2SH(P2PKH), bad sig but no VERIFY_P2SH", 0, true) .PushSig(keys.key0) .DamagePush(10) .PushRedeem()); tests.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey1.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG, "P2SH(P2PKH), bad sig", SCRIPT_VERIFY_P2SH, true) .PushSig(keys.key0) .DamagePush(10) .PushRedeem() .ScriptError(SCRIPT_ERR_EQUALVERIFY)); tests.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG, "3-of-3", 0) .Num(0) .PushSig(keys.key0) .PushSig(keys.key1) .PushSig(keys.key2)); tests.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG, "3-of-3, 2 sigs", 0) .Num(0) .PushSig(keys.key0) .PushSig(keys.key1) .Num(0) .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG, "P2SH(2-of-3)", SCRIPT_VERIFY_P2SH, true) .Num(0) .PushSig(keys.key1) .PushSig(keys.key2) .PushRedeem()); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG, "P2SH(2-of-3), 1 sig", SCRIPT_VERIFY_P2SH, true) .Num(0) .PushSig(keys.key1) .Num(0) .PushRedeem() .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "P2PK with too much R padding but no DERSIG", 0) .PushSig(keys.key1, SigHashType(), 31, 32) .EditPush(1, "43021F", "44022000")); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "P2PK with too much R padding", SCRIPT_VERIFY_DERSIG) .PushSig(keys.key1, SigHashType(), 31, 32) .EditPush(1, "43021F", "44022000") .ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "P2PK with too much S padding but no DERSIG", 0) .PushSig(keys.key1) .EditPush(1, "44", "45") .EditPush(37, "20", "2100")); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "P2PK with too much S padding", SCRIPT_VERIFY_DERSIG) .PushSig(keys.key1) .EditPush(1, "44", "45") .EditPush(37, "20", "2100") .ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "P2PK with too little R padding but no DERSIG", 0) .PushSig(keys.key1, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220")); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "P2PK with too little R padding", SCRIPT_VERIFY_DERSIG) .PushSig(keys.key1, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220") .ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back( TestBuilder( CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG << OP_NOT, "P2PK NOT with bad sig with too much R padding but no DERSIG", 0) .PushSig(keys.key2, SigHashType(), 31, 32) .EditPush(1, "43021F", "44022000") .DamagePush(10)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG << OP_NOT, "P2PK NOT with bad sig with too much R padding", SCRIPT_VERIFY_DERSIG) .PushSig(keys.key2, SigHashType(), 31, 32) .EditPush(1, "43021F", "44022000") .DamagePush(10) .ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG << OP_NOT, "P2PK NOT with too much R padding but no DERSIG", 0) .PushSig(keys.key2, SigHashType(), 31, 32) .EditPush(1, "43021F", "44022000") .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG << OP_NOT, "P2PK NOT with too much R padding", SCRIPT_VERIFY_DERSIG) .PushSig(keys.key2, SigHashType(), 31, 32) .EditPush(1, "43021F", "44022000") .ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "BIP66 example 1, without DERSIG", 0) .PushSig(keys.key1, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220")); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "BIP66 example 1, with DERSIG", SCRIPT_VERIFY_DERSIG) .PushSig(keys.key1, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220") .ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, "BIP66 example 2, without DERSIG", 0) .PushSig(keys.key1, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220") .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, "BIP66 example 2, with DERSIG", SCRIPT_VERIFY_DERSIG) .PushSig(keys.key1, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220") .ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "BIP66 example 3, without DERSIG", 0) .Num(0) .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "BIP66 example 3, with DERSIG", SCRIPT_VERIFY_DERSIG) .Num(0) .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, "BIP66 example 4, without DERSIG", 0) .Num(0)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, "BIP66 example 4, with DERSIG", SCRIPT_VERIFY_DERSIG) .Num(0)); tests.push_back( TestBuilder( CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, "BIP66 example 4, with DERSIG, non-null DER-compliant signature", SCRIPT_VERIFY_DERSIG) .Push("300602010102010101")); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, "BIP66 example 4, with DERSIG and NULLFAIL", SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_NULLFAIL) .Num(0)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, "BIP66 example 4, with DERSIG and NULLFAIL, " "non-null DER-compliant signature", SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_NULLFAIL) .Push("300602010102010101") .ScriptError(SCRIPT_ERR_SIG_NULLFAIL)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "BIP66 example 5, without DERSIG", 0) .Num(1) .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "BIP66 example 5, with DERSIG", SCRIPT_VERIFY_DERSIG) .Num(1) .ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, "BIP66 example 6, without DERSIG", 0) .Num(1)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, "BIP66 example 6, with DERSIG", SCRIPT_VERIFY_DERSIG) .Num(1) .ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG, "BIP66 example 7, without DERSIG", 0) .Num(0) .PushSig(keys.key1, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220") .PushSig(keys.key2)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG, "BIP66 example 7, with DERSIG", SCRIPT_VERIFY_DERSIG) .Num(0) .PushSig(keys.key1, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220") .PushSig(keys.key2) .ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT, "BIP66 example 8, without DERSIG", 0) .Num(0) .PushSig(keys.key1, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220") .PushSig(keys.key2) .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT, "BIP66 example 8, with DERSIG", SCRIPT_VERIFY_DERSIG) .Num(0) .PushSig(keys.key1, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220") .PushSig(keys.key2) .ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG, "BIP66 example 9, without DERSIG", 0) .Num(0) .Num(0) .PushSig(keys.key2, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220") .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG, "BIP66 example 9, with DERSIG", SCRIPT_VERIFY_DERSIG) .Num(0) .Num(0) .PushSig(keys.key2, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220") .ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT, "BIP66 example 10, without DERSIG", 0) .Num(0) .Num(0) .PushSig(keys.key2, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220")); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT, "BIP66 example 10, with DERSIG", SCRIPT_VERIFY_DERSIG) .Num(0) .Num(0) .PushSig(keys.key2, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220") .ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG, "BIP66 example 11, without DERSIG", 0) .Num(0) .PushSig(keys.key1, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220") .Num(0) .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG, "BIP66 example 11, with DERSIG", SCRIPT_VERIFY_DERSIG) .Num(0) .PushSig(keys.key1, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220") .Num(0) .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT, "BIP66 example 12, without DERSIG", 0) .Num(0) .PushSig(keys.key1, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220") .Num(0)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT, "BIP66 example 12, with DERSIG", SCRIPT_VERIFY_DERSIG) .Num(0) .PushSig(keys.key1, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220") .Num(0)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, "P2PK with multi-byte hashtype, without DERSIG", 0) .PushSig(keys.key2) .EditPush(70, "01", "0101")); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, "P2PK with multi-byte hashtype, with DERSIG", SCRIPT_VERIFY_DERSIG) .PushSig(keys.key2) .EditPush(70, "01", "0101") .ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, "P2PK with high S but no LOW_S", 0) .PushSig(keys.key2, SigHashType(), 32, 33)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, "P2PK with high S", SCRIPT_VERIFY_LOW_S) .PushSig(keys.key2, SigHashType(), 32, 33) .ScriptError(SCRIPT_ERR_SIG_HIGH_S)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG, "P2PK with hybrid pubkey but no STRICTENC", 0) .PushSig(keys.key0)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG, "P2PK with hybrid pubkey", SCRIPT_VERIFY_STRICTENC) .PushSig(keys.key0, SigHashType()) .ScriptError(SCRIPT_ERR_PUBKEYTYPE)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT, "P2PK NOT with hybrid pubkey but no STRICTENC", 0) .PushSig(keys.key0) .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT, "P2PK NOT with hybrid pubkey", SCRIPT_VERIFY_STRICTENC) .PushSig(keys.key0) .ScriptError(SCRIPT_ERR_PUBKEYTYPE)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT, "P2PK NOT with invalid hybrid pubkey but no STRICTENC", 0) .PushSig(keys.key0) .DamagePush(10)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT, "P2PK NOT with invalid hybrid pubkey", SCRIPT_VERIFY_STRICTENC) .PushSig(keys.key0) .DamagePush(10) .ScriptError(SCRIPT_ERR_PUBKEYTYPE)); tests.push_back( TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey0H) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG, "1-of-2 with the second 1 hybrid pubkey and no STRICTENC", 0) .Num(0) .PushSig(keys.key1)); tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey0H) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG, "1-of-2 with the second 1 hybrid pubkey", SCRIPT_VERIFY_STRICTENC) .Num(0) .PushSig(keys.key1)); tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey0H) << OP_2 << OP_CHECKMULTISIG, "1-of-2 with the first 1 hybrid pubkey", SCRIPT_VERIFY_STRICTENC) .Num(0) .PushSig(keys.key1) .ScriptError(SCRIPT_ERR_PUBKEYTYPE)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG, "P2PK with undefined hashtype but no STRICTENC", 0) .PushSig(keys.key1, SigHashType(5))); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG, "P2PK with undefined hashtype", SCRIPT_VERIFY_STRICTENC) .PushSig(keys.key1, SigHashType(5)) .ScriptError(SCRIPT_ERR_SIG_HASHTYPE)); tests.push_back( TestBuilder( CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG << OP_NOT, "P2PK NOT with invalid sig and undefined hashtype but no STRICTENC", 0) .PushSig(keys.key1, SigHashType(5)) .DamagePush(10)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG << OP_NOT, "P2PK NOT with invalid sig and undefined hashtype", SCRIPT_VERIFY_STRICTENC) .PushSig(keys.key1, SigHashType(5)) .DamagePush(10) .ScriptError(SCRIPT_ERR_SIG_HASHTYPE)); tests.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG, "3-of-3 with nonzero dummy but no NULLDUMMY", 0) .Num(1) .PushSig(keys.key0) .PushSig(keys.key1) .PushSig(keys.key2)); tests.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG, "3-of-3 with nonzero dummy", SCRIPT_VERIFY_NULLDUMMY) .Num(1) .PushSig(keys.key0) .PushSig(keys.key1) .PushSig(keys.key2) .ScriptError(SCRIPT_ERR_SIG_NULLDUMMY)); tests.push_back( TestBuilder( CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG << OP_NOT, "3-of-3 NOT with invalid sig and nonzero dummy but no NULLDUMMY", 0) .Num(1) .PushSig(keys.key0) .PushSig(keys.key1) .PushSig(keys.key2) .DamagePush(10)); tests.push_back( TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG << OP_NOT, "3-of-3 NOT with invalid sig with nonzero dummy", SCRIPT_VERIFY_NULLDUMMY) .Num(1) .PushSig(keys.key0) .PushSig(keys.key1) .PushSig(keys.key2) .DamagePush(10) .ScriptError(SCRIPT_ERR_SIG_NULLDUMMY)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG, "2-of-2 with two identical keys and sigs " "pushed using OP_DUP but no SIGPUSHONLY", 0) .Num(0) .PushSig(keys.key1) .Add(CScript() << OP_DUP)); tests.push_back( TestBuilder( CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG, "2-of-2 with two identical keys and sigs pushed using OP_DUP", SCRIPT_VERIFY_SIGPUSHONLY) .Num(0) .PushSig(keys.key1) .Add(CScript() << OP_DUP) .ScriptError(SCRIPT_ERR_SIG_PUSHONLY)); tests.push_back( TestBuilder( CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, "P2SH(P2PK) with non-push scriptSig but no P2SH or SIGPUSHONLY", 0, true) .PushSig(keys.key2) .Add(CScript() << OP_NOP8) .PushRedeem()); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, "P2PK with non-push scriptSig but with P2SH validation", 0) .PushSig(keys.key2) .Add(CScript() << OP_NOP8)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, "P2SH(P2PK) with non-push scriptSig but no SIGPUSHONLY", SCRIPT_VERIFY_P2SH, true) .PushSig(keys.key2) .Add(CScript() << OP_NOP8) .PushRedeem() .ScriptError(SCRIPT_ERR_SIG_PUSHONLY)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, "P2SH(P2PK) with non-push scriptSig but not P2SH", SCRIPT_VERIFY_SIGPUSHONLY, true) .PushSig(keys.key2) .Add(CScript() << OP_NOP8) .PushRedeem() .ScriptError(SCRIPT_ERR_SIG_PUSHONLY)); tests.push_back( TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG, "2-of-2 with two identical keys and sigs pushed", SCRIPT_VERIFY_SIGPUSHONLY) .Num(0) .PushSig(keys.key1) .PushSig(keys.key1)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2PK with unnecessary input but no CLEANSTACK", SCRIPT_VERIFY_P2SH) .Num(11) .PushSig(keys.key0)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2PK with unnecessary input", SCRIPT_VERIFY_CLEANSTACK | SCRIPT_VERIFY_P2SH) .Num(11) .PushSig(keys.key0) .ScriptError(SCRIPT_ERR_CLEANSTACK)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2SH with unnecessary input but no CLEANSTACK", SCRIPT_VERIFY_P2SH, true) .Num(11) .PushSig(keys.key0) .PushRedeem()); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2SH with unnecessary input", SCRIPT_VERIFY_CLEANSTACK | SCRIPT_VERIFY_P2SH, true) .Num(11) .PushSig(keys.key0) .PushRedeem() .ScriptError(SCRIPT_ERR_CLEANSTACK)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2SH with CLEANSTACK", SCRIPT_VERIFY_CLEANSTACK | SCRIPT_VERIFY_P2SH, true) .PushSig(keys.key0) .PushRedeem()); static const Amount TEST_AMOUNT(12345000000000); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2PK FORKID", SCRIPT_ENABLE_SIGHASH_FORKID, false, TEST_AMOUNT) .PushSig(keys.key0, SigHashType().withForkId(), 32, 32, TEST_AMOUNT)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2PK INVALID AMOUNT", SCRIPT_ENABLE_SIGHASH_FORKID, false, TEST_AMOUNT) .PushSig(keys.key0, SigHashType().withForkId(), 32, 32, TEST_AMOUNT + Amount(1)) .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2PK INVALID FORKID", SCRIPT_VERIFY_STRICTENC, false, TEST_AMOUNT) .PushSig(keys.key0, SigHashType().withForkId(), 32, 32, TEST_AMOUNT) .ScriptError(SCRIPT_ERR_ILLEGAL_FORKID)); // Test replay protection tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2PK REPLAY PROTECTED", SCRIPT_ENABLE_SIGHASH_FORKID | SCRIPT_ENABLE_REPLAY_PROTECTION, false, TEST_AMOUNT) .PushSig(keys.key0, SigHashType().withForkId(), 32, 32, TEST_AMOUNT, SCRIPT_ENABLE_SIGHASH_FORKID | SCRIPT_ENABLE_REPLAY_PROTECTION)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2PK REPLAY PROTECTED", SCRIPT_ENABLE_SIGHASH_FORKID | SCRIPT_ENABLE_REPLAY_PROTECTION, false, TEST_AMOUNT) .PushSig(keys.key0, SigHashType().withForkId(), 32, 32, TEST_AMOUNT, SCRIPT_ENABLE_SIGHASH_FORKID) .ScriptError(SCRIPT_ERR_EVAL_FALSE)); std::set tests_set; { UniValue json_tests = read_json(std::string( json_tests::script_tests, json_tests::script_tests + sizeof(json_tests::script_tests))); for (unsigned int idx = 0; idx < json_tests.size(); idx++) { const UniValue &tv = json_tests[idx]; tests_set.insert(JSONPrettyPrint(tv.get_array())); } } std::string strGen; for (TestBuilder &test : tests) { test.Test(); std::string str = JSONPrettyPrint(test.GetJSON()); #ifndef UPDATE_JSON_TESTS if (tests_set.count(str) == 0) { BOOST_CHECK_MESSAGE( false, "Missing auto script_valid test: " + test.GetComment()); } #endif strGen += str + ",\n"; } #ifdef UPDATE_JSON_TESTS FILE *file = fopen("script_tests.json.gen", "w"); fputs(strGen.c_str(), file); fclose(file); #endif } BOOST_AUTO_TEST_CASE(script_json_test) { // Read tests from test/data/script_tests.json // Format is an array of arrays // Inner arrays are [ ["wit"..., nValue]?, "scriptSig", "scriptPubKey", // "flags", "expected_scripterror" ] // ... where scriptSig and scriptPubKey are stringified // scripts. UniValue tests = read_json(std::string( json_tests::script_tests, json_tests::script_tests + sizeof(json_tests::script_tests))); for (unsigned int idx = 0; idx < tests.size(); idx++) { UniValue test = tests[idx]; std::string strTest = test.write(); Amount nValue(0); unsigned int pos = 0; if (test.size() > 0 && test[pos].isArray()) { nValue = AmountFromValue(test[pos][0]); pos++; } // Allow size > 3; extra stuff ignored (useful for comments) if (test.size() < 4 + pos) { if (test.size() != 1) { BOOST_ERROR("Bad test: " << strTest); } continue; } std::string scriptSigString = test[pos++].get_str(); std::string scriptPubKeyString = test[pos++].get_str(); try { CScript scriptSig = ParseScript(scriptSigString); CScript scriptPubKey = ParseScript(scriptPubKeyString); unsigned int scriptflags = ParseScriptFlags(test[pos++].get_str()); int scriptError = ParseScriptError(test[pos++].get_str()); DoTest(scriptPubKey, scriptSig, scriptflags, strTest, scriptError, nValue); } catch (std::runtime_error &e) { BOOST_TEST_MESSAGE("Script test failed. scriptSig: " << scriptSigString << " scriptPubKey: " << scriptPubKeyString); BOOST_TEST_MESSAGE("Exception: " << e.what()); throw; } } } BOOST_AUTO_TEST_CASE(script_PushData) { // Check that PUSHDATA1, PUSHDATA2, and PUSHDATA4 create the same value on // the stack as the 1-75 opcodes do. static const uint8_t direct[] = {1, 0x5a}; static const uint8_t pushdata1[] = {OP_PUSHDATA1, 1, 0x5a}; static const uint8_t pushdata2[] = {OP_PUSHDATA2, 1, 0, 0x5a}; static const uint8_t pushdata4[] = {OP_PUSHDATA4, 1, 0, 0, 0, 0x5a}; ScriptError err; std::vector> directStack; BOOST_CHECK(EvalScript(directStack, CScript(&direct[0], &direct[sizeof(direct)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); std::vector> pushdata1Stack; BOOST_CHECK(EvalScript( pushdata1Stack, CScript(&pushdata1[0], &pushdata1[sizeof(pushdata1)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), &err)); BOOST_CHECK(pushdata1Stack == directStack); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); std::vector> pushdata2Stack; BOOST_CHECK(EvalScript( pushdata2Stack, CScript(&pushdata2[0], &pushdata2[sizeof(pushdata2)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), &err)); BOOST_CHECK(pushdata2Stack == directStack); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); std::vector> pushdata4Stack; BOOST_CHECK(EvalScript( pushdata4Stack, CScript(&pushdata4[0], &pushdata4[sizeof(pushdata4)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), &err)); BOOST_CHECK(pushdata4Stack == directStack); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); } CScript sign_multisig(CScript scriptPubKey, std::vector keys, CTransaction transaction) { uint256 hash = SignatureHash(scriptPubKey, transaction, 0, SigHashType(), Amount(0)); CScript result; // // NOTE: CHECKMULTISIG has an unfortunate bug; it requires one extra item on // the stack, before the signatures. Putting OP_0 on the stack is the // workaround; fixing the bug would mean splitting the block chain (old // clients would not accept new CHECKMULTISIG transactions, and vice-versa) // result << OP_0; for (const CKey &key : keys) { std::vector vchSig; BOOST_CHECK(key.Sign(hash, vchSig)); vchSig.push_back(uint8_t(SIGHASH_ALL)); result << vchSig; } return result; } CScript sign_multisig(CScript scriptPubKey, const CKey &key, CTransaction transaction) { std::vector keys; keys.push_back(key); return sign_multisig(scriptPubKey, keys, transaction); } BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12) { ScriptError err; CKey key1, key2, key3; key1.MakeNewKey(true); key2.MakeNewKey(false); key3.MakeNewKey(true); CScript scriptPubKey12; scriptPubKey12 << OP_1 << ToByteVector(key1.GetPubKey()) << ToByteVector(key2.GetPubKey()) << OP_2 << OP_CHECKMULTISIG; CMutableTransaction txFrom12 = BuildCreditingTransaction(scriptPubKey12, Amount(0)); CMutableTransaction txTo12 = BuildSpendingTransaction(CScript(), txFrom12); CScript goodsig1 = sign_multisig(scriptPubKey12, key1, CTransaction(txTo12)); BOOST_CHECK(VerifyScript( goodsig1, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); txTo12.vout[0].nValue = Amount(2); BOOST_CHECK(!VerifyScript( goodsig1, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); CScript goodsig2 = sign_multisig(scriptPubKey12, key2, CTransaction(txTo12)); BOOST_CHECK(VerifyScript( goodsig2, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); CScript badsig1 = sign_multisig(scriptPubKey12, key3, CTransaction(txTo12)); BOOST_CHECK(!VerifyScript( badsig1, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); } BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23) { ScriptError err; CKey key1, key2, key3, key4; key1.MakeNewKey(true); key2.MakeNewKey(false); key3.MakeNewKey(true); key4.MakeNewKey(false); CScript scriptPubKey23; scriptPubKey23 << OP_2 << ToByteVector(key1.GetPubKey()) << ToByteVector(key2.GetPubKey()) << ToByteVector(key3.GetPubKey()) << OP_3 << OP_CHECKMULTISIG; CMutableTransaction txFrom23 = BuildCreditingTransaction(scriptPubKey23, Amount(0)); CMutableTransaction mutableTxTo23 = BuildSpendingTransaction(CScript(), txFrom23); // after it has been set up, mutableTxTo23 does not change in this test, // so we can convert it to readonly transaction and use // TransactionSignatureChecker // instead of MutableTransactionSignatureChecker const CTransaction txTo23(mutableTxTo23); std::vector keys; keys.push_back(key1); keys.push_back(key2); CScript goodsig1 = sign_multisig(scriptPubKey23, keys, txTo23); BOOST_CHECK(VerifyScript( goodsig1, scriptPubKey23, flags, TransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); keys.clear(); keys.push_back(key1); keys.push_back(key3); CScript goodsig2 = sign_multisig(scriptPubKey23, keys, txTo23); BOOST_CHECK(VerifyScript( goodsig2, scriptPubKey23, flags, TransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); keys.clear(); keys.push_back(key2); keys.push_back(key3); CScript goodsig3 = sign_multisig(scriptPubKey23, keys, txTo23); BOOST_CHECK(VerifyScript( goodsig3, scriptPubKey23, flags, TransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); keys.clear(); keys.push_back(key2); keys.push_back(key2); // Can't re-use sig CScript badsig1 = sign_multisig(scriptPubKey23, keys, txTo23); BOOST_CHECK(!VerifyScript( badsig1, scriptPubKey23, flags, TransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); keys.push_back(key2); keys.push_back(key1); // sigs must be in correct order CScript badsig2 = sign_multisig(scriptPubKey23, keys, txTo23); BOOST_CHECK(!VerifyScript( badsig2, scriptPubKey23, flags, TransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); keys.push_back(key3); keys.push_back(key2); // sigs must be in correct order CScript badsig3 = sign_multisig(scriptPubKey23, keys, txTo23); BOOST_CHECK(!VerifyScript( badsig3, scriptPubKey23, flags, TransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); keys.push_back(key4); keys.push_back(key2); // sigs must match pubkeys CScript badsig4 = sign_multisig(scriptPubKey23, keys, txTo23); BOOST_CHECK(!VerifyScript( badsig4, scriptPubKey23, flags, TransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); keys.push_back(key1); keys.push_back(key4); // sigs must match pubkeys CScript badsig5 = sign_multisig(scriptPubKey23, keys, txTo23); BOOST_CHECK(!VerifyScript( badsig5, scriptPubKey23, flags, TransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); // Must have signatures CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23); BOOST_CHECK(!VerifyScript( badsig6, scriptPubKey23, flags, TransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err)); } BOOST_AUTO_TEST_CASE(script_combineSigs) { // Test the CombineSignatures function Amount amount(0); CBasicKeyStore keystore; std::vector keys; std::vector pubkeys; for (int i = 0; i < 3; i++) { CKey key; key.MakeNewKey(i % 2 == 1); keys.push_back(key); pubkeys.push_back(key.GetPubKey()); keystore.AddKey(key); } CMutableTransaction txFrom = BuildCreditingTransaction( GetScriptForDestination(keys[0].GetPubKey().GetID()), Amount(0)); CMutableTransaction txTo = BuildSpendingTransaction(CScript(), txFrom); CScript &scriptPubKey = txFrom.vout[0].scriptPubKey; CScript &scriptSig = txTo.vin[0].scriptSig; // Although it looks like CMutableTransaction is not modified after it’s // been set up (it is not passed as parameter to any non-const function), // it is actually modified when new value is assigned to scriptPubKey, // which points to mutableTxFrom.vout[0].scriptPubKey. Therefore we can // not use single instance of CTransaction in this test. // CTransaction creates a copy of CMutableTransaction and is not modified // when scriptPubKey is assigned to. SignatureData empty; SignatureData combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, empty); BOOST_CHECK(combined.scriptSig.empty()); // Single signature case: SignSignature(keystore, CTransaction(txFrom), txTo, 0, SigHashType()); // changes scriptSig combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty); BOOST_CHECK(combined.scriptSig == scriptSig); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig)); BOOST_CHECK(combined.scriptSig == scriptSig); CScript scriptSigCopy = scriptSig; // Signing again will give a different, valid signature: SignSignature(keystore, CTransaction(txFrom), txTo, 0, SigHashType()); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig)); BOOST_CHECK(combined.scriptSig == scriptSigCopy || combined.scriptSig == scriptSig); // P2SH, single-signature case: CScript pkSingle; pkSingle << ToByteVector(keys[0].GetPubKey()) << OP_CHECKSIG; keystore.AddCScript(pkSingle); scriptPubKey = GetScriptForDestination(CScriptID(pkSingle)); SignSignature(keystore, CTransaction(txFrom), txTo, 0, SigHashType()); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty); BOOST_CHECK(combined.scriptSig == scriptSig); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig)); BOOST_CHECK(combined.scriptSig == scriptSig); scriptSigCopy = scriptSig; SignSignature(keystore, CTransaction(txFrom), txTo, 0, SigHashType()); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig)); BOOST_CHECK(combined.scriptSig == scriptSigCopy || combined.scriptSig == scriptSig); // dummy scriptSigCopy with placeholder, should always choose // non-placeholder: scriptSigCopy = CScript() << OP_0 << std::vector(pkSingle.begin(), pkSingle.end()); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig)); BOOST_CHECK(combined.scriptSig == scriptSig); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), SignatureData(scriptSigCopy)); BOOST_CHECK(combined.scriptSig == scriptSig); // Hardest case: Multisig 2-of-3 scriptPubKey = GetScriptForMultisig(2, pubkeys); keystore.AddCScript(scriptPubKey); SignSignature(keystore, CTransaction(txFrom), txTo, 0, SigHashType()); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty); BOOST_CHECK(combined.scriptSig == scriptSig); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig)); BOOST_CHECK(combined.scriptSig == scriptSig); // A couple of partially-signed versions: std::vector sig1; uint256 hash1 = SignatureHash(scriptPubKey, CTransaction(txTo), 0, SigHashType(), Amount(0)); BOOST_CHECK(keys[0].Sign(hash1, sig1)); sig1.push_back(SIGHASH_ALL); std::vector sig2; uint256 hash2 = SignatureHash( scriptPubKey, CTransaction(txTo), 0, SigHashType().withBaseType(BaseSigHashType::NONE), Amount(0)); BOOST_CHECK(keys[1].Sign(hash2, sig2)); sig2.push_back(SIGHASH_NONE); std::vector sig3; uint256 hash3 = SignatureHash( scriptPubKey, CTransaction(txTo), 0, SigHashType().withBaseType(BaseSigHashType::SINGLE), Amount(0)); BOOST_CHECK(keys[2].Sign(hash3, sig3)); sig3.push_back(SIGHASH_SINGLE); // Not fussy about order (or even existence) of placeholders or signatures: CScript partial1a = CScript() << OP_0 << sig1 << OP_0; CScript partial1b = CScript() << OP_0 << OP_0 << sig1; CScript partial2a = CScript() << OP_0 << sig2; CScript partial2b = CScript() << sig2 << OP_0; CScript partial3a = CScript() << sig3; CScript partial3b = CScript() << OP_0 << OP_0 << sig3; CScript partial3c = CScript() << OP_0 << sig3 << OP_0; CScript complete12 = CScript() << OP_0 << sig1 << sig2; CScript complete13 = CScript() << OP_0 << sig1 << sig3; CScript complete23 = CScript() << OP_0 << sig2 << sig3; combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1a), SignatureData(partial1b)); BOOST_CHECK(combined.scriptSig == partial1a); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1a), SignatureData(partial2a)); BOOST_CHECK(combined.scriptSig == complete12); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial2a), SignatureData(partial1a)); BOOST_CHECK(combined.scriptSig == complete12); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1b), SignatureData(partial2b)); BOOST_CHECK(combined.scriptSig == complete12); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial1b)); BOOST_CHECK(combined.scriptSig == complete13); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial2a), SignatureData(partial3a)); BOOST_CHECK(combined.scriptSig == complete23); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial2b)); BOOST_CHECK(combined.scriptSig == complete23); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial3a)); BOOST_CHECK(combined.scriptSig == partial3c); } BOOST_AUTO_TEST_CASE(script_standard_push) { ScriptError err; for (int i = 0; i < 67000; i++) { CScript script; script << i; BOOST_CHECK_MESSAGE(script.IsPushOnly(), "Number " << i << " is not pure push."); BOOST_CHECK_MESSAGE(VerifyScript(script, CScript() << OP_1, SCRIPT_VERIFY_MINIMALDATA, BaseSignatureChecker(), &err), "Number " << i << " push is not minimal data."); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); } for (unsigned int i = 0; i <= MAX_SCRIPT_ELEMENT_SIZE; i++) { std::vector data(i, '\111'); CScript script; script << data; BOOST_CHECK_MESSAGE(script.IsPushOnly(), "Length " << i << " is not pure push."); BOOST_CHECK_MESSAGE(VerifyScript(script, CScript() << OP_1, SCRIPT_VERIFY_MINIMALDATA, BaseSignatureChecker(), &err), "Length " << i << " push is not minimal data."); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); } } BOOST_AUTO_TEST_CASE(script_IsPushOnly_on_invalid_scripts) { // IsPushOnly returns false when given a script containing only pushes that // are invalid due to truncation. IsPushOnly() is consensus critical because // P2SH evaluation uses it, although this specific behavior should not be // consensus critical as the P2SH evaluation would fail first due to the // invalid push. Still, it doesn't hurt to test it explicitly. static const uint8_t direct[] = {1}; BOOST_CHECK(!CScript(direct, direct + sizeof(direct)).IsPushOnly()); } BOOST_AUTO_TEST_CASE(script_GetScriptAsm) { BOOST_CHECK_EQUAL("OP_CHECKLOCKTIMEVERIFY", ScriptToAsmStr(CScript() << OP_NOP2, true)); BOOST_CHECK_EQUAL( "OP_CHECKLOCKTIMEVERIFY", ScriptToAsmStr(CScript() << OP_CHECKLOCKTIMEVERIFY, true)); BOOST_CHECK_EQUAL("OP_CHECKLOCKTIMEVERIFY", ScriptToAsmStr(CScript() << OP_NOP2)); BOOST_CHECK_EQUAL("OP_CHECKLOCKTIMEVERIFY", ScriptToAsmStr(CScript() << OP_CHECKLOCKTIMEVERIFY)); std::string derSig("304502207fa7a6d1e0ee81132a269ad84e68d695483745cde8b541e" "3bf630749894e342a022100c1f7ab20e13e22fb95281a870f3dcf38" "d782e53023ee313d741ad0cfbc0c5090"); std::string pubKey( "03b0da749730dc9b4b1f4a14d6902877a92541f5368778853d9c4a0cb7802dcfb2"); std::vector vchPubKey = ToByteVector(ParseHex(pubKey)); BOOST_CHECK_EQUAL( derSig + "00 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "00")) << vchPubKey, true)); BOOST_CHECK_EQUAL( derSig + "80 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "80")) << vchPubKey, true)); BOOST_CHECK_EQUAL( derSig + "[ALL] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "01")) << vchPubKey, true)); BOOST_CHECK_EQUAL( derSig + "[ALL|ANYONECANPAY] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "81")) << vchPubKey, true)); BOOST_CHECK_EQUAL( derSig + "[ALL|FORKID] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "41")) << vchPubKey, true)); BOOST_CHECK_EQUAL( derSig + "[ALL|FORKID|ANYONECANPAY] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "c1")) << vchPubKey, true)); BOOST_CHECK_EQUAL( derSig + "[NONE] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "02")) << vchPubKey, true)); BOOST_CHECK_EQUAL( derSig + "[NONE|ANYONECANPAY] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "82")) << vchPubKey, true)); BOOST_CHECK_EQUAL( derSig + "[NONE|FORKID] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "42")) << vchPubKey, true)); BOOST_CHECK_EQUAL( derSig + "[NONE|FORKID|ANYONECANPAY] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "c2")) << vchPubKey, true)); BOOST_CHECK_EQUAL( derSig + "[SINGLE] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "03")) << vchPubKey, true)); BOOST_CHECK_EQUAL( derSig + "[SINGLE|ANYONECANPAY] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "83")) << vchPubKey, true)); BOOST_CHECK_EQUAL( derSig + "[SINGLE|FORKID] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "43")) << vchPubKey, true)); BOOST_CHECK_EQUAL( derSig + "[SINGLE|FORKID|ANYONECANPAY] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "c3")) << vchPubKey, true)); BOOST_CHECK_EQUAL(derSig + "00 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "00")) << vchPubKey)); BOOST_CHECK_EQUAL(derSig + "80 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "80")) << vchPubKey)); BOOST_CHECK_EQUAL(derSig + "01 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "01")) << vchPubKey)); BOOST_CHECK_EQUAL(derSig + "02 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "02")) << vchPubKey)); BOOST_CHECK_EQUAL(derSig + "03 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "03")) << vchPubKey)); BOOST_CHECK_EQUAL(derSig + "81 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "81")) << vchPubKey)); BOOST_CHECK_EQUAL(derSig + "82 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "82")) << vchPubKey)); BOOST_CHECK_EQUAL(derSig + "83 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "83")) << vchPubKey)); } static CScript ScriptFromHex(const char *hex) { std::vector data = ParseHex(hex); return CScript(data.begin(), data.end()); } BOOST_AUTO_TEST_CASE(script_FindAndDelete) { // Exercise the FindAndDelete functionality CScript s; CScript d; CScript expect; s = CScript() << OP_1 << OP_2; // delete nothing should be a no-op d = CScript(); expect = s; BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0); BOOST_CHECK(s == expect); s = CScript() << OP_1 << OP_2 << OP_3; d = CScript() << OP_2; expect = CScript() << OP_1 << OP_3; BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1); BOOST_CHECK(s == expect); s = CScript() << OP_3 << OP_1 << OP_3 << OP_3 << OP_4 << OP_3; d = CScript() << OP_3; expect = CScript() << OP_1 << OP_4; BOOST_CHECK_EQUAL(s.FindAndDelete(d), 4); BOOST_CHECK(s == expect); // PUSH 0x02ff03 onto stack s = ScriptFromHex("0302ff03"); d = ScriptFromHex("0302ff03"); expect = CScript(); BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1); BOOST_CHECK(s == expect); // PUSH 0x2ff03 PUSH 0x2ff03 s = ScriptFromHex("0302ff030302ff03"); d = ScriptFromHex("0302ff03"); expect = CScript(); BOOST_CHECK_EQUAL(s.FindAndDelete(d), 2); BOOST_CHECK(s == expect); s = ScriptFromHex("0302ff030302ff03"); d = ScriptFromHex("02"); expect = s; // FindAndDelete matches entire opcodes BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0); BOOST_CHECK(s == expect); s = ScriptFromHex("0302ff030302ff03"); d = ScriptFromHex("ff"); expect = s; BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0); BOOST_CHECK(s == expect); // This is an odd edge case: strip of the push-three-bytes prefix, leaving // 02ff03 which is push-two-bytes: s = ScriptFromHex("0302ff030302ff03"); d = ScriptFromHex("03"); expect = CScript() << ParseHex("ff03") << ParseHex("ff03"); BOOST_CHECK_EQUAL(s.FindAndDelete(d), 2); BOOST_CHECK(s == expect); // Byte sequence that spans multiple opcodes: // PUSH(0xfeed) OP_1 OP_VERIFY s = ScriptFromHex("02feed5169"); d = ScriptFromHex("feed51"); expect = s; // doesn't match 'inside' opcodes BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0); BOOST_CHECK(s == expect); // PUSH(0xfeed) OP_1 OP_VERIFY s = ScriptFromHex("02feed5169"); d = ScriptFromHex("02feed51"); expect = ScriptFromHex("69"); BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1); BOOST_CHECK(s == expect); s = ScriptFromHex("516902feed5169"); d = ScriptFromHex("feed51"); expect = s; BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0); BOOST_CHECK(s == expect); s = ScriptFromHex("516902feed5169"); d = ScriptFromHex("02feed51"); expect = ScriptFromHex("516969"); BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1); BOOST_CHECK(s == expect); s = CScript() << OP_0 << OP_0 << OP_1 << OP_1; d = CScript() << OP_0 << OP_1; // FindAndDelete is single-pass expect = CScript() << OP_0 << OP_1; BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1); BOOST_CHECK(s == expect); s = CScript() << OP_0 << OP_0 << OP_1 << OP_0 << OP_1 << OP_1; d = CScript() << OP_0 << OP_1; // FindAndDelete is single-pass expect = CScript() << OP_0 << OP_1; BOOST_CHECK_EQUAL(s.FindAndDelete(d), 2); BOOST_CHECK(s == expect); // Another weird edge case: // End with invalid push (not enough data)... s = ScriptFromHex("0003feed"); // ... can remove the invalid push d = ScriptFromHex("03feed"); expect = ScriptFromHex("00"); BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1); BOOST_CHECK(s == expect); s = ScriptFromHex("0003feed"); d = ScriptFromHex("00"); expect = ScriptFromHex("03feed"); BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1); BOOST_CHECK(s == expect); } BOOST_AUTO_TEST_SUITE_END()