mirror of
https://github.com/Retropex/bitcoin.git
synced 2025-05-18 22:20:44 +02:00

9c1052a521
wallet: Default new wallets to descriptor wallets (Andrew Chow)f19ad40463
rpc, wallet: Descriptor wallets are no longer experimental (Andrew Chow) Pull request description: Changes the default wallet type from legacy to descriptors. Descriptor wallets will now by the default type. Additionally, descriptor wallets will no longer be marked as experimental. This follows the timeline proposed in #20160 ACKs for top commit: lsilva01: Tested ACK9c1052a521
on Ubuntu 20.04 prayank23: tACK9c1052a521
meshcollider: Code review ACK9c1052a521
Tree-SHA512: 834e6fec88e0c18673af7ebe135bd5333694d1be502164eb93a90e3e76c27974165aa4e59426945100c88e4eca07356e16886ef5b05cf789683ecb23fc71a12a
216 lines
8.9 KiB
C++
216 lines
8.9 KiB
C++
// 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 <fs.h>
|
|
#include <util/system.h>
|
|
#include <util/translation.h>
|
|
#include <wallet/dump.h>
|
|
#include <wallet/salvage.h>
|
|
#include <wallet/wallet.h>
|
|
#include <wallet/walletutil.h>
|
|
|
|
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, uint64_t wallet_creation_flags)
|
|
{
|
|
LOCK(wallet_instance->cs_wallet);
|
|
|
|
wallet_instance->SetMinVersion(FEATURE_HD_SPLIT);
|
|
wallet_instance->AddWalletFlags(wallet_creation_flags);
|
|
|
|
if (!wallet_instance->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
|
|
auto spk_man = wallet_instance->GetOrCreateLegacyScriptPubKeyMan();
|
|
spk_man->SetupGeneration(false);
|
|
} else {
|
|
wallet_instance->SetupDescriptorScriptPubKeyMans();
|
|
}
|
|
|
|
tfm::format(std::cout, "Topping up keypool...\n");
|
|
wallet_instance->TopUpKeyPool();
|
|
}
|
|
|
|
static std::shared_ptr<CWallet> MakeWallet(const std::string& name, const fs::path& path, DatabaseOptions options)
|
|
{
|
|
DatabaseStatus status;
|
|
bilingual_str error;
|
|
std::unique_ptr<WalletDatabase> database = MakeDatabase(path, options, status, error);
|
|
if (!database) {
|
|
tfm::format(std::cerr, "%s\n", error.original);
|
|
return nullptr;
|
|
}
|
|
|
|
// dummy chain interface
|
|
std::shared_ptr<CWallet> wallet_instance{new CWallet(nullptr /* chain */, name, std::move(database)), WalletToolReleaseWallet};
|
|
DBErrors load_wallet_ret;
|
|
try {
|
|
load_wallet_ret = wallet_instance->LoadWallet();
|
|
} 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 if (load_wallet_ret == DBErrors::NEED_RESCAN) {
|
|
tfm::format(std::cerr, "Error reading %s! Some transaction data might be missing or"
|
|
" incorrect. Wallet requires a rescan.",
|
|
name);
|
|
} else {
|
|
tfm::format(std::cerr, "Error loading %s", name);
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
if (options.require_create) WalletCreate(wallet_instance.get(), options.create_flags);
|
|
|
|
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 ArgsManager& args, const std::string& command)
|
|
{
|
|
if (args.IsArgSet("-format") && command != "createfromdump") {
|
|
tfm::format(std::cerr, "The -format option can only be used with the \"createfromdump\" command.\n");
|
|
return false;
|
|
}
|
|
if (args.IsArgSet("-dumpfile") && command != "dump" && command != "createfromdump") {
|
|
tfm::format(std::cerr, "The -dumpfile option can only be used with the \"dump\" and \"createfromdump\" commands.\n");
|
|
return false;
|
|
}
|
|
if (args.IsArgSet("-descriptors") && command != "create") {
|
|
tfm::format(std::cerr, "The -descriptors option can only be used with the 'create' command.\n");
|
|
return false;
|
|
}
|
|
if (args.IsArgSet("-legacy") && command != "create") {
|
|
tfm::format(std::cerr, "The -legacy option can only be used with the 'create' command.\n");
|
|
return false;
|
|
}
|
|
if (command == "create" && !args.IsArgSet("-wallet")) {
|
|
tfm::format(std::cerr, "Wallet name must be provided when creating a new wallet.\n");
|
|
return false;
|
|
}
|
|
const std::string name = args.GetArg("-wallet", "");
|
|
const fs::path path = fsbridge::AbsPathJoin(GetWalletDir(), fs::PathFromString(name));
|
|
|
|
if (command == "create") {
|
|
DatabaseOptions options;
|
|
options.require_create = true;
|
|
// If -legacy is set, use it. Otherwise default to false.
|
|
bool make_legacy = args.GetBoolArg("-legacy", false);
|
|
// If neither -legacy nor -descriptors is set, default to true. If -descriptors is set, use its value.
|
|
bool make_descriptors = (!args.IsArgSet("-descriptors") && !args.IsArgSet("-legacy")) || (args.IsArgSet("-descriptors") && args.GetBoolArg("-descriptors", true));
|
|
if (make_legacy && make_descriptors) {
|
|
tfm::format(std::cerr, "Only one of -legacy or -descriptors can be set to true, not both\n");
|
|
return false;
|
|
}
|
|
if (!make_legacy && !make_descriptors) {
|
|
tfm::format(std::cerr, "One of -legacy or -descriptors must be set to true (or omitted)\n");
|
|
return false;
|
|
}
|
|
if (make_descriptors) {
|
|
options.create_flags |= WALLET_FLAG_DESCRIPTORS;
|
|
options.require_format = DatabaseFormat::SQLITE;
|
|
}
|
|
|
|
std::shared_ptr<CWallet> wallet_instance = MakeWallet(name, path, options);
|
|
if (wallet_instance) {
|
|
WalletShowInfo(wallet_instance.get());
|
|
wallet_instance->Close();
|
|
}
|
|
} else if (command == "info") {
|
|
DatabaseOptions options;
|
|
options.require_existing = true;
|
|
std::shared_ptr<CWallet> wallet_instance = MakeWallet(name, path, options);
|
|
if (!wallet_instance) return false;
|
|
WalletShowInfo(wallet_instance.get());
|
|
wallet_instance->Close();
|
|
} else if (command == "salvage") {
|
|
#ifdef USE_BDB
|
|
bilingual_str error;
|
|
std::vector<bilingual_str> 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, "Salvage command is not available as BDB support is not compiled");
|
|
return false;
|
|
#endif
|
|
} else if (command == "dump") {
|
|
DatabaseOptions options;
|
|
options.require_existing = true;
|
|
std::shared_ptr<CWallet> wallet_instance = MakeWallet(name, path, options);
|
|
if (!wallet_instance) return false;
|
|
bilingual_str error;
|
|
bool ret = DumpWallet(*wallet_instance, error);
|
|
if (!ret && !error.empty()) {
|
|
tfm::format(std::cerr, "%s\n", error.original);
|
|
return ret;
|
|
}
|
|
tfm::format(std::cout, "The dumpfile may contain private keys. To ensure the safety of your Bitcoin, do not share the dumpfile.\n");
|
|
return ret;
|
|
} else if (command == "createfromdump") {
|
|
bilingual_str error;
|
|
std::vector<bilingual_str> warnings;
|
|
bool ret = CreateFromDump(name, path, error, warnings);
|
|
for (const auto& warning : warnings) {
|
|
tfm::format(std::cout, "%s\n", warning.original);
|
|
}
|
|
if (!ret && !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
|