diff options
author | MarcoFalke <falke.marco@gmail.com> | 2019-01-31 11:07:45 -0500 |
---|---|---|
committer | MarcoFalke <falke.marco@gmail.com> | 2019-01-31 11:07:51 -0500 |
commit | 252fd15addf1cd061c3b6258ad916df7deeecf83 (patch) | |
tree | d47f3028534b6eed320da0dee5e317a067b2b9d8 /src/wallet | |
parent | 4d661baf1aca4226d1c4ec89fe7e44c1f93f04da (diff) | |
parent | 3c3e31c3a49c657093cacdff2c1c5e25363902ce (diff) | |
download | bitcoin-252fd15addf1cd061c3b6258ad916df7deeecf83.tar.xz |
Merge #13926: [Tools] bitcoin-wallet - a tool for creating and managing wallets offline
3c3e31c3a4 [tests] Add wallet-tool test (João Barbosa)
49d2374acf [tools] Add wallet inspection and modification tool (Jonas Schnelli)
Pull request description:
Adds an offline tool `bitcoin-wallet-tool` for wallet creation and maintenance.
Currently this tool can create a new wallet file, display information on an existing wallet, and run the salvage and zapwallettxes maintenance tasks on an existing wallet. It can later be extended to support other common wallet maintenance tasks.
Doing wallet maintenance tasks in an offline tool makes much more sense (and is potentially safer) than having to spin up a full node.
Tree-SHA512: 75a28b8a58858d9d76c7532db40eacdefc5714ea5aab536fb1dc9756e2f7d750d69d68d59c50a68e633ce38fb5b8c3e3d4880db30fe01561e07ce58d42bceb2b
Diffstat (limited to 'src/wallet')
-rw-r--r-- | src/wallet/crypter.cpp | 4 | ||||
-rw-r--r-- | src/wallet/crypter.h | 2 | ||||
-rw-r--r-- | src/wallet/wallet.cpp | 4 | ||||
-rw-r--r-- | src/wallet/wallet.h | 2 | ||||
-rw-r--r-- | src/wallet/wallettool.cpp | 139 | ||||
-rw-r--r-- | src/wallet/wallettool.h | 20 |
6 files changed, 165 insertions, 6 deletions
diff --git a/src/wallet/crypter.cpp b/src/wallet/crypter.cpp index f5ac6e98b2..1dc78255f6 100644 --- a/src/wallet/crypter.cpp +++ b/src/wallet/crypter.cpp @@ -175,7 +175,7 @@ bool CCryptoKeyStore::Lock() return true; } -bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn) +bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn, bool accept_no_keys) { { LOCK(cs_KeyStore); @@ -204,7 +204,7 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn) LogPrintf("The wallet is probably corrupted: Some keys decrypt but not all.\n"); throw std::runtime_error("Error unlocking wallet: some keys decrypt but not all. Your wallet file may be corrupt."); } - if (keyFail || !keyPass) + if (keyFail || (!keyPass && !accept_no_keys)) return false; vMasterKey = vMasterKeyIn; fDecryptionThoroughlyChecked = true; diff --git a/src/wallet/crypter.h b/src/wallet/crypter.h index 418316c398..8e195ca8fa 100644 --- a/src/wallet/crypter.h +++ b/src/wallet/crypter.h @@ -133,7 +133,7 @@ protected: //! will encrypt previously unencrypted keys bool EncryptKeys(CKeyingMaterial& vMasterKeyIn); - bool Unlock(const CKeyingMaterial& vMasterKeyIn); + bool Unlock(const CKeyingMaterial& vMasterKeyIn, bool accept_no_keys = false); CryptedKeyMap mapCryptedKeys GUARDED_BY(cs_KeyStore); public: diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 757cb81795..879ff8fb54 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -398,7 +398,7 @@ bool CWallet::LoadWatchOnly(const CScript &dest) return CCryptoKeyStore::AddWatchOnly(dest); } -bool CWallet::Unlock(const SecureString& strWalletPassphrase) +bool CWallet::Unlock(const SecureString& strWalletPassphrase, bool accept_no_keys) { CCrypter crypter; CKeyingMaterial _vMasterKey; @@ -411,7 +411,7 @@ bool CWallet::Unlock(const SecureString& strWalletPassphrase) return false; if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, _vMasterKey)) continue; // try another master key - if (CCryptoKeyStore::Unlock(_vMasterKey)) + if (CCryptoKeyStore::Unlock(_vMasterKey, accept_no_keys)) return true; } } diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 06c7900ce1..4776b0eacc 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -884,7 +884,7 @@ public: //! Holds a timestamp at which point the wallet is scheduled (externally) to be relocked. Caller must arrange for actual relocking to occur via Lock(). int64_t nRelockTime = 0; - bool Unlock(const SecureString& strWalletPassphrase); + bool Unlock(const SecureString& strWalletPassphrase, bool accept_no_keys = false); bool ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase); bool EncryptWallet(const SecureString& strWalletPassphrase); diff --git a/src/wallet/wallettool.cpp b/src/wallet/wallettool.cpp new file mode 100644 index 0000000000..30b0c48eef --- /dev/null +++ b/src/wallet/wallettool.cpp @@ -0,0 +1,139 @@ +// Copyright (c) 2016-2018 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 <base58.h> +#include <fs.h> +#include <interfaces/chain.h> +#include <util/system.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->Flush(); + delete wallet; +} + +static std::shared_ptr<CWallet> CreateWallet(const std::string& name, const fs::path& path) +{ + if (fs::exists(path)) { + fprintf(stderr, "Error: File exists already\n"); + return nullptr; + } + // dummy chain interface + auto chain = interfaces::MakeChain(); + std::shared_ptr<CWallet> wallet_instance(new CWallet(*chain, WalletLocation(name), WalletDatabase::Create(path)), WalletToolReleaseWallet); + bool first_run = true; + DBErrors load_wallet_ret = wallet_instance->LoadWallet(first_run); + if (load_wallet_ret != DBErrors::LOAD_OK) { + fprintf(stderr, "Error creating %s", name.c_str()); + return nullptr; + } + + wallet_instance->SetMinVersion(FEATURE_HD_SPLIT); + + // generate a new HD seed + CPubKey seed = wallet_instance->GenerateNewSeed(); + wallet_instance->SetHDSeed(seed); + + fprintf(stdout, "Topping up keypool...\n"); + wallet_instance->TopUpKeyPool(); + return wallet_instance; +} + +static std::shared_ptr<CWallet> LoadWallet(const std::string& name, const fs::path& path) +{ + if (!fs::exists(path)) { + fprintf(stderr, "Error: Wallet files does not exist\n"); + return nullptr; + } + + // dummy chain interface + auto chain = interfaces::MakeChain(); + std::shared_ptr<CWallet> wallet_instance(new CWallet(*chain, WalletLocation(name), WalletDatabase::Create(path)), WalletToolReleaseWallet); + DBErrors load_wallet_ret; + try { + bool first_run; + load_wallet_ret = wallet_instance->LoadWallet(first_run); + } catch (const std::runtime_error) { + fprintf(stderr, "Error loading %s. Is wallet being used by another process?\n", name.c_str()); + return nullptr; + } + + if (load_wallet_ret != DBErrors::LOAD_OK) { + wallet_instance = nullptr; + if (load_wallet_ret == DBErrors::CORRUPT) { + fprintf(stderr, "Error loading %s: Wallet corrupted", name.c_str()); + return nullptr; + } else if (load_wallet_ret == DBErrors::NONCRITICAL_ERROR) { + fprintf(stderr, "Error reading %s! All keys read correctly, but transaction data" + " or address book entries might be missing or incorrect.", + name.c_str()); + } else if (load_wallet_ret == DBErrors::TOO_NEW) { + fprintf(stderr, "Error loading %s: Wallet requires newer version of %s", + name.c_str(), PACKAGE_NAME); + return nullptr; + } else if (load_wallet_ret == DBErrors::NEED_REWRITE) { + fprintf(stderr, "Wallet needed to be rewritten: restart %s to complete", PACKAGE_NAME); + return nullptr; + } else { + fprintf(stderr, "Error loading %s", name.c_str()); + return nullptr; + } + } + + return wallet_instance; +} + +static void WalletShowInfo(CWallet* wallet_instance) +{ + // lock required because of some AssertLockHeld() + LOCK(wallet_instance->cs_wallet); + + fprintf(stdout, "Wallet info\n===========\n"); + fprintf(stdout, "Encrypted: %s\n", wallet_instance->IsCrypted() ? "yes" : "no"); + fprintf(stdout, "HD (hd seed available): %s\n", wallet_instance->GetHDChain().seed_id.IsNull() ? "no" : "yes"); + fprintf(stdout, "Keypool Size: %u\n", wallet_instance->GetKeyPoolSize()); + fprintf(stdout, "Transactions: %zu\n", wallet_instance->mapWallet.size()); + fprintf(stdout, "Address Book: %zu\n", wallet_instance->mapAddressBook.size()); +} + +bool ExecuteWalletToolFunc(const std::string& command, const std::string& name) +{ + fs::path path = fs::absolute(name, GetWalletDir()); + + if (command == "create") { + std::shared_ptr<CWallet> wallet_instance = CreateWallet(name, path); + if (wallet_instance) { + WalletShowInfo(wallet_instance.get()); + wallet_instance->Flush(); + } + } else if (command == "info") { + if (!fs::exists(path)) { + fprintf(stderr, "Error: no wallet file at %s\n", name.c_str()); + return false; + } + std::string error; + if (!WalletBatch::VerifyEnvironment(path, error)) { + fprintf(stderr, "Error loading %s. Is wallet being used by other process?\n", name.c_str()); + return false; + } + std::shared_ptr<CWallet> wallet_instance = LoadWallet(name, path); + if (!wallet_instance) return false; + WalletShowInfo(wallet_instance.get()); + wallet_instance->Flush(); + } else { + fprintf(stderr, "Invalid command: %s\n", command.c_str()); + return false; + } + + return true; +} +} // namespace WalletTool diff --git a/src/wallet/wallettool.h b/src/wallet/wallettool.h new file mode 100644 index 0000000000..5b06fd1792 --- /dev/null +++ b/src/wallet/wallettool.h @@ -0,0 +1,20 @@ +// Copyright (c) 2016-2018 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_WALLET_WALLETTOOL_H +#define BITCOIN_WALLET_WALLETTOOL_H + +#include <script/ismine.h> +#include <wallet/wallet.h> + +namespace WalletTool { + +std::shared_ptr<CWallet> CreateWallet(const std::string& name, const fs::path& path); +std::shared_ptr<CWallet> LoadWallet(const std::string& name, const fs::path& path); +void WalletShowInfo(CWallet* wallet_instance); +bool ExecuteWalletToolFunc(const std::string& command, const std::string& file); + +} // namespace WalletTool + +#endif // BITCOIN_WALLET_WALLETTOOL_H |