|
|
|
@ -1161,10 +1161,19 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23)
|
|
|
|
|
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Wrapper around ProduceSignature to combine two scriptsigs */
|
|
|
|
|
SignatureData CombineSignatures(const CTxOut& txout, const CMutableTransaction& tx, const SignatureData& scriptSig1, const SignatureData& scriptSig2)
|
|
|
|
|
{
|
|
|
|
|
SignatureData data;
|
|
|
|
|
data.MergeSignatureData(scriptSig1);
|
|
|
|
|
data.MergeSignatureData(scriptSig2);
|
|
|
|
|
ProduceSignature(DUMMY_SIGNING_PROVIDER, MutableTransactionSignatureCreator(&tx, 0, txout.nValue), txout.scriptPubKey, data);
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(script_combineSigs)
|
|
|
|
|
{
|
|
|
|
|
// Test the CombineSignatures function
|
|
|
|
|
CAmount amount = 0;
|
|
|
|
|
// Test the ProduceSignature's ability to combine signatures function
|
|
|
|
|
CBasicKeyStore keystore;
|
|
|
|
|
std::vector<CKey> keys;
|
|
|
|
|
std::vector<CPubKey> pubkeys;
|
|
|
|
@ -1180,52 +1189,51 @@ BOOST_AUTO_TEST_CASE(script_combineSigs)
|
|
|
|
|
CMutableTransaction txFrom = BuildCreditingTransaction(GetScriptForDestination(keys[0].GetPubKey().GetID()));
|
|
|
|
|
CMutableTransaction txTo = BuildSpendingTransaction(CScript(), CScriptWitness(), txFrom);
|
|
|
|
|
CScript& scriptPubKey = txFrom.vout[0].scriptPubKey;
|
|
|
|
|
CScript& scriptSig = txTo.vin[0].scriptSig;
|
|
|
|
|
SignatureData scriptSig;
|
|
|
|
|
|
|
|
|
|
SignatureData empty;
|
|
|
|
|
SignatureData combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, empty);
|
|
|
|
|
SignatureData combined = CombineSignatures(txFrom.vout[0], txTo, empty, empty);
|
|
|
|
|
BOOST_CHECK(combined.scriptSig.empty());
|
|
|
|
|
|
|
|
|
|
// Single signature case:
|
|
|
|
|
SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL); // 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;
|
|
|
|
|
scriptSig = DataFromTransaction(txTo, 0, txFrom.vout[0]);
|
|
|
|
|
combined = CombineSignatures(txFrom.vout[0], txTo, scriptSig, empty);
|
|
|
|
|
BOOST_CHECK(combined.scriptSig == scriptSig.scriptSig);
|
|
|
|
|
combined = CombineSignatures(txFrom.vout[0], txTo, empty, scriptSig);
|
|
|
|
|
BOOST_CHECK(combined.scriptSig == scriptSig.scriptSig);
|
|
|
|
|
SignatureData scriptSigCopy = scriptSig;
|
|
|
|
|
// Signing again will give a different, valid signature:
|
|
|
|
|
SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL);
|
|
|
|
|
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig));
|
|
|
|
|
BOOST_CHECK(combined.scriptSig == scriptSigCopy || combined.scriptSig == scriptSig);
|
|
|
|
|
scriptSig = DataFromTransaction(txTo, 0, txFrom.vout[0]);
|
|
|
|
|
combined = CombineSignatures(txFrom.vout[0], txTo, scriptSigCopy, scriptSig);
|
|
|
|
|
BOOST_CHECK(combined.scriptSig == scriptSigCopy.scriptSig || combined.scriptSig == scriptSig.scriptSig);
|
|
|
|
|
|
|
|
|
|
// P2SH, single-signature case:
|
|
|
|
|
CScript pkSingle; pkSingle << ToByteVector(keys[0].GetPubKey()) << OP_CHECKSIG;
|
|
|
|
|
keystore.AddCScript(pkSingle);
|
|
|
|
|
scriptPubKey = GetScriptForDestination(CScriptID(pkSingle));
|
|
|
|
|
SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL);
|
|
|
|
|
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);
|
|
|
|
|
scriptSig = DataFromTransaction(txTo, 0, txFrom.vout[0]);
|
|
|
|
|
combined = CombineSignatures(txFrom.vout[0], txTo, scriptSig, empty);
|
|
|
|
|
BOOST_CHECK(combined.scriptSig == scriptSig.scriptSig);
|
|
|
|
|
combined = CombineSignatures(txFrom.vout[0], txTo, empty, scriptSig);
|
|
|
|
|
BOOST_CHECK(combined.scriptSig == scriptSig.scriptSig);
|
|
|
|
|
scriptSigCopy = scriptSig;
|
|
|
|
|
SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL);
|
|
|
|
|
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<unsigned char>(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);
|
|
|
|
|
scriptSig = DataFromTransaction(txTo, 0, txFrom.vout[0]);
|
|
|
|
|
combined = CombineSignatures(txFrom.vout[0], txTo, scriptSigCopy, scriptSig);
|
|
|
|
|
BOOST_CHECK(combined.scriptSig == scriptSigCopy.scriptSig || combined.scriptSig == scriptSig.scriptSig);
|
|
|
|
|
|
|
|
|
|
// Hardest case: Multisig 2-of-3
|
|
|
|
|
scriptPubKey = GetScriptForMultisig(2, pubkeys);
|
|
|
|
|
keystore.AddCScript(scriptPubKey);
|
|
|
|
|
SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL);
|
|
|
|
|
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);
|
|
|
|
|
scriptSig = DataFromTransaction(txTo, 0, txFrom.vout[0]);
|
|
|
|
|
combined = CombineSignatures(txFrom.vout[0], txTo, scriptSig, empty);
|
|
|
|
|
BOOST_CHECK(combined.scriptSig == scriptSig.scriptSig);
|
|
|
|
|
combined = CombineSignatures(txFrom.vout[0], txTo, empty, scriptSig);
|
|
|
|
|
BOOST_CHECK(combined.scriptSig == scriptSig.scriptSig);
|
|
|
|
|
|
|
|
|
|
// A couple of partially-signed versions:
|
|
|
|
|
std::vector<unsigned char> sig1;
|
|
|
|
@ -1252,22 +1260,28 @@ BOOST_AUTO_TEST_CASE(script_combineSigs)
|
|
|
|
|
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));
|
|
|
|
|
SignatureData partial1_sigs;
|
|
|
|
|
partial1_sigs.signatures.emplace(keys[0].GetPubKey().GetID(), SigPair(keys[0].GetPubKey(), sig1));
|
|
|
|
|
SignatureData partial2_sigs;
|
|
|
|
|
partial2_sigs.signatures.emplace(keys[1].GetPubKey().GetID(), SigPair(keys[1].GetPubKey(), sig2));
|
|
|
|
|
SignatureData partial3_sigs;
|
|
|
|
|
partial3_sigs.signatures.emplace(keys[2].GetPubKey().GetID(), SigPair(keys[2].GetPubKey(), sig3));
|
|
|
|
|
|
|
|
|
|
combined = CombineSignatures(txFrom.vout[0], txTo, partial1_sigs, partial1_sigs);
|
|
|
|
|
BOOST_CHECK(combined.scriptSig == partial1a);
|
|
|
|
|
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1a), SignatureData(partial2a));
|
|
|
|
|
combined = CombineSignatures(txFrom.vout[0], txTo, partial1_sigs, partial2_sigs);
|
|
|
|
|
BOOST_CHECK(combined.scriptSig == complete12);
|
|
|
|
|
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial2a), SignatureData(partial1a));
|
|
|
|
|
combined = CombineSignatures(txFrom.vout[0], txTo, partial2_sigs, partial1_sigs);
|
|
|
|
|
BOOST_CHECK(combined.scriptSig == complete12);
|
|
|
|
|
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1b), SignatureData(partial2b));
|
|
|
|
|
combined = CombineSignatures(txFrom.vout[0], txTo, partial1_sigs, partial2_sigs);
|
|
|
|
|
BOOST_CHECK(combined.scriptSig == complete12);
|
|
|
|
|
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial1b));
|
|
|
|
|
combined = CombineSignatures(txFrom.vout[0], txTo, partial3_sigs, partial1_sigs);
|
|
|
|
|
BOOST_CHECK(combined.scriptSig == complete13);
|
|
|
|
|
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial2a), SignatureData(partial3a));
|
|
|
|
|
combined = CombineSignatures(txFrom.vout[0], txTo, partial2_sigs, partial3_sigs);
|
|
|
|
|
BOOST_CHECK(combined.scriptSig == complete23);
|
|
|
|
|
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial2b));
|
|
|
|
|
combined = CombineSignatures(txFrom.vout[0], txTo, partial3_sigs, partial2_sigs);
|
|
|
|
|
BOOST_CHECK(combined.scriptSig == complete23);
|
|
|
|
|
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial3a));
|
|
|
|
|
combined = CombineSignatures(txFrom.vout[0], txTo, partial3_sigs, partial3_sigs);
|
|
|
|
|
BOOST_CHECK(combined.scriptSig == partial3c);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|