scriptpubkeyman.cpp raw

   1  // Copyright (c) 2019-present The Bitcoin Core developers
   2  // Distributed under the MIT software license, see the accompanying
   3  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
   4  
   5  #include <wallet/scriptpubkeyman.h>
   6  
   7  #include <coins.h>
   8  #include <hash.h>
   9  #include <key_io.h>
  10  #include <node/types.h>
  11  #include <outputtype.h>
  12  #include <script/descriptor.h>
  13  #include <script/script.h>
  14  #include <script/sign.h>
  15  #include <script/solver.h>
  16  #include <util/bip32.h>
  17  #include <util/check.h>
  18  #include <util/log.h>
  19  #include <util/strencodings.h>
  20  #include <util/string.h>
  21  #include <util/time.h>
  22  #include <util/translation.h>
  23  
  24  #include <optional>
  25  
  26  using common::PSBTError;
  27  using util::ToString;
  28  
  29  namespace wallet {
  30  
  31  typedef std::vector<unsigned char> valtype;
  32  
  33  // Legacy wallet IsMine(). Used only in migration
  34  // DO NOT USE ANYTHING IN THIS NAMESPACE OUTSIDE OF MIGRATION
  35  namespace {
  36  
  37  /**
  38   * This is an enum that tracks the execution context of a script, similar to
  39   * SigVersion in script/interpreter. It is separate however because we want to
  40   * distinguish between top-level scriptPubKey execution and P2SH redeemScript
  41   * execution (a distinction that has no impact on consensus rules).
  42   */
  43  enum class IsMineSigVersion
  44  {
  45      TOP = 0,        //!< scriptPubKey execution
  46      P2SH = 1,       //!< P2SH redeemScript
  47      WITNESS_V0 = 2, //!< P2WSH witness script execution
  48  };
  49  
  50  /**
  51   * This is an internal representation of isminetype + invalidity.
  52   * Its order is significant, as we return the max of all explored
  53   * possibilities.
  54   */
  55  enum class IsMineResult
  56  {
  57      NO = 0,         //!< Not ours
  58      WATCH_ONLY = 1, //!< Included in watch-only balance
  59      SPENDABLE = 2,  //!< Included in all balances
  60      INVALID = 3,    //!< Not spendable by anyone (uncompressed pubkey in segwit, P2SH inside P2SH or witness, witness inside witness)
  61  };
  62  
  63  bool PermitsUncompressed(IsMineSigVersion sigversion)
  64  {
  65      return sigversion == IsMineSigVersion::TOP || sigversion == IsMineSigVersion::P2SH;
  66  }
  67  
  68  bool HaveKeys(const std::vector<valtype>& pubkeys, const LegacyDataSPKM& keystore)
  69  {
  70      for (const valtype& pubkey : pubkeys) {
  71          CKeyID keyID = CPubKey(pubkey).GetID();
  72          if (!keystore.HaveKey(keyID)) return false;
  73      }
  74      return true;
  75  }
  76  
  77  //! Recursively solve script and return spendable/watchonly/invalid status.
  78  //!
  79  //! @param keystore            legacy key and script store
  80  //! @param scriptPubKey        script to solve
  81  //! @param sigversion          script type (top-level / redeemscript / witnessscript)
  82  //! @param recurse_scripthash  whether to recurse into nested p2sh and p2wsh
  83  //!                            scripts or simply treat any script that has been
  84  //!                            stored in the keystore as spendable
  85  // NOLINTNEXTLINE(misc-no-recursion)
  86  IsMineResult LegacyWalletIsMineInnerDONOTUSE(const LegacyDataSPKM& keystore, const CScript& scriptPubKey, IsMineSigVersion sigversion, bool recurse_scripthash=true)
  87  {
  88      IsMineResult ret = IsMineResult::NO;
  89  
  90      std::vector<valtype> vSolutions;
  91      TxoutType whichType = Solver(scriptPubKey, vSolutions);
  92  
  93      CKeyID keyID;
  94      switch (whichType) {
  95      case TxoutType::NONSTANDARD:
  96      case TxoutType::NULL_DATA:
  97      case TxoutType::WITNESS_UNKNOWN:
  98      case TxoutType::WITNESS_V1_TAPROOT:
  99      case TxoutType::ANCHOR:
 100          break;
 101      case TxoutType::PUBKEY:
 102          keyID = CPubKey(vSolutions[0]).GetID();
 103          if (!PermitsUncompressed(sigversion) && vSolutions[0].size() != 33) {
 104              return IsMineResult::INVALID;
 105          }
 106          if (keystore.HaveKey(keyID)) {
 107              ret = std::max(ret, IsMineResult::SPENDABLE);
 108          }
 109          break;
 110      case TxoutType::WITNESS_V0_KEYHASH:
 111      {
 112          if (sigversion == IsMineSigVersion::WITNESS_V0) {
 113              // P2WPKH inside P2WSH is invalid.
 114              return IsMineResult::INVALID;
 115          }
 116          if (sigversion == IsMineSigVersion::TOP && !keystore.HaveCScript(CScriptID(CScript() << OP_0 << vSolutions[0]))) {
 117              // We do not support bare witness outputs unless the P2SH version of it would be
 118              // acceptable as well. This protects against matching before segwit activates.
 119              // This also applies to the P2WSH case.
 120              break;
 121          }
 122          ret = std::max(ret, LegacyWalletIsMineInnerDONOTUSE(keystore, GetScriptForDestination(PKHash(uint160(vSolutions[0]))), IsMineSigVersion::WITNESS_V0));
 123          break;
 124      }
 125      case TxoutType::PUBKEYHASH:
 126          keyID = CKeyID(uint160(vSolutions[0]));
 127          if (!PermitsUncompressed(sigversion)) {
 128              CPubKey pubkey;
 129              if (keystore.GetPubKey(keyID, pubkey) && !pubkey.IsCompressed()) {
 130                  return IsMineResult::INVALID;
 131              }
 132          }
 133          if (keystore.HaveKey(keyID)) {
 134              ret = std::max(ret, IsMineResult::SPENDABLE);
 135          }
 136          break;
 137      case TxoutType::SCRIPTHASH:
 138      {
 139          if (sigversion != IsMineSigVersion::TOP) {
 140              // P2SH inside P2WSH or P2SH is invalid.
 141              return IsMineResult::INVALID;
 142          }
 143          CScriptID scriptID = CScriptID(uint160(vSolutions[0]));
 144          CScript subscript;
 145          if (keystore.GetCScript(scriptID, subscript)) {
 146              ret = std::max(ret, recurse_scripthash ? LegacyWalletIsMineInnerDONOTUSE(keystore, subscript, IsMineSigVersion::P2SH) : IsMineResult::SPENDABLE);
 147          }
 148          break;
 149      }
 150      case TxoutType::WITNESS_V0_SCRIPTHASH:
 151      {
 152          if (sigversion == IsMineSigVersion::WITNESS_V0) {
 153              // P2WSH inside P2WSH is invalid.
 154              return IsMineResult::INVALID;
 155          }
 156          if (sigversion == IsMineSigVersion::TOP && !keystore.HaveCScript(CScriptID(CScript() << OP_0 << vSolutions[0]))) {
 157              break;
 158          }
 159          CScriptID scriptID{RIPEMD160(vSolutions[0])};
 160          CScript subscript;
 161          if (keystore.GetCScript(scriptID, subscript)) {
 162              ret = std::max(ret, recurse_scripthash ? LegacyWalletIsMineInnerDONOTUSE(keystore, subscript, IsMineSigVersion::WITNESS_V0) : IsMineResult::SPENDABLE);
 163          }
 164          break;
 165      }
 166  
 167      case TxoutType::MULTISIG:
 168      {
 169          // Never treat bare multisig outputs as ours (they can still be made watchonly-though)
 170          if (sigversion == IsMineSigVersion::TOP) {
 171              break;
 172          }
 173  
 174          // Only consider transactions "mine" if we own ALL the
 175          // keys involved. Multi-signature transactions that are
 176          // partially owned (somebody else has a key that can spend
 177          // them) enable spend-out-from-under-you attacks, especially
 178          // in shared-wallet situations.
 179          std::vector<valtype> keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1);
 180          if (!PermitsUncompressed(sigversion)) {
 181              for (size_t i = 0; i < keys.size(); i++) {
 182                  if (keys[i].size() != 33) {
 183                      return IsMineResult::INVALID;
 184                  }
 185              }
 186          }
 187          if (HaveKeys(keys, keystore)) {
 188              ret = std::max(ret, IsMineResult::SPENDABLE);
 189          }
 190          break;
 191      }
 192      } // no default case, so the compiler can warn about missing cases
 193  
 194      if (ret == IsMineResult::NO && keystore.HaveWatchOnly(scriptPubKey)) {
 195          ret = std::max(ret, IsMineResult::WATCH_ONLY);
 196      }
 197      return ret;
 198  }
 199  
 200  } // namespace
 201  
 202  bool LegacyDataSPKM::IsMine(const CScript& script) const
 203  {
 204      switch (LegacyWalletIsMineInnerDONOTUSE(*this, script, IsMineSigVersion::TOP)) {
 205      case IsMineResult::INVALID:
 206      case IsMineResult::NO:
 207          return false;
 208      case IsMineResult::WATCH_ONLY:
 209      case IsMineResult::SPENDABLE:
 210          return true;
 211      }
 212      assert(false);
 213  }
 214  
 215  bool LegacyDataSPKM::CheckDecryptionKey(const CKeyingMaterial& master_key)
 216  {
 217      {
 218          LOCK(cs_KeyStore);
 219          assert(mapKeys.empty());
 220  
 221          bool keyPass = mapCryptedKeys.empty(); // Always pass when there are no encrypted keys
 222          bool keyFail = false;
 223          CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin();
 224          WalletBatch batch(m_storage.GetDatabase());
 225          for (; mi != mapCryptedKeys.end(); ++mi)
 226          {
 227              const CPubKey &vchPubKey = (*mi).second.first;
 228              const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
 229              CKey key;
 230              if (!DecryptKey(master_key, vchCryptedSecret, vchPubKey, key))
 231              {
 232                  keyFail = true;
 233                  break;
 234              }
 235              keyPass = true;
 236              if (fDecryptionThoroughlyChecked)
 237                  break;
 238              else {
 239                  // Rewrite these encrypted keys with checksums
 240                  batch.WriteCryptedKey(vchPubKey, vchCryptedSecret, mapKeyMetadata[vchPubKey.GetID()]);
 241              }
 242          }
 243          if (keyPass && keyFail)
 244          {
 245              LogWarning("The wallet is probably corrupted: Some keys decrypt but not all.");
 246              throw std::runtime_error("Error unlocking wallet: some keys decrypt but not all. Your wallet file may be corrupt.");
 247          }
 248          if (keyFail || !keyPass)
 249              return false;
 250          fDecryptionThoroughlyChecked = true;
 251      }
 252      return true;
 253  }
 254  
 255  std::unique_ptr<SigningProvider> LegacyDataSPKM::GetSolvingProvider(const CScript& script) const
 256  {
 257      return std::make_unique<LegacySigningProvider>(*this);
 258  }
 259  
 260  bool LegacyDataSPKM::CanProvide(const CScript& script, SignatureData& sigdata)
 261  {
 262      IsMineResult ismine = LegacyWalletIsMineInnerDONOTUSE(*this, script, IsMineSigVersion::TOP, /* recurse_scripthash= */ false);
 263      if (ismine == IsMineResult::SPENDABLE || ismine == IsMineResult::WATCH_ONLY) {
 264          // If ismine, it means we recognize keys or script ids in the script, or
 265          // are watching the script itself, and we can at least provide metadata
 266          // or solving information, even if not able to sign fully.
 267          return true;
 268      } else {
 269          // If, given the stuff in sigdata, we could make a valid signature, then we can provide for this script
 270          ProduceSignature(*this, DUMMY_SIGNATURE_CREATOR, script, sigdata);
 271          if (!sigdata.signatures.empty()) {
 272              // If we could make signatures, make sure we have a private key to actually make a signature
 273              bool has_privkeys = false;
 274              for (const auto& key_sig_pair : sigdata.signatures) {
 275                  has_privkeys |= HaveKey(key_sig_pair.first);
 276              }
 277              return has_privkeys;
 278          }
 279          return false;
 280      }
 281  }
 282  
 283  bool LegacyDataSPKM::LoadKey(const CKey& key, const CPubKey &pubkey)
 284  {
 285      return AddKeyPubKeyInner(key, pubkey);
 286  }
 287  
 288  bool LegacyDataSPKM::LoadCScript(const CScript& redeemScript)
 289  {
 290      /* A sanity check was added in pull #3843 to avoid adding redeemScripts
 291       * that never can be redeemed. However, old wallets may still contain
 292       * these. Do not add them to the wallet and warn. */
 293      if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE)
 294      {
 295          std::string strAddr = EncodeDestination(ScriptHash(redeemScript));
 296          WalletLogPrintf("%s: Warning: This wallet contains a redeemScript of size %i which exceeds maximum size %i thus can never be redeemed. Do not use address %s.\n", __func__, redeemScript.size(), MAX_SCRIPT_ELEMENT_SIZE, strAddr);
 297          return true;
 298      }
 299  
 300      return FillableSigningProvider::AddCScript(redeemScript);
 301  }
 302  
 303  void LegacyDataSPKM::LoadKeyMetadata(const CKeyID& keyID, const CKeyMetadata& meta)
 304  {
 305      LOCK(cs_KeyStore);
 306      mapKeyMetadata[keyID] = meta;
 307  }
 308  
 309  void LegacyDataSPKM::LoadScriptMetadata(const CScriptID& script_id, const CKeyMetadata& meta)
 310  {
 311      LOCK(cs_KeyStore);
 312      m_script_metadata[script_id] = meta;
 313  }
 314  
 315  bool LegacyDataSPKM::AddKeyPubKeyInner(const CKey& key, const CPubKey& pubkey)
 316  {
 317      LOCK(cs_KeyStore);
 318      return FillableSigningProvider::AddKeyPubKey(key, pubkey);
 319  }
 320  
 321  bool LegacyDataSPKM::LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret, bool checksum_valid)
 322  {
 323      // Set fDecryptionThoroughlyChecked to false when the checksum is invalid
 324      if (!checksum_valid) {
 325          fDecryptionThoroughlyChecked = false;
 326      }
 327  
 328      return AddCryptedKeyInner(vchPubKey, vchCryptedSecret);
 329  }
 330  
 331  bool LegacyDataSPKM::AddCryptedKeyInner(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
 332  {
 333      LOCK(cs_KeyStore);
 334      assert(mapKeys.empty());
 335  
 336      mapCryptedKeys[vchPubKey.GetID()] = make_pair(vchPubKey, vchCryptedSecret);
 337      ImplicitlyLearnRelatedKeyScripts(vchPubKey);
 338      return true;
 339  }
 340  
 341  bool LegacyDataSPKM::HaveWatchOnly(const CScript &dest) const
 342  {
 343      LOCK(cs_KeyStore);
 344      return setWatchOnly.contains(dest);
 345  }
 346  
 347  bool LegacyDataSPKM::LoadWatchOnly(const CScript &dest)
 348  {
 349      return AddWatchOnlyInMem(dest);
 350  }
 351  
 352  static bool ExtractPubKey(const CScript &dest, CPubKey& pubKeyOut)
 353  {
 354      std::vector<std::vector<unsigned char>> solutions;
 355      return Solver(dest, solutions) == TxoutType::PUBKEY &&
 356          (pubKeyOut = CPubKey(solutions[0])).IsFullyValid();
 357  }
 358  
 359  bool LegacyDataSPKM::AddWatchOnlyInMem(const CScript &dest)
 360  {
 361      LOCK(cs_KeyStore);
 362      setWatchOnly.insert(dest);
 363      CPubKey pubKey;
 364      if (ExtractPubKey(dest, pubKey)) {
 365          mapWatchKeys[pubKey.GetID()] = pubKey;
 366          ImplicitlyLearnRelatedKeyScripts(pubKey);
 367      }
 368      return true;
 369  }
 370  
 371  void LegacyDataSPKM::LoadHDChain(const CHDChain& chain)
 372  {
 373      LOCK(cs_KeyStore);
 374      m_hd_chain = chain;
 375  }
 376  
 377  void LegacyDataSPKM::AddInactiveHDChain(const CHDChain& chain)
 378  {
 379      LOCK(cs_KeyStore);
 380      assert(!chain.seed_id.IsNull());
 381      m_inactive_hd_chains[chain.seed_id] = chain;
 382  }
 383  
 384  bool LegacyDataSPKM::HaveKey(const CKeyID &address) const
 385  {
 386      LOCK(cs_KeyStore);
 387      if (!m_storage.HasEncryptionKeys()) {
 388          return FillableSigningProvider::HaveKey(address);
 389      }
 390      return mapCryptedKeys.contains(address);
 391  }
 392  
 393  bool LegacyDataSPKM::GetKey(const CKeyID &address, CKey& keyOut) const
 394  {
 395      LOCK(cs_KeyStore);
 396      if (!m_storage.HasEncryptionKeys()) {
 397          return FillableSigningProvider::GetKey(address, keyOut);
 398      }
 399  
 400      CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
 401      if (mi != mapCryptedKeys.end())
 402      {
 403          const CPubKey &vchPubKey = (*mi).second.first;
 404          const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
 405          return m_storage.WithEncryptionKey([&](const CKeyingMaterial& encryption_key) {
 406              return DecryptKey(encryption_key, vchCryptedSecret, vchPubKey, keyOut);
 407          });
 408      }
 409      return false;
 410  }
 411  
 412  bool LegacyDataSPKM::GetKeyOrigin(const CKeyID& keyID, KeyOriginInfo& info) const
 413  {
 414      CKeyMetadata meta;
 415      {
 416          LOCK(cs_KeyStore);
 417          auto it = mapKeyMetadata.find(keyID);
 418          if (it == mapKeyMetadata.end()) {
 419              return false;
 420          }
 421          meta = it->second;
 422      }
 423      if (meta.has_key_origin) {
 424          std::copy(meta.key_origin.fingerprint, meta.key_origin.fingerprint + 4, info.fingerprint);
 425          info.path = meta.key_origin.path;
 426      } else { // Single pubkeys get the master fingerprint of themselves
 427          std::copy(keyID.begin(), keyID.begin() + 4, info.fingerprint);
 428      }
 429      return true;
 430  }
 431  
 432  bool LegacyDataSPKM::GetWatchPubKey(const CKeyID &address, CPubKey &pubkey_out) const
 433  {
 434      LOCK(cs_KeyStore);
 435      WatchKeyMap::const_iterator it = mapWatchKeys.find(address);
 436      if (it != mapWatchKeys.end()) {
 437          pubkey_out = it->second;
 438          return true;
 439      }
 440      return false;
 441  }
 442  
 443  bool LegacyDataSPKM::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const
 444  {
 445      LOCK(cs_KeyStore);
 446      if (!m_storage.HasEncryptionKeys()) {
 447          if (!FillableSigningProvider::GetPubKey(address, vchPubKeyOut)) {
 448              return GetWatchPubKey(address, vchPubKeyOut);
 449          }
 450          return true;
 451      }
 452  
 453      CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
 454      if (mi != mapCryptedKeys.end())
 455      {
 456          vchPubKeyOut = (*mi).second.first;
 457          return true;
 458      }
 459      // Check for watch-only pubkeys
 460      return GetWatchPubKey(address, vchPubKeyOut);
 461  }
 462  
 463  std::unordered_set<CScript, SaltedSipHasher> LegacyDataSPKM::GetCandidateScriptPubKeys() const
 464  {
 465      LOCK(cs_KeyStore);
 466      std::unordered_set<CScript, SaltedSipHasher> candidate_spks;
 467  
 468      // For every private key in the wallet, there should be a P2PK, P2PKH, P2WPKH, and P2SH-P2WPKH
 469      const auto& add_pubkey = [&candidate_spks](const CPubKey& pub) -> void {
 470          candidate_spks.insert(GetScriptForRawPubKey(pub));
 471          candidate_spks.insert(GetScriptForDestination(PKHash(pub)));
 472  
 473          CScript wpkh = GetScriptForDestination(WitnessV0KeyHash(pub));
 474          candidate_spks.insert(wpkh);
 475          candidate_spks.insert(GetScriptForDestination(ScriptHash(wpkh)));
 476      };
 477      for (const auto& [_, key] : mapKeys) {
 478          add_pubkey(key.GetPubKey());
 479      }
 480      for (const auto& [_, ckeypair] : mapCryptedKeys) {
 481          add_pubkey(ckeypair.first);
 482      }
 483  
 484      // mapScripts contains all redeemScripts and witnessScripts. Therefore each script in it has
 485      // itself, P2SH, P2WSH, and P2SH-P2WSH as a candidate.
 486      // Invalid scripts such as P2SH-P2SH and P2WSH-P2SH, among others, will be added as candidates.
 487      // Callers of this function will need to remove such scripts.
 488      const auto& add_script = [&candidate_spks](const CScript& script) -> void {
 489          candidate_spks.insert(script);
 490          candidate_spks.insert(GetScriptForDestination(ScriptHash(script)));
 491  
 492          CScript wsh = GetScriptForDestination(WitnessV0ScriptHash(script));
 493          candidate_spks.insert(wsh);
 494          candidate_spks.insert(GetScriptForDestination(ScriptHash(wsh)));
 495      };
 496      for (const auto& [_, script] : mapScripts) {
 497          add_script(script);
 498      }
 499  
 500      // Although setWatchOnly should only contain output scripts, we will also include each script's
 501      // P2SH, P2WSH, and P2SH-P2WSH as a precaution.
 502      for (const auto& script : setWatchOnly) {
 503          add_script(script);
 504      }
 505  
 506      return candidate_spks;
 507  }
 508  
 509  std::unordered_set<CScript, SaltedSipHasher> LegacyDataSPKM::GetScriptPubKeys() const
 510  {
 511      // Run IsMine() on each candidate output script. Any script that IsMine is an output
 512      // script to return.
 513      // This both filters out things that are not watched by the wallet, and things that are invalid.
 514      std::unordered_set<CScript, SaltedSipHasher> spks;
 515      for (const CScript& script : GetCandidateScriptPubKeys()) {
 516          if (IsMine(script)) {
 517              spks.insert(script);
 518          }
 519      }
 520  
 521      return spks;
 522  }
 523  
 524  std::unordered_set<CScript, SaltedSipHasher> LegacyDataSPKM::GetNotMineScriptPubKeys() const
 525  {
 526      LOCK(cs_KeyStore);
 527      std::unordered_set<CScript, SaltedSipHasher> spks;
 528      for (const CScript& script : setWatchOnly) {
 529          if (!IsMine(script)) spks.insert(script);
 530      }
 531      return spks;
 532  }
 533  
 534  std::optional<MigrationData> LegacyDataSPKM::MigrateToDescriptor()
 535  {
 536      LOCK(cs_KeyStore);
 537      if (m_storage.IsLocked()) {
 538          return std::nullopt;
 539      }
 540  
 541      MigrationData out;
 542  
 543      std::unordered_set<CScript, SaltedSipHasher> spks{GetScriptPubKeys()};
 544  
 545      // Get all key ids
 546      std::set<CKeyID> keyids;
 547      for (const auto& key_pair : mapKeys) {
 548          keyids.insert(key_pair.first);
 549      }
 550      for (const auto& key_pair : mapCryptedKeys) {
 551          keyids.insert(key_pair.first);
 552      }
 553  
 554      // Get key metadata and figure out which keys don't have a seed
 555      // Note that we do not ignore the seeds themselves because they are considered IsMine!
 556      for (auto keyid_it = keyids.begin(); keyid_it != keyids.end();) {
 557          const CKeyID& keyid = *keyid_it;
 558          const auto& it = mapKeyMetadata.find(keyid);
 559          if (it != mapKeyMetadata.end()) {
 560              const CKeyMetadata& meta = it->second;
 561              if (meta.hdKeypath == "s" || meta.hdKeypath == "m") {
 562                  keyid_it++;
 563                  continue;
 564              }
 565              if (!meta.hd_seed_id.IsNull() && (m_hd_chain.seed_id == meta.hd_seed_id || m_inactive_hd_chains.contains(meta.hd_seed_id))) {
 566                  keyid_it = keyids.erase(keyid_it);
 567                  continue;
 568              }
 569          }
 570          keyid_it++;
 571      }
 572  
 573      WalletBatch batch(m_storage.GetDatabase());
 574      if (!batch.TxnBegin()) {
 575          LogWarning("Error generating descriptors for migration, cannot initialize db transaction");
 576          return std::nullopt;
 577      }
 578  
 579      // keyids is now all non-HD keys. Each key will have its own combo descriptor
 580      for (const CKeyID& keyid : keyids) {
 581          CKey key;
 582          if (!GetKey(keyid, key)) {
 583              assert(false);
 584          }
 585  
 586          // Get birthdate from key meta
 587          uint64_t creation_time = 0;
 588          const auto& it = mapKeyMetadata.find(keyid);
 589          if (it != mapKeyMetadata.end()) {
 590              creation_time = it->second.nCreateTime;
 591          }
 592  
 593          // Get the key origin
 594          // Maybe this doesn't matter because floating keys here shouldn't have origins
 595          KeyOriginInfo info;
 596          bool has_info = GetKeyOrigin(keyid, info);
 597          std::string origin_str = has_info ? "[" + HexStr(info.fingerprint) + FormatHDKeypath(info.path) + "]" : "";
 598  
 599          // Construct the combo descriptor
 600          std::string desc_str = "combo(" + origin_str + HexStr(key.GetPubKey()) + ")";
 601          FlatSigningProvider provider;
 602          std::string error;
 603          std::vector<std::unique_ptr<Descriptor>> descs = Parse(desc_str, provider, error, false);
 604          CHECK_NONFATAL(descs.size() == 1); // It shouldn't be possible to have an invalid or multipath descriptor
 605          WalletDescriptor w_desc(std::move(descs.at(0)), creation_time, 0, 0, 0);
 606  
 607          // Make the DescriptorScriptPubKeyMan and get the scriptPubKeys
 608          provider.keys.emplace(key.GetPubKey().GetID(), key);
 609          auto desc_spk_man = DescriptorScriptPubKeyMan::CreateFromMigration(m_storage, batch, w_desc, /*keypool_size=*/0, provider);
 610          auto desc_spks = desc_spk_man->GetScriptPubKeys();
 611  
 612          // Remove the scriptPubKeys from our current set
 613          for (const CScript& spk : desc_spks) {
 614              size_t erased = spks.erase(spk);
 615              assert(erased == 1);
 616              assert(IsMine(spk));
 617          }
 618  
 619          out.desc_spkms.push_back(std::move(desc_spk_man));
 620      }
 621  
 622      // Handle HD keys by using the CHDChains
 623      std::set<CHDChain> chains;
 624      chains.insert(m_hd_chain);
 625      for (const auto& chain_pair : m_inactive_hd_chains) {
 626          chains.insert(chain_pair.second);
 627      }
 628  
 629      bool can_support_hd_split_feature = m_hd_chain.nVersion >= CHDChain::VERSION_HD_CHAIN_SPLIT;
 630  
 631      std::set<CExtPubKey> master_xpubs;
 632      for (const CHDChain& chain : chains) {
 633          if (chain.seed_id.IsNull()) continue;
 634  
 635          // Get the master xprv
 636          CKey seed_key;
 637          if (!GetKey(chain.seed_id, seed_key)) {
 638              assert(false);
 639          }
 640          CExtKey master_key;
 641          master_key.SetSeed(seed_key);
 642  
 643          // Get the xpub and verify that we haven't already seen this xpub before
 644          CExtPubKey master_xpub = master_key.Neuter();
 645          const auto& [_, inserted] = master_xpubs.insert(master_xpub);
 646          if (!inserted) continue;
 647  
 648          for (int i = 0; i < 2; ++i) {
 649              // Skip if doing internal chain and split chain is not supported
 650              if (i == 1 && !can_support_hd_split_feature) {
 651                  continue;
 652              }
 653  
 654              // Make the combo descriptor
 655              std::string xpub = EncodeExtPubKey(master_key.Neuter());
 656              std::string desc_str = "combo(" + xpub + "/0h/" + ToString(i) + "h/*h)";
 657              FlatSigningProvider provider;
 658              std::string error;
 659              std::vector<std::unique_ptr<Descriptor>> descs = Parse(desc_str, provider, error, false);
 660              CHECK_NONFATAL(descs.size() == 1); // It shouldn't be possible to have an invalid or multipath descriptor
 661              uint32_t chain_counter = std::max((i == 1 ? chain.nInternalChainCounter : chain.nExternalChainCounter), (uint32_t)0);
 662              WalletDescriptor w_desc(std::move(descs.at(0)), 0, 0, chain_counter, 0);
 663  
 664              // Make the DescriptorScriptPubKeyMan and get the scriptPubKeys
 665              provider.keys.emplace(master_key.key.GetPubKey().GetID(), master_key.key);
 666              auto desc_spk_man = DescriptorScriptPubKeyMan::CreateFromMigration(m_storage, batch, w_desc, /*keypool_size=*/0, provider);
 667              auto desc_spks = desc_spk_man->GetScriptPubKeys();
 668  
 669              // Remove the scriptPubKeys from our current set
 670              for (const CScript& spk : desc_spks) {
 671                  size_t erased = spks.erase(spk);
 672                  assert(erased == 1);
 673                  assert(IsMine(spk));
 674              }
 675  
 676              out.desc_spkms.push_back(std::move(desc_spk_man));
 677          }
 678      }
 679      // Add the current master seed to the migration data
 680      if (!m_hd_chain.seed_id.IsNull()) {
 681          CKey seed_key;
 682          if (!GetKey(m_hd_chain.seed_id, seed_key)) {
 683              assert(false);
 684          }
 685          out.master_key.SetSeed(seed_key);
 686      }
 687  
 688      // Handle the rest of the scriptPubKeys which must be imports and may not have all info
 689      for (auto it = spks.begin(); it != spks.end();) {
 690          const CScript& spk = *it;
 691  
 692          // Get birthdate from script meta
 693          uint64_t creation_time = 0;
 694          const auto& mit = m_script_metadata.find(CScriptID(spk));
 695          if (mit != m_script_metadata.end()) {
 696              creation_time = mit->second.nCreateTime;
 697          }
 698  
 699          // InferDescriptor as that will get us all the solving info if it is there
 700          std::unique_ptr<Descriptor> desc = InferDescriptor(spk, *GetSolvingProvider(spk));
 701  
 702          // Past bugs in InferDescriptor have caused it to create descriptors which cannot be re-parsed.
 703          // Re-parse the descriptors to detect that, and skip any that do not parse.
 704          {
 705              std::string desc_str = desc->ToString();
 706              FlatSigningProvider parsed_keys;
 707              std::string parse_error;
 708              std::vector<std::unique_ptr<Descriptor>> parsed_descs = Parse(desc_str, parsed_keys, parse_error);
 709              if (parsed_descs.empty()) {
 710                  // Remove this scriptPubKey from the set
 711                  it = spks.erase(it);
 712                  continue;
 713              }
 714          }
 715  
 716          // Get the private keys for this descriptor
 717          std::vector<CScript> scripts;
 718          FlatSigningProvider keys;
 719          if (!desc->Expand(0, DUMMY_SIGNING_PROVIDER, scripts, keys)) {
 720              assert(false);
 721          }
 722          std::set<CKeyID> privkeyids;
 723          for (const auto& key_orig_pair : keys.origins) {
 724              privkeyids.insert(key_orig_pair.first);
 725          }
 726  
 727          std::vector<CScript> desc_spks;
 728  
 729          // If we can't provide all private keys for this inferred descriptor,
 730          // but this wallet is not watch-only, migrate it to the watch-only wallet.
 731          if (!desc->HavePrivateKeys(*this) && !m_storage.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
 732              out.watch_descs.emplace_back(desc->ToString(), creation_time);
 733  
 734              // Get the scriptPubKeys without writing this to the wallet
 735              FlatSigningProvider provider;
 736              desc->Expand(0, provider, desc_spks, provider);
 737          } else {
 738              // Make the DescriptorScriptPubKeyMan and get the scriptPubKeys
 739              for (const auto& keyid : privkeyids) {
 740                  CKey key;
 741                  if (!GetKey(keyid, key)) {
 742                      continue;
 743                  }
 744                  keys.keys.emplace(key.GetPubKey().GetID(), key);
 745              }
 746              WalletDescriptor w_desc(std::move(desc), creation_time, 0, 0, 0);
 747              auto desc_spk_man = DescriptorScriptPubKeyMan::CreateFromMigration(m_storage, batch, w_desc, /*keypool_size=*/0, keys);
 748              auto desc_spks_set = desc_spk_man->GetScriptPubKeys();
 749              desc_spks.insert(desc_spks.end(), desc_spks_set.begin(), desc_spks_set.end());
 750  
 751              out.desc_spkms.push_back(std::move(desc_spk_man));
 752          }
 753  
 754          // Remove the scriptPubKeys from our current set
 755          for (const CScript& desc_spk : desc_spks) {
 756              auto del_it = spks.find(desc_spk);
 757              assert(del_it != spks.end());
 758              assert(IsMine(desc_spk));
 759              it = spks.erase(del_it);
 760          }
 761      }
 762  
 763      // Make sure that we have accounted for all scriptPubKeys
 764      if (!Assume(spks.empty())) {
 765          LogError("%s", STR_INTERNAL_BUG("Error: Some output scripts were not migrated."));
 766          return std::nullopt;
 767      }
 768  
 769      // Legacy wallets can also contain scripts whose P2SH, P2WSH, or P2SH-P2WSH it is not watching for
 770      // but can provide script data to a PSBT spending them. These "solvable" output scripts will need to
 771      // be put into the separate "solvables" wallet.
 772      // These can be detected by going through the entire candidate output scripts, finding the not IsMine scripts,
 773      // and checking CanProvide() which will dummy sign.
 774      for (const CScript& script : GetCandidateScriptPubKeys()) {
 775          // Since we only care about P2SH, P2WSH, and P2SH-P2WSH, filter out any scripts that are not those
 776          if (!script.IsPayToScriptHash() && !script.IsPayToWitnessScriptHash()) {
 777              continue;
 778          }
 779          if (IsMine(script)) {
 780              continue;
 781          }
 782          SignatureData dummy_sigdata;
 783          if (!CanProvide(script, dummy_sigdata)) {
 784              continue;
 785          }
 786  
 787          // Get birthdate from script meta
 788          uint64_t creation_time = 0;
 789          const auto& it = m_script_metadata.find(CScriptID(script));
 790          if (it != m_script_metadata.end()) {
 791              creation_time = it->second.nCreateTime;
 792          }
 793  
 794          // InferDescriptor as that will get us all the solving info if it is there
 795          std::unique_ptr<Descriptor> desc = InferDescriptor(script, *GetSolvingProvider(script));
 796          if (!desc->IsSolvable()) {
 797              // The wallet was able to provide some information, but not enough to make a descriptor that actually
 798              // contains anything useful. This is probably because the script itself is actually unsignable (e.g. P2WSH-P2WSH).
 799              continue;
 800          }
 801  
 802          // Past bugs in InferDescriptor have caused it to create descriptors which cannot be re-parsed
 803          // Re-parse the descriptors to detect that, and skip any that do not parse.
 804          {
 805              std::string desc_str = desc->ToString();
 806              FlatSigningProvider parsed_keys;
 807              std::string parse_error;
 808              std::vector<std::unique_ptr<Descriptor>> parsed_descs = Parse(desc_str, parsed_keys, parse_error, false);
 809              if (parsed_descs.empty()) {
 810                  continue;
 811              }
 812          }
 813  
 814          out.solvable_descs.emplace_back(desc->ToString(), creation_time);
 815      }
 816  
 817      // Finalize transaction
 818      if (!batch.TxnCommit()) {
 819          LogWarning("Error generating descriptors for migration, cannot commit db transaction");
 820          return std::nullopt;
 821      }
 822  
 823      return out;
 824  }
 825  
 826  bool LegacyDataSPKM::DeleteRecordsWithDB(WalletBatch& batch)
 827  {
 828      LOCK(cs_KeyStore);
 829      return batch.EraseRecords(DBKeys::LEGACY_TYPES);
 830  }
 831  
 832  std::unique_ptr<DescriptorScriptPubKeyMan> DescriptorScriptPubKeyMan::CreateFromImport(WalletStorage& storage, WalletDescriptor& descriptor, int64_t keypool_size, const FlatSigningProvider& provider)
 833  {
 834      auto spkm = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(storage, descriptor, keypool_size));
 835      LOCK(spkm->cs_desc_man);
 836      WalletBatch batch(storage.GetDatabase());
 837      spkm->UpdateWithSigningProvider(batch, provider);
 838      return spkm;
 839  }
 840  
 841  std::unique_ptr<DescriptorScriptPubKeyMan> DescriptorScriptPubKeyMan::CreateFromMigration(WalletStorage& storage, WalletBatch& batch, WalletDescriptor& descriptor, int64_t keypool_size, const FlatSigningProvider& provider)
 842  {
 843      auto spkm = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(storage, descriptor, keypool_size));
 844      LOCK(spkm->cs_desc_man);
 845      spkm->UpdateWithSigningProvider(batch, provider);
 846      return spkm;
 847  }
 848  
 849  DescriptorScriptPubKeyMan::DescriptorScriptPubKeyMan(WalletStorage& storage, WalletDescriptor& descriptor, int64_t keypool_size, const KeyMap& keys, const CryptedKeyMap& ckeys)
 850      : ScriptPubKeyMan(storage),
 851      m_map_keys(keys),
 852      m_map_crypted_keys(ckeys),
 853      m_keypool_size(keypool_size),
 854      m_wallet_descriptor(descriptor)
 855  {
 856      if (!keys.empty() && !ckeys.empty()) {
 857          throw std::runtime_error("Wallet contains both unencrypted and encrypted keys");
 858      }
 859      Load();
 860  }
 861  
 862  std::unique_ptr<DescriptorScriptPubKeyMan> DescriptorScriptPubKeyMan::LoadFromStorage(WalletStorage& storage, WalletDescriptor& descriptor, int64_t keypool_size, const KeyMap& keys, const CryptedKeyMap& ckeys)
 863  {
 864      return std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(storage, descriptor, keypool_size, keys, ckeys));
 865  }
 866  
 867  std::unique_ptr<DescriptorScriptPubKeyMan> DescriptorScriptPubKeyMan::GenerateNewSingleSig(WalletStorage& storage, WalletBatch& batch, int64_t keypool_size, const CExtKey& master_key, OutputType addr_type, bool internal)
 868  {
 869      auto spkm = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(storage, keypool_size));
 870      spkm->SetupDescriptorGeneration(batch, master_key, addr_type, internal);
 871      return spkm;
 872  }
 873  
 874  util::Result<CTxDestination> DescriptorScriptPubKeyMan::GetNewDestination(const OutputType type)
 875  {
 876      // Returns true if this descriptor supports getting new addresses. Conditions where we may be unable to fetch them (e.g. locked) are caught later
 877      if (!CanGetAddresses()) {
 878          return util::Error{_("No addresses available")};
 879      }
 880      {
 881          LOCK(cs_desc_man);
 882          assert(m_wallet_descriptor.descriptor->IsSingleType()); // This is a combo descriptor which should not be an active descriptor
 883          std::optional<OutputType> desc_addr_type = m_wallet_descriptor.descriptor->GetOutputType();
 884          assert(desc_addr_type);
 885          if (type != *desc_addr_type) {
 886              throw std::runtime_error(std::string(__func__) + ": Types are inconsistent. Stored type does not match type of newly generated address");
 887          }
 888  
 889          TopUp();
 890  
 891          // Get the scriptPubKey from the descriptor
 892          FlatSigningProvider out_keys;
 893          std::vector<CScript> scripts_temp;
 894          if (m_wallet_descriptor.range_end <= m_max_cached_index && !TopUp(1)) {
 895              // We can't generate anymore keys
 896              return util::Error{_("Error: Keypool ran out, please call keypoolrefill first")};
 897          }
 898          if (!m_wallet_descriptor.descriptor->ExpandFromCache(m_wallet_descriptor.next_index, m_wallet_descriptor.cache, scripts_temp, out_keys)) {
 899              // We can't generate anymore keys
 900              return util::Error{_("Error: Keypool ran out, please call keypoolrefill first")};
 901          }
 902  
 903          CTxDestination dest;
 904          if (!ExtractDestination(scripts_temp[0], dest)) {
 905              return util::Error{_("Error: Cannot extract destination from the generated scriptpubkey")}; // shouldn't happen
 906          }
 907          m_wallet_descriptor.next_index++;
 908          WalletBatch(m_storage.GetDatabase()).WriteDescriptor(GetID(), m_wallet_descriptor);
 909          return dest;
 910      }
 911  }
 912  
 913  bool DescriptorScriptPubKeyMan::IsMine(const CScript& script) const
 914  {
 915      LOCK(cs_desc_man);
 916      return m_map_script_pub_keys.contains(script);
 917  }
 918  
 919  bool DescriptorScriptPubKeyMan::CheckDecryptionKey(const CKeyingMaterial& master_key)
 920  {
 921      LOCK(cs_desc_man);
 922      if (!m_map_keys.empty()) {
 923          return false;
 924      }
 925  
 926      bool keyPass = m_map_crypted_keys.empty(); // Always pass when there are no encrypted keys
 927      bool keyFail = false;
 928      for (const auto& mi : m_map_crypted_keys) {
 929          const CPubKey &pubkey = mi.second.first;
 930          const std::vector<unsigned char> &crypted_secret = mi.second.second;
 931          CKey key;
 932          if (!DecryptKey(master_key, crypted_secret, pubkey, key)) {
 933              keyFail = true;
 934              break;
 935          }
 936          keyPass = true;
 937          if (m_decryption_thoroughly_checked)
 938              break;
 939      }
 940      if (keyPass && keyFail) {
 941          LogWarning("The wallet is probably corrupted: Some keys decrypt but not all.");
 942          throw std::runtime_error("Error unlocking wallet: some keys decrypt but not all. Your wallet file may be corrupt.");
 943      }
 944      if (keyFail || !keyPass) {
 945          return false;
 946      }
 947      m_decryption_thoroughly_checked = true;
 948      return true;
 949  }
 950  
 951  bool DescriptorScriptPubKeyMan::Encrypt(const CKeyingMaterial& master_key, WalletBatch* batch)
 952  {
 953      LOCK(cs_desc_man);
 954      if (!m_map_crypted_keys.empty()) {
 955          return false;
 956      }
 957  
 958      for (const KeyMap::value_type& key_in : m_map_keys)
 959      {
 960          const CKey &key = key_in.second;
 961          CPubKey pubkey = key.GetPubKey();
 962          CKeyingMaterial secret{UCharCast(key.begin()), UCharCast(key.end())};
 963          std::vector<unsigned char> crypted_secret;
 964          if (!EncryptSecret(master_key, secret, pubkey.GetHash(), crypted_secret)) {
 965              return false;
 966          }
 967          m_map_crypted_keys[pubkey.GetID()] = make_pair(pubkey, crypted_secret);
 968          batch->WriteCryptedDescriptorKey(GetID(), pubkey, crypted_secret);
 969      }
 970      m_map_keys.clear();
 971      return true;
 972  }
 973  
 974  util::Result<CTxDestination> DescriptorScriptPubKeyMan::GetReservedDestination(const OutputType type, bool internal, int64_t& index)
 975  {
 976      LOCK(cs_desc_man);
 977      auto op_dest = GetNewDestination(type);
 978      index = m_wallet_descriptor.next_index - 1;
 979      return op_dest;
 980  }
 981  
 982  void DescriptorScriptPubKeyMan::ReturnDestination(int64_t index, bool internal, const CTxDestination& addr)
 983  {
 984      LOCK(cs_desc_man);
 985      // Only return when the index was the most recent
 986      if (m_wallet_descriptor.next_index - 1 == index) {
 987          m_wallet_descriptor.next_index--;
 988      }
 989      WalletBatch(m_storage.GetDatabase()).WriteDescriptor(GetID(), m_wallet_descriptor);
 990      NotifyCanGetAddressesChanged();
 991  }
 992  
 993  std::map<CKeyID, CKey> DescriptorScriptPubKeyMan::GetKeys() const
 994  {
 995      AssertLockHeld(cs_desc_man);
 996      if (m_storage.HasEncryptionKeys() && !m_storage.IsLocked()) {
 997          KeyMap keys;
 998          for (const auto& key_pair : m_map_crypted_keys) {
 999              const CPubKey& pubkey = key_pair.second.first;
1000              const std::vector<unsigned char>& crypted_secret = key_pair.second.second;
1001              CKey key;
1002              m_storage.WithEncryptionKey([&](const CKeyingMaterial& encryption_key) {
1003                  return DecryptKey(encryption_key, crypted_secret, pubkey, key);
1004              });
1005              keys[pubkey.GetID()] = key;
1006          }
1007          return keys;
1008      }
1009      return m_map_keys;
1010  }
1011  
1012  bool DescriptorScriptPubKeyMan::HasPrivKey(const CKeyID& keyid) const
1013  {
1014      AssertLockHeld(cs_desc_man);
1015      return m_map_keys.contains(keyid) || m_map_crypted_keys.contains(keyid);
1016  }
1017  
1018  std::optional<CKey> DescriptorScriptPubKeyMan::GetKey(const CKeyID& keyid) const
1019  {
1020      AssertLockHeld(cs_desc_man);
1021      if (m_storage.HasEncryptionKeys() && !m_storage.IsLocked()) {
1022          const auto& it = m_map_crypted_keys.find(keyid);
1023          if (it == m_map_crypted_keys.end()) {
1024              return std::nullopt;
1025          }
1026          const std::vector<unsigned char>& crypted_secret = it->second.second;
1027          CKey key;
1028          if (!Assume(m_storage.WithEncryptionKey([&](const CKeyingMaterial& encryption_key) {
1029              return DecryptKey(encryption_key, crypted_secret, it->second.first, key);
1030          }))) {
1031              return std::nullopt;
1032          }
1033          return key;
1034      }
1035      const auto& it = m_map_keys.find(keyid);
1036      if (it == m_map_keys.end()) {
1037          return std::nullopt;
1038      }
1039      return it->second;
1040  }
1041  
1042  bool DescriptorScriptPubKeyMan::TopUp(unsigned int size)
1043  {
1044      WalletBatch batch(m_storage.GetDatabase());
1045      if (!batch.TxnBegin()) return false;
1046      bool res = TopUpWithDB(batch, size);
1047      if (!batch.TxnCommit()) throw std::runtime_error(strprintf("Error during descriptors keypool top up. Cannot commit changes for wallet [%s]", m_storage.LogName()));
1048      return res;
1049  }
1050  
1051  bool DescriptorScriptPubKeyMan::TopUpWithDB(WalletBatch& batch, unsigned int size)
1052  {
1053      LOCK(cs_desc_man);
1054      std::set<CScript> new_spks;
1055      unsigned int target_size;
1056      if (size > 0) {
1057          target_size = size;
1058      } else {
1059          target_size = m_keypool_size;
1060      }
1061  
1062      // Calculate the new range_end
1063      int32_t new_range_end = std::max(m_wallet_descriptor.next_index + (int32_t)target_size, m_wallet_descriptor.range_end);
1064  
1065      // If the descriptor is not ranged, we actually just want to fill the first cache item
1066      if (!m_wallet_descriptor.descriptor->IsRange()) {
1067          new_range_end = 1;
1068          m_wallet_descriptor.range_end = 1;
1069          m_wallet_descriptor.range_start = 0;
1070      }
1071  
1072      FlatSigningProvider provider;
1073      provider.keys = GetKeys();
1074  
1075      uint256 id = GetID();
1076      for (int32_t i = m_max_cached_index + 1; i < new_range_end; ++i) {
1077          FlatSigningProvider out_keys;
1078          std::vector<CScript> scripts_temp;
1079          DescriptorCache temp_cache;
1080          // Maybe we have a cached xpub and we can expand from the cache first
1081          if (!m_wallet_descriptor.descriptor->ExpandFromCache(i, m_wallet_descriptor.cache, scripts_temp, out_keys)) {
1082              if (!m_wallet_descriptor.descriptor->Expand(i, provider, scripts_temp, out_keys, &temp_cache)) return false;
1083          }
1084          // Add all of the scriptPubKeys to the scriptPubKey set
1085          new_spks.insert(scripts_temp.begin(), scripts_temp.end());
1086          for (const CScript& script : scripts_temp) {
1087              m_map_script_pub_keys[script] = i;
1088          }
1089          for (const auto& pk_pair : out_keys.pubkeys) {
1090              const CPubKey& pubkey = pk_pair.second;
1091              if (m_map_pubkeys.contains(pubkey)) {
1092                  // We don't need to give an error here.
1093                  // It doesn't matter which of many valid indexes the pubkey has, we just need an index where we can derive it and its private key
1094                  continue;
1095              }
1096              m_map_pubkeys[pubkey] = i;
1097          }
1098          // Merge and write the cache
1099          DescriptorCache new_items = m_wallet_descriptor.cache.MergeAndDiff(temp_cache);
1100          if (!batch.WriteDescriptorCacheItems(id, new_items)) {
1101              throw std::runtime_error(std::string(__func__) + ": writing cache items failed");
1102          }
1103          m_max_cached_index++;
1104      }
1105      m_wallet_descriptor.range_end = new_range_end;
1106      batch.WriteDescriptor(GetID(), m_wallet_descriptor);
1107  
1108      // By this point, the cache size should be the size of the entire range
1109      assert(m_wallet_descriptor.range_end - 1 == m_max_cached_index);
1110  
1111      m_storage.TopUpCallback(new_spks, this);
1112      NotifyCanGetAddressesChanged();
1113      return true;
1114  }
1115  
1116  std::vector<WalletDestination> DescriptorScriptPubKeyMan::MarkUnusedAddresses(const CScript& script)
1117  {
1118      LOCK(cs_desc_man);
1119      std::vector<WalletDestination> result;
1120      if (IsMine(script)) {
1121          int32_t index = m_map_script_pub_keys[script];
1122          if (index >= m_wallet_descriptor.next_index) {
1123              WalletLogPrintf("%s: Detected a used keypool item at index %d, mark all keypool items up to this item as used\n", __func__, index);
1124              auto out_keys = std::make_unique<FlatSigningProvider>();
1125              std::vector<CScript> scripts_temp;
1126              while (index >= m_wallet_descriptor.next_index) {
1127                  if (!m_wallet_descriptor.descriptor->ExpandFromCache(m_wallet_descriptor.next_index, m_wallet_descriptor.cache, scripts_temp, *out_keys)) {
1128                      throw std::runtime_error(std::string(__func__) + ": Unable to expand descriptor from cache");
1129                  }
1130                  CTxDestination dest;
1131                  ExtractDestination(scripts_temp[0], dest);
1132                  result.push_back({dest, std::nullopt});
1133                  m_wallet_descriptor.next_index++;
1134              }
1135          }
1136          if (!TopUp()) {
1137              WalletLogPrintf("%s: Topping up keypool failed (locked wallet)\n", __func__);
1138          }
1139      }
1140  
1141      return result;
1142  }
1143  
1144  void DescriptorScriptPubKeyMan::AddDescriptorKey(const CKey& key, const CPubKey &pubkey)
1145  {
1146      LOCK(cs_desc_man);
1147      WalletBatch batch(m_storage.GetDatabase());
1148      if (!AddDescriptorKeyWithDB(batch, key, pubkey)) {
1149          throw std::runtime_error(std::string(__func__) + ": writing descriptor private key failed");
1150      }
1151  }
1152  
1153  bool DescriptorScriptPubKeyMan::AddDescriptorKeyWithDB(WalletBatch& batch, const CKey& key, const CPubKey &pubkey)
1154  {
1155      AssertLockHeld(cs_desc_man);
1156      assert(!m_storage.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS));
1157  
1158      // Check if provided key already exists
1159      if (m_map_keys.contains(pubkey.GetID()) ||
1160          m_map_crypted_keys.contains(pubkey.GetID())) {
1161          return true;
1162      }
1163  
1164      if (m_storage.HasEncryptionKeys()) {
1165          if (m_storage.IsLocked()) {
1166              return false;
1167          }
1168  
1169          std::vector<unsigned char> crypted_secret;
1170          CKeyingMaterial secret{UCharCast(key.begin()), UCharCast(key.end())};
1171          if (!m_storage.WithEncryptionKey([&](const CKeyingMaterial& encryption_key) {
1172                  return EncryptSecret(encryption_key, secret, pubkey.GetHash(), crypted_secret);
1173              })) {
1174              return false;
1175          }
1176  
1177          m_map_crypted_keys[pubkey.GetID()] = make_pair(pubkey, crypted_secret);
1178          return batch.WriteCryptedDescriptorKey(GetID(), pubkey, crypted_secret);
1179      } else {
1180          m_map_keys[pubkey.GetID()] = key;
1181          return batch.WriteDescriptorKey(GetID(), pubkey, key.GetPrivKey());
1182      }
1183  }
1184  
1185  void DescriptorScriptPubKeyMan::SetupDescriptorGeneration(WalletBatch& batch, const CExtKey& master_key, OutputType addr_type, bool internal)
1186  {
1187      LOCK(cs_desc_man);
1188      Assert(m_storage.IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));
1189      Assert(!m_wallet_descriptor.descriptor);
1190  
1191      m_wallet_descriptor = GenerateWalletDescriptor(master_key.Neuter(), addr_type, internal);
1192  
1193      // Store the master private key, and descriptor
1194      if (!AddDescriptorKeyWithDB(batch, master_key.key, master_key.key.GetPubKey())) {
1195          throw std::runtime_error(std::string(__func__) + ": writing descriptor master private key failed");
1196      }
1197      if (!batch.WriteDescriptor(GetID(), m_wallet_descriptor)) {
1198          throw std::runtime_error(std::string(__func__) + ": writing descriptor failed");
1199      }
1200  
1201      // Set m_decryption_thoroughly_checked for encrypted wallets
1202      if (m_storage.HasEncryptionKeys()) {
1203          m_decryption_thoroughly_checked = true;
1204      }
1205  
1206      // TopUp
1207      TopUpWithDB(batch);
1208  
1209      m_storage.UnsetBlankWalletFlag(batch);
1210  }
1211  
1212  bool DescriptorScriptPubKeyMan::IsHDEnabled() const
1213  {
1214      LOCK(cs_desc_man);
1215      return m_wallet_descriptor.descriptor->IsRange();
1216  }
1217  
1218  bool DescriptorScriptPubKeyMan::CanGetAddresses(bool internal) const
1219  {
1220      // We can only give out addresses from descriptors that are single type (not combo), ranged,
1221      // and either have cached keys or can generate more keys (ignoring encryption)
1222      LOCK(cs_desc_man);
1223      return m_wallet_descriptor.descriptor->IsSingleType() &&
1224             m_wallet_descriptor.descriptor->IsRange() &&
1225             (HavePrivateKeys() || m_wallet_descriptor.next_index < m_wallet_descriptor.range_end || m_wallet_descriptor.descriptor->CanSelfExpand());
1226  }
1227  
1228  bool DescriptorScriptPubKeyMan::HavePrivateKeys() const
1229  {
1230      LOCK(cs_desc_man);
1231      return m_map_keys.size() > 0 || m_map_crypted_keys.size() > 0;
1232  }
1233  
1234  bool DescriptorScriptPubKeyMan::HaveCryptedKeys() const
1235  {
1236      LOCK(cs_desc_man);
1237      return !m_map_crypted_keys.empty();
1238  }
1239  
1240  unsigned int DescriptorScriptPubKeyMan::GetKeyPoolSize() const
1241  {
1242      LOCK(cs_desc_man);
1243      return m_wallet_descriptor.range_end - m_wallet_descriptor.next_index;
1244  }
1245  
1246  int64_t DescriptorScriptPubKeyMan::GetTimeFirstKey() const
1247  {
1248      LOCK(cs_desc_man);
1249      return m_wallet_descriptor.creation_time;
1250  }
1251  
1252  std::unique_ptr<FlatSigningProvider> DescriptorScriptPubKeyMan::GetSigningProvider(const CScript& script, bool include_private) const
1253  {
1254      LOCK(cs_desc_man);
1255  
1256      // Find the index of the script
1257      auto it = m_map_script_pub_keys.find(script);
1258      if (it == m_map_script_pub_keys.end()) {
1259          return nullptr;
1260      }
1261      int32_t index = it->second;
1262  
1263      return GetSigningProvider(index, include_private);
1264  }
1265  
1266  std::unique_ptr<FlatSigningProvider> DescriptorScriptPubKeyMan::GetSigningProvider(const CPubKey& pubkey) const
1267  {
1268      LOCK(cs_desc_man);
1269  
1270      // Find index of the pubkey
1271      auto it = m_map_pubkeys.find(pubkey);
1272      if (it == m_map_pubkeys.end()) {
1273          return nullptr;
1274      }
1275      int32_t index = it->second;
1276  
1277      // Always try to get the signing provider with private keys. This function should only be called during signing anyways
1278      std::unique_ptr<FlatSigningProvider> out = GetSigningProvider(index, true);
1279      if (!out->HaveKey(pubkey.GetID())) {
1280          return nullptr;
1281      }
1282      return out;
1283  }
1284  
1285  std::unique_ptr<FlatSigningProvider> DescriptorScriptPubKeyMan::GetSigningProvider(int32_t index, bool include_private) const
1286  {
1287      AssertLockHeld(cs_desc_man);
1288  
1289      std::unique_ptr<FlatSigningProvider> out_keys = std::make_unique<FlatSigningProvider>();
1290  
1291      // Fetch SigningProvider from cache to avoid re-deriving
1292      auto it = m_map_signing_providers.find(index);
1293      if (it != m_map_signing_providers.end()) {
1294          out_keys->Merge(FlatSigningProvider{it->second});
1295      } else {
1296          // Get the scripts, keys, and key origins for this script
1297          std::vector<CScript> scripts_temp;
1298          if (!m_wallet_descriptor.descriptor->ExpandFromCache(index, m_wallet_descriptor.cache, scripts_temp, *out_keys)) return nullptr;
1299  
1300          // Cache SigningProvider so we don't need to re-derive if we need this SigningProvider again
1301          m_map_signing_providers[index] = *out_keys;
1302      }
1303  
1304      if (HavePrivateKeys() && include_private) {
1305          FlatSigningProvider master_provider;
1306          master_provider.keys = GetKeys();
1307          m_wallet_descriptor.descriptor->ExpandPrivate(index, master_provider, *out_keys);
1308  
1309          // Always include musig_secnonces as this descriptor may have a participant private key
1310          // but not a musig() descriptor
1311          out_keys->musig2_secnonces = &m_musig2_secnonces;
1312      }
1313  
1314      return out_keys;
1315  }
1316  
1317  std::unique_ptr<SigningProvider> DescriptorScriptPubKeyMan::GetSolvingProvider(const CScript& script) const
1318  {
1319      return GetSigningProvider(script, false);
1320  }
1321  
1322  bool DescriptorScriptPubKeyMan::CanProvide(const CScript& script, SignatureData& sigdata)
1323  {
1324      return IsMine(script);
1325  }
1326  
1327  bool DescriptorScriptPubKeyMan::SignTransaction(CMutableTransaction& tx, const std::map<COutPoint, Coin>& coins, int sighash, std::map<int, bilingual_str>& input_errors) const
1328  {
1329      std::unique_ptr<FlatSigningProvider> keys = std::make_unique<FlatSigningProvider>();
1330      for (const auto& coin_pair : coins) {
1331          std::unique_ptr<FlatSigningProvider> coin_keys = GetSigningProvider(coin_pair.second.out.scriptPubKey, true);
1332          if (!coin_keys) {
1333              continue;
1334          }
1335          keys->Merge(std::move(*coin_keys));
1336      }
1337  
1338      return ::SignTransaction(tx, keys.get(), coins, {.sighash_type = sighash}, input_errors);
1339  }
1340  
1341  SigningResult DescriptorScriptPubKeyMan::SignMessage(const std::string& message, const PKHash& pkhash, std::string& str_sig) const
1342  {
1343      std::unique_ptr<FlatSigningProvider> keys = GetSigningProvider(GetScriptForDestination(pkhash), true);
1344      if (!keys) {
1345          return SigningResult::PRIVATE_KEY_NOT_AVAILABLE;
1346      }
1347  
1348      CKey key;
1349      if (!keys->GetKey(ToKeyID(pkhash), key)) {
1350          return SigningResult::PRIVATE_KEY_NOT_AVAILABLE;
1351      }
1352  
1353      if (!MessageSign(key, message, str_sig)) {
1354          return SigningResult::SIGNING_FAILED;
1355      }
1356      return SigningResult::OK;
1357  }
1358  
1359  std::optional<PSBTError> DescriptorScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& psbtx, const PrecomputedTransactionData& txdata, const common::PSBTFillOptions& options, int* n_signed) const
1360  {
1361      if (n_signed) {
1362          *n_signed = 0;
1363      }
1364      for (unsigned int i = 0; i < psbtx.inputs.size(); ++i) {
1365          PSBTInput& input = psbtx.inputs.at(i);
1366  
1367          if (PSBTInputSigned(input)) {
1368              continue;
1369          }
1370  
1371          // Get the scriptPubKey to know which SigningProvider to use
1372          CScript script;
1373          if (!input.witness_utxo.IsNull()) {
1374              script = input.witness_utxo.scriptPubKey;
1375          } else if (input.non_witness_utxo) {
1376              if (input.prev_out >= input.non_witness_utxo->vout.size()) {
1377                  return PSBTError::MISSING_INPUTS;
1378              }
1379              script = input.non_witness_utxo->vout[input.prev_out].scriptPubKey;
1380          } else {
1381              // There's no UTXO so we can just skip this now
1382              continue;
1383          }
1384  
1385          std::unique_ptr<FlatSigningProvider> keys = std::make_unique<FlatSigningProvider>();
1386          std::unique_ptr<FlatSigningProvider> script_keys = GetSigningProvider(script, /*include_private=*/options.sign);
1387          if (script_keys) {
1388              keys->Merge(std::move(*script_keys));
1389          } else {
1390              // Maybe there are pubkeys listed that we can sign for
1391              std::vector<CPubKey> pubkeys;
1392              pubkeys.reserve(input.hd_keypaths.size() + 2);
1393  
1394              // ECDSA Pubkeys
1395              for (const auto& [pk, _] : input.hd_keypaths) {
1396                  pubkeys.push_back(pk);
1397              }
1398  
1399              // Taproot output pubkey
1400              std::vector<std::vector<unsigned char>> sols;
1401              if (Solver(script, sols) == TxoutType::WITNESS_V1_TAPROOT) {
1402                  sols[0].insert(sols[0].begin(), 0x02);
1403                  pubkeys.emplace_back(sols[0]);
1404                  sols[0][0] = 0x03;
1405                  pubkeys.emplace_back(sols[0]);
1406              }
1407  
1408              // Taproot pubkeys
1409              for (const auto& pk_pair : input.m_tap_bip32_paths) {
1410                  const XOnlyPubKey& pubkey = pk_pair.first;
1411                  for (unsigned char prefix : {0x02, 0x03}) {
1412                      unsigned char b[33] = {prefix};
1413                      std::copy(pubkey.begin(), pubkey.end(), b + 1);
1414                      CPubKey fullpubkey;
1415                      fullpubkey.Set(b, b + 33);
1416                      pubkeys.push_back(fullpubkey);
1417                  }
1418              }
1419  
1420              for (const auto& pubkey : pubkeys) {
1421                  std::unique_ptr<FlatSigningProvider> pk_keys = GetSigningProvider(pubkey);
1422                  if (pk_keys) {
1423                      keys->Merge(std::move(*pk_keys));
1424                  }
1425              }
1426          }
1427  
1428          PSBTError res = SignPSBTInput(HidingSigningProvider(keys.get(), /*hide_secret=*/!options.sign, /*hide_origin=*/!options.bip32_derivs), psbtx, i, &txdata, options, /*out_sigdata=*/nullptr);
1429          if (res != PSBTError::OK && res != PSBTError::INCOMPLETE) {
1430              return res;
1431          }
1432  
1433          bool signed_one = PSBTInputSigned(input);
1434          if (n_signed && (signed_one || !options.sign)) {
1435              // If sign is false, we assume that we _could_ sign if we get here. This
1436              // will never have false negatives; it is hard to tell under what i
1437              // circumstances it could have false positives.
1438              (*n_signed)++;
1439          }
1440      }
1441  
1442      // Fill in the bip32 keypaths and redeemscripts for the outputs so that hardware wallets can identify change
1443      for (unsigned int i = 0; i < psbtx.outputs.size(); ++i) {
1444          std::unique_ptr<SigningProvider> keys = GetSolvingProvider(psbtx.outputs.at(i).script);
1445          if (!keys) {
1446              continue;
1447          }
1448          UpdatePSBTOutput(HidingSigningProvider(keys.get(), /*hide_secret=*/true, /*hide_origin=*/!options.bip32_derivs), psbtx, i);
1449      }
1450  
1451      return {};
1452  }
1453  
1454  std::unique_ptr<CKeyMetadata> DescriptorScriptPubKeyMan::GetMetadata(const CTxDestination& dest) const
1455  {
1456      std::unique_ptr<SigningProvider> provider = GetSigningProvider(GetScriptForDestination(dest));
1457      if (provider) {
1458          KeyOriginInfo orig;
1459          CKeyID key_id = GetKeyForDestination(*provider, dest);
1460          if (provider->GetKeyOrigin(key_id, orig)) {
1461              LOCK(cs_desc_man);
1462              std::unique_ptr<CKeyMetadata> meta = std::make_unique<CKeyMetadata>();
1463              meta->key_origin = orig;
1464              meta->has_key_origin = true;
1465              meta->nCreateTime = m_wallet_descriptor.creation_time;
1466              return meta;
1467          }
1468      }
1469      return nullptr;
1470  }
1471  
1472  uint256 DescriptorScriptPubKeyMan::GetID() const
1473  {
1474      LOCK(cs_desc_man);
1475      return m_wallet_descriptor.id;
1476  }
1477  
1478  void DescriptorScriptPubKeyMan::Load()
1479  {
1480      LOCK(cs_desc_man);
1481      std::set<CScript> new_spks;
1482      for (int32_t i = m_wallet_descriptor.range_start; i < m_wallet_descriptor.range_end; ++i) {
1483          FlatSigningProvider out_keys;
1484          std::vector<CScript> scripts_temp;
1485          if (!m_wallet_descriptor.descriptor->ExpandFromCache(i, m_wallet_descriptor.cache, scripts_temp, out_keys)) {
1486              throw std::runtime_error("Error: Unable to expand wallet descriptor from cache");
1487          }
1488          // Add all of the scriptPubKeys to the scriptPubKey set
1489          new_spks.insert(scripts_temp.begin(), scripts_temp.end());
1490          for (const CScript& script : scripts_temp) {
1491              if (m_map_script_pub_keys.contains(script)) {
1492                  throw std::runtime_error(strprintf("Error: Already loaded script at index %d as being at index %d", i, m_map_script_pub_keys[script]));
1493              }
1494              m_map_script_pub_keys[script] = i;
1495          }
1496          for (const auto& pk_pair : out_keys.pubkeys) {
1497              const CPubKey& pubkey = pk_pair.second;
1498              if (m_map_pubkeys.contains(pubkey)) {
1499                  // We don't need to give an error here.
1500                  // It doesn't matter which of many valid indexes the pubkey has, we just need an index where we can derive it and its private key
1501                  continue;
1502              }
1503              m_map_pubkeys[pubkey] = i;
1504          }
1505          m_max_cached_index++;
1506      }
1507      // Make sure the wallet knows about our new spks
1508      m_storage.TopUpCallback(new_spks, this);
1509  }
1510  
1511  bool DescriptorScriptPubKeyMan::HasWalletDescriptor(const WalletDescriptor& desc) const
1512  {
1513      LOCK(cs_desc_man);
1514      return !m_wallet_descriptor.id.IsNull() && !desc.id.IsNull() && m_wallet_descriptor.id == desc.id;
1515  }
1516  
1517  void DescriptorScriptPubKeyMan::WriteDescriptor()
1518  {
1519      LOCK(cs_desc_man);
1520      WalletBatch batch(m_storage.GetDatabase());
1521      if (!batch.WriteDescriptor(GetID(), m_wallet_descriptor)) {
1522          throw std::runtime_error(std::string(__func__) + ": writing descriptor failed");
1523      }
1524  }
1525  
1526  WalletDescriptor DescriptorScriptPubKeyMan::GetWalletDescriptor() const
1527  {
1528      return m_wallet_descriptor;
1529  }
1530  
1531  std::unordered_set<CScript, SaltedSipHasher> DescriptorScriptPubKeyMan::GetScriptPubKeys() const
1532  {
1533      return GetScriptPubKeys(0);
1534  }
1535  
1536  std::unordered_set<CScript, SaltedSipHasher> DescriptorScriptPubKeyMan::GetScriptPubKeys(int32_t minimum_index) const
1537  {
1538      LOCK(cs_desc_man);
1539      std::unordered_set<CScript, SaltedSipHasher> script_pub_keys;
1540      script_pub_keys.reserve(m_map_script_pub_keys.size());
1541  
1542      for (auto const& [script_pub_key, index] : m_map_script_pub_keys) {
1543          if (index >= minimum_index) script_pub_keys.insert(script_pub_key);
1544      }
1545      return script_pub_keys;
1546  }
1547  
1548  int32_t DescriptorScriptPubKeyMan::GetEndRange() const
1549  {
1550      return m_max_cached_index + 1;
1551  }
1552  
1553  bool DescriptorScriptPubKeyMan::GetDescriptorString(std::string& out, const bool priv) const
1554  {
1555      LOCK(cs_desc_man);
1556  
1557      FlatSigningProvider provider;
1558      provider.keys = GetKeys();
1559  
1560      if (priv) {
1561          // For the private version, always return the master key to avoid
1562          // exposing child private keys. The risk implications of exposing child
1563          // private keys together with the parent xpub may be non-obvious for users.
1564          return m_wallet_descriptor.descriptor->ToPrivateString(provider, out);
1565      }
1566  
1567      return m_wallet_descriptor.descriptor->ToNormalizedString(provider, out, &m_wallet_descriptor.cache);
1568  }
1569  
1570  void DescriptorScriptPubKeyMan::UpgradeDescriptorCache()
1571  {
1572      LOCK(cs_desc_man);
1573      if (m_storage.IsLocked() || m_storage.IsWalletFlagSet(WALLET_FLAG_LAST_HARDENED_XPUB_CACHED)) {
1574          return;
1575      }
1576  
1577      // Skip if we have the last hardened xpub cache
1578      if (m_wallet_descriptor.cache.GetCachedLastHardenedExtPubKeys().size() > 0) {
1579          return;
1580      }
1581  
1582      // Expand the descriptor
1583      FlatSigningProvider provider;
1584      provider.keys = GetKeys();
1585      FlatSigningProvider out_keys;
1586      std::vector<CScript> scripts_temp;
1587      DescriptorCache temp_cache;
1588      if (!m_wallet_descriptor.descriptor->Expand(0, provider, scripts_temp, out_keys, &temp_cache)){
1589          throw std::runtime_error("Unable to expand descriptor");
1590      }
1591  
1592      // Cache the last hardened xpubs
1593      DescriptorCache diff = m_wallet_descriptor.cache.MergeAndDiff(temp_cache);
1594      if (!WalletBatch(m_storage.GetDatabase()).WriteDescriptorCacheItems(GetID(), diff)) {
1595          throw std::runtime_error(std::string(__func__) + ": writing cache items failed");
1596      }
1597  }
1598  
1599  util::Result<void> DescriptorScriptPubKeyMan::UpdateWalletDescriptor(WalletDescriptor& descriptor, const FlatSigningProvider& provider)
1600  {
1601      LOCK(cs_desc_man);
1602      std::string error;
1603      if (!CanUpdateToWalletDescriptor(descriptor, error)) {
1604          return util::Error{Untranslated(std::move(error))};
1605      }
1606  
1607      m_map_pubkeys.clear();
1608      m_map_script_pub_keys.clear();
1609      m_max_cached_index = -1;
1610      m_wallet_descriptor = descriptor;
1611  
1612      WalletBatch batch(m_storage.GetDatabase());
1613      UpdateWithSigningProvider(batch, provider);
1614      NotifyFirstKeyTimeChanged(this, m_wallet_descriptor.creation_time);
1615      return {};
1616  }
1617  
1618  void DescriptorScriptPubKeyMan::UpdateWithSigningProvider(WalletBatch& batch, const FlatSigningProvider& signing_provider)
1619  {
1620      AssertLockHeld(cs_desc_man);
1621      // Add the private keys to the descriptor
1622      for (const auto& entry : signing_provider.keys) {
1623          const CKey& key = entry.second;
1624          if (!AddDescriptorKeyWithDB(batch, key, key.GetPubKey())) {
1625              throw std::runtime_error(std::string(__func__) + ": writing descriptor private key failed");
1626          }
1627      }
1628  
1629      // Top up key pool, to generate scriptPubKeys
1630      if (!TopUpWithDB(batch)) {
1631          throw std::runtime_error("Could not top up scriptPubKeys");
1632      }
1633  }
1634  
1635  bool DescriptorScriptPubKeyMan::CanUpdateToWalletDescriptor(const WalletDescriptor& descriptor, std::string& error)
1636  {
1637      LOCK(cs_desc_man);
1638      if (!HasWalletDescriptor(descriptor)) {
1639          error = "can only update matching descriptor";
1640          return false;
1641      }
1642  
1643      if (!descriptor.descriptor->IsRange()) {
1644          // Skip range check for non-range descriptors
1645          return true;
1646      }
1647  
1648      if (descriptor.range_start > m_wallet_descriptor.range_start ||
1649          descriptor.range_end < m_wallet_descriptor.range_end) {
1650          // Use inclusive range for error
1651          error = strprintf("new range must include current range = [%d,%d]",
1652                            m_wallet_descriptor.range_start,
1653                            m_wallet_descriptor.range_end - 1);
1654          return false;
1655      }
1656  
1657      return true;
1658  }
1659  } // namespace wallet
1660