// Copyright (c) 2016-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include #include #include #include #include #include namespace WalletTool { // The standard wallet deleter function blocks on the validation interface // queue, which doesn't exist for the bitcoin-wallet. Define our own // deleter here. static void WalletToolReleaseWallet(CWallet* wallet) { wallet->WalletLogPrintf("Releasing wallet\n"); wallet->Close(); delete wallet; } static void WalletCreate(CWallet* wallet_instance) { LOCK(wallet_instance->cs_wallet); wallet_instance->SetMinVersion(FEATURE_HD_SPLIT); // generate a new HD seed auto spk_man = wallet_instance->GetOrCreateLegacyScriptPubKeyMan(); CPubKey seed = spk_man->GenerateNewSeed(); spk_man->SetHDSeed(seed); tfm::format(std::cout, "Topping up keypool...\n"); wallet_instance->TopUpKeyPool(); } static std::shared_ptr MakeWallet(const std::string& name, const fs::path& path, bool create) { DatabaseOptions options; DatabaseStatus status; if (create) { options.require_create = true; } else { options.require_existing = true; } bilingual_str error; std::unique_ptr database = MakeDatabase(path, options, status, error); if (!database) { tfm::format(std::cerr, "%s\n", error.original); return nullptr; } // dummy chain interface std::shared_ptr wallet_instance{new CWallet(nullptr /* chain */, name, std::move(database)), WalletToolReleaseWallet}; DBErrors load_wallet_ret; try { bool first_run; load_wallet_ret = wallet_instance->LoadWallet(first_run); } catch (const std::runtime_error&) { tfm::format(std::cerr, "Error loading %s. Is wallet being used by another process?\n", name); return nullptr; } if (load_wallet_ret != DBErrors::LOAD_OK) { wallet_instance = nullptr; if (load_wallet_ret == DBErrors::CORRUPT) { tfm::format(std::cerr, "Error loading %s: Wallet corrupted", name); return nullptr; } else if (load_wallet_ret == DBErrors::NONCRITICAL_ERROR) { tfm::format(std::cerr, "Error reading %s! All keys read correctly, but transaction data" " or address book entries might be missing or incorrect.", name); } else if (load_wallet_ret == DBErrors::TOO_NEW) { tfm::format(std::cerr, "Error loading %s: Wallet requires newer version of %s", name, PACKAGE_NAME); return nullptr; } else if (load_wallet_ret == DBErrors::NEED_REWRITE) { tfm::format(std::cerr, "Wallet needed to be rewritten: restart %s to complete", PACKAGE_NAME); return nullptr; } else { tfm::format(std::cerr, "Error loading %s", name); return nullptr; } } if (create) WalletCreate(wallet_instance.get()); return wallet_instance; } static void WalletShowInfo(CWallet* wallet_instance) { LOCK(wallet_instance->cs_wallet); tfm::format(std::cout, "Wallet info\n===========\n"); tfm::format(std::cout, "Name: %s\n", wallet_instance->GetName()); tfm::format(std::cout, "Format: %s\n", wallet_instance->GetDatabase().Format()); tfm::format(std::cout, "Descriptors: %s\n", wallet_instance->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS) ? "yes" : "no"); tfm::format(std::cout, "Encrypted: %s\n", wallet_instance->IsCrypted() ? "yes" : "no"); tfm::format(std::cout, "HD (hd seed available): %s\n", wallet_instance->IsHDEnabled() ? "yes" : "no"); tfm::format(std::cout, "Keypool Size: %u\n", wallet_instance->GetKeyPoolSize()); tfm::format(std::cout, "Transactions: %zu\n", wallet_instance->mapWallet.size()); tfm::format(std::cout, "Address Book: %zu\n", wallet_instance->m_address_book.size()); } bool ExecuteWalletToolFunc(const std::string& command, const std::string& name) { fs::path path = fs::absolute(name, GetWalletDir()); if (command == "create") { std::shared_ptr wallet_instance = MakeWallet(name, path, /* create= */ true); if (wallet_instance) { WalletShowInfo(wallet_instance.get()); wallet_instance->Close(); } } else if (command == "info" || command == "salvage") { if (command == "info") { std::shared_ptr wallet_instance = MakeWallet(name, path, /* create= */ false); if (!wallet_instance) return false; WalletShowInfo(wallet_instance.get()); wallet_instance->Close(); } else if (command == "salvage") { bilingual_str error; std::vector warnings; bool ret = RecoverDatabaseFile(path, error, warnings); if (!ret) { for (const auto& warning : warnings) { tfm::format(std::cerr, "%s\n", warning.original); } if (!error.empty()) { tfm::format(std::cerr, "%s\n", error.original); } } return ret; } } else { tfm::format(std::cerr, "Invalid command: %s\n", command); return false; } return true; } } // namespace WalletTool