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