diff options
author | Jonas Schnelli <dev@jonasschnelli.ch> | 2016-09-16 16:45:36 +0200 |
---|---|---|
committer | John Newbery <john@johnnewbery.com> | 2019-01-30 16:26:52 -0500 |
commit | 49d2374acf5845c5f760b5fd241482f292164147 (patch) | |
tree | e063f45b28b8dfef299d92b11ed25fdc3ff43b73 /src/wallet | |
parent | a5daf70ffb80c14ddf9f35c638d9e8087d8732e9 (diff) |
[tools] Add wallet inspection and modification tool
This commit adds wallet-tool, a tool for creating and interacting with
wallet files. Original implementation was by Jonas Schnelli
<dev@jonasschnelli.ch> with modifications by John Newbery
<john@johnnewbery.com>
MSVC files were provided by Chun Kuan Lee <ken2812221@gmail.com>:
build: Add MSVC project files for bitcoin-wallet-tool
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 098055673b..154ae2d51f 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 6872fbad2d..0f7c7bdfe7 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -887,7 +887,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 |