


// Copyright (c) 20112013 The Bitcoin Core developers




// Distributed under the MIT/X11 software license, see the accompanying




// file COPYING or http://www.opensource.org/licenses/mitlicense.php.








#include "key.h"




#include "keystore.h"




#include "main.h"




#include "scriptutils.h"




#include "uint256.h"








#include <boost/assign/std/vector.hpp>




#include <boost/foreach.hpp>




#include <boost/test/unit_test.hpp>








using namespace std;




using namespace boost::assign;








typedef vector<unsigned char> valtype;








BOOST_AUTO_TEST_SUITE(multisig_tests)








CScript




sign_multisig(CScript scriptPubKey, vector<CKey> keys, CTransaction transaction, int whichIn)




{




uint256 hash = SignatureHash(scriptPubKey, transaction, whichIn, SIGHASH_ALL);








CScript result;




result << OP_0; // CHECKMULTISIG bug workaround




BOOST_FOREACH(const CKey &key, keys)




{




vector<unsigned char> vchSig;




BOOST_CHECK(key.Sign(hash, vchSig));




vchSig.push_back((unsigned char)SIGHASH_ALL);




result << vchSig;




}




return result;




}








BOOST_AUTO_TEST_CASE(multisig_verify)




{




unsigned int flags = SCRIPT_VERIFY_P2SH  SCRIPT_VERIFY_STRICTENC;








CKey key[4];




for (int i = 0; i < 4; i++)




key[i].MakeNewKey(true);








CScript a_and_b;




a_and_b << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;








CScript a_or_b;




a_or_b << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;








CScript escrow;




escrow << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << OP_3 << OP_CHECKMULTISIG;








CMutableTransaction txFrom; // Funding transaction




txFrom.vout.resize(3);




txFrom.vout[0].scriptPubKey = a_and_b;




txFrom.vout[1].scriptPubKey = a_or_b;




txFrom.vout[2].scriptPubKey = escrow;








CMutableTransaction txTo[3]; // Spending transaction




for (int i = 0; i < 3; 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.GetHash();




txTo[i].vout[0].nValue = 1;




}








vector<CKey> keys;




CScript s;








// Test a AND b:




keys.clear();




keys += key[0],key[1]; // magic operator+= from boost.assign




s = sign_multisig(a_and_b, keys, txTo[0], 0);




BOOST_CHECK(VerifyScript(s, a_and_b, txTo[0], 0, flags, 0));








for (int i = 0; i < 4; i++)




{




keys.clear();




keys += key[i];




s = sign_multisig(a_and_b, keys, txTo[0], 0);




BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, txTo[0], 0, flags, 0), strprintf("a&b 1: %d", i));








keys.clear();




keys += key[1],key[i];




s = sign_multisig(a_and_b, keys, txTo[0], 0);




BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, txTo[0], 0, flags, 0), strprintf("a&b 2: %d", i));




}








// Test a OR b:




for (int i = 0; i < 4; i++)




{




keys.clear();




keys += key[i];




s = sign_multisig(a_or_b, keys, txTo[1], 0);




if (i == 0  i == 1)




BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, txTo[1], 0, flags, 0), strprintf("ab: %d", i));




else




BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, txTo[1], 0, flags, 0), strprintf("ab: %d", i));




}




s.clear();




s << OP_0 << OP_0;




BOOST_CHECK(!VerifyScript(s, a_or_b, txTo[1], 0, flags, 0));




s.clear();




s << OP_0 << OP_1;




BOOST_CHECK(!VerifyScript(s, a_or_b, txTo[1], 0, flags, 0));












for (int i = 0; i < 4; i++)




for (int j = 0; j < 4; j++)




{




keys.clear();




keys += key[i],key[j];




s = sign_multisig(escrow, keys, txTo[2], 0);




if (i < j && i < 3 && j < 3)




BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, txTo[2], 0, flags, 0), strprintf("escrow 1: %d %d", i, j));




else




BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, txTo[2], 0, flags, 0), strprintf("escrow 2: %d %d", i, j));




}




}








BOOST_AUTO_TEST_CASE(multisig_IsStandard)




{




CKey key[4];




for (int i = 0; i < 4; i++)




key[i].MakeNewKey(true);








txnouttype whichType;








CScript a_and_b;




a_and_b << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;




BOOST_CHECK(::IsStandard(a_and_b, whichType));








CScript a_or_b;




a_or_b << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;




BOOST_CHECK(::IsStandard(a_or_b, whichType));








CScript escrow;




escrow << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << OP_3 << OP_CHECKMULTISIG;




BOOST_CHECK(::IsStandard(escrow, whichType));








CScript one_of_four;




one_of_four << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << key[3].GetPubKey() << OP_4 << OP_CHECKMULTISIG;




BOOST_CHECK(!::IsStandard(one_of_four, whichType));








CScript malformed[6];




malformed[0] << OP_3 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;




malformed[1] << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_3 << OP_CHECKMULTISIG;




malformed[2] << OP_0 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;




malformed[3] << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_0 << OP_CHECKMULTISIG;




malformed[4] << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_CHECKMULTISIG;




malformed[5] << OP_1 << key[0].GetPubKey() << key[1].GetPubKey();








for (int i = 0; i < 6; i++)




BOOST_CHECK(!::IsStandard(malformed[i], whichType));




}








