Bitcoin Core  26.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;
51  uncompressedKey.MakeNewKey(false);
52  CPubKey uncompressedPubkey = uncompressedKey.GetPubKey();
53  std::unique_ptr<interfaces::Chain>& chain = m_node.chain;
54 
55  CScript scriptPubKey;
56  isminetype result;
57 
58  // P2PK compressed - Legacy
59  {
60  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
61  keystore.SetupLegacyScriptPubKeyMan();
63  scriptPubKey = GetScriptForRawPubKey(pubkeys[0]);
64 
65  // Keystore does not have key
66  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
68  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
69 
70  // Keystore has key
71  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
72  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
74  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1);
75  }
76 
77  // P2PK compressed - Descriptor
78  {
79  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
80  std::string desc_str = "pk(" + EncodeSecret(keys[0]) + ")";
81 
82  auto spk_manager = CreateDescriptor(keystore, desc_str, true);
83 
84  scriptPubKey = GetScriptForRawPubKey(pubkeys[0]);
85  result = spk_manager->IsMine(scriptPubKey);
87  }
88 
89  // P2PK uncompressed - Legacy
90  {
91  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
92  keystore.SetupLegacyScriptPubKeyMan();
94  scriptPubKey = GetScriptForRawPubKey(uncompressedPubkey);
95 
96  // Keystore does not have key
97  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
99  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
100 
101  // Keystore has key
102  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
103  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
105  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1);
106  }
107 
108  // P2PK uncompressed - Descriptor
109  {
110  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
111  std::string desc_str = "pk(" + EncodeSecret(uncompressedKey) + ")";
112 
113  auto spk_manager = CreateDescriptor(keystore, desc_str, true);
114 
115  scriptPubKey = GetScriptForRawPubKey(uncompressedPubkey);
116  result = spk_manager->IsMine(scriptPubKey);
118  }
119 
120  // P2PKH compressed - Legacy
121  {
122  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
123  keystore.SetupLegacyScriptPubKeyMan();
125  scriptPubKey = GetScriptForDestination(PKHash(pubkeys[0]));
126 
127  // Keystore does not have key
128  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
129  BOOST_CHECK_EQUAL(result, ISMINE_NO);
130  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
131 
132  // Keystore has key
133  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
134  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
136  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1);
137  }
138 
139  // P2PKH compressed - Descriptor
140  {
141  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
142  std::string desc_str = "pkh(" + EncodeSecret(keys[0]) + ")";
143 
144  auto spk_manager = CreateDescriptor(keystore, desc_str, true);
145 
146  scriptPubKey = GetScriptForDestination(PKHash(pubkeys[0]));
147  result = spk_manager->IsMine(scriptPubKey);
149  }
150 
151  // P2PKH uncompressed - Legacy
152  {
153  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
154  keystore.SetupLegacyScriptPubKeyMan();
156  scriptPubKey = GetScriptForDestination(PKHash(uncompressedPubkey));
157 
158  // Keystore does not have key
159  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
160  BOOST_CHECK_EQUAL(result, ISMINE_NO);
161  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
162 
163  // Keystore has key
164  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
165  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
167  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1);
168  }
169 
170  // P2PKH uncompressed - Descriptor
171  {
172  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
173  std::string desc_str = "pkh(" + EncodeSecret(uncompressedKey) + ")";
174 
175  auto spk_manager = CreateDescriptor(keystore, desc_str, true);
176 
177  scriptPubKey = GetScriptForDestination(PKHash(uncompressedPubkey));
178  result = spk_manager->IsMine(scriptPubKey);
180  }
181 
182  // P2SH - Legacy
183  {
184  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
185  keystore.SetupLegacyScriptPubKeyMan();
187 
188  CScript redeemScript = GetScriptForDestination(PKHash(pubkeys[0]));
189  scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
190 
191  // Keystore does not have redeemScript or key
192  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
193  BOOST_CHECK_EQUAL(result, ISMINE_NO);
194  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
195 
196  // Keystore has redeemScript but no key
197  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(redeemScript));
198  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
199  BOOST_CHECK_EQUAL(result, ISMINE_NO);
200  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
201 
202  // Keystore has redeemScript and key
203  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
204  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
206  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1);
207  }
208 
209  // P2SH - Descriptor
210  {
211  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
212  std::string desc_str = "sh(pkh(" + EncodeSecret(keys[0]) + "))";
213 
214  auto spk_manager = CreateDescriptor(keystore, desc_str, true);
215 
216  CScript redeemScript = GetScriptForDestination(PKHash(pubkeys[0]));
217  scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
218  result = spk_manager->IsMine(scriptPubKey);
220  }
221 
222  // (P2PKH inside) P2SH inside P2SH (invalid) - Legacy
223  {
224  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
225  keystore.SetupLegacyScriptPubKeyMan();
227 
228  CScript redeemscript_inner = GetScriptForDestination(PKHash(pubkeys[0]));
229  CScript redeemscript = GetScriptForDestination(ScriptHash(redeemscript_inner));
230  scriptPubKey = GetScriptForDestination(ScriptHash(redeemscript));
231 
232  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(redeemscript));
233  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(redeemscript_inner));
234  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(scriptPubKey));
235  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
236  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
237  BOOST_CHECK_EQUAL(result, ISMINE_NO);
238  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
239  }
240 
241  // (P2PKH inside) P2SH inside P2SH (invalid) - Descriptor
242  {
243  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
244  std::string desc_str = "sh(sh(" + EncodeSecret(keys[0]) + "))";
245 
246  auto spk_manager = CreateDescriptor(keystore, desc_str, false);
247  BOOST_CHECK_EQUAL(spk_manager, nullptr);
248  }
249 
250  // (P2PKH inside) P2SH inside P2WSH (invalid) - Legacy
251  {
252  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
253  keystore.SetupLegacyScriptPubKeyMan();
255 
256  CScript redeemscript = GetScriptForDestination(PKHash(pubkeys[0]));
257  CScript witnessscript = GetScriptForDestination(ScriptHash(redeemscript));
258  scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessscript));
259 
260  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(witnessscript));
261  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(redeemscript));
262  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(scriptPubKey));
263  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
264  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
265  BOOST_CHECK_EQUAL(result, ISMINE_NO);
266  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
267  }
268 
269  // (P2PKH inside) P2SH inside P2WSH (invalid) - Descriptor
270  {
271  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
272  std::string desc_str = "wsh(sh(" + EncodeSecret(keys[0]) + "))";
273 
274  auto spk_manager = CreateDescriptor(keystore, desc_str, false);
275  BOOST_CHECK_EQUAL(spk_manager, nullptr);
276  }
277 
278  // P2WPKH inside P2WSH (invalid) - Legacy
279  {
280  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
281  keystore.SetupLegacyScriptPubKeyMan();
283 
284  CScript witnessscript = GetScriptForDestination(WitnessV0KeyHash(pubkeys[0]));
285  scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessscript));
286 
287  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(witnessscript));
288  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(scriptPubKey));
289  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
290  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
291  BOOST_CHECK_EQUAL(result, ISMINE_NO);
292  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
293  }
294 
295  // P2WPKH inside P2WSH (invalid) - Descriptor
296  {
297  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
298  std::string desc_str = "wsh(wpkh(" + EncodeSecret(keys[0]) + "))";
299 
300  auto spk_manager = CreateDescriptor(keystore, desc_str, false);
301  BOOST_CHECK_EQUAL(spk_manager, nullptr);
302  }
303 
304  // (P2PKH inside) P2WSH inside P2WSH (invalid) - Legacy
305  {
306  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
307  keystore.SetupLegacyScriptPubKeyMan();
309 
310  CScript witnessscript_inner = GetScriptForDestination(PKHash(pubkeys[0]));
311  CScript witnessscript = GetScriptForDestination(WitnessV0ScriptHash(witnessscript_inner));
312  scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessscript));
313 
314  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(witnessscript_inner));
315  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(witnessscript));
316  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(scriptPubKey));
317  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
318  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
319  BOOST_CHECK_EQUAL(result, ISMINE_NO);
320  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
321  }
322 
323  // (P2PKH inside) P2WSH inside P2WSH (invalid) - Descriptor
324  {
325  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
326  std::string desc_str = "wsh(wsh(" + EncodeSecret(keys[0]) + "))";
327 
328  auto spk_manager = CreateDescriptor(keystore, desc_str, false);
329  BOOST_CHECK_EQUAL(spk_manager, nullptr);
330  }
331 
332  // P2WPKH compressed - Legacy
333  {
334  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
335  keystore.SetupLegacyScriptPubKeyMan();
337  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
338 
339  scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(pubkeys[0]));
340 
341  // Keystore implicitly has key and P2SH redeemScript
342  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(scriptPubKey));
343  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
345  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1);
346  }
347 
348  // P2WPKH compressed - Descriptor
349  {
350  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
351  std::string desc_str = "wpkh(" + EncodeSecret(keys[0]) + ")";
352 
353  auto spk_manager = CreateDescriptor(keystore, desc_str, true);
354 
355  scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(pubkeys[0]));
356  result = spk_manager->IsMine(scriptPubKey);
358  }
359 
360  // P2WPKH uncompressed - Legacy
361  {
362  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
363  keystore.SetupLegacyScriptPubKeyMan();
365  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
366 
367  scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(uncompressedPubkey));
368 
369  // Keystore has key, but no P2SH redeemScript
370  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
371  BOOST_CHECK_EQUAL(result, ISMINE_NO);
372  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
373 
374  // Keystore has key and P2SH redeemScript
375  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(scriptPubKey));
376  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
377  BOOST_CHECK_EQUAL(result, ISMINE_NO);
378  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
379  }
380 
381  // P2WPKH uncompressed (invalid) - Descriptor
382  {
383  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
384  std::string desc_str = "wpkh(" + EncodeSecret(uncompressedKey) + ")";
385 
386  auto spk_manager = CreateDescriptor(keystore, desc_str, false);
387  BOOST_CHECK_EQUAL(spk_manager, nullptr);
388  }
389 
390  // scriptPubKey multisig - Legacy
391  {
392  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
393  keystore.SetupLegacyScriptPubKeyMan();
395 
396  scriptPubKey = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]});
397 
398  // Keystore does not have any keys
399  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
400  BOOST_CHECK_EQUAL(result, ISMINE_NO);
401  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
402 
403  // Keystore has 1/2 keys
404  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
405 
406  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
407  BOOST_CHECK_EQUAL(result, ISMINE_NO);
408  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
409 
410  // Keystore has 2/2 keys
411  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[1]));
412 
413  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
414  BOOST_CHECK_EQUAL(result, ISMINE_NO);
415  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
416 
417  // Keystore has 2/2 keys and the script
418  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(scriptPubKey));
419 
420  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
421  BOOST_CHECK_EQUAL(result, ISMINE_NO);
422  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
423  }
424 
425  // scriptPubKey multisig - Descriptor
426  {
427  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
428  std::string desc_str = "multi(2, " + EncodeSecret(uncompressedKey) + ", " + EncodeSecret(keys[1]) + ")";
429 
430  auto spk_manager = CreateDescriptor(keystore, desc_str, true);
431 
432  scriptPubKey = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]});
433  result = spk_manager->IsMine(scriptPubKey);
435  }
436 
437  // P2SH multisig - Legacy
438  {
439  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
440  keystore.SetupLegacyScriptPubKeyMan();
442  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
443  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[1]));
444 
445  CScript redeemScript = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]});
446  scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
447 
448  // Keystore has no redeemScript
449  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
450  BOOST_CHECK_EQUAL(result, ISMINE_NO);
451  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
452 
453  // Keystore has redeemScript
454  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(redeemScript));
455  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
457  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1);
458  }
459 
460  // P2SH multisig - Descriptor
461  {
462  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
463 
464  std::string desc_str = "sh(multi(2, " + EncodeSecret(uncompressedKey) + ", " + EncodeSecret(keys[1]) + "))";
465 
466  auto spk_manager = CreateDescriptor(keystore, desc_str, true);
467 
468  CScript redeemScript = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]});
469  scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
470  result = spk_manager->IsMine(scriptPubKey);
472  }
473 
474  // P2WSH multisig with compressed keys - Legacy
475  {
476  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
477  keystore.SetupLegacyScriptPubKeyMan();
479  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
480  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[1]));
481 
482  CScript witnessScript = GetScriptForMultisig(2, {pubkeys[0], pubkeys[1]});
483  scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessScript));
484 
485  // Keystore has keys, but no witnessScript or P2SH redeemScript
486  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
487  BOOST_CHECK_EQUAL(result, ISMINE_NO);
488  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
489 
490  // Keystore has keys and witnessScript, but no P2SH redeemScript
491  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(witnessScript));
492  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
493  BOOST_CHECK_EQUAL(result, ISMINE_NO);
494  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
495 
496  // Keystore has keys, witnessScript, P2SH redeemScript
497  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(scriptPubKey));
498  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
500  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1);
501  }
502 
503  // P2WSH multisig with compressed keys - Descriptor
504  {
505  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
506 
507  std::string desc_str = "wsh(multi(2, " + EncodeSecret(keys[0]) + ", " + EncodeSecret(keys[1]) + "))";
508 
509  auto spk_manager = CreateDescriptor(keystore, desc_str, true);
510 
511  CScript redeemScript = GetScriptForMultisig(2, {pubkeys[0], pubkeys[1]});
512  scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(redeemScript));
513  result = spk_manager->IsMine(scriptPubKey);
515  }
516 
517  // P2WSH multisig with uncompressed key - Legacy
518  {
519  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
520  keystore.SetupLegacyScriptPubKeyMan();
522  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
523  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[1]));
524 
525  CScript witnessScript = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]});
526  scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessScript));
527 
528  // Keystore has keys, but no witnessScript or P2SH redeemScript
529  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
530  BOOST_CHECK_EQUAL(result, ISMINE_NO);
531  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
532 
533  // Keystore has keys and witnessScript, but no P2SH redeemScript
534  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(witnessScript));
535  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
536  BOOST_CHECK_EQUAL(result, ISMINE_NO);
537  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
538 
539  // Keystore has keys, witnessScript, P2SH redeemScript
540  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(scriptPubKey));
541  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
542  BOOST_CHECK_EQUAL(result, ISMINE_NO);
543  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
544  }
545 
546  // P2WSH multisig with uncompressed key (invalid) - Descriptor
547  {
548  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
549 
550  std::string desc_str = "wsh(multi(2, " + EncodeSecret(uncompressedKey) + ", " + EncodeSecret(keys[1]) + "))";
551 
552  auto spk_manager = CreateDescriptor(keystore, desc_str, false);
553  BOOST_CHECK_EQUAL(spk_manager, nullptr);
554  }
555 
556  // P2WSH multisig wrapped in P2SH - Legacy
557  {
558  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
559  keystore.SetupLegacyScriptPubKeyMan();
561 
562  CScript witnessScript = GetScriptForMultisig(2, {pubkeys[0], pubkeys[1]});
563  CScript redeemScript = GetScriptForDestination(WitnessV0ScriptHash(witnessScript));
564  scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
565 
566  // Keystore has no witnessScript, P2SH redeemScript, or keys
567  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
568  BOOST_CHECK_EQUAL(result, ISMINE_NO);
569  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
570 
571  // Keystore has witnessScript and P2SH redeemScript, but no keys
572  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(redeemScript));
573  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddCScript(witnessScript));
574  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
575  BOOST_CHECK_EQUAL(result, ISMINE_NO);
576  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
577 
578  // Keystore has keys, witnessScript, P2SH redeemScript
579  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
580  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[1]));
581  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
583  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1);
584  }
585 
586  // P2WSH multisig wrapped in P2SH - Descriptor
587  {
588  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
589 
590  std::string desc_str = "sh(wsh(multi(2, " + EncodeSecret(keys[0]) + ", " + EncodeSecret(keys[1]) + ")))";
591 
592  auto spk_manager = CreateDescriptor(keystore, desc_str, true);
593 
594  CScript witnessScript = GetScriptForMultisig(2, {pubkeys[0], pubkeys[1]});
595  CScript redeemScript = GetScriptForDestination(WitnessV0ScriptHash(witnessScript));
596  scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
597  result = spk_manager->IsMine(scriptPubKey);
599  }
600 
601  // Combo - Descriptor
602  {
603  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
604 
605  std::string desc_str = "combo(" + EncodeSecret(keys[0]) + ")";
606 
607  auto spk_manager = CreateDescriptor(keystore, desc_str, true);
608 
609  // Test P2PK
610  result = spk_manager->IsMine(GetScriptForRawPubKey(pubkeys[0]));
612 
613  // Test P2PKH
614  result = spk_manager->IsMine(GetScriptForDestination(PKHash(pubkeys[0])));
616 
617  // Test P2SH (combo descriptor does not describe P2SH)
618  CScript redeemScript = GetScriptForDestination(PKHash(pubkeys[0]));
619  scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
620  result = spk_manager->IsMine(scriptPubKey);
621  BOOST_CHECK_EQUAL(result, ISMINE_NO);
622 
623  // Test P2WPKH
624  scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(pubkeys[0]));
625  result = spk_manager->IsMine(scriptPubKey);
627 
628  // P2SH-P2WPKH output
629  redeemScript = GetScriptForDestination(WitnessV0KeyHash(pubkeys[0]));
630  scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
631  result = spk_manager->IsMine(scriptPubKey);
633 
634  // Test P2TR (combo descriptor does not describe P2TR)
635  XOnlyPubKey xpk(pubkeys[0]);
636  Assert(xpk.IsFullyValid());
637  TaprootBuilder builder;
638  builder.Finalize(xpk);
639  WitnessV1Taproot output = builder.GetOutput();
640  scriptPubKey = GetScriptForDestination(output);
641  result = spk_manager->IsMine(scriptPubKey);
642  BOOST_CHECK_EQUAL(result, ISMINE_NO);
643  }
644 
645  // Taproot - Descriptor
646  {
647  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
648 
649  std::string desc_str = "tr(" + EncodeSecret(keys[0]) + ")";
650 
651  auto spk_manager = CreateDescriptor(keystore, desc_str, true);
652 
653  XOnlyPubKey xpk(pubkeys[0]);
654  Assert(xpk.IsFullyValid());
655  TaprootBuilder builder;
656  builder.Finalize(xpk);
657  WitnessV1Taproot output = builder.GetOutput();
658  scriptPubKey = GetScriptForDestination(output);
659  result = spk_manager->IsMine(scriptPubKey);
661  }
662 
663  // OP_RETURN
664  {
665  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
666  keystore.SetupLegacyScriptPubKeyMan();
668  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
669 
670  scriptPubKey.clear();
671  scriptPubKey << OP_RETURN << ToByteVector(pubkeys[0]);
672 
673  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
674  BOOST_CHECK_EQUAL(result, ISMINE_NO);
675  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
676  }
677 
678  // witness unspendable
679  {
680  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
681  keystore.SetupLegacyScriptPubKeyMan();
683  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
684 
685  scriptPubKey.clear();
686  scriptPubKey << OP_0 << ToByteVector(ParseHex("aabb"));
687 
688  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
689  BOOST_CHECK_EQUAL(result, ISMINE_NO);
690  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
691  }
692 
693  // witness unknown
694  {
695  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
696  keystore.SetupLegacyScriptPubKeyMan();
698  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
699 
700  scriptPubKey.clear();
701  scriptPubKey << OP_16 << ToByteVector(ParseHex("aabb"));
702 
703  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
704  BOOST_CHECK_EQUAL(result, ISMINE_NO);
705  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
706  }
707 
708  // Nonstandard
709  {
710  CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
711  keystore.SetupLegacyScriptPubKeyMan();
713  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
714 
715  scriptPubKey.clear();
716  scriptPubKey << OP_9 << OP_ADD << OP_11 << OP_EQUAL;
717 
718  result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
719  BOOST_CHECK_EQUAL(result, ISMINE_NO);
720  BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0);
721  }
722 }
723 
725 } // 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:3463
void SetupLegacyScriptPubKeyMan()
Make a LegacyScriptPubKeyMan and set it for all types, internal, and external.
Definition: wallet.cpp:3489
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:309
BOOST_AUTO_TEST_SUITE_END()
std::string EncodeSecret(const CKey &key)
Definition: key_io.cpp:227
bool error(const char *fmt, const Args &... args)
Definition: logging.h:262
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:49
std::unique_ptr< interfaces::Chain > chain
Definition: context.h:63
#define LOCK(cs)
Definition: sync.h:257