Files

260 lines
10 KiB
C++
Raw Permalink Normal View History

2017-11-09 19:34:51 +01:00
/*
* This file is part of the Flowee project
* Copyright (C) 2011-2013 The Bitcoin Core developers
2021-01-20 19:21:53 +01:00
* Copyright (C) 2019-2021 Tom Zander <tom@flowee.org>
2017-11-09 19:34:51 +01:00
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "multisig_tests.h"
2021-01-20 18:22:34 +01:00
#include <common/MutableTransactionSignatureChecker.h>
#include <primitives/transaction.h>
#include "keystore.h"
2014-10-11 22:41:05 +00:00
#include "policy/policy.h"
2013-04-13 00:13:08 -05:00
#include <vector>
typedef std::vector<unsigned char> valtype;
2022-07-06 22:12:33 +02:00
CScript sign_multisig(CScript scriptPubKey, std::vector<PrivateKey> keys, const CTransaction &transaction, int whichIn)
{
uint256 hash = SignatureHash(scriptPubKey, transaction, whichIn, 0, SIGHASH_ALL);
CScript result;
result << OP_0; // CHECKMULTISIG bug workaround
2022-07-06 22:12:33 +02:00
for (const PrivateKey &key : keys) {
std::vector<unsigned char> vchSig;
2021-04-19 15:45:02 +02:00
const bool rc = key.signECDSA(hash, vchSig);
assert(rc);
vchSig.push_back((unsigned char)SIGHASH_ALL);
result << vchSig;
}
return result;
}
void MultiSigTests::multisig_verify()
{
2012-11-13 23:03:25 +01:00
unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC;
2022-07-06 22:12:33 +02:00
PrivateKey key[4];
2021-01-20 19:21:53 +01:00
int64_t amount = 0;
for (int i = 0; i < 4; i++)
2022-05-11 13:46:15 +02:00
key[i].makeNewKey(true);
CScript a_and_b;
2022-05-11 13:46:15 +02:00
a_and_b << OP_2 << ToByteVector(key[0].getPubKey()) << ToByteVector(key[1].getPubKey()) << OP_2 << OP_CHECKMULTISIG;
CScript a_or_b;
2022-05-11 13:46:15 +02:00
a_or_b << OP_1 << ToByteVector(key[0].getPubKey()) << ToByteVector(key[1].getPubKey()) << OP_2 << OP_CHECKMULTISIG;
CScript escrow;
2022-05-11 13:46:15 +02:00
escrow << OP_2 << ToByteVector(key[0].getPubKey()) << ToByteVector(key[1].getPubKey()) << ToByteVector(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;
}
2022-07-06 22:12:33 +02:00
std::vector<PrivateKey> keys;
CScript s;
2020-04-11 18:35:43 +02:00
Script::State state(flags);
// Test a AND b:
keys.assign(1,key[0]);
keys.push_back(key[1]);
s = sign_multisig(a_and_b, keys, txTo[0], 0);
2020-04-11 18:35:43 +02:00
QVERIFY(Script::verify(s, a_and_b, MutableTransactionSignatureChecker(&txTo[0], 0, amount), state));
QVERIFY2(state.error == SCRIPT_ERR_OK, state.errorString());
for (int i = 0; i < 4; i++) {
keys.assign(1,key[i]);
s = sign_multisig(a_and_b, keys, txTo[0], 0);
2020-04-11 18:35:43 +02:00
QVERIFY2(!Script::verify(s, a_and_b, MutableTransactionSignatureChecker(&txTo[0], 0, amount), state), strprintf("a&b 1: %d", i).c_str());
QVERIFY2(state.error == SCRIPT_ERR_INVALID_STACK_OPERATION, state.errorString());
keys.assign(1,key[1]);
keys.push_back(key[i]);
s = sign_multisig(a_and_b, keys, txTo[0], 0);
2020-04-11 18:35:43 +02:00
QVERIFY2(!Script::verify(s, a_and_b, MutableTransactionSignatureChecker(&txTo[0], 0, amount), state), strprintf("a&b 2: %d", i).c_str());
QVERIFY2(state.error == SCRIPT_ERR_EVAL_FALSE, state.errorString());
}
// Test a OR b:
for (int i = 0; i < 4; i++) {
keys.assign(1,key[i]);
s = sign_multisig(a_or_b, keys, txTo[1], 0);
if (i == 0 || i == 1)
{
2020-04-11 18:35:43 +02:00
QVERIFY2(Script::verify(s, a_or_b, MutableTransactionSignatureChecker(&txTo[1], 0, amount), state), strprintf("a|b: %d", i).c_str());
QVERIFY2(state.error == SCRIPT_ERR_OK, state.errorString());
}
else
{
2020-04-11 18:35:43 +02:00
QVERIFY2(!Script::verify(s, a_or_b, MutableTransactionSignatureChecker(&txTo[1], 0, amount), state), strprintf("a|b: %d", i).c_str());
QVERIFY2(state.error == SCRIPT_ERR_EVAL_FALSE, state.errorString());
}
}
s.clear();
s << OP_0 << OP_1;
2020-04-11 18:35:43 +02:00
QVERIFY(!Script::verify(s, a_or_b, MutableTransactionSignatureChecker(&txTo[1], 0, amount), state));
QVERIFY2(state.error == SCRIPT_ERR_SIG_DER, state.errorString());
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
{
keys.assign(1,key[i]);
keys.push_back(key[j]);
s = sign_multisig(escrow, keys, txTo[2], 0);
if (i < j && i < 3 && j < 3)
{
2020-04-11 18:35:43 +02:00
QVERIFY2(Script::verify(s, escrow, MutableTransactionSignatureChecker(&txTo[2], 0, amount), state), strprintf("escrow 1: %d %d", i, j).c_str());
QVERIFY2(state.error == SCRIPT_ERR_OK, state.errorString());
}
else {
2020-04-11 18:35:43 +02:00
QVERIFY2(!Script::verify(s, escrow, MutableTransactionSignatureChecker(&txTo[2], 0, amount), state), strprintf("escrow 2: %d %d", i, j).c_str());
QVERIFY2(state.error == SCRIPT_ERR_EVAL_FALSE, state.errorString());
}
}
}
void MultiSigTests::multisig_IsStandard()
{
2022-07-06 22:12:33 +02:00
PrivateKey key[4];
2011-10-03 13:05:43 -04:00
for (int i = 0; i < 4; i++)
2022-05-11 13:46:15 +02:00
key[i].makeNewKey(true);
2019-06-06 21:37:49 +02:00
Script::TxnOutType whichType;
CScript a_and_b;
2022-05-11 13:46:15 +02:00
a_and_b << OP_2 << ToByteVector(key[0].getPubKey()) << ToByteVector(key[1].getPubKey()) << OP_2 << OP_CHECKMULTISIG;
2021-03-13 13:47:44 +01:00
int dataSize = 0;
QVERIFY(::IsStandard(a_and_b, whichType, dataSize));
CScript a_or_b;
2022-05-11 13:46:15 +02:00
a_or_b << OP_1 << ToByteVector(key[0].getPubKey()) << ToByteVector(key[1].getPubKey()) << OP_2 << OP_CHECKMULTISIG;
2021-03-13 13:47:44 +01:00
QVERIFY(::IsStandard(a_or_b, whichType, dataSize));
CScript escrow;
2022-05-11 13:46:15 +02:00
escrow << OP_2 << ToByteVector(key[0].getPubKey()) << ToByteVector(key[1].getPubKey()) << ToByteVector(key[2].getPubKey()) << OP_3 << OP_CHECKMULTISIG;
2021-03-13 13:47:44 +01:00
QVERIFY(::IsStandard(escrow, whichType, dataSize));
2011-10-03 13:05:43 -04:00
CScript one_of_four;
2022-05-11 13:46:15 +02:00
one_of_four << OP_1 << ToByteVector(key[0].getPubKey()) << ToByteVector(key[1].getPubKey()) << ToByteVector(key[2].getPubKey()) << ToByteVector(key[3].getPubKey()) << OP_4 << OP_CHECKMULTISIG;
2021-03-13 13:47:44 +01:00
QVERIFY(!::IsStandard(one_of_four, whichType, dataSize));
2011-10-03 13:05:43 -04:00
CScript malformed[6];
2022-05-11 13:46:15 +02:00
malformed[0] << OP_3 << ToByteVector(key[0].getPubKey()) << ToByteVector(key[1].getPubKey()) << OP_2 << OP_CHECKMULTISIG;
malformed[1] << OP_2 << ToByteVector(key[0].getPubKey()) << ToByteVector(key[1].getPubKey()) << OP_3 << OP_CHECKMULTISIG;
malformed[2] << OP_0 << ToByteVector(key[0].getPubKey()) << ToByteVector(key[1].getPubKey()) << OP_2 << OP_CHECKMULTISIG;
malformed[3] << OP_1 << ToByteVector(key[0].getPubKey()) << ToByteVector(key[1].getPubKey()) << OP_0 << OP_CHECKMULTISIG;
malformed[4] << OP_1 << ToByteVector(key[0].getPubKey()) << ToByteVector(key[1].getPubKey()) << OP_CHECKMULTISIG;
malformed[5] << OP_1 << ToByteVector(key[0].getPubKey()) << ToByteVector(key[1].getPubKey());
2011-10-03 13:05:43 -04:00
for (int i = 0; i < 6; i++) {
QVERIFY(::IsStandard(malformed[i], whichType, dataSize));
QCOMPARE(whichType, Script::TX_SCRIPT);
}
}
void MultiSigTests::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 (a|b) or 2-of-3 keys needed
// to spend an escrow transaction.
//
CBasicKeyStore keystore, emptykeystore, partialkeystore;
2022-07-06 22:12:33 +02:00
PrivateKey key[3];
CTxDestination keyaddr[3];
for (int i = 0; i < 3; i++) {
2022-05-11 13:46:15 +02:00
key[i].makeNewKey(true);
keystore.AddKey(key[i]);
2022-05-11 13:46:15 +02:00
keyaddr[i] = key[i].getPubKey().getKeyId();
}
partialkeystore.AddKey(key[0]);
{
std::vector<valtype> solutions;
2019-06-06 21:37:49 +02:00
Script::TxnOutType whichType;
CScript s;
2022-05-11 13:46:15 +02:00
s << ToByteVector(key[0].getPubKey()) << OP_CHECKSIG;
QVERIFY(Script::solver(s, whichType, solutions));
QVERIFY(solutions.size() == 1);
CTxDestination addr;
QVERIFY(ExtractDestination(s, addr));
QVERIFY(addr == keyaddr[0]);
}
{
std::vector<valtype> solutions;
2019-06-06 21:37:49 +02:00
Script::TxnOutType whichType;
CScript s;
2022-05-11 13:46:15 +02:00
s << OP_DUP << OP_HASH160 << ToByteVector(key[0].getPubKey().getKeyId()) << OP_EQUALVERIFY << OP_CHECKSIG;
QVERIFY(Script::solver(s, whichType, solutions));
QVERIFY(solutions.size() == 1);
CTxDestination addr;
QVERIFY(ExtractDestination(s, addr));
QVERIFY(addr == keyaddr[0]);
}
{
std::vector<valtype> solutions;
2019-06-06 21:37:49 +02:00
Script::TxnOutType whichType;
CScript s;
2022-05-11 13:46:15 +02:00
s << OP_2 << ToByteVector(key[0].getPubKey()) << ToByteVector(key[1].getPubKey()) << OP_2 << OP_CHECKMULTISIG;
QVERIFY(Script::solver(s, whichType, solutions));
QCOMPARE(solutions.size(), 4U);
CTxDestination addr;
QVERIFY(!ExtractDestination(s, addr));
}
{
std::vector<valtype> solutions;
2019-06-06 21:37:49 +02:00
Script::TxnOutType whichType;
CScript s;
2022-05-11 13:46:15 +02:00
s << OP_1 << ToByteVector(key[0].getPubKey()) << ToByteVector(key[1].getPubKey()) << OP_2 << OP_CHECKMULTISIG;
QVERIFY(Script::solver(s, whichType, solutions));
QCOMPARE(solutions.size(), 4U);
std::vector<CTxDestination> addrs;
2011-10-03 13:05:43 -04:00
int nRequired;
QVERIFY(ExtractDestinations(s, whichType, addrs, nRequired));
QVERIFY(addrs[0] == keyaddr[0]);
QVERIFY(addrs[1] == keyaddr[1]);
QVERIFY(nRequired == 1);
}
{
std::vector<valtype> solutions;
2019-06-06 21:37:49 +02:00
Script::TxnOutType whichType;
CScript s;
2022-05-11 13:46:15 +02:00
s << OP_2 << ToByteVector(key[0].getPubKey()) << ToByteVector(key[1].getPubKey()) << ToByteVector(key[2].getPubKey()) << OP_3 << OP_CHECKMULTISIG;
QVERIFY(Script::solver(s, whichType, solutions));
QVERIFY(solutions.size() == 5);
}
}