Merge pull request #4481 from Munkybooty/backports-0.19-pr2

Backports 0.19 pr2
This commit is contained in:
UdjinM6 2021-11-15 23:34:23 +03:00 committed by GitHub
commit 0e4ebdc4aa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 534 additions and 29 deletions

1
.gitignore vendored
View File

@ -10,6 +10,7 @@ src/dash
src/dashd
src/dash-cli
src/dash-tx
src/dash-wallet
src/test/fuzz
!src/test/fuzz/*.*
src/test/test_dash

View File

@ -18,6 +18,7 @@ BITCOIN_DAEMON_NAME=dashd
BITCOIN_GUI_NAME=dash-qt
BITCOIN_CLI_NAME=dash-cli
BITCOIN_TX_NAME=dash-tx
BITCOIN_WALLET_TOOL_NAME=dash-wallet
dnl Unless the user specified ARFLAGS, force it to be cr
AC_ARG_VAR(ARFLAGS, [Flags for the archiver, defaults to <cr> if not set])
@ -537,7 +538,7 @@ CPPFLAGS="$CPPFLAGS -DHAVE_BUILD_INFO -D__STDC_FORMAT_MACROS"
AC_ARG_WITH([utils],
[AS_HELP_STRING([--with-utils],
[build dash-cli dash-tx (default=yes)])],
[build dash-cli dash-tx dash-wallet (default=yes)])],
[build_bitcoin_utils=$withval],
[build_bitcoin_utils=yes])
@ -553,6 +554,12 @@ AC_ARG_ENABLE([util-tx],
[build_bitcoin_tx=$enableval],
[build_bitcoin_tx=$build_bitcoin_utils])
AC_ARG_ENABLE([util-wallet],
[AS_HELP_STRING([--enable-util-wallet],
[build dash-wallet])],
[build_bitcoin_wallet=$enableval],
[build_bitcoin_wallet=$build_bitcoin_utils])
AC_ARG_WITH([libs],
[AS_HELP_STRING([--with-libs],
[build libraries (default=yes)])],
@ -1161,7 +1168,7 @@ if test x$suppress_external_warnings != xno ; then
QT_TEST_INCLUDES=SUPPRESS_WARNINGS($QT_TEST_INCLUDES)
fi
if test x$build_bitcoin_cli$build_bitcoin_tx$build_bitcoind$bitcoin_enable_qt$use_tests$use_bench = xnononononono; then
if test x$build_bitcoin_wallet$build_bitcoin_cli$build_bitcoin_tx$build_bitcoind$bitcoin_enable_qt$use_tests$use_bench = xnonononononono; then
use_boost=no
else
use_boost=yes
@ -1387,7 +1394,7 @@ AC_CHECK_LIB([gmp], [__gmpz_init],GMP_LIBS=-lgmp, AC_MSG_ERROR(libgmp missing))
dnl check if immer headers-only library is present
AC_CHECK_HEADER([immer/map.hpp],, AC_MSG_ERROR(immer map headers missing))
if test x$build_bitcoin_cli$build_bitcoin_tx$build_bitcoind$bitcoin_enable_qt$use_tests$use_bench = xnononononono; then
if test x$build_bitcoin_wallet$build_bitcoin_cli$build_bitcoin_tx$build_bitcoind$bitcoin_enable_qt$use_tests$use_bench = xnonononononono; then
need_bundled_univalue=no
else
@ -1449,6 +1456,10 @@ AC_MSG_CHECKING([whether to build dash-tx])
AM_CONDITIONAL([BUILD_BITCOIN_TX], [test x$build_bitcoin_tx = xyes])
AC_MSG_RESULT($build_bitcoin_tx)
AC_MSG_CHECKING([whether to build dash-wallet])
AM_CONDITIONAL([BUILD_BITCOIN_WALLET], [test x$build_bitcoin_wallet = xyes])
AC_MSG_RESULT($build_bitcoin_wallet)
AC_MSG_CHECKING([whether to build libraries])
AM_CONDITIONAL([BUILD_BITCOIN_LIBS], [test x$build_bitcoin_libs = xyes])
if test x$build_bitcoin_libs = xyes; then
@ -1602,7 +1613,7 @@ else
fi
AC_MSG_RESULT($dsymutil_needs_flat)
if test x$build_bitcoin_cli$build_bitcoin_tx$build_bitcoin_libs$build_bitcoind$bitcoin_enable_qt$use_bench$use_tests = xnonononononono; then
if test x$build_bitcoin_wallet$build_bitcoin_cli$build_bitcoin_tx$build_bitcoind$bitcoin_enable_qt$use_tests$use_bench = xnonononononono; then
AC_MSG_ERROR([No targets! Please specify at least one of: --with-utils --with-libs --with-daemon --with-gui --enable-bench or --enable-tests])
fi
@ -1651,6 +1662,7 @@ AC_SUBST(BITCOIN_DAEMON_NAME)
AC_SUBST(BITCOIN_GUI_NAME)
AC_SUBST(BITCOIN_CLI_NAME)
AC_SUBST(BITCOIN_TX_NAME)
AC_SUBST(BITCOIN_WALLET_TOOL_NAME)
AC_SUBST(RELDFLAGS)
AC_SUBST(DEBUG_CPPFLAGS)

View File

@ -64,6 +64,7 @@ LIBBITCOINCONSENSUS=libdashconsensus.la
endif
if ENABLE_WALLET
LIBBITCOIN_WALLET=libdash_wallet.a
LIBBITCOIN_WALLET_TOOL=libdash_wallet_tool.a
endif
LIBBITCOIN_CRYPTO= $(LIBBITCOIN_CRYPTO_BASE)
@ -93,6 +94,7 @@ EXTRA_LIBRARIES += \
$(LIBBITCOIN_SERVER) \
$(LIBBITCOIN_CLI) \
$(LIBBITCOIN_WALLET) \
$(LIBBITCOIN_WALLET_TOOL) \
$(LIBBITCOIN_ZMQ)
lib_LTLIBRARIES = $(LIBBITCOINCONSENSUS)
@ -112,6 +114,11 @@ endif
if BUILD_BITCOIN_TX
bin_PROGRAMS += dash-tx
endif
if ENABLE_WALLET
if BUILD_BITCOIN_WALLET
bin_PROGRAMS += dash-wallet
endif
endif
.PHONY: FORCE check-symbols check-security
# dash core #
@ -305,6 +312,7 @@ BITCOIN_CORE_H = \
wallet/rpcwallet.h \
wallet/wallet.h \
wallet/walletdb.h \
wallet/wallettool.h \
wallet/walletutil.h \
wallet/coinselection.h \
warnings.h \
@ -462,6 +470,12 @@ libdash_wallet_a_SOURCES = \
wallet/coinselection.cpp \
$(BITCOIN_CORE_H)
libdash_wallet_tool_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
libdash_wallet_tool_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libdash_wallet_tool_a_SOURCES = \
wallet/wallettool.cpp \
$(BITCOIN_CORE_H)
# crypto primitives library
crypto_libdash_crypto_base_a_CPPFLAGS = $(AM_CPPFLAGS) $(PIC_FLAGS)
crypto_libdash_crypto_base_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) $(PIC_FLAGS)
@ -739,6 +753,37 @@ dash_tx_LDADD = \
dash_tx_LDADD += $(BACKTRACE_LIB) $(BOOST_LIBS) $(CRYPTO_LIBS) $(BLS_LIBS) $(GMP_LIBS)
#
# dash-wallet binary #
dash_wallet_SOURCES = dash-wallet.cpp
dash_wallet_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
dash_wallet_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
dash_wallet_LDFLAGS = $(LDFLAGS_WRAP_EXCEPTIONS) $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
if TARGET_WINDOWS
dash_wallet_SOURCES += dash-wallet-res.rc
endif
# Libraries below may be listed more than once to resolve circular dependencies (see
# https://eli.thegreenplace.net/2013/07/09/library-order-in-static-linking#circular-dependency)
dash_wallet_LDADD = \
$(LIBBITCOIN_WALLET_TOOL) \
$(LIBBITCOIN_SERVER) \
$(LIBBITCOIN_WALLET) \
$(LIBBITCOIN_SERVER) \
$(LIBBITCOIN_COMMON) \
$(LIBBITCOIN_CONSENSUS) \
$(LIBBITCOIN_UTIL) \
$(LIBBITCOIN_CRYPTO) \
$(LIBBITCOIN_ZMQ) \
$(LIBLEVELDB) \
$(LIBLEVELDB_SSE42) \
$(LIBMEMENV) \
$(LIBSECP256K1) \
$(LIBUNIVALUE)
dash_wallet_LDADD += $(BACKTRACE_LIB) $(BOOST_LIBS) $(BDB_LIBS) $(CRYPTO_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(MINIUPNPC_LIBS) $(ZMQ_LIBS) $(BLS_LIBS) $(GMP_LIBS)
#
# dashconsensus library #
if BUILD_BITCOIN_LIBS
include_HEADERS = script/dashconsensus.h

35
src/dash-wallet-res.rc Normal file
View File

@ -0,0 +1,35 @@
#include <windows.h> // needed for VERSIONINFO
#include "clientversion.h" // holds the needed client version information
#define VER_PRODUCTVERSION CLIENT_VERSION_MAJOR,CLIENT_VERSION_MINOR,CLIENT_VERSION_REVISION,CLIENT_VERSION_BUILD
#define VER_PRODUCTVERSION_STR STRINGIZE(CLIENT_VERSION_MAJOR) "." STRINGIZE(CLIENT_VERSION_MINOR) "." STRINGIZE(CLIENT_VERSION_REVISION) "." STRINGIZE(CLIENT_VERSION_BUILD)
#define VER_FILEVERSION VER_PRODUCTVERSION
#define VER_FILEVERSION_STR VER_PRODUCTVERSION_STR
VS_VERSION_INFO VERSIONINFO
FILEVERSION VER_FILEVERSION
PRODUCTVERSION VER_PRODUCTVERSION
FILEOS VOS_NT_WINDOWS32
FILETYPE VFT_APP
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904E4" // U.S. English - multilingual (hex)
BEGIN
VALUE "CompanyName", "Dash Core"
VALUE "FileDescription", "dash-wallet (CLI tool for " PACKAGE_NAME " wallets)"
VALUE "FileVersion", VER_FILEVERSION_STR
VALUE "InternalName", "dash-wallet"
VALUE "LegalCopyright", COPYRIGHT_STR
VALUE "LegalTrademarks1", "Distributed under the MIT software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php."
VALUE "OriginalFilename", "dash-wallet.exe"
VALUE "ProductName", "dash-wallet"
VALUE "ProductVersion", VER_PRODUCTVERSION_STR
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x0, 1252 // language neutral - multilingual (decimal)
END
END

118
src/dash-wallet.cpp Normal file
View File

@ -0,0 +1,118 @@
// 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.
#if defined(HAVE_CONFIG_H)
#include <config/dash-config.h>
#endif
#include <chainparams.h>
#include <chainparamsbase.h>
#include <consensus/consensus.h>
#include <logging.h>
#include <util/system.h>
#include <util/strencodings.h>
#include <wallet/wallettool.h>
#include <stdio.h>
const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;
static void SetupWalletToolArgs()
{
SetupChainParamsBaseOptions();
gArgs.AddArg("-?", "This help message", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
gArgs.AddArg("-datadir=<dir>", "Specify data directory", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
gArgs.AddArg("-wallet=<wallet-name>", "Specify wallet name", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
gArgs.AddArg("-debug=<category>", "Output debugging information (default: 0).", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
gArgs.AddArg("-printtoconsole", "Send trace/debug info to console (default: 1 when no -debug is true, 0 otherwise.", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
gArgs.AddArg("info", "Get wallet info", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
gArgs.AddArg("create", "Create new wallet file", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
// Hidden
gArgs.AddArg("-h", "", ArgsManager::ALLOW_ANY, OptionsCategory::HIDDEN);
gArgs.AddArg("-help", "", ArgsManager::ALLOW_ANY, OptionsCategory::HIDDEN);
}
static bool WalletAppInit(int argc, char* argv[])
{
SetupWalletToolArgs();
std::string error_message;
if (!gArgs.ParseParameters(argc, argv, error_message)) {
tfm::format(std::cerr, "Error parsing command line arguments: %s\n", error_message);
return false;
}
if (argc < 2 || HelpRequested(gArgs)) {
std::string usage = strprintf("%s dash-wallet version", PACKAGE_NAME) + " " + FormatFullVersion() + "\n\n" +
"wallet-tool is an offline tool for creating and interacting with Dash Core wallet files.\n" +
"By default wallet-tool will act on wallets in the default mainnet wallet directory in the datadir.\n" +
"To change the target wallet, use the -datadir, -wallet and -testnet/-regtest arguments.\n\n" +
"Usage:\n" +
" dash-wallet [options] <command>\n\n" +
gArgs.GetHelpMessage();
tfm::format(std::cout, "%s", usage);
return false;
}
// check for printtoconsole, allow -debug
LogInstance().m_print_to_console = gArgs.GetBoolArg("-printtoconsole", gArgs.GetBoolArg("-debug", false));
if (!fs::is_directory(GetDataDir(false))) {
tfm::format(std::cerr, "Error: Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", ""));
return false;
}
// Check for -testnet or -regtest parameter (Params() calls are only valid after this clause)
SelectParams(gArgs.GetChainName());
return true;
}
int main(int argc, char* argv[])
{
#ifdef WIN32
util::WinCmdLineArgs winArgs;
std::tie(argc, argv) = winArgs.get();
#endif
SetupEnvironment();
RandomInit();
try {
if (!WalletAppInit(argc, argv)) return EXIT_FAILURE;
} catch (...) {
PrintExceptionContinue(std::current_exception(), "WalletAppInit()");
return EXIT_FAILURE;
}
std::string method {};
for(int i = 1; i < argc; ++i) {
if (!IsSwitchChar(argv[i][0])) {
if (!method.empty()) {
tfm::format(std::cerr, "Error: two methods provided (%s and %s). Only one method should be provided.\n", method, argv[i]);
return EXIT_FAILURE;
}
method = argv[i];
}
}
if (method.empty()) {
tfm::format(std::cerr, "No method provided. Run `dash-wallet -help` for valid methods.\n");
return EXIT_FAILURE;
}
// A name must be provided when creating a file
if (method == "create" && !gArgs.IsArgSet("-wallet")) {
tfm::format(std::cerr, "Wallet name must be provided when creating a new wallet.\n");
return EXIT_FAILURE;
}
std::string name = gArgs.GetArg("-wallet", "");
ECCVerifyHandle globalVerifyHandle;
ECC_Start();
if (!WalletTool::ExecuteWalletToolFunc(method, name))
return EXIT_FAILURE;
ECC_Stop();
return EXIT_SUCCESS;
}

View File

@ -469,6 +469,11 @@ QList<QModelIndex> getEntryData(QAbstractItemView *view, int column)
return view->selectionModel()->selectedRows(column);
}
QString getDefaultDataDirectory()
{
return boostPathToQString(GetDefaultDataDir());
}
QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir,
const QString &filter,
QString *selectedSuffixOut)

View File

@ -145,6 +145,11 @@ namespace GUIUtil
void setClipboard(const QString& str);
/**
* Determine default data directory for operating system.
*/
QString getDefaultDataDirectory();
/** Get save filename, mimics QFileDialog::getSaveFileName, except that it appends a default suffix
when no suffix is provided by the user.

View File

@ -170,7 +170,7 @@ QString Intro::getDataDirectory()
void Intro::setDataDirectory(const QString &dataDir)
{
ui->dataDirectory->setText(dataDir);
if(dataDir == getDefaultDataDirectory())
if(dataDir == GUIUtil::getDefaultDataDirectory())
{
ui->dataDirDefault->setChecked(true);
ui->dataDirectory->setEnabled(false);
@ -182,11 +182,6 @@ void Intro::setDataDirectory(const QString &dataDir)
}
}
QString Intro::getDefaultDataDirectory()
{
return GUIUtil::boostPathToQString(GetDefaultDataDir());
}
bool Intro::pickDataDirectory(interfaces::Node& node)
{
QSettings settings;
@ -195,13 +190,13 @@ bool Intro::pickDataDirectory(interfaces::Node& node)
if(!gArgs.GetArg("-datadir", "").empty())
return true;
/* 1) Default data directory for operating system */
QString dataDirDefaultCurrent = getDefaultDataDirectory();
QString dataDirDefaultCurrent = GUIUtil::getDefaultDataDirectory();
/* 2) Allow QSettings to override default dir */
QString dataDir = settings.value("strDataDir", dataDirDefaultCurrent).toString();
/* 3) Check to see if default datadir is the one we expect */
QString dataDirDefaultSettings = settings.value("strDataDirDefault").toString();
if(!fs::exists(GUIUtil::qstringToBoostPath(dataDir)) || gArgs.GetBoolArg("-choosedatadir", DEFAULT_CHOOSE_DATADIR) || dataDirDefaultCurrent != dataDirDefaultSettings)
if(!fs::exists(GUIUtil::qstringToBoostPath(dataDir)) || gArgs.GetBoolArg("-choosedatadir", DEFAULT_CHOOSE_DATADIR) || dataDirDefaultCurrent != dataDirDefaultSettings || settings.value("fReset", false).toBool() || gArgs.GetBoolArg("-resetguisettings", false))
{
/* Use selectParams here to guarantee Params() can be used by node interface */
try {
@ -240,12 +235,13 @@ bool Intro::pickDataDirectory(interfaces::Node& node)
settings.setValue("strDataDir", dataDir);
settings.setValue("strDataDirDefault", dataDirDefaultCurrent);
settings.setValue("fReset", false);
}
/* Only override -datadir if different from the default, to make it possible to
* override -datadir in the dash.conf file in the default data directory
* (to be consistent with dashd behavior)
*/
if(dataDir != dataDirDefaultCurrent) {
if(dataDir != GUIUtil::getDefaultDataDirectory()) {
node.softSetArg("-datadir", GUIUtil::qstringToBoostPath(dataDir).string()); // use OS locale for path setting
}
return true;
@ -299,7 +295,7 @@ void Intro::on_ellipsisButton_clicked()
void Intro::on_dataDirDefault_clicked()
{
setDataDirectory(getDefaultDataDirectory());
setDataDirectory(GUIUtil::getDefaultDataDirectory());
}
void Intro::on_dataDirCustom_clicked()

View File

@ -48,11 +48,6 @@ public:
*/
static bool pickDataDirectory(interfaces::Node& node);
/**
* Determine default data directory for operating system.
*/
static QString getDefaultDataDirectory();
Q_SIGNALS:
void requestCheck();

View File

@ -208,6 +208,9 @@ void OptionsModel::Init(bool resetSettings)
if (!m_node.softSetArg("-par", settings.value("nThreadsScriptVerif").toString().toStdString()))
addOverriddenOption("-par");
if (!settings.contains("strDataDir"))
settings.setValue("strDataDir", GUIUtil::getDefaultDataDirectory());
// Wallet
#ifdef ENABLE_WALLET
if (!settings.contains("bSpendZeroConfChange"))
@ -306,9 +309,19 @@ void OptionsModel::Reset()
// Backup old settings to chain-specific datadir for troubleshooting
BackupSettings(GetDataDir(true) / "guisettings.ini.bak", settings);
// Save the strDataDir setting
QString dataDir = GUIUtil::getDefaultDataDirectory();
dataDir = settings.value("strDataDir", dataDir).toString();
// Remove all entries from our QSettings object
settings.clear();
// Set strDataDir
settings.setValue("strDataDir", dataDir);
// Set that this was reset
settings.setValue("fReset", true);
// default setting for OptionsModel::StartAtStartup - disabled
if (GUIUtil::GetStartOnSystemStartup())
GUIUtil::SetStartOnSystemStartup(false);

View File

@ -242,7 +242,7 @@ bool CCryptoKeyStore::Lock(bool fAllowMixing)
return true;
}
bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn, bool fForMixingOnly)
bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn, bool fForMixingOnly, bool accept_no_keys)
{
{
LOCK(cs_KeyStore);
@ -271,7 +271,7 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn, bool fForMixin
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 && cryptedHDChain.IsNull()))
if (keyFail || (!keyPass && cryptedHDChain.IsNull() && !accept_no_keys))
return false;
vMasterKey = vMasterKeyIn;

