PIVX Core  5.6.99
P2P Digital Currency
multisig_tests.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2013 The Bitcoin Core developers
2 // Copyright (c) 2019-2021 The PIVX Core developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 
6 #include "key.h"
7 #include "keystore.h"
8 #include "policy/policy.h"
9 #include "script/script.h"
10 #include "script/script_error.h"
11 #include "script/interpreter.h"
12 #include "script/sign.h"
13 #include "script/ismine.h"
14 #include "uint256.h"
15 #include "test_pivx.h"
16 
17 
18 #include <boost/test/unit_test.hpp>
19 
20 
21 typedef std::vector<unsigned char> valtype;
22 
24 
25 CScript
26 sign_multisig(const CScript& scriptPubKey, const std::vector<CKey>& keys, const CTransaction& transaction, int whichIn)
27 {
28  const uint256& hash = SignatureHash(scriptPubKey, transaction, whichIn, SIGHASH_ALL, 0, SIGVERSION_BASE);
29 
30  CScript result;
31  result << OP_0; // CHECKMULTISIG bug workaround
32  for (const CKey &key : keys)
33  {
34  std::vector<unsigned char> vchSig;
35  BOOST_CHECK(key.Sign(hash, vchSig));
36  vchSig.push_back((unsigned char)SIGHASH_ALL);
37  result << vchSig;
38  }
39  return result;
40 }
41 
42 BOOST_AUTO_TEST_CASE(multisig_verify)
43 {
45 
46  ScriptError err;
47  CKey key[4];
48  CAmount amount = 0;
49  for (int i = 0; i < 4; i++)
50  key[i].MakeNewKey(true);
51 
52  CScript a_and_b;
53  a_and_b << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
54 
55  CScript a_or_b;
56  a_or_b << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
57 
58  CScript escrow;
59  escrow << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << OP_3 << OP_CHECKMULTISIG;
60 
61  CMutableTransaction txFrom; // Funding transaction
62  txFrom.vout.resize(3);
63  txFrom.vout[0].scriptPubKey = a_and_b;
64  txFrom.vout[1].scriptPubKey = a_or_b;
65  txFrom.vout[2].scriptPubKey = escrow;
66 
67  CMutableTransaction txTo[3]; // Spending transaction
68  for (int i = 0; i < 3; i++)
69  {
70  txTo[i].vin.resize(1);
71  txTo[i].vout.resize(1);
72  txTo[i].vin[0].prevout.n = i;
73  txTo[i].vin[0].prevout.hash = txFrom.GetHash();
74  txTo[i].vout[0].nValue = 1;
75  }
76 
77  std::vector<CKey> keys;
78  CScript s;
79 
80  // Test a AND b:
81  keys.clear();
82  keys.push_back(key[0]);
83  keys.push_back(key[1]);
84  s = sign_multisig(a_and_b, keys, txTo[0], 0);
85  BOOST_CHECK(VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), SIGVERSION_BASE, &err));
86  BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
87 
88  for (int i = 0; i < 4; i++)
89  {
90  keys.clear();
91  keys.push_back(key[i]);
92  s = sign_multisig(a_and_b, keys, txTo[0], 0);
93  BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), SIGVERSION_BASE, &err), strprintf("a&b 1: %d", i));
94  BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err));
95 
96  keys.clear();
97  keys.push_back(key[1]);
98  keys.push_back(key[i]);
99  s = sign_multisig(a_and_b, keys, txTo[0], 0);
100  BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), SIGVERSION_BASE, &err), strprintf("a&b 2: %d", i));
101  BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
102  }
103 
104  // Test a OR b:
105  for (int i = 0; i < 4; i++)
106  {
107  keys.clear();
108  keys.push_back(key[i]);
109  s = sign_multisig(a_or_b, keys, txTo[1], 0);
110  if (i == 0 || i == 1)
111  {
112  BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount), SIGVERSION_BASE, &err), strprintf("a|b: %d", i));
113  BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
114  }
115  else
116  {
117  BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount), SIGVERSION_BASE, &err), strprintf("a|b: %d", i));
118  BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
119  }
120  }
121  s.clear();
122  s << OP_0 << OP_1;
123  BOOST_CHECK(!VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount), SIGVERSION_BASE, &err));
124  BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_SIG_DER, ScriptErrorString(err));
125 
126 
127  for (int i = 0; i < 4; i++)
128  for (int j = 0; j < 4; j++)
129  {
130  keys.clear();
131  keys.push_back(key[i]);
132  keys.push_back(key[j]);
133  s = sign_multisig(escrow, keys, txTo[2], 0);
134  if (i < j && i < 3 && j < 3)
135  {
136  BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, flags, MutableTransactionSignatureChecker(&txTo[2], 0, amount), SIGVERSION_BASE, &err), strprintf("escrow 1: %d %d", i, j));
137  BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
138  }
139  else
140  {
141  BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, flags, MutableTransactionSignatureChecker(&txTo[2], 0, amount), SIGVERSION_BASE, &err), strprintf("escrow 2: %d %d", i, j));
142  BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
143  }
144  }
145 }
146 
147 BOOST_AUTO_TEST_CASE(multisig_IsStandard)
148 {
149  CKey key[4];
150  for (int i = 0; i < 4; i++)
151  key[i].MakeNewKey(true);
152 
153  txnouttype whichType;
154 
155  CScript a_and_b;
156  a_and_b << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
157  BOOST_CHECK(::IsStandard(a_and_b, whichType));
158 
159  CScript a_or_b;
160  a_or_b << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
161  BOOST_CHECK(::IsStandard(a_or_b, whichType));
162 
163  CScript escrow;
164  escrow << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << OP_3 << OP_CHECKMULTISIG;
165  BOOST_CHECK(::IsStandard(escrow, whichType));
166 
167  CScript one_of_four;
168  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;
169  BOOST_CHECK(!::IsStandard(one_of_four, whichType));
170 
171  CScript malformed[6];
172  malformed[0] << OP_3 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
173  malformed[1] << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_3 << OP_CHECKMULTISIG;
174  malformed[2] << OP_0 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
175  malformed[3] << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_0 << OP_CHECKMULTISIG;
176  malformed[4] << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_CHECKMULTISIG;
177  malformed[5] << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey());
178 
179  for (int i = 0; i < 6; i++)
180  BOOST_CHECK(!::IsStandard(malformed[i], whichType));
181 }
182 
183 BOOST_AUTO_TEST_CASE(multisig_Solver1)
184 {
185  // Tests Solver() that returns lists of keys that are
186  // required to satisfy a ScriptPubKey
187  //
188  // Also tests IsMine() and ExtractDestination()
189  //
190  // Note: ExtractDestination for the multisignature transactions
191  // always returns false for this release, even if you have
192  // one key that would satisfy an (a|b) or 2-of-3 keys needed
193  // to spend an escrow transaction.
194  //
195  CBasicKeyStore keystore, emptykeystore, partialkeystore;
196  CKey key[3];
197  CTxDestination keyaddr[3];
198  for (int i = 0; i < 3; i++)
199  {
200  key[i].MakeNewKey(true);
201  keystore.AddKey(key[i]);
202  keyaddr[i] = key[i].GetPubKey().GetID();
203  }
204  partialkeystore.AddKey(key[0]);
205 
206  {
207  std::vector<valtype> solutions;
208  txnouttype whichType;
209  CScript s;
210  s << ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG;
211  BOOST_CHECK(Solver(s, whichType, solutions));
212  BOOST_CHECK(solutions.size() == 1);
213  CTxDestination addr;
215  BOOST_CHECK(addr == keyaddr[0]);
216  BOOST_CHECK(IsMine(keystore, s));
217  BOOST_CHECK(!IsMine(emptykeystore, s));
218  }
219  {
220  std::vector<valtype> solutions;
221  txnouttype whichType;
222  CScript s;
223  s << OP_DUP << OP_HASH160 << ToByteVector(key[0].GetPubKey().GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
224  BOOST_CHECK(Solver(s, whichType, solutions));
225  BOOST_CHECK(solutions.size() == 1);
226  CTxDestination addr;
228  BOOST_CHECK(addr == keyaddr[0]);
229  BOOST_CHECK(IsMine(keystore, s));
230  BOOST_CHECK(!IsMine(emptykeystore, s));
231  }
232  {
233  std::vector<valtype> solutions;
234  txnouttype whichType;
235  CScript s;
236  s << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
237  BOOST_CHECK(Solver(s, whichType, solutions));
238  BOOST_CHECK_EQUAL(solutions.size(), 4U);
239  CTxDestination addr;
240  BOOST_CHECK(!ExtractDestination(s, addr));
241  BOOST_CHECK(IsMine(keystore, s));
242  BOOST_CHECK(!IsMine(emptykeystore, s));
243  BOOST_CHECK(!IsMine(partialkeystore, s));
244  }
245  {
246  std::vector<valtype> solutions;
247  txnouttype whichType;
248  CScript s;
249  s << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
250  BOOST_CHECK(Solver(s, whichType, solutions));
251  BOOST_CHECK_EQUAL(solutions.size(), 4U);
252  std::vector<CTxDestination> addrs;
253  int nRequired;
254  BOOST_CHECK(ExtractDestinations(s, whichType, addrs, nRequired));
255  BOOST_CHECK(addrs[0] == keyaddr[0]);
256  BOOST_CHECK(addrs[1] == keyaddr[1]);
257  BOOST_CHECK(nRequired == 1);
258  BOOST_CHECK(IsMine(keystore, s));
259  BOOST_CHECK(!IsMine(emptykeystore, s));
260  BOOST_CHECK(!IsMine(partialkeystore, s));
261  }
262  {
263  std::vector<valtype> solutions;
264  txnouttype whichType;
265  CScript s;
266  s << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << OP_3 << OP_CHECKMULTISIG;
267  BOOST_CHECK(Solver(s, whichType, solutions));
268  BOOST_CHECK(solutions.size() == 5);
269  }
270 }
271 
272 BOOST_AUTO_TEST_CASE(multisig_Sign)
273 {
274  // Test SignSignature() (and therefore the version of Solver() that signs transactions)
275  CBasicKeyStore keystore;
276  CKey key[4];
277  for (int i = 0; i < 4; i++)
278  {
279  key[i].MakeNewKey(true);
280  keystore.AddKey(key[i]);
281  }
282 
283  CScript a_and_b;
284  a_and_b << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
285 
286  CScript a_or_b;
287  a_or_b << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
288 
289  CScript escrow;
290  escrow << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << OP_3 << OP_CHECKMULTISIG;
291 
292  CMutableTransaction txFrom; // Funding transaction
293  txFrom.vout.resize(3);
294  txFrom.vout[0].scriptPubKey = a_and_b;
295  txFrom.vout[1].scriptPubKey = a_or_b;
296  txFrom.vout[2].scriptPubKey = escrow;
297 
298  CMutableTransaction txTo[3]; // Spending transaction
299  for (int i = 0; i < 3; i++)
300  {
301  txTo[i].vin.resize(1);
302  txTo[i].vout.resize(1);
303  txTo[i].vin[0].prevout.n = i;
304  txTo[i].vin[0].prevout.hash = txFrom.GetHash();
305  txTo[i].vout[0].nValue = 1;
306  }
307 
308  for (int i = 0; i < 3; i++)
309  {
310  BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0, SIGHASH_ALL), strprintf("SignSignature %d", i));
311  }
312 }
313 
314 
int64_t CAmount
Amount in PIV (Can be negative)
Definition: amount.h:13
Basic key store, that keeps keys in an address->secret map.
Definition: keystore.h:99
An encapsulated private key.
Definition: key.h:30
void MakeNewKey(bool fCompressed)
Generate a new private key using a cryptographic PRNG.
Definition: key.cpp:158
CPubKey GetPubKey() const
Compute the public key from a private key.
Definition: key.cpp:186
virtual bool AddKey(const CKey &key)
Definition: keystore.cpp:14
CKeyID GetID() const
Get the KeyID of this public key (hash of its serialization)
Definition: pubkey.h:167
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:381
void clear()
Definition: script.h:659
The basic transaction that is broadcasted on the network and contained in blocks.
Definition: transaction.h:244
256-bit opaque blob.
Definition: uint256.h:138
BOOST_AUTO_TEST_SUITE_END()
bool VerifyScript(const CScript &scriptSig, const CScript &scriptPubKey, unsigned int flags, const BaseSignatureChecker &checker, SigVersion sigversion, ScriptError *serror)
uint256 SignatureHash(const CScript &scriptCode, const CTransaction &txTo, unsigned int nIn, int nHashType, const CAmount &amount, SigVersion sigversion, const PrecomputedTransactionData *cache)
@ SCRIPT_VERIFY_P2SH
Definition: interpreter.h:36
@ SCRIPT_VERIFY_STRICTENC
Definition: interpreter.h:41
@ SIGHASH_ALL
Definition: interpreter.h:24
isminetype IsMine(const CKeyStore &keystore, const CTxDestination &dest)
Definition: ismine.cpp:29
BOOST_AUTO_TEST_CASE(multisig_verify)
std::vector< unsigned char > valtype
CScript sign_multisig(const CScript &scriptPubKey, const std::vector< CKey > &keys, const CTransaction &transaction, int whichIn)
#define BOOST_FIXTURE_TEST_SUITE(a, b)
Definition: object.cpp:14
#define BOOST_CHECK_EQUAL(v1, v2)
Definition: object.cpp:18
#define BOOST_CHECK(expr)
Definition: object.cpp:17
int flags
Definition: pivx-tx.cpp:400
bool IsStandard(const CScript &scriptPubKey, txnouttype &whichType)
Check transaction inputs to mitigate two potential denial-of-service attacks:
Definition: policy.cpp:78
std::vector< unsigned char > ToByteVector(const T &in)
Definition: script.h:43
@ OP_2
Definition: script.h:61
@ OP_CHECKMULTISIG
Definition: script.h:168
@ OP_CHECKSIG
Definition: script.h:166
@ OP_4
Definition: script.h:63
@ OP_DUP
Definition: script.h:101
@ OP_HASH160
Definition: script.h:163
@ OP_1
Definition: script.h:59
@ OP_3
Definition: script.h:62
@ OP_0
Definition: script.h:52
@ OP_EQUALVERIFY
Definition: script.h:123
const char * ScriptErrorString(const ScriptError serror)
Definition: script_error.cpp:9
enum ScriptError_t ScriptError
@ SCRIPT_ERR_EVAL_FALSE
Definition: script_error.h:14
@ SCRIPT_ERR_INVALID_STACK_OPERATION
Definition: script_error.h:37
@ SCRIPT_ERR_SIG_DER
Definition: script_error.h:47
@ SCRIPT_ERR_OK
Definition: script_error.h:12
bool SignSignature(const CKeyStore &keystore, const CScript &fromPubKey, CMutableTransaction &txTo, unsigned int nIn, const CAmount &amount, int nHashType, bool fColdStake)
Produce a script signature for a transaction.
Definition: sign.cpp:192
bool ExtractDestinations(const CScript &scriptPubKey, txnouttype &typeRet, std::vector< CTxDestination > &addressRet, int &nRequiredRet)
Parse a standard scriptPubKey with one or more destination addresses.
Definition: standard.cpp:195
bool Solver(const CScript &scriptPubKey, txnouttype &typeRet, std::vector< std::vector< unsigned char > > &vSolutionsRet)
Parse a scriptPubKey and identify script type for standard scripts.
Definition: standard.cpp:90
bool ExtractDestination(const CScript &scriptPubKey, CTxDestination &addressRet, bool fColdStake)
Parse a standard scriptPubKey for the destination address.
Definition: standard.cpp:162
boost::variant< CNoDestination, CKeyID, CScriptID, CExchangeKeyID > CTxDestination
A txout script template with a specific destination.
Definition: standard.h:72
txnouttype
Definition: standard.h:46
A mutable version of CTransaction.
Definition: transaction.h:409
uint256 GetHash() const
Compute the hash of this CMutableTransaction.
Definition: transaction.cpp:96
std::vector< CTxOut > vout
Definition: transaction.h:411
std::vector< CTxIn > vin
Definition: transaction.h:410
#define strprintf
Definition: tinyformat.h:1056
@ SIGVERSION_BASE
Definition: transaction.h:27