/ src / wallet / test / util.cpp
util.cpp
  1  // Copyright (c) 2021-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/test/util.h>
  6  
  7  #include <chain.h>
  8  #include <key.h>
  9  #include <key_io.h>
 10  #include <streams.h>
 11  #include <test/util/setup_common.h>
 12  #include <validationinterface.h>
 13  #include <wallet/context.h>
 14  #include <wallet/wallet.h>
 15  #include <wallet/walletdb.h>
 16  
 17  #include <sqlite3.h>
 18  
 19  #include <memory>
 20  
 21  namespace wallet {
 22  std::unique_ptr<CWallet> CreateSyncedWallet(interfaces::Chain& chain, CChain& cchain, const CKey& key)
 23  {
 24      auto wallet = std::make_unique<CWallet>(&chain, "", CreateMockableWalletDatabase());
 25      {
 26          LOCK2(wallet->cs_wallet, ::cs_main);
 27          wallet->SetLastBlockProcessed(cchain.Height(), cchain.Tip()->GetBlockHash());
 28      }
 29      {
 30          LOCK(wallet->cs_wallet);
 31          wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
 32          wallet->SetupDescriptorScriptPubKeyMans();
 33  
 34          FlatSigningProvider provider;
 35          std::string error;
 36          auto descs = Parse("combo(" + EncodeSecret(key) + ")", provider, error, /* require_checksum=*/ false);
 37          assert(descs.size() == 1);
 38          auto& desc = descs.at(0);
 39          WalletDescriptor w_desc(std::move(desc), 0, 0, 1, 1);
 40          Assert(wallet->AddWalletDescriptor(w_desc, provider, "", false));
 41      }
 42      WalletRescanReserver reserver(*wallet);
 43      reserver.reserve();
 44      CWallet::ScanResult result = wallet->ScanForWalletTransactions(cchain.Genesis()->GetBlockHash(), /*start_height=*/0, /*max_height=*/{}, reserver, /*fUpdate=*/false, /*save_progress=*/false);
 45      assert(result.status == CWallet::ScanResult::SUCCESS);
 46      assert(result.last_scanned_block == cchain.Tip()->GetBlockHash());
 47      assert(*result.last_scanned_height == cchain.Height());
 48      assert(result.last_failed_block.IsNull());
 49      return wallet;
 50  }
 51  
 52  std::shared_ptr<CWallet> TestCreateWallet(std::unique_ptr<WalletDatabase> database, WalletContext& context, uint64_t create_flags)
 53  {
 54      bilingual_str _error;
 55      std::vector<bilingual_str> _warnings;
 56      auto wallet = CWallet::CreateNew(context, "", std::move(database), create_flags, _error, _warnings);
 57      NotifyWalletLoaded(context, wallet);
 58      if (context.chain) {
 59          wallet->postInitProcess();
 60      }
 61      return wallet;
 62  }
 63  
 64  std::shared_ptr<CWallet> TestCreateWallet(WalletContext& context)
 65  {
 66      DatabaseOptions options;
 67      options.require_create = true;
 68      options.create_flags = WALLET_FLAG_DESCRIPTORS;
 69      DatabaseStatus status;
 70      bilingual_str error;
 71      std::vector<bilingual_str> warnings;
 72      auto database = MakeWalletDatabase("", options, status, error);
 73      return TestCreateWallet(std::move(database), context, options.create_flags);
 74  }
 75  
 76  
 77  std::shared_ptr<CWallet> TestLoadWallet(std::unique_ptr<WalletDatabase> database, WalletContext& context)
 78  {
 79      bilingual_str error;
 80      std::vector<bilingual_str> warnings;
 81      auto wallet = CWallet::LoadExisting(context, "", std::move(database), error, warnings);
 82      NotifyWalletLoaded(context, wallet);
 83      if (context.chain) {
 84          wallet->postInitProcess();
 85      }
 86      return wallet;
 87  }
 88  
 89  std::shared_ptr<CWallet> TestLoadWallet(WalletContext& context)
 90  {
 91      DatabaseOptions options;
 92      options.require_existing = true;
 93      DatabaseStatus status;
 94      bilingual_str error;
 95      std::vector<bilingual_str> warnings;
 96      auto database = MakeWalletDatabase("", options, status, error);
 97      return TestLoadWallet(std::move(database), context);
 98  }
 99  
100  void TestUnloadWallet(std::shared_ptr<CWallet>&& wallet)
101  {
102      // Calls SyncWithValidationInterfaceQueue
103      wallet->chain().waitForNotificationsIfTipChanged({});
104      wallet->m_chain_notifications_handler.reset();
105      WaitForDeleteWallet(std::move(wallet));
106  }
107  
108  std::unique_ptr<WalletDatabase> DuplicateMockDatabase(WalletDatabase& database)
109  {
110      std::unique_ptr<DatabaseBatch> batch_orig = database.MakeBatch();
111      std::unique_ptr<DatabaseCursor> cursor_orig = batch_orig->GetNewCursor();
112  
113      std::unique_ptr<WalletDatabase> new_db = CreateMockableWalletDatabase();
114      std::unique_ptr<DatabaseBatch> new_db_batch = new_db->MakeBatch();
115      MockableSQLiteBatch* batch_new = dynamic_cast<MockableSQLiteBatch*>(new_db_batch.get());
116      Assert(batch_new);
117  
118      while (true) {
119          DataStream key, value;
120          DatabaseCursor::Status status = cursor_orig->Next(key, value);
121          Assert(status != DatabaseCursor::Status::FAIL);
122          if (status != DatabaseCursor::Status::MORE) break;
123          batch_new->WriteKey(std::move(key), std::move(value));
124      }
125  
126      return new_db;
127  }
128  
129  std::string getnewaddress(CWallet& w)
130  {
131      constexpr auto output_type = OutputType::BECH32;
132      return EncodeDestination(getNewDestination(w, output_type));
133  }
134  
135  CTxDestination getNewDestination(CWallet& w, OutputType output_type)
136  {
137      return *Assert(w.GetNewDestination(output_type, ""));
138  }
139  
140  MockableSQLiteDatabase::MockableSQLiteDatabase()
141      : SQLiteDatabase(fs::PathFromString("mock/"), fs::PathFromString("mock/wallet.dat"), DatabaseOptions(), SQLITE_OPEN_MEMORY)
142  {}
143  
144  std::unique_ptr<WalletDatabase> CreateMockableWalletDatabase()
145  {
146      return std::make_unique<MockableSQLiteDatabase>();
147  }
148  
149  wallet::DescriptorScriptPubKeyMan* CreateDescriptor(CWallet& keystore, const std::string& desc_str, const bool success)
150  {
151      keystore.SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
152  
153      FlatSigningProvider keys;
154      std::string error;
155      auto parsed_descs = Parse(desc_str, keys, error, false);
156      Assert(success == (!parsed_descs.empty()));
157      if (!success) return nullptr;
158      auto& desc = parsed_descs.at(0);
159  
160      const int64_t range_start = 0, range_end = 1, next_index = 0, timestamp = 1;
161  
162      WalletDescriptor w_desc(std::move(desc), timestamp, range_start, range_end, next_index);
163  
164      LOCK(keystore.cs_wallet);
165      auto spkm = Assert(keystore.AddWalletDescriptor(w_desc, keys,/*label=*/"", /*internal=*/false));
166      return &spkm.value().get();
167  };
168  } // namespace wallet