View File

@ -140,7 +140,7 @@ protected:
bool SetHDChain(const CHDChain& chain);
bool SetCryptedHDChain(const CHDChain& chain);
bool Unlock(const CKeyingMaterial& vMasterKeyIn, bool fForMixingOnly = false);
bool Unlock(const CKeyingMaterial& vMasterKeyIn, bool fForMixingOnly = false, bool accept_no_keys = false);
CryptedKeyMap mapCryptedKeys GUARDED_BY(cs_KeyStore);
public:

View File

@ -579,7 +579,7 @@ bool CWallet::LoadWatchOnly(const CScript &dest)
return CCryptoKeyStore::AddWatchOnly(dest);
}
bool CWallet::Unlock(const SecureString& strWalletPassphrase, bool fForMixingOnly)
bool CWallet::Unlock(const SecureString& strWalletPassphrase, bool fForMixingOnly, bool accept_no_keys)
{
SecureString strWalletPassphraseFinal;
@ -609,7 +609,7 @@ bool CWallet::Unlock(const SecureString& strWalletPassphrase, bool fForMixingOnl
return false;
if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, _vMasterKey))
continue; // try another master key
if (CCryptoKeyStore::Unlock(_vMasterKey, fForMixingOnly)) {
if (CCryptoKeyStore::Unlock(_vMasterKey, fForMixingOnly, accept_no_keys)) {
if(nWalletBackups == -2) {
TopUpKeyPool();
WalletLogPrintf("Keypool replenished, re-initializing automatic backups.\n");
@ -4154,7 +4154,10 @@ bool CWallet::NewKeyPool()
batch.ErasePool(nIndex);
}
setExternalKeyPool.clear();
coinJoinClientManagers.at(GetName())->StopMixing();
auto it = coinJoinClientManagers.find(GetName());
if (it != coinJoinClientManagers.end()) {
it->second->StopMixing();
}
nKeysLeftSinceAutoBackup = 0;
m_pool_key_to_index.clear();

View File

@ -979,7 +979,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 fForMixingOnly = false);
bool Unlock(const SecureString& strWalletPassphrase, bool fForMixingOnly = false, bool accept_no_keys = false);
bool ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase);
bool EncryptWallet(const SecureString& strWalletPassphrase);

