/ src / wallet / test / ismine_tests.cpp
ismine_tests.cpp
  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  
 26      FlatSigningProvider keys;
 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();
 61          LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
 62          scriptPubKey = GetScriptForRawPubKey(pubkeys[0]);
 63  
 64          // Keystore does not have key
 65          result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
 66          BOOST_CHECK_EQUAL(result, ISMINE_NO);
 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);
 72          BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
 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);
 85          BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
 86      }
 87  
 88      // P2PK uncompressed - Legacy
 89      {
 90          CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
 91          keystore.SetupLegacyScriptPubKeyMan();
 92          LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
 93          scriptPubKey = GetScriptForRawPubKey(uncompressedPubkey);
 94  
 95          // Keystore does not have key
 96          result = keystore.GetLegacyScriptPubKeyMan()->IsMine(scriptPubKey);
 97          BOOST_CHECK_EQUAL(result, ISMINE_NO);
 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);
103          BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
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);
116          BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
117      }
118  
119      // P2PKH compressed - Legacy
120      {
121          CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
122          keystore.SetupLegacyScriptPubKeyMan();
123          LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
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);
134          BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
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);
147          BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
148      }
149  
150      // P2PKH uncompressed - Legacy
151      {
152          CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
153          keystore.SetupLegacyScriptPubKeyMan();
154          LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
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);
165          BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
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);
178          BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
179      }
180  
181      // P2SH - Legacy
182      {
183          CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
184          keystore.SetupLegacyScriptPubKeyMan();
185          LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
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);
204          BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
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);
218          BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
219      }
220  
221      // (P2PKH inside) P2SH inside P2SH (invalid) - Legacy
222      {
223          CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
224          keystore.SetupLegacyScriptPubKeyMan();
225          LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
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();
253          LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
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();
281          LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
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();
307          LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
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();
335          LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
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);
343          BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
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);
356          BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
357      }
358  
359      // P2WPKH uncompressed - Legacy
360      {
361          CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
362          keystore.SetupLegacyScriptPubKeyMan();
363          LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
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();
393          LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
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);
433          BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
434      }
435  
436      // P2SH multisig - Legacy
437      {
438          CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
439          keystore.SetupLegacyScriptPubKeyMan();
440          LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
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);
455          BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
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);
470          BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
471      }
472  
473      // P2WSH multisig with compressed keys - Legacy
474      {
475          CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
476          keystore.SetupLegacyScriptPubKeyMan();
477          LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
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);
498          BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
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);
513          BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
514      }
515  
516      // P2WSH multisig with uncompressed key - Legacy
517      {
518          CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
519          keystore.SetupLegacyScriptPubKeyMan();
520          LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
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();
559          LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
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);
581          BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
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);
597          BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
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]));
610          BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
611  
612          // Test P2PKH
613          result = spk_manager->IsMine(GetScriptForDestination(PKHash(pubkeys[0])));
614          BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
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);
625          BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
626  
627          // P2SH-P2WPKH output
628          redeemScript = GetScriptForDestination(WitnessV0KeyHash(pubkeys[0]));
629          scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
630          result = spk_manager->IsMine(scriptPubKey);
631          BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
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);
659          BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
660      }
661  
662      // OP_RETURN
663      {
664          CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
665          keystore.SetupLegacyScriptPubKeyMan();
666          LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
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();
681          LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
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();
696          LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
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();
711          LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
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  
723  BOOST_AUTO_TEST_SUITE_END()
724  } // namespace wallet