mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 12:02:48 +01:00
5ec99ff3b4
fa61b9d1a68820758f9540653920deaeae6abe79 util: Add ArgsManager::GetCommand() and use it in bitcoin-wallet (MarcoFalke) 7777105a24a36b62df35d12ecf6c6370671568c8 refactor: Move all command dependend checks to ExecuteWalletToolFunc (MarcoFalke) fa06bce4ac17f93decd4ee38c956e7aa55983f0d test: Add tests (MarcoFalke) fac05ccdade8b34c969b9cd9b37b355bc0aabf9c wallet: [refactor] Pass ArgsManager to WalletAppInit (MarcoFalke) Pull request description: This not only moves the parsing responsibility out from the wallet tool, but it also makes it easier to implement bitcoin-util #19937 Fixes: #20902 ACKs for top commit: ajtowns: ACK fa61b9d1a68820758f9540653920deaeae6abe79 fjahr: Code review ACK fa61b9d1a68820758f9540653920deaeae6abe79 Tree-SHA512: 79622b806e8bf9dcd0dc24a8a6687345710df57720992e83a41cd8d6762a6dc112044ebc58fcf6e8fbf45de29a79b04873c5b8c2494a1eaaf902a2884703e47b
237 lines
9.3 KiB
C++
237 lines
9.3 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/translation.h>
|
|
#include <util/system.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 dash-wallet. Define our own
|
|
// deleter here.
|
|
static void WalletToolReleaseWallet(CWallet* wallet)
|
|
{
|
|
wallet->WalletLogPrintf("Releasing wallet\n");
|
|
wallet->Close();
|
|
delete wallet;
|
|
}
|
|
|
|
static const bool DEFAULT_USE_HD_WALLET{true};
|
|
|
|
static void WalletCreate(CWallet* wallet_instance, uint64_t wallet_creation_flags)
|
|
{
|
|
LOCK(wallet_instance->cs_wallet);
|
|
if (gArgs.GetBoolArg("-usehd", DEFAULT_USE_HD_WALLET)) {
|
|
wallet_instance->SetMinVersion(FEATURE_LATEST);
|
|
} else {
|
|
wallet_instance->SetMinVersion(FEATURE_COMPRPUBKEY);
|
|
}
|
|
wallet_instance->SetWalletFlag(wallet_creation_flags);
|
|
|
|
if (!wallet_instance->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
|
|
// TODO: use here SetupGeneration instead, such as: spk_man->SetupGeneration(false);
|
|
// SetupGeneration is not backported yet
|
|
wallet_instance->SetupLegacyScriptPubKeyMan();
|
|
auto spk_man = wallet_instance->GetOrCreateLegacyScriptPubKeyMan();
|
|
if (gArgs.GetBoolArg("-usehd", DEFAULT_USE_HD_WALLET)) {
|
|
spk_man->GenerateNewHDChain(/*secureMnemonic=*/"", /*secureMnemonicPassphrase=*/"");
|
|
}
|
|
} 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(/*chain=*/ nullptr, /*coinjoin_loader=*/ nullptr, 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 (options.require_create) WalletCreate(wallet_instance.get(), options.create_flags);
|
|
|
|
return wallet_instance;
|
|
}
|
|
|
|
static void WalletShowInfo(CWallet* wallet_instance)
|
|
{
|
|
// lock required because of some AssertLockHeld()
|
|
LOCK(wallet_instance->cs_wallet);
|
|
|
|
CHDChain hdChainTmp;
|
|
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 (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(), name);
|
|
|
|
if (command == "create") {
|
|
DatabaseOptions options;
|
|
options.require_create = true;
|
|
if (args.GetBoolArg("-descriptors", false)) {
|
|
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 == "wipetxes") {
|
|
#ifdef USE_BDB
|
|
DatabaseOptions options;
|
|
options.require_existing = true;
|
|
std::shared_ptr<CWallet> wallet_instance = MakeWallet(name, path, options);
|
|
if (wallet_instance == nullptr) return false;
|
|
|
|
std::vector<uint256> vHash;
|
|
std::vector<uint256> vHashOut;
|
|
|
|
LOCK(wallet_instance->cs_wallet);
|
|
|
|
for (auto& [txid, _] : wallet_instance->mapWallet) {
|
|
vHash.push_back(txid);
|
|
}
|
|
|
|
if (wallet_instance->ZapSelectTx(vHash, vHashOut) != DBErrors::LOAD_OK) {
|
|
tfm::format(std::cerr, "Could not properly delete transactions");
|
|
wallet_instance->Close();
|
|
return false;
|
|
}
|
|
|
|
wallet_instance->Close();
|
|
return vHashOut.size() == vHash.size();
|
|
#else
|
|
tfm::format(std::cerr, "Wipetxes 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
|