140
src/wallet/wallettool.cpp Normal file
View File

@ -0,0 +1,140 @@
// 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 dash-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)) {
tfm::format(std::cerr, "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) {
tfm::format(std::cerr, "Error creating %s", name);
return nullptr;
}
wallet_instance->SetMinVersion(FEATURE_HD);
// generate a new HD seed
// NOTE: we do not yet create HD wallets by default
// wallet_instance->GenerateNewHDChain("", "");
tfm::format(std::cout, "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)) {
tfm::format(std::cerr, "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) {
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;
}
}
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, "Encrypted: %s\n", wallet_instance->IsCrypted() ? "yes" : "no");
tfm::format(std::cout, "HD (hd seed available): %s\n", wallet_instance->GetHDChain(hdChainTmp) ? "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->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)) {
tfm::format(std::cerr, "Error: no wallet file at %s\n", name);
return false;
}
std::string error;
if (!WalletBatch::VerifyEnvironment(path, error)) {
tfm::format(std::cerr, "Error loading %s. Is wallet being used by other process?\n", name);
return false;
}
std::shared_ptr<CWallet> wallet_instance = LoadWallet(name, path);
if (!wallet_instance) return false;
WalletShowInfo(wallet_instance.get());
wallet_instance->Flush();
} else {
tfm::format(std::cerr, "Invalid command: %s\n", command);
return false;
}
return true;
}
} // namespace WalletTool

