mirror of
https://github.com/dashpay/dash.git
synced 2024-12-26 04:22:55 +01:00
Merge pull request #4481 from Munkybooty/backports-0.19-pr2
Backports 0.19 pr2
This commit is contained in:
commit
0e4ebdc4aa
1
.gitignore
vendored
1
.gitignore
vendored
@ -10,6 +10,7 @@ src/dash
|
|||||||
src/dashd
|
src/dashd
|
||||||
src/dash-cli
|
src/dash-cli
|
||||||
src/dash-tx
|
src/dash-tx
|
||||||
|
src/dash-wallet
|
||||||
src/test/fuzz
|
src/test/fuzz
|
||||||
!src/test/fuzz/*.*
|
!src/test/fuzz/*.*
|
||||||
src/test/test_dash
|
src/test/test_dash
|
||||||
|
20
configure.ac
20
configure.ac
@ -18,6 +18,7 @@ BITCOIN_DAEMON_NAME=dashd
|
|||||||
BITCOIN_GUI_NAME=dash-qt
|
BITCOIN_GUI_NAME=dash-qt
|
||||||
BITCOIN_CLI_NAME=dash-cli
|
BITCOIN_CLI_NAME=dash-cli
|
||||||
BITCOIN_TX_NAME=dash-tx
|
BITCOIN_TX_NAME=dash-tx
|
||||||
|
BITCOIN_WALLET_TOOL_NAME=dash-wallet
|
||||||
|
|
||||||
dnl Unless the user specified ARFLAGS, force it to be cr
|
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])
|
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],
|
AC_ARG_WITH([utils],
|
||||||
[AS_HELP_STRING([--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=$withval],
|
||||||
[build_bitcoin_utils=yes])
|
[build_bitcoin_utils=yes])
|
||||||
|
|
||||||
@ -553,6 +554,12 @@ AC_ARG_ENABLE([util-tx],
|
|||||||
[build_bitcoin_tx=$enableval],
|
[build_bitcoin_tx=$enableval],
|
||||||
[build_bitcoin_tx=$build_bitcoin_utils])
|
[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],
|
AC_ARG_WITH([libs],
|
||||||
[AS_HELP_STRING([--with-libs],
|
[AS_HELP_STRING([--with-libs],
|
||||||
[build libraries (default=yes)])],
|
[build libraries (default=yes)])],
|
||||||
@ -1161,7 +1168,7 @@ if test x$suppress_external_warnings != xno ; then
|
|||||||
QT_TEST_INCLUDES=SUPPRESS_WARNINGS($QT_TEST_INCLUDES)
|
QT_TEST_INCLUDES=SUPPRESS_WARNINGS($QT_TEST_INCLUDES)
|
||||||
fi
|
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
|
use_boost=no
|
||||||
else
|
else
|
||||||
use_boost=yes
|
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
|
dnl check if immer headers-only library is present
|
||||||
AC_CHECK_HEADER([immer/map.hpp],, AC_MSG_ERROR(immer map headers missing))
|
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
|
need_bundled_univalue=no
|
||||||
else
|
else
|
||||||
|
|
||||||
@ -1449,6 +1456,10 @@ AC_MSG_CHECKING([whether to build dash-tx])
|
|||||||
AM_CONDITIONAL([BUILD_BITCOIN_TX], [test x$build_bitcoin_tx = xyes])
|
AM_CONDITIONAL([BUILD_BITCOIN_TX], [test x$build_bitcoin_tx = xyes])
|
||||||
AC_MSG_RESULT($build_bitcoin_tx)
|
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])
|
AC_MSG_CHECKING([whether to build libraries])
|
||||||
AM_CONDITIONAL([BUILD_BITCOIN_LIBS], [test x$build_bitcoin_libs = xyes])
|
AM_CONDITIONAL([BUILD_BITCOIN_LIBS], [test x$build_bitcoin_libs = xyes])
|
||||||
if test x$build_bitcoin_libs = xyes; then
|
if test x$build_bitcoin_libs = xyes; then
|
||||||
@ -1602,7 +1613,7 @@ else
|
|||||||
fi
|
fi
|
||||||
AC_MSG_RESULT($dsymutil_needs_flat)
|
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])
|
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
|
fi
|
||||||
|
|
||||||
@ -1651,6 +1662,7 @@ AC_SUBST(BITCOIN_DAEMON_NAME)
|
|||||||
AC_SUBST(BITCOIN_GUI_NAME)
|
AC_SUBST(BITCOIN_GUI_NAME)
|
||||||
AC_SUBST(BITCOIN_CLI_NAME)
|
AC_SUBST(BITCOIN_CLI_NAME)
|
||||||
AC_SUBST(BITCOIN_TX_NAME)
|
AC_SUBST(BITCOIN_TX_NAME)
|
||||||
|
AC_SUBST(BITCOIN_WALLET_TOOL_NAME)
|
||||||
|
|
||||||
AC_SUBST(RELDFLAGS)
|
AC_SUBST(RELDFLAGS)
|
||||||
AC_SUBST(DEBUG_CPPFLAGS)
|
AC_SUBST(DEBUG_CPPFLAGS)
|
||||||
|
@ -64,6 +64,7 @@ LIBBITCOINCONSENSUS=libdashconsensus.la
|
|||||||
endif
|
endif
|
||||||
if ENABLE_WALLET
|
if ENABLE_WALLET
|
||||||
LIBBITCOIN_WALLET=libdash_wallet.a
|
LIBBITCOIN_WALLET=libdash_wallet.a
|
||||||
|
LIBBITCOIN_WALLET_TOOL=libdash_wallet_tool.a
|
||||||
endif
|
endif
|
||||||
|
|
||||||
LIBBITCOIN_CRYPTO= $(LIBBITCOIN_CRYPTO_BASE)
|
LIBBITCOIN_CRYPTO= $(LIBBITCOIN_CRYPTO_BASE)
|
||||||
@ -93,6 +94,7 @@ EXTRA_LIBRARIES += \
|
|||||||
$(LIBBITCOIN_SERVER) \
|
$(LIBBITCOIN_SERVER) \
|
||||||
$(LIBBITCOIN_CLI) \
|
$(LIBBITCOIN_CLI) \
|
||||||
$(LIBBITCOIN_WALLET) \
|
$(LIBBITCOIN_WALLET) \
|
||||||
|
$(LIBBITCOIN_WALLET_TOOL) \
|
||||||
$(LIBBITCOIN_ZMQ)
|
$(LIBBITCOIN_ZMQ)
|
||||||
|
|
||||||
lib_LTLIBRARIES = $(LIBBITCOINCONSENSUS)
|
lib_LTLIBRARIES = $(LIBBITCOINCONSENSUS)
|
||||||
@ -112,6 +114,11 @@ endif
|
|||||||
if BUILD_BITCOIN_TX
|
if BUILD_BITCOIN_TX
|
||||||
bin_PROGRAMS += dash-tx
|
bin_PROGRAMS += dash-tx
|
||||||
endif
|
endif
|
||||||
|
if ENABLE_WALLET
|
||||||
|
if BUILD_BITCOIN_WALLET
|
||||||
|
bin_PROGRAMS += dash-wallet
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
.PHONY: FORCE check-symbols check-security
|
.PHONY: FORCE check-symbols check-security
|
||||||
# dash core #
|
# dash core #
|
||||||
@ -305,6 +312,7 @@ BITCOIN_CORE_H = \
|
|||||||
wallet/rpcwallet.h \
|
wallet/rpcwallet.h \
|
||||||
wallet/wallet.h \
|
wallet/wallet.h \
|
||||||
wallet/walletdb.h \
|
wallet/walletdb.h \
|
||||||
|
wallet/wallettool.h \
|
||||||
wallet/walletutil.h \
|
wallet/walletutil.h \
|
||||||
wallet/coinselection.h \
|
wallet/coinselection.h \
|
||||||
warnings.h \
|
warnings.h \
|
||||||
@ -462,6 +470,12 @@ libdash_wallet_a_SOURCES = \
|
|||||||
wallet/coinselection.cpp \
|
wallet/coinselection.cpp \
|
||||||
$(BITCOIN_CORE_H)
|
$(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 primitives library
|
||||||
crypto_libdash_crypto_base_a_CPPFLAGS = $(AM_CPPFLAGS) $(PIC_FLAGS)
|
crypto_libdash_crypto_base_a_CPPFLAGS = $(AM_CPPFLAGS) $(PIC_FLAGS)
|
||||||
crypto_libdash_crypto_base_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) $(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_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 #
|
# dashconsensus library #
|
||||||
if BUILD_BITCOIN_LIBS
|
if BUILD_BITCOIN_LIBS
|
||||||
include_HEADERS = script/dashconsensus.h
|
include_HEADERS = script/dashconsensus.h
|
||||||
|
35
src/dash-wallet-res.rc
Normal file
35
src/dash-wallet-res.rc
Normal 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
118
src/dash-wallet.cpp
Normal 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;
|
||||||
|
}
|
@ -469,6 +469,11 @@ QList<QModelIndex> getEntryData(QAbstractItemView *view, int column)
|
|||||||
return view->selectionModel()->selectedRows(column);
|
return view->selectionModel()->selectedRows(column);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString getDefaultDataDirectory()
|
||||||
|
{
|
||||||
|
return boostPathToQString(GetDefaultDataDir());
|
||||||
|
}
|
||||||
|
|
||||||
QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir,
|
QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir,
|
||||||
const QString &filter,
|
const QString &filter,
|
||||||
QString *selectedSuffixOut)
|
QString *selectedSuffixOut)
|
||||||
|
@ -145,6 +145,11 @@ namespace GUIUtil
|
|||||||
|
|
||||||
void setClipboard(const QString& str);
|
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
|
/** Get save filename, mimics QFileDialog::getSaveFileName, except that it appends a default suffix
|
||||||
when no suffix is provided by the user.
|
when no suffix is provided by the user.
|
||||||
|
|
||||||
|
@ -170,7 +170,7 @@ QString Intro::getDataDirectory()
|
|||||||
void Intro::setDataDirectory(const QString &dataDir)
|
void Intro::setDataDirectory(const QString &dataDir)
|
||||||
{
|
{
|
||||||
ui->dataDirectory->setText(dataDir);
|
ui->dataDirectory->setText(dataDir);
|
||||||
if(dataDir == getDefaultDataDirectory())
|
if(dataDir == GUIUtil::getDefaultDataDirectory())
|
||||||
{
|
{
|
||||||
ui->dataDirDefault->setChecked(true);
|
ui->dataDirDefault->setChecked(true);
|
||||||
ui->dataDirectory->setEnabled(false);
|
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)
|
bool Intro::pickDataDirectory(interfaces::Node& node)
|
||||||
{
|
{
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
@ -195,13 +190,13 @@ bool Intro::pickDataDirectory(interfaces::Node& node)
|
|||||||
if(!gArgs.GetArg("-datadir", "").empty())
|
if(!gArgs.GetArg("-datadir", "").empty())
|
||||||
return true;
|
return true;
|
||||||
/* 1) Default data directory for operating system */
|
/* 1) Default data directory for operating system */
|
||||||
QString dataDirDefaultCurrent = getDefaultDataDirectory();
|
QString dataDirDefaultCurrent = GUIUtil::getDefaultDataDirectory();
|
||||||
/* 2) Allow QSettings to override default dir */
|
/* 2) Allow QSettings to override default dir */
|
||||||
QString dataDir = settings.value("strDataDir", dataDirDefaultCurrent).toString();
|
QString dataDir = settings.value("strDataDir", dataDirDefaultCurrent).toString();
|
||||||
/* 3) Check to see if default datadir is the one we expect */
|
/* 3) Check to see if default datadir is the one we expect */
|
||||||
QString dataDirDefaultSettings = settings.value("strDataDirDefault").toString();
|
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 */
|
/* Use selectParams here to guarantee Params() can be used by node interface */
|
||||||
try {
|
try {
|
||||||
@ -240,12 +235,13 @@ bool Intro::pickDataDirectory(interfaces::Node& node)
|
|||||||
|
|
||||||
settings.setValue("strDataDir", dataDir);
|
settings.setValue("strDataDir", dataDir);
|
||||||
settings.setValue("strDataDirDefault", dataDirDefaultCurrent);
|
settings.setValue("strDataDirDefault", dataDirDefaultCurrent);
|
||||||
|
settings.setValue("fReset", false);
|
||||||
}
|
}
|
||||||
/* Only override -datadir if different from the default, to make it possible to
|
/* 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
|
* override -datadir in the dash.conf file in the default data directory
|
||||||
* (to be consistent with dashd behavior)
|
* (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
|
node.softSetArg("-datadir", GUIUtil::qstringToBoostPath(dataDir).string()); // use OS locale for path setting
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -299,7 +295,7 @@ void Intro::on_ellipsisButton_clicked()
|
|||||||
|
|
||||||
void Intro::on_dataDirDefault_clicked()
|
void Intro::on_dataDirDefault_clicked()
|
||||||
{
|
{
|
||||||
setDataDirectory(getDefaultDataDirectory());
|
setDataDirectory(GUIUtil::getDefaultDataDirectory());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Intro::on_dataDirCustom_clicked()
|
void Intro::on_dataDirCustom_clicked()
|
||||||
|
@ -48,11 +48,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
static bool pickDataDirectory(interfaces::Node& node);
|
static bool pickDataDirectory(interfaces::Node& node);
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine default data directory for operating system.
|
|
||||||
*/
|
|
||||||
static QString getDefaultDataDirectory();
|
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void requestCheck();
|
void requestCheck();
|
||||||
|
|
||||||
|
@ -208,6 +208,9 @@ void OptionsModel::Init(bool resetSettings)
|
|||||||
if (!m_node.softSetArg("-par", settings.value("nThreadsScriptVerif").toString().toStdString()))
|
if (!m_node.softSetArg("-par", settings.value("nThreadsScriptVerif").toString().toStdString()))
|
||||||
addOverriddenOption("-par");
|
addOverriddenOption("-par");
|
||||||
|
|
||||||
|
if (!settings.contains("strDataDir"))
|
||||||
|
settings.setValue("strDataDir", GUIUtil::getDefaultDataDirectory());
|
||||||
|
|
||||||
// Wallet
|
// Wallet
|
||||||
#ifdef ENABLE_WALLET
|
#ifdef ENABLE_WALLET
|
||||||
if (!settings.contains("bSpendZeroConfChange"))
|
if (!settings.contains("bSpendZeroConfChange"))
|
||||||
@ -306,9 +309,19 @@ void OptionsModel::Reset()
|
|||||||
// Backup old settings to chain-specific datadir for troubleshooting
|
// Backup old settings to chain-specific datadir for troubleshooting
|
||||||
BackupSettings(GetDataDir(true) / "guisettings.ini.bak", settings);
|
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
|
// Remove all entries from our QSettings object
|
||||||
settings.clear();
|
settings.clear();
|
||||||
|
|
||||||
|
// Set strDataDir
|
||||||
|
settings.setValue("strDataDir", dataDir);
|
||||||
|
|
||||||
|
// Set that this was reset
|
||||||
|
settings.setValue("fReset", true);
|
||||||
|
|
||||||
// default setting for OptionsModel::StartAtStartup - disabled
|
// default setting for OptionsModel::StartAtStartup - disabled
|
||||||
if (GUIUtil::GetStartOnSystemStartup())
|
if (GUIUtil::GetStartOnSystemStartup())
|
||||||
GUIUtil::SetStartOnSystemStartup(false);
|
GUIUtil::SetStartOnSystemStartup(false);
|
||||||
|
@ -242,7 +242,7 @@ bool CCryptoKeyStore::Lock(bool fAllowMixing)
|
|||||||
return true;
|
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);
|
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");
|
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.");
|
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;
|
return false;
|
||||||
|
|
||||||
vMasterKey = vMasterKeyIn;
|
vMasterKey = vMasterKeyIn;
|
||||||
|
@ -140,7 +140,7 @@ protected:
|
|||||||
bool SetHDChain(const CHDChain& chain);
|
bool SetHDChain(const CHDChain& chain);
|
||||||
bool SetCryptedHDChain(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);
|
CryptedKeyMap mapCryptedKeys GUARDED_BY(cs_KeyStore);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -579,7 +579,7 @@ bool CWallet::LoadWatchOnly(const CScript &dest)
|
|||||||
return CCryptoKeyStore::AddWatchOnly(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;
|
SecureString strWalletPassphraseFinal;
|
||||||
|
|
||||||
@ -609,7 +609,7 @@ bool CWallet::Unlock(const SecureString& strWalletPassphrase, bool fForMixingOnl
|
|||||||
return false;
|
return false;
|
||||||
if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, _vMasterKey))
|
if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, _vMasterKey))
|
||||||
continue; // try another master key
|
continue; // try another master key
|
||||||
if (CCryptoKeyStore::Unlock(_vMasterKey, fForMixingOnly)) {
|
if (CCryptoKeyStore::Unlock(_vMasterKey, fForMixingOnly, accept_no_keys)) {
|
||||||
if(nWalletBackups == -2) {
|
if(nWalletBackups == -2) {
|
||||||
TopUpKeyPool();
|
TopUpKeyPool();
|
||||||
WalletLogPrintf("Keypool replenished, re-initializing automatic backups.\n");
|
WalletLogPrintf("Keypool replenished, re-initializing automatic backups.\n");
|
||||||
@ -4154,7 +4154,10 @@ bool CWallet::NewKeyPool()
|
|||||||
batch.ErasePool(nIndex);
|
batch.ErasePool(nIndex);
|
||||||
}
|
}
|
||||||
setExternalKeyPool.clear();
|
setExternalKeyPool.clear();
|
||||||
coinJoinClientManagers.at(GetName())->StopMixing();
|
auto it = coinJoinClientManagers.find(GetName());
|
||||||
|
if (it != coinJoinClientManagers.end()) {
|
||||||
|
it->second->StopMixing();
|
||||||
|
}
|
||||||
nKeysLeftSinceAutoBackup = 0;
|
nKeysLeftSinceAutoBackup = 0;
|
||||||
|
|
||||||
m_pool_key_to_index.clear();
|
m_pool_key_to_index.clear();
|
||||||
|
@ -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().
|
//! 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;
|
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 ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase);
|
||||||
bool EncryptWallet(const SecureString& strWalletPassphrase);
|
bool EncryptWallet(const SecureString& strWalletPassphrase);
|
||||||
|
|
||||||
|
140
src/wallet/wallettool.cpp
Normal file
140
src/wallet/wallettool.cpp
Normal 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
20
src/wallet/wallettool.h
Normal 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
|
@ -6,6 +6,7 @@
|
|||||||
# test/functional/test_runner.py and test/util/bitcoin-util-test.py
|
# test/functional/test_runner.py and test/util/bitcoin-util-test.py
|
||||||
|
|
||||||
[environment]
|
[environment]
|
||||||
|
PACKAGE_NAME=@PACKAGE_NAME@
|
||||||
SRCDIR=@abs_top_srcdir@
|
SRCDIR=@abs_top_srcdir@
|
||||||
BUILDDIR=@abs_top_builddir@
|
BUILDDIR=@abs_top_builddir@
|
||||||
EXEEXT=@EXEEXT@
|
EXEEXT=@EXEEXT@
|
||||||
|
@ -23,7 +23,7 @@ class FilelockTest(BitcoinTestFramework):
|
|||||||
self.log.info("Using datadir {}".format(datadir))
|
self.log.info("Using datadir {}".format(datadir))
|
||||||
|
|
||||||
self.log.info("Check that we can't start a second dashd instance using the same 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)
|
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():
|
if self.is_wallet_compiled():
|
||||||
|
@ -16,7 +16,7 @@ class TestBitcoinCli(BitcoinTestFramework):
|
|||||||
"""Main test logic"""
|
"""Main test logic"""
|
||||||
|
|
||||||
cli_response = self.nodes[0].cli("-version").send_cli()
|
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`")
|
self.log.info("Compare responses from getwalletinfo RPC and `dash-cli getwalletinfo`")
|
||||||
if self.is_wallet_compiled():
|
if self.is_wallet_compiled():
|
||||||
|
@ -179,6 +179,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
|
|||||||
|
|
||||||
config = configparser.ConfigParser()
|
config = configparser.ConfigParser()
|
||||||
config.read_file(open(self.options.configfile))
|
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.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"])
|
self.options.bitcoincli = os.getenv("BITCOINCLI", default=config["environment"]["BUILDDIR"] + '/src/dash-cli' + config["environment"]["EXEEXT"])
|
||||||
|
|
||||||
|
@ -120,6 +120,7 @@ BASE_SCRIPTS = [
|
|||||||
'interface_bitcoin_cli.py',
|
'interface_bitcoin_cli.py',
|
||||||
'mempool_resurrect.py',
|
'mempool_resurrect.py',
|
||||||
'wallet_txn_doublespend.py --mineblock',
|
'wallet_txn_doublespend.py --mineblock',
|
||||||
|
'tool_wallet.py',
|
||||||
'wallet_txn_clone.py',
|
'wallet_txn_clone.py',
|
||||||
'rpc_getchaintips.py',
|
'rpc_getchaintips.py',
|
||||||
'rpc_misc.py',
|
'rpc_misc.py',
|
||||||
@ -606,7 +607,7 @@ class TestResult():
|
|||||||
def check_script_prefixes():
|
def check_script_prefixes():
|
||||||
"""Check that test scripts start with one of the allowed name 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]
|
bad_script_names = [script for script in ALL_SCRIPTS if good_prefixes_re.match(script) is None]
|
||||||
|
|
||||||
if bad_script_names:
|
if bad_script_names:
|
||||||
|
114
test/functional/tool_wallet.py
Executable file
114
test/functional/tool_wallet.py
Executable 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()
|
Loading…
Reference in New Issue
Block a user