| 43 | } |
| 44 | |
| 45 | util::Result<std::string> ExportWatchOnlyWallet(const CWallet& wallet, const fs::path& destination, WalletContext& context) |
| 46 | { |
| 47 | AssertLockHeld(wallet.cs_wallet); |
| 48 | |
| 49 | if (destination.empty()) { |
| 50 | return util::Error{_("Error: Export destination cannot be empty")}; |
| 51 | } |
| 52 | if (fs::exists(destination)) { |
| 53 | return util::Error{strprintf(_("Error: Export destination '%s' already exists"), fs::PathToString(destination))}; |
| 54 | } |
| 55 | if (!std::ofstream{fs::PathToString(destination)}) { |
| 56 | return util::Error{strprintf(_("Error: Could not create file '%s'"), fs::PathToString(destination))}; |
| 57 | } |
| 58 | bool success = false; |
| 59 | auto cleanup_destination = interfaces::MakeCleanupHandler([&success, &destination] { |
| 60 | if (!success) fs::remove(destination); |
| 61 | }); |
| 62 | |
| 63 | // Get the descriptors from this wallet |
| 64 | util::Expected<std::vector<WalletDescInfo>, std::string> exported = ExportDescriptors(wallet, /*export_private=*/false); |
| 65 | if (!exported) { |
| 66 | return util::Error{Untranslated(exported.error())}; |
| 67 | } |
| 68 | if (exported->empty()) { |
| 69 | return util::Error{_("Error: Wallet has no descriptors to export")}; |
| 70 | } |
| 71 | |
| 72 | // Setup DatabaseOptions to create a new sqlite database |
| 73 | DatabaseOptions options; |
| 74 | options.require_existing = false; |
| 75 | options.require_create = true; |
| 76 | options.require_format = DatabaseFormat::SQLITE; |
| 77 | |
| 78 | // Make the wallet with the same flags as this wallet, but without private keys |
| 79 | options.create_flags = wallet.GetWalletFlags() | WALLET_FLAG_DISABLE_PRIVATE_KEYS; |
| 80 | |
| 81 | // Make the watchonly wallet |
| 82 | DatabaseStatus status; |
| 83 | std::vector<bilingual_str> warnings; |
| 84 | std::string wallet_name = wallet.GetName() + "_watchonly_temp"; |
| 85 | bilingual_str error; |
| 86 | std::unique_ptr<WalletDatabase> database = MakeWalletDatabase(wallet_name, options, status, error); |
| 87 | if (!database) { |
| 88 | return util::Error{strprintf(_("Wallet file creation failed: %s"), error)}; |
| 89 | } |
| 90 | |
| 91 | // Always remove the temporary wallet files, even when returning early on error. |
| 92 | std::shared_ptr<CWallet> watchonly_wallet; |
| 93 | fs::path wallet_path = fs::PathFromString(database->Filename()).parent_path(); |
| 94 | std::vector<fs::path> cleanup_files = database->Files(); |
| 95 | auto cleanup_watchonly_wallet = interfaces::MakeCleanupHandler([&watchonly_wallet, &wallet_path, &cleanup_files] { |
| 96 | if (watchonly_wallet) watchonly_wallet.reset(); |
| 97 | for (const auto& file : cleanup_files) { |
| 98 | fs::remove(file); |
| 99 | } |
| 100 | fs::remove(wallet_path); |
| 101 | }); |
| 102 |
no test coverage detected