20
src/wallet/wallettool.h Normal file
View File

@ -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

View File

@ -6,6 +6,7 @@
# test/functional/test_runner.py and test/util/bitcoin-util-test.py
[environment]
PACKAGE_NAME=@PACKAGE_NAME@
SRCDIR=@abs_top_srcdir@
BUILDDIR=@abs_top_builddir@
EXEEXT=@EXEEXT@

View File

@ -23,7 +23,7 @@ class FilelockTest(BitcoinTestFramework):
self.log.info("Using datadir {}".format(datadir))
self.log.info("Check that we can't start a second dashd instance using the same datadir")
expected_msg = "Error: Cannot obtain a lock on data directory {}. Dash Core is probably already running.".format(datadir)
expected_msg = "Error: Cannot obtain a lock on data directory {0}. {1} is probably already running.".format(datadir, self.config['environment']['PACKAGE_NAME'])
self.nodes[1].assert_start_raises_init_error(extra_args=['-datadir={}'.format(self.nodes[0].datadir), '-noserver'], expected_msg=expected_msg)
if self.is_wallet_compiled():

View File

@ -16,7 +16,7 @@ class TestBitcoinCli(BitcoinTestFramework):
"""Main test logic"""
cli_response = self.nodes[0].cli("-version").send_cli()
assert "Dash Core RPC client version" in cli_response
assert "{} RPC client version".format(self.config['environment']['PACKAGE_NAME']) in cli_response
self.log.info("Compare responses from getwalletinfo RPC and `dash-cli getwalletinfo`")
if self.is_wallet_compiled():

