Bitcoin Core  27.99.0
P2P Digital Currency
ismine_tests.cpp
Go to the documentation of this file.
1 // Copyright (c) 2017-2022 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 <key_io.h>
7 #include <node/context.h>
8 #include <script/script.h>
9 #include <script/solver.h>
10 #include <script/signingprovider.h>
11 #include <test/util/setup_common.h>
12 #include <wallet/types.h>
13 #include <wallet/wallet.h>
14 #include <wallet/test/util.h>
15 
16 #include <boost/test/unit_test.hpp>
17 
18 
19 namespace wallet {
20 BOOST_FIXTURE_TEST_SUITE(ismine_tests, BasicTestingSetup)
21 
22 wallet::ScriptPubKeyMan* CreateDescriptor(CWallet& keystore, const std::string& desc_str, const bool success)
23 {
24  keystore.SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
25 
27  std::string error;
28  std::unique_ptr<Descriptor> parsed_desc = Parse(desc_str, keys, error, false);
29  BOOST_CHECK(success == (parsed_desc != nullptr));
30  if (!success) return nullptr;
31 
32  const int64_t range_start = 0, range_end = 1, next_index = 0, timestamp = 1;
33 
34  WalletDescriptor w_desc(std::move(parsed_desc), timestamp, range_start, range_end, next_index);
35 
36  LOCK(keystore.cs_wallet);
37 
38  return Assert(keystore.AddWalletDescriptor(w_desc, keys,/*label=*/"", /*internal=*/false));
39 };
40 
41 BOOST_AUTO_TEST_CASE(ismine_standard)
42 {
43  CKey keys[2];
44  CPubKey pubkeys[2];
45  for (int i = 0; i < 2; i++) {
46  keys[i].MakeNewKey(true);
47  pubkeys[i] = keys[i].GetPubKey();
48  }
49 
50  CKey uncompressedKey = GenerateRandomKey(/*compressed=*/false);
51  CPubKey uncompressedPubkey = uncompressedKey.GetPubKey();
52  std::unique_ptr<interfaces::Chain>& chain = m_node.chain;
53 
54  CScript scriptPubKey;
55  isminetype result;
56 
57  // P2PK compressed - Legacy
58  {
59  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
60  keystore.SetupLegacyScriptPubKeyMan();
62  scriptPubKey = GetScriptForRawPubKey(pubkeys[0]);
63 
64  // Keystore does not have key
65  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
67  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
68 
69  // Keystore has key
70  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
71  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
73  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1);
74  }
75 
76  // P2PK compressed - Descriptor
77  {
78  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
79  std::string desc_str = "pk(" + EncodeSecret(keys[0]) + ")";
80 
81  auto spk_manager = CreateDescriptor(keystore, desc_str, true);
82 
83  scriptPubKey = GetScriptForRawPubKey(pubkeys[0]);
84  result = spk_manager->IsMine(scriptPubKey);
86  }
87 
88  // P2PK uncompressed - Legacy
89  {
90  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
91  keystore.SetupLegacyScriptPubKeyMan();
93  scriptPubKey = GetScriptForRawPubKey(uncompressedPubkey);
94 
95  // Keystore does not have key
96  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
98  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
99 
100  // Keystore has key
101  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
102  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
104  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1);
105  }
106 
107  // P2PK uncompressed - Descriptor
108  {
109  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
110  std::string desc_str = "pk(" + EncodeSecret(uncompressedKey) + ")";
111 
112  auto spk_manager = CreateDescriptor(keystore, desc_str, true);
113 
114  scriptPubKey = GetScriptForRawPubKey(uncompressedPubkey);
115  result = spk_manager->IsMine(scriptPubKey);
117  }
118 
119  // P2PKH compressed - Legacy
120  {
121  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
122  keystore.SetupLegacyScriptPubKeyMan();
124  scriptPubKey = GetScriptForDestination(PKHash(pubkeys[0]));
125 
126  // Keystore does not have key
127  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
128  BOOST_CHECK_EQUAL(result, ISMINE_NO);
129  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
130 
131  // Keystore has key
132  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
133  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
135  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1);
136  }
137 
138  // P2PKH compressed - Descriptor
139  {
140  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
141  std::string desc_str = "pkh(" + EncodeSecret(keys[0]) + ")";
142 
143  auto spk_manager = CreateDescriptor(keystore, desc_str, true);
144 
145  scriptPubKey = GetScriptForDestination(PKHash(pubkeys[0]));
146  result = spk_manager->IsMine(scriptPubKey);
148  }
149 
150  // P2PKH uncompressed - Legacy
151  {
152  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
153  keystore.SetupLegacyScriptPubKeyMan();
155  scriptPubKey = GetScriptForDestination(PKHash(uncompressedPubkey));
156 
157  // Keystore does not have key
158  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
159  BOOST_CHECK_EQUAL(result, ISMINE_NO);
160  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
161 
162  // Keystore has key
163  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
164  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
166  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1);
167  }
168 
169  // P2PKH uncompressed - Descriptor
170  {
171  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
172  std::string desc_str = "pkh(" + EncodeSecret(uncompressedKey) + ")";
173 
174  auto spk_manager = CreateDescriptor(keystore, desc_str, true);
175 
176  scriptPubKey = GetScriptForDestination(PKHash(uncompressedPubkey));
177  result = spk_manager->IsMine(scriptPubKey);
179  }
180 
181  // P2SH - Legacy
182  {
183  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
184  keystore.SetupLegacyScriptPubKeyMan();
186 
187  CScript redeemScript = GetScriptForDestination(PKHash(pubkeys[0]));
188  scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
189 
190  // Keystore does not have redeemScript or key
191  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
192  BOOST_CHECK_EQUAL(result, ISMINE_NO);
193  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
194 
195  // Keystore has redeemScript but no key
196  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(redeemScript));
197  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
198  BOOST_CHECK_EQUAL(result, ISMINE_NO);
199  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
200 
201  // Keystore has redeemScript and key
202  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
203  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
205  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1);
206  }
207 
208  // P2SH - Descriptor
209  {
210  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
211  std::string desc_str = "sh(pkh(" + EncodeSecret(keys[0]) + "))";
212 
213  auto spk_manager = CreateDescriptor(keystore, desc_str, true);
214 
215  CScript redeemScript = GetScriptForDestination(PKHash(pubkeys[0]));
216  scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
217  result = spk_manager->IsMine(scriptPubKey);
219  }
220 
221  // (P2PKH inside) P2SH inside P2SH (invalid) - Legacy
222  {
223  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
224  keystore.SetupLegacyScriptPubKeyMan();
226 
227  CScript redeemscript_inner = GetScriptForDestination(PKHash(pubkeys[0]));
228  CScript redeemscript = GetScriptForDestination(ScriptHash(redeemscript_inner));
229  scriptPubKey = GetScriptForDestination(ScriptHash(redeemscript));
230 
231  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(redeemscript));
232  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(redeemscript_inner));
233  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(scriptPubKey));
234  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
235  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
236  BOOST_CHECK_EQUAL(result, ISMINE_NO);
237  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
238  }
239 
240  // (P2PKH inside) P2SH inside P2SH (invalid) - Descriptor
241  {
242  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
243  std::string desc_str = "sh(sh(" + EncodeSecret(keys[0]) + "))";
244 
245  auto spk_manager = CreateDescriptor(keystore, desc_str, false);
246  BOOST_CHECK_EQUAL(spk_manager, nullptr);
247  }
248 
249  // (P2PKH inside) P2SH inside P2WSH (invalid) - Legacy
250  {
251  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
252  keystore.SetupLegacyScriptPubKeyMan();
254 
255  CScript redeemscript = GetScriptForDestination(PKHash(pubkeys[0]));
256  CScript witnessscript = GetScriptForDestination(ScriptHash(redeemscript));
257  scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessscript));
258 
259  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(witnessscript));
260  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(redeemscript));
261  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(scriptPubKey));
262  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
263  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
264  BOOST_CHECK_EQUAL(result, ISMINE_NO);
265  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
266  }
267 
268  // (P2PKH inside) P2SH inside P2WSH (invalid) - Descriptor
269  {
270  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
271  std::string desc_str = "wsh(sh(" + EncodeSecret(keys[0]) + "))";
272 
273  auto spk_manager = CreateDescriptor(keystore, desc_str, false);
274  BOOST_CHECK_EQUAL(spk_manager, nullptr);
275  }
276 
277  // P2WPKH inside P2WSH (invalid) - Legacy
278  {
279  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
280  keystore.SetupLegacyScriptPubKeyMan();
282 
283  CScript witnessscript = GetScriptForDestination(WitnessV0KeyHash(pubkeys[0]));
284  scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessscript));
285 
286  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(witnessscript));
287  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(scriptPubKey));
288  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
289  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
290  BOOST_CHECK_EQUAL(result, ISMINE_NO);
291  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
292  }
293 
294  // P2WPKH inside P2WSH (invalid) - Descriptor
295  {
296  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
297  std::string desc_str = "wsh(wpkh(" + EncodeSecret(keys[0]) + "))";
298 
299  auto spk_manager = CreateDescriptor(keystore, desc_str, false);
300  BOOST_CHECK_EQUAL(spk_manager, nullptr);
301  }
302 
303  // (P2PKH inside) P2WSH inside P2WSH (invalid) - Legacy
304  {
305  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
306  keystore.SetupLegacyScriptPubKeyMan();
308 
309  CScript witnessscript_inner = GetScriptForDestination(PKHash(pubkeys[0]));
310  CScript witnessscript = GetScriptForDestination(WitnessV0ScriptHash(witnessscript_inner));
311  scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessscript));
312 
313  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(witnessscript_inner));
314  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(witnessscript));
315  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(scriptPubKey));
316  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
317  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
318  BOOST_CHECK_EQUAL(result, ISMINE_NO);
319  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
320  }
321 
322  // (P2PKH inside) P2WSH inside P2WSH (invalid) - Descriptor
323  {
324  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
325  std::string desc_str = "wsh(wsh(" + EncodeSecret(keys[0]) + "))";
326 
327  auto spk_manager = CreateDescriptor(keystore, desc_str, false);
328  BOOST_CHECK_EQUAL(spk_manager, nullptr);
329  }
330 
331  // P2WPKH compressed - Legacy
332  {
333  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
334  keystore.SetupLegacyScriptPubKeyMan();
336  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
337 
338  scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(pubkeys[0]));
339 
340  // Keystore implicitly has key and P2SH redeemScript
341  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(scriptPubKey));
342  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
344  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1);
345  }
346 
347  // P2WPKH compressed - Descriptor
348  {
349  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
350  std::string desc_str = "wpkh(" + EncodeSecret(keys[0]) + ")";
351 
352  auto spk_manager = CreateDescriptor(keystore, desc_str, true);
353 
354  scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(pubkeys[0]));
355  result = spk_manager->IsMine(scriptPubKey);
357  }
358 
359  // P2WPKH uncompressed - Legacy
360  {
361  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
362  keystore.SetupLegacyScriptPubKeyMan();
364  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
365 
366  scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(uncompressedPubkey));
367 
368  // Keystore has key, but no P2SH redeemScript
369  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
370  BOOST_CHECK_EQUAL(result, ISMINE_NO);
371  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
372 
373  // Keystore has key and P2SH redeemScript
374  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(scriptPubKey));
375  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
376  BOOST_CHECK_EQUAL(result, ISMINE_NO);
377  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
378  }
379 
380  // P2WPKH uncompressed (invalid) - Descriptor
381  {
382  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
383  std::string desc_str = "wpkh(" + EncodeSecret(uncompressedKey) + ")";
384 
385  auto spk_manager = CreateDescriptor(keystore, desc_str, false);
386  BOOST_CHECK_EQUAL(spk_manager, nullptr);
387  }
388 
389  // scriptPubKey multisig - Legacy
390  {
391  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
392  keystore.SetupLegacyScriptPubKeyMan();
394 
395  scriptPubKey = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]});
396 
397  // Keystore does not have any keys
398  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
399  BOOST_CHECK_EQUAL(result, ISMINE_NO);
400  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
401 
402  // Keystore has 1/2 keys
403  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
404 
405  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
406  BOOST_CHECK_EQUAL(result, ISMINE_NO);
407  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
408 
409  // Keystore has 2/2 keys
410  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[1]));
411 
412  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
413  BOOST_CHECK_EQUAL(result, ISMINE_NO);
414  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
415 
416  // Keystore has 2/2 keys and the script
417  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(scriptPubKey));
418 
419  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
420  BOOST_CHECK_EQUAL(result, ISMINE_NO);
421  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
422  }
423 
424  // scriptPubKey multisig - Descriptor
425  {
426  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
427  std::string desc_str = "multi(2, " + EncodeSecret(uncompressedKey) + ", " + EncodeSecret(keys[1]) + ")";
428 
429  auto spk_manager = CreateDescriptor(keystore, desc_str, true);
430 
431  scriptPubKey = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]});
432  result = spk_manager->IsMine(scriptPubKey);
434  }
435 
436  // P2SH multisig - Legacy
437  {
438  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
439  keystore.SetupLegacyScriptPubKeyMan();
441  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
442  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[1]));
443 
444  CScript redeemScript = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]});
445  scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
446 
447  // Keystore has no redeemScript
448  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
449  BOOST_CHECK_EQUAL(result, ISMINE_NO);
450  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
451 
452  // Keystore has redeemScript
453  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(redeemScript));
454  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
456  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1);
457  }
458 
459  // P2SH multisig - Descriptor
460  {
461  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
462 
463  std::string desc_str = "sh(multi(2, " + EncodeSecret(uncompressedKey) + ", " + EncodeSecret(keys[1]) + "))";
464 
465  auto spk_manager = CreateDescriptor(keystore, desc_str, true);
466 
467  CScript redeemScript = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]});
468  scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
469  result = spk_manager->IsMine(scriptPubKey);
471  }
472 
473  // P2WSH multisig with compressed keys - Legacy
474  {
475  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
476  keystore.SetupLegacyScriptPubKeyMan();
478  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
479  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[1]));
480 
481  CScript witnessScript = GetScriptForMultisig(2, {pubkeys[0], pubkeys[1]});
482  scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessScript));
483 
484  // Keystore has keys, but no witnessScript or P2SH redeemScript
485  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
486  BOOST_CHECK_EQUAL(result, ISMINE_NO);
487  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
488 
489  // Keystore has keys and witnessScript, but no P2SH redeemScript
490  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(witnessScript));
491  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
492  BOOST_CHECK_EQUAL(result, ISMINE_NO);
493  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
494 
495  // Keystore has keys, witnessScript, P2SH redeemScript
496  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(scriptPubKey));
497  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
499  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1);
500  }
501 
502  // P2WSH multisig with compressed keys - Descriptor
503  {
504  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
505 
506  std::string desc_str = "wsh(multi(2, " + EncodeSecret(keys[0]) + ", " + EncodeSecret(keys[1]) + "))";
507 
508  auto spk_manager = CreateDescriptor(keystore, desc_str, true);
509 
510  CScript redeemScript = GetScriptForMultisig(2, {pubkeys[0], pubkeys[1]});
511  scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(redeemScript));
512  result = spk_manager->IsMine(scriptPubKey);
514  }
515 
516  // P2WSH multisig with uncompressed key - Legacy
517  {
518  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
519  keystore.SetupLegacyScriptPubKeyMan();
521  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
522  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[1]));
523 
524  CScript witnessScript = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]});
525  scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessScript));
526 
527  // Keystore has keys, but no witnessScript or P2SH redeemScript
528  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
529  BOOST_CHECK_EQUAL(result, ISMINE_NO);
530  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
531 
532  // Keystore has keys and witnessScript, but no P2SH redeemScript
533  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(witnessScript));
534  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
535  BOOST_CHECK_EQUAL(result, ISMINE_NO);
536  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
537 
538  // Keystore has keys, witnessScript, P2SH redeemScript
539  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(scriptPubKey));
540  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
541  BOOST_CHECK_EQUAL(result, ISMINE_NO);
542  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
543  }
544 
545  // P2WSH multisig with uncompressed key (invalid) - Descriptor
546  {
547  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
548 
549  std::string desc_str = "wsh(multi(2, " + EncodeSecret(uncompressedKey) + ", " + EncodeSecret(keys[1]) + "))";
550 
551  auto spk_manager = CreateDescriptor(keystore, desc_str, false);
552  BOOST_CHECK_EQUAL(spk_manager, nullptr);
553  }
554 
555  // P2WSH multisig wrapped in P2SH - Legacy
556  {
557  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
558  keystore.SetupLegacyScriptPubKeyMan();
560 
561  CScript witnessScript = GetScriptForMultisig(2, {pubkeys[0], pubkeys[1]});
562  CScript redeemScript = GetScriptForDestination(WitnessV0ScriptHash(witnessScript));
563  scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
564 
565  // Keystore has no witnessScript, P2SH redeemScript, or keys
566  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
567  BOOST_CHECK_EQUAL(result, ISMINE_NO);
568  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
569 
570  // Keystore has witnessScript and P2SH redeemScript, but no keys
571  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(redeemScript));
572  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(witnessScript));
573  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
574  BOOST_CHECK_EQUAL(result, ISMINE_NO);
575  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
576 
577  // Keystore has keys, witnessScript, P2SH redeemScript
578  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
579  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[1]));
580  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
582  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1);
583  }
584 
585  // P2WSH multisig wrapped in P2SH - Descriptor
586  {
587  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
588 
589  std::string desc_str = "sh(wsh(multi(2, " + EncodeSecret(keys[0]) + ", " + EncodeSecret(keys[1]) + ")))";
590 
591  auto spk_manager = CreateDescriptor(keystore, desc_str, true);
592 
593  CScript witnessScript = GetScriptForMultisig(2, {pubkeys[0], pubkeys[1]});
594  CScript redeemScript = GetScriptForDestination(WitnessV0ScriptHash(witnessScript));
595  scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
596  result = spk_manager->IsMine(scriptPubKey);
598  }
599 
600  // Combo - Descriptor
601  {
602  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
603 
604  std::string desc_str = "combo(" + EncodeSecret(keys[0]) + ")";
605 
606  auto spk_manager = CreateDescriptor(keystore, desc_str, true);
607 
608  // Test P2PK
609  result = spk_manager->IsMine(GetScriptForRawPubKey(pubkeys[0]));
611 
612  // Test P2PKH
613  result = spk_manager->IsMine(GetScriptForDestination(PKHash(pubkeys[0])));
615 
616  // Test P2SH (combo descriptor does not describe P2SH)
617  CScript redeemScript = GetScriptForDestination(PKHash(pubkeys[0]));
618  scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
619  result = spk_manager->IsMine(scriptPubKey);
620  BOOST_CHECK_EQUAL(result, ISMINE_NO);
621 
622  // Test P2WPKH
623  scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(pubkeys[0]));
624  result = spk_manager->IsMine(scriptPubKey);
626 
627  // P2SH-P2WPKH output
628  redeemScript = GetScriptForDestination(WitnessV0KeyHash(pubkeys[0]));
629  scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
630  result = spk_manager->IsMine(scriptPubKey);
632 
633  // Test P2TR (combo descriptor does not describe P2TR)
634  XOnlyPubKey xpk(pubkeys[0]);
635  Assert(xpk.IsFullyValid());
636  TaprootBuilder builder;
637  builder.Finalize(xpk);
638  WitnessV1Taproot output = builder.GetOutput();
639  scriptPubKey = GetScriptForDestination(output);
640  result = spk_manager->IsMine(scriptPubKey);
641  BOOST_CHECK_EQUAL(result, ISMINE_NO);
642  }
643 
644  // Taproot - Descriptor
645  {
646  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
647 
648  std::string desc_str = "tr(" + EncodeSecret(keys[0]) + ")";
649 
650  auto spk_manager = CreateDescriptor(keystore, desc_str, true);
651 
652  XOnlyPubKey xpk(pubkeys[0]);
653  Assert(xpk.IsFullyValid());
654  TaprootBuilder builder;
655  builder.Finalize(xpk);
656  WitnessV1Taproot output = builder.GetOutput();
657  scriptPubKey = GetScriptForDestination(output);
658  result = spk_manager->IsMine(scriptPubKey);
660  }
661 
662  // OP_RETURN
663  {
664  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
665  keystore.SetupLegacyScriptPubKeyMan();
667  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
668 
669  scriptPubKey.clear();
670  scriptPubKey << OP_RETURN << ToByteVector(pubkeys[0]);
671 
672  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
673  BOOST_CHECK_EQUAL(result, ISMINE_NO);
674  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
675  }
676 
677  // witness unspendable
678  {
679  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
680  keystore.SetupLegacyScriptPubKeyMan();
682  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
683 
684  scriptPubKey.clear();
685  scriptPubKey << OP_0 << ToByteVector(ParseHex("aabb"));
686 
687  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
688  BOOST_CHECK_EQUAL(result, ISMINE_NO);
689  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
690  }
691 
692  // witness unknown
693  {
694  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
695  keystore.SetupLegacyScriptPubKeyMan();
697  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
698 
699  scriptPubKey.clear();
700  scriptPubKey << OP_16 << ToByteVector(ParseHex("aabb"));
701 
702  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
703  BOOST_CHECK_EQUAL(result, ISMINE_NO);
704  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
705  }
706 
707  // Nonstandard
708  {
709  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
710  keystore.SetupLegacyScriptPubKeyMan();
712  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
713 
714  scriptPubKey.clear();
715  scriptPubKey << OP_9 << OP_ADD << OP_11 << OP_EQUAL;
716 
717  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
718  BOOST_CHECK_EQUAL(result, ISMINE_NO);
719  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
720  }
721 }
722 
724 } // namespace wallet
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
node::NodeContext m_node
Definition: bitcoin-gui.cpp:37
#define Assert(val)
Identity function.
Definition: check.h:77
An encapsulated private key.
Definition: key.h:33
void MakeNewKey(bool fCompressed)
Generate a new private key using a cryptographic PRNG.
Definition: key.cpp:161
CPubKey GetPubKey() const
Compute the public key from a private key.
Definition: key.cpp:188
An encapsulated public key.
Definition: pubkey.h:34
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:414
void clear()
Definition: script.h:557
virtual bool AddKey(const CKey &key)
RecursiveMutex cs_KeyStore
Utility class to construct Taproot outputs from internal key and script tree.
WitnessV1Taproot GetOutput()
Compute scriptPubKey (after Finalize()).
TaprootBuilder & Finalize(const XOnlyPubKey &internal_key)
Finalize the construction.
bool IsFullyValid() const
Determine if this pubkey is fully valid.
Definition: pubkey.cpp:214
A CWallet maintains a set of transactions and balances, and provides the ability to create new transa...
Definition: wallet.h:301
LegacyScriptPubKeyMan * GetLegacyScriptPubKeyMan() const
Get the LegacyScriptPubKeyMan which is used for all types, internal, and external.
Definition: wallet.cpp:3590
void SetupLegacyScriptPubKeyMan()
Make a LegacyScriptPubKeyMan and set it for all types, internal, and external.
Definition: wallet.cpp:3618
std::unordered_set< CScript, SaltedSipHasher > GetScriptPubKeys() const override
Returns a set of all the scriptPubKeys that this ScriptPubKeyMan watches.
isminetype IsMine(const CScript &script) const override
bool AddCScript(const CScript &redeemScript) override
Descriptor with some wallet metadata.
Definition: walletutil.h:85
static UniValue Parse(std::string_view raw)
Parse string to UniValue or throw runtime_error if string contains invalid JSON.
Definition: client.cpp:318
BOOST_AUTO_TEST_SUITE_END()
CKey GenerateRandomKey(bool compressed) noexcept
Definition: key.cpp:372
std::string EncodeSecret(const CKey &key)
Definition: key_io.cpp:227
wallet::ScriptPubKeyMan * CreateDescriptor(CWallet &keystore, const std::string &desc_str, const bool success)
std::unique_ptr< WalletDatabase > CreateMockableWalletDatabase(MockableData records)
Definition: util.cpp:190
isminetype
IsMine() return codes, which depend on ScriptPubKeyMan implementation.
Definition: types.h:40
@ ISMINE_NO
Definition: types.h:41
@ ISMINE_SPENDABLE
Definition: types.h:43
BOOST_AUTO_TEST_CASE(bnb_search_test)
@ WALLET_FLAG_DESCRIPTORS
Indicate that this wallet supports DescriptorScriptPubKeyMan.
Definition: walletutil.h:74
#define BOOST_CHECK_EQUAL(v1, v2)
Definition: object.cpp:18
#define BOOST_CHECK(expr)
Definition: object.cpp:17
std::vector< unsigned char > ToByteVector(const T &in)
Definition: script.h:66
@ OP_16
Definition: script.h:98
@ OP_EQUAL
Definition: script.h:145
@ OP_ADD
Definition: script.h:160
@ OP_9
Definition: script.h:91
@ OP_11
Definition: script.h:93
@ OP_0
Definition: script.h:75
@ OP_RETURN
Definition: script.h:110
CScript GetScriptForMultisig(int nRequired, const std::vector< CPubKey > &keys)
Generate a multisig script.
Definition: solver.cpp:214
CScript GetScriptForRawPubKey(const CPubKey &pubKey)
Generate a P2PK script for the given pubkey.
Definition: solver.cpp:209
std::vector< Byte > ParseHex(std::string_view hex_str)
Like TryParseHex, but returns an empty vector on invalid input.
Definition: strencodings.h:65
Basic testing setup.
Definition: setup_common.h:52
std::unique_ptr< interfaces::Chain > chain
Definition: context.h:66
#define LOCK(cs)
Definition: sync.h:257