BOOST_AUTO_TEST_CASE(multisig_Solver1)




{




// Tests Solver() that returns lists of keys that are




// required to satisfy a ScriptPubKey




//




// Also tests IsMine() and ExtractDestination()




//




// Note: ExtractDestination for the multisignature transactions




// always returns false for this release, even if you have




// one key that would satisfy an (ab) or 2of3 keys needed




// to spend an escrow transaction.




//




CBasicKeyStore keystore, emptykeystore, partialkeystore;




CKey key[3];




CTxDestination keyaddr[3];




for (int i = 0; i < 3; i++)




{




key[i].MakeNewKey(true);




keystore.AddKey(key[i]);




keyaddr[i] = key[i].GetPubKey().GetID();




}




partialkeystore.AddKey(key[0]);








{




vector<valtype> solutions;




txnouttype whichType;




CScript s;




s << key[0].GetPubKey() << OP_CHECKSIG;




BOOST_CHECK(Solver(s, whichType, solutions));




BOOST_CHECK(solutions.size() == 1);




CTxDestination addr;




BOOST_CHECK(ExtractDestination(s, addr));




BOOST_CHECK(addr == keyaddr[0]);




BOOST_CHECK(IsMine(keystore, s));




BOOST_CHECK(!IsMine(emptykeystore, s));




}




{




vector<valtype> solutions;




txnouttype whichType;




CScript s;




s << OP_DUP << OP_HASH160 << key[0].GetPubKey().GetID() << OP_EQUALVERIFY << OP_CHECKSIG;




BOOST_CHECK(Solver(s, whichType, solutions));




BOOST_CHECK(solutions.size() == 1);




CTxDestination addr;




BOOST_CHECK(ExtractDestination(s, addr));




BOOST_CHECK(addr == keyaddr[0]);




BOOST_CHECK(IsMine(keystore, s));




BOOST_CHECK(!IsMine(emptykeystore, s));




}




{




vector<valtype> solutions;




txnouttype whichType;




CScript s;




s << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;




BOOST_CHECK(Solver(s, whichType, solutions));




BOOST_CHECK_EQUAL(solutions.size(), 4U);




CTxDestination addr;




BOOST_CHECK(!ExtractDestination(s, addr));




BOOST_CHECK(IsMine(keystore, s));




BOOST_CHECK(!IsMine(emptykeystore, s));




BOOST_CHECK(!IsMine(partialkeystore, s));




}




{




vector<valtype> solutions;




txnouttype whichType;




CScript s;




s << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;




BOOST_CHECK(Solver(s, whichType, solutions));




BOOST_CHECK_EQUAL(solutions.size(), 4U);




vector<CTxDestination> addrs;




int nRequired;




BOOST_CHECK(ExtractDestinations(s, whichType, addrs, nRequired));




BOOST_CHECK(addrs[0] == keyaddr[0]);




BOOST_CHECK(addrs[1] == keyaddr[1]);




BOOST_CHECK(nRequired == 1);




BOOST_CHECK(IsMine(keystore, s));




BOOST_CHECK(!IsMine(emptykeystore, s));




BOOST_CHECK(!IsMine(partialkeystore, s));




}




{




vector<valtype> solutions;




txnouttype whichType;




CScript s;




s << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << OP_3 << OP_CHECKMULTISIG;




BOOST_CHECK(Solver(s, whichType, solutions));




BOOST_CHECK(solutions.size() == 5);




}




}








BOOST_AUTO_TEST_CASE(multisig_Sign)




{




// 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]);




}








CScript a_and_b;




a_and_b << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;








CScript a_or_b;




a_or_b << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;








CScript escrow;




escrow << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << OP_3 << OP_CHECKMULTISIG;








CMutableTransaction txFrom; // Funding transaction




txFrom.vout.resize(3);




txFrom.vout[0].scriptPubKey = a_and_b;




txFrom.vout[1].scriptPubKey = a_or_b;




txFrom.vout[2].scriptPubKey = escrow;








CMutableTransaction txTo[3]; // Spending transaction




for (int i = 0; i < 3; 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.GetHash();




txTo[i].vout[0].nValue = 1;




}








for (int i = 0; i < 3; i++)




{




BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0), strprintf("SignSignature %d", i));




}




}












BOOST_AUTO_TEST_SUITE_END()