View File

@ -179,6 +179,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
config = configparser.ConfigParser()
config.read_file(open(self.options.configfile))
self.config = config
self.options.bitcoind = os.getenv("BITCOIND", default=config["environment"]["BUILDDIR"] + '/src/dashd' + config["environment"]["EXEEXT"])
self.options.bitcoincli = os.getenv("BITCOINCLI", default=config["environment"]["BUILDDIR"] + '/src/dash-cli' + config["environment"]["EXEEXT"])

View File

@ -120,6 +120,7 @@ BASE_SCRIPTS = [
'interface_bitcoin_cli.py',
'mempool_resurrect.py',
'wallet_txn_doublespend.py --mineblock',
'tool_wallet.py',
'wallet_txn_clone.py',
'rpc_getchaintips.py',
'rpc_misc.py',
@ -606,7 +607,7 @@ class TestResult():
def check_script_prefixes():
"""Check that test scripts start with one of the allowed name prefixes."""
good_prefixes_re = re.compile("(example|feature|interface|mempool|mining|p2p|rpc|wallet)_")
good_prefixes_re = re.compile("(example|feature|interface|mempool|mining|p2p|rpc|wallet|tool)_")
bad_script_names = [script for script in ALL_SCRIPTS if good_prefixes_re.match(script) is None]
if bad_script_names:

114
test/functional/tool_wallet.py Executable file
View File

@ -0,0 +1,114 @@
#!/usr/bin/env python3
# Copyright (c) 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.
"""Test dash-wallet."""
import subprocess
import textwrap
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
class ToolWalletTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
self.setup_clean_chain = True
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
def dash_wallet_process(self, *args):
binary = self.config["environment"]["BUILDDIR"] + '/src/dash-wallet' + self.config["environment"]["EXEEXT"]
args = ['-datadir={}'.format(self.nodes[0].datadir), '-regtest'] + list(args)
return subprocess.Popen([binary] + args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
def assert_raises_tool_error(self, error, *args):
p = self.dash_wallet_process(*args)
stdout, stderr = p.communicate()
assert_equal(p.poll(), 1)
assert_equal(stdout, '')
assert_equal(stderr.strip(), error)
def assert_tool_output(self, output, *args):
p = self.dash_wallet_process(*args)
stdout, stderr = p.communicate()
assert_equal(p.poll(), 0)
assert_equal(stderr, '')
assert_equal(stdout, output)
def run_test(self):
self.assert_raises_tool_error('Invalid command: foo', 'foo')
# `dash-wallet help` is an error. Use `dash-wallet -help`
self.assert_raises_tool_error('Invalid command: help', 'help')
self.assert_raises_tool_error('Error: two methods provided (info and create). Only one method should be provided.', 'info', 'create')
self.assert_raises_tool_error('Error parsing command line arguments: Invalid parameter -foo', '-foo')
self.assert_raises_tool_error('Error loading wallet.dat. Is wallet being used by other process?', '-wallet=wallet.dat', 'info')
self.assert_raises_tool_error('Error: no wallet file at nonexistent.dat', '-wallet=nonexistent.dat', 'info')
# stop the node to close the wallet to call info command
self.stop_node(0)
out = textwrap.dedent('''\
Wallet info
===========
Encrypted: no
HD (hd seed available): no
Keypool Size: 1
Transactions: 0
Address Book: 0
''')
self.assert_tool_output(out, '-wallet=wallet.dat', 'info')
self.start_node(0)
self.nodes[0].upgradetohd()
self.stop_node(0)
out = textwrap.dedent('''\
Wallet info
===========
Encrypted: no
HD (hd seed available): yes
Keypool Size: 2
Transactions: 0
Address Book: 0
''')
self.assert_tool_output(out, '-wallet=wallet.dat', 'info')
# mutate the wallet to check the info command output changes accordingly
self.start_node(0)
self.nodes[0].generate(1)
self.stop_node(0)
out = textwrap.dedent('''\
Wallet info
===========
Encrypted: no
HD (hd seed available): yes
Keypool Size: 1
Transactions: 1
Address Book: 0
''')
self.assert_tool_output(out, '-wallet=wallet.dat', 'info')
out = textwrap.dedent('''\
Topping up keypool...
Wallet info
===========
Encrypted: no
HD (hd seed available): no
Keypool Size: 1000
Transactions: 0
Address Book: 0
''')
self.assert_tool_output(out, '-wallet=foo', 'create')
self.start_node(0, ['-wallet=foo'])
out = self.nodes[0].getwalletinfo()
self.stop_node(0)
assert_equal(0, out['txcount'])
assert_equal(1000, out['keypoolsize'])
if __name__ == '__main__':
ToolWalletTest().main()