Bitcoin Core  31.0.0
P2P Digital Currency
multisig_tests.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-present The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #include <key.h>
6 #include <policy/policy.h>
7 #include <script/interpreter.h>
8 #include <script/script.h>
9 #include <script/script_error.h>
10 #include <script/sign.h>
11 #include <script/signingprovider.h>
12 #include <test/util/common.h>
13 #include <test/util/setup_common.h>
15 #include <tinyformat.h>
16 #include <uint256.h>
17 
18 
19 #include <boost/test/unit_test.hpp>
20 
22 
23 static CScript
24 sign_multisig(const CScript& scriptPubKey, const std::vector<CKey>& keys, const CTransaction& transaction, int whichIn)
25 {
26  uint256 hash = SignatureHash(scriptPubKey, transaction, whichIn, SIGHASH_ALL, 0, SigVersion::BASE);
27 
29  result << OP_0; // CHECKMULTISIG bug workaround
30  for (const CKey &key : keys)
31  {
32  std::vector<unsigned char> vchSig;
33  BOOST_CHECK(key.Sign(hash, vchSig));
34  vchSig.push_back((unsigned char)SIGHASH_ALL);
35  result << vchSig;
36  }
37  return result;
38 }
39 
40 BOOST_AUTO_TEST_CASE(multisig_verify)
41 {
43 
44  ScriptError err;
45  CKey key[4];
46  CAmount amount = 0;
47  for (int i = 0; i < 4; i++)
48  key[i].MakeNewKey(true);
49 
50  CScript a_and_b;
51  a_and_b << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
52 
53  CScript a_or_b;
54  a_or_b << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
55 
56  CScript escrow;
57  escrow << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << OP_3 << OP_CHECKMULTISIG;
58 
59  CMutableTransaction txFrom; // Funding transaction
60  txFrom.vout.resize(3);
61  txFrom.vout[0].scriptPubKey = a_and_b;
62  txFrom.vout[1].scriptPubKey = a_or_b;
63  txFrom.vout[2].scriptPubKey = escrow;
64 
65  CMutableTransaction txTo[3]; // Spending transaction
66  for (int i = 0; i < 3; i++)
67  {
68  txTo[i].vin.resize(1);
69  txTo[i].vout.resize(1);
70  txTo[i].vin[0].prevout.n = i;
71  txTo[i].vin[0].prevout.hash = txFrom.GetHash();
72  txTo[i].vout[0].nValue = 1;
73  }
74 
75  std::vector<CKey> keys;
76  CScript s;
77 
78  // Test a AND b:
79  keys.assign(1,key[0]);
80  keys.push_back(key[1]);
81  s = sign_multisig(a_and_b, keys, CTransaction(txTo[0]), 0);
83  BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
84 
85  for (int i = 0; i < 4; i++)
86  {
87  keys.assign(1,key[i]);
88  s = sign_multisig(a_and_b, keys, CTransaction(txTo[0]), 0);
89  BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, nullptr, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount, MissingDataBehavior::ASSERT_FAIL), &err), strprintf("a&b 1: %d", i));
90  BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err));
91 
92  keys.assign(1,key[1]);
93  keys.push_back(key[i]);
94  s = sign_multisig(a_and_b, keys, CTransaction(txTo[0]), 0);
95  BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, nullptr, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount, MissingDataBehavior::ASSERT_FAIL), &err), strprintf("a&b 2: %d", i));
96  BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
97  }
98 
99  // Test a OR b:
100  for (int i = 0; i < 4; i++)
101  {
102  keys.assign(1,key[i]);
103  s = sign_multisig(a_or_b, keys, CTransaction(txTo[1]), 0);
104  if (i == 0 || i == 1)
105  {
106  BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, nullptr, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount, MissingDataBehavior::ASSERT_FAIL), &err), strprintf("a|b: %d", i));
107  BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
108  }
109  else
110  {
111  BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, nullptr, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount, MissingDataBehavior::ASSERT_FAIL), &err), strprintf("a|b: %d", i));
112  BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
113  }
114  }
115  s.clear();
116  s << OP_0 << OP_1;
118  BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_SIG_DER, ScriptErrorString(err));
119 
120 
121  for (int i = 0; i < 4; i++)
122  for (int j = 0; j < 4; j++)
123  {
124  keys.assign(1,key[i]);
125  keys.push_back(key[j]);
126  s = sign_multisig(escrow, keys, CTransaction(txTo[2]), 0);
127  if (i < j && i < 3 && j < 3)
128  {
129  BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, nullptr, flags, MutableTransactionSignatureChecker(&txTo[2], 0, amount, MissingDataBehavior::ASSERT_FAIL), &err), strprintf("escrow 1: %d %d", i, j));
130  BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
131  }
132  else
133  {
134  BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, nullptr, flags, MutableTransactionSignatureChecker(&txTo[2], 0, amount, MissingDataBehavior::ASSERT_FAIL), &err), strprintf("escrow 2: %d %d", i, j));
135  BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
136  }
137  }
138 }
139 
140 BOOST_AUTO_TEST_CASE(multisig_IsStandard)
141 {
142  CKey key[4];
143  for (int i = 0; i < 4; i++)
144  key[i].MakeNewKey(true);
145 
146  const auto is_standard{[](const CScript& spk) {
147  TxoutType type;
148  bool res{::IsStandard(spk, type)};
149  if (res) {
151  }
152  return res;
153  }};
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(is_standard(a_and_b));
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(is_standard(a_or_b));
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(is_standard(escrow));
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(!is_standard(one_of_four));
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(!is_standard(malformed[i]));
181  }
182 }
183 
184 BOOST_AUTO_TEST_CASE(multisig_Sign)
185 {
186  // Test SignSignature() (and therefore the version of Solver() that signs transactions)
187  FillableSigningProvider keystore;
188  CKey key[4];
189  for (int i = 0; i < 4; i++)
190  {
191  key[i].MakeNewKey(true);
192  BOOST_CHECK(keystore.AddKey(key[i]));
193  }
194 
195  CScript a_and_b;
196  a_and_b << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
197 
198  CScript a_or_b;
199  a_or_b << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
200 
201  CScript escrow;
202  escrow << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << OP_3 << OP_CHECKMULTISIG;
203 
204  CMutableTransaction txFrom; // Funding transaction
205  txFrom.vout.resize(3);
206  txFrom.vout[0].scriptPubKey = a_and_b;
207  txFrom.vout[1].scriptPubKey = a_or_b;
208  txFrom.vout[2].scriptPubKey = escrow;
209 
210  CMutableTransaction txTo[3]; // Spending transaction
211  for (int i = 0; i < 3; i++)
212  {
213  txTo[i].vin.resize(1);
214  txTo[i].vout.resize(1);
215  txTo[i].vin[0].prevout.n = i;
216  txTo[i].vin[0].prevout.hash = txFrom.GetHash();
217  txTo[i].vout[0].nValue = 1;
218  }
219 
220  for (int i = 0; i < 3; i++)
221  {
222  SignatureData empty;
223  BOOST_CHECK_MESSAGE(SignSignature(keystore, CTransaction(txFrom), txTo[i], 0, SIGHASH_ALL, empty), strprintf("SignSignature %d", i));
224  }
225 }
226 
227 
uint256 SignatureHash(const CScript &scriptCode, const T &txTo, unsigned int nIn, int32_t nHashType, const CAmount &amount, SigVersion sigversion, const PrecomputedTransactionData *cache, SigHashCache *sighash_cache)
enum ScriptError_t ScriptError
static CScript sign_multisig(const CScript &scriptPubKey, const std::vector< CKey > &keys, const CTransaction &transaction, int whichIn)
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1172
std::vector< CTxIn > vin
Definition: transaction.h:359
Bare scripts and BIP16 P2SH-wrapped redeemscripts.
Definition: script.h:76
bool VerifyScript(const CScript &scriptSig, const CScript &scriptPubKey, const CScriptWitness *witness, script_verify_flags flags, const BaseSignatureChecker &checker, ScriptError *serror)
Basic testing setup.
Definition: setup_common.h:64
Definition: script.h:83
int64_t CAmount
Amount in satoshis (Can be negative)
Definition: amount.h:12
Abort execution through assertion failure (for consensus code)
BOOST_FIXTURE_TEST_SUITE(cuckoocache_tests, BasicTestingSetup)
Test Suite for CuckooCache.
BOOST_AUTO_TEST_SUITE_END()
Fillable signing provider that keeps keys in an address->secret map.
std::string ScriptErrorString(const ScriptError serror)
void MakeNewKey(bool fCompressed)
Generate a new private key using a cryptographic PRNG.
Definition: key.cpp:162
GenericTransactionSignatureChecker< CMutableTransaction > MutableTransactionSignatureChecker
Definition: interpreter.h:337
Txid GetHash() const
Compute the hash of this CMutableTransaction.
Definition: transaction.cpp:69
std::vector< CTxOut > vout
Definition: transaction.h:360
bool SignSignature(const SigningProvider &provider, const CScript &fromPubKey, CMutableTransaction &txTo, unsigned int nIn, const CAmount &amount, int nHashType, SignatureData &sig_data)
Produce a satisfying script (scriptSig or witness).
int flags
Definition: bitcoin-tx.cpp:529
std::vector< unsigned char > ToByteVector(const T &in)
Definition: script.h:67
256-bit opaque blob.
Definition: uint256.h:195
TxoutType
Definition: solver.h:22
auto result
Definition: common-types.h:74
#define BOOST_CHECK_EQUAL(v1, v2)
Definition: object.cpp:17
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:404
static bool GetPubKey(const SigningProvider &provider, const SignatureData &sigdata, const CKeyID &address, CPubKey &pubkey)
Definition: sign.cpp:221
Definition: script.h:86
BOOST_AUTO_TEST_CASE(multisig_verify)
A mutable version of CTransaction.
Definition: transaction.h:357
Definition: script.h:85
An encapsulated private key.
Definition: key.h:35
The basic transaction that is broadcasted on the network and contained in blocks. ...
Definition: transaction.h:280
bool IsStandard(const CScript &scriptPubKey, TxoutType &whichType)
Definition: policy.cpp:79
virtual bool AddKey(const CKey &key)
Definition: script.h:87
#define BOOST_CHECK(expr)
Definition: object.cpp:16