aboutsummaryrefslogtreecommitdiff
path: root/src/test
diff options
context:
space:
mode:
authorGavin Andresen <gavinandresen@gmail.com>2011-09-28 12:30:06 -0400
committerGavin Andresen <gavinandresen@gmail.com>2011-12-19 12:40:19 -0500
commitbf798734db4539a39edd6badf54a1c3aecf193e5 (patch)
tree850f60c149335de2c85c0aafd10a8fc50aca9c7e /src/test
parent1466b8b78ad8cabf93ac3f65f5929213c5dd3c8f (diff)
Support 3 new multisignature IsStandard transactions
Initial support for (a and b), (a or b), and 2-of-3 escrow transactions (where a, b, and c are keys).
Diffstat (limited to 'src/test')
-rw-r--r--src/test/multisig_tests.cpp288
1 files changed, 288 insertions, 0 deletions
diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp
new file mode 100644
index 0000000000..459d112369
--- /dev/null
+++ b/src/test/multisig_tests.cpp
@@ -0,0 +1,288 @@
+#include <boost/assert.hpp>
+#include <boost/assign/list_of.hpp>
+#include <boost/assign/list_inserter.hpp>
+#include <boost/assign/std/vector.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/foreach.hpp>
+#include <boost/tuple/tuple.hpp>
+
+#include <openssl/ec.h>
+#include <openssl/err.h>
+
+#include "keystore.h"
+#include "main.h"
+#include "script.h"
+#include "wallet.h"
+
+using namespace std;
+using namespace boost::assign;
+
+typedef vector<unsigned char> valtype;
+
+extern uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
+extern bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, int nHashType);
+extern bool VerifySignature(const CTransaction& txFrom, const CTransaction& txTo, unsigned int nIn, int nHashType);
+extern bool Solver(const CScript& scriptPubKey, vector<vector<pair<opcodetype, valtype> > >& vSolutionsRet);
+
+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(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)
+{
+ CKey key[4];
+ for (int i = 0; i < 4; i++)
+ key[i].MakeNewKey();
+
+ 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;
+
+ CTransaction 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;
+
+ CTransaction 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, 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, 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, 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, 0), strprintf("a|b: %d", i));
+ else
+ BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, txTo[1], 0, 0), strprintf("a|b: %d", i));
+ }
+ s.clear();
+ s << OP_0 << OP_0;
+ BOOST_CHECK(!VerifyScript(s, a_or_b, txTo[1], 0, 0));
+ s.clear();
+ s << OP_0 << OP_1;
+ BOOST_CHECK(!VerifyScript(s, a_or_b, txTo[1], 0, 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, 0), strprintf("escrow 1: %d %d", i, j));
+ else
+ BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, txTo[2], 0, 0), strprintf("escrow 2: %d %d", i, j));
+ }
+}
+
+BOOST_AUTO_TEST_CASE(multisig_IsStandard)
+{
+ CKey key[3];
+ for (int i = 0; i < 3; i++)
+ key[i].MakeNewKey();
+
+ 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));
+
+ 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));
+
+ CScript escrow;
+ escrow << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << OP_3 << OP_CHECKMULTISIG;
+ BOOST_CHECK(::IsStandard(escrow));
+}
+
+BOOST_AUTO_TEST_CASE(multisig_Solver1)
+{
+ // Tests Solver() that returns lists of keys that are
+ // required to satisfy a ScriptPubKey
+ //
+ // Also tests IsMine() and ExtractAddress()
+ //
+ // Note: ExtractAddress for the multisignature transactions
+ // always returns false for this release, even if you have
+ // one key that would satisfy an (a|b) or 2-of-3 keys needed
+ // to spend an escrow transaction.
+ //
+ CBasicKeyStore keystore, emptykeystore;
+ CKey key[3];
+ CBitcoinAddress keyaddr[3];
+ for (int i = 0; i < 3; i++)
+ {
+ key[i].MakeNewKey();
+ keystore.AddKey(key[i]);
+ keyaddr[i].SetPubKey(key[i].GetPubKey());
+ }
+
+ {
+ vector<vector<pair<opcodetype, valtype> > > solutions;
+ CScript s;
+ s << key[0].GetPubKey() << OP_CHECKSIG;
+ BOOST_CHECK(Solver(s, solutions));
+ BOOST_CHECK(solutions.size() == 1);
+ if (solutions.size() == 1)
+ BOOST_CHECK(solutions[0].size() == 1);
+ CBitcoinAddress addr;
+ BOOST_CHECK(ExtractAddress(s, &keystore, addr));
+ BOOST_CHECK(addr == keyaddr[0]);
+ BOOST_CHECK(IsMine(keystore, s));
+ BOOST_CHECK(!IsMine(emptykeystore, s));
+ }
+ {
+ vector<vector<pair<opcodetype, valtype> > > solutions;
+ CScript s;
+ s << OP_DUP << OP_HASH160 << Hash160(key[0].GetPubKey()) << OP_EQUALVERIFY << OP_CHECKSIG;
+ BOOST_CHECK(Solver(s, solutions));
+ BOOST_CHECK(solutions.size() == 1);
+ if (solutions.size() == 1)
+ BOOST_CHECK(solutions[0].size() == 1);
+ CBitcoinAddress addr;
+ BOOST_CHECK(ExtractAddress(s, &keystore, addr));
+ BOOST_CHECK(addr == keyaddr[0]);
+ BOOST_CHECK(IsMine(keystore, s));
+ BOOST_CHECK(!IsMine(emptykeystore, s));
+ }
+ {
+ vector<vector<pair<opcodetype, valtype> > > solutions;
+ CScript s;
+ s << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;
+ BOOST_CHECK(Solver(s, solutions));
+ BOOST_CHECK(solutions.size() == 1);
+ if (solutions.size() == 1)
+ BOOST_CHECK(solutions[0].size() == 2);
+ CBitcoinAddress addr;
+ BOOST_CHECK(!ExtractAddress(s, &keystore, addr));
+ BOOST_CHECK(IsMine(keystore, s));
+ BOOST_CHECK(!IsMine(emptykeystore, s));
+ }
+ {
+ vector<vector<pair<opcodetype, valtype> > > solutions;
+ CScript s;
+ s << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;
+ BOOST_CHECK(Solver(s, solutions));
+ BOOST_CHECK(solutions.size() == 2);
+ if (solutions.size() == 2)
+ {
+ BOOST_CHECK(solutions[0].size() == 1);
+ BOOST_CHECK(solutions[1].size() == 1);
+ }
+ CBitcoinAddress addr;
+ BOOST_CHECK(ExtractAddress(s, &keystore, addr));
+ BOOST_CHECK(addr == keyaddr[0]);
+ BOOST_CHECK(IsMine(keystore, s));
+ BOOST_CHECK(!IsMine(emptykeystore, s));
+ }
+ {
+ vector<vector<pair<opcodetype, valtype> > > solutions;
+ CScript s;
+ s << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << OP_3 << OP_CHECKMULTISIG;
+ BOOST_CHECK(Solver(s, solutions));
+ BOOST_CHECK(solutions.size() == 3);
+ if (solutions.size() == 3)
+ {
+ BOOST_CHECK(solutions[0].size() == 2);
+ BOOST_CHECK(solutions[1].size() == 2);
+ BOOST_CHECK(solutions[2].size() == 2);
+ }
+ }
+}
+
+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();
+ 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;
+
+ CTransaction 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;
+
+ CTransaction 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()