Merge #10244: Refactor: separate gui from wallet and node
9960137
Add developer notes about blocking GUI code (Russell Yanofsky)9a61eed
Use WalletBalances struct in Qt (Russell Yanofsky)56f33ca
Remove direct bitcoin calls from qt/sendcoinsdialog.cpp (Russell Yanofsky)e872c93
Remove direct bitcoin access from qt/guiutil.cpp (Russell Yanofsky)5884558
Remove direct bitcoin calls from qt transaction table files (Russell Yanofsky)3cab2ce
Remove direct bitcoin calls from qt/paymentserver.cpp (Russell Yanofsky)3ec2ebc
Remove direct bitcoin calls from qt/addresstablemodel.cpp (Russell Yanofsky)827de03
Remove direct bitcoin calls from qt/coincontroldialog.cpp (Russell Yanofsky)a0704a8
Remove most direct bitcoin calls from qt/walletmodel.cpp (Russell Yanofsky)90d4640
Remove direct bitcoin calls from qt/optionsdialog.cpp (Russell Yanofsky)582daf6
Remove direct bitcoin calls from qt/rpcconsole.cpp (Russell Yanofsky)3034a46
Remove direct bitcoin calls from qt/bantablemodel.cpp (Russell Yanofsky)e0b66a3
Remove direct bitcoin calls from qt/peertablemodel.cpp (Russell Yanofsky)d7c2c95
Remove direct bitcoin calls from qt/intro.cpp (Russell Yanofsky)fe6f27e
Remove direct bitcoin calls from qt/clientmodel.cpp (Russell Yanofsky)5fba3af
Remove direct bitcoin calls from qt/splashscreen.cpp (Russell Yanofsky)c2f672f
Remove direct bitcoin calls from qt/utilitydialog.cpp (Russell Yanofsky)3d619e9
Remove direct bitcoin calls from qt/bitcoingui.cpp (Russell Yanofsky)c0f2756
Remove direct bitcoin calls from qt/optionsmodel.cpp (Russell Yanofsky)71e0d90
Remove direct bitcoin calls from qt/bitcoin.cpp (Russell Yanofsky)ea73b84
Add src/interface/README.md (Russell Yanofsky) Pull request description: This is a refactoring PR that does not change behavior in any way. This change: 1. Creates abstract [`Node`](https://github.com/ryanofsky/bitcoin/blob/pr/ipc-local/src/interface/node.h) and [`Wallet`](https://github.com/ryanofsky/bitcoin/blob/pr/ipc-local/src/interface/wallet.h) interfaces in [`src/interface/`](https://github.com/ryanofsky/bitcoin/tree/pr/ipc-local/src/interface) 1. Updates Qt code to call the new interfaces. This largely consists of diffs of the form: ```diff - InitLogging(); - InitParameterInteraction(); + node.initLogging(); + node.initParameterInteraction(); ``` This change allows followup PR #10102 (makes `bitcoin-qt` control `bitcoind` over an IPC socket) to work without any significant updates to Qt code. Additionally: * It provides a single place to describe the interface between GUI and daemon code. * It can make better GUI testing possible, because Node and Wallet objects have virtual methods that can be overloaded for mocking. * It can be used to help make the GUI more responsive (see https://github.com/bitcoin/bitcoin/issues/10504) Other notes: * I used python scripts [hide-globals.py](https://github.com/ryanofsky/home/blob/master/src/2017/hide-globals/hide-globals.py) and [replace-syms.py](https://github.com/ryanofsky/home/blob/master/src/2017/hide-globals/replace-syms.py) to identify all the places where Qt code was accessing libbitcoin global variables and calling functions accessing those global variables. * These changes were originally part of #10102. Thanks to @JeremyRubin for the suggestion of splitting them out. Commits: - [`ea73b84d2d` Add src/interface/README.md](ea73b84d2d
) - [`71e0d90876` Remove direct bitcoin calls from qt/bitcoin.cpp](71e0d90876
) - [`c0f2756be5` Remove direct bitcoin calls from qt/optionsmodel.cpp](c0f2756be5
) - [`3d619e9d36` Remove direct bitcoin calls from qt/bitcoingui.cpp](3d619e9d36
) - [`c2f672fb19` Remove direct bitcoin calls from qt/utilitydialog.cpp](c2f672fb19
) - [`5fba3af21e` Remove direct bitcoin calls from qt/splashscreen.cpp](5fba3af21e
) - [`fe6f27e6ea` Remove direct bitcoin calls from qt/clientmodel.cpp](fe6f27e6ea
) - [`d7c2c95948` Remove direct bitcoin calls from qt/intro.cpp](d7c2c95948
) - [`e0b66a3b7c` Remove direct bitcoin calls from qt/peertablemodel.cpp](e0b66a3b7c
) - [`3034a462a5` Remove direct bitcoin calls from qt/bantablemodel.cpp](3034a462a5
) - [`582daf6d22` Remove direct bitcoin calls from qt/rpcconsole.cpp](582daf6d22
) - [`90d4640b7e` Remove direct bitcoin calls from qt/optionsdialog.cpp](90d4640b7e
) - [`a0704a8996` Remove most direct bitcoin calls from qt/walletmodel.cpp](a0704a8996
) - [`827de038ab` Remove direct bitcoin calls from qt/coincontroldialog.cpp](827de038ab
) - [`3ec2ebcd9b` Remove direct bitcoin calls from qt/addresstablemodel.cpp](3ec2ebcd9b
) - [`3cab2ce5f9` Remove direct bitcoin calls from qt/paymentserver.cpp](3cab2ce5f9
) - [`58845587e1` Remove direct bitcoin calls from qt transaction table files](58845587e1
) - [`e872c93ee8` Remove direct bitcoin access from qt/guiutil.cpp](e872c93ee8
) - [`56f33ca349` Remove direct bitcoin calls from qt/sendcoinsdialog.cpp](56f33ca349
) - [`9a61eed1fc` Use WalletBalances struct in Qt](9a61eed1fc
) - [`9960137697` Add developer notes about blocking GUI code](9960137697
) Tree-SHA512: 7b9eff2f37d4ea21972d7cc6a3dbe144248595d6c330524396d867f3cd2841d666cdc040fd3605af559dab51b075812402f61d628d16cf13719335c1d8bf8ed3
This commit is contained in:
commit
5f0c6a7b0e
65 changed files with 2249 additions and 1086 deletions
|
@ -625,6 +625,19 @@ GUI
|
||||||
should not interact with the user. That's where View classes come in. The converse also
|
should not interact with the user. That's where View classes come in. The converse also
|
||||||
holds: try to not directly access core data structures from Views.
|
holds: try to not directly access core data structures from Views.
|
||||||
|
|
||||||
|
- Avoid adding slow or blocking code in the GUI thread. In particular do not
|
||||||
|
add new `interface::Node` and `interface::Wallet` method calls, even if they
|
||||||
|
may be fast now, in case they are changed to lock or communicate across
|
||||||
|
processes in the future.
|
||||||
|
|
||||||
|
Prefer to offload work from the GUI thread to worker threads (see
|
||||||
|
`RPCExecutor` in console code as an example) or take other steps (see
|
||||||
|
https://doc.qt.io/archives/qq/qq27-responsive-guis.html) to keep the GUI
|
||||||
|
responsive.
|
||||||
|
|
||||||
|
- *Rationale*: Blocking the GUI thread can increase latency, and lead to
|
||||||
|
hangs and deadlocks.
|
||||||
|
|
||||||
Subtrees
|
Subtrees
|
||||||
----------
|
----------
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ DIST_SUBDIRS = secp256k1 univalue
|
||||||
AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS) $(HARDENED_LDFLAGS) $(GPROF_LDFLAGS) $(SANITIZER_LDFLAGS)
|
AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS) $(HARDENED_LDFLAGS) $(GPROF_LDFLAGS) $(SANITIZER_LDFLAGS)
|
||||||
AM_CXXFLAGS = $(HARDENED_CXXFLAGS) $(ERROR_CXXFLAGS) $(GPROF_CXXFLAGS) $(SANITIZER_CXXFLAGS)
|
AM_CXXFLAGS = $(HARDENED_CXXFLAGS) $(ERROR_CXXFLAGS) $(GPROF_CXXFLAGS) $(SANITIZER_CXXFLAGS)
|
||||||
AM_CPPFLAGS = $(HARDENED_CPPFLAGS)
|
AM_CPPFLAGS = $(HARDENED_CPPFLAGS)
|
||||||
|
AM_LIBTOOLFLAGS = --preserve-dup-deps
|
||||||
EXTRA_LIBRARIES =
|
EXTRA_LIBRARIES =
|
||||||
|
|
||||||
if EMBEDDED_UNIVALUE
|
if EMBEDDED_UNIVALUE
|
||||||
|
@ -104,6 +105,9 @@ BITCOIN_CORE_H = \
|
||||||
httpserver.h \
|
httpserver.h \
|
||||||
indirectmap.h \
|
indirectmap.h \
|
||||||
init.h \
|
init.h \
|
||||||
|
interface/handler.h \
|
||||||
|
interface/node.h \
|
||||||
|
interface/wallet.h \
|
||||||
key.h \
|
key.h \
|
||||||
key_io.h \
|
key_io.h \
|
||||||
keystore.h \
|
keystore.h \
|
||||||
|
@ -245,6 +249,7 @@ endif
|
||||||
libbitcoin_wallet_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
|
libbitcoin_wallet_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
|
||||||
libbitcoin_wallet_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
libbitcoin_wallet_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||||
libbitcoin_wallet_a_SOURCES = \
|
libbitcoin_wallet_a_SOURCES = \
|
||||||
|
interface/wallet.cpp \
|
||||||
wallet/crypter.cpp \
|
wallet/crypter.cpp \
|
||||||
wallet/db.cpp \
|
wallet/db.cpp \
|
||||||
wallet/feebumper.cpp \
|
wallet/feebumper.cpp \
|
||||||
|
@ -357,6 +362,8 @@ libbitcoin_util_a_SOURCES = \
|
||||||
compat/glibcxx_sanity.cpp \
|
compat/glibcxx_sanity.cpp \
|
||||||
compat/strnlen.cpp \
|
compat/strnlen.cpp \
|
||||||
fs.cpp \
|
fs.cpp \
|
||||||
|
interface/handler.cpp \
|
||||||
|
interface/node.cpp \
|
||||||
random.cpp \
|
random.cpp \
|
||||||
rpc/protocol.cpp \
|
rpc/protocol.cpp \
|
||||||
rpc/util.cpp \
|
rpc/util.cpp \
|
||||||
|
|
|
@ -402,7 +402,7 @@ if TARGET_WINDOWS
|
||||||
endif
|
endif
|
||||||
qt_bitcoin_qt_LDADD = qt/libbitcoinqt.a $(LIBBITCOIN_SERVER)
|
qt_bitcoin_qt_LDADD = qt/libbitcoinqt.a $(LIBBITCOIN_SERVER)
|
||||||
if ENABLE_WALLET
|
if ENABLE_WALLET
|
||||||
qt_bitcoin_qt_LDADD += $(LIBBITCOIN_WALLET)
|
qt_bitcoin_qt_LDADD += $(LIBBITCOIN_UTIL) $(LIBBITCOIN_WALLET)
|
||||||
endif
|
endif
|
||||||
if ENABLE_ZMQ
|
if ENABLE_ZMQ
|
||||||
qt_bitcoin_qt_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)
|
qt_bitcoin_qt_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)
|
||||||
|
@ -411,7 +411,7 @@ qt_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL)
|
||||||
$(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \
|
$(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \
|
||||||
$(EVENT_PTHREADS_LIBS) $(EVENT_LIBS)
|
$(EVENT_PTHREADS_LIBS) $(EVENT_LIBS)
|
||||||
qt_bitcoin_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
|
qt_bitcoin_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
|
||||||
qt_bitcoin_qt_LIBTOOLFLAGS = --tag CXX
|
qt_bitcoin_qt_LIBTOOLFLAGS = $(AM_LIBTOOLFLAGS) --tag CXX
|
||||||
|
|
||||||
#locale/foo.ts -> locale/foo.qm
|
#locale/foo.ts -> locale/foo.qm
|
||||||
QT_QM=$(QT_TS:.ts=.qm)
|
QT_QM=$(QT_TS:.ts=.qm)
|
||||||
|
|
|
@ -52,7 +52,7 @@ nodist_qt_test_test_bitcoin_qt_SOURCES = $(TEST_QT_MOC_CPP)
|
||||||
|
|
||||||
qt_test_test_bitcoin_qt_LDADD = $(LIBBITCOINQT) $(LIBBITCOIN_SERVER)
|
qt_test_test_bitcoin_qt_LDADD = $(LIBBITCOINQT) $(LIBBITCOIN_SERVER)
|
||||||
if ENABLE_WALLET
|
if ENABLE_WALLET
|
||||||
qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_WALLET)
|
qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_UTIL) $(LIBBITCOIN_WALLET)
|
||||||
endif
|
endif
|
||||||
if ENABLE_ZMQ
|
if ENABLE_ZMQ
|
||||||
qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)
|
qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)
|
||||||
|
|
17
src/interface/README.md
Normal file
17
src/interface/README.md
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
# Internal c++ interfaces
|
||||||
|
|
||||||
|
The following interfaces are defined here:
|
||||||
|
|
||||||
|
* [`Chain`](chain.h) — used by wallet to access blockchain and mempool state. Added in [#10973](https://github.com/bitcoin/bitcoin/pull/10973).
|
||||||
|
|
||||||
|
* [`Chain::Client`](chain.h) — used by node to start & stop `Chain` clients. Added in [#10973](https://github.com/bitcoin/bitcoin/pull/10973).
|
||||||
|
|
||||||
|
* [`Node`](node.h) — used by GUI to start & stop bitcoin node. Added in [#10244](https://github.com/bitcoin/bitcoin/pull/10244).
|
||||||
|
|
||||||
|
* [`Wallet`](wallet.h) — used by GUI to access wallets. Added in [#10244](https://github.com/bitcoin/bitcoin/pull/10244).
|
||||||
|
|
||||||
|
* [`Handler`](handler.h) — returned by `handleEvent` methods on interfaces above and used to manage lifetimes of event handlers.
|
||||||
|
|
||||||
|
* [`Init`](init.h) — used by multiprocess code to access interfaces above on startup. Added in [#10102](https://github.com/bitcoin/bitcoin/pull/10102).
|
||||||
|
|
||||||
|
The interfaces above define boundaries between major components of bitcoin code (node, wallet, and gui), making it possible for them to run in different processes, and be tested, developed, and understood independently. These interfaces are not currently designed to be stable or to be used externally.
|
33
src/interface/handler.cpp
Normal file
33
src/interface/handler.cpp
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
#include <interface/handler.h>
|
||||||
|
|
||||||
|
#include <util.h>
|
||||||
|
|
||||||
|
#include <boost/signals2/connection.hpp>
|
||||||
|
#include <memory>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace interface {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class HandlerImpl : public Handler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HandlerImpl(boost::signals2::connection connection) : m_connection(std::move(connection)) {}
|
||||||
|
|
||||||
|
void disconnect() override { m_connection.disconnect(); }
|
||||||
|
|
||||||
|
boost::signals2::scoped_connection m_connection;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
std::unique_ptr<Handler> MakeHandler(boost::signals2::connection connection)
|
||||||
|
{
|
||||||
|
return MakeUnique<HandlerImpl>(std::move(connection));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace interface
|
35
src/interface/handler.h
Normal file
35
src/interface/handler.h
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
#ifndef BITCOIN_INTERFACE_HANDLER_H
|
||||||
|
#define BITCOIN_INTERFACE_HANDLER_H
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
namespace signals2 {
|
||||||
|
class connection;
|
||||||
|
} // namespace signals2
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
namespace interface {
|
||||||
|
|
||||||
|
//! Generic interface for managing an event handler or callback function
|
||||||
|
//! registered with another interface. Has a single disconnect method to cancel
|
||||||
|
//! the registration and prevent any future notifications.
|
||||||
|
class Handler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~Handler() {}
|
||||||
|
|
||||||
|
//! Disconnect the handler.
|
||||||
|
virtual void disconnect() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Return handler wrapping a boost signal connection.
|
||||||
|
std::unique_ptr<Handler> MakeHandler(boost::signals2::connection connection);
|
||||||
|
|
||||||
|
} // namespace interface
|
||||||
|
|
||||||
|
#endif // BITCOIN_INTERFACE_HANDLER_H
|
308
src/interface/node.cpp
Normal file
308
src/interface/node.cpp
Normal file
|
@ -0,0 +1,308 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
#include <interface/node.h>
|
||||||
|
|
||||||
|
#include <addrdb.h>
|
||||||
|
#include <amount.h>
|
||||||
|
#include <chain.h>
|
||||||
|
#include <chainparams.h>
|
||||||
|
#include <init.h>
|
||||||
|
#include <interface/handler.h>
|
||||||
|
#include <interface/wallet.h>
|
||||||
|
#include <net.h>
|
||||||
|
#include <net_processing.h>
|
||||||
|
#include <netaddress.h>
|
||||||
|
#include <netbase.h>
|
||||||
|
#include <policy/feerate.h>
|
||||||
|
#include <policy/fees.h>
|
||||||
|
#include <policy/policy.h>
|
||||||
|
#include <primitives/block.h>
|
||||||
|
#include <rpc/server.h>
|
||||||
|
#include <scheduler.h>
|
||||||
|
#include <sync.h>
|
||||||
|
#include <txmempool.h>
|
||||||
|
#include <ui_interface.h>
|
||||||
|
#include <util.h>
|
||||||
|
#include <validation.h>
|
||||||
|
#include <warnings.h>
|
||||||
|
|
||||||
|
#if defined(HAVE_CONFIG_H)
|
||||||
|
#include <config/bitcoin-config.h>
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_WALLET
|
||||||
|
#include <wallet/fees.h>
|
||||||
|
#include <wallet/wallet.h>
|
||||||
|
#define CHECK_WALLET(x) x
|
||||||
|
#else
|
||||||
|
#define CHECK_WALLET(x) throw std::logic_error("Wallet function called in non-wallet build.")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <boost/thread/thread.hpp>
|
||||||
|
#include <univalue.h>
|
||||||
|
|
||||||
|
namespace interface {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class NodeImpl : public Node
|
||||||
|
{
|
||||||
|
void parseParameters(int argc, const char* const argv[]) override
|
||||||
|
{
|
||||||
|
gArgs.ParseParameters(argc, argv);
|
||||||
|
}
|
||||||
|
void readConfigFile(const std::string& conf_path) override { gArgs.ReadConfigFile(conf_path); }
|
||||||
|
bool softSetArg(const std::string& arg, const std::string& value) override { return gArgs.SoftSetArg(arg, value); }
|
||||||
|
bool softSetBoolArg(const std::string& arg, bool value) override { return gArgs.SoftSetBoolArg(arg, value); }
|
||||||
|
void selectParams(const std::string& network) override { SelectParams(network); }
|
||||||
|
std::string getNetwork() override { return Params().NetworkIDString(); }
|
||||||
|
void initLogging() override { InitLogging(); }
|
||||||
|
void initParameterInteraction() override { InitParameterInteraction(); }
|
||||||
|
std::string getWarnings(const std::string& type) override { return GetWarnings(type); }
|
||||||
|
uint32_t getLogCategories() override { return ::logCategories; }
|
||||||
|
bool baseInitialize() override
|
||||||
|
{
|
||||||
|
return AppInitBasicSetup() && AppInitParameterInteraction() && AppInitSanityChecks() &&
|
||||||
|
AppInitLockDataDirectory();
|
||||||
|
}
|
||||||
|
bool appInitMain() override { return AppInitMain(); }
|
||||||
|
void appShutdown() override
|
||||||
|
{
|
||||||
|
Interrupt();
|
||||||
|
Shutdown();
|
||||||
|
}
|
||||||
|
void startShutdown() override { StartShutdown(); }
|
||||||
|
bool shutdownRequested() override { return ShutdownRequested(); }
|
||||||
|
void mapPort(bool use_upnp) override
|
||||||
|
{
|
||||||
|
if (use_upnp) {
|
||||||
|
StartMapPort();
|
||||||
|
} else {
|
||||||
|
InterruptMapPort();
|
||||||
|
StopMapPort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::string helpMessage(HelpMessageMode mode) override { return HelpMessage(mode); }
|
||||||
|
bool getProxy(Network net, proxyType& proxy_info) override { return GetProxy(net, proxy_info); }
|
||||||
|
size_t getNodeCount(CConnman::NumConnections flags) override
|
||||||
|
{
|
||||||
|
return g_connman ? g_connman->GetNodeCount(flags) : 0;
|
||||||
|
}
|
||||||
|
bool getNodesStats(NodesStats& stats) override
|
||||||
|
{
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
if (g_connman) {
|
||||||
|
std::vector<CNodeStats> stats_temp;
|
||||||
|
g_connman->GetNodeStats(stats_temp);
|
||||||
|
|
||||||
|
stats.reserve(stats_temp.size());
|
||||||
|
for (auto& node_stats_temp : stats_temp) {
|
||||||
|
stats.emplace_back(std::move(node_stats_temp), false, CNodeStateStats());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to retrieve the CNodeStateStats for each node.
|
||||||
|
TRY_LOCK(::cs_main, lockMain);
|
||||||
|
if (lockMain) {
|
||||||
|
for (auto& node_stats : stats) {
|
||||||
|
std::get<1>(node_stats) =
|
||||||
|
GetNodeStateStats(std::get<0>(node_stats).nodeid, std::get<2>(node_stats));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool getBanned(banmap_t& banmap) override
|
||||||
|
{
|
||||||
|
if (g_connman) {
|
||||||
|
g_connman->GetBanned(banmap);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool ban(const CNetAddr& net_addr, BanReason reason, int64_t ban_time_offset) override
|
||||||
|
{
|
||||||
|
if (g_connman) {
|
||||||
|
g_connman->Ban(net_addr, reason, ban_time_offset);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool unban(const CSubNet& ip) override
|
||||||
|
{
|
||||||
|
if (g_connman) {
|
||||||
|
g_connman->Unban(ip);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool disconnect(NodeId id) override
|
||||||
|
{
|
||||||
|
if (g_connman) {
|
||||||
|
return g_connman->DisconnectNode(id);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int64_t getTotalBytesRecv() override { return g_connman ? g_connman->GetTotalBytesRecv() : 0; }
|
||||||
|
int64_t getTotalBytesSent() override { return g_connman ? g_connman->GetTotalBytesSent() : 0; }
|
||||||
|
size_t getMempoolSize() override { return ::mempool.size(); }
|
||||||
|
size_t getMempoolDynamicUsage() override { return ::mempool.DynamicMemoryUsage(); }
|
||||||
|
bool getHeaderTip(int& height, int64_t& block_time) override
|
||||||
|
{
|
||||||
|
LOCK(::cs_main);
|
||||||
|
if (::pindexBestHeader) {
|
||||||
|
height = ::pindexBestHeader->nHeight;
|
||||||
|
block_time = ::pindexBestHeader->GetBlockTime();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int getNumBlocks() override
|
||||||
|
{
|
||||||
|
LOCK(::cs_main);
|
||||||
|
return ::chainActive.Height();
|
||||||
|
}
|
||||||
|
int64_t getLastBlockTime() override
|
||||||
|
{
|
||||||
|
LOCK(::cs_main);
|
||||||
|
if (::chainActive.Tip()) {
|
||||||
|
return ::chainActive.Tip()->GetBlockTime();
|
||||||
|
}
|
||||||
|
return Params().GenesisBlock().GetBlockTime(); // Genesis block's time of current network
|
||||||
|
}
|
||||||
|
double getVerificationProgress() override
|
||||||
|
{
|
||||||
|
const CBlockIndex* tip;
|
||||||
|
{
|
||||||
|
LOCK(::cs_main);
|
||||||
|
tip = ::chainActive.Tip();
|
||||||
|
}
|
||||||
|
return GuessVerificationProgress(Params().TxData(), tip);
|
||||||
|
}
|
||||||
|
bool isInitialBlockDownload() override { return IsInitialBlockDownload(); }
|
||||||
|
bool getReindex() override { return ::fReindex; }
|
||||||
|
bool getImporting() override { return ::fImporting; }
|
||||||
|
void setNetworkActive(bool active) override
|
||||||
|
{
|
||||||
|
if (g_connman) {
|
||||||
|
g_connman->SetNetworkActive(active);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool getNetworkActive() override { return g_connman && g_connman->GetNetworkActive(); }
|
||||||
|
unsigned int getTxConfirmTarget() override { CHECK_WALLET(return ::nTxConfirmTarget); }
|
||||||
|
CAmount getRequiredFee(unsigned int tx_bytes) override { CHECK_WALLET(return GetRequiredFee(tx_bytes)); }
|
||||||
|
CAmount getMinimumFee(unsigned int tx_bytes,
|
||||||
|
const CCoinControl& coin_control,
|
||||||
|
int* returned_target,
|
||||||
|
FeeReason* reason) override
|
||||||
|
{
|
||||||
|
FeeCalculation fee_calc;
|
||||||
|
CAmount result;
|
||||||
|
CHECK_WALLET(result = GetMinimumFee(tx_bytes, coin_control, ::mempool, ::feeEstimator, &fee_calc));
|
||||||
|
if (returned_target) *returned_target = fee_calc.returnedTarget;
|
||||||
|
if (reason) *reason = fee_calc.reason;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
CAmount getMaxTxFee() override { return ::maxTxFee; }
|
||||||
|
CFeeRate estimateSmartFee(int num_blocks, bool conservative, int* returned_target = nullptr) override
|
||||||
|
{
|
||||||
|
FeeCalculation fee_calc;
|
||||||
|
CFeeRate result = ::feeEstimator.estimateSmartFee(num_blocks, &fee_calc, conservative);
|
||||||
|
if (returned_target) {
|
||||||
|
*returned_target = fee_calc.returnedTarget;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
CFeeRate getDustRelayFee() override { return ::dustRelayFee; }
|
||||||
|
CFeeRate getFallbackFee() override { CHECK_WALLET(return CWallet::fallbackFee); }
|
||||||
|
CFeeRate getPayTxFee() override { CHECK_WALLET(return ::payTxFee); }
|
||||||
|
void setPayTxFee(CFeeRate rate) override { CHECK_WALLET(::payTxFee = rate); }
|
||||||
|
UniValue executeRpc(const std::string& command, const UniValue& params, const std::string& uri) override
|
||||||
|
{
|
||||||
|
JSONRPCRequest req;
|
||||||
|
req.params = params;
|
||||||
|
req.strMethod = command;
|
||||||
|
req.URI = uri;
|
||||||
|
return ::tableRPC.execute(req);
|
||||||
|
}
|
||||||
|
std::vector<std::string> listRpcCommands() override { return ::tableRPC.listCommands(); }
|
||||||
|
void rpcSetTimerInterfaceIfUnset(RPCTimerInterface* iface) override { RPCSetTimerInterfaceIfUnset(iface); }
|
||||||
|
void rpcUnsetTimerInterface(RPCTimerInterface* iface) override { RPCUnsetTimerInterface(iface); }
|
||||||
|
bool getUnspentOutput(const COutPoint& output, Coin& coin) override
|
||||||
|
{
|
||||||
|
LOCK(::cs_main);
|
||||||
|
return ::pcoinsTip->GetCoin(output, coin);
|
||||||
|
}
|
||||||
|
std::vector<std::unique_ptr<Wallet>> getWallets() override
|
||||||
|
{
|
||||||
|
#ifdef ENABLE_WALLET
|
||||||
|
std::vector<std::unique_ptr<Wallet>> wallets;
|
||||||
|
for (CWalletRef wallet : ::vpwallets) {
|
||||||
|
wallets.emplace_back(MakeWallet(*wallet));
|
||||||
|
}
|
||||||
|
return wallets;
|
||||||
|
#else
|
||||||
|
throw std::logic_error("Node::getWallets() called in non-wallet build.");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
std::unique_ptr<Handler> handleInitMessage(InitMessageFn fn) override
|
||||||
|
{
|
||||||
|
return MakeHandler(::uiInterface.InitMessage.connect(fn));
|
||||||
|
}
|
||||||
|
std::unique_ptr<Handler> handleMessageBox(MessageBoxFn fn) override
|
||||||
|
{
|
||||||
|
return MakeHandler(::uiInterface.ThreadSafeMessageBox.connect(fn));
|
||||||
|
}
|
||||||
|
std::unique_ptr<Handler> handleQuestion(QuestionFn fn) override
|
||||||
|
{
|
||||||
|
return MakeHandler(::uiInterface.ThreadSafeQuestion.connect(fn));
|
||||||
|
}
|
||||||
|
std::unique_ptr<Handler> handleShowProgress(ShowProgressFn fn) override
|
||||||
|
{
|
||||||
|
return MakeHandler(::uiInterface.ShowProgress.connect(fn));
|
||||||
|
}
|
||||||
|
std::unique_ptr<Handler> handleLoadWallet(LoadWalletFn fn) override
|
||||||
|
{
|
||||||
|
CHECK_WALLET(
|
||||||
|
return MakeHandler(::uiInterface.LoadWallet.connect([fn](CWallet* wallet) { fn(MakeWallet(*wallet)); })));
|
||||||
|
}
|
||||||
|
std::unique_ptr<Handler> handleNotifyNumConnectionsChanged(NotifyNumConnectionsChangedFn fn) override
|
||||||
|
{
|
||||||
|
return MakeHandler(::uiInterface.NotifyNumConnectionsChanged.connect(fn));
|
||||||
|
}
|
||||||
|
std::unique_ptr<Handler> handleNotifyNetworkActiveChanged(NotifyNetworkActiveChangedFn fn) override
|
||||||
|
{
|
||||||
|
return MakeHandler(::uiInterface.NotifyNetworkActiveChanged.connect(fn));
|
||||||
|
}
|
||||||
|
std::unique_ptr<Handler> handleNotifyAlertChanged(NotifyAlertChangedFn fn) override
|
||||||
|
{
|
||||||
|
return MakeHandler(::uiInterface.NotifyAlertChanged.connect(fn));
|
||||||
|
}
|
||||||
|
std::unique_ptr<Handler> handleBannedListChanged(BannedListChangedFn fn) override
|
||||||
|
{
|
||||||
|
return MakeHandler(::uiInterface.BannedListChanged.connect(fn));
|
||||||
|
}
|
||||||
|
std::unique_ptr<Handler> handleNotifyBlockTip(NotifyBlockTipFn fn) override
|
||||||
|
{
|
||||||
|
return MakeHandler(::uiInterface.NotifyBlockTip.connect([fn](bool initial_download, const CBlockIndex* block) {
|
||||||
|
fn(initial_download, block->nHeight, block->GetBlockTime(),
|
||||||
|
GuessVerificationProgress(Params().TxData(), block));
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
std::unique_ptr<Handler> handleNotifyHeaderTip(NotifyHeaderTipFn fn) override
|
||||||
|
{
|
||||||
|
return MakeHandler(
|
||||||
|
::uiInterface.NotifyHeaderTip.connect([fn](bool initial_download, const CBlockIndex* block) {
|
||||||
|
fn(initial_download, block->nHeight, block->GetBlockTime(),
|
||||||
|
GuessVerificationProgress(Params().TxData(), block));
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
std::unique_ptr<Node> MakeNode() { return MakeUnique<NodeImpl>(); }
|
||||||
|
|
||||||
|
} // namespace interface
|
259
src/interface/node.h
Normal file
259
src/interface/node.h
Normal file
|
@ -0,0 +1,259 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
#ifndef BITCOIN_INTERFACE_NODE_H
|
||||||
|
#define BITCOIN_INTERFACE_NODE_H
|
||||||
|
|
||||||
|
#include <addrdb.h> // For banmap_t
|
||||||
|
#include <amount.h> // For CAmount
|
||||||
|
#include <init.h> // For HelpMessageMode
|
||||||
|
#include <net.h> // For CConnman::NumConnections
|
||||||
|
#include <netaddress.h> // For Network
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string>
|
||||||
|
#include <tuple>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class CCoinControl;
|
||||||
|
class CFeeRate;
|
||||||
|
class CNodeStats;
|
||||||
|
class Coin;
|
||||||
|
class RPCTimerInterface;
|
||||||
|
class UniValue;
|
||||||
|
class proxyType;
|
||||||
|
enum class FeeReason;
|
||||||
|
struct CNodeStateStats;
|
||||||
|
|
||||||
|
namespace interface {
|
||||||
|
|
||||||
|
class Handler;
|
||||||
|
class Wallet;
|
||||||
|
|
||||||
|
//! Top-level interface for a bitcoin node (bitcoind process).
|
||||||
|
class Node
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~Node() {}
|
||||||
|
|
||||||
|
//! Set command line arguments.
|
||||||
|
virtual void parseParameters(int argc, const char* const argv[]) = 0;
|
||||||
|
|
||||||
|
//! Set a command line argument if it doesn't already have a value
|
||||||
|
virtual bool softSetArg(const std::string& arg, const std::string& value) = 0;
|
||||||
|
|
||||||
|
//! Set a command line boolean argument if it doesn't already have a value
|
||||||
|
virtual bool softSetBoolArg(const std::string& arg, bool value) = 0;
|
||||||
|
|
||||||
|
//! Load settings from configuration file.
|
||||||
|
virtual void readConfigFile(const std::string& conf_path) = 0;
|
||||||
|
|
||||||
|
//! Choose network parameters.
|
||||||
|
virtual void selectParams(const std::string& network) = 0;
|
||||||
|
|
||||||
|
//! Get network name.
|
||||||
|
virtual std::string getNetwork() = 0;
|
||||||
|
|
||||||
|
//! Init logging.
|
||||||
|
virtual void initLogging() = 0;
|
||||||
|
|
||||||
|
//! Init parameter interaction.
|
||||||
|
virtual void initParameterInteraction() = 0;
|
||||||
|
|
||||||
|
//! Get warnings.
|
||||||
|
virtual std::string getWarnings(const std::string& type) = 0;
|
||||||
|
|
||||||
|
// Get log flags.
|
||||||
|
virtual uint32_t getLogCategories() = 0;
|
||||||
|
|
||||||
|
//! Initialize app dependencies.
|
||||||
|
virtual bool baseInitialize() = 0;
|
||||||
|
|
||||||
|
//! Start node.
|
||||||
|
virtual bool appInitMain() = 0;
|
||||||
|
|
||||||
|
//! Stop node.
|
||||||
|
virtual void appShutdown() = 0;
|
||||||
|
|
||||||
|
//! Start shutdown.
|
||||||
|
virtual void startShutdown() = 0;
|
||||||
|
|
||||||
|
//! Return whether shutdown was requested.
|
||||||
|
virtual bool shutdownRequested() = 0;
|
||||||
|
|
||||||
|
//! Get help message string.
|
||||||
|
virtual std::string helpMessage(HelpMessageMode mode) = 0;
|
||||||
|
|
||||||
|
//! Map port.
|
||||||
|
virtual void mapPort(bool use_upnp) = 0;
|
||||||
|
|
||||||
|
//! Get proxy.
|
||||||
|
virtual bool getProxy(Network net, proxyType& proxy_info) = 0;
|
||||||
|
|
||||||
|
//! Get number of connections.
|
||||||
|
virtual size_t getNodeCount(CConnman::NumConnections flags) = 0;
|
||||||
|
|
||||||
|
//! Get stats for connected nodes.
|
||||||
|
using NodesStats = std::vector<std::tuple<CNodeStats, bool, CNodeStateStats>>;
|
||||||
|
virtual bool getNodesStats(NodesStats& stats) = 0;
|
||||||
|
|
||||||
|
//! Get ban map entries.
|
||||||
|
virtual bool getBanned(banmap_t& banmap) = 0;
|
||||||
|
|
||||||
|
//! Ban node.
|
||||||
|
virtual bool ban(const CNetAddr& net_addr, BanReason reason, int64_t ban_time_offset) = 0;
|
||||||
|
|
||||||
|
//! Unban node.
|
||||||
|
virtual bool unban(const CSubNet& ip) = 0;
|
||||||
|
|
||||||
|
//! Disconnect node.
|
||||||
|
virtual bool disconnect(NodeId id) = 0;
|
||||||
|
|
||||||
|
//! Get total bytes recv.
|
||||||
|
virtual int64_t getTotalBytesRecv() = 0;
|
||||||
|
|
||||||
|
//! Get total bytes sent.
|
||||||
|
virtual int64_t getTotalBytesSent() = 0;
|
||||||
|
|
||||||
|
//! Get mempool size.
|
||||||
|
virtual size_t getMempoolSize() = 0;
|
||||||
|
|
||||||
|
//! Get mempool dynamic usage.
|
||||||
|
virtual size_t getMempoolDynamicUsage() = 0;
|
||||||
|
|
||||||
|
//! Get header tip height and time.
|
||||||
|
virtual bool getHeaderTip(int& height, int64_t& block_time) = 0;
|
||||||
|
|
||||||
|
//! Get num blocks.
|
||||||
|
virtual int getNumBlocks() = 0;
|
||||||
|
|
||||||
|
//! Get last block time.
|
||||||
|
virtual int64_t getLastBlockTime() = 0;
|
||||||
|
|
||||||
|
//! Get verification progress.
|
||||||
|
virtual double getVerificationProgress() = 0;
|
||||||
|
|
||||||
|
//! Is initial block download.
|
||||||
|
virtual bool isInitialBlockDownload() = 0;
|
||||||
|
|
||||||
|
//! Get reindex.
|
||||||
|
virtual bool getReindex() = 0;
|
||||||
|
|
||||||
|
//! Get importing.
|
||||||
|
virtual bool getImporting() = 0;
|
||||||
|
|
||||||
|
//! Set network active.
|
||||||
|
virtual void setNetworkActive(bool active) = 0;
|
||||||
|
|
||||||
|
//! Get network active.
|
||||||
|
virtual bool getNetworkActive() = 0;
|
||||||
|
|
||||||
|
//! Get tx confirm target.
|
||||||
|
virtual unsigned int getTxConfirmTarget() = 0;
|
||||||
|
|
||||||
|
//! Get required fee.
|
||||||
|
virtual CAmount getRequiredFee(unsigned int tx_bytes) = 0;
|
||||||
|
|
||||||
|
//! Get minimum fee.
|
||||||
|
virtual CAmount getMinimumFee(unsigned int tx_bytes,
|
||||||
|
const CCoinControl& coin_control,
|
||||||
|
int* returned_target,
|
||||||
|
FeeReason* reason) = 0;
|
||||||
|
|
||||||
|
//! Get max tx fee.
|
||||||
|
virtual CAmount getMaxTxFee() = 0;
|
||||||
|
|
||||||
|
//! Estimate smart fee.
|
||||||
|
virtual CFeeRate estimateSmartFee(int num_blocks, bool conservative, int* returned_target = nullptr) = 0;
|
||||||
|
|
||||||
|
//! Get dust relay fee.
|
||||||
|
virtual CFeeRate getDustRelayFee() = 0;
|
||||||
|
|
||||||
|
//! Get fallback fee.
|
||||||
|
virtual CFeeRate getFallbackFee() = 0;
|
||||||
|
|
||||||
|
//! Get pay tx fee.
|
||||||
|
virtual CFeeRate getPayTxFee() = 0;
|
||||||
|
|
||||||
|
//! Set pay tx fee.
|
||||||
|
virtual void setPayTxFee(CFeeRate rate) = 0;
|
||||||
|
|
||||||
|
//! Execute rpc command.
|
||||||
|
virtual UniValue executeRpc(const std::string& command, const UniValue& params, const std::string& uri) = 0;
|
||||||
|
|
||||||
|
//! List rpc commands.
|
||||||
|
virtual std::vector<std::string> listRpcCommands() = 0;
|
||||||
|
|
||||||
|
//! Set RPC timer interface if unset.
|
||||||
|
virtual void rpcSetTimerInterfaceIfUnset(RPCTimerInterface* iface) = 0;
|
||||||
|
|
||||||
|
//! Unset RPC timer interface.
|
||||||
|
virtual void rpcUnsetTimerInterface(RPCTimerInterface* iface) = 0;
|
||||||
|
|
||||||
|
//! Get unspent outputs associated with a transaction.
|
||||||
|
virtual bool getUnspentOutput(const COutPoint& output, Coin& coin) = 0;
|
||||||
|
|
||||||
|
//! Return interfaces for accessing wallets (if any).
|
||||||
|
virtual std::vector<std::unique_ptr<Wallet>> getWallets() = 0;
|
||||||
|
|
||||||
|
//! Register handler for init messages.
|
||||||
|
using InitMessageFn = std::function<void(const std::string& message)>;
|
||||||
|
virtual std::unique_ptr<Handler> handleInitMessage(InitMessageFn fn) = 0;
|
||||||
|
|
||||||
|
//! Register handler for message box messages.
|
||||||
|
using MessageBoxFn =
|
||||||
|
std::function<bool(const std::string& message, const std::string& caption, unsigned int style)>;
|
||||||
|
virtual std::unique_ptr<Handler> handleMessageBox(MessageBoxFn fn) = 0;
|
||||||
|
|
||||||
|
//! Register handler for question messages.
|
||||||
|
using QuestionFn = std::function<bool(const std::string& message,
|
||||||
|
const std::string& non_interactive_message,
|
||||||
|
const std::string& caption,
|
||||||
|
unsigned int style)>;
|
||||||
|
virtual std::unique_ptr<Handler> handleQuestion(QuestionFn fn) = 0;
|
||||||
|
|
||||||
|
//! Register handler for progress messages.
|
||||||
|
using ShowProgressFn = std::function<void(const std::string& title, int progress, bool resume_possible)>;
|
||||||
|
virtual std::unique_ptr<Handler> handleShowProgress(ShowProgressFn fn) = 0;
|
||||||
|
|
||||||
|
//! Register handler for load wallet messages.
|
||||||
|
using LoadWalletFn = std::function<void(std::unique_ptr<Wallet> wallet)>;
|
||||||
|
virtual std::unique_ptr<Handler> handleLoadWallet(LoadWalletFn fn) = 0;
|
||||||
|
|
||||||
|
//! Register handler for number of connections changed messages.
|
||||||
|
using NotifyNumConnectionsChangedFn = std::function<void(int new_num_connections)>;
|
||||||
|
virtual std::unique_ptr<Handler> handleNotifyNumConnectionsChanged(NotifyNumConnectionsChangedFn fn) = 0;
|
||||||
|
|
||||||
|
//! Register handler for network active messages.
|
||||||
|
using NotifyNetworkActiveChangedFn = std::function<void(bool network_active)>;
|
||||||
|
virtual std::unique_ptr<Handler> handleNotifyNetworkActiveChanged(NotifyNetworkActiveChangedFn fn) = 0;
|
||||||
|
|
||||||
|
//! Register handler for notify alert messages.
|
||||||
|
using NotifyAlertChangedFn = std::function<void()>;
|
||||||
|
virtual std::unique_ptr<Handler> handleNotifyAlertChanged(NotifyAlertChangedFn fn) = 0;
|
||||||
|
|
||||||
|
//! Register handler for ban list messages.
|
||||||
|
using BannedListChangedFn = std::function<void()>;
|
||||||
|
virtual std::unique_ptr<Handler> handleBannedListChanged(BannedListChangedFn fn) = 0;
|
||||||
|
|
||||||
|
//! Register handler for block tip messages.
|
||||||
|
using NotifyBlockTipFn =
|
||||||
|
std::function<void(bool initial_download, int height, int64_t block_time, double verification_progress)>;
|
||||||
|
virtual std::unique_ptr<Handler> handleNotifyBlockTip(NotifyBlockTipFn fn) = 0;
|
||||||
|
|
||||||
|
//! Register handler for header tip messages.
|
||||||
|
using NotifyHeaderTipFn =
|
||||||
|
std::function<void(bool initial_download, int height, int64_t block_time, double verification_progress)>;
|
||||||
|
virtual std::unique_ptr<Handler> handleNotifyHeaderTip(NotifyHeaderTipFn fn) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Return implementation of Node interface.
|
||||||
|
std::unique_ptr<Node> MakeNode();
|
||||||
|
|
||||||
|
} // namespace interface
|
||||||
|
|
||||||
|
#endif // BITCOIN_INTERFACE_NODE_H
|
441
src/interface/wallet.cpp
Normal file
441
src/interface/wallet.cpp
Normal file
|
@ -0,0 +1,441 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
#include <interface/wallet.h>
|
||||||
|
|
||||||
|
#include <amount.h>
|
||||||
|
#include <chain.h>
|
||||||
|
#include <consensus/validation.h>
|
||||||
|
#include <interface/handler.h>
|
||||||
|
#include <net.h>
|
||||||
|
#include <policy/policy.h>
|
||||||
|
#include <primitives/transaction.h>
|
||||||
|
#include <script/ismine.h>
|
||||||
|
#include <script/standard.h>
|
||||||
|
#include <support/allocators/secure.h>
|
||||||
|
#include <sync.h>
|
||||||
|
#include <timedata.h>
|
||||||
|
#include <ui_interface.h>
|
||||||
|
#include <uint256.h>
|
||||||
|
#include <validation.h>
|
||||||
|
#include <wallet/feebumper.h>
|
||||||
|
#include <wallet/wallet.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace interface {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class PendingWalletTxImpl : public PendingWalletTx
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PendingWalletTxImpl(CWallet& wallet) : m_wallet(wallet), m_key(&wallet) {}
|
||||||
|
|
||||||
|
const CTransaction& get() override { return *m_tx; }
|
||||||
|
|
||||||
|
int64_t getVirtualSize() override { return GetVirtualTransactionSize(*m_tx); }
|
||||||
|
|
||||||
|
bool commit(WalletValueMap value_map,
|
||||||
|
WalletOrderForm order_form,
|
||||||
|
std::string from_account,
|
||||||
|
std::string& reject_reason) override
|
||||||
|
{
|
||||||
|
LOCK2(cs_main, m_wallet.cs_wallet);
|
||||||
|
CValidationState state;
|
||||||
|
if (!m_wallet.CommitTransaction(m_tx, std::move(value_map), std::move(order_form), std::move(from_account), m_key, g_connman.get(), state)) {
|
||||||
|
reject_reason = state.GetRejectReason();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
CTransactionRef m_tx;
|
||||||
|
CWallet& m_wallet;
|
||||||
|
CReserveKey m_key;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Construct wallet tx struct.
|
||||||
|
WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx)
|
||||||
|
{
|
||||||
|
WalletTx result;
|
||||||
|
result.tx = wtx.tx;
|
||||||
|
result.txin_is_mine.reserve(wtx.tx->vin.size());
|
||||||
|
for (const auto& txin : wtx.tx->vin) {
|
||||||
|
result.txin_is_mine.emplace_back(wallet.IsMine(txin));
|
||||||
|
}
|
||||||
|
result.txout_is_mine.reserve(wtx.tx->vout.size());
|
||||||
|
result.txout_address.reserve(wtx.tx->vout.size());
|
||||||
|
result.txout_address_is_mine.reserve(wtx.tx->vout.size());
|
||||||
|
for (const auto& txout : wtx.tx->vout) {
|
||||||
|
result.txout_is_mine.emplace_back(wallet.IsMine(txout));
|
||||||
|
result.txout_address.emplace_back();
|
||||||
|
result.txout_address_is_mine.emplace_back(ExtractDestination(txout.scriptPubKey, result.txout_address.back()) ?
|
||||||
|
IsMine(wallet, result.txout_address.back()) :
|
||||||
|
ISMINE_NO);
|
||||||
|
}
|
||||||
|
result.credit = wtx.GetCredit(ISMINE_ALL);
|
||||||
|
result.debit = wtx.GetDebit(ISMINE_ALL);
|
||||||
|
result.change = wtx.GetChange();
|
||||||
|
result.time = wtx.GetTxTime();
|
||||||
|
result.value_map = wtx.mapValue;
|
||||||
|
result.is_coinbase = wtx.IsCoinBase();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Construct wallet tx status struct.
|
||||||
|
WalletTxStatus MakeWalletTxStatus(const CWalletTx& wtx)
|
||||||
|
{
|
||||||
|
WalletTxStatus result;
|
||||||
|
auto mi = ::mapBlockIndex.find(wtx.hashBlock);
|
||||||
|
CBlockIndex* block = mi != ::mapBlockIndex.end() ? mi->second : nullptr;
|
||||||
|
result.block_height = (block ? block->nHeight : std::numeric_limits<int>::max()),
|
||||||
|
result.blocks_to_maturity = wtx.GetBlocksToMaturity();
|
||||||
|
result.depth_in_main_chain = wtx.GetDepthInMainChain();
|
||||||
|
result.request_count = wtx.GetRequestCount();
|
||||||
|
result.time_received = wtx.nTimeReceived;
|
||||||
|
result.lock_time = wtx.tx->nLockTime;
|
||||||
|
result.is_final = CheckFinalTx(*wtx.tx);
|
||||||
|
result.is_trusted = wtx.IsTrusted();
|
||||||
|
result.is_abandoned = wtx.isAbandoned();
|
||||||
|
result.is_coinbase = wtx.IsCoinBase();
|
||||||
|
result.is_in_main_chain = wtx.IsInMainChain();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Construct wallet TxOut struct.
|
||||||
|
WalletTxOut MakeWalletTxOut(CWallet& wallet, const CWalletTx& wtx, int n, int depth)
|
||||||
|
{
|
||||||
|
WalletTxOut result;
|
||||||
|
result.txout = wtx.tx->vout[n];
|
||||||
|
result.time = wtx.GetTxTime();
|
||||||
|
result.depth_in_main_chain = depth;
|
||||||
|
result.is_spent = wallet.IsSpent(wtx.GetHash(), n);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
class WalletImpl : public Wallet
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
WalletImpl(CWallet& wallet) : m_wallet(wallet) {}
|
||||||
|
|
||||||
|
bool encryptWallet(const SecureString& wallet_passphrase) override
|
||||||
|
{
|
||||||
|
return m_wallet.EncryptWallet(wallet_passphrase);
|
||||||
|
}
|
||||||
|
bool isCrypted() override { return m_wallet.IsCrypted(); }
|
||||||
|
bool lock() override { return m_wallet.Lock(); }
|
||||||
|
bool unlock(const SecureString& wallet_passphrase) override { return m_wallet.Unlock(wallet_passphrase); }
|
||||||
|
bool isLocked() override { return m_wallet.IsLocked(); }
|
||||||
|
bool changeWalletPassphrase(const SecureString& old_wallet_passphrase,
|
||||||
|
const SecureString& new_wallet_passphrase) override
|
||||||
|
{
|
||||||
|
return m_wallet.ChangeWalletPassphrase(old_wallet_passphrase, new_wallet_passphrase);
|
||||||
|
}
|
||||||
|
bool backupWallet(const std::string& filename) override { return m_wallet.BackupWallet(filename); }
|
||||||
|
std::string getWalletName() override { return m_wallet.GetName(); }
|
||||||
|
bool getKeyFromPool(bool internal, CPubKey& pub_key) override
|
||||||
|
{
|
||||||
|
return m_wallet.GetKeyFromPool(pub_key, internal);
|
||||||
|
}
|
||||||
|
bool getPubKey(const CKeyID& address, CPubKey& pub_key) override { return m_wallet.GetPubKey(address, pub_key); }
|
||||||
|
bool getPrivKey(const CKeyID& address, CKey& key) override { return m_wallet.GetKey(address, key); }
|
||||||
|
bool isSpendable(const CTxDestination& dest) override { return IsMine(m_wallet, dest) & ISMINE_SPENDABLE; }
|
||||||
|
bool haveWatchOnly() override { return m_wallet.HaveWatchOnly(); };
|
||||||
|
bool setAddressBook(const CTxDestination& dest, const std::string& name, const std::string& purpose) override
|
||||||
|
{
|
||||||
|
return m_wallet.SetAddressBook(dest, name, purpose);
|
||||||
|
}
|
||||||
|
bool delAddressBook(const CTxDestination& dest) override
|
||||||
|
{
|
||||||
|
return m_wallet.DelAddressBook(dest);
|
||||||
|
}
|
||||||
|
bool getAddress(const CTxDestination& dest, std::string* name, isminetype* is_mine) override
|
||||||
|
{
|
||||||
|
LOCK(m_wallet.cs_wallet);
|
||||||
|
auto it = m_wallet.mapAddressBook.find(dest);
|
||||||
|
if (it == m_wallet.mapAddressBook.end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (name) {
|
||||||
|
*name = it->second.name;
|
||||||
|
}
|
||||||
|
if (is_mine) {
|
||||||
|
*is_mine = IsMine(m_wallet, dest);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
std::vector<WalletAddress> getAddresses() override
|
||||||
|
{
|
||||||
|
LOCK(m_wallet.cs_wallet);
|
||||||
|
std::vector<WalletAddress> result;
|
||||||
|
for (const auto& item : m_wallet.mapAddressBook) {
|
||||||
|
result.emplace_back(item.first, IsMine(m_wallet, item.first), item.second.name, item.second.purpose);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
void learnRelatedScripts(const CPubKey& key, OutputType type) override { m_wallet.LearnRelatedScripts(key, type); }
|
||||||
|
bool addDestData(const CTxDestination& dest, const std::string& key, const std::string& value) override
|
||||||
|
{
|
||||||
|
LOCK(m_wallet.cs_wallet);
|
||||||
|
return m_wallet.AddDestData(dest, key, value);
|
||||||
|
}
|
||||||
|
bool eraseDestData(const CTxDestination& dest, const std::string& key) override
|
||||||
|
{
|
||||||
|
LOCK(m_wallet.cs_wallet);
|
||||||
|
return m_wallet.EraseDestData(dest, key);
|
||||||
|
}
|
||||||
|
std::vector<std::string> getDestValues(const std::string& prefix) override
|
||||||
|
{
|
||||||
|
return m_wallet.GetDestValues(prefix);
|
||||||
|
}
|
||||||
|
void lockCoin(const COutPoint& output) override
|
||||||
|
{
|
||||||
|
LOCK2(cs_main, m_wallet.cs_wallet);
|
||||||
|
return m_wallet.LockCoin(output);
|
||||||
|
}
|
||||||
|
void unlockCoin(const COutPoint& output) override
|
||||||
|
{
|
||||||
|
LOCK2(cs_main, m_wallet.cs_wallet);
|
||||||
|
return m_wallet.UnlockCoin(output);
|
||||||
|
}
|
||||||
|
bool isLockedCoin(const COutPoint& output) override
|
||||||
|
{
|
||||||
|
LOCK2(cs_main, m_wallet.cs_wallet);
|
||||||
|
return m_wallet.IsLockedCoin(output.hash, output.n);
|
||||||
|
}
|
||||||
|
void listLockedCoins(std::vector<COutPoint>& outputs) override
|
||||||
|
{
|
||||||
|
LOCK2(cs_main, m_wallet.cs_wallet);
|
||||||
|
return m_wallet.ListLockedCoins(outputs);
|
||||||
|
}
|
||||||
|
std::unique_ptr<PendingWalletTx> createTransaction(const std::vector<CRecipient>& recipients,
|
||||||
|
const CCoinControl& coin_control,
|
||||||
|
bool sign,
|
||||||
|
int& change_pos,
|
||||||
|
CAmount& fee,
|
||||||
|
std::string& fail_reason) override
|
||||||
|
{
|
||||||
|
LOCK2(cs_main, m_wallet.cs_wallet);
|
||||||
|
auto pending = MakeUnique<PendingWalletTxImpl>(m_wallet);
|
||||||
|
if (!m_wallet.CreateTransaction(recipients, pending->m_tx, pending->m_key, fee, change_pos,
|
||||||
|
fail_reason, coin_control, sign)) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return std::move(pending);
|
||||||
|
}
|
||||||
|
bool transactionCanBeAbandoned(const uint256& txid) override { return m_wallet.TransactionCanBeAbandoned(txid); }
|
||||||
|
bool abandonTransaction(const uint256& txid) override
|
||||||
|
{
|
||||||
|
LOCK2(cs_main, m_wallet.cs_wallet);
|
||||||
|
return m_wallet.AbandonTransaction(txid);
|
||||||
|
}
|
||||||
|
bool transactionCanBeBumped(const uint256& txid) override
|
||||||
|
{
|
||||||
|
return feebumper::TransactionCanBeBumped(&m_wallet, txid);
|
||||||
|
}
|
||||||
|
bool createBumpTransaction(const uint256& txid,
|
||||||
|
const CCoinControl& coin_control,
|
||||||
|
CAmount total_fee,
|
||||||
|
std::vector<std::string>& errors,
|
||||||
|
CAmount& old_fee,
|
||||||
|
CAmount& new_fee,
|
||||||
|
CMutableTransaction& mtx) override
|
||||||
|
{
|
||||||
|
return feebumper::CreateTransaction(&m_wallet, txid, coin_control, total_fee, errors, old_fee, new_fee, mtx) ==
|
||||||
|
feebumper::Result::OK;
|
||||||
|
}
|
||||||
|
bool signBumpTransaction(CMutableTransaction& mtx) override { return feebumper::SignTransaction(&m_wallet, mtx); }
|
||||||
|
bool commitBumpTransaction(const uint256& txid,
|
||||||
|
CMutableTransaction&& mtx,
|
||||||
|
std::vector<std::string>& errors,
|
||||||
|
uint256& bumped_txid) override
|
||||||
|
{
|
||||||
|
return feebumper::CommitTransaction(&m_wallet, txid, std::move(mtx), errors, bumped_txid) ==
|
||||||
|
feebumper::Result::OK;
|
||||||
|
}
|
||||||
|
CTransactionRef getTx(const uint256& txid) override
|
||||||
|
{
|
||||||
|
LOCK2(::cs_main, m_wallet.cs_wallet);
|
||||||
|
auto mi = m_wallet.mapWallet.find(txid);
|
||||||
|
if (mi != m_wallet.mapWallet.end()) {
|
||||||
|
return mi->second.tx;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
WalletTx getWalletTx(const uint256& txid) override
|
||||||
|
{
|
||||||
|
LOCK2(::cs_main, m_wallet.cs_wallet);
|
||||||
|
auto mi = m_wallet.mapWallet.find(txid);
|
||||||
|
if (mi != m_wallet.mapWallet.end()) {
|
||||||
|
return MakeWalletTx(m_wallet, mi->second);
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
std::vector<WalletTx> getWalletTxs() override
|
||||||
|
{
|
||||||
|
LOCK2(::cs_main, m_wallet.cs_wallet);
|
||||||
|
std::vector<WalletTx> result;
|
||||||
|
result.reserve(m_wallet.mapWallet.size());
|
||||||
|
for (const auto& entry : m_wallet.mapWallet) {
|
||||||
|
result.emplace_back(MakeWalletTx(m_wallet, entry.second));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
bool tryGetTxStatus(const uint256& txid,
|
||||||
|
interface::WalletTxStatus& tx_status,
|
||||||
|
int& num_blocks,
|
||||||
|
int64_t& adjusted_time) override
|
||||||
|
{
|
||||||
|
TRY_LOCK(::cs_main, locked_chain);
|
||||||
|
if (!locked_chain) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
TRY_LOCK(m_wallet.cs_wallet, locked_wallet);
|
||||||
|
if (!locked_wallet) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto mi = m_wallet.mapWallet.find(txid);
|
||||||
|
if (mi == m_wallet.mapWallet.end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
num_blocks = ::chainActive.Height();
|
||||||
|
adjusted_time = GetAdjustedTime();
|
||||||
|
tx_status = MakeWalletTxStatus(mi->second);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
WalletTx getWalletTxDetails(const uint256& txid,
|
||||||
|
WalletTxStatus& tx_status,
|
||||||
|
WalletOrderForm& order_form,
|
||||||
|
bool& in_mempool,
|
||||||
|
int& num_blocks,
|
||||||
|
int64_t& adjusted_time) override
|
||||||
|
{
|
||||||
|
LOCK2(::cs_main, m_wallet.cs_wallet);
|
||||||
|
auto mi = m_wallet.mapWallet.find(txid);
|
||||||
|
if (mi != m_wallet.mapWallet.end()) {
|
||||||
|
num_blocks = ::chainActive.Height();
|
||||||
|
adjusted_time = GetAdjustedTime();
|
||||||
|
in_mempool = mi->second.InMempool();
|
||||||
|
order_form = mi->second.vOrderForm;
|
||||||
|
tx_status = MakeWalletTxStatus(mi->second);
|
||||||
|
return MakeWalletTx(m_wallet, mi->second);
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
WalletBalances getBalances() override
|
||||||
|
{
|
||||||
|
WalletBalances result;
|
||||||
|
result.balance = m_wallet.GetBalance();
|
||||||
|
result.unconfirmed_balance = m_wallet.GetUnconfirmedBalance();
|
||||||
|
result.immature_balance = m_wallet.GetImmatureBalance();
|
||||||
|
result.have_watch_only = m_wallet.HaveWatchOnly();
|
||||||
|
if (result.have_watch_only) {
|
||||||
|
result.watch_only_balance = m_wallet.GetWatchOnlyBalance();
|
||||||
|
result.unconfirmed_watch_only_balance = m_wallet.GetUnconfirmedWatchOnlyBalance();
|
||||||
|
result.immature_watch_only_balance = m_wallet.GetImmatureWatchOnlyBalance();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
bool tryGetBalances(WalletBalances& balances, int& num_blocks) override
|
||||||
|
{
|
||||||
|
TRY_LOCK(cs_main, locked_chain);
|
||||||
|
if (!locked_chain) return false;
|
||||||
|
TRY_LOCK(m_wallet.cs_wallet, locked_wallet);
|
||||||
|
if (!locked_wallet) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
balances = getBalances();
|
||||||
|
num_blocks = ::chainActive.Height();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
CAmount getBalance() override { return m_wallet.GetBalance(); }
|
||||||
|
CAmount getAvailableBalance(const CCoinControl& coin_control) override
|
||||||
|
{
|
||||||
|
return m_wallet.GetAvailableBalance(&coin_control);
|
||||||
|
}
|
||||||
|
isminetype txinIsMine(const CTxIn& txin) override
|
||||||
|
{
|
||||||
|
LOCK2(::cs_main, m_wallet.cs_wallet);
|
||||||
|
return m_wallet.IsMine(txin);
|
||||||
|
}
|
||||||
|
isminetype txoutIsMine(const CTxOut& txout) override
|
||||||
|
{
|
||||||
|
LOCK2(::cs_main, m_wallet.cs_wallet);
|
||||||
|
return m_wallet.IsMine(txout);
|
||||||
|
}
|
||||||
|
CAmount getDebit(const CTxIn& txin, isminefilter filter) override
|
||||||
|
{
|
||||||
|
LOCK2(::cs_main, m_wallet.cs_wallet);
|
||||||
|
return m_wallet.GetDebit(txin, filter);
|
||||||
|
}
|
||||||
|
CAmount getCredit(const CTxOut& txout, isminefilter filter) override
|
||||||
|
{
|
||||||
|
LOCK2(::cs_main, m_wallet.cs_wallet);
|
||||||
|
return m_wallet.GetCredit(txout, filter);
|
||||||
|
}
|
||||||
|
CoinsList listCoins() override
|
||||||
|
{
|
||||||
|
LOCK2(::cs_main, m_wallet.cs_wallet);
|
||||||
|
CoinsList result;
|
||||||
|
for (const auto& entry : m_wallet.ListCoins()) {
|
||||||
|
auto& group = result[entry.first];
|
||||||
|
for (const auto& coin : entry.second) {
|
||||||
|
group.emplace_back(
|
||||||
|
COutPoint(coin.tx->GetHash(), coin.i), MakeWalletTxOut(m_wallet, *coin.tx, coin.i, coin.nDepth));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
std::vector<WalletTxOut> getCoins(const std::vector<COutPoint>& outputs) override
|
||||||
|
{
|
||||||
|
LOCK2(::cs_main, m_wallet.cs_wallet);
|
||||||
|
std::vector<WalletTxOut> result;
|
||||||
|
result.reserve(outputs.size());
|
||||||
|
for (const auto& output : outputs) {
|
||||||
|
result.emplace_back();
|
||||||
|
auto it = m_wallet.mapWallet.find(output.hash);
|
||||||
|
if (it != m_wallet.mapWallet.end()) {
|
||||||
|
int depth = it->second.GetDepthInMainChain();
|
||||||
|
if (depth >= 0) {
|
||||||
|
result.back() = MakeWalletTxOut(m_wallet, it->second, output.n, depth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
bool hdEnabled() override { return m_wallet.IsHDEnabled(); }
|
||||||
|
OutputType getDefaultAddressType() override { return m_wallet.m_default_address_type; }
|
||||||
|
OutputType getDefaultChangeType() override { return m_wallet.m_default_change_type; }
|
||||||
|
std::unique_ptr<Handler> handleShowProgress(ShowProgressFn fn) override
|
||||||
|
{
|
||||||
|
return MakeHandler(m_wallet.ShowProgress.connect(fn));
|
||||||
|
}
|
||||||
|
std::unique_ptr<Handler> handleStatusChanged(StatusChangedFn fn) override
|
||||||
|
{
|
||||||
|
return MakeHandler(m_wallet.NotifyStatusChanged.connect([fn](CCryptoKeyStore*) { fn(); }));
|
||||||
|
}
|
||||||
|
std::unique_ptr<Handler> handleAddressBookChanged(AddressBookChangedFn fn) override
|
||||||
|
{
|
||||||
|
return MakeHandler(m_wallet.NotifyAddressBookChanged.connect(
|
||||||
|
[fn](CWallet*, const CTxDestination& address, const std::string& label, bool is_mine,
|
||||||
|
const std::string& purpose, ChangeType status) { fn(address, label, is_mine, purpose, status); }));
|
||||||
|
}
|
||||||
|
std::unique_ptr<Handler> handleTransactionChanged(TransactionChangedFn fn) override
|
||||||
|
{
|
||||||
|
return MakeHandler(m_wallet.NotifyTransactionChanged.connect(
|
||||||
|
[fn, this](CWallet*, const uint256& txid, ChangeType status) { fn(txid, status); }));
|
||||||
|
}
|
||||||
|
std::unique_ptr<Handler> handleWatchOnlyChanged(WatchOnlyChangedFn fn) override
|
||||||
|
{
|
||||||
|
return MakeHandler(m_wallet.NotifyWatchonlyChanged.connect(fn));
|
||||||
|
}
|
||||||
|
|
||||||
|
CWallet& m_wallet;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
std::unique_ptr<Wallet> MakeWallet(CWallet& wallet) { return MakeUnique<WalletImpl>(wallet); }
|
||||||
|
|
||||||
|
} // namespace interface
|
352
src/interface/wallet.h
Normal file
352
src/interface/wallet.h
Normal file
|
@ -0,0 +1,352 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
#ifndef BITCOIN_INTERFACE_WALLET_H
|
||||||
|
#define BITCOIN_INTERFACE_WALLET_H
|
||||||
|
|
||||||
|
#include <amount.h> // For CAmount
|
||||||
|
#include <pubkey.h> // For CTxDestination (CKeyID and CScriptID)
|
||||||
|
#include <script/ismine.h> // For isminefilter, isminetype
|
||||||
|
#include <script/standard.h> // For CTxDestination
|
||||||
|
#include <support/allocators/secure.h> // For SecureString
|
||||||
|
#include <ui_interface.h> // For ChangeType
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string>
|
||||||
|
#include <tuple>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class CCoinControl;
|
||||||
|
class CKey;
|
||||||
|
class CWallet;
|
||||||
|
enum class OutputType;
|
||||||
|
struct CRecipient;
|
||||||
|
|
||||||
|
namespace interface {
|
||||||
|
|
||||||
|
class Handler;
|
||||||
|
class PendingWalletTx;
|
||||||
|
struct WalletAddress;
|
||||||
|
struct WalletBalances;
|
||||||
|
struct WalletTx;
|
||||||
|
struct WalletTxOut;
|
||||||
|
struct WalletTxStatus;
|
||||||
|
|
||||||
|
using WalletOrderForm = std::vector<std::pair<std::string, std::string>>;
|
||||||
|
using WalletValueMap = std::map<std::string, std::string>;
|
||||||
|
|
||||||
|
//! Interface for accessing a wallet.
|
||||||
|
class Wallet
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~Wallet() {}
|
||||||
|
|
||||||
|
//! Encrypt wallet.
|
||||||
|
virtual bool encryptWallet(const SecureString& wallet_passphrase) = 0;
|
||||||
|
|
||||||
|
//! Return whether wallet is encrypted.
|
||||||
|
virtual bool isCrypted() = 0;
|
||||||
|
|
||||||
|
//! Lock wallet.
|
||||||
|
virtual bool lock() = 0;
|
||||||
|
|
||||||
|
//! Unlock wallet.
|
||||||
|
virtual bool unlock(const SecureString& wallet_passphrase) = 0;
|
||||||
|
|
||||||
|
//! Return whether wallet is locked.
|
||||||
|
virtual bool isLocked() = 0;
|
||||||
|
|
||||||
|
//! Change wallet passphrase.
|
||||||
|
virtual bool changeWalletPassphrase(const SecureString& old_wallet_passphrase,
|
||||||
|
const SecureString& new_wallet_passphrase) = 0;
|
||||||
|
|
||||||
|
//! Back up wallet.
|
||||||
|
virtual bool backupWallet(const std::string& filename) = 0;
|
||||||
|
|
||||||
|
//! Get wallet name.
|
||||||
|
virtual std::string getWalletName() = 0;
|
||||||
|
|
||||||
|
// Get key from pool.
|
||||||
|
virtual bool getKeyFromPool(bool internal, CPubKey& pub_key) = 0;
|
||||||
|
|
||||||
|
//! Get public key.
|
||||||
|
virtual bool getPubKey(const CKeyID& address, CPubKey& pub_key) = 0;
|
||||||
|
|
||||||
|
//! Get private key.
|
||||||
|
virtual bool getPrivKey(const CKeyID& address, CKey& key) = 0;
|
||||||
|
|
||||||
|
//! Return whether wallet has private key.
|
||||||
|
virtual bool isSpendable(const CTxDestination& dest) = 0;
|
||||||
|
|
||||||
|
//! Return whether wallet has watch only keys.
|
||||||
|
virtual bool haveWatchOnly() = 0;
|
||||||
|
|
||||||
|
//! Add or update address.
|
||||||
|
virtual bool setAddressBook(const CTxDestination& dest, const std::string& name, const std::string& purpose) = 0;
|
||||||
|
|
||||||
|
// Remove address.
|
||||||
|
virtual bool delAddressBook(const CTxDestination& dest) = 0;
|
||||||
|
|
||||||
|
//! Look up address in wallet, return whether exists.
|
||||||
|
virtual bool getAddress(const CTxDestination& dest,
|
||||||
|
std::string* name = nullptr,
|
||||||
|
isminetype* is_mine = nullptr) = 0;
|
||||||
|
|
||||||
|
//! Get wallet address list.
|
||||||
|
virtual std::vector<WalletAddress> getAddresses() = 0;
|
||||||
|
|
||||||
|
//! Add scripts to key store so old so software versions opening the wallet
|
||||||
|
//! database can detect payments to newer address types.
|
||||||
|
virtual void learnRelatedScripts(const CPubKey& key, OutputType type) = 0;
|
||||||
|
|
||||||
|
//! Add dest data.
|
||||||
|
virtual bool addDestData(const CTxDestination& dest, const std::string& key, const std::string& value) = 0;
|
||||||
|
|
||||||
|
//! Erase dest data.
|
||||||
|
virtual bool eraseDestData(const CTxDestination& dest, const std::string& key) = 0;
|
||||||
|
|
||||||
|
//! Get dest values with prefix.
|
||||||
|
virtual std::vector<std::string> getDestValues(const std::string& prefix) = 0;
|
||||||
|
|
||||||
|
//! Lock coin.
|
||||||
|
virtual void lockCoin(const COutPoint& output) = 0;
|
||||||
|
|
||||||
|
//! Unlock coin.
|
||||||
|
virtual void unlockCoin(const COutPoint& output) = 0;
|
||||||
|
|
||||||
|
//! Return whether coin is locked.
|
||||||
|
virtual bool isLockedCoin(const COutPoint& output) = 0;
|
||||||
|
|
||||||
|
//! List locked coins.
|
||||||
|
virtual void listLockedCoins(std::vector<COutPoint>& outputs) = 0;
|
||||||
|
|
||||||
|
//! Create transaction.
|
||||||
|
virtual std::unique_ptr<PendingWalletTx> createTransaction(const std::vector<CRecipient>& recipients,
|
||||||
|
const CCoinControl& coin_control,
|
||||||
|
bool sign,
|
||||||
|
int& change_pos,
|
||||||
|
CAmount& fee,
|
||||||
|
std::string& fail_reason) = 0;
|
||||||
|
|
||||||
|
//! Return whether transaction can be abandoned.
|
||||||
|
virtual bool transactionCanBeAbandoned(const uint256& txid) = 0;
|
||||||
|
|
||||||
|
//! Abandon transaction.
|
||||||
|
virtual bool abandonTransaction(const uint256& txid) = 0;
|
||||||
|
|
||||||
|
//! Return whether transaction can be bumped.
|
||||||
|
virtual bool transactionCanBeBumped(const uint256& txid) = 0;
|
||||||
|
|
||||||
|
//! Create bump transaction.
|
||||||
|
virtual bool createBumpTransaction(const uint256& txid,
|
||||||
|
const CCoinControl& coin_control,
|
||||||
|
CAmount total_fee,
|
||||||
|
std::vector<std::string>& errors,
|
||||||
|
CAmount& old_fee,
|
||||||
|
CAmount& new_fee,
|
||||||
|
CMutableTransaction& mtx) = 0;
|
||||||
|
|
||||||
|
//! Sign bump transaction.
|
||||||
|
virtual bool signBumpTransaction(CMutableTransaction& mtx) = 0;
|
||||||
|
|
||||||
|
//! Commit bump transaction.
|
||||||
|
virtual bool commitBumpTransaction(const uint256& txid,
|
||||||
|
CMutableTransaction&& mtx,
|
||||||
|
std::vector<std::string>& errors,
|
||||||
|
uint256& bumped_txid) = 0;
|
||||||
|
|
||||||
|
//! Get a transaction.
|
||||||
|
virtual CTransactionRef getTx(const uint256& txid) = 0;
|
||||||
|
|
||||||
|
//! Get transaction information.
|
||||||
|
virtual WalletTx getWalletTx(const uint256& txid) = 0;
|
||||||
|
|
||||||
|
//! Get list of all wallet transactions.
|
||||||
|
virtual std::vector<WalletTx> getWalletTxs() = 0;
|
||||||
|
|
||||||
|
//! Try to get updated status for a particular transaction, if possible without blocking.
|
||||||
|
virtual bool tryGetTxStatus(const uint256& txid,
|
||||||
|
WalletTxStatus& tx_status,
|
||||||
|
int& num_blocks,
|
||||||
|
int64_t& adjusted_time) = 0;
|
||||||
|
|
||||||
|
//! Get transaction details.
|
||||||
|
virtual WalletTx getWalletTxDetails(const uint256& txid,
|
||||||
|
WalletTxStatus& tx_status,
|
||||||
|
WalletOrderForm& order_form,
|
||||||
|
bool& in_mempool,
|
||||||
|
int& num_blocks,
|
||||||
|
int64_t& adjusted_time) = 0;
|
||||||
|
|
||||||
|
//! Get balances.
|
||||||
|
virtual WalletBalances getBalances() = 0;
|
||||||
|
|
||||||
|
//! Get balances if possible without blocking.
|
||||||
|
virtual bool tryGetBalances(WalletBalances& balances, int& num_blocks) = 0;
|
||||||
|
|
||||||
|
//! Get balance.
|
||||||
|
virtual CAmount getBalance() = 0;
|
||||||
|
|
||||||
|
//! Get available balance.
|
||||||
|
virtual CAmount getAvailableBalance(const CCoinControl& coin_control) = 0;
|
||||||
|
|
||||||
|
//! Return whether transaction input belongs to wallet.
|
||||||
|
virtual isminetype txinIsMine(const CTxIn& txin) = 0;
|
||||||
|
|
||||||
|
//! Return whether transaction output belongs to wallet.
|
||||||
|
virtual isminetype txoutIsMine(const CTxOut& txout) = 0;
|
||||||
|
|
||||||
|
//! Return debit amount if transaction input belongs to wallet.
|
||||||
|
virtual CAmount getDebit(const CTxIn& txin, isminefilter filter) = 0;
|
||||||
|
|
||||||
|
//! Return credit amount if transaction input belongs to wallet.
|
||||||
|
virtual CAmount getCredit(const CTxOut& txout, isminefilter filter) = 0;
|
||||||
|
|
||||||
|
//! Return AvailableCoins + LockedCoins grouped by wallet address.
|
||||||
|
//! (put change in one group with wallet address)
|
||||||
|
using CoinsList = std::map<CTxDestination, std::vector<std::tuple<COutPoint, WalletTxOut>>>;
|
||||||
|
virtual CoinsList listCoins() = 0;
|
||||||
|
|
||||||
|
//! Return wallet transaction output information.
|
||||||
|
virtual std::vector<WalletTxOut> getCoins(const std::vector<COutPoint>& outputs) = 0;
|
||||||
|
|
||||||
|
// Return whether HD enabled.
|
||||||
|
virtual bool hdEnabled() = 0;
|
||||||
|
|
||||||
|
// Get default address type.
|
||||||
|
virtual OutputType getDefaultAddressType() = 0;
|
||||||
|
|
||||||
|
// Get default change type.
|
||||||
|
virtual OutputType getDefaultChangeType() = 0;
|
||||||
|
|
||||||
|
//! Register handler for show progress messages.
|
||||||
|
using ShowProgressFn = std::function<void(const std::string& title, int progress)>;
|
||||||
|
virtual std::unique_ptr<Handler> handleShowProgress(ShowProgressFn fn) = 0;
|
||||||
|
|
||||||
|
//! Register handler for status changed messages.
|
||||||
|
using StatusChangedFn = std::function<void()>;
|
||||||
|
virtual std::unique_ptr<Handler> handleStatusChanged(StatusChangedFn fn) = 0;
|
||||||
|
|
||||||
|
//! Register handler for address book changed messages.
|
||||||
|
using AddressBookChangedFn = std::function<void(const CTxDestination& address,
|
||||||
|
const std::string& label,
|
||||||
|
bool is_mine,
|
||||||
|
const std::string& purpose,
|
||||||
|
ChangeType status)>;
|
||||||
|
virtual std::unique_ptr<Handler> handleAddressBookChanged(AddressBookChangedFn fn) = 0;
|
||||||
|
|
||||||
|
//! Register handler for transaction changed messages.
|
||||||
|
using TransactionChangedFn = std::function<void(const uint256& txid, ChangeType status)>;
|
||||||
|
virtual std::unique_ptr<Handler> handleTransactionChanged(TransactionChangedFn fn) = 0;
|
||||||
|
|
||||||
|
//! Register handler for watchonly changed messages.
|
||||||
|
using WatchOnlyChangedFn = std::function<void(bool have_watch_only)>;
|
||||||
|
virtual std::unique_ptr<Handler> handleWatchOnlyChanged(WatchOnlyChangedFn fn) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Tracking object returned by CreateTransaction and passed to CommitTransaction.
|
||||||
|
class PendingWalletTx
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~PendingWalletTx() {}
|
||||||
|
|
||||||
|
//! Get transaction data.
|
||||||
|
virtual const CTransaction& get() = 0;
|
||||||
|
|
||||||
|
//! Get virtual transaction size.
|
||||||
|
virtual int64_t getVirtualSize() = 0;
|
||||||
|
|
||||||
|
//! Send pending transaction and commit to wallet.
|
||||||
|
virtual bool commit(WalletValueMap value_map,
|
||||||
|
WalletOrderForm order_form,
|
||||||
|
std::string from_account,
|
||||||
|
std::string& reject_reason) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Information about one wallet address.
|
||||||
|
struct WalletAddress
|
||||||
|
{
|
||||||
|
CTxDestination dest;
|
||||||
|
isminetype is_mine;
|
||||||
|
std::string name;
|
||||||
|
std::string purpose;
|
||||||
|
|
||||||
|
WalletAddress(CTxDestination dest, isminetype is_mine, std::string name, std::string purpose)
|
||||||
|
: dest(std::move(dest)), is_mine(is_mine), name(std::move(name)), purpose(std::move(purpose))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Collection of wallet balances.
|
||||||
|
struct WalletBalances
|
||||||
|
{
|
||||||
|
CAmount balance = 0;
|
||||||
|
CAmount unconfirmed_balance = 0;
|
||||||
|
CAmount immature_balance = 0;
|
||||||
|
bool have_watch_only = false;
|
||||||
|
CAmount watch_only_balance = 0;
|
||||||
|
CAmount unconfirmed_watch_only_balance = 0;
|
||||||
|
CAmount immature_watch_only_balance = 0;
|
||||||
|
|
||||||
|
bool balanceChanged(const WalletBalances& prev) const
|
||||||
|
{
|
||||||
|
return balance != prev.balance || unconfirmed_balance != prev.unconfirmed_balance ||
|
||||||
|
immature_balance != prev.immature_balance || watch_only_balance != prev.watch_only_balance ||
|
||||||
|
unconfirmed_watch_only_balance != prev.unconfirmed_watch_only_balance ||
|
||||||
|
immature_watch_only_balance != prev.immature_watch_only_balance;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Wallet transaction information.
|
||||||
|
struct WalletTx
|
||||||
|
{
|
||||||
|
CTransactionRef tx;
|
||||||
|
std::vector<isminetype> txin_is_mine;
|
||||||
|
std::vector<isminetype> txout_is_mine;
|
||||||
|
std::vector<CTxDestination> txout_address;
|
||||||
|
std::vector<isminetype> txout_address_is_mine;
|
||||||
|
CAmount credit;
|
||||||
|
CAmount debit;
|
||||||
|
CAmount change;
|
||||||
|
int64_t time;
|
||||||
|
std::map<std::string, std::string> value_map;
|
||||||
|
bool is_coinbase;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Updated transaction status.
|
||||||
|
struct WalletTxStatus
|
||||||
|
{
|
||||||
|
int block_height;
|
||||||
|
int blocks_to_maturity;
|
||||||
|
int depth_in_main_chain;
|
||||||
|
int request_count;
|
||||||
|
unsigned int time_received;
|
||||||
|
uint32_t lock_time;
|
||||||
|
bool is_final;
|
||||||
|
bool is_trusted;
|
||||||
|
bool is_abandoned;
|
||||||
|
bool is_coinbase;
|
||||||
|
bool is_in_main_chain;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Wallet transaction output.
|
||||||
|
struct WalletTxOut
|
||||||
|
{
|
||||||
|
CTxOut txout;
|
||||||
|
int64_t time;
|
||||||
|
int depth_in_main_chain = -1;
|
||||||
|
bool is_spent = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Return implementation of Wallet interface. This function will be undefined
|
||||||
|
//! in builds where ENABLE_WALLET is false.
|
||||||
|
std::unique_ptr<Wallet> MakeWallet(CWallet& wallet);
|
||||||
|
|
||||||
|
} // namespace interface
|
||||||
|
|
||||||
|
#endif // BITCOIN_INTERFACE_WALLET_H
|
|
@ -86,9 +86,9 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CNodeStateStats {
|
struct CNodeStateStats {
|
||||||
int nMisbehavior;
|
int nMisbehavior = 0;
|
||||||
int nSyncHeight;
|
int nSyncHeight = -1;
|
||||||
int nCommonHeight;
|
int nCommonHeight = -1;
|
||||||
std::vector<int> vHeightInFlight;
|
std::vector<int> vHeightInFlight;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <qt/guiutil.h>
|
#include <qt/guiutil.h>
|
||||||
#include <qt/walletmodel.h>
|
#include <qt/walletmodel.h>
|
||||||
|
|
||||||
|
#include <interface/node.h>
|
||||||
#include <key_io.h>
|
#include <key_io.h>
|
||||||
#include <wallet/wallet.h>
|
#include <wallet/wallet.h>
|
||||||
|
|
||||||
|
@ -67,28 +68,23 @@ static AddressTableEntry::Type translateTransactionType(const QString &strPurpos
|
||||||
class AddressTablePriv
|
class AddressTablePriv
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CWallet *wallet;
|
|
||||||
QList<AddressTableEntry> cachedAddressTable;
|
QList<AddressTableEntry> cachedAddressTable;
|
||||||
AddressTableModel *parent;
|
AddressTableModel *parent;
|
||||||
|
|
||||||
AddressTablePriv(CWallet *_wallet, AddressTableModel *_parent):
|
AddressTablePriv(AddressTableModel *_parent):
|
||||||
wallet(_wallet), parent(_parent) {}
|
parent(_parent) {}
|
||||||
|
|
||||||
void refreshAddressTable()
|
void refreshAddressTable(interface::Wallet& wallet)
|
||||||
{
|
{
|
||||||
cachedAddressTable.clear();
|
cachedAddressTable.clear();
|
||||||
{
|
{
|
||||||
LOCK(wallet->cs_wallet);
|
for (const auto& address : wallet.getAddresses())
|
||||||
for (const std::pair<CTxDestination, CAddressBookData>& item : wallet->mapAddressBook)
|
|
||||||
{
|
{
|
||||||
const CTxDestination& address = item.first;
|
|
||||||
bool fMine = IsMine(*wallet, address);
|
|
||||||
AddressTableEntry::Type addressType = translateTransactionType(
|
AddressTableEntry::Type addressType = translateTransactionType(
|
||||||
QString::fromStdString(item.second.purpose), fMine);
|
QString::fromStdString(address.purpose), address.is_mine);
|
||||||
const std::string& strName = item.second.name;
|
|
||||||
cachedAddressTable.append(AddressTableEntry(addressType,
|
cachedAddressTable.append(AddressTableEntry(addressType,
|
||||||
QString::fromStdString(strName),
|
QString::fromStdString(address.name),
|
||||||
QString::fromStdString(EncodeDestination(address))));
|
QString::fromStdString(EncodeDestination(address.dest))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// qLowerBound() and qUpperBound() require our cachedAddressTable list to be sorted in asc order
|
// qLowerBound() and qUpperBound() require our cachedAddressTable list to be sorted in asc order
|
||||||
|
@ -162,12 +158,12 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
AddressTableModel::AddressTableModel(CWallet *_wallet, WalletModel *parent) :
|
AddressTableModel::AddressTableModel(WalletModel *parent) :
|
||||||
QAbstractTableModel(parent),walletModel(parent),wallet(_wallet),priv(0)
|
QAbstractTableModel(parent),walletModel(parent),priv(0)
|
||||||
{
|
{
|
||||||
columns << tr("Label") << tr("Address");
|
columns << tr("Label") << tr("Address");
|
||||||
priv = new AddressTablePriv(wallet, this);
|
priv = new AddressTablePriv(this);
|
||||||
priv->refreshAddressTable();
|
priv->refreshAddressTable(parent->wallet());
|
||||||
}
|
}
|
||||||
|
|
||||||
AddressTableModel::~AddressTableModel()
|
AddressTableModel::~AddressTableModel()
|
||||||
|
@ -244,7 +240,6 @@ bool AddressTableModel::setData(const QModelIndex &index, const QVariant &value,
|
||||||
|
|
||||||
if(role == Qt::EditRole)
|
if(role == Qt::EditRole)
|
||||||
{
|
{
|
||||||
LOCK(wallet->cs_wallet); /* For SetAddressBook / DelAddressBook */
|
|
||||||
CTxDestination curAddress = DecodeDestination(rec->address.toStdString());
|
CTxDestination curAddress = DecodeDestination(rec->address.toStdString());
|
||||||
if(index.column() == Label)
|
if(index.column() == Label)
|
||||||
{
|
{
|
||||||
|
@ -254,7 +249,7 @@ bool AddressTableModel::setData(const QModelIndex &index, const QVariant &value,
|
||||||
editStatus = NO_CHANGES;
|
editStatus = NO_CHANGES;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
wallet->SetAddressBook(curAddress, value.toString().toStdString(), strPurpose);
|
walletModel->wallet().setAddressBook(curAddress, value.toString().toStdString(), strPurpose);
|
||||||
} else if(index.column() == Address) {
|
} else if(index.column() == Address) {
|
||||||
CTxDestination newAddress = DecodeDestination(value.toString().toStdString());
|
CTxDestination newAddress = DecodeDestination(value.toString().toStdString());
|
||||||
// Refuse to set invalid address, set error status and return false
|
// Refuse to set invalid address, set error status and return false
|
||||||
|
@ -271,7 +266,7 @@ bool AddressTableModel::setData(const QModelIndex &index, const QVariant &value,
|
||||||
}
|
}
|
||||||
// Check for duplicate addresses to prevent accidental deletion of addresses, if you try
|
// Check for duplicate addresses to prevent accidental deletion of addresses, if you try
|
||||||
// to paste an existing address over another address (with a different label)
|
// to paste an existing address over another address (with a different label)
|
||||||
else if(wallet->mapAddressBook.count(newAddress))
|
if (walletModel->wallet().getAddress(newAddress))
|
||||||
{
|
{
|
||||||
editStatus = DUPLICATE_ADDRESS;
|
editStatus = DUPLICATE_ADDRESS;
|
||||||
return false;
|
return false;
|
||||||
|
@ -280,9 +275,9 @@ bool AddressTableModel::setData(const QModelIndex &index, const QVariant &value,
|
||||||
else if(rec->type == AddressTableEntry::Sending)
|
else if(rec->type == AddressTableEntry::Sending)
|
||||||
{
|
{
|
||||||
// Remove old entry
|
// Remove old entry
|
||||||
wallet->DelAddressBook(curAddress);
|
walletModel->wallet().delAddressBook(curAddress);
|
||||||
// Add new entry with new address
|
// Add new entry with new address
|
||||||
wallet->SetAddressBook(newAddress, rec->label.toStdString(), strPurpose);
|
walletModel->wallet().setAddressBook(newAddress, value.toString().toStdString(), strPurpose);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -356,8 +351,7 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con
|
||||||
}
|
}
|
||||||
// Check for duplicate addresses
|
// Check for duplicate addresses
|
||||||
{
|
{
|
||||||
LOCK(wallet->cs_wallet);
|
if(walletModel->wallet().getAddress(DecodeDestination(strAddress)))
|
||||||
if(wallet->mapAddressBook.count(DecodeDestination(strAddress)))
|
|
||||||
{
|
{
|
||||||
editStatus = DUPLICATE_ADDRESS;
|
editStatus = DUPLICATE_ADDRESS;
|
||||||
return QString();
|
return QString();
|
||||||
|
@ -368,7 +362,7 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con
|
||||||
{
|
{
|
||||||
// Generate a new address to associate with given label
|
// Generate a new address to associate with given label
|
||||||
CPubKey newKey;
|
CPubKey newKey;
|
||||||
if(!wallet->GetKeyFromPool(newKey))
|
if(!walletModel->wallet().getKeyFromPool(false /* internal */, newKey))
|
||||||
{
|
{
|
||||||
WalletModel::UnlockContext ctx(walletModel->requestUnlock());
|
WalletModel::UnlockContext ctx(walletModel->requestUnlock());
|
||||||
if(!ctx.isValid())
|
if(!ctx.isValid())
|
||||||
|
@ -377,13 +371,13 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con
|
||||||
editStatus = WALLET_UNLOCK_FAILURE;
|
editStatus = WALLET_UNLOCK_FAILURE;
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
if(!wallet->GetKeyFromPool(newKey))
|
if(!walletModel->wallet().getKeyFromPool(false /* internal */, newKey))
|
||||||
{
|
{
|
||||||
editStatus = KEY_GENERATION_FAILURE;
|
editStatus = KEY_GENERATION_FAILURE;
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wallet->LearnRelatedScripts(newKey, address_type);
|
walletModel->wallet().learnRelatedScripts(newKey, address_type);
|
||||||
strAddress = EncodeDestination(GetDestinationForKey(newKey, address_type));
|
strAddress = EncodeDestination(GetDestinationForKey(newKey, address_type));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -392,7 +386,7 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add entry
|
// Add entry
|
||||||
wallet->SetAddressBook(DecodeDestination(strAddress), strLabel,
|
walletModel->wallet().setAddressBook(DecodeDestination(strAddress), strLabel,
|
||||||
(type == Send ? "send" : "receive"));
|
(type == Send ? "send" : "receive"));
|
||||||
return QString::fromStdString(strAddress);
|
return QString::fromStdString(strAddress);
|
||||||
}
|
}
|
||||||
|
@ -407,7 +401,7 @@ bool AddressTableModel::removeRows(int row, int count, const QModelIndex &parent
|
||||||
// Also refuse to remove receiving addresses.
|
// Also refuse to remove receiving addresses.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
wallet->DelAddressBook(DecodeDestination(rec->address.toStdString()));
|
walletModel->wallet().delAddressBook(DecodeDestination(rec->address.toStdString()));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -416,12 +410,11 @@ bool AddressTableModel::removeRows(int row, int count, const QModelIndex &parent
|
||||||
QString AddressTableModel::labelForAddress(const QString &address) const
|
QString AddressTableModel::labelForAddress(const QString &address) const
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
LOCK(wallet->cs_wallet);
|
|
||||||
CTxDestination destination = DecodeDestination(address.toStdString());
|
CTxDestination destination = DecodeDestination(address.toStdString());
|
||||||
std::map<CTxDestination, CAddressBookData>::iterator mi = wallet->mapAddressBook.find(destination);
|
std::string name;
|
||||||
if (mi != wallet->mapAddressBook.end())
|
if (walletModel->wallet().getAddress(destination, &name))
|
||||||
{
|
{
|
||||||
return QString::fromStdString(mi->second.name);
|
return QString::fromStdString(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return QString();
|
return QString();
|
||||||
|
@ -441,7 +434,7 @@ int AddressTableModel::lookupAddress(const QString &address) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
OutputType AddressTableModel::GetDefaultAddressType() const { return wallet->m_default_address_type; };
|
OutputType AddressTableModel::GetDefaultAddressType() const { return walletModel->wallet().getDefaultAddressType(); };
|
||||||
|
|
||||||
void AddressTableModel::emitDataChanged(int idx)
|
void AddressTableModel::emitDataChanged(int idx)
|
||||||
{
|
{
|
||||||
|
|
|
@ -13,7 +13,9 @@ enum class OutputType;
|
||||||
class AddressTablePriv;
|
class AddressTablePriv;
|
||||||
class WalletModel;
|
class WalletModel;
|
||||||
|
|
||||||
class CWallet;
|
namespace interface {
|
||||||
|
class Wallet;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Qt model of the address book in the core. This allows views to access and modify the address book.
|
Qt model of the address book in the core. This allows views to access and modify the address book.
|
||||||
|
@ -23,7 +25,7 @@ class AddressTableModel : public QAbstractTableModel
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit AddressTableModel(CWallet *wallet, WalletModel *parent = 0);
|
explicit AddressTableModel(WalletModel *parent = 0);
|
||||||
~AddressTableModel();
|
~AddressTableModel();
|
||||||
|
|
||||||
enum ColumnIndex {
|
enum ColumnIndex {
|
||||||
|
@ -80,7 +82,6 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
WalletModel *walletModel;
|
WalletModel *walletModel;
|
||||||
CWallet *wallet;
|
|
||||||
AddressTablePriv *priv;
|
AddressTablePriv *priv;
|
||||||
QStringList columns;
|
QStringList columns;
|
||||||
EditStatus editStatus;
|
EditStatus editStatus;
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <qt/guiconstants.h>
|
#include <qt/guiconstants.h>
|
||||||
#include <qt/guiutil.h>
|
#include <qt/guiutil.h>
|
||||||
|
|
||||||
|
#include <interface/node.h>
|
||||||
#include <sync.h>
|
#include <sync.h>
|
||||||
#include <utiltime.h>
|
#include <utiltime.h>
|
||||||
|
|
||||||
|
@ -45,11 +46,10 @@ public:
|
||||||
Qt::SortOrder sortOrder;
|
Qt::SortOrder sortOrder;
|
||||||
|
|
||||||
/** Pull a full list of banned nodes from CNode into our cache */
|
/** Pull a full list of banned nodes from CNode into our cache */
|
||||||
void refreshBanlist()
|
void refreshBanlist(interface::Node& node)
|
||||||
{
|
{
|
||||||
banmap_t banMap;
|
banmap_t banMap;
|
||||||
if(g_connman)
|
node.getBanned(banMap);
|
||||||
g_connman->GetBanned(banMap);
|
|
||||||
|
|
||||||
cachedBanlist.clear();
|
cachedBanlist.clear();
|
||||||
#if QT_VERSION >= 0x040700
|
#if QT_VERSION >= 0x040700
|
||||||
|
@ -82,8 +82,9 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
BanTableModel::BanTableModel(ClientModel *parent) :
|
BanTableModel::BanTableModel(interface::Node& node, ClientModel *parent) :
|
||||||
QAbstractTableModel(parent),
|
QAbstractTableModel(parent),
|
||||||
|
m_node(node),
|
||||||
clientModel(parent)
|
clientModel(parent)
|
||||||
{
|
{
|
||||||
columns << tr("IP/Netmask") << tr("Banned Until");
|
columns << tr("IP/Netmask") << tr("Banned Until");
|
||||||
|
@ -168,7 +169,7 @@ QModelIndex BanTableModel::index(int row, int column, const QModelIndex &parent)
|
||||||
void BanTableModel::refresh()
|
void BanTableModel::refresh()
|
||||||
{
|
{
|
||||||
Q_EMIT layoutAboutToBeChanged();
|
Q_EMIT layoutAboutToBeChanged();
|
||||||
priv->refreshBanlist();
|
priv->refreshBanlist(m_node);
|
||||||
Q_EMIT layoutChanged();
|
Q_EMIT layoutChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,10 @@
|
||||||
class ClientModel;
|
class ClientModel;
|
||||||
class BanTablePriv;
|
class BanTablePriv;
|
||||||
|
|
||||||
|
namespace interface {
|
||||||
|
class Node;
|
||||||
|
}
|
||||||
|
|
||||||
struct CCombinedBan {
|
struct CCombinedBan {
|
||||||
CSubNet subnet;
|
CSubNet subnet;
|
||||||
CBanEntry banEntry;
|
CBanEntry banEntry;
|
||||||
|
@ -41,7 +45,7 @@ class BanTableModel : public QAbstractTableModel
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit BanTableModel(ClientModel *parent = 0);
|
explicit BanTableModel(interface::Node& node, ClientModel *parent = 0);
|
||||||
~BanTableModel();
|
~BanTableModel();
|
||||||
void startAutoRefresh();
|
void startAutoRefresh();
|
||||||
void stopAutoRefresh();
|
void stopAutoRefresh();
|
||||||
|
@ -67,6 +71,7 @@ public Q_SLOTS:
|
||||||
void refresh();
|
void refresh();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
interface::Node& m_node;
|
||||||
ClientModel *clientModel;
|
ClientModel *clientModel;
|
||||||
QStringList columns;
|
QStringList columns;
|
||||||
std::unique_ptr<BanTablePriv> priv;
|
std::unique_ptr<BanTablePriv> priv;
|
||||||
|
|
|
@ -27,6 +27,8 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <init.h>
|
#include <init.h>
|
||||||
|
#include <interface/handler.h>
|
||||||
|
#include <interface/node.h>
|
||||||
#include <rpc/server.h>
|
#include <rpc/server.h>
|
||||||
#include <ui_interface.h>
|
#include <ui_interface.h>
|
||||||
#include <uint256.h>
|
#include <uint256.h>
|
||||||
|
@ -35,7 +37,6 @@
|
||||||
|
|
||||||
#ifdef ENABLE_WALLET
|
#ifdef ENABLE_WALLET
|
||||||
#include <wallet/init.h>
|
#include <wallet/init.h>
|
||||||
#include <wallet/wallet.h>
|
|
||||||
#endif
|
#endif
|
||||||
#include <walletinitinterface.h>
|
#include <walletinitinterface.h>
|
||||||
|
|
||||||
|
@ -181,11 +182,7 @@ class BitcoinCore: public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit BitcoinCore();
|
explicit BitcoinCore(interface::Node& node);
|
||||||
/** Basic initialization, before starting initialization/shutdown thread.
|
|
||||||
* Return true on success.
|
|
||||||
*/
|
|
||||||
static bool baseInitialize();
|
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
void initialize();
|
void initialize();
|
||||||
|
@ -197,9 +194,10 @@ Q_SIGNALS:
|
||||||
void runawayException(const QString &message);
|
void runawayException(const QString &message);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/// Pass fatal exception message to UI thread
|
/// Pass fatal exception message to UI thread
|
||||||
void handleRunawayException(const std::exception *e);
|
void handleRunawayException(const std::exception *e);
|
||||||
|
|
||||||
|
interface::Node& m_node;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Main Bitcoin application object */
|
/** Main Bitcoin application object */
|
||||||
|
@ -207,7 +205,7 @@ class BitcoinApplication: public QApplication
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit BitcoinApplication(int &argc, char **argv);
|
explicit BitcoinApplication(interface::Node& node, int &argc, char **argv);
|
||||||
~BitcoinApplication();
|
~BitcoinApplication();
|
||||||
|
|
||||||
#ifdef ENABLE_WALLET
|
#ifdef ENABLE_WALLET
|
||||||
|
@ -248,6 +246,7 @@ Q_SIGNALS:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QThread *coreThread;
|
QThread *coreThread;
|
||||||
|
interface::Node& m_node;
|
||||||
OptionsModel *optionsModel;
|
OptionsModel *optionsModel;
|
||||||
ClientModel *clientModel;
|
ClientModel *clientModel;
|
||||||
BitcoinGUI *window;
|
BitcoinGUI *window;
|
||||||
|
@ -265,36 +264,15 @@ private:
|
||||||
|
|
||||||
#include <qt/bitcoin.moc>
|
#include <qt/bitcoin.moc>
|
||||||
|
|
||||||
BitcoinCore::BitcoinCore():
|
BitcoinCore::BitcoinCore(interface::Node& node) :
|
||||||
QObject()
|
QObject(), m_node(node)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void BitcoinCore::handleRunawayException(const std::exception *e)
|
void BitcoinCore::handleRunawayException(const std::exception *e)
|
||||||
{
|
{
|
||||||
PrintExceptionContinue(e, "Runaway exception");
|
PrintExceptionContinue(e, "Runaway exception");
|
||||||
Q_EMIT runawayException(QString::fromStdString(GetWarnings("gui")));
|
Q_EMIT runawayException(QString::fromStdString(m_node.getWarnings("gui")));
|
||||||
}
|
|
||||||
|
|
||||||
bool BitcoinCore::baseInitialize()
|
|
||||||
{
|
|
||||||
if (!AppInitBasicSetup())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!AppInitParameterInteraction())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!AppInitSanityChecks())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!AppInitLockDataDirectory())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BitcoinCore::initialize()
|
void BitcoinCore::initialize()
|
||||||
|
@ -302,7 +280,7 @@ void BitcoinCore::initialize()
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
qDebug() << __func__ << ": Running initialization in thread";
|
qDebug() << __func__ << ": Running initialization in thread";
|
||||||
bool rv = AppInitMain();
|
bool rv = m_node.appInitMain();
|
||||||
Q_EMIT initializeResult(rv);
|
Q_EMIT initializeResult(rv);
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
handleRunawayException(&e);
|
handleRunawayException(&e);
|
||||||
|
@ -316,8 +294,7 @@ void BitcoinCore::shutdown()
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
qDebug() << __func__ << ": Running Shutdown in thread";
|
qDebug() << __func__ << ": Running Shutdown in thread";
|
||||||
Interrupt();
|
m_node.appShutdown();
|
||||||
Shutdown();
|
|
||||||
qDebug() << __func__ << ": Shutdown finished";
|
qDebug() << __func__ << ": Shutdown finished";
|
||||||
Q_EMIT shutdownResult();
|
Q_EMIT shutdownResult();
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
|
@ -327,9 +304,10 @@ void BitcoinCore::shutdown()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BitcoinApplication::BitcoinApplication(int &argc, char **argv):
|
BitcoinApplication::BitcoinApplication(interface::Node& node, int &argc, char **argv):
|
||||||
QApplication(argc, argv),
|
QApplication(argc, argv),
|
||||||
coreThread(0),
|
coreThread(0),
|
||||||
|
m_node(node),
|
||||||
optionsModel(0),
|
optionsModel(0),
|
||||||
clientModel(0),
|
clientModel(0),
|
||||||
window(0),
|
window(0),
|
||||||
|
@ -384,12 +362,12 @@ void BitcoinApplication::createPaymentServer()
|
||||||
|
|
||||||
void BitcoinApplication::createOptionsModel(bool resetSettings)
|
void BitcoinApplication::createOptionsModel(bool resetSettings)
|
||||||
{
|
{
|
||||||
optionsModel = new OptionsModel(nullptr, resetSettings);
|
optionsModel = new OptionsModel(m_node, nullptr, resetSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BitcoinApplication::createWindow(const NetworkStyle *networkStyle)
|
void BitcoinApplication::createWindow(const NetworkStyle *networkStyle)
|
||||||
{
|
{
|
||||||
window = new BitcoinGUI(platformStyle, networkStyle, 0);
|
window = new BitcoinGUI(m_node, platformStyle, networkStyle, 0);
|
||||||
|
|
||||||
pollShutdownTimer = new QTimer(window);
|
pollShutdownTimer = new QTimer(window);
|
||||||
connect(pollShutdownTimer, SIGNAL(timeout()), window, SLOT(detectShutdown()));
|
connect(pollShutdownTimer, SIGNAL(timeout()), window, SLOT(detectShutdown()));
|
||||||
|
@ -397,7 +375,7 @@ void BitcoinApplication::createWindow(const NetworkStyle *networkStyle)
|
||||||
|
|
||||||
void BitcoinApplication::createSplashScreen(const NetworkStyle *networkStyle)
|
void BitcoinApplication::createSplashScreen(const NetworkStyle *networkStyle)
|
||||||
{
|
{
|
||||||
SplashScreen *splash = new SplashScreen(0, networkStyle);
|
SplashScreen *splash = new SplashScreen(m_node, 0, networkStyle);
|
||||||
// We don't hold a direct pointer to the splash screen after creation, but the splash
|
// We don't hold a direct pointer to the splash screen after creation, but the splash
|
||||||
// screen will take care of deleting itself when slotFinish happens.
|
// screen will take care of deleting itself when slotFinish happens.
|
||||||
splash->show();
|
splash->show();
|
||||||
|
@ -410,7 +388,7 @@ void BitcoinApplication::startThread()
|
||||||
if(coreThread)
|
if(coreThread)
|
||||||
return;
|
return;
|
||||||
coreThread = new QThread(this);
|
coreThread = new QThread(this);
|
||||||
BitcoinCore *executor = new BitcoinCore();
|
BitcoinCore *executor = new BitcoinCore(m_node);
|
||||||
executor->moveToThread(coreThread);
|
executor->moveToThread(coreThread);
|
||||||
|
|
||||||
/* communication to and from thread */
|
/* communication to and from thread */
|
||||||
|
@ -428,8 +406,8 @@ void BitcoinApplication::startThread()
|
||||||
|
|
||||||
void BitcoinApplication::parameterSetup()
|
void BitcoinApplication::parameterSetup()
|
||||||
{
|
{
|
||||||
InitLogging();
|
m_node.initLogging();
|
||||||
InitParameterInteraction();
|
m_node.initParameterInteraction();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BitcoinApplication::requestInitialize()
|
void BitcoinApplication::requestInitialize()
|
||||||
|
@ -462,7 +440,7 @@ void BitcoinApplication::requestShutdown()
|
||||||
delete clientModel;
|
delete clientModel;
|
||||||
clientModel = 0;
|
clientModel = 0;
|
||||||
|
|
||||||
StartShutdown();
|
m_node.startShutdown();
|
||||||
|
|
||||||
// Request shutdown from core thread
|
// Request shutdown from core thread
|
||||||
Q_EMIT requestedShutdown();
|
Q_EMIT requestedShutdown();
|
||||||
|
@ -482,13 +460,14 @@ void BitcoinApplication::initializeResult(bool success)
|
||||||
paymentServer->setOptionsModel(optionsModel);
|
paymentServer->setOptionsModel(optionsModel);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
clientModel = new ClientModel(optionsModel);
|
clientModel = new ClientModel(m_node, optionsModel);
|
||||||
window->setClientModel(clientModel);
|
window->setClientModel(clientModel);
|
||||||
|
|
||||||
#ifdef ENABLE_WALLET
|
#ifdef ENABLE_WALLET
|
||||||
bool fFirstWallet = true;
|
bool fFirstWallet = true;
|
||||||
for (CWalletRef pwallet : vpwallets) {
|
auto wallets = m_node.getWallets();
|
||||||
WalletModel * const walletModel = new WalletModel(platformStyle, pwallet, optionsModel);
|
for (auto& wallet : wallets) {
|
||||||
|
WalletModel * const walletModel = new WalletModel(std::move(wallet), m_node, platformStyle, optionsModel);
|
||||||
|
|
||||||
window->addWallet(walletModel);
|
window->addWallet(walletModel);
|
||||||
if (fFirstWallet) {
|
if (fFirstWallet) {
|
||||||
|
@ -496,8 +475,8 @@ void BitcoinApplication::initializeResult(bool success)
|
||||||
fFirstWallet = false;
|
fFirstWallet = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
connect(walletModel, SIGNAL(coinsSent(CWallet*,SendCoinsRecipient,QByteArray)),
|
connect(walletModel, SIGNAL(coinsSent(WalletModel*,SendCoinsRecipient,QByteArray)),
|
||||||
paymentServer, SLOT(fetchPaymentACK(CWallet*,const SendCoinsRecipient&,QByteArray)));
|
paymentServer, SLOT(fetchPaymentACK(WalletModel*,const SendCoinsRecipient&,QByteArray)));
|
||||||
|
|
||||||
m_wallet_models.push_back(walletModel);
|
m_wallet_models.push_back(walletModel);
|
||||||
}
|
}
|
||||||
|
@ -556,9 +535,11 @@ int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
SetupEnvironment();
|
SetupEnvironment();
|
||||||
|
|
||||||
|
std::unique_ptr<interface::Node> node = interface::MakeNode();
|
||||||
|
|
||||||
/// 1. Parse command-line options. These take precedence over anything else.
|
/// 1. Parse command-line options. These take precedence over anything else.
|
||||||
// Command-line options take precedence:
|
// Command-line options take precedence:
|
||||||
gArgs.ParseParameters(argc, argv);
|
node->parseParameters(argc, argv);
|
||||||
|
|
||||||
// Do not refer to data directory yet, this can be overridden by Intro::pickDataDirectory
|
// Do not refer to data directory yet, this can be overridden by Intro::pickDataDirectory
|
||||||
|
|
||||||
|
@ -572,7 +553,7 @@ int main(int argc, char *argv[])
|
||||||
Q_INIT_RESOURCE(bitcoin);
|
Q_INIT_RESOURCE(bitcoin);
|
||||||
Q_INIT_RESOURCE(bitcoin_locale);
|
Q_INIT_RESOURCE(bitcoin_locale);
|
||||||
|
|
||||||
BitcoinApplication app(argc, argv);
|
BitcoinApplication app(*node, argc, argv);
|
||||||
#if QT_VERSION > 0x050100
|
#if QT_VERSION > 0x050100
|
||||||
// Generate high-dpi pixmaps
|
// Generate high-dpi pixmaps
|
||||||
QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
|
QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
|
||||||
|
@ -615,14 +596,14 @@ int main(int argc, char *argv[])
|
||||||
// Show help message immediately after parsing command-line options (for "-lang") and setting locale,
|
// Show help message immediately after parsing command-line options (for "-lang") and setting locale,
|
||||||
// but before showing splash screen.
|
// but before showing splash screen.
|
||||||
if (HelpRequested(gArgs) || gArgs.IsArgSet("-version")) {
|
if (HelpRequested(gArgs) || gArgs.IsArgSet("-version")) {
|
||||||
HelpMessageDialog help(nullptr, gArgs.IsArgSet("-version"));
|
HelpMessageDialog help(*node, nullptr, gArgs.IsArgSet("-version"));
|
||||||
help.showOrPrint();
|
help.showOrPrint();
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 5. Now that settings and translations are available, ask user for data directory
|
/// 5. Now that settings and translations are available, ask user for data directory
|
||||||
// User language is set up: pick a data directory
|
// User language is set up: pick a data directory
|
||||||
if (!Intro::pickDataDirectory())
|
if (!Intro::pickDataDirectory(*node))
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
|
||||||
/// 6. Determine availability of data and blocks directory and parse bitcoin.conf
|
/// 6. Determine availability of data and blocks directory and parse bitcoin.conf
|
||||||
|
@ -634,7 +615,7 @@ int main(int argc, char *argv[])
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
gArgs.ReadConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME));
|
node->readConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME));
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
QMessageBox::critical(0, QObject::tr(PACKAGE_NAME),
|
QMessageBox::critical(0, QObject::tr(PACKAGE_NAME),
|
||||||
QObject::tr("Error: Cannot parse configuration file: %1. Only use key=value syntax.").arg(e.what()));
|
QObject::tr("Error: Cannot parse configuration file: %1. Only use key=value syntax.").arg(e.what()));
|
||||||
|
@ -649,14 +630,14 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
// Check for -testnet or -regtest parameter (Params() calls are only valid after this clause)
|
// Check for -testnet or -regtest parameter (Params() calls are only valid after this clause)
|
||||||
try {
|
try {
|
||||||
SelectParams(ChainNameFromCommandLine());
|
node->selectParams(ChainNameFromCommandLine());
|
||||||
} catch(std::exception &e) {
|
} catch(std::exception &e) {
|
||||||
QMessageBox::critical(0, QObject::tr(PACKAGE_NAME), QObject::tr("Error: %1").arg(e.what()));
|
QMessageBox::critical(0, QObject::tr(PACKAGE_NAME), QObject::tr("Error: %1").arg(e.what()));
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
#ifdef ENABLE_WALLET
|
#ifdef ENABLE_WALLET
|
||||||
// Parse URIs on command line -- this can affect Params()
|
// Parse URIs on command line -- this can affect Params()
|
||||||
PaymentServer::ipcParseCommandLine(argc, argv);
|
PaymentServer::ipcParseCommandLine(*node, argc, argv);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
QScopedPointer<const NetworkStyle> networkStyle(NetworkStyle::instantiate(QString::fromStdString(Params().NetworkIDString())));
|
QScopedPointer<const NetworkStyle> networkStyle(NetworkStyle::instantiate(QString::fromStdString(Params().NetworkIDString())));
|
||||||
|
@ -706,7 +687,7 @@ int main(int argc, char *argv[])
|
||||||
app.createOptionsModel(gArgs.GetBoolArg("-resetguisettings", false));
|
app.createOptionsModel(gArgs.GetBoolArg("-resetguisettings", false));
|
||||||
|
|
||||||
// Subscribe to global signals from core
|
// Subscribe to global signals from core
|
||||||
uiInterface.InitMessage.connect(InitMessage);
|
std::unique_ptr<interface::Handler> handler = node->handleInitMessage(InitMessage);
|
||||||
|
|
||||||
if (gArgs.GetBoolArg("-splash", DEFAULT_SPLASHSCREEN) && !gArgs.GetBoolArg("-min", false))
|
if (gArgs.GetBoolArg("-splash", DEFAULT_SPLASHSCREEN) && !gArgs.GetBoolArg("-min", false))
|
||||||
app.createSplashScreen(networkStyle.data());
|
app.createSplashScreen(networkStyle.data());
|
||||||
|
@ -718,7 +699,7 @@ int main(int argc, char *argv[])
|
||||||
// Perform base initialization before spinning up initialization/shutdown thread
|
// Perform base initialization before spinning up initialization/shutdown thread
|
||||||
// This is acceptable because this function only contains steps that are quick to execute,
|
// This is acceptable because this function only contains steps that are quick to execute,
|
||||||
// so the GUI thread won't be held up.
|
// so the GUI thread won't be held up.
|
||||||
if (BitcoinCore::baseInitialize()) {
|
if (node->baseInitialize()) {
|
||||||
app.requestInitialize();
|
app.requestInitialize();
|
||||||
#if defined(Q_OS_WIN) && QT_VERSION >= 0x050000
|
#if defined(Q_OS_WIN) && QT_VERSION >= 0x050000
|
||||||
WinShutdownMonitor::registerShutdownBlockReason(QObject::tr("%1 didn't yet exit safely...").arg(QObject::tr(PACKAGE_NAME)), (HWND)app.getMainWinId());
|
WinShutdownMonitor::registerShutdownBlockReason(QObject::tr("%1 didn't yet exit safely...").arg(QObject::tr(PACKAGE_NAME)), (HWND)app.getMainWinId());
|
||||||
|
@ -733,10 +714,10 @@ int main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
PrintExceptionContinue(&e, "Runaway exception");
|
PrintExceptionContinue(&e, "Runaway exception");
|
||||||
app.handleRunawayException(QString::fromStdString(GetWarnings("gui")));
|
app.handleRunawayException(QString::fromStdString(node->getWarnings("gui")));
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
PrintExceptionContinue(nullptr, "Runaway exception");
|
PrintExceptionContinue(nullptr, "Runaway exception");
|
||||||
app.handleRunawayException(QString::fromStdString(GetWarnings("gui")));
|
app.handleRunawayException(QString::fromStdString(node->getWarnings("gui")));
|
||||||
}
|
}
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,8 @@
|
||||||
|
|
||||||
#include <chainparams.h>
|
#include <chainparams.h>
|
||||||
#include <init.h>
|
#include <init.h>
|
||||||
|
#include <interface/handler.h>
|
||||||
|
#include <interface/node.h>
|
||||||
#include <ui_interface.h>
|
#include <ui_interface.h>
|
||||||
#include <util.h>
|
#include <util.h>
|
||||||
|
|
||||||
|
@ -72,9 +74,10 @@ const std::string BitcoinGUI::DEFAULT_UIPLATFORM =
|
||||||
#endif
|
#endif
|
||||||
;
|
;
|
||||||
|
|
||||||
BitcoinGUI::BitcoinGUI(const PlatformStyle *_platformStyle, const NetworkStyle *networkStyle, QWidget *parent) :
|
BitcoinGUI::BitcoinGUI(interface::Node& node, const PlatformStyle *_platformStyle, const NetworkStyle *networkStyle, QWidget *parent) :
|
||||||
QMainWindow(parent),
|
QMainWindow(parent),
|
||||||
enableWallet(false),
|
enableWallet(false),
|
||||||
|
m_node(node),
|
||||||
clientModel(0),
|
clientModel(0),
|
||||||
walletFrame(0),
|
walletFrame(0),
|
||||||
unitDisplayControl(0),
|
unitDisplayControl(0),
|
||||||
|
@ -149,8 +152,8 @@ BitcoinGUI::BitcoinGUI(const PlatformStyle *_platformStyle, const NetworkStyle *
|
||||||
setUnifiedTitleAndToolBarOnMac(true);
|
setUnifiedTitleAndToolBarOnMac(true);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
rpcConsole = new RPCConsole(_platformStyle, 0);
|
rpcConsole = new RPCConsole(node, _platformStyle, 0);
|
||||||
helpMessageDialog = new HelpMessageDialog(this, false);
|
helpMessageDialog = new HelpMessageDialog(node, this, false);
|
||||||
#ifdef ENABLE_WALLET
|
#ifdef ENABLE_WALLET
|
||||||
if(enableWallet)
|
if(enableWallet)
|
||||||
{
|
{
|
||||||
|
@ -490,7 +493,7 @@ void BitcoinGUI::setClientModel(ClientModel *_clientModel)
|
||||||
connect(_clientModel, SIGNAL(networkActiveChanged(bool)), this, SLOT(setNetworkActive(bool)));
|
connect(_clientModel, SIGNAL(networkActiveChanged(bool)), this, SLOT(setNetworkActive(bool)));
|
||||||
|
|
||||||
modalOverlay->setKnownBestHeight(_clientModel->getHeaderTipHeight(), QDateTime::fromTime_t(_clientModel->getHeaderTipTime()));
|
modalOverlay->setKnownBestHeight(_clientModel->getHeaderTipHeight(), QDateTime::fromTime_t(_clientModel->getHeaderTipTime()));
|
||||||
setNumBlocks(_clientModel->getNumBlocks(), _clientModel->getLastBlockDate(), _clientModel->getVerificationProgress(nullptr), false);
|
setNumBlocks(m_node.getNumBlocks(), QDateTime::fromTime_t(m_node.getLastBlockTime()), m_node.getVerificationProgress(), false);
|
||||||
connect(_clientModel, SIGNAL(numBlocksChanged(int,QDateTime,double,bool)), this, SLOT(setNumBlocks(int,QDateTime,double,bool)));
|
connect(_clientModel, SIGNAL(numBlocksChanged(int,QDateTime,double,bool)), this, SLOT(setNumBlocks(int,QDateTime,double,bool)));
|
||||||
|
|
||||||
// Receive and report messages from client model
|
// Receive and report messages from client model
|
||||||
|
@ -665,7 +668,7 @@ void BitcoinGUI::aboutClicked()
|
||||||
if(!clientModel)
|
if(!clientModel)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
HelpMessageDialog dlg(this, true);
|
HelpMessageDialog dlg(m_node, this, true);
|
||||||
dlg.exec();
|
dlg.exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -748,7 +751,7 @@ void BitcoinGUI::updateNetworkState()
|
||||||
|
|
||||||
QString tooltip;
|
QString tooltip;
|
||||||
|
|
||||||
if (clientModel->getNetworkActive()) {
|
if (m_node.getNetworkActive()) {
|
||||||
tooltip = tr("%n active connection(s) to Bitcoin network", "", count) + QString(".<br>") + tr("Click to disable network activity.");
|
tooltip = tr("%n active connection(s) to Bitcoin network", "", count) + QString(".<br>") + tr("Click to disable network activity.");
|
||||||
} else {
|
} else {
|
||||||
tooltip = tr("Network activity disabled.") + QString("<br>") + tr("Click to enable network activity again.");
|
tooltip = tr("Network activity disabled.") + QString("<br>") + tr("Click to enable network activity again.");
|
||||||
|
@ -1007,7 +1010,7 @@ void BitcoinGUI::incomingTransaction(const QString& date, int unit, const CAmoun
|
||||||
// On new transaction, make an info balloon
|
// On new transaction, make an info balloon
|
||||||
QString msg = tr("Date: %1\n").arg(date) +
|
QString msg = tr("Date: %1\n").arg(date) +
|
||||||
tr("Amount: %1\n").arg(BitcoinUnits::formatWithUnit(unit, amount, true));
|
tr("Amount: %1\n").arg(BitcoinUnits::formatWithUnit(unit, amount, true));
|
||||||
if (WalletModel::isMultiwallet() && !walletName.isEmpty()) {
|
if (m_node.getWallets().size() > 1 && !walletName.isEmpty()) {
|
||||||
msg += tr("Wallet: %1\n").arg(walletName);
|
msg += tr("Wallet: %1\n").arg(walletName);
|
||||||
}
|
}
|
||||||
msg += tr("Type: %1\n").arg(type);
|
msg += tr("Type: %1\n").arg(type);
|
||||||
|
@ -1113,7 +1116,7 @@ void BitcoinGUI::updateWalletStatus()
|
||||||
}
|
}
|
||||||
WalletModel * const walletModel = walletView->getWalletModel();
|
WalletModel * const walletModel = walletView->getWalletModel();
|
||||||
setEncryptionStatus(walletModel->getEncryptionStatus());
|
setEncryptionStatus(walletModel->getEncryptionStatus());
|
||||||
setHDStatus(walletModel->hdEnabled());
|
setHDStatus(walletModel->wallet().hdEnabled());
|
||||||
}
|
}
|
||||||
#endif // ENABLE_WALLET
|
#endif // ENABLE_WALLET
|
||||||
|
|
||||||
|
@ -1149,7 +1152,7 @@ void BitcoinGUI::toggleHidden()
|
||||||
|
|
||||||
void BitcoinGUI::detectShutdown()
|
void BitcoinGUI::detectShutdown()
|
||||||
{
|
{
|
||||||
if (ShutdownRequested())
|
if (m_node.shutdownRequested())
|
||||||
{
|
{
|
||||||
if(rpcConsole)
|
if(rpcConsole)
|
||||||
rpcConsole->hide();
|
rpcConsole->hide();
|
||||||
|
@ -1214,22 +1217,20 @@ static bool ThreadSafeMessageBox(BitcoinGUI *gui, const std::string& message, co
|
||||||
void BitcoinGUI::subscribeToCoreSignals()
|
void BitcoinGUI::subscribeToCoreSignals()
|
||||||
{
|
{
|
||||||
// Connect signals to client
|
// Connect signals to client
|
||||||
uiInterface.ThreadSafeMessageBox.connect(boost::bind(ThreadSafeMessageBox, this, _1, _2, _3));
|
m_handler_message_box = m_node.handleMessageBox(boost::bind(ThreadSafeMessageBox, this, _1, _2, _3));
|
||||||
uiInterface.ThreadSafeQuestion.connect(boost::bind(ThreadSafeMessageBox, this, _1, _3, _4));
|
m_handler_question = m_node.handleQuestion(boost::bind(ThreadSafeMessageBox, this, _1, _3, _4));
|
||||||
}
|
}
|
||||||
|
|
||||||
void BitcoinGUI::unsubscribeFromCoreSignals()
|
void BitcoinGUI::unsubscribeFromCoreSignals()
|
||||||
{
|
{
|
||||||
// Disconnect signals from client
|
// Disconnect signals from client
|
||||||
uiInterface.ThreadSafeMessageBox.disconnect(boost::bind(ThreadSafeMessageBox, this, _1, _2, _3));
|
m_handler_message_box->disconnect();
|
||||||
uiInterface.ThreadSafeQuestion.disconnect(boost::bind(ThreadSafeMessageBox, this, _1, _3, _4));
|
m_handler_question->disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BitcoinGUI::toggleNetworkActive()
|
void BitcoinGUI::toggleNetworkActive()
|
||||||
{
|
{
|
||||||
if (clientModel) {
|
m_node.setNetworkActive(!m_node.getNetworkActive());
|
||||||
clientModel->setNetworkActive(!clientModel->getNetworkActive());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UnitDisplayStatusBarControl::UnitDisplayStatusBarControl(const PlatformStyle *platformStyle) :
|
UnitDisplayStatusBarControl::UnitDisplayStatusBarControl(const PlatformStyle *platformStyle) :
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
#include <QPoint>
|
#include <QPoint>
|
||||||
#include <QSystemTrayIcon>
|
#include <QSystemTrayIcon>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
class ClientModel;
|
class ClientModel;
|
||||||
class NetworkStyle;
|
class NetworkStyle;
|
||||||
class Notificator;
|
class Notificator;
|
||||||
|
@ -31,6 +33,11 @@ class WalletModel;
|
||||||
class HelpMessageDialog;
|
class HelpMessageDialog;
|
||||||
class ModalOverlay;
|
class ModalOverlay;
|
||||||
|
|
||||||
|
namespace interface {
|
||||||
|
class Handler;
|
||||||
|
class Node;
|
||||||
|
}
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
class QAction;
|
class QAction;
|
||||||
class QComboBox;
|
class QComboBox;
|
||||||
|
@ -49,7 +56,7 @@ class BitcoinGUI : public QMainWindow
|
||||||
public:
|
public:
|
||||||
static const std::string DEFAULT_UIPLATFORM;
|
static const std::string DEFAULT_UIPLATFORM;
|
||||||
|
|
||||||
explicit BitcoinGUI(const PlatformStyle *platformStyle, const NetworkStyle *networkStyle, QWidget *parent = 0);
|
explicit BitcoinGUI(interface::Node& node, const PlatformStyle *platformStyle, const NetworkStyle *networkStyle, QWidget *parent = 0);
|
||||||
~BitcoinGUI();
|
~BitcoinGUI();
|
||||||
|
|
||||||
/** Set the client model.
|
/** Set the client model.
|
||||||
|
@ -76,6 +83,9 @@ protected:
|
||||||
bool eventFilter(QObject *object, QEvent *event);
|
bool eventFilter(QObject *object, QEvent *event);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
interface::Node& m_node;
|
||||||
|
std::unique_ptr<interface::Handler> m_handler_message_box;
|
||||||
|
std::unique_ptr<interface::Handler> m_handler_question;
|
||||||
ClientModel *clientModel;
|
ClientModel *clientModel;
|
||||||
WalletFrame *walletFrame;
|
WalletFrame *walletFrame;
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,8 @@
|
||||||
#include <chainparams.h>
|
#include <chainparams.h>
|
||||||
#include <checkpoints.h>
|
#include <checkpoints.h>
|
||||||
#include <clientversion.h>
|
#include <clientversion.h>
|
||||||
|
#include <interface/handler.h>
|
||||||
|
#include <interface/node.h>
|
||||||
#include <validation.h>
|
#include <validation.h>
|
||||||
#include <net.h>
|
#include <net.h>
|
||||||
#include <txmempool.h>
|
#include <txmempool.h>
|
||||||
|
@ -30,8 +32,9 @@ class CBlockIndex;
|
||||||
static int64_t nLastHeaderTipUpdateNotification = 0;
|
static int64_t nLastHeaderTipUpdateNotification = 0;
|
||||||
static int64_t nLastBlockTipUpdateNotification = 0;
|
static int64_t nLastBlockTipUpdateNotification = 0;
|
||||||
|
|
||||||
ClientModel::ClientModel(OptionsModel *_optionsModel, QObject *parent) :
|
ClientModel::ClientModel(interface::Node& node, OptionsModel *_optionsModel, QObject *parent) :
|
||||||
QObject(parent),
|
QObject(parent),
|
||||||
|
m_node(node),
|
||||||
optionsModel(_optionsModel),
|
optionsModel(_optionsModel),
|
||||||
peerTableModel(0),
|
peerTableModel(0),
|
||||||
banTableModel(0),
|
banTableModel(0),
|
||||||
|
@ -39,8 +42,8 @@ ClientModel::ClientModel(OptionsModel *_optionsModel, QObject *parent) :
|
||||||
{
|
{
|
||||||
cachedBestHeaderHeight = -1;
|
cachedBestHeaderHeight = -1;
|
||||||
cachedBestHeaderTime = -1;
|
cachedBestHeaderTime = -1;
|
||||||
peerTableModel = new PeerTableModel(this);
|
peerTableModel = new PeerTableModel(m_node, this);
|
||||||
banTableModel = new BanTableModel(this);
|
banTableModel = new BanTableModel(m_node, this);
|
||||||
pollTimer = new QTimer(this);
|
pollTimer = new QTimer(this);
|
||||||
connect(pollTimer, SIGNAL(timeout()), this, SLOT(updateTimer()));
|
connect(pollTimer, SIGNAL(timeout()), this, SLOT(updateTimer()));
|
||||||
pollTimer->start(MODEL_UPDATE_DELAY);
|
pollTimer->start(MODEL_UPDATE_DELAY);
|
||||||
|
@ -64,15 +67,7 @@ int ClientModel::getNumConnections(unsigned int flags) const
|
||||||
else if (flags == CONNECTIONS_ALL)
|
else if (flags == CONNECTIONS_ALL)
|
||||||
connections = CConnman::CONNECTIONS_ALL;
|
connections = CConnman::CONNECTIONS_ALL;
|
||||||
|
|
||||||
if(g_connman)
|
return m_node.getNodeCount(connections);
|
||||||
return g_connman->GetNodeCount(connections);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ClientModel::getNumBlocks() const
|
|
||||||
{
|
|
||||||
LOCK(cs_main);
|
|
||||||
return chainActive.Height();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int ClientModel::getHeaderTipHeight() const
|
int ClientModel::getHeaderTipHeight() const
|
||||||
|
@ -80,10 +75,11 @@ int ClientModel::getHeaderTipHeight() const
|
||||||
if (cachedBestHeaderHeight == -1) {
|
if (cachedBestHeaderHeight == -1) {
|
||||||
// make sure we initially populate the cache via a cs_main lock
|
// make sure we initially populate the cache via a cs_main lock
|
||||||
// otherwise we need to wait for a tip update
|
// otherwise we need to wait for a tip update
|
||||||
LOCK(cs_main);
|
int height;
|
||||||
if (pindexBestHeader) {
|
int64_t blockTime;
|
||||||
cachedBestHeaderHeight = pindexBestHeader->nHeight;
|
if (m_node.getHeaderTip(height, blockTime)) {
|
||||||
cachedBestHeaderTime = pindexBestHeader->GetBlockTime();
|
cachedBestHeaderHeight = height;
|
||||||
|
cachedBestHeaderTime = blockTime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return cachedBestHeaderHeight;
|
return cachedBestHeaderHeight;
|
||||||
|
@ -92,66 +88,22 @@ int ClientModel::getHeaderTipHeight() const
|
||||||
int64_t ClientModel::getHeaderTipTime() const
|
int64_t ClientModel::getHeaderTipTime() const
|
||||||
{
|
{
|
||||||
if (cachedBestHeaderTime == -1) {
|
if (cachedBestHeaderTime == -1) {
|
||||||
LOCK(cs_main);
|
int height;
|
||||||
if (pindexBestHeader) {
|
int64_t blockTime;
|
||||||
cachedBestHeaderHeight = pindexBestHeader->nHeight;
|
if (m_node.getHeaderTip(height, blockTime)) {
|
||||||
cachedBestHeaderTime = pindexBestHeader->GetBlockTime();
|
cachedBestHeaderHeight = height;
|
||||||
|
cachedBestHeaderTime = blockTime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return cachedBestHeaderTime;
|
return cachedBestHeaderTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
quint64 ClientModel::getTotalBytesRecv() const
|
|
||||||
{
|
|
||||||
if(!g_connman)
|
|
||||||
return 0;
|
|
||||||
return g_connman->GetTotalBytesRecv();
|
|
||||||
}
|
|
||||||
|
|
||||||
quint64 ClientModel::getTotalBytesSent() const
|
|
||||||
{
|
|
||||||
if(!g_connman)
|
|
||||||
return 0;
|
|
||||||
return g_connman->GetTotalBytesSent();
|
|
||||||
}
|
|
||||||
|
|
||||||
QDateTime ClientModel::getLastBlockDate() const
|
|
||||||
{
|
|
||||||
LOCK(cs_main);
|
|
||||||
|
|
||||||
if (chainActive.Tip())
|
|
||||||
return QDateTime::fromTime_t(chainActive.Tip()->GetBlockTime());
|
|
||||||
|
|
||||||
return QDateTime::fromTime_t(Params().GenesisBlock().GetBlockTime()); // Genesis block's time of current network
|
|
||||||
}
|
|
||||||
|
|
||||||
long ClientModel::getMempoolSize() const
|
|
||||||
{
|
|
||||||
return mempool.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t ClientModel::getMempoolDynamicUsage() const
|
|
||||||
{
|
|
||||||
return mempool.DynamicMemoryUsage();
|
|
||||||
}
|
|
||||||
|
|
||||||
double ClientModel::getVerificationProgress(const CBlockIndex *tipIn) const
|
|
||||||
{
|
|
||||||
CBlockIndex *tip = const_cast<CBlockIndex *>(tipIn);
|
|
||||||
LOCK(cs_main);
|
|
||||||
if (!tip)
|
|
||||||
{
|
|
||||||
tip = chainActive.Tip();
|
|
||||||
}
|
|
||||||
return GuessVerificationProgress(Params().TxData(), tip);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClientModel::updateTimer()
|
void ClientModel::updateTimer()
|
||||||
{
|
{
|
||||||
// no locking required at this point
|
// no locking required at this point
|
||||||
// the following calls will acquire the required lock
|
// the following calls will acquire the required lock
|
||||||
Q_EMIT mempoolSizeChanged(getMempoolSize(), getMempoolDynamicUsage());
|
Q_EMIT mempoolSizeChanged(m_node.getMempoolSize(), m_node.getMempoolDynamicUsage());
|
||||||
Q_EMIT bytesChanged(getTotalBytesRecv(), getTotalBytesSent());
|
Q_EMIT bytesChanged(m_node.getTotalBytesRecv(), m_node.getTotalBytesSent());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientModel::updateNumConnections(int numConnections)
|
void ClientModel::updateNumConnections(int numConnections)
|
||||||
|
@ -169,16 +121,11 @@ void ClientModel::updateAlert()
|
||||||
Q_EMIT alertsChanged(getStatusBarWarnings());
|
Q_EMIT alertsChanged(getStatusBarWarnings());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ClientModel::inInitialBlockDownload() const
|
|
||||||
{
|
|
||||||
return IsInitialBlockDownload();
|
|
||||||
}
|
|
||||||
|
|
||||||
enum BlockSource ClientModel::getBlockSource() const
|
enum BlockSource ClientModel::getBlockSource() const
|
||||||
{
|
{
|
||||||
if (fReindex)
|
if (m_node.getReindex())
|
||||||
return BlockSource::REINDEX;
|
return BlockSource::REINDEX;
|
||||||
else if (fImporting)
|
else if (m_node.getImporting())
|
||||||
return BlockSource::DISK;
|
return BlockSource::DISK;
|
||||||
else if (getNumConnections() > 0)
|
else if (getNumConnections() > 0)
|
||||||
return BlockSource::NETWORK;
|
return BlockSource::NETWORK;
|
||||||
|
@ -186,24 +133,9 @@ enum BlockSource ClientModel::getBlockSource() const
|
||||||
return BlockSource::NONE;
|
return BlockSource::NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientModel::setNetworkActive(bool active)
|
|
||||||
{
|
|
||||||
if (g_connman) {
|
|
||||||
g_connman->SetNetworkActive(active);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ClientModel::getNetworkActive() const
|
|
||||||
{
|
|
||||||
if (g_connman) {
|
|
||||||
return g_connman->GetNetworkActive();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString ClientModel::getStatusBarWarnings() const
|
QString ClientModel::getStatusBarWarnings() const
|
||||||
{
|
{
|
||||||
return QString::fromStdString(GetWarnings("gui"));
|
return QString::fromStdString(m_node.getWarnings("gui"));
|
||||||
}
|
}
|
||||||
|
|
||||||
OptionsModel *ClientModel::getOptionsModel()
|
OptionsModel *ClientModel::getOptionsModel()
|
||||||
|
@ -285,7 +217,7 @@ static void BannedListChanged(ClientModel *clientmodel)
|
||||||
QMetaObject::invokeMethod(clientmodel, "updateBanlist", Qt::QueuedConnection);
|
QMetaObject::invokeMethod(clientmodel, "updateBanlist", Qt::QueuedConnection);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void BlockTipChanged(ClientModel *clientmodel, bool initialSync, const CBlockIndex *pIndex, bool fHeader)
|
static void BlockTipChanged(ClientModel *clientmodel, bool initialSync, int height, int64_t blockTime, double verificationProgress, bool fHeader)
|
||||||
{
|
{
|
||||||
// lock free async UI updates in case we have a new block tip
|
// lock free async UI updates in case we have a new block tip
|
||||||
// during initial sync, only update the UI if the last update
|
// during initial sync, only update the UI if the last update
|
||||||
|
@ -298,16 +230,16 @@ static void BlockTipChanged(ClientModel *clientmodel, bool initialSync, const CB
|
||||||
|
|
||||||
if (fHeader) {
|
if (fHeader) {
|
||||||
// cache best headers time and height to reduce future cs_main locks
|
// cache best headers time and height to reduce future cs_main locks
|
||||||
clientmodel->cachedBestHeaderHeight = pIndex->nHeight;
|
clientmodel->cachedBestHeaderHeight = height;
|
||||||
clientmodel->cachedBestHeaderTime = pIndex->GetBlockTime();
|
clientmodel->cachedBestHeaderTime = blockTime;
|
||||||
}
|
}
|
||||||
// if we are in-sync, update the UI regardless of last update time
|
// if we are in-sync, update the UI regardless of last update time
|
||||||
if (!initialSync || now - nLastUpdateNotification > MODEL_UPDATE_DELAY) {
|
if (!initialSync || now - nLastUpdateNotification > MODEL_UPDATE_DELAY) {
|
||||||
//pass an async signal to the UI thread
|
//pass an async signal to the UI thread
|
||||||
QMetaObject::invokeMethod(clientmodel, "numBlocksChanged", Qt::QueuedConnection,
|
QMetaObject::invokeMethod(clientmodel, "numBlocksChanged", Qt::QueuedConnection,
|
||||||
Q_ARG(int, pIndex->nHeight),
|
Q_ARG(int, height),
|
||||||
Q_ARG(QDateTime, QDateTime::fromTime_t(pIndex->GetBlockTime())),
|
Q_ARG(QDateTime, QDateTime::fromTime_t(blockTime)),
|
||||||
Q_ARG(double, clientmodel->getVerificationProgress(pIndex)),
|
Q_ARG(double, verificationProgress),
|
||||||
Q_ARG(bool, fHeader));
|
Q_ARG(bool, fHeader));
|
||||||
nLastUpdateNotification = now;
|
nLastUpdateNotification = now;
|
||||||
}
|
}
|
||||||
|
@ -316,23 +248,23 @@ static void BlockTipChanged(ClientModel *clientmodel, bool initialSync, const CB
|
||||||
void ClientModel::subscribeToCoreSignals()
|
void ClientModel::subscribeToCoreSignals()
|
||||||
{
|
{
|
||||||
// Connect signals to client
|
// Connect signals to client
|
||||||
uiInterface.ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2));
|
m_handler_show_progress = m_node.handleShowProgress(boost::bind(ShowProgress, this, _1, _2));
|
||||||
uiInterface.NotifyNumConnectionsChanged.connect(boost::bind(NotifyNumConnectionsChanged, this, _1));
|
m_handler_notify_num_connections_changed = m_node.handleNotifyNumConnectionsChanged(boost::bind(NotifyNumConnectionsChanged, this, _1));
|
||||||
uiInterface.NotifyNetworkActiveChanged.connect(boost::bind(NotifyNetworkActiveChanged, this, _1));
|
m_handler_notify_network_active_changed = m_node.handleNotifyNetworkActiveChanged(boost::bind(NotifyNetworkActiveChanged, this, _1));
|
||||||
uiInterface.NotifyAlertChanged.connect(boost::bind(NotifyAlertChanged, this));
|
m_handler_notify_alert_changed = m_node.handleNotifyAlertChanged(boost::bind(NotifyAlertChanged, this));
|
||||||
uiInterface.BannedListChanged.connect(boost::bind(BannedListChanged, this));
|
m_handler_banned_list_changed = m_node.handleBannedListChanged(boost::bind(BannedListChanged, this));
|
||||||
uiInterface.NotifyBlockTip.connect(boost::bind(BlockTipChanged, this, _1, _2, false));
|
m_handler_notify_block_tip = m_node.handleNotifyBlockTip(boost::bind(BlockTipChanged, this, _1, _2, _3, _4, false));
|
||||||
uiInterface.NotifyHeaderTip.connect(boost::bind(BlockTipChanged, this, _1, _2, true));
|
m_handler_notify_header_tip = m_node.handleNotifyHeaderTip(boost::bind(BlockTipChanged, this, _1, _2, _3, _4, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientModel::unsubscribeFromCoreSignals()
|
void ClientModel::unsubscribeFromCoreSignals()
|
||||||
{
|
{
|
||||||
// Disconnect signals from client
|
// Disconnect signals from client
|
||||||
uiInterface.ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2));
|
m_handler_show_progress->disconnect();
|
||||||
uiInterface.NotifyNumConnectionsChanged.disconnect(boost::bind(NotifyNumConnectionsChanged, this, _1));
|
m_handler_notify_num_connections_changed->disconnect();
|
||||||
uiInterface.NotifyNetworkActiveChanged.disconnect(boost::bind(NotifyNetworkActiveChanged, this, _1));
|
m_handler_notify_network_active_changed->disconnect();
|
||||||
uiInterface.NotifyAlertChanged.disconnect(boost::bind(NotifyAlertChanged, this));
|
m_handler_notify_alert_changed->disconnect();
|
||||||
uiInterface.BannedListChanged.disconnect(boost::bind(BannedListChanged, this));
|
m_handler_banned_list_changed->disconnect();
|
||||||
uiInterface.NotifyBlockTip.disconnect(boost::bind(BlockTipChanged, this, _1, _2, false));
|
m_handler_notify_block_tip->disconnect();
|
||||||
uiInterface.NotifyHeaderTip.disconnect(boost::bind(BlockTipChanged, this, _1, _2, true));
|
m_handler_notify_header_tip->disconnect();
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
class BanTableModel;
|
class BanTableModel;
|
||||||
class OptionsModel;
|
class OptionsModel;
|
||||||
|
@ -16,6 +17,11 @@ class PeerTableModel;
|
||||||
|
|
||||||
class CBlockIndex;
|
class CBlockIndex;
|
||||||
|
|
||||||
|
namespace interface {
|
||||||
|
class Handler;
|
||||||
|
class Node;
|
||||||
|
}
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
class QTimer;
|
class QTimer;
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
@ -40,37 +46,21 @@ class ClientModel : public QObject
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ClientModel(OptionsModel *optionsModel, QObject *parent = 0);
|
explicit ClientModel(interface::Node& node, OptionsModel *optionsModel, QObject *parent = 0);
|
||||||
~ClientModel();
|
~ClientModel();
|
||||||
|
|
||||||
|
interface::Node& node() const { return m_node; }
|
||||||
OptionsModel *getOptionsModel();
|
OptionsModel *getOptionsModel();
|
||||||
PeerTableModel *getPeerTableModel();
|
PeerTableModel *getPeerTableModel();
|
||||||
BanTableModel *getBanTableModel();
|
BanTableModel *getBanTableModel();
|
||||||
|
|
||||||
//! Return number of connections, default is in- and outbound (total)
|
//! Return number of connections, default is in- and outbound (total)
|
||||||
int getNumConnections(unsigned int flags = CONNECTIONS_ALL) const;
|
int getNumConnections(unsigned int flags = CONNECTIONS_ALL) const;
|
||||||
int getNumBlocks() const;
|
|
||||||
int getHeaderTipHeight() const;
|
int getHeaderTipHeight() const;
|
||||||
int64_t getHeaderTipTime() const;
|
int64_t getHeaderTipTime() const;
|
||||||
//! Return number of transactions in the mempool
|
|
||||||
long getMempoolSize() const;
|
|
||||||
//! Return the dynamic memory usage of the mempool
|
|
||||||
size_t getMempoolDynamicUsage() const;
|
|
||||||
|
|
||||||
quint64 getTotalBytesRecv() const;
|
|
||||||
quint64 getTotalBytesSent() const;
|
|
||||||
|
|
||||||
double getVerificationProgress(const CBlockIndex *tip) const;
|
|
||||||
QDateTime getLastBlockDate() const;
|
|
||||||
|
|
||||||
//! Return true if core is doing initial block download
|
|
||||||
bool inInitialBlockDownload() const;
|
|
||||||
//! Returns enum BlockSource of the current importing/syncing state
|
//! Returns enum BlockSource of the current importing/syncing state
|
||||||
enum BlockSource getBlockSource() const;
|
enum BlockSource getBlockSource() const;
|
||||||
//! Return true if network activity in core is enabled
|
|
||||||
bool getNetworkActive() const;
|
|
||||||
//! Toggle network activity state in core
|
|
||||||
void setNetworkActive(bool active);
|
|
||||||
//! Return warnings to be displayed in status bar
|
//! Return warnings to be displayed in status bar
|
||||||
QString getStatusBarWarnings() const;
|
QString getStatusBarWarnings() const;
|
||||||
|
|
||||||
|
@ -85,6 +75,14 @@ public:
|
||||||
mutable std::atomic<int64_t> cachedBestHeaderTime;
|
mutable std::atomic<int64_t> cachedBestHeaderTime;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
interface::Node& m_node;
|
||||||
|
std::unique_ptr<interface::Handler> m_handler_show_progress;
|
||||||
|
std::unique_ptr<interface::Handler> m_handler_notify_num_connections_changed;
|
||||||
|
std::unique_ptr<interface::Handler> m_handler_notify_network_active_changed;
|
||||||
|
std::unique_ptr<interface::Handler> m_handler_notify_alert_changed;
|
||||||
|
std::unique_ptr<interface::Handler> m_handler_banned_list_changed;
|
||||||
|
std::unique_ptr<interface::Handler> m_handler_notify_block_tip;
|
||||||
|
std::unique_ptr<interface::Handler> m_handler_notify_header_tip;
|
||||||
OptionsModel *optionsModel;
|
OptionsModel *optionsModel;
|
||||||
PeerTableModel *peerTableModel;
|
PeerTableModel *peerTableModel;
|
||||||
BanTableModel *banTableModel;
|
BanTableModel *banTableModel;
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
#include <qt/walletmodel.h>
|
#include <qt/walletmodel.h>
|
||||||
|
|
||||||
#include <wallet/coincontrol.h>
|
#include <wallet/coincontrol.h>
|
||||||
#include <init.h>
|
#include <interface/node.h>
|
||||||
#include <key_io.h>
|
#include <key_io.h>
|
||||||
#include <policy/fees.h>
|
#include <policy/fees.h>
|
||||||
#include <policy/policy.h>
|
#include <policy/policy.h>
|
||||||
|
@ -209,7 +209,7 @@ void CoinControlDialog::showMenu(const QPoint &point)
|
||||||
if (item->text(COLUMN_TXHASH).length() == 64) // transaction hash is 64 characters (this means it is a child node, so it is not a parent node in tree mode)
|
if (item->text(COLUMN_TXHASH).length() == 64) // transaction hash is 64 characters (this means it is a child node, so it is not a parent node in tree mode)
|
||||||
{
|
{
|
||||||
copyTransactionHashAction->setEnabled(true);
|
copyTransactionHashAction->setEnabled(true);
|
||||||
if (model->isLockedCoin(uint256S(item->text(COLUMN_TXHASH).toStdString()), item->text(COLUMN_VOUT_INDEX).toUInt()))
|
if (model->wallet().isLockedCoin(COutPoint(uint256S(item->text(COLUMN_TXHASH).toStdString()), item->text(COLUMN_VOUT_INDEX).toUInt())))
|
||||||
{
|
{
|
||||||
lockAction->setEnabled(false);
|
lockAction->setEnabled(false);
|
||||||
unlockAction->setEnabled(true);
|
unlockAction->setEnabled(true);
|
||||||
|
@ -269,7 +269,7 @@ void CoinControlDialog::lockCoin()
|
||||||
contextMenuItem->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked);
|
contextMenuItem->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked);
|
||||||
|
|
||||||
COutPoint outpt(uint256S(contextMenuItem->text(COLUMN_TXHASH).toStdString()), contextMenuItem->text(COLUMN_VOUT_INDEX).toUInt());
|
COutPoint outpt(uint256S(contextMenuItem->text(COLUMN_TXHASH).toStdString()), contextMenuItem->text(COLUMN_VOUT_INDEX).toUInt());
|
||||||
model->lockCoin(outpt);
|
model->wallet().lockCoin(outpt);
|
||||||
contextMenuItem->setDisabled(true);
|
contextMenuItem->setDisabled(true);
|
||||||
contextMenuItem->setIcon(COLUMN_CHECKBOX, platformStyle->SingleColorIcon(":/icons/lock_closed"));
|
contextMenuItem->setIcon(COLUMN_CHECKBOX, platformStyle->SingleColorIcon(":/icons/lock_closed"));
|
||||||
updateLabelLocked();
|
updateLabelLocked();
|
||||||
|
@ -279,7 +279,7 @@ void CoinControlDialog::lockCoin()
|
||||||
void CoinControlDialog::unlockCoin()
|
void CoinControlDialog::unlockCoin()
|
||||||
{
|
{
|
||||||
COutPoint outpt(uint256S(contextMenuItem->text(COLUMN_TXHASH).toStdString()), contextMenuItem->text(COLUMN_VOUT_INDEX).toUInt());
|
COutPoint outpt(uint256S(contextMenuItem->text(COLUMN_TXHASH).toStdString()), contextMenuItem->text(COLUMN_VOUT_INDEX).toUInt());
|
||||||
model->unlockCoin(outpt);
|
model->wallet().unlockCoin(outpt);
|
||||||
contextMenuItem->setDisabled(false);
|
contextMenuItem->setDisabled(false);
|
||||||
contextMenuItem->setIcon(COLUMN_CHECKBOX, QIcon());
|
contextMenuItem->setIcon(COLUMN_CHECKBOX, QIcon());
|
||||||
updateLabelLocked();
|
updateLabelLocked();
|
||||||
|
@ -405,7 +405,7 @@ void CoinControlDialog::viewItemChanged(QTreeWidgetItem* item, int column)
|
||||||
void CoinControlDialog::updateLabelLocked()
|
void CoinControlDialog::updateLabelLocked()
|
||||||
{
|
{
|
||||||
std::vector<COutPoint> vOutpts;
|
std::vector<COutPoint> vOutpts;
|
||||||
model->listLockedCoins(vOutpts);
|
model->wallet().listLockedCoins(vOutpts);
|
||||||
if (vOutpts.size() > 0)
|
if (vOutpts.size() > 0)
|
||||||
{
|
{
|
||||||
ui->labelLocked->setText(tr("(%1 locked)").arg(vOutpts.size()));
|
ui->labelLocked->setText(tr("(%1 locked)").arg(vOutpts.size()));
|
||||||
|
@ -431,7 +431,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
|
||||||
{
|
{
|
||||||
CTxOut txout(amount, static_cast<CScript>(std::vector<unsigned char>(24, 0)));
|
CTxOut txout(amount, static_cast<CScript>(std::vector<unsigned char>(24, 0)));
|
||||||
txDummy.vout.push_back(txout);
|
txDummy.vout.push_back(txout);
|
||||||
fDust |= IsDust(txout, ::dustRelayFee);
|
fDust |= IsDust(txout, model->node().getDustRelayFee());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -445,16 +445,16 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
|
||||||
bool fWitness = false;
|
bool fWitness = false;
|
||||||
|
|
||||||
std::vector<COutPoint> vCoinControl;
|
std::vector<COutPoint> vCoinControl;
|
||||||
std::vector<COutput> vOutputs;
|
|
||||||
coinControl()->ListSelected(vCoinControl);
|
coinControl()->ListSelected(vCoinControl);
|
||||||
model->getOutputs(vCoinControl, vOutputs);
|
|
||||||
|
|
||||||
for (const COutput& out : vOutputs) {
|
size_t i = 0;
|
||||||
|
for (const auto& out : model->wallet().getCoins(vCoinControl)) {
|
||||||
|
if (out.depth_in_main_chain < 0) continue;
|
||||||
|
|
||||||
// unselect already spent, very unlikely scenario, this could happen
|
// unselect already spent, very unlikely scenario, this could happen
|
||||||
// when selected are spent elsewhere, like rpc or another computer
|
// when selected are spent elsewhere, like rpc or another computer
|
||||||
uint256 txhash = out.tx->GetHash();
|
const COutPoint& outpt = vCoinControl[i++];
|
||||||
COutPoint outpt(txhash, out.i);
|
if (out.is_spent)
|
||||||
if (model->isSpent(outpt))
|
|
||||||
{
|
{
|
||||||
coinControl()->UnSelect(outpt);
|
coinControl()->UnSelect(outpt);
|
||||||
continue;
|
continue;
|
||||||
|
@ -464,22 +464,22 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
|
||||||
nQuantity++;
|
nQuantity++;
|
||||||
|
|
||||||
// Amount
|
// Amount
|
||||||
nAmount += out.tx->tx->vout[out.i].nValue;
|
nAmount += out.txout.nValue;
|
||||||
|
|
||||||
// Bytes
|
// Bytes
|
||||||
CTxDestination address;
|
CTxDestination address;
|
||||||
int witnessversion = 0;
|
int witnessversion = 0;
|
||||||
std::vector<unsigned char> witnessprogram;
|
std::vector<unsigned char> witnessprogram;
|
||||||
if (out.tx->tx->vout[out.i].scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram))
|
if (out.txout.scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram))
|
||||||
{
|
{
|
||||||
nBytesInputs += (32 + 4 + 1 + (107 / WITNESS_SCALE_FACTOR) + 4);
|
nBytesInputs += (32 + 4 + 1 + (107 / WITNESS_SCALE_FACTOR) + 4);
|
||||||
fWitness = true;
|
fWitness = true;
|
||||||
}
|
}
|
||||||
else if(ExtractDestination(out.tx->tx->vout[out.i].scriptPubKey, address))
|
else if(ExtractDestination(out.txout.scriptPubKey, address))
|
||||||
{
|
{
|
||||||
CPubKey pubkey;
|
CPubKey pubkey;
|
||||||
CKeyID *keyid = boost::get<CKeyID>(&address);
|
CKeyID *keyid = boost::get<CKeyID>(&address);
|
||||||
if (keyid && model->getPubKey(*keyid, pubkey))
|
if (keyid && model->wallet().getPubKey(*keyid, pubkey))
|
||||||
{
|
{
|
||||||
nBytesInputs += (pubkey.IsCompressed() ? 148 : 180);
|
nBytesInputs += (pubkey.IsCompressed() ? 148 : 180);
|
||||||
}
|
}
|
||||||
|
@ -509,7 +509,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
|
||||||
nBytes -= 34;
|
nBytes -= 34;
|
||||||
|
|
||||||
// Fee
|
// Fee
|
||||||
nPayFee = GetMinimumFee(nBytes, *coinControl(), ::mempool, ::feeEstimator, nullptr /* FeeCalculation */);
|
nPayFee = model->node().getMinimumFee(nBytes, *coinControl(), nullptr /* returned_target */, nullptr /* reason */);
|
||||||
|
|
||||||
if (nPayAmount > 0)
|
if (nPayAmount > 0)
|
||||||
{
|
{
|
||||||
|
@ -521,7 +521,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
|
||||||
if (nChange > 0 && nChange < MIN_CHANGE)
|
if (nChange > 0 && nChange < MIN_CHANGE)
|
||||||
{
|
{
|
||||||
CTxOut txout(nChange, static_cast<CScript>(std::vector<unsigned char>(24, 0)));
|
CTxOut txout(nChange, static_cast<CScript>(std::vector<unsigned char>(24, 0)));
|
||||||
if (IsDust(txout, ::dustRelayFee))
|
if (IsDust(txout, model->node().getDustRelayFee()))
|
||||||
{
|
{
|
||||||
nPayFee += nChange;
|
nPayFee += nChange;
|
||||||
nChange = 0;
|
nChange = 0;
|
||||||
|
@ -621,13 +621,10 @@ void CoinControlDialog::updateView()
|
||||||
|
|
||||||
int nDisplayUnit = model->getOptionsModel()->getDisplayUnit();
|
int nDisplayUnit = model->getOptionsModel()->getDisplayUnit();
|
||||||
|
|
||||||
std::map<QString, std::vector<COutput> > mapCoins;
|
for (const auto& coins : model->wallet().listCoins()) {
|
||||||
model->listCoins(mapCoins);
|
|
||||||
|
|
||||||
for (const std::pair<QString, std::vector<COutput>>& coins : mapCoins) {
|
|
||||||
CCoinControlWidgetItem *itemWalletAddress = new CCoinControlWidgetItem();
|
CCoinControlWidgetItem *itemWalletAddress = new CCoinControlWidgetItem();
|
||||||
itemWalletAddress->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked);
|
itemWalletAddress->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked);
|
||||||
QString sWalletAddress = coins.first;
|
QString sWalletAddress = QString::fromStdString(EncodeDestination(coins.first));
|
||||||
QString sWalletLabel = model->getAddressTableModel()->labelForAddress(sWalletAddress);
|
QString sWalletLabel = model->getAddressTableModel()->labelForAddress(sWalletAddress);
|
||||||
if (sWalletLabel.isEmpty())
|
if (sWalletLabel.isEmpty())
|
||||||
sWalletLabel = tr("(no label)");
|
sWalletLabel = tr("(no label)");
|
||||||
|
@ -649,8 +646,10 @@ void CoinControlDialog::updateView()
|
||||||
|
|
||||||
CAmount nSum = 0;
|
CAmount nSum = 0;
|
||||||
int nChildren = 0;
|
int nChildren = 0;
|
||||||
for (const COutput& out : coins.second) {
|
for (const auto& outpair : coins.second) {
|
||||||
nSum += out.tx->tx->vout[out.i].nValue;
|
const COutPoint& output = std::get<0>(outpair);
|
||||||
|
const interface::WalletTxOut& out = std::get<1>(outpair);
|
||||||
|
nSum += out.txout.nValue;
|
||||||
nChildren++;
|
nChildren++;
|
||||||
|
|
||||||
CCoinControlWidgetItem *itemOutput;
|
CCoinControlWidgetItem *itemOutput;
|
||||||
|
@ -662,7 +661,7 @@ void CoinControlDialog::updateView()
|
||||||
// address
|
// address
|
||||||
CTxDestination outputAddress;
|
CTxDestination outputAddress;
|
||||||
QString sAddress = "";
|
QString sAddress = "";
|
||||||
if(ExtractDestination(out.tx->tx->vout[out.i].scriptPubKey, outputAddress))
|
if(ExtractDestination(out.txout.scriptPubKey, outputAddress))
|
||||||
{
|
{
|
||||||
sAddress = QString::fromStdString(EncodeDestination(outputAddress));
|
sAddress = QString::fromStdString(EncodeDestination(outputAddress));
|
||||||
|
|
||||||
|
@ -687,35 +686,33 @@ void CoinControlDialog::updateView()
|
||||||
}
|
}
|
||||||
|
|
||||||
// amount
|
// amount
|
||||||
itemOutput->setText(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, out.tx->tx->vout[out.i].nValue));
|
itemOutput->setText(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, out.txout.nValue));
|
||||||
itemOutput->setData(COLUMN_AMOUNT, Qt::UserRole, QVariant((qlonglong)out.tx->tx->vout[out.i].nValue)); // padding so that sorting works correctly
|
itemOutput->setData(COLUMN_AMOUNT, Qt::UserRole, QVariant((qlonglong)out.txout.nValue)); // padding so that sorting works correctly
|
||||||
|
|
||||||
// date
|
// date
|
||||||
itemOutput->setText(COLUMN_DATE, GUIUtil::dateTimeStr(out.tx->GetTxTime()));
|
itemOutput->setText(COLUMN_DATE, GUIUtil::dateTimeStr(out.time));
|
||||||
itemOutput->setData(COLUMN_DATE, Qt::UserRole, QVariant((qlonglong)out.tx->GetTxTime()));
|
itemOutput->setData(COLUMN_DATE, Qt::UserRole, QVariant((qlonglong)out.time));
|
||||||
|
|
||||||
// confirmations
|
// confirmations
|
||||||
itemOutput->setText(COLUMN_CONFIRMATIONS, QString::number(out.nDepth));
|
itemOutput->setText(COLUMN_CONFIRMATIONS, QString::number(out.depth_in_main_chain));
|
||||||
itemOutput->setData(COLUMN_CONFIRMATIONS, Qt::UserRole, QVariant((qlonglong)out.nDepth));
|
itemOutput->setData(COLUMN_CONFIRMATIONS, Qt::UserRole, QVariant((qlonglong)out.depth_in_main_chain));
|
||||||
|
|
||||||
// transaction hash
|
// transaction hash
|
||||||
uint256 txhash = out.tx->GetHash();
|
itemOutput->setText(COLUMN_TXHASH, QString::fromStdString(output.hash.GetHex()));
|
||||||
itemOutput->setText(COLUMN_TXHASH, QString::fromStdString(txhash.GetHex()));
|
|
||||||
|
|
||||||
// vout index
|
// vout index
|
||||||
itemOutput->setText(COLUMN_VOUT_INDEX, QString::number(out.i));
|
itemOutput->setText(COLUMN_VOUT_INDEX, QString::number(output.n));
|
||||||
|
|
||||||
// disable locked coins
|
// disable locked coins
|
||||||
if (model->isLockedCoin(txhash, out.i))
|
if (model->wallet().isLockedCoin(output))
|
||||||
{
|
{
|
||||||
COutPoint outpt(txhash, out.i);
|
coinControl()->UnSelect(output); // just to be sure
|
||||||
coinControl()->UnSelect(outpt); // just to be sure
|
|
||||||
itemOutput->setDisabled(true);
|
itemOutput->setDisabled(true);
|
||||||
itemOutput->setIcon(COLUMN_CHECKBOX, platformStyle->SingleColorIcon(":/icons/lock_closed"));
|
itemOutput->setIcon(COLUMN_CHECKBOX, platformStyle->SingleColorIcon(":/icons/lock_closed"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// set checkbox
|
// set checkbox
|
||||||
if (coinControl()->IsSelected(COutPoint(txhash, out.i)))
|
if (coinControl()->IsSelected(output))
|
||||||
itemOutput->setCheckState(COLUMN_CHECKBOX, Qt::Checked);
|
itemOutput->setCheckState(COLUMN_CHECKBOX, Qt::Checked);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
#include <chainparams.h>
|
#include <chainparams.h>
|
||||||
#include <primitives/transaction.h>
|
#include <primitives/transaction.h>
|
||||||
#include <key_io.h>
|
#include <key_io.h>
|
||||||
#include <init.h>
|
#include <interface/node.h>
|
||||||
#include <policy/policy.h>
|
#include <policy/policy.h>
|
||||||
#include <protocol.h>
|
#include <protocol.h>
|
||||||
#include <script/script.h>
|
#include <script/script.h>
|
||||||
|
@ -232,12 +232,12 @@ QString formatBitcoinURI(const SendCoinsRecipient &info)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isDust(const QString& address, const CAmount& amount)
|
bool isDust(interface::Node& node, const QString& address, const CAmount& amount)
|
||||||
{
|
{
|
||||||
CTxDestination dest = DecodeDestination(address.toStdString());
|
CTxDestination dest = DecodeDestination(address.toStdString());
|
||||||
CScript script = GetScriptForDestination(dest);
|
CScript script = GetScriptForDestination(dest);
|
||||||
CTxOut txOut(amount, script);
|
CTxOut txOut(amount, script);
|
||||||
return IsDust(txOut, ::dustRelayFee);
|
return IsDust(txOut, node.getDustRelayFee());
|
||||||
}
|
}
|
||||||
|
|
||||||
QString HtmlEscape(const QString& str, bool fMultiLine)
|
QString HtmlEscape(const QString& str, bool fMultiLine)
|
||||||
|
|
|
@ -20,6 +20,11 @@
|
||||||
class QValidatedLineEdit;
|
class QValidatedLineEdit;
|
||||||
class SendCoinsRecipient;
|
class SendCoinsRecipient;
|
||||||
|
|
||||||
|
namespace interface
|
||||||
|
{
|
||||||
|
class Node;
|
||||||
|
}
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
class QAbstractItemView;
|
class QAbstractItemView;
|
||||||
class QDateTime;
|
class QDateTime;
|
||||||
|
@ -49,7 +54,7 @@ namespace GUIUtil
|
||||||
QString formatBitcoinURI(const SendCoinsRecipient &info);
|
QString formatBitcoinURI(const SendCoinsRecipient &info);
|
||||||
|
|
||||||
// Returns true if given address+amount meets "dust" definition
|
// Returns true if given address+amount meets "dust" definition
|
||||||
bool isDust(const QString& address, const CAmount& amount);
|
bool isDust(interface::Node& node, const QString& address, const CAmount& amount);
|
||||||
|
|
||||||
// HTML escaping for rich text controls
|
// HTML escaping for rich text controls
|
||||||
QString HtmlEscape(const QString& str, bool fMultiLine=false);
|
QString HtmlEscape(const QString& str, bool fMultiLine=false);
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
#include <qt/guiutil.h>
|
#include <qt/guiutil.h>
|
||||||
|
|
||||||
|
#include <interface/node.h>
|
||||||
#include <util.h>
|
#include <util.h>
|
||||||
|
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
|
@ -186,7 +187,7 @@ QString Intro::getDefaultDataDirectory()
|
||||||
return GUIUtil::boostPathToQString(GetDefaultDataDir());
|
return GUIUtil::boostPathToQString(GetDefaultDataDir());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Intro::pickDataDirectory()
|
bool Intro::pickDataDirectory(interface::Node& node)
|
||||||
{
|
{
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
/* If data directory provided on command line, no need to look at settings
|
/* If data directory provided on command line, no need to look at settings
|
||||||
|
@ -233,8 +234,9 @@ bool Intro::pickDataDirectory()
|
||||||
* override -datadir in the bitcoin.conf file in the default data directory
|
* override -datadir in the bitcoin.conf file in the default data directory
|
||||||
* (to be consistent with bitcoind behavior)
|
* (to be consistent with bitcoind behavior)
|
||||||
*/
|
*/
|
||||||
if(dataDir != getDefaultDataDirectory())
|
if(dataDir != getDefaultDataDirectory()) {
|
||||||
gArgs.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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,10 @@ static const bool DEFAULT_CHOOSE_DATADIR = false;
|
||||||
|
|
||||||
class FreespaceChecker;
|
class FreespaceChecker;
|
||||||
|
|
||||||
|
namespace interface {
|
||||||
|
class Node;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class Intro;
|
class Intro;
|
||||||
}
|
}
|
||||||
|
@ -41,7 +45,7 @@ public:
|
||||||
* @note do NOT call global GetDataDir() before calling this function, this
|
* @note do NOT call global GetDataDir() before calling this function, this
|
||||||
* will cause the wrong path to be cached.
|
* will cause the wrong path to be cached.
|
||||||
*/
|
*/
|
||||||
static bool pickDataDirectory();
|
static bool pickDataDirectory(interface::Node& node);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine default data directory for operating system.
|
* Determine default data directory for operating system.
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <qt/guiutil.h>
|
#include <qt/guiutil.h>
|
||||||
#include <qt/optionsmodel.h>
|
#include <qt/optionsmodel.h>
|
||||||
|
|
||||||
|
#include <interface/node.h>
|
||||||
#include <validation.h> // for DEFAULT_SCRIPTCHECK_THREADS and MAX_SCRIPTCHECK_THREADS
|
#include <validation.h> // for DEFAULT_SCRIPTCHECK_THREADS and MAX_SCRIPTCHECK_THREADS
|
||||||
#include <netbase.h>
|
#include <netbase.h>
|
||||||
#include <txdb.h> // for -dbcache defaults
|
#include <txdb.h> // for -dbcache defaults
|
||||||
|
@ -313,17 +314,17 @@ void OptionsDialog::updateDefaultProxyNets()
|
||||||
std::string strProxy;
|
std::string strProxy;
|
||||||
QString strDefaultProxyGUI;
|
QString strDefaultProxyGUI;
|
||||||
|
|
||||||
GetProxy(NET_IPV4, proxy);
|
model->node().getProxy(NET_IPV4, proxy);
|
||||||
strProxy = proxy.proxy.ToStringIP() + ":" + proxy.proxy.ToStringPort();
|
strProxy = proxy.proxy.ToStringIP() + ":" + proxy.proxy.ToStringPort();
|
||||||
strDefaultProxyGUI = ui->proxyIp->text() + ":" + ui->proxyPort->text();
|
strDefaultProxyGUI = ui->proxyIp->text() + ":" + ui->proxyPort->text();
|
||||||
(strProxy == strDefaultProxyGUI.toStdString()) ? ui->proxyReachIPv4->setChecked(true) : ui->proxyReachIPv4->setChecked(false);
|
(strProxy == strDefaultProxyGUI.toStdString()) ? ui->proxyReachIPv4->setChecked(true) : ui->proxyReachIPv4->setChecked(false);
|
||||||
|
|
||||||
GetProxy(NET_IPV6, proxy);
|
model->node().getProxy(NET_IPV6, proxy);
|
||||||
strProxy = proxy.proxy.ToStringIP() + ":" + proxy.proxy.ToStringPort();
|
strProxy = proxy.proxy.ToStringIP() + ":" + proxy.proxy.ToStringPort();
|
||||||
strDefaultProxyGUI = ui->proxyIp->text() + ":" + ui->proxyPort->text();
|
strDefaultProxyGUI = ui->proxyIp->text() + ":" + ui->proxyPort->text();
|
||||||
(strProxy == strDefaultProxyGUI.toStdString()) ? ui->proxyReachIPv6->setChecked(true) : ui->proxyReachIPv6->setChecked(false);
|
(strProxy == strDefaultProxyGUI.toStdString()) ? ui->proxyReachIPv6->setChecked(true) : ui->proxyReachIPv6->setChecked(false);
|
||||||
|
|
||||||
GetProxy(NET_TOR, proxy);
|
model->node().getProxy(NET_TOR, proxy);
|
||||||
strProxy = proxy.proxy.ToStringIP() + ":" + proxy.proxy.ToStringPort();
|
strProxy = proxy.proxy.ToStringIP() + ":" + proxy.proxy.ToStringPort();
|
||||||
strDefaultProxyGUI = ui->proxyIp->text() + ":" + ui->proxyPort->text();
|
strDefaultProxyGUI = ui->proxyIp->text() + ":" + ui->proxyPort->text();
|
||||||
(strProxy == strDefaultProxyGUI.toStdString()) ? ui->proxyReachTor->setChecked(true) : ui->proxyReachTor->setChecked(false);
|
(strProxy == strDefaultProxyGUI.toStdString()) ? ui->proxyReachTor->setChecked(true) : ui->proxyReachTor->setChecked(false);
|
||||||
|
|
|
@ -11,26 +11,21 @@
|
||||||
#include <qt/bitcoinunits.h>
|
#include <qt/bitcoinunits.h>
|
||||||
#include <qt/guiutil.h>
|
#include <qt/guiutil.h>
|
||||||
|
|
||||||
#include <init.h>
|
#include <interface/node.h>
|
||||||
#include <validation.h> // For DEFAULT_SCRIPTCHECK_THREADS
|
#include <validation.h> // For DEFAULT_SCRIPTCHECK_THREADS
|
||||||
#include <net.h>
|
#include <net.h>
|
||||||
#include <netbase.h>
|
#include <netbase.h>
|
||||||
#include <txdb.h> // for -dbcache defaults
|
#include <txdb.h> // for -dbcache defaults
|
||||||
#include <qt/intro.h>
|
#include <qt/intro.h>
|
||||||
|
|
||||||
#ifdef ENABLE_WALLET
|
|
||||||
#include <wallet/wallet.h>
|
|
||||||
#include <wallet/walletdb.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <QNetworkProxy>
|
#include <QNetworkProxy>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
|
||||||
const char *DEFAULT_GUI_PROXY_HOST = "127.0.0.1";
|
const char *DEFAULT_GUI_PROXY_HOST = "127.0.0.1";
|
||||||
|
|
||||||
OptionsModel::OptionsModel(QObject *parent, bool resetSettings) :
|
OptionsModel::OptionsModel(interface::Node& node, QObject *parent, bool resetSettings) :
|
||||||
QAbstractListModel(parent)
|
QAbstractListModel(parent), m_node(node)
|
||||||
{
|
{
|
||||||
Init(resetSettings);
|
Init(resetSettings);
|
||||||
}
|
}
|
||||||
|
@ -93,12 +88,12 @@ void OptionsModel::Init(bool resetSettings)
|
||||||
// Main
|
// Main
|
||||||
if (!settings.contains("nDatabaseCache"))
|
if (!settings.contains("nDatabaseCache"))
|
||||||
settings.setValue("nDatabaseCache", (qint64)nDefaultDbCache);
|
settings.setValue("nDatabaseCache", (qint64)nDefaultDbCache);
|
||||||
if (!gArgs.SoftSetArg("-dbcache", settings.value("nDatabaseCache").toString().toStdString()))
|
if (!m_node.softSetArg("-dbcache", settings.value("nDatabaseCache").toString().toStdString()))
|
||||||
addOverriddenOption("-dbcache");
|
addOverriddenOption("-dbcache");
|
||||||
|
|
||||||
if (!settings.contains("nThreadsScriptVerif"))
|
if (!settings.contains("nThreadsScriptVerif"))
|
||||||
settings.setValue("nThreadsScriptVerif", DEFAULT_SCRIPTCHECK_THREADS);
|
settings.setValue("nThreadsScriptVerif", DEFAULT_SCRIPTCHECK_THREADS);
|
||||||
if (!gArgs.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"))
|
if (!settings.contains("strDataDir"))
|
||||||
|
@ -108,19 +103,19 @@ void OptionsModel::Init(bool resetSettings)
|
||||||
#ifdef ENABLE_WALLET
|
#ifdef ENABLE_WALLET
|
||||||
if (!settings.contains("bSpendZeroConfChange"))
|
if (!settings.contains("bSpendZeroConfChange"))
|
||||||
settings.setValue("bSpendZeroConfChange", true);
|
settings.setValue("bSpendZeroConfChange", true);
|
||||||
if (!gArgs.SoftSetBoolArg("-spendzeroconfchange", settings.value("bSpendZeroConfChange").toBool()))
|
if (!m_node.softSetBoolArg("-spendzeroconfchange", settings.value("bSpendZeroConfChange").toBool()))
|
||||||
addOverriddenOption("-spendzeroconfchange");
|
addOverriddenOption("-spendzeroconfchange");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Network
|
// Network
|
||||||
if (!settings.contains("fUseUPnP"))
|
if (!settings.contains("fUseUPnP"))
|
||||||
settings.setValue("fUseUPnP", DEFAULT_UPNP);
|
settings.setValue("fUseUPnP", DEFAULT_UPNP);
|
||||||
if (!gArgs.SoftSetBoolArg("-upnp", settings.value("fUseUPnP").toBool()))
|
if (!m_node.softSetBoolArg("-upnp", settings.value("fUseUPnP").toBool()))
|
||||||
addOverriddenOption("-upnp");
|
addOverriddenOption("-upnp");
|
||||||
|
|
||||||
if (!settings.contains("fListen"))
|
if (!settings.contains("fListen"))
|
||||||
settings.setValue("fListen", DEFAULT_LISTEN);
|
settings.setValue("fListen", DEFAULT_LISTEN);
|
||||||
if (!gArgs.SoftSetBoolArg("-listen", settings.value("fListen").toBool()))
|
if (!m_node.softSetBoolArg("-listen", settings.value("fListen").toBool()))
|
||||||
addOverriddenOption("-listen");
|
addOverriddenOption("-listen");
|
||||||
|
|
||||||
if (!settings.contains("fUseProxy"))
|
if (!settings.contains("fUseProxy"))
|
||||||
|
@ -128,7 +123,7 @@ void OptionsModel::Init(bool resetSettings)
|
||||||
if (!settings.contains("addrProxy"))
|
if (!settings.contains("addrProxy"))
|
||||||
settings.setValue("addrProxy", QString("%1:%2").arg(DEFAULT_GUI_PROXY_HOST, DEFAULT_GUI_PROXY_PORT));
|
settings.setValue("addrProxy", QString("%1:%2").arg(DEFAULT_GUI_PROXY_HOST, DEFAULT_GUI_PROXY_PORT));
|
||||||
// Only try to set -proxy, if user has enabled fUseProxy
|
// Only try to set -proxy, if user has enabled fUseProxy
|
||||||
if (settings.value("fUseProxy").toBool() && !gArgs.SoftSetArg("-proxy", settings.value("addrProxy").toString().toStdString()))
|
if (settings.value("fUseProxy").toBool() && !m_node.softSetArg("-proxy", settings.value("addrProxy").toString().toStdString()))
|
||||||
addOverriddenOption("-proxy");
|
addOverriddenOption("-proxy");
|
||||||
else if(!settings.value("fUseProxy").toBool() && !gArgs.GetArg("-proxy", "").empty())
|
else if(!settings.value("fUseProxy").toBool() && !gArgs.GetArg("-proxy", "").empty())
|
||||||
addOverriddenOption("-proxy");
|
addOverriddenOption("-proxy");
|
||||||
|
@ -138,7 +133,7 @@ void OptionsModel::Init(bool resetSettings)
|
||||||
if (!settings.contains("addrSeparateProxyTor"))
|
if (!settings.contains("addrSeparateProxyTor"))
|
||||||
settings.setValue("addrSeparateProxyTor", QString("%1:%2").arg(DEFAULT_GUI_PROXY_HOST, DEFAULT_GUI_PROXY_PORT));
|
settings.setValue("addrSeparateProxyTor", QString("%1:%2").arg(DEFAULT_GUI_PROXY_HOST, DEFAULT_GUI_PROXY_PORT));
|
||||||
// Only try to set -onion, if user has enabled fUseSeparateProxyTor
|
// Only try to set -onion, if user has enabled fUseSeparateProxyTor
|
||||||
if (settings.value("fUseSeparateProxyTor").toBool() && !gArgs.SoftSetArg("-onion", settings.value("addrSeparateProxyTor").toString().toStdString()))
|
if (settings.value("fUseSeparateProxyTor").toBool() && !m_node.softSetArg("-onion", settings.value("addrSeparateProxyTor").toString().toStdString()))
|
||||||
addOverriddenOption("-onion");
|
addOverriddenOption("-onion");
|
||||||
else if(!settings.value("fUseSeparateProxyTor").toBool() && !gArgs.GetArg("-onion", "").empty())
|
else if(!settings.value("fUseSeparateProxyTor").toBool() && !gArgs.GetArg("-onion", "").empty())
|
||||||
addOverriddenOption("-onion");
|
addOverriddenOption("-onion");
|
||||||
|
@ -146,7 +141,7 @@ void OptionsModel::Init(bool resetSettings)
|
||||||
// Display
|
// Display
|
||||||
if (!settings.contains("language"))
|
if (!settings.contains("language"))
|
||||||
settings.setValue("language", "");
|
settings.setValue("language", "");
|
||||||
if (!gArgs.SoftSetArg("-lang", settings.value("language").toString().toStdString()))
|
if (!m_node.softSetArg("-lang", settings.value("language").toString().toStdString()))
|
||||||
addOverriddenOption("-lang");
|
addOverriddenOption("-lang");
|
||||||
|
|
||||||
language = settings.value("language").toString();
|
language = settings.value("language").toString();
|
||||||
|
@ -315,12 +310,7 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in
|
||||||
break;
|
break;
|
||||||
case MapPortUPnP: // core option - can be changed on-the-fly
|
case MapPortUPnP: // core option - can be changed on-the-fly
|
||||||
settings.setValue("fUseUPnP", value.toBool());
|
settings.setValue("fUseUPnP", value.toBool());
|
||||||
if (value.toBool()) {
|
m_node.mapPort(value.toBool());
|
||||||
StartMapPort();
|
|
||||||
} else {
|
|
||||||
InterruptMapPort();
|
|
||||||
StopMapPort();
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case MinimizeOnClose:
|
case MinimizeOnClose:
|
||||||
fMinimizeOnClose = value.toBool();
|
fMinimizeOnClose = value.toBool();
|
||||||
|
@ -453,7 +443,7 @@ bool OptionsModel::getProxySettings(QNetworkProxy& proxy) const
|
||||||
// Directly query current base proxy, because
|
// Directly query current base proxy, because
|
||||||
// GUI settings can be overridden with -proxy.
|
// GUI settings can be overridden with -proxy.
|
||||||
proxyType curProxy;
|
proxyType curProxy;
|
||||||
if (GetProxy(NET_IPV4, curProxy)) {
|
if (m_node.getProxy(NET_IPV4, curProxy)) {
|
||||||
proxy.setType(QNetworkProxy::Socks5Proxy);
|
proxy.setType(QNetworkProxy::Socks5Proxy);
|
||||||
proxy.setHostName(QString::fromStdString(curProxy.proxy.ToStringIP()));
|
proxy.setHostName(QString::fromStdString(curProxy.proxy.ToStringIP()));
|
||||||
proxy.setPort(curProxy.proxy.GetPort());
|
proxy.setPort(curProxy.proxy.GetPort());
|
||||||
|
|
|
@ -9,6 +9,10 @@
|
||||||
|
|
||||||
#include <QAbstractListModel>
|
#include <QAbstractListModel>
|
||||||
|
|
||||||
|
namespace interface {
|
||||||
|
class Node;
|
||||||
|
}
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
class QNetworkProxy;
|
class QNetworkProxy;
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
@ -27,7 +31,7 @@ class OptionsModel : public QAbstractListModel
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit OptionsModel(QObject *parent = 0, bool resetSettings = false);
|
explicit OptionsModel(interface::Node& node, QObject *parent = 0, bool resetSettings = false);
|
||||||
|
|
||||||
enum OptionID {
|
enum OptionID {
|
||||||
StartAtStartup, // bool
|
StartAtStartup, // bool
|
||||||
|
@ -75,7 +79,10 @@ public:
|
||||||
void setRestartRequired(bool fRequired);
|
void setRestartRequired(bool fRequired);
|
||||||
bool isRestartRequired() const;
|
bool isRestartRequired() const;
|
||||||
|
|
||||||
|
interface::Node& node() const { return m_node; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
interface::Node& m_node;
|
||||||
/* Qt-only settings */
|
/* Qt-only settings */
|
||||||
bool fHideTrayIcon;
|
bool fHideTrayIcon;
|
||||||
bool fMinimizeToTray;
|
bool fMinimizeToTray;
|
||||||
|
|
|
@ -21,6 +21,8 @@
|
||||||
#define DECORATION_SIZE 54
|
#define DECORATION_SIZE 54
|
||||||
#define NUM_ITEMS 5
|
#define NUM_ITEMS 5
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(interface::WalletBalances)
|
||||||
|
|
||||||
class TxViewDelegate : public QAbstractItemDelegate
|
class TxViewDelegate : public QAbstractItemDelegate
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -113,16 +115,12 @@ OverviewPage::OverviewPage(const PlatformStyle *platformStyle, QWidget *parent)
|
||||||
ui(new Ui::OverviewPage),
|
ui(new Ui::OverviewPage),
|
||||||
clientModel(0),
|
clientModel(0),
|
||||||
walletModel(0),
|
walletModel(0),
|
||||||
currentBalance(-1),
|
|
||||||
currentUnconfirmedBalance(-1),
|
|
||||||
currentImmatureBalance(-1),
|
|
||||||
currentWatchOnlyBalance(-1),
|
|
||||||
currentWatchUnconfBalance(-1),
|
|
||||||
currentWatchImmatureBalance(-1),
|
|
||||||
txdelegate(new TxViewDelegate(platformStyle, this))
|
txdelegate(new TxViewDelegate(platformStyle, this))
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
m_balances.balance = -1;
|
||||||
|
|
||||||
// use a SingleColorIcon for the "out of sync warning" icon
|
// use a SingleColorIcon for the "out of sync warning" icon
|
||||||
QIcon icon = platformStyle->SingleColorIcon(":/icons/warning");
|
QIcon icon = platformStyle->SingleColorIcon(":/icons/warning");
|
||||||
icon.addPixmap(icon.pixmap(QSize(64,64), QIcon::Normal), QIcon::Disabled); // also set the disabled icon because we are using a disabled QPushButton to work around missing HiDPI support of QLabel (https://bugreports.qt.io/browse/QTBUG-42503)
|
icon.addPixmap(icon.pixmap(QSize(64,64), QIcon::Normal), QIcon::Disabled); // also set the disabled icon because we are using a disabled QPushButton to work around missing HiDPI support of QLabel (https://bugreports.qt.io/browse/QTBUG-42503)
|
||||||
|
@ -159,28 +157,23 @@ OverviewPage::~OverviewPage()
|
||||||
delete ui;
|
delete ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OverviewPage::setBalance(const CAmount& balance, const CAmount& unconfirmedBalance, const CAmount& immatureBalance, const CAmount& watchOnlyBalance, const CAmount& watchUnconfBalance, const CAmount& watchImmatureBalance)
|
void OverviewPage::setBalance(const interface::WalletBalances& balances)
|
||||||
{
|
{
|
||||||
int unit = walletModel->getOptionsModel()->getDisplayUnit();
|
int unit = walletModel->getOptionsModel()->getDisplayUnit();
|
||||||
currentBalance = balance;
|
m_balances = balances;
|
||||||
currentUnconfirmedBalance = unconfirmedBalance;
|
ui->labelBalance->setText(BitcoinUnits::formatWithUnit(unit, balances.balance, false, BitcoinUnits::separatorAlways));
|
||||||
currentImmatureBalance = immatureBalance;
|
ui->labelUnconfirmed->setText(BitcoinUnits::formatWithUnit(unit, balances.unconfirmed_balance, false, BitcoinUnits::separatorAlways));
|
||||||
currentWatchOnlyBalance = watchOnlyBalance;
|
ui->labelImmature->setText(BitcoinUnits::formatWithUnit(unit, balances.immature_balance, false, BitcoinUnits::separatorAlways));
|
||||||
currentWatchUnconfBalance = watchUnconfBalance;
|
ui->labelTotal->setText(BitcoinUnits::formatWithUnit(unit, balances.balance + balances.unconfirmed_balance + balances.immature_balance, false, BitcoinUnits::separatorAlways));
|
||||||
currentWatchImmatureBalance = watchImmatureBalance;
|
ui->labelWatchAvailable->setText(BitcoinUnits::formatWithUnit(unit, balances.watch_only_balance, false, BitcoinUnits::separatorAlways));
|
||||||
ui->labelBalance->setText(BitcoinUnits::formatWithUnit(unit, balance, false, BitcoinUnits::separatorAlways));
|
ui->labelWatchPending->setText(BitcoinUnits::formatWithUnit(unit, balances.unconfirmed_watch_only_balance, false, BitcoinUnits::separatorAlways));
|
||||||
ui->labelUnconfirmed->setText(BitcoinUnits::formatWithUnit(unit, unconfirmedBalance, false, BitcoinUnits::separatorAlways));
|
ui->labelWatchImmature->setText(BitcoinUnits::formatWithUnit(unit, balances.immature_watch_only_balance, false, BitcoinUnits::separatorAlways));
|
||||||
ui->labelImmature->setText(BitcoinUnits::formatWithUnit(unit, immatureBalance, false, BitcoinUnits::separatorAlways));
|
ui->labelWatchTotal->setText(BitcoinUnits::formatWithUnit(unit, balances.watch_only_balance + balances.unconfirmed_watch_only_balance + balances.immature_watch_only_balance, false, BitcoinUnits::separatorAlways));
|
||||||
ui->labelTotal->setText(BitcoinUnits::formatWithUnit(unit, balance + unconfirmedBalance + immatureBalance, false, BitcoinUnits::separatorAlways));
|
|
||||||
ui->labelWatchAvailable->setText(BitcoinUnits::formatWithUnit(unit, watchOnlyBalance, false, BitcoinUnits::separatorAlways));
|
|
||||||
ui->labelWatchPending->setText(BitcoinUnits::formatWithUnit(unit, watchUnconfBalance, false, BitcoinUnits::separatorAlways));
|
|
||||||
ui->labelWatchImmature->setText(BitcoinUnits::formatWithUnit(unit, watchImmatureBalance, false, BitcoinUnits::separatorAlways));
|
|
||||||
ui->labelWatchTotal->setText(BitcoinUnits::formatWithUnit(unit, watchOnlyBalance + watchUnconfBalance + watchImmatureBalance, false, BitcoinUnits::separatorAlways));
|
|
||||||
|
|
||||||
// only show immature (newly mined) balance if it's non-zero, so as not to complicate things
|
// only show immature (newly mined) balance if it's non-zero, so as not to complicate things
|
||||||
// for the non-mining users
|
// for the non-mining users
|
||||||
bool showImmature = immatureBalance != 0;
|
bool showImmature = balances.immature_balance != 0;
|
||||||
bool showWatchOnlyImmature = watchImmatureBalance != 0;
|
bool showWatchOnlyImmature = balances.immature_watch_only_balance != 0;
|
||||||
|
|
||||||
// for symmetry reasons also show immature label when the watch-only one is shown
|
// for symmetry reasons also show immature label when the watch-only one is shown
|
||||||
ui->labelImmature->setVisible(showImmature || showWatchOnlyImmature);
|
ui->labelImmature->setVisible(showImmature || showWatchOnlyImmature);
|
||||||
|
@ -231,13 +224,14 @@ void OverviewPage::setWalletModel(WalletModel *model)
|
||||||
ui->listTransactions->setModelColumn(TransactionTableModel::ToAddress);
|
ui->listTransactions->setModelColumn(TransactionTableModel::ToAddress);
|
||||||
|
|
||||||
// Keep up to date with wallet
|
// Keep up to date with wallet
|
||||||
setBalance(model->getBalance(), model->getUnconfirmedBalance(), model->getImmatureBalance(),
|
interface::Wallet& wallet = model->wallet();
|
||||||
model->getWatchBalance(), model->getWatchUnconfirmedBalance(), model->getWatchImmatureBalance());
|
interface::WalletBalances balances = wallet.getBalances();
|
||||||
connect(model, SIGNAL(balanceChanged(CAmount,CAmount,CAmount,CAmount,CAmount,CAmount)), this, SLOT(setBalance(CAmount,CAmount,CAmount,CAmount,CAmount,CAmount)));
|
setBalance(balances);
|
||||||
|
connect(model, SIGNAL(balanceChanged(interface::WalletBalances)), this, SLOT(setBalance(interface::WalletBalances)));
|
||||||
|
|
||||||
connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
|
connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
|
||||||
|
|
||||||
updateWatchOnlyLabels(model->haveWatchOnly());
|
updateWatchOnlyLabels(wallet.haveWatchOnly());
|
||||||
connect(model, SIGNAL(notifyWatchonlyChanged(bool)), this, SLOT(updateWatchOnlyLabels(bool)));
|
connect(model, SIGNAL(notifyWatchonlyChanged(bool)), this, SLOT(updateWatchOnlyLabels(bool)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,9 +243,9 @@ void OverviewPage::updateDisplayUnit()
|
||||||
{
|
{
|
||||||
if(walletModel && walletModel->getOptionsModel())
|
if(walletModel && walletModel->getOptionsModel())
|
||||||
{
|
{
|
||||||
if(currentBalance != -1)
|
if (m_balances.balance != -1) {
|
||||||
setBalance(currentBalance, currentUnconfirmedBalance, currentImmatureBalance,
|
setBalance(m_balances);
|
||||||
currentWatchOnlyBalance, currentWatchUnconfBalance, currentWatchImmatureBalance);
|
}
|
||||||
|
|
||||||
// Update txdelegate->unit with the current unit
|
// Update txdelegate->unit with the current unit
|
||||||
txdelegate->unit = walletModel->getOptionsModel()->getDisplayUnit();
|
txdelegate->unit = walletModel->getOptionsModel()->getDisplayUnit();
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#ifndef BITCOIN_QT_OVERVIEWPAGE_H
|
#ifndef BITCOIN_QT_OVERVIEWPAGE_H
|
||||||
#define BITCOIN_QT_OVERVIEWPAGE_H
|
#define BITCOIN_QT_OVERVIEWPAGE_H
|
||||||
|
|
||||||
#include <amount.h>
|
#include <interface/wallet.h>
|
||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
@ -38,8 +38,7 @@ public:
|
||||||
void showOutOfSyncWarning(bool fShow);
|
void showOutOfSyncWarning(bool fShow);
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
void setBalance(const CAmount& balance, const CAmount& unconfirmedBalance, const CAmount& immatureBalance,
|
void setBalance(const interface::WalletBalances& balances);
|
||||||
const CAmount& watchOnlyBalance, const CAmount& watchUnconfBalance, const CAmount& watchImmatureBalance);
|
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void transactionClicked(const QModelIndex &index);
|
void transactionClicked(const QModelIndex &index);
|
||||||
|
@ -49,12 +48,7 @@ private:
|
||||||
Ui::OverviewPage *ui;
|
Ui::OverviewPage *ui;
|
||||||
ClientModel *clientModel;
|
ClientModel *clientModel;
|
||||||
WalletModel *walletModel;
|
WalletModel *walletModel;
|
||||||
CAmount currentBalance;
|
interface::WalletBalances m_balances;
|
||||||
CAmount currentUnconfirmedBalance;
|
|
||||||
CAmount currentImmatureBalance;
|
|
||||||
CAmount currentWatchOnlyBalance;
|
|
||||||
CAmount currentWatchUnconfBalance;
|
|
||||||
CAmount currentWatchImmatureBalance;
|
|
||||||
|
|
||||||
TxViewDelegate *txdelegate;
|
TxViewDelegate *txdelegate;
|
||||||
std::unique_ptr<TransactionFilterProxy> filter;
|
std::unique_ptr<TransactionFilterProxy> filter;
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <qt/optionsmodel.h>
|
#include <qt/optionsmodel.h>
|
||||||
|
|
||||||
#include <chainparams.h>
|
#include <chainparams.h>
|
||||||
|
#include <interface/node.h>
|
||||||
#include <policy/policy.h>
|
#include <policy/policy.h>
|
||||||
#include <key_io.h>
|
#include <key_io.h>
|
||||||
#include <ui_interface.h>
|
#include <ui_interface.h>
|
||||||
|
@ -200,7 +201,7 @@ void PaymentServer::LoadRootCAs(X509_STORE* _store)
|
||||||
// Warning: ipcSendCommandLine() is called early in init,
|
// Warning: ipcSendCommandLine() is called early in init,
|
||||||
// so don't use "Q_EMIT message()", but "QMessageBox::"!
|
// so don't use "Q_EMIT message()", but "QMessageBox::"!
|
||||||
//
|
//
|
||||||
void PaymentServer::ipcParseCommandLine(int argc, char* argv[])
|
void PaymentServer::ipcParseCommandLine(interface::Node& node, int argc, char* argv[])
|
||||||
{
|
{
|
||||||
for (int i = 1; i < argc; i++)
|
for (int i = 1; i < argc; i++)
|
||||||
{
|
{
|
||||||
|
@ -222,11 +223,11 @@ void PaymentServer::ipcParseCommandLine(int argc, char* argv[])
|
||||||
auto tempChainParams = CreateChainParams(CBaseChainParams::MAIN);
|
auto tempChainParams = CreateChainParams(CBaseChainParams::MAIN);
|
||||||
|
|
||||||
if (IsValidDestinationString(r.address.toStdString(), *tempChainParams)) {
|
if (IsValidDestinationString(r.address.toStdString(), *tempChainParams)) {
|
||||||
SelectParams(CBaseChainParams::MAIN);
|
node.selectParams(CBaseChainParams::MAIN);
|
||||||
} else {
|
} else {
|
||||||
tempChainParams = CreateChainParams(CBaseChainParams::TESTNET);
|
tempChainParams = CreateChainParams(CBaseChainParams::TESTNET);
|
||||||
if (IsValidDestinationString(r.address.toStdString(), *tempChainParams)) {
|
if (IsValidDestinationString(r.address.toStdString(), *tempChainParams)) {
|
||||||
SelectParams(CBaseChainParams::TESTNET);
|
node.selectParams(CBaseChainParams::TESTNET);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -240,11 +241,11 @@ void PaymentServer::ipcParseCommandLine(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
if (request.getDetails().network() == "main")
|
if (request.getDetails().network() == "main")
|
||||||
{
|
{
|
||||||
SelectParams(CBaseChainParams::MAIN);
|
node.selectParams(CBaseChainParams::MAIN);
|
||||||
}
|
}
|
||||||
else if (request.getDetails().network() == "test")
|
else if (request.getDetails().network() == "test")
|
||||||
{
|
{
|
||||||
SelectParams(CBaseChainParams::TESTNET);
|
node.selectParams(CBaseChainParams::TESTNET);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -527,7 +528,7 @@ bool PaymentServer::processPaymentRequest(const PaymentRequestPlus& request, Sen
|
||||||
|
|
||||||
if (request.IsInitialized()) {
|
if (request.IsInitialized()) {
|
||||||
// Payment request network matches client network?
|
// Payment request network matches client network?
|
||||||
if (!verifyNetwork(request.getDetails())) {
|
if (!verifyNetwork(optionsModel->node(), request.getDetails())) {
|
||||||
Q_EMIT message(tr("Payment request rejected"), tr("Payment request network doesn't match client network."),
|
Q_EMIT message(tr("Payment request rejected"), tr("Payment request network doesn't match client network."),
|
||||||
CClientUIInterface::MSG_ERROR);
|
CClientUIInterface::MSG_ERROR);
|
||||||
|
|
||||||
|
@ -584,7 +585,7 @@ bool PaymentServer::processPaymentRequest(const PaymentRequestPlus& request, Sen
|
||||||
|
|
||||||
// Extract and check amounts
|
// Extract and check amounts
|
||||||
CTxOut txOut(sendingTo.second, sendingTo.first);
|
CTxOut txOut(sendingTo.second, sendingTo.first);
|
||||||
if (IsDust(txOut, ::dustRelayFee)) {
|
if (IsDust(txOut, optionsModel->node().getDustRelayFee())) {
|
||||||
Q_EMIT message(tr("Payment request error"), tr("Requested payment amount of %1 is too small (considered dust).")
|
Q_EMIT message(tr("Payment request error"), tr("Requested payment amount of %1 is too small (considered dust).")
|
||||||
.arg(BitcoinUnits::formatWithUnit(optionsModel->getDisplayUnit(), sendingTo.second)),
|
.arg(BitcoinUnits::formatWithUnit(optionsModel->getDisplayUnit(), sendingTo.second)),
|
||||||
CClientUIInterface::MSG_ERROR);
|
CClientUIInterface::MSG_ERROR);
|
||||||
|
@ -622,7 +623,7 @@ void PaymentServer::fetchRequest(const QUrl& url)
|
||||||
netManager->get(netRequest);
|
netManager->get(netRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PaymentServer::fetchPaymentACK(CWallet* wallet, const SendCoinsRecipient& recipient, QByteArray transaction)
|
void PaymentServer::fetchPaymentACK(WalletModel* walletModel, const SendCoinsRecipient& recipient, QByteArray transaction)
|
||||||
{
|
{
|
||||||
const payments::PaymentDetails& details = recipient.paymentRequest.getDetails();
|
const payments::PaymentDetails& details = recipient.paymentRequest.getDetails();
|
||||||
if (!details.has_payment_url())
|
if (!details.has_payment_url())
|
||||||
|
@ -641,17 +642,17 @@ void PaymentServer::fetchPaymentACK(CWallet* wallet, const SendCoinsRecipient& r
|
||||||
|
|
||||||
// Create a new refund address, or re-use:
|
// Create a new refund address, or re-use:
|
||||||
CPubKey newKey;
|
CPubKey newKey;
|
||||||
if (wallet->GetKeyFromPool(newKey)) {
|
if (walletModel->wallet().getKeyFromPool(false /* internal */, newKey)) {
|
||||||
// BIP70 requests encode the scriptPubKey directly, so we are not restricted to address
|
// BIP70 requests encode the scriptPubKey directly, so we are not restricted to address
|
||||||
// types supported by the receiver. As a result, we choose the address format we also
|
// types supported by the receiver. As a result, we choose the address format we also
|
||||||
// use for change. Despite an actual payment and not change, this is a close match:
|
// use for change. Despite an actual payment and not change, this is a close match:
|
||||||
// it's the output type we use subject to privacy issues, but not restricted by what
|
// it's the output type we use subject to privacy issues, but not restricted by what
|
||||||
// other software supports.
|
// other software supports.
|
||||||
const OutputType change_type = wallet->m_default_change_type != OutputType::NONE ? wallet->m_default_change_type : wallet->m_default_address_type;
|
const OutputType change_type = walletModel->wallet().getDefaultChangeType() != OutputType::NONE ? walletModel->wallet().getDefaultChangeType() : walletModel->wallet().getDefaultAddressType();
|
||||||
wallet->LearnRelatedScripts(newKey, change_type);
|
walletModel->wallet().learnRelatedScripts(newKey, change_type);
|
||||||
CTxDestination dest = GetDestinationForKey(newKey, change_type);
|
CTxDestination dest = GetDestinationForKey(newKey, change_type);
|
||||||
std::string label = tr("Refund from %1").arg(recipient.authenticatedMerchant).toStdString();
|
std::string label = tr("Refund from %1").arg(recipient.authenticatedMerchant).toStdString();
|
||||||
wallet->SetAddressBook(dest, label, "refund");
|
walletModel->wallet().setAddressBook(dest, label, "refund");
|
||||||
|
|
||||||
CScript s = GetScriptForDestination(dest);
|
CScript s = GetScriptForDestination(dest);
|
||||||
payments::Output* refund_to = payment.add_refund_to();
|
payments::Output* refund_to = payment.add_refund_to();
|
||||||
|
@ -759,14 +760,14 @@ void PaymentServer::handlePaymentACK(const QString& paymentACKMsg)
|
||||||
Q_EMIT message(tr("Payment acknowledged"), paymentACKMsg, CClientUIInterface::ICON_INFORMATION | CClientUIInterface::MODAL);
|
Q_EMIT message(tr("Payment acknowledged"), paymentACKMsg, CClientUIInterface::ICON_INFORMATION | CClientUIInterface::MODAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PaymentServer::verifyNetwork(const payments::PaymentDetails& requestDetails)
|
bool PaymentServer::verifyNetwork(interface::Node& node, const payments::PaymentDetails& requestDetails)
|
||||||
{
|
{
|
||||||
bool fVerified = requestDetails.network() == Params().NetworkIDString();
|
bool fVerified = requestDetails.network() == node.getNetwork();
|
||||||
if (!fVerified) {
|
if (!fVerified) {
|
||||||
qWarning() << QString("PaymentServer::%1: Payment request network \"%2\" doesn't match client network \"%3\".")
|
qWarning() << QString("PaymentServer::%1: Payment request network \"%2\" doesn't match client network \"%3\".")
|
||||||
.arg(__func__)
|
.arg(__func__)
|
||||||
.arg(QString::fromStdString(requestDetails.network()))
|
.arg(QString::fromStdString(requestDetails.network()))
|
||||||
.arg(QString::fromStdString(Params().NetworkIDString()));
|
.arg(QString::fromStdString(node.getNetwork()));
|
||||||
}
|
}
|
||||||
return fVerified;
|
return fVerified;
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,8 +40,6 @@
|
||||||
|
|
||||||
class OptionsModel;
|
class OptionsModel;
|
||||||
|
|
||||||
class CWallet;
|
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
class QApplication;
|
class QApplication;
|
||||||
class QByteArray;
|
class QByteArray;
|
||||||
|
@ -62,7 +60,7 @@ class PaymentServer : public QObject
|
||||||
public:
|
public:
|
||||||
// Parse URIs on command line
|
// Parse URIs on command line
|
||||||
// Returns false on error
|
// Returns false on error
|
||||||
static void ipcParseCommandLine(int argc, char *argv[]);
|
static void ipcParseCommandLine(interface::Node& node, int argc, char *argv[]);
|
||||||
|
|
||||||
// Returns true if there were URIs on the command line
|
// Returns true if there were URIs on the command line
|
||||||
// which were successfully sent to an already-running
|
// which were successfully sent to an already-running
|
||||||
|
@ -89,7 +87,7 @@ public:
|
||||||
void setOptionsModel(OptionsModel *optionsModel);
|
void setOptionsModel(OptionsModel *optionsModel);
|
||||||
|
|
||||||
// Verify that the payment request network matches the client network
|
// Verify that the payment request network matches the client network
|
||||||
static bool verifyNetwork(const payments::PaymentDetails& requestDetails);
|
static bool verifyNetwork(interface::Node& node, const payments::PaymentDetails& requestDetails);
|
||||||
// Verify if the payment request is expired
|
// Verify if the payment request is expired
|
||||||
static bool verifyExpired(const payments::PaymentDetails& requestDetails);
|
static bool verifyExpired(const payments::PaymentDetails& requestDetails);
|
||||||
// Verify the payment request size is valid as per BIP70
|
// Verify the payment request size is valid as per BIP70
|
||||||
|
@ -113,7 +111,7 @@ public Q_SLOTS:
|
||||||
void uiReady();
|
void uiReady();
|
||||||
|
|
||||||
// Submit Payment message to a merchant, get back PaymentACK:
|
// Submit Payment message to a merchant, get back PaymentACK:
|
||||||
void fetchPaymentACK(CWallet* wallet, const SendCoinsRecipient& recipient, QByteArray transaction);
|
void fetchPaymentACK(WalletModel* walletModel, const SendCoinsRecipient& recipient, QByteArray transaction);
|
||||||
|
|
||||||
// Handle an incoming URI, URI with local file scheme or file
|
// Handle an incoming URI, URI with local file scheme or file
|
||||||
void handleURIOrFile(const QString& s);
|
void handleURIOrFile(const QString& s);
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <qt/guiconstants.h>
|
#include <qt/guiconstants.h>
|
||||||
#include <qt/guiutil.h>
|
#include <qt/guiutil.h>
|
||||||
|
|
||||||
|
#include <interface/node.h>
|
||||||
#include <validation.h> // for cs_main
|
#include <validation.h> // for cs_main
|
||||||
#include <sync.h>
|
#include <sync.h>
|
||||||
|
|
||||||
|
@ -56,38 +57,26 @@ public:
|
||||||
std::map<NodeId, int> mapNodeRows;
|
std::map<NodeId, int> mapNodeRows;
|
||||||
|
|
||||||
/** Pull a full list of peers from vNodes into our cache */
|
/** Pull a full list of peers from vNodes into our cache */
|
||||||
void refreshPeers()
|
void refreshPeers(interface::Node& node)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
cachedNodeStats.clear();
|
cachedNodeStats.clear();
|
||||||
std::vector<CNodeStats> vstats;
|
|
||||||
if(g_connman)
|
interface::Node::NodesStats nodes_stats;
|
||||||
g_connman->GetNodeStats(vstats);
|
node.getNodesStats(nodes_stats);
|
||||||
#if QT_VERSION >= 0x040700
|
#if QT_VERSION >= 0x040700
|
||||||
cachedNodeStats.reserve(vstats.size());
|
cachedNodeStats.reserve(nodes_stats.size());
|
||||||
#endif
|
#endif
|
||||||
for (const CNodeStats& nodestats : vstats)
|
for (auto& node_stats : nodes_stats)
|
||||||
{
|
{
|
||||||
CNodeCombinedStats stats;
|
CNodeCombinedStats stats;
|
||||||
stats.nodeStateStats.nMisbehavior = 0;
|
stats.nodeStats = std::get<0>(node_stats);
|
||||||
stats.nodeStateStats.nSyncHeight = -1;
|
stats.fNodeStateStatsAvailable = std::get<1>(node_stats);
|
||||||
stats.nodeStateStats.nCommonHeight = -1;
|
stats.nodeStateStats = std::get<2>(node_stats);
|
||||||
stats.fNodeStateStatsAvailable = false;
|
|
||||||
stats.nodeStats = nodestats;
|
|
||||||
cachedNodeStats.append(stats);
|
cachedNodeStats.append(stats);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to retrieve the CNodeStateStats for each node.
|
|
||||||
{
|
|
||||||
TRY_LOCK(cs_main, lockMain);
|
|
||||||
if (lockMain)
|
|
||||||
{
|
|
||||||
for (CNodeCombinedStats &stats : cachedNodeStats)
|
|
||||||
stats.fNodeStateStatsAvailable = GetNodeStateStats(stats.nodeStats.nodeid, stats.nodeStateStats);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sortColumn >= 0)
|
if (sortColumn >= 0)
|
||||||
// sort cacheNodeStats (use stable sort to prevent rows jumping around unnecessarily)
|
// sort cacheNodeStats (use stable sort to prevent rows jumping around unnecessarily)
|
||||||
qStableSort(cachedNodeStats.begin(), cachedNodeStats.end(), NodeLessThan(sortColumn, sortOrder));
|
qStableSort(cachedNodeStats.begin(), cachedNodeStats.end(), NodeLessThan(sortColumn, sortOrder));
|
||||||
|
@ -113,8 +102,9 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
PeerTableModel::PeerTableModel(ClientModel *parent) :
|
PeerTableModel::PeerTableModel(interface::Node& node, ClientModel *parent) :
|
||||||
QAbstractTableModel(parent),
|
QAbstractTableModel(parent),
|
||||||
|
m_node(node),
|
||||||
clientModel(parent),
|
clientModel(parent),
|
||||||
timer(0)
|
timer(0)
|
||||||
{
|
{
|
||||||
|
@ -235,7 +225,7 @@ const CNodeCombinedStats *PeerTableModel::getNodeStats(int idx)
|
||||||
void PeerTableModel::refresh()
|
void PeerTableModel::refresh()
|
||||||
{
|
{
|
||||||
Q_EMIT layoutAboutToBeChanged();
|
Q_EMIT layoutAboutToBeChanged();
|
||||||
priv->refreshPeers();
|
priv->refreshPeers(m_node);
|
||||||
Q_EMIT layoutChanged();
|
Q_EMIT layoutChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,10 @@
|
||||||
class ClientModel;
|
class ClientModel;
|
||||||
class PeerTablePriv;
|
class PeerTablePriv;
|
||||||
|
|
||||||
|
namespace interface {
|
||||||
|
class Node;
|
||||||
|
}
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
class QTimer;
|
class QTimer;
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
@ -47,7 +51,7 @@ class PeerTableModel : public QAbstractTableModel
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit PeerTableModel(ClientModel *parent = 0);
|
explicit PeerTableModel(interface::Node& node, ClientModel *parent = 0);
|
||||||
~PeerTableModel();
|
~PeerTableModel();
|
||||||
const CNodeCombinedStats *getNodeStats(int idx);
|
const CNodeCombinedStats *getNodeStats(int idx);
|
||||||
int getRowByNodeId(NodeId nodeid);
|
int getRowByNodeId(NodeId nodeid);
|
||||||
|
@ -78,6 +82,7 @@ public Q_SLOTS:
|
||||||
void refresh();
|
void refresh();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
interface::Node& m_node;
|
||||||
ClientModel *clientModel;
|
ClientModel *clientModel;
|
||||||
QStringList columns;
|
QStringList columns;
|
||||||
std::unique_ptr<PeerTablePriv> priv;
|
std::unique_ptr<PeerTablePriv> priv;
|
||||||
|
|
|
@ -95,13 +95,13 @@ void ReceiveCoinsDialog::setModel(WalletModel *_model)
|
||||||
columnResizingFixer = new GUIUtil::TableViewLastColumnResizingFixer(tableView, AMOUNT_MINIMUM_COLUMN_WIDTH, DATE_COLUMN_WIDTH, this);
|
columnResizingFixer = new GUIUtil::TableViewLastColumnResizingFixer(tableView, AMOUNT_MINIMUM_COLUMN_WIDTH, DATE_COLUMN_WIDTH, this);
|
||||||
|
|
||||||
// configure bech32 checkbox, disable if launched with legacy as default:
|
// configure bech32 checkbox, disable if launched with legacy as default:
|
||||||
if (model->getDefaultAddressType() == OutputType::BECH32) {
|
if (model->wallet().getDefaultAddressType() == OutputType::BECH32) {
|
||||||
ui->useBech32->setCheckState(Qt::Checked);
|
ui->useBech32->setCheckState(Qt::Checked);
|
||||||
} else {
|
} else {
|
||||||
ui->useBech32->setCheckState(Qt::Unchecked);
|
ui->useBech32->setCheckState(Qt::Unchecked);
|
||||||
}
|
}
|
||||||
|
|
||||||
ui->useBech32->setVisible(model->getDefaultAddressType() != OutputType::LEGACY);
|
ui->useBech32->setVisible(model->wallet().getDefaultAddressType() != OutputType::LEGACY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,7 +144,7 @@ void ReceiveCoinsDialog::on_receiveButton_clicked()
|
||||||
QString address;
|
QString address;
|
||||||
QString label = ui->reqLabel->text();
|
QString label = ui->reqLabel->text();
|
||||||
/* Generate new receiving address */
|
/* Generate new receiving address */
|
||||||
OutputType address_type = model->getDefaultAddressType();
|
OutputType address_type = model->wallet().getDefaultAddressType();
|
||||||
if (address_type != OutputType::LEGACY) {
|
if (address_type != OutputType::LEGACY) {
|
||||||
address_type = ui->useBech32->isChecked() ? OutputType::BECH32 : OutputType::P2SH_SEGWIT;
|
address_type = ui->useBech32->isChecked() ? OutputType::BECH32 : OutputType::P2SH_SEGWIT;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,10 +12,9 @@
|
||||||
#include <streams.h>
|
#include <streams.h>
|
||||||
|
|
||||||
|
|
||||||
RecentRequestsTableModel::RecentRequestsTableModel(CWallet *wallet, WalletModel *parent) :
|
RecentRequestsTableModel::RecentRequestsTableModel(WalletModel *parent) :
|
||||||
QAbstractTableModel(parent), walletModel(parent)
|
QAbstractTableModel(parent), walletModel(parent)
|
||||||
{
|
{
|
||||||
Q_UNUSED(wallet);
|
|
||||||
nReceiveRequestsMaxId = 0;
|
nReceiveRequestsMaxId = 0;
|
||||||
|
|
||||||
// Load entries from wallet
|
// Load entries from wallet
|
||||||
|
|
|
@ -11,8 +11,6 @@
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
|
|
||||||
class CWallet;
|
|
||||||
|
|
||||||
class RecentRequestEntry
|
class RecentRequestEntry
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -60,7 +58,7 @@ class RecentRequestsTableModel: public QAbstractTableModel
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit RecentRequestsTableModel(CWallet *wallet, WalletModel *parent);
|
explicit RecentRequestsTableModel(WalletModel *parent);
|
||||||
~RecentRequestsTableModel();
|
~RecentRequestsTableModel();
|
||||||
|
|
||||||
enum ColumnIndex {
|
enum ColumnIndex {
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <qt/platformstyle.h>
|
#include <qt/platformstyle.h>
|
||||||
#include <qt/walletmodel.h>
|
#include <qt/walletmodel.h>
|
||||||
#include <chainparams.h>
|
#include <chainparams.h>
|
||||||
|
#include <interface/node.h>
|
||||||
#include <netbase.h>
|
#include <netbase.h>
|
||||||
#include <rpc/server.h>
|
#include <rpc/server.h>
|
||||||
#include <rpc/client.h>
|
#include <rpc/client.h>
|
||||||
|
@ -83,12 +84,17 @@ const QStringList historyFilter = QStringList()
|
||||||
class RPCExecutor : public QObject
|
class RPCExecutor : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
RPCExecutor(interface::Node& node) : m_node(node) {}
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
void request(const QString &command, const QString &walletID);
|
void request(const QString &command, const QString &walletID);
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void reply(int category, const QString &command);
|
void reply(int category, const QString &command);
|
||||||
|
|
||||||
|
private:
|
||||||
|
interface::Node& m_node;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Class for handling RPC timers
|
/** Class for handling RPC timers
|
||||||
|
@ -140,13 +146,14 @@ public:
|
||||||
* - Within double quotes, only escape \c " and backslashes before a \c " or another backslash
|
* - Within double quotes, only escape \c " and backslashes before a \c " or another backslash
|
||||||
* - Within single quotes, no escaping is possible and no special interpretation takes place
|
* - Within single quotes, no escaping is possible and no special interpretation takes place
|
||||||
*
|
*
|
||||||
|
* @param[in] node optional node to execute command on
|
||||||
* @param[out] result stringified Result from the executed command(chain)
|
* @param[out] result stringified Result from the executed command(chain)
|
||||||
* @param[in] strCommand Command line to split
|
* @param[in] strCommand Command line to split
|
||||||
* @param[in] fExecute set true if you want the command to be executed
|
* @param[in] fExecute set true if you want the command to be executed
|
||||||
* @param[out] pstrFilteredOut Command line, filtered to remove any sensitive data
|
* @param[out] pstrFilteredOut Command line, filtered to remove any sensitive data
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bool RPCConsole::RPCParseCommandLine(std::string &strResult, const std::string &strCommand, const bool fExecute, std::string * const pstrFilteredOut, const std::string *walletID)
|
bool RPCConsole::RPCParseCommandLine(interface::Node* node, std::string &strResult, const std::string &strCommand, const bool fExecute, std::string * const pstrFilteredOut, const std::string *walletID)
|
||||||
{
|
{
|
||||||
std::vector< std::vector<std::string> > stack;
|
std::vector< std::vector<std::string> > stack;
|
||||||
stack.push_back(std::vector<std::string>());
|
stack.push_back(std::vector<std::string>());
|
||||||
|
@ -300,16 +307,17 @@ bool RPCConsole::RPCParseCommandLine(std::string &strResult, const std::string &
|
||||||
if (fExecute) {
|
if (fExecute) {
|
||||||
// Convert argument list to JSON objects in method-dependent way,
|
// Convert argument list to JSON objects in method-dependent way,
|
||||||
// and pass it along with the method name to the dispatcher.
|
// and pass it along with the method name to the dispatcher.
|
||||||
JSONRPCRequest req;
|
UniValue params = RPCConvertValues(stack.back()[0], std::vector<std::string>(stack.back().begin() + 1, stack.back().end()));
|
||||||
req.params = RPCConvertValues(stack.back()[0], std::vector<std::string>(stack.back().begin() + 1, stack.back().end()));
|
std::string method = stack.back()[0];
|
||||||
req.strMethod = stack.back()[0];
|
std::string uri;
|
||||||
#ifdef ENABLE_WALLET
|
#ifdef ENABLE_WALLET
|
||||||
if (walletID && !walletID->empty()) {
|
if (walletID && !walletID->empty()) {
|
||||||
QByteArray encodedName = QUrl::toPercentEncoding(QString::fromStdString(*walletID));
|
QByteArray encodedName = QUrl::toPercentEncoding(QString::fromStdString(*walletID));
|
||||||
req.URI = "/wallet/"+std::string(encodedName.constData(), encodedName.length());
|
uri = "/wallet/"+std::string(encodedName.constData(), encodedName.length());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
lastResult = tableRPC.execute(req);
|
assert(node);
|
||||||
|
lastResult = node->executeRpc(method, params, uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
state = STATE_COMMAND_EXECUTED;
|
state = STATE_COMMAND_EXECUTED;
|
||||||
|
@ -416,7 +424,7 @@ void RPCExecutor::request(const QString &command, const QString &walletID)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
std::string wallet_id = walletID.toStdString();
|
std::string wallet_id = walletID.toStdString();
|
||||||
if(!RPCConsole::RPCExecuteCommandLine(result, executableCommand, nullptr, &wallet_id))
|
if(!RPCConsole::RPCExecuteCommandLine(m_node, result, executableCommand, nullptr, &wallet_id))
|
||||||
{
|
{
|
||||||
Q_EMIT reply(RPCConsole::CMD_ERROR, QString("Parse error: unbalanced ' or \""));
|
Q_EMIT reply(RPCConsole::CMD_ERROR, QString("Parse error: unbalanced ' or \""));
|
||||||
return;
|
return;
|
||||||
|
@ -443,8 +451,9 @@ void RPCExecutor::request(const QString &command, const QString &walletID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RPCConsole::RPCConsole(const PlatformStyle *_platformStyle, QWidget *parent) :
|
RPCConsole::RPCConsole(interface::Node& node, const PlatformStyle *_platformStyle, QWidget *parent) :
|
||||||
QWidget(parent),
|
QWidget(parent),
|
||||||
|
m_node(node),
|
||||||
ui(new Ui::RPCConsole),
|
ui(new Ui::RPCConsole),
|
||||||
clientModel(0),
|
clientModel(0),
|
||||||
historyPtr(0),
|
historyPtr(0),
|
||||||
|
@ -493,7 +502,7 @@ RPCConsole::RPCConsole(const PlatformStyle *_platformStyle, QWidget *parent) :
|
||||||
rpcTimerInterface = new QtRPCTimerInterface();
|
rpcTimerInterface = new QtRPCTimerInterface();
|
||||||
// avoid accidentally overwriting an existing, non QTThread
|
// avoid accidentally overwriting an existing, non QTThread
|
||||||
// based timer interface
|
// based timer interface
|
||||||
RPCSetTimerInterfaceIfUnset(rpcTimerInterface);
|
m_node.rpcSetTimerInterfaceIfUnset(rpcTimerInterface);
|
||||||
|
|
||||||
setTrafficGraphRange(INITIAL_TRAFFIC_GRAPH_MINS);
|
setTrafficGraphRange(INITIAL_TRAFFIC_GRAPH_MINS);
|
||||||
|
|
||||||
|
@ -508,7 +517,7 @@ RPCConsole::~RPCConsole()
|
||||||
{
|
{
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
settings.setValue("RPCConsoleWindowGeometry", saveGeometry());
|
settings.setValue("RPCConsoleWindowGeometry", saveGeometry());
|
||||||
RPCUnsetTimerInterface(rpcTimerInterface);
|
m_node.rpcUnsetTimerInterface(rpcTimerInterface);
|
||||||
delete rpcTimerInterface;
|
delete rpcTimerInterface;
|
||||||
delete ui;
|
delete ui;
|
||||||
}
|
}
|
||||||
|
@ -566,13 +575,14 @@ void RPCConsole::setClientModel(ClientModel *model)
|
||||||
setNumConnections(model->getNumConnections());
|
setNumConnections(model->getNumConnections());
|
||||||
connect(model, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int)));
|
connect(model, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int)));
|
||||||
|
|
||||||
setNumBlocks(model->getNumBlocks(), model->getLastBlockDate(), model->getVerificationProgress(nullptr), false);
|
interface::Node& node = clientModel->node();
|
||||||
|
setNumBlocks(node.getNumBlocks(), QDateTime::fromTime_t(node.getLastBlockTime()), node.getVerificationProgress(), false);
|
||||||
connect(model, SIGNAL(numBlocksChanged(int,QDateTime,double,bool)), this, SLOT(setNumBlocks(int,QDateTime,double,bool)));
|
connect(model, SIGNAL(numBlocksChanged(int,QDateTime,double,bool)), this, SLOT(setNumBlocks(int,QDateTime,double,bool)));
|
||||||
|
|
||||||
updateNetworkState();
|
updateNetworkState();
|
||||||
connect(model, SIGNAL(networkActiveChanged(bool)), this, SLOT(setNetworkActive(bool)));
|
connect(model, SIGNAL(networkActiveChanged(bool)), this, SLOT(setNetworkActive(bool)));
|
||||||
|
|
||||||
updateTrafficStats(model->getTotalBytesRecv(), model->getTotalBytesSent());
|
updateTrafficStats(node.getTotalBytesRecv(), node.getTotalBytesSent());
|
||||||
connect(model, SIGNAL(bytesChanged(quint64,quint64)), this, SLOT(updateTrafficStats(quint64, quint64)));
|
connect(model, SIGNAL(bytesChanged(quint64,quint64)), this, SLOT(updateTrafficStats(quint64, quint64)));
|
||||||
|
|
||||||
connect(model, SIGNAL(mempoolSizeChanged(long,size_t)), this, SLOT(setMempoolSize(long,size_t)));
|
connect(model, SIGNAL(mempoolSizeChanged(long,size_t)), this, SLOT(setMempoolSize(long,size_t)));
|
||||||
|
@ -667,7 +677,7 @@ void RPCConsole::setClientModel(ClientModel *model)
|
||||||
|
|
||||||
//Setup autocomplete and attach it
|
//Setup autocomplete and attach it
|
||||||
QStringList wordList;
|
QStringList wordList;
|
||||||
std::vector<std::string> commandList = tableRPC.listCommands();
|
std::vector<std::string> commandList = m_node.listRpcCommands();
|
||||||
for (size_t i = 0; i < commandList.size(); ++i)
|
for (size_t i = 0; i < commandList.size(); ++i)
|
||||||
{
|
{
|
||||||
wordList << commandList[i].c_str();
|
wordList << commandList[i].c_str();
|
||||||
|
@ -835,7 +845,7 @@ void RPCConsole::updateNetworkState()
|
||||||
connections += tr("In:") + " " + QString::number(clientModel->getNumConnections(CONNECTIONS_IN)) + " / ";
|
connections += tr("In:") + " " + QString::number(clientModel->getNumConnections(CONNECTIONS_IN)) + " / ";
|
||||||
connections += tr("Out:") + " " + QString::number(clientModel->getNumConnections(CONNECTIONS_OUT)) + ")";
|
connections += tr("Out:") + " " + QString::number(clientModel->getNumConnections(CONNECTIONS_OUT)) + ")";
|
||||||
|
|
||||||
if(!clientModel->getNetworkActive()) {
|
if(!clientModel->node().getNetworkActive()) {
|
||||||
connections += " (" + tr("Network activity disabled") + ")";
|
connections += " (" + tr("Network activity disabled") + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -882,7 +892,7 @@ void RPCConsole::on_lineEdit_returnPressed()
|
||||||
std::string strFilteredCmd;
|
std::string strFilteredCmd;
|
||||||
try {
|
try {
|
||||||
std::string dummy;
|
std::string dummy;
|
||||||
if (!RPCParseCommandLine(dummy, cmd.toStdString(), false, &strFilteredCmd)) {
|
if (!RPCParseCommandLine(nullptr, dummy, cmd.toStdString(), false, &strFilteredCmd)) {
|
||||||
// Failed to parse command, so we cannot even filter it for the history
|
// Failed to parse command, so we cannot even filter it for the history
|
||||||
throw std::runtime_error("Invalid command line");
|
throw std::runtime_error("Invalid command line");
|
||||||
}
|
}
|
||||||
|
@ -955,7 +965,7 @@ void RPCConsole::browseHistory(int offset)
|
||||||
|
|
||||||
void RPCConsole::startExecutor()
|
void RPCConsole::startExecutor()
|
||||||
{
|
{
|
||||||
RPCExecutor *executor = new RPCExecutor();
|
RPCExecutor *executor = new RPCExecutor(m_node);
|
||||||
executor->moveToThread(&thread);
|
executor->moveToThread(&thread);
|
||||||
|
|
||||||
// Replies from executor object must go to this object
|
// Replies from executor object must go to this object
|
||||||
|
@ -1181,9 +1191,6 @@ void RPCConsole::showBanTableContextMenu(const QPoint& point)
|
||||||
|
|
||||||
void RPCConsole::disconnectSelectedNode()
|
void RPCConsole::disconnectSelectedNode()
|
||||||
{
|
{
|
||||||
if(!g_connman)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Get selected peer addresses
|
// Get selected peer addresses
|
||||||
QList<QModelIndex> nodes = GUIUtil::getEntryData(ui->peerWidget, PeerTableModel::NetNodeId);
|
QList<QModelIndex> nodes = GUIUtil::getEntryData(ui->peerWidget, PeerTableModel::NetNodeId);
|
||||||
for(int i = 0; i < nodes.count(); i++)
|
for(int i = 0; i < nodes.count(); i++)
|
||||||
|
@ -1191,14 +1198,14 @@ void RPCConsole::disconnectSelectedNode()
|
||||||
// Get currently selected peer address
|
// Get currently selected peer address
|
||||||
NodeId id = nodes.at(i).data().toLongLong();
|
NodeId id = nodes.at(i).data().toLongLong();
|
||||||
// Find the node, disconnect it and clear the selected node
|
// Find the node, disconnect it and clear the selected node
|
||||||
if(g_connman->DisconnectNode(id))
|
if(m_node.disconnect(id))
|
||||||
clearSelectedNode();
|
clearSelectedNode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RPCConsole::banSelectedNode(int bantime)
|
void RPCConsole::banSelectedNode(int bantime)
|
||||||
{
|
{
|
||||||
if (!clientModel || !g_connman)
|
if (!clientModel)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Get selected peer addresses
|
// Get selected peer addresses
|
||||||
|
@ -1216,7 +1223,7 @@ void RPCConsole::banSelectedNode(int bantime)
|
||||||
// Find possible nodes, ban it and clear the selected node
|
// Find possible nodes, ban it and clear the selected node
|
||||||
const CNodeCombinedStats *stats = clientModel->getPeerTableModel()->getNodeStats(detailNodeRow);
|
const CNodeCombinedStats *stats = clientModel->getPeerTableModel()->getNodeStats(detailNodeRow);
|
||||||
if(stats) {
|
if(stats) {
|
||||||
g_connman->Ban(stats->nodeStats.addr, BanReasonManuallyAdded, bantime);
|
m_node.ban(stats->nodeStats.addr, BanReasonManuallyAdded, bantime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
clearSelectedNode();
|
clearSelectedNode();
|
||||||
|
@ -1237,9 +1244,8 @@ void RPCConsole::unbanSelectedNode()
|
||||||
CSubNet possibleSubnet;
|
CSubNet possibleSubnet;
|
||||||
|
|
||||||
LookupSubNet(strNode.toStdString().c_str(), possibleSubnet);
|
LookupSubNet(strNode.toStdString().c_str(), possibleSubnet);
|
||||||
if (possibleSubnet.IsValid() && g_connman)
|
if (possibleSubnet.IsValid() && m_node.unban(possibleSubnet))
|
||||||
{
|
{
|
||||||
g_connman->Unban(possibleSubnet);
|
|
||||||
clientModel->getBanTableModel()->refresh();
|
clientModel->getBanTableModel()->refresh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,10 @@ class PlatformStyle;
|
||||||
class RPCTimerInterface;
|
class RPCTimerInterface;
|
||||||
class WalletModel;
|
class WalletModel;
|
||||||
|
|
||||||
|
namespace interface {
|
||||||
|
class Node;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class RPCConsole;
|
class RPCConsole;
|
||||||
}
|
}
|
||||||
|
@ -34,12 +38,12 @@ class RPCConsole: public QWidget
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit RPCConsole(const PlatformStyle *platformStyle, QWidget *parent);
|
explicit RPCConsole(interface::Node& node, const PlatformStyle *platformStyle, QWidget *parent);
|
||||||
~RPCConsole();
|
~RPCConsole();
|
||||||
|
|
||||||
static bool RPCParseCommandLine(std::string &strResult, const std::string &strCommand, bool fExecute, std::string * const pstrFilteredOut = nullptr, const std::string *walletID = nullptr);
|
static bool RPCParseCommandLine(interface::Node* node, std::string &strResult, const std::string &strCommand, bool fExecute, std::string * const pstrFilteredOut = nullptr, const std::string *walletID = nullptr);
|
||||||
static bool RPCExecuteCommandLine(std::string &strResult, const std::string &strCommand, std::string * const pstrFilteredOut = nullptr, const std::string *walletID = nullptr) {
|
static bool RPCExecuteCommandLine(interface::Node& node, std::string &strResult, const std::string &strCommand, std::string * const pstrFilteredOut = nullptr, const std::string *walletID = nullptr) {
|
||||||
return RPCParseCommandLine(strResult, strCommand, true, pstrFilteredOut, walletID);
|
return RPCParseCommandLine(&node, strResult, strCommand, true, pstrFilteredOut, walletID);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setClientModel(ClientModel *model);
|
void setClientModel(ClientModel *model);
|
||||||
|
@ -140,6 +144,7 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
interface::Node& m_node;
|
||||||
Ui::RPCConsole *ui;
|
Ui::RPCConsole *ui;
|
||||||
ClientModel *clientModel;
|
ClientModel *clientModel;
|
||||||
QStringList history;
|
QStringList history;
|
||||||
|
|
|
@ -15,9 +15,9 @@
|
||||||
#include <qt/sendcoinsentry.h>
|
#include <qt/sendcoinsentry.h>
|
||||||
|
|
||||||
#include <chainparams.h>
|
#include <chainparams.h>
|
||||||
|
#include <interface/node.h>
|
||||||
#include <key_io.h>
|
#include <key_io.h>
|
||||||
#include <wallet/coincontrol.h>
|
#include <wallet/coincontrol.h>
|
||||||
#include <validation.h> // mempool and minRelayTxFee
|
|
||||||
#include <ui_interface.h>
|
#include <ui_interface.h>
|
||||||
#include <txmempool.h>
|
#include <txmempool.h>
|
||||||
#include <policy/fees.h>
|
#include <policy/fees.h>
|
||||||
|
@ -149,9 +149,9 @@ void SendCoinsDialog::setModel(WalletModel *_model)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setBalance(_model->getBalance(), _model->getUnconfirmedBalance(), _model->getImmatureBalance(),
|
interface::WalletBalances balances = _model->wallet().getBalances();
|
||||||
_model->getWatchBalance(), _model->getWatchUnconfirmedBalance(), _model->getWatchImmatureBalance());
|
setBalance(balances);
|
||||||
connect(_model, SIGNAL(balanceChanged(CAmount,CAmount,CAmount,CAmount,CAmount,CAmount)), this, SLOT(setBalance(CAmount,CAmount,CAmount,CAmount,CAmount,CAmount)));
|
connect(_model, SIGNAL(balanceChanged(interface::WalletBalances)), this, SLOT(setBalance(interface::WalletBalances)));
|
||||||
connect(_model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
|
connect(_model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
|
||||||
updateDisplayUnit();
|
updateDisplayUnit();
|
||||||
|
|
||||||
|
@ -175,7 +175,7 @@ void SendCoinsDialog::setModel(WalletModel *_model)
|
||||||
connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(coinControlUpdateLabels()));
|
connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(coinControlUpdateLabels()));
|
||||||
connect(ui->optInRBF, SIGNAL(stateChanged(int)), this, SLOT(updateSmartFeeLabel()));
|
connect(ui->optInRBF, SIGNAL(stateChanged(int)), this, SLOT(updateSmartFeeLabel()));
|
||||||
connect(ui->optInRBF, SIGNAL(stateChanged(int)), this, SLOT(coinControlUpdateLabels()));
|
connect(ui->optInRBF, SIGNAL(stateChanged(int)), this, SLOT(coinControlUpdateLabels()));
|
||||||
ui->customFee->setSingleStep(GetRequiredFee(1000));
|
ui->customFee->setSingleStep(model->node().getRequiredFee(1000));
|
||||||
updateFeeSectionControls();
|
updateFeeSectionControls();
|
||||||
updateMinFeeLabel();
|
updateMinFeeLabel();
|
||||||
updateSmartFeeLabel();
|
updateSmartFeeLabel();
|
||||||
|
@ -193,7 +193,7 @@ void SendCoinsDialog::setModel(WalletModel *_model)
|
||||||
settings.remove("nSmartFeeSliderPosition");
|
settings.remove("nSmartFeeSliderPosition");
|
||||||
}
|
}
|
||||||
if (settings.value("nConfTarget").toInt() == 0)
|
if (settings.value("nConfTarget").toInt() == 0)
|
||||||
ui->confTargetSelector->setCurrentIndex(getIndexForConfTarget(model->getDefaultConfirmTarget()));
|
ui->confTargetSelector->setCurrentIndex(getIndexForConfTarget(model->node().getTxConfirmTarget()));
|
||||||
else
|
else
|
||||||
ui->confTargetSelector->setCurrentIndex(getIndexForConfTarget(settings.value("nConfTarget").toInt()));
|
ui->confTargetSelector->setCurrentIndex(getIndexForConfTarget(settings.value("nConfTarget").toInt()));
|
||||||
}
|
}
|
||||||
|
@ -224,7 +224,7 @@ void SendCoinsDialog::on_sendButton_clicked()
|
||||||
SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());
|
SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());
|
||||||
if(entry)
|
if(entry)
|
||||||
{
|
{
|
||||||
if(entry->validate())
|
if(entry->validate(model->node()))
|
||||||
{
|
{
|
||||||
recipients.append(entry->getValue());
|
recipients.append(entry->getValue());
|
||||||
}
|
}
|
||||||
|
@ -372,7 +372,7 @@ void SendCoinsDialog::on_sendButton_clicked()
|
||||||
accept();
|
accept();
|
||||||
CoinControlDialog::coinControl()->UnSelectAll();
|
CoinControlDialog::coinControl()->UnSelectAll();
|
||||||
coinControlUpdateLabels();
|
coinControlUpdateLabels();
|
||||||
Q_EMIT coinsSent(currentTransaction.getTransaction()->GetHash());
|
Q_EMIT coinsSent(currentTransaction.getWtx()->get().GetHash());
|
||||||
}
|
}
|
||||||
fNewRecipientAllowed = true;
|
fNewRecipientAllowed = true;
|
||||||
}
|
}
|
||||||
|
@ -515,24 +515,17 @@ bool SendCoinsDialog::handlePaymentRequest(const SendCoinsRecipient &rv)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SendCoinsDialog::setBalance(const CAmount& balance, const CAmount& unconfirmedBalance, const CAmount& immatureBalance,
|
void SendCoinsDialog::setBalance(const interface::WalletBalances& balances)
|
||||||
const CAmount& watchBalance, const CAmount& watchUnconfirmedBalance, const CAmount& watchImmatureBalance)
|
|
||||||
{
|
{
|
||||||
Q_UNUSED(unconfirmedBalance);
|
|
||||||
Q_UNUSED(immatureBalance);
|
|
||||||
Q_UNUSED(watchBalance);
|
|
||||||
Q_UNUSED(watchUnconfirmedBalance);
|
|
||||||
Q_UNUSED(watchImmatureBalance);
|
|
||||||
|
|
||||||
if(model && model->getOptionsModel())
|
if(model && model->getOptionsModel())
|
||||||
{
|
{
|
||||||
ui->labelBalance->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), balance));
|
ui->labelBalance->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), balances.balance));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SendCoinsDialog::updateDisplayUnit()
|
void SendCoinsDialog::updateDisplayUnit()
|
||||||
{
|
{
|
||||||
setBalance(model->getBalance(), 0, 0, 0, 0, 0);
|
setBalance(model->wallet().getBalances());
|
||||||
ui->customFee->setDisplayUnit(model->getOptionsModel()->getDisplayUnit());
|
ui->customFee->setDisplayUnit(model->getOptionsModel()->getDisplayUnit());
|
||||||
updateMinFeeLabel();
|
updateMinFeeLabel();
|
||||||
updateSmartFeeLabel();
|
updateSmartFeeLabel();
|
||||||
|
@ -573,7 +566,7 @@ void SendCoinsDialog::processSendCoinsReturn(const WalletModel::SendCoinsReturn
|
||||||
msgParams.second = CClientUIInterface::MSG_ERROR;
|
msgParams.second = CClientUIInterface::MSG_ERROR;
|
||||||
break;
|
break;
|
||||||
case WalletModel::AbsurdFee:
|
case WalletModel::AbsurdFee:
|
||||||
msgParams.first = tr("A fee higher than %1 is considered an absurdly high fee.").arg(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), maxTxFee));
|
msgParams.first = tr("A fee higher than %1 is considered an absurdly high fee.").arg(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), model->node().getMaxTxFee()));
|
||||||
break;
|
break;
|
||||||
case WalletModel::PaymentRequestExpired:
|
case WalletModel::PaymentRequestExpired:
|
||||||
msgParams.first = tr("Payment request expired.");
|
msgParams.first = tr("Payment request expired.");
|
||||||
|
@ -618,7 +611,7 @@ void SendCoinsDialog::useAvailableBalance(SendCoinsEntry* entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate available amount to send.
|
// Calculate available amount to send.
|
||||||
CAmount amount = model->getBalance(&coin_control);
|
CAmount amount = model->wallet().getAvailableBalance(coin_control);
|
||||||
for (int i = 0; i < ui->entries->count(); ++i) {
|
for (int i = 0; i < ui->entries->count(); ++i) {
|
||||||
SendCoinsEntry* e = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());
|
SendCoinsEntry* e = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());
|
||||||
if (e && !e->isHidden() && e != entry) {
|
if (e && !e->isHidden() && e != entry) {
|
||||||
|
@ -636,7 +629,7 @@ void SendCoinsDialog::useAvailableBalance(SendCoinsEntry* entry)
|
||||||
|
|
||||||
void SendCoinsDialog::setMinimumFee()
|
void SendCoinsDialog::setMinimumFee()
|
||||||
{
|
{
|
||||||
ui->customFee->setValue(GetRequiredFee(1000));
|
ui->customFee->setValue(model->node().getRequiredFee(1000));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SendCoinsDialog::updateFeeSectionControls()
|
void SendCoinsDialog::updateFeeSectionControls()
|
||||||
|
@ -668,7 +661,7 @@ void SendCoinsDialog::updateMinFeeLabel()
|
||||||
{
|
{
|
||||||
if (model && model->getOptionsModel())
|
if (model && model->getOptionsModel())
|
||||||
ui->checkBoxMinimumFee->setText(tr("Pay only the required fee of %1").arg(
|
ui->checkBoxMinimumFee->setText(tr("Pay only the required fee of %1").arg(
|
||||||
BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), GetRequiredFee(1000)) + "/kB")
|
BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), model->node().getRequiredFee(1000)) + "/kB")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -692,12 +685,13 @@ void SendCoinsDialog::updateSmartFeeLabel()
|
||||||
CCoinControl coin_control;
|
CCoinControl coin_control;
|
||||||
updateCoinControlState(coin_control);
|
updateCoinControlState(coin_control);
|
||||||
coin_control.m_feerate.reset(); // Explicitly use only fee estimation rate for smart fee labels
|
coin_control.m_feerate.reset(); // Explicitly use only fee estimation rate for smart fee labels
|
||||||
FeeCalculation feeCalc;
|
int returned_target;
|
||||||
CFeeRate feeRate = CFeeRate(GetMinimumFee(1000, coin_control, ::mempool, ::feeEstimator, &feeCalc));
|
FeeReason reason;
|
||||||
|
CFeeRate feeRate = CFeeRate(model->node().getMinimumFee(1000, coin_control, &returned_target, &reason));
|
||||||
|
|
||||||
ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), feeRate.GetFeePerK()) + "/kB");
|
ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), feeRate.GetFeePerK()) + "/kB");
|
||||||
|
|
||||||
if (feeCalc.reason == FeeReason::FALLBACK) {
|
if (reason == FeeReason::FALLBACK) {
|
||||||
ui->labelSmartFee2->show(); // (Smart fee not initialized yet. This usually takes a few blocks...)
|
ui->labelSmartFee2->show(); // (Smart fee not initialized yet. This usually takes a few blocks...)
|
||||||
ui->labelFeeEstimation->setText("");
|
ui->labelFeeEstimation->setText("");
|
||||||
ui->fallbackFeeWarningLabel->setVisible(true);
|
ui->fallbackFeeWarningLabel->setVisible(true);
|
||||||
|
@ -709,7 +703,7 @@ void SendCoinsDialog::updateSmartFeeLabel()
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ui->labelSmartFee2->hide();
|
ui->labelSmartFee2->hide();
|
||||||
ui->labelFeeEstimation->setText(tr("Estimated to begin confirmation within %n block(s).", "", feeCalc.returnedTarget));
|
ui->labelFeeEstimation->setText(tr("Estimated to begin confirmation within %n block(s).", "", returned_target));
|
||||||
ui->fallbackFeeWarningLabel->setVisible(false);
|
ui->fallbackFeeWarningLabel->setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -814,7 +808,7 @@ void SendCoinsDialog::coinControlChangeEdited(const QString& text)
|
||||||
}
|
}
|
||||||
else // Valid address
|
else // Valid address
|
||||||
{
|
{
|
||||||
if (!model->IsSpendable(dest)) {
|
if (!model->wallet().isSpendable(dest)) {
|
||||||
ui->labelCoinControlChangeLabel->setText(tr("Warning: Unknown change address"));
|
ui->labelCoinControlChangeLabel->setText(tr("Warning: Unknown change address"));
|
||||||
|
|
||||||
// confirmation dialog
|
// confirmation dialog
|
||||||
|
|
|
@ -51,8 +51,7 @@ public Q_SLOTS:
|
||||||
void accept();
|
void accept();
|
||||||
SendCoinsEntry *addEntry();
|
SendCoinsEntry *addEntry();
|
||||||
void updateTabsAndLabels();
|
void updateTabsAndLabels();
|
||||||
void setBalance(const CAmount& balance, const CAmount& unconfirmedBalance, const CAmount& immatureBalance,
|
void setBalance(const interface::WalletBalances& balances);
|
||||||
const CAmount& watchOnlyBalance, const CAmount& watchUnconfBalance, const CAmount& watchImmatureBalance);
|
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void coinsSent(const uint256& txid);
|
void coinsSent(const uint256& txid);
|
||||||
|
|
|
@ -127,7 +127,7 @@ void SendCoinsEntry::useAvailableBalanceClicked()
|
||||||
Q_EMIT useAvailableBalance(this);
|
Q_EMIT useAvailableBalance(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SendCoinsEntry::validate()
|
bool SendCoinsEntry::validate(interface::Node& node)
|
||||||
{
|
{
|
||||||
if (!model)
|
if (!model)
|
||||||
return false;
|
return false;
|
||||||
|
@ -158,7 +158,7 @@ bool SendCoinsEntry::validate()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reject dust outputs:
|
// Reject dust outputs:
|
||||||
if (retval && GUIUtil::isDust(ui->payTo->text(), ui->payAmount->value())) {
|
if (retval && GUIUtil::isDust(node, ui->payTo->text(), ui->payAmount->value())) {
|
||||||
ui->payAmount->setValid(false);
|
ui->payAmount->setValid(false);
|
||||||
retval = false;
|
retval = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ public:
|
||||||
~SendCoinsEntry();
|
~SendCoinsEntry();
|
||||||
|
|
||||||
void setModel(WalletModel *model);
|
void setModel(WalletModel *model);
|
||||||
bool validate();
|
bool validate(interface::Node& node);
|
||||||
SendCoinsRecipient getValue();
|
SendCoinsRecipient getValue();
|
||||||
|
|
||||||
/** Return whether the entry is still empty and unedited */
|
/** Return whether the entry is still empty and unedited */
|
||||||
|
|
|
@ -140,7 +140,7 @@ void SignVerifyMessageDialog::on_signMessageButton_SM_clicked()
|
||||||
}
|
}
|
||||||
|
|
||||||
CKey key;
|
CKey key;
|
||||||
if (!model->getPrivKey(*keyID, key))
|
if (!model->wallet().getPrivKey(*keyID, key))
|
||||||
{
|
{
|
||||||
ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }");
|
ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }");
|
||||||
ui->statusLabel_SM->setText(tr("Private key for the entered address is not available."));
|
ui->statusLabel_SM->setText(tr("Private key for the entered address is not available."));
|
||||||
|
|
|
@ -12,22 +12,21 @@
|
||||||
|
|
||||||
#include <clientversion.h>
|
#include <clientversion.h>
|
||||||
#include <init.h>
|
#include <init.h>
|
||||||
|
#include <interface/handler.h>
|
||||||
|
#include <interface/node.h>
|
||||||
|
#include <interface/wallet.h>
|
||||||
#include <util.h>
|
#include <util.h>
|
||||||
#include <ui_interface.h>
|
#include <ui_interface.h>
|
||||||
#include <version.h>
|
#include <version.h>
|
||||||
|
|
||||||
#ifdef ENABLE_WALLET
|
|
||||||
#include <wallet/wallet.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QCloseEvent>
|
#include <QCloseEvent>
|
||||||
#include <QDesktopWidget>
|
#include <QDesktopWidget>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QRadialGradient>
|
#include <QRadialGradient>
|
||||||
|
|
||||||
SplashScreen::SplashScreen(Qt::WindowFlags f, const NetworkStyle *networkStyle) :
|
SplashScreen::SplashScreen(interface::Node& node, Qt::WindowFlags f, const NetworkStyle *networkStyle) :
|
||||||
QWidget(0, f), curAlignment(0)
|
QWidget(0, f), curAlignment(0), m_node(node)
|
||||||
{
|
{
|
||||||
// set reference point, paddings
|
// set reference point, paddings
|
||||||
int paddingRight = 50;
|
int paddingRight = 50;
|
||||||
|
@ -143,7 +142,7 @@ bool SplashScreen::eventFilter(QObject * obj, QEvent * ev) {
|
||||||
if (ev->type() == QEvent::KeyPress) {
|
if (ev->type() == QEvent::KeyPress) {
|
||||||
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(ev);
|
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(ev);
|
||||||
if(keyEvent->text()[0] == 'q') {
|
if(keyEvent->text()[0] == 'q') {
|
||||||
StartShutdown();
|
m_node.startShutdown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return QObject::eventFilter(obj, ev);
|
return QObject::eventFilter(obj, ev);
|
||||||
|
@ -177,35 +176,34 @@ static void ShowProgress(SplashScreen *splash, const std::string &title, int nPr
|
||||||
: _("press q to shutdown")) +
|
: _("press q to shutdown")) +
|
||||||
strprintf("\n%d", nProgress) + "%");
|
strprintf("\n%d", nProgress) + "%");
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_WALLET
|
#ifdef ENABLE_WALLET
|
||||||
void SplashScreen::ConnectWallet(CWallet* wallet)
|
void SplashScreen::ConnectWallet(std::unique_ptr<interface::Wallet> wallet)
|
||||||
{
|
{
|
||||||
wallet->ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2, false));
|
m_connected_wallet_handlers.emplace_back(wallet->handleShowProgress(boost::bind(ShowProgress, this, _1, _2, false)));
|
||||||
connectedWallets.push_back(wallet);
|
m_connected_wallets.emplace_back(std::move(wallet));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void SplashScreen::subscribeToCoreSignals()
|
void SplashScreen::subscribeToCoreSignals()
|
||||||
{
|
{
|
||||||
// Connect signals to client
|
// Connect signals to client
|
||||||
uiInterface.InitMessage.connect(boost::bind(InitMessage, this, _1));
|
m_handler_init_message = m_node.handleInitMessage(boost::bind(InitMessage, this, _1));
|
||||||
uiInterface.ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2, _3));
|
m_handler_show_progress = m_node.handleShowProgress(boost::bind(ShowProgress, this, _1, _2, _3));
|
||||||
#ifdef ENABLE_WALLET
|
#ifdef ENABLE_WALLET
|
||||||
uiInterface.LoadWallet.connect(boost::bind(&SplashScreen::ConnectWallet, this, _1));
|
m_handler_load_wallet = m_node.handleLoadWallet([this](std::unique_ptr<interface::Wallet> wallet) { ConnectWallet(std::move(wallet)); });
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void SplashScreen::unsubscribeFromCoreSignals()
|
void SplashScreen::unsubscribeFromCoreSignals()
|
||||||
{
|
{
|
||||||
// Disconnect signals from client
|
// Disconnect signals from client
|
||||||
uiInterface.InitMessage.disconnect(boost::bind(InitMessage, this, _1));
|
m_handler_init_message->disconnect();
|
||||||
uiInterface.ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2, _3));
|
m_handler_show_progress->disconnect();
|
||||||
#ifdef ENABLE_WALLET
|
for (auto& handler : m_connected_wallet_handlers) {
|
||||||
for (CWallet* const & pwallet : connectedWallets) {
|
handler->disconnect();
|
||||||
pwallet->ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2, false));
|
|
||||||
}
|
}
|
||||||
#endif
|
m_connected_wallet_handlers.clear();
|
||||||
|
m_connected_wallets.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SplashScreen::showMessage(const QString &message, int alignment, const QColor &color)
|
void SplashScreen::showMessage(const QString &message, int alignment, const QColor &color)
|
||||||
|
@ -227,6 +225,6 @@ void SplashScreen::paintEvent(QPaintEvent *event)
|
||||||
|
|
||||||
void SplashScreen::closeEvent(QCloseEvent *event)
|
void SplashScreen::closeEvent(QCloseEvent *event)
|
||||||
{
|
{
|
||||||
StartShutdown(); // allows an "emergency" shutdown during startup
|
m_node.startShutdown(); // allows an "emergency" shutdown during startup
|
||||||
event->ignore();
|
event->ignore();
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,9 +8,16 @@
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <QSplashScreen>
|
#include <QSplashScreen>
|
||||||
|
|
||||||
class CWallet;
|
#include <memory>
|
||||||
|
|
||||||
class NetworkStyle;
|
class NetworkStyle;
|
||||||
|
|
||||||
|
namespace interface {
|
||||||
|
class Handler;
|
||||||
|
class Node;
|
||||||
|
class Wallet;
|
||||||
|
};
|
||||||
|
|
||||||
/** Class for the splashscreen with information of the running client.
|
/** Class for the splashscreen with information of the running client.
|
||||||
*
|
*
|
||||||
* @note this is intentionally not a QSplashScreen. Bitcoin Core initialization
|
* @note this is intentionally not a QSplashScreen. Bitcoin Core initialization
|
||||||
|
@ -22,7 +29,7 @@ class SplashScreen : public QWidget
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit SplashScreen(Qt::WindowFlags f, const NetworkStyle *networkStyle);
|
explicit SplashScreen(interface::Node& node, Qt::WindowFlags f, const NetworkStyle *networkStyle);
|
||||||
~SplashScreen();
|
~SplashScreen();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -45,14 +52,19 @@ private:
|
||||||
/** Disconnect core signals to splash screen */
|
/** Disconnect core signals to splash screen */
|
||||||
void unsubscribeFromCoreSignals();
|
void unsubscribeFromCoreSignals();
|
||||||
/** Connect wallet signals to splash screen */
|
/** Connect wallet signals to splash screen */
|
||||||
void ConnectWallet(CWallet*);
|
void ConnectWallet(std::unique_ptr<interface::Wallet> wallet);
|
||||||
|
|
||||||
QPixmap pixmap;
|
QPixmap pixmap;
|
||||||
QString curMessage;
|
QString curMessage;
|
||||||
QColor curColor;
|
QColor curColor;
|
||||||
int curAlignment;
|
int curAlignment;
|
||||||
|
|
||||||
QList<CWallet*> connectedWallets;
|
interface::Node& m_node;
|
||||||
|
std::unique_ptr<interface::Handler> m_handler_init_message;
|
||||||
|
std::unique_ptr<interface::Handler> m_handler_show_progress;
|
||||||
|
std::unique_ptr<interface::Handler> m_handler_load_wallet;
|
||||||
|
std::list<std::unique_ptr<interface::Wallet>> m_connected_wallets;
|
||||||
|
std::list<std::unique_ptr<interface::Handler>> m_connected_wallet_handlers;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // BITCOIN_QT_SPLASHSCREEN_H
|
#endif // BITCOIN_QT_SPLASHSCREEN_H
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#include <amount.h>
|
#include <amount.h>
|
||||||
#include <chainparams.h>
|
#include <chainparams.h>
|
||||||
|
#include <interface/node.h>
|
||||||
#include <random.h>
|
#include <random.h>
|
||||||
#include <script/script.h>
|
#include <script/script.h>
|
||||||
#include <script/standard.h>
|
#include <script/standard.h>
|
||||||
|
@ -66,7 +67,8 @@ static SendCoinsRecipient handleRequest(PaymentServer* server, std::vector<unsig
|
||||||
void PaymentServerTests::paymentServerTests()
|
void PaymentServerTests::paymentServerTests()
|
||||||
{
|
{
|
||||||
SelectParams(CBaseChainParams::MAIN);
|
SelectParams(CBaseChainParams::MAIN);
|
||||||
OptionsModel optionsModel;
|
auto node = interface::MakeNode();
|
||||||
|
OptionsModel optionsModel(*node);
|
||||||
PaymentServer* server = new PaymentServer(nullptr, false);
|
PaymentServer* server = new PaymentServer(nullptr, false);
|
||||||
X509_STORE* caStore = X509_STORE_new();
|
X509_STORE* caStore = X509_STORE_new();
|
||||||
X509_STORE_add_cert(caStore, parse_b64der_cert(caCert1_BASE64));
|
X509_STORE_add_cert(caStore, parse_b64der_cert(caCert1_BASE64));
|
||||||
|
@ -145,7 +147,7 @@ void PaymentServerTests::paymentServerTests()
|
||||||
// Ensure the request is initialized, because network "main" is default, even for
|
// Ensure the request is initialized, because network "main" is default, even for
|
||||||
// uninitialized payment requests and that will fail our test here.
|
// uninitialized payment requests and that will fail our test here.
|
||||||
QVERIFY(r.paymentRequest.IsInitialized());
|
QVERIFY(r.paymentRequest.IsInitialized());
|
||||||
QCOMPARE(PaymentServer::verifyNetwork(r.paymentRequest.getDetails()), false);
|
QCOMPARE(PaymentServer::verifyNetwork(*node, r.paymentRequest.getDetails()), false);
|
||||||
|
|
||||||
// Expired payment request (expires is set to 1 = 1970-01-01 00:00:01):
|
// Expired payment request (expires is set to 1 = 1970-01-01 00:00:01):
|
||||||
data = DecodeBase64(paymentrequest2_cert2_BASE64);
|
data = DecodeBase64(paymentrequest2_cert2_BASE64);
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <chainparams.h>
|
#include <chainparams.h>
|
||||||
#include <consensus/validation.h>
|
#include <consensus/validation.h>
|
||||||
#include <fs.h>
|
#include <fs.h>
|
||||||
|
#include <interface/node.h>
|
||||||
#include <validation.h>
|
#include <validation.h>
|
||||||
#include <rpc/register.h>
|
#include <rpc/register.h>
|
||||||
#include <rpc/server.h>
|
#include <rpc/server.h>
|
||||||
|
@ -45,89 +46,90 @@ void RPCNestedTests::rpcNestedTests()
|
||||||
std::string result;
|
std::string result;
|
||||||
std::string result2;
|
std::string result2;
|
||||||
std::string filtered;
|
std::string filtered;
|
||||||
RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo()[chain]", &filtered); //simple result filtering with path
|
auto node = interface::MakeNode();
|
||||||
|
RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo()[chain]", &filtered); //simple result filtering with path
|
||||||
QVERIFY(result=="main");
|
QVERIFY(result=="main");
|
||||||
QVERIFY(filtered == "getblockchaininfo()[chain]");
|
QVERIFY(filtered == "getblockchaininfo()[chain]");
|
||||||
|
|
||||||
RPCConsole::RPCExecuteCommandLine(result, "getblock(getbestblockhash())"); //simple 2 level nesting
|
RPCConsole::RPCExecuteCommandLine(*node, result, "getblock(getbestblockhash())"); //simple 2 level nesting
|
||||||
RPCConsole::RPCExecuteCommandLine(result, "getblock(getblock(getbestblockhash())[hash], true)");
|
RPCConsole::RPCExecuteCommandLine(*node, result, "getblock(getblock(getbestblockhash())[hash], true)");
|
||||||
|
|
||||||
RPCConsole::RPCExecuteCommandLine(result, "getblock( getblock( getblock(getbestblockhash())[hash] )[hash], true)"); //4 level nesting with whitespace, filtering path and boolean parameter
|
RPCConsole::RPCExecuteCommandLine(*node, result, "getblock( getblock( getblock(getbestblockhash())[hash] )[hash], true)"); //4 level nesting with whitespace, filtering path and boolean parameter
|
||||||
|
|
||||||
RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo");
|
RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo");
|
||||||
QVERIFY(result.substr(0,1) == "{");
|
QVERIFY(result.substr(0,1) == "{");
|
||||||
|
|
||||||
RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo()");
|
RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo()");
|
||||||
QVERIFY(result.substr(0,1) == "{");
|
QVERIFY(result.substr(0,1) == "{");
|
||||||
|
|
||||||
RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo "); //whitespace at the end will be tolerated
|
RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo "); //whitespace at the end will be tolerated
|
||||||
QVERIFY(result.substr(0,1) == "{");
|
QVERIFY(result.substr(0,1) == "{");
|
||||||
|
|
||||||
(RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo()[\"chain\"]")); //Quote path identifier are allowed, but look after a child containing the quotes in the key
|
(RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo()[\"chain\"]")); //Quote path identifier are allowed, but look after a child containing the quotes in the key
|
||||||
QVERIFY(result == "null");
|
QVERIFY(result == "null");
|
||||||
|
|
||||||
(RPCConsole::RPCExecuteCommandLine(result, "createrawtransaction [] {} 0")); //parameter not in brackets are allowed
|
(RPCConsole::RPCExecuteCommandLine(*node, result, "createrawtransaction [] {} 0")); //parameter not in brackets are allowed
|
||||||
(RPCConsole::RPCExecuteCommandLine(result2, "createrawtransaction([],{},0)")); //parameter in brackets are allowed
|
(RPCConsole::RPCExecuteCommandLine(*node, result2, "createrawtransaction([],{},0)")); //parameter in brackets are allowed
|
||||||
QVERIFY(result == result2);
|
QVERIFY(result == result2);
|
||||||
(RPCConsole::RPCExecuteCommandLine(result2, "createrawtransaction( [], {} , 0 )")); //whitespace between parameters is allowed
|
(RPCConsole::RPCExecuteCommandLine(*node, result2, "createrawtransaction( [], {} , 0 )")); //whitespace between parameters is allowed
|
||||||
QVERIFY(result == result2);
|
QVERIFY(result == result2);
|
||||||
|
|
||||||
RPCConsole::RPCExecuteCommandLine(result, "getblock(getbestblockhash())[tx][0]", &filtered);
|
RPCConsole::RPCExecuteCommandLine(*node, result, "getblock(getbestblockhash())[tx][0]", &filtered);
|
||||||
QVERIFY(result == "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b");
|
QVERIFY(result == "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b");
|
||||||
QVERIFY(filtered == "getblock(getbestblockhash())[tx][0]");
|
QVERIFY(filtered == "getblock(getbestblockhash())[tx][0]");
|
||||||
|
|
||||||
RPCConsole::RPCParseCommandLine(result, "importprivkey", false, &filtered);
|
RPCConsole::RPCParseCommandLine(nullptr, result, "importprivkey", false, &filtered);
|
||||||
QVERIFY(filtered == "importprivkey(…)");
|
QVERIFY(filtered == "importprivkey(…)");
|
||||||
RPCConsole::RPCParseCommandLine(result, "signmessagewithprivkey abc", false, &filtered);
|
RPCConsole::RPCParseCommandLine(nullptr, result, "signmessagewithprivkey abc", false, &filtered);
|
||||||
QVERIFY(filtered == "signmessagewithprivkey(…)");
|
QVERIFY(filtered == "signmessagewithprivkey(…)");
|
||||||
RPCConsole::RPCParseCommandLine(result, "signmessagewithprivkey abc,def", false, &filtered);
|
RPCConsole::RPCParseCommandLine(nullptr, result, "signmessagewithprivkey abc,def", false, &filtered);
|
||||||
QVERIFY(filtered == "signmessagewithprivkey(…)");
|
QVERIFY(filtered == "signmessagewithprivkey(…)");
|
||||||
RPCConsole::RPCParseCommandLine(result, "signrawtransactionwithkey(abc)", false, &filtered);
|
RPCConsole::RPCParseCommandLine(nullptr, result, "signrawtransactionwithkey(abc)", false, &filtered);
|
||||||
QVERIFY(filtered == "signrawtransactionwithkey(…)");
|
QVERIFY(filtered == "signrawtransactionwithkey(…)");
|
||||||
RPCConsole::RPCParseCommandLine(result, "walletpassphrase(help())", false, &filtered);
|
RPCConsole::RPCParseCommandLine(nullptr, result, "walletpassphrase(help())", false, &filtered);
|
||||||
QVERIFY(filtered == "walletpassphrase(…)");
|
QVERIFY(filtered == "walletpassphrase(…)");
|
||||||
RPCConsole::RPCParseCommandLine(result, "walletpassphrasechange(help(walletpassphrasechange(abc)))", false, &filtered);
|
RPCConsole::RPCParseCommandLine(nullptr, result, "walletpassphrasechange(help(walletpassphrasechange(abc)))", false, &filtered);
|
||||||
QVERIFY(filtered == "walletpassphrasechange(…)");
|
QVERIFY(filtered == "walletpassphrasechange(…)");
|
||||||
RPCConsole::RPCParseCommandLine(result, "help(encryptwallet(abc, def))", false, &filtered);
|
RPCConsole::RPCParseCommandLine(nullptr, result, "help(encryptwallet(abc, def))", false, &filtered);
|
||||||
QVERIFY(filtered == "help(encryptwallet(…))");
|
QVERIFY(filtered == "help(encryptwallet(…))");
|
||||||
RPCConsole::RPCParseCommandLine(result, "help(importprivkey())", false, &filtered);
|
RPCConsole::RPCParseCommandLine(nullptr, result, "help(importprivkey())", false, &filtered);
|
||||||
QVERIFY(filtered == "help(importprivkey(…))");
|
QVERIFY(filtered == "help(importprivkey(…))");
|
||||||
RPCConsole::RPCParseCommandLine(result, "help(importprivkey(help()))", false, &filtered);
|
RPCConsole::RPCParseCommandLine(nullptr, result, "help(importprivkey(help()))", false, &filtered);
|
||||||
QVERIFY(filtered == "help(importprivkey(…))");
|
QVERIFY(filtered == "help(importprivkey(…))");
|
||||||
RPCConsole::RPCParseCommandLine(result, "help(importprivkey(abc), walletpassphrase(def))", false, &filtered);
|
RPCConsole::RPCParseCommandLine(nullptr, result, "help(importprivkey(abc), walletpassphrase(def))", false, &filtered);
|
||||||
QVERIFY(filtered == "help(importprivkey(…), walletpassphrase(…))");
|
QVERIFY(filtered == "help(importprivkey(…), walletpassphrase(…))");
|
||||||
|
|
||||||
RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest");
|
RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest");
|
||||||
QVERIFY(result == "[]");
|
QVERIFY(result == "[]");
|
||||||
RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest ''");
|
RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest ''");
|
||||||
QVERIFY(result == "[\"\"]");
|
QVERIFY(result == "[\"\"]");
|
||||||
RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest \"\"");
|
RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest \"\"");
|
||||||
QVERIFY(result == "[\"\"]");
|
QVERIFY(result == "[\"\"]");
|
||||||
RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest '' abc");
|
RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest '' abc");
|
||||||
QVERIFY(result == "[\"\",\"abc\"]");
|
QVERIFY(result == "[\"\",\"abc\"]");
|
||||||
RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest abc '' abc");
|
RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest abc '' abc");
|
||||||
QVERIFY(result == "[\"abc\",\"\",\"abc\"]");
|
QVERIFY(result == "[\"abc\",\"\",\"abc\"]");
|
||||||
RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest abc abc");
|
RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest abc abc");
|
||||||
QVERIFY(result == "[\"abc\",\"abc\"]");
|
QVERIFY(result == "[\"abc\",\"abc\"]");
|
||||||
RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest abc\t\tabc");
|
RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest abc\t\tabc");
|
||||||
QVERIFY(result == "[\"abc\",\"abc\"]");
|
QVERIFY(result == "[\"abc\",\"abc\"]");
|
||||||
RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest(abc )");
|
RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest(abc )");
|
||||||
QVERIFY(result == "[\"abc\"]");
|
QVERIFY(result == "[\"abc\"]");
|
||||||
RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest( abc )");
|
RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest( abc )");
|
||||||
QVERIFY(result == "[\"abc\"]");
|
QVERIFY(result == "[\"abc\"]");
|
||||||
RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest( abc , cba )");
|
RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest( abc , cba )");
|
||||||
QVERIFY(result == "[\"abc\",\"cba\"]");
|
QVERIFY(result == "[\"abc\",\"cba\"]");
|
||||||
|
|
||||||
#if QT_VERSION >= 0x050300
|
#if QT_VERSION >= 0x050300
|
||||||
// do the QVERIFY_EXCEPTION_THROWN checks only with Qt5.3 and higher (QVERIFY_EXCEPTION_THROWN was introduced in Qt5.3)
|
// do the QVERIFY_EXCEPTION_THROWN checks only with Qt5.3 and higher (QVERIFY_EXCEPTION_THROWN was introduced in Qt5.3)
|
||||||
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo() .\n"), std::runtime_error); //invalid syntax
|
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo() .\n"), std::runtime_error); //invalid syntax
|
||||||
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo() getblockchaininfo()"), std::runtime_error); //invalid syntax
|
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo() getblockchaininfo()"), std::runtime_error); //invalid syntax
|
||||||
(RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo(")); //tolerate non closing brackets if we have no arguments
|
(RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo(")); //tolerate non closing brackets if we have no arguments
|
||||||
(RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo()()()")); //tolerate non command brackts
|
(RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo()()()")); //tolerate non command brackts
|
||||||
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo(True)"), UniValue); //invalid argument
|
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo(True)"), UniValue); //invalid argument
|
||||||
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "a(getblockchaininfo(True))"), UniValue); //method not found
|
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(*node, result, "a(getblockchaininfo(True))"), UniValue); //method not found
|
||||||
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest abc,,abc"), std::runtime_error); //don't tollerate empty arguments when using ,
|
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest abc,,abc"), std::runtime_error); //don't tollerate empty arguments when using ,
|
||||||
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest(abc,,abc)"), std::runtime_error); //don't tollerate empty arguments when using ,
|
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest(abc,,abc)"), std::runtime_error); //don't tollerate empty arguments when using ,
|
||||||
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest(abc,,)"), std::runtime_error); //don't tollerate empty arguments when using ,
|
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest(abc,,)"), std::runtime_error); //don't tollerate empty arguments when using ,
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include <qt/test/wallettests.h>
|
#include <qt/test/wallettests.h>
|
||||||
|
|
||||||
|
#include <interface/node.h>
|
||||||
#include <qt/bitcoinamountfield.h>
|
#include <qt/bitcoinamountfield.h>
|
||||||
#include <qt/callback.h>
|
#include <qt/callback.h>
|
||||||
#include <qt/optionsmodel.h>
|
#include <qt/optionsmodel.h>
|
||||||
|
@ -177,8 +178,11 @@ void TestGUI()
|
||||||
std::unique_ptr<const PlatformStyle> platformStyle(PlatformStyle::instantiate("other"));
|
std::unique_ptr<const PlatformStyle> platformStyle(PlatformStyle::instantiate("other"));
|
||||||
SendCoinsDialog sendCoinsDialog(platformStyle.get());
|
SendCoinsDialog sendCoinsDialog(platformStyle.get());
|
||||||
TransactionView transactionView(platformStyle.get());
|
TransactionView transactionView(platformStyle.get());
|
||||||
OptionsModel optionsModel;
|
auto node = interface::MakeNode();
|
||||||
WalletModel walletModel(platformStyle.get(), &wallet, &optionsModel);
|
OptionsModel optionsModel(*node);
|
||||||
|
vpwallets.insert(vpwallets.begin(), &wallet);
|
||||||
|
WalletModel walletModel(std::move(node->getWallets()[0]), *node, platformStyle.get(), &optionsModel);
|
||||||
|
vpwallets.erase(vpwallets.begin());
|
||||||
sendCoinsDialog.setModel(&walletModel);
|
sendCoinsDialog.setModel(&walletModel);
|
||||||
transactionView.setModel(&walletModel);
|
transactionView.setModel(&walletModel);
|
||||||
|
|
||||||
|
@ -203,7 +207,7 @@ void TestGUI()
|
||||||
QLabel* balanceLabel = overviewPage.findChild<QLabel*>("labelBalance");
|
QLabel* balanceLabel = overviewPage.findChild<QLabel*>("labelBalance");
|
||||||
QString balanceText = balanceLabel->text();
|
QString balanceText = balanceLabel->text();
|
||||||
int unit = walletModel.getOptionsModel()->getDisplayUnit();
|
int unit = walletModel.getOptionsModel()->getDisplayUnit();
|
||||||
CAmount balance = walletModel.getBalance();
|
CAmount balance = walletModel.wallet().getBalance();
|
||||||
QString balanceComparison = BitcoinUnits::formatWithUnit(unit, balance, false, BitcoinUnits::separatorAlways);
|
QString balanceComparison = BitcoinUnits::formatWithUnit(unit, balance, false, BitcoinUnits::separatorAlways);
|
||||||
QCOMPARE(balanceText, balanceComparison);
|
QCOMPARE(balanceText, balanceComparison);
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
// Distributed under the MIT software license, see the accompanying
|
// Distributed under the MIT software license, see the accompanying
|
||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#include <interface/node.h>
|
||||||
#include <qt/trafficgraphwidget.h>
|
#include <qt/trafficgraphwidget.h>
|
||||||
#include <qt/clientmodel.h>
|
#include <qt/clientmodel.h>
|
||||||
|
|
||||||
|
@ -35,8 +36,8 @@ void TrafficGraphWidget::setClientModel(ClientModel *model)
|
||||||
{
|
{
|
||||||
clientModel = model;
|
clientModel = model;
|
||||||
if(model) {
|
if(model) {
|
||||||
nLastBytesIn = model->getTotalBytesRecv();
|
nLastBytesIn = model->node().getTotalBytesRecv();
|
||||||
nLastBytesOut = model->getTotalBytesSent();
|
nLastBytesOut = model->node().getTotalBytesSent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,8 +124,8 @@ void TrafficGraphWidget::updateRates()
|
||||||
{
|
{
|
||||||
if(!clientModel) return;
|
if(!clientModel) return;
|
||||||
|
|
||||||
quint64 bytesIn = clientModel->getTotalBytesRecv(),
|
quint64 bytesIn = clientModel->node().getTotalBytesRecv(),
|
||||||
bytesOut = clientModel->getTotalBytesSent();
|
bytesOut = clientModel->node().getTotalBytesSent();
|
||||||
float inRate = (bytesIn - nLastBytesIn) / 1024.0f * 1000 / timer->interval();
|
float inRate = (bytesIn - nLastBytesIn) / 1024.0f * 1000 / timer->interval();
|
||||||
float outRate = (bytesOut - nLastBytesOut) / 1024.0f * 1000 / timer->interval();
|
float outRate = (bytesOut - nLastBytesOut) / 1024.0f * 1000 / timer->interval();
|
||||||
vSamplesIn.push_front(inRate);
|
vSamplesIn.push_front(inRate);
|
||||||
|
@ -169,8 +170,8 @@ void TrafficGraphWidget::clear()
|
||||||
fMax = 0.0f;
|
fMax = 0.0f;
|
||||||
|
|
||||||
if(clientModel) {
|
if(clientModel) {
|
||||||
nLastBytesIn = clientModel->getTotalBytesRecv();
|
nLastBytesIn = clientModel->node().getTotalBytesRecv();
|
||||||
nLastBytesOut = clientModel->getTotalBytesSent();
|
nLastBytesOut = clientModel->node().getTotalBytesSent();
|
||||||
}
|
}
|
||||||
timer->start();
|
timer->start();
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <qt/transactionrecord.h>
|
#include <qt/transactionrecord.h>
|
||||||
|
|
||||||
#include <consensus/consensus.h>
|
#include <consensus/consensus.h>
|
||||||
|
#include <interface/node.h>
|
||||||
#include <key_io.h>
|
#include <key_io.h>
|
||||||
#include <validation.h>
|
#include <validation.h>
|
||||||
#include <script/script.h>
|
#include <script/script.h>
|
||||||
|
@ -22,25 +23,24 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx)
|
QString TransactionDesc::FormatTxStatus(const interface::WalletTx& wtx, const interface::WalletTxStatus& status, bool inMempool, int numBlocks, int64_t adjustedTime)
|
||||||
{
|
{
|
||||||
AssertLockHeld(cs_main);
|
if (!status.is_final)
|
||||||
if (!CheckFinalTx(*wtx.tx))
|
|
||||||
{
|
{
|
||||||
if (wtx.tx->nLockTime < LOCKTIME_THRESHOLD)
|
if (wtx.tx->nLockTime < LOCKTIME_THRESHOLD)
|
||||||
return tr("Open for %n more block(s)", "", wtx.tx->nLockTime - chainActive.Height());
|
return tr("Open for %n more block(s)", "", wtx.tx->nLockTime - numBlocks);
|
||||||
else
|
else
|
||||||
return tr("Open until %1").arg(GUIUtil::dateTimeStr(wtx.tx->nLockTime));
|
return tr("Open until %1").arg(GUIUtil::dateTimeStr(wtx.tx->nLockTime));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int nDepth = wtx.GetDepthInMainChain();
|
int nDepth = status.depth_in_main_chain;
|
||||||
if (nDepth < 0)
|
if (nDepth < 0)
|
||||||
return tr("conflicted with a transaction with %1 confirmations").arg(-nDepth);
|
return tr("conflicted with a transaction with %1 confirmations").arg(-nDepth);
|
||||||
else if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
|
else if (adjustedTime - status.time_received > 2 * 60 && status.request_count == 0)
|
||||||
return tr("%1/offline").arg(nDepth);
|
return tr("%1/offline").arg(nDepth);
|
||||||
else if (nDepth == 0)
|
else if (nDepth == 0)
|
||||||
return tr("0/unconfirmed, %1").arg((wtx.InMempool() ? tr("in memory pool") : tr("not in memory pool"))) + (wtx.isAbandoned() ? ", "+tr("abandoned") : "");
|
return tr("0/unconfirmed, %1").arg((inMempool ? tr("in memory pool") : tr("not in memory pool"))) + (status.is_abandoned ? ", "+tr("abandoned") : "");
|
||||||
else if (nDepth < 6)
|
else if (nDepth < 6)
|
||||||
return tr("%1/unconfirmed").arg(nDepth);
|
return tr("%1/unconfirmed").arg(nDepth);
|
||||||
else
|
else
|
||||||
|
@ -48,21 +48,27 @@ QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionRecord *rec, int unit)
|
QString TransactionDesc::toHTML(interface::Node& node, interface::Wallet& wallet, TransactionRecord *rec, int unit)
|
||||||
{
|
{
|
||||||
|
int numBlocks;
|
||||||
|
int64_t adjustedTime;
|
||||||
|
interface::WalletTxStatus status;
|
||||||
|
interface::WalletOrderForm orderForm;
|
||||||
|
bool inMempool;
|
||||||
|
interface::WalletTx wtx = wallet.getWalletTxDetails(rec->hash, status, orderForm, inMempool, numBlocks, adjustedTime);
|
||||||
|
|
||||||
QString strHTML;
|
QString strHTML;
|
||||||
|
|
||||||
LOCK2(cs_main, wallet->cs_wallet);
|
|
||||||
strHTML.reserve(4000);
|
strHTML.reserve(4000);
|
||||||
strHTML += "<html><font face='verdana, arial, helvetica, sans-serif'>";
|
strHTML += "<html><font face='verdana, arial, helvetica, sans-serif'>";
|
||||||
|
|
||||||
int64_t nTime = wtx.GetTxTime();
|
int64_t nTime = wtx.time;
|
||||||
CAmount nCredit = wtx.GetCredit(ISMINE_ALL);
|
CAmount nCredit = wtx.credit;
|
||||||
CAmount nDebit = wtx.GetDebit(ISMINE_ALL);
|
CAmount nDebit = wtx.debit;
|
||||||
CAmount nNet = nCredit - nDebit;
|
CAmount nNet = nCredit - nDebit;
|
||||||
|
|
||||||
strHTML += "<b>" + tr("Status") + ":</b> " + FormatTxStatus(wtx);
|
strHTML += "<b>" + tr("Status") + ":</b> " + FormatTxStatus(wtx, status, inMempool, numBlocks, adjustedTime);
|
||||||
int nRequests = wtx.GetRequestCount();
|
int nRequests = status.request_count;
|
||||||
if (nRequests != -1)
|
if (nRequests != -1)
|
||||||
{
|
{
|
||||||
if (nRequests == 0)
|
if (nRequests == 0)
|
||||||
|
@ -77,14 +83,14 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
|
||||||
//
|
//
|
||||||
// From
|
// From
|
||||||
//
|
//
|
||||||
if (wtx.IsCoinBase())
|
if (wtx.is_coinbase)
|
||||||
{
|
{
|
||||||
strHTML += "<b>" + tr("Source") + ":</b> " + tr("Generated") + "<br>";
|
strHTML += "<b>" + tr("Source") + ":</b> " + tr("Generated") + "<br>";
|
||||||
}
|
}
|
||||||
else if (wtx.mapValue.count("from") && !wtx.mapValue["from"].empty())
|
else if (wtx.value_map.count("from") && !wtx.value_map["from"].empty())
|
||||||
{
|
{
|
||||||
// Online transaction
|
// Online transaction
|
||||||
strHTML += "<b>" + tr("From") + ":</b> " + GUIUtil::HtmlEscape(wtx.mapValue["from"]) + "<br>";
|
strHTML += "<b>" + tr("From") + ":</b> " + GUIUtil::HtmlEscape(wtx.value_map["from"]) + "<br>";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -94,14 +100,16 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
|
||||||
// Credit
|
// Credit
|
||||||
CTxDestination address = DecodeDestination(rec->address);
|
CTxDestination address = DecodeDestination(rec->address);
|
||||||
if (IsValidDestination(address)) {
|
if (IsValidDestination(address)) {
|
||||||
if (wallet->mapAddressBook.count(address))
|
std::string name;
|
||||||
|
isminetype ismine;
|
||||||
|
if (wallet.getAddress(address, &name, &ismine))
|
||||||
{
|
{
|
||||||
strHTML += "<b>" + tr("From") + ":</b> " + tr("unknown") + "<br>";
|
strHTML += "<b>" + tr("From") + ":</b> " + tr("unknown") + "<br>";
|
||||||
strHTML += "<b>" + tr("To") + ":</b> ";
|
strHTML += "<b>" + tr("To") + ":</b> ";
|
||||||
strHTML += GUIUtil::HtmlEscape(rec->address);
|
strHTML += GUIUtil::HtmlEscape(rec->address);
|
||||||
QString addressOwned = (::IsMine(*wallet, address) == ISMINE_SPENDABLE) ? tr("own address") : tr("watch-only");
|
QString addressOwned = ismine == ISMINE_SPENDABLE ? tr("own address") : tr("watch-only");
|
||||||
if (!wallet->mapAddressBook[address].name.empty())
|
if (!name.empty())
|
||||||
strHTML += " (" + addressOwned + ", " + tr("label") + ": " + GUIUtil::HtmlEscape(wallet->mapAddressBook[address].name) + ")";
|
strHTML += " (" + addressOwned + ", " + tr("label") + ": " + GUIUtil::HtmlEscape(name) + ")";
|
||||||
else
|
else
|
||||||
strHTML += " (" + addressOwned + ")";
|
strHTML += " (" + addressOwned + ")";
|
||||||
strHTML += "<br>";
|
strHTML += "<br>";
|
||||||
|
@ -113,31 +121,32 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
|
||||||
//
|
//
|
||||||
// To
|
// To
|
||||||
//
|
//
|
||||||
if (wtx.mapValue.count("to") && !wtx.mapValue["to"].empty())
|
if (wtx.value_map.count("to") && !wtx.value_map["to"].empty())
|
||||||
{
|
{
|
||||||
// Online transaction
|
// Online transaction
|
||||||
std::string strAddress = wtx.mapValue["to"];
|
std::string strAddress = wtx.value_map["to"];
|
||||||
strHTML += "<b>" + tr("To") + ":</b> ";
|
strHTML += "<b>" + tr("To") + ":</b> ";
|
||||||
CTxDestination dest = DecodeDestination(strAddress);
|
CTxDestination dest = DecodeDestination(strAddress);
|
||||||
if (wallet->mapAddressBook.count(dest) && !wallet->mapAddressBook[dest].name.empty())
|
std::string name;
|
||||||
strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[dest].name) + " ";
|
if (wallet.getAddress(dest, &name) && !name.empty())
|
||||||
|
strHTML += GUIUtil::HtmlEscape(name) + " ";
|
||||||
strHTML += GUIUtil::HtmlEscape(strAddress) + "<br>";
|
strHTML += GUIUtil::HtmlEscape(strAddress) + "<br>";
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Amount
|
// Amount
|
||||||
//
|
//
|
||||||
if (wtx.IsCoinBase() && nCredit == 0)
|
if (wtx.is_coinbase && nCredit == 0)
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
// Coinbase
|
// Coinbase
|
||||||
//
|
//
|
||||||
CAmount nUnmatured = 0;
|
CAmount nUnmatured = 0;
|
||||||
for (const CTxOut& txout : wtx.tx->vout)
|
for (const CTxOut& txout : wtx.tx->vout)
|
||||||
nUnmatured += wallet->GetCredit(txout, ISMINE_ALL);
|
nUnmatured += wallet.getCredit(txout, ISMINE_ALL);
|
||||||
strHTML += "<b>" + tr("Credit") + ":</b> ";
|
strHTML += "<b>" + tr("Credit") + ":</b> ";
|
||||||
if (wtx.IsInMainChain())
|
if (status.is_in_main_chain)
|
||||||
strHTML += BitcoinUnits::formatHtmlWithUnit(unit, nUnmatured)+ " (" + tr("matures in %n more block(s)", "", wtx.GetBlocksToMaturity()) + ")";
|
strHTML += BitcoinUnits::formatHtmlWithUnit(unit, nUnmatured)+ " (" + tr("matures in %n more block(s)", "", status.blocks_to_maturity) + ")";
|
||||||
else
|
else
|
||||||
strHTML += "(" + tr("not accepted") + ")";
|
strHTML += "(" + tr("not accepted") + ")";
|
||||||
strHTML += "<br>";
|
strHTML += "<br>";
|
||||||
|
@ -152,16 +161,14 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
isminetype fAllFromMe = ISMINE_SPENDABLE;
|
isminetype fAllFromMe = ISMINE_SPENDABLE;
|
||||||
for (const CTxIn& txin : wtx.tx->vin)
|
for (isminetype mine : wtx.txin_is_mine)
|
||||||
{
|
{
|
||||||
isminetype mine = wallet->IsMine(txin);
|
|
||||||
if(fAllFromMe > mine) fAllFromMe = mine;
|
if(fAllFromMe > mine) fAllFromMe = mine;
|
||||||
}
|
}
|
||||||
|
|
||||||
isminetype fAllToMe = ISMINE_SPENDABLE;
|
isminetype fAllToMe = ISMINE_SPENDABLE;
|
||||||
for (const CTxOut& txout : wtx.tx->vout)
|
for (isminetype mine : wtx.txout_is_mine)
|
||||||
{
|
{
|
||||||
isminetype mine = wallet->IsMine(txout);
|
|
||||||
if(fAllToMe > mine) fAllToMe = mine;
|
if(fAllToMe > mine) fAllToMe = mine;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,22 +180,24 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
|
||||||
//
|
//
|
||||||
// Debit
|
// Debit
|
||||||
//
|
//
|
||||||
|
auto mine = wtx.txout_is_mine.begin();
|
||||||
for (const CTxOut& txout : wtx.tx->vout)
|
for (const CTxOut& txout : wtx.tx->vout)
|
||||||
{
|
{
|
||||||
// Ignore change
|
// Ignore change
|
||||||
isminetype toSelf = wallet->IsMine(txout);
|
isminetype toSelf = *(mine++);
|
||||||
if ((toSelf == ISMINE_SPENDABLE) && (fAllFromMe == ISMINE_SPENDABLE))
|
if ((toSelf == ISMINE_SPENDABLE) && (fAllFromMe == ISMINE_SPENDABLE))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!wtx.mapValue.count("to") || wtx.mapValue["to"].empty())
|
if (!wtx.value_map.count("to") || wtx.value_map["to"].empty())
|
||||||
{
|
{
|
||||||
// Offline transaction
|
// Offline transaction
|
||||||
CTxDestination address;
|
CTxDestination address;
|
||||||
if (ExtractDestination(txout.scriptPubKey, address))
|
if (ExtractDestination(txout.scriptPubKey, address))
|
||||||
{
|
{
|
||||||
strHTML += "<b>" + tr("To") + ":</b> ";
|
strHTML += "<b>" + tr("To") + ":</b> ";
|
||||||
if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].name.empty())
|
std::string name;
|
||||||
strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address].name) + " ";
|
if (wallet.getAddress(address, &name) && !name.empty())
|
||||||
|
strHTML += GUIUtil::HtmlEscape(name) + " ";
|
||||||
strHTML += GUIUtil::HtmlEscape(EncodeDestination(address));
|
strHTML += GUIUtil::HtmlEscape(EncodeDestination(address));
|
||||||
if(toSelf == ISMINE_SPENDABLE)
|
if(toSelf == ISMINE_SPENDABLE)
|
||||||
strHTML += " (own address)";
|
strHTML += " (own address)";
|
||||||
|
@ -206,7 +215,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
|
||||||
if (fAllToMe)
|
if (fAllToMe)
|
||||||
{
|
{
|
||||||
// Payment to self
|
// Payment to self
|
||||||
CAmount nChange = wtx.GetChange();
|
CAmount nChange = wtx.change;
|
||||||
CAmount nValue = nCredit - nChange;
|
CAmount nValue = nCredit - nChange;
|
||||||
strHTML += "<b>" + tr("Total debit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -nValue) + "<br>";
|
strHTML += "<b>" + tr("Total debit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -nValue) + "<br>";
|
||||||
strHTML += "<b>" + tr("Total credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, nValue) + "<br>";
|
strHTML += "<b>" + tr("Total credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, nValue) + "<br>";
|
||||||
|
@ -221,12 +230,18 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
|
||||||
//
|
//
|
||||||
// Mixed debit transaction
|
// Mixed debit transaction
|
||||||
//
|
//
|
||||||
for (const CTxIn& txin : wtx.tx->vin)
|
auto mine = wtx.txin_is_mine.begin();
|
||||||
if (wallet->IsMine(txin))
|
for (const CTxIn& txin : wtx.tx->vin) {
|
||||||
strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -wallet->GetDebit(txin, ISMINE_ALL)) + "<br>";
|
if (*(mine++)) {
|
||||||
for (const CTxOut& txout : wtx.tx->vout)
|
strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -wallet.getDebit(txin, ISMINE_ALL)) + "<br>";
|
||||||
if (wallet->IsMine(txout))
|
}
|
||||||
strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, wallet->GetCredit(txout, ISMINE_ALL)) + "<br>";
|
}
|
||||||
|
mine = wtx.txout_is_mine.begin();
|
||||||
|
for (const CTxOut& txout : wtx.tx->vout) {
|
||||||
|
if (*(mine++)) {
|
||||||
|
strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, wallet.getCredit(txout, ISMINE_ALL)) + "<br>";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,10 +250,10 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
|
||||||
//
|
//
|
||||||
// Message
|
// Message
|
||||||
//
|
//
|
||||||
if (wtx.mapValue.count("message") && !wtx.mapValue["message"].empty())
|
if (wtx.value_map.count("message") && !wtx.value_map["message"].empty())
|
||||||
strHTML += "<br><b>" + tr("Message") + ":</b><br>" + GUIUtil::HtmlEscape(wtx.mapValue["message"], true) + "<br>";
|
strHTML += "<br><b>" + tr("Message") + ":</b><br>" + GUIUtil::HtmlEscape(wtx.value_map["message"], true) + "<br>";
|
||||||
if (wtx.mapValue.count("comment") && !wtx.mapValue["comment"].empty())
|
if (wtx.value_map.count("comment") && !wtx.value_map["comment"].empty())
|
||||||
strHTML += "<br><b>" + tr("Comment") + ":</b><br>" + GUIUtil::HtmlEscape(wtx.mapValue["comment"], true) + "<br>";
|
strHTML += "<br><b>" + tr("Comment") + ":</b><br>" + GUIUtil::HtmlEscape(wtx.value_map["comment"], true) + "<br>";
|
||||||
|
|
||||||
strHTML += "<b>" + tr("Transaction ID") + ":</b> " + rec->getTxHash() + "<br>";
|
strHTML += "<b>" + tr("Transaction ID") + ":</b> " + rec->getTxHash() + "<br>";
|
||||||
strHTML += "<b>" + tr("Transaction total size") + ":</b> " + QString::number(wtx.tx->GetTotalSize()) + " bytes<br>";
|
strHTML += "<b>" + tr("Transaction total size") + ":</b> " + QString::number(wtx.tx->GetTotalSize()) + " bytes<br>";
|
||||||
|
@ -246,14 +261,14 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
|
||||||
strHTML += "<b>" + tr("Output index") + ":</b> " + QString::number(rec->getOutputIndex()) + "<br>";
|
strHTML += "<b>" + tr("Output index") + ":</b> " + QString::number(rec->getOutputIndex()) + "<br>";
|
||||||
|
|
||||||
// Message from normal bitcoin:URI (bitcoin:123...?message=example)
|
// Message from normal bitcoin:URI (bitcoin:123...?message=example)
|
||||||
for (const std::pair<std::string, std::string>& r : wtx.vOrderForm)
|
for (const std::pair<std::string, std::string>& r : orderForm)
|
||||||
if (r.first == "Message")
|
if (r.first == "Message")
|
||||||
strHTML += "<br><b>" + tr("Message") + ":</b><br>" + GUIUtil::HtmlEscape(r.second, true) + "<br>";
|
strHTML += "<br><b>" + tr("Message") + ":</b><br>" + GUIUtil::HtmlEscape(r.second, true) + "<br>";
|
||||||
|
|
||||||
//
|
//
|
||||||
// PaymentRequest info:
|
// PaymentRequest info:
|
||||||
//
|
//
|
||||||
for (const std::pair<std::string, std::string>& r : wtx.vOrderForm)
|
for (const std::pair<std::string, std::string>& r : orderForm)
|
||||||
{
|
{
|
||||||
if (r.first == "PaymentRequest")
|
if (r.first == "PaymentRequest")
|
||||||
{
|
{
|
||||||
|
@ -265,7 +280,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wtx.IsCoinBase())
|
if (wtx.is_coinbase)
|
||||||
{
|
{
|
||||||
quint32 numBlocksToMaturity = COINBASE_MATURITY + 1;
|
quint32 numBlocksToMaturity = COINBASE_MATURITY + 1;
|
||||||
strHTML += "<br>" + tr("Generated coins must mature %1 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to \"not accepted\" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.").arg(QString::number(numBlocksToMaturity)) + "<br>";
|
strHTML += "<br>" + tr("Generated coins must mature %1 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to \"not accepted\" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.").arg(QString::number(numBlocksToMaturity)) + "<br>";
|
||||||
|
@ -274,15 +289,15 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
|
||||||
//
|
//
|
||||||
// Debug view
|
// Debug view
|
||||||
//
|
//
|
||||||
if (logCategories != BCLog::NONE)
|
if (node.getLogCategories() != BCLog::NONE)
|
||||||
{
|
{
|
||||||
strHTML += "<hr><br>" + tr("Debug information") + "<br><br>";
|
strHTML += "<hr><br>" + tr("Debug information") + "<br><br>";
|
||||||
for (const CTxIn& txin : wtx.tx->vin)
|
for (const CTxIn& txin : wtx.tx->vin)
|
||||||
if(wallet->IsMine(txin))
|
if(wallet.txinIsMine(txin))
|
||||||
strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -wallet->GetDebit(txin, ISMINE_ALL)) + "<br>";
|
strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -wallet.getDebit(txin, ISMINE_ALL)) + "<br>";
|
||||||
for (const CTxOut& txout : wtx.tx->vout)
|
for (const CTxOut& txout : wtx.tx->vout)
|
||||||
if(wallet->IsMine(txout))
|
if(wallet.txoutIsMine(txout))
|
||||||
strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, wallet->GetCredit(txout, ISMINE_ALL)) + "<br>";
|
strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, wallet.getCredit(txout, ISMINE_ALL)) + "<br>";
|
||||||
|
|
||||||
strHTML += "<br><b>" + tr("Transaction") + ":</b><br>";
|
strHTML += "<br><b>" + tr("Transaction") + ":</b><br>";
|
||||||
strHTML += GUIUtil::HtmlEscape(wtx.tx->ToString(), true);
|
strHTML += GUIUtil::HtmlEscape(wtx.tx->ToString(), true);
|
||||||
|
@ -295,7 +310,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
|
||||||
COutPoint prevout = txin.prevout;
|
COutPoint prevout = txin.prevout;
|
||||||
|
|
||||||
Coin prev;
|
Coin prev;
|
||||||
if(pcoinsTip->GetCoin(prevout, prev))
|
if(node.getUnspentOutput(prevout, prev))
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
strHTML += "<li>";
|
strHTML += "<li>";
|
||||||
|
@ -303,13 +318,14 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
|
||||||
CTxDestination address;
|
CTxDestination address;
|
||||||
if (ExtractDestination(vout.scriptPubKey, address))
|
if (ExtractDestination(vout.scriptPubKey, address))
|
||||||
{
|
{
|
||||||
if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].name.empty())
|
std::string name;
|
||||||
strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address].name) + " ";
|
if (wallet.getAddress(address, &name) && !name.empty())
|
||||||
|
strHTML += GUIUtil::HtmlEscape(name) + " ";
|
||||||
strHTML += QString::fromStdString(EncodeDestination(address));
|
strHTML += QString::fromStdString(EncodeDestination(address));
|
||||||
}
|
}
|
||||||
strHTML = strHTML + " " + tr("Amount") + "=" + BitcoinUnits::formatHtmlWithUnit(unit, vout.nValue);
|
strHTML = strHTML + " " + tr("Amount") + "=" + BitcoinUnits::formatHtmlWithUnit(unit, vout.nValue);
|
||||||
strHTML = strHTML + " IsMine=" + (wallet->IsMine(vout) & ISMINE_SPENDABLE ? tr("true") : tr("false")) + "</li>";
|
strHTML = strHTML + " IsMine=" + (wallet.txoutIsMine(vout) & ISMINE_SPENDABLE ? tr("true") : tr("false")) + "</li>";
|
||||||
strHTML = strHTML + " IsWatchOnly=" + (wallet->IsMine(vout) & ISMINE_WATCH_ONLY ? tr("true") : tr("false")) + "</li>";
|
strHTML = strHTML + " IsWatchOnly=" + (wallet.txoutIsMine(vout) & ISMINE_WATCH_ONLY ? tr("true") : tr("false")) + "</li>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,12 @@
|
||||||
|
|
||||||
class TransactionRecord;
|
class TransactionRecord;
|
||||||
|
|
||||||
class CWallet;
|
namespace interface {
|
||||||
class CWalletTx;
|
class Node;
|
||||||
|
class Wallet;
|
||||||
|
struct WalletTx;
|
||||||
|
struct WalletTxStatus;
|
||||||
|
}
|
||||||
|
|
||||||
/** Provide a human-readable extended HTML description of a transaction.
|
/** Provide a human-readable extended HTML description of a transaction.
|
||||||
*/
|
*/
|
||||||
|
@ -20,12 +24,12 @@ class TransactionDesc: public QObject
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static QString toHTML(CWallet *wallet, CWalletTx &wtx, TransactionRecord *rec, int unit);
|
static QString toHTML(interface::Node& node, interface::Wallet& wallet, TransactionRecord *rec, int unit);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TransactionDesc() {}
|
TransactionDesc() {}
|
||||||
|
|
||||||
static QString FormatTxStatus(const CWalletTx& wtx);
|
static QString FormatTxStatus(const interface::WalletTx& wtx, const interface::WalletTxStatus& status, bool inMempool, int numBlocks, int64_t adjustedTime);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // BITCOIN_QT_TRANSACTIONDESC_H
|
#endif // BITCOIN_QT_TRANSACTIONDESC_H
|
||||||
|
|
|
@ -5,17 +5,17 @@
|
||||||
#include <qt/transactionrecord.h>
|
#include <qt/transactionrecord.h>
|
||||||
|
|
||||||
#include <consensus/consensus.h>
|
#include <consensus/consensus.h>
|
||||||
|
#include <interface/wallet.h>
|
||||||
#include <key_io.h>
|
#include <key_io.h>
|
||||||
#include <validation.h>
|
|
||||||
#include <timedata.h>
|
#include <timedata.h>
|
||||||
#include <wallet/wallet.h>
|
#include <validation.h>
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
||||||
/* Return positive answer if transaction should be shown in list.
|
/* Return positive answer if transaction should be shown in list.
|
||||||
*/
|
*/
|
||||||
bool TransactionRecord::showTransaction(const CWalletTx &wtx)
|
bool TransactionRecord::showTransaction()
|
||||||
{
|
{
|
||||||
// There are currently no cases where we hide transactions, but
|
// There are currently no cases where we hide transactions, but
|
||||||
// we may want to use this in the future for things like RBF.
|
// we may want to use this in the future for things like RBF.
|
||||||
|
@ -25,17 +25,17 @@ bool TransactionRecord::showTransaction(const CWalletTx &wtx)
|
||||||
/*
|
/*
|
||||||
* Decompose CWallet transaction to model transaction records.
|
* Decompose CWallet transaction to model transaction records.
|
||||||
*/
|
*/
|
||||||
QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *wallet, const CWalletTx &wtx)
|
QList<TransactionRecord> TransactionRecord::decomposeTransaction(const interface::WalletTx& wtx)
|
||||||
{
|
{
|
||||||
QList<TransactionRecord> parts;
|
QList<TransactionRecord> parts;
|
||||||
int64_t nTime = wtx.GetTxTime();
|
int64_t nTime = wtx.time;
|
||||||
CAmount nCredit = wtx.GetCredit(ISMINE_ALL);
|
CAmount nCredit = wtx.credit;
|
||||||
CAmount nDebit = wtx.GetDebit(ISMINE_ALL);
|
CAmount nDebit = wtx.debit;
|
||||||
CAmount nNet = nCredit - nDebit;
|
CAmount nNet = nCredit - nDebit;
|
||||||
uint256 hash = wtx.GetHash();
|
uint256 hash = wtx.tx->GetHash();
|
||||||
std::map<std::string, std::string> mapValue = wtx.mapValue;
|
std::map<std::string, std::string> mapValue = wtx.value_map;
|
||||||
|
|
||||||
if (nNet > 0 || wtx.IsCoinBase())
|
if (nNet > 0 || wtx.is_coinbase)
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
// Credit
|
// Credit
|
||||||
|
@ -43,7 +43,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
|
||||||
for(unsigned int i = 0; i < wtx.tx->vout.size(); i++)
|
for(unsigned int i = 0; i < wtx.tx->vout.size(); i++)
|
||||||
{
|
{
|
||||||
const CTxOut& txout = wtx.tx->vout[i];
|
const CTxOut& txout = wtx.tx->vout[i];
|
||||||
isminetype mine = wallet->IsMine(txout);
|
isminetype mine = wtx.txout_is_mine[i];
|
||||||
if(mine)
|
if(mine)
|
||||||
{
|
{
|
||||||
TransactionRecord sub(hash, nTime);
|
TransactionRecord sub(hash, nTime);
|
||||||
|
@ -51,11 +51,11 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
|
||||||
sub.idx = i; // vout index
|
sub.idx = i; // vout index
|
||||||
sub.credit = txout.nValue;
|
sub.credit = txout.nValue;
|
||||||
sub.involvesWatchAddress = mine & ISMINE_WATCH_ONLY;
|
sub.involvesWatchAddress = mine & ISMINE_WATCH_ONLY;
|
||||||
if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address))
|
if (wtx.txout_address_is_mine[i])
|
||||||
{
|
{
|
||||||
// Received by Bitcoin Address
|
// Received by Bitcoin Address
|
||||||
sub.type = TransactionRecord::RecvWithAddress;
|
sub.type = TransactionRecord::RecvWithAddress;
|
||||||
sub.address = EncodeDestination(address);
|
sub.address = EncodeDestination(wtx.txout_address[i]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -63,7 +63,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
|
||||||
sub.type = TransactionRecord::RecvFromOther;
|
sub.type = TransactionRecord::RecvFromOther;
|
||||||
sub.address = mapValue["from"];
|
sub.address = mapValue["from"];
|
||||||
}
|
}
|
||||||
if (wtx.IsCoinBase())
|
if (wtx.is_coinbase)
|
||||||
{
|
{
|
||||||
// Generated
|
// Generated
|
||||||
sub.type = TransactionRecord::Generated;
|
sub.type = TransactionRecord::Generated;
|
||||||
|
@ -77,17 +77,15 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
|
||||||
{
|
{
|
||||||
bool involvesWatchAddress = false;
|
bool involvesWatchAddress = false;
|
||||||
isminetype fAllFromMe = ISMINE_SPENDABLE;
|
isminetype fAllFromMe = ISMINE_SPENDABLE;
|
||||||
for (const CTxIn& txin : wtx.tx->vin)
|
for (isminetype mine : wtx.txin_is_mine)
|
||||||
{
|
{
|
||||||
isminetype mine = wallet->IsMine(txin);
|
|
||||||
if(mine & ISMINE_WATCH_ONLY) involvesWatchAddress = true;
|
if(mine & ISMINE_WATCH_ONLY) involvesWatchAddress = true;
|
||||||
if(fAllFromMe > mine) fAllFromMe = mine;
|
if(fAllFromMe > mine) fAllFromMe = mine;
|
||||||
}
|
}
|
||||||
|
|
||||||
isminetype fAllToMe = ISMINE_SPENDABLE;
|
isminetype fAllToMe = ISMINE_SPENDABLE;
|
||||||
for (const CTxOut& txout : wtx.tx->vout)
|
for (isminetype mine : wtx.txout_is_mine)
|
||||||
{
|
{
|
||||||
isminetype mine = wallet->IsMine(txout);
|
|
||||||
if(mine & ISMINE_WATCH_ONLY) involvesWatchAddress = true;
|
if(mine & ISMINE_WATCH_ONLY) involvesWatchAddress = true;
|
||||||
if(fAllToMe > mine) fAllToMe = mine;
|
if(fAllToMe > mine) fAllToMe = mine;
|
||||||
}
|
}
|
||||||
|
@ -95,7 +93,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
|
||||||
if (fAllFromMe && fAllToMe)
|
if (fAllFromMe && fAllToMe)
|
||||||
{
|
{
|
||||||
// Payment to self
|
// Payment to self
|
||||||
CAmount nChange = wtx.GetChange();
|
CAmount nChange = wtx.change;
|
||||||
|
|
||||||
parts.append(TransactionRecord(hash, nTime, TransactionRecord::SendToSelf, "",
|
parts.append(TransactionRecord(hash, nTime, TransactionRecord::SendToSelf, "",
|
||||||
-(nDebit - nChange), nCredit - nChange));
|
-(nDebit - nChange), nCredit - nChange));
|
||||||
|
@ -115,19 +113,18 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
|
||||||
sub.idx = nOut;
|
sub.idx = nOut;
|
||||||
sub.involvesWatchAddress = involvesWatchAddress;
|
sub.involvesWatchAddress = involvesWatchAddress;
|
||||||
|
|
||||||
if(wallet->IsMine(txout))
|
if(wtx.txout_is_mine[nOut])
|
||||||
{
|
{
|
||||||
// Ignore parts sent to self, as this is usually the change
|
// Ignore parts sent to self, as this is usually the change
|
||||||
// from a transaction sent back to our own address.
|
// from a transaction sent back to our own address.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
CTxDestination address;
|
if (!boost::get<CNoDestination>(&wtx.txout_address[nOut]))
|
||||||
if (ExtractDestination(txout.scriptPubKey, address))
|
|
||||||
{
|
{
|
||||||
// Sent to Bitcoin Address
|
// Sent to Bitcoin Address
|
||||||
sub.type = TransactionRecord::SendToAddress;
|
sub.type = TransactionRecord::SendToAddress;
|
||||||
sub.address = EncodeDestination(address);
|
sub.address = EncodeDestination(wtx.txout_address[nOut]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -161,50 +158,46 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
|
||||||
return parts;
|
return parts;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TransactionRecord::updateStatus(const CWalletTx &wtx)
|
void TransactionRecord::updateStatus(const interface::WalletTxStatus& wtx, int numBlocks, int64_t adjustedTime)
|
||||||
{
|
{
|
||||||
AssertLockHeld(cs_main);
|
|
||||||
// Determine transaction status
|
// Determine transaction status
|
||||||
|
|
||||||
// Find the block the tx is in
|
|
||||||
const CBlockIndex* pindex = LookupBlockIndex(wtx.hashBlock);
|
|
||||||
|
|
||||||
// Sort order, unrecorded transactions sort to the top
|
// Sort order, unrecorded transactions sort to the top
|
||||||
status.sortKey = strprintf("%010d-%01d-%010u-%03d",
|
status.sortKey = strprintf("%010d-%01d-%010u-%03d",
|
||||||
(pindex ? pindex->nHeight : std::numeric_limits<int>::max()),
|
wtx.block_height,
|
||||||
(wtx.IsCoinBase() ? 1 : 0),
|
wtx.is_coinbase ? 1 : 0,
|
||||||
wtx.nTimeReceived,
|
wtx.time_received,
|
||||||
idx);
|
idx);
|
||||||
status.countsForBalance = wtx.IsTrusted() && !(wtx.GetBlocksToMaturity() > 0);
|
status.countsForBalance = wtx.is_trusted && !(wtx.blocks_to_maturity > 0);
|
||||||
status.depth = wtx.GetDepthInMainChain();
|
status.depth = wtx.depth_in_main_chain;
|
||||||
status.cur_num_blocks = chainActive.Height();
|
status.cur_num_blocks = numBlocks;
|
||||||
|
|
||||||
if (!CheckFinalTx(*wtx.tx))
|
if (!wtx.is_final)
|
||||||
{
|
{
|
||||||
if (wtx.tx->nLockTime < LOCKTIME_THRESHOLD)
|
if (wtx.lock_time < LOCKTIME_THRESHOLD)
|
||||||
{
|
{
|
||||||
status.status = TransactionStatus::OpenUntilBlock;
|
status.status = TransactionStatus::OpenUntilBlock;
|
||||||
status.open_for = wtx.tx->nLockTime - chainActive.Height();
|
status.open_for = wtx.lock_time - numBlocks;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
status.status = TransactionStatus::OpenUntilDate;
|
status.status = TransactionStatus::OpenUntilDate;
|
||||||
status.open_for = wtx.tx->nLockTime;
|
status.open_for = wtx.lock_time;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// For generated transactions, determine maturity
|
// For generated transactions, determine maturity
|
||||||
else if(type == TransactionRecord::Generated)
|
else if(type == TransactionRecord::Generated)
|
||||||
{
|
{
|
||||||
if (wtx.GetBlocksToMaturity() > 0)
|
if (wtx.blocks_to_maturity > 0)
|
||||||
{
|
{
|
||||||
status.status = TransactionStatus::Immature;
|
status.status = TransactionStatus::Immature;
|
||||||
|
|
||||||
if (wtx.IsInMainChain())
|
if (wtx.is_in_main_chain)
|
||||||
{
|
{
|
||||||
status.matures_in = wtx.GetBlocksToMaturity();
|
status.matures_in = wtx.blocks_to_maturity;
|
||||||
|
|
||||||
// Check if the block was requested by anyone
|
// Check if the block was requested by anyone
|
||||||
if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
|
if (adjustedTime - wtx.time_received > 2 * 60 && wtx.request_count == 0)
|
||||||
status.status = TransactionStatus::MaturesWarning;
|
status.status = TransactionStatus::MaturesWarning;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -223,14 +216,14 @@ void TransactionRecord::updateStatus(const CWalletTx &wtx)
|
||||||
{
|
{
|
||||||
status.status = TransactionStatus::Conflicted;
|
status.status = TransactionStatus::Conflicted;
|
||||||
}
|
}
|
||||||
else if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
|
else if (adjustedTime - wtx.time_received > 2 * 60 && wtx.request_count == 0)
|
||||||
{
|
{
|
||||||
status.status = TransactionStatus::Offline;
|
status.status = TransactionStatus::Offline;
|
||||||
}
|
}
|
||||||
else if (status.depth == 0)
|
else if (status.depth == 0)
|
||||||
{
|
{
|
||||||
status.status = TransactionStatus::Unconfirmed;
|
status.status = TransactionStatus::Unconfirmed;
|
||||||
if (wtx.isAbandoned())
|
if (wtx.is_abandoned)
|
||||||
status.status = TransactionStatus::Abandoned;
|
status.status = TransactionStatus::Abandoned;
|
||||||
}
|
}
|
||||||
else if (status.depth < RecommendedNumConfirmations)
|
else if (status.depth < RecommendedNumConfirmations)
|
||||||
|
@ -245,10 +238,9 @@ void TransactionRecord::updateStatus(const CWalletTx &wtx)
|
||||||
status.needsUpdate = false;
|
status.needsUpdate = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TransactionRecord::statusUpdateNeeded() const
|
bool TransactionRecord::statusUpdateNeeded(int numBlocks) const
|
||||||
{
|
{
|
||||||
AssertLockHeld(cs_main);
|
return status.cur_num_blocks != numBlocks || status.needsUpdate;
|
||||||
return status.cur_num_blocks != chainActive.Height() || status.needsUpdate;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString TransactionRecord::getTxHash() const
|
QString TransactionRecord::getTxHash() const
|
||||||
|
|
|
@ -11,8 +11,12 @@
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
class CWallet;
|
namespace interface {
|
||||||
class CWalletTx;
|
class Node;
|
||||||
|
class Wallet;
|
||||||
|
struct WalletTx;
|
||||||
|
struct WalletTxStatus;
|
||||||
|
}
|
||||||
|
|
||||||
/** UI model for transaction status. The transaction status is the part of a transaction that will change over time.
|
/** UI model for transaction status. The transaction status is the part of a transaction that will change over time.
|
||||||
*/
|
*/
|
||||||
|
@ -106,8 +110,8 @@ public:
|
||||||
|
|
||||||
/** Decompose CWallet transaction to model transaction records.
|
/** Decompose CWallet transaction to model transaction records.
|
||||||
*/
|
*/
|
||||||
static bool showTransaction(const CWalletTx &wtx);
|
static bool showTransaction();
|
||||||
static QList<TransactionRecord> decomposeTransaction(const CWallet *wallet, const CWalletTx &wtx);
|
static QList<TransactionRecord> decomposeTransaction(const interface::WalletTx& wtx);
|
||||||
|
|
||||||
/** @name Immutable transaction attributes
|
/** @name Immutable transaction attributes
|
||||||
@{*/
|
@{*/
|
||||||
|
@ -136,11 +140,11 @@ public:
|
||||||
|
|
||||||
/** Update status from core wallet tx.
|
/** Update status from core wallet tx.
|
||||||
*/
|
*/
|
||||||
void updateStatus(const CWalletTx &wtx);
|
void updateStatus(const interface::WalletTxStatus& wtx, int numBlocks, int64_t adjustedTime);
|
||||||
|
|
||||||
/** Return whether a status update is needed.
|
/** Return whether a status update is needed.
|
||||||
*/
|
*/
|
||||||
bool statusUpdateNeeded() const;
|
bool statusUpdateNeeded(int numBlocks) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // BITCOIN_QT_TRANSACTIONRECORD_H
|
#endif // BITCOIN_QT_TRANSACTIONRECORD_H
|
||||||
|
|
|
@ -14,11 +14,12 @@
|
||||||
#include <qt/walletmodel.h>
|
#include <qt/walletmodel.h>
|
||||||
|
|
||||||
#include <core_io.h>
|
#include <core_io.h>
|
||||||
|
#include <interface/handler.h>
|
||||||
|
#include <interface/node.h>
|
||||||
#include <validation.h>
|
#include <validation.h>
|
||||||
#include <sync.h>
|
#include <sync.h>
|
||||||
#include <uint256.h>
|
#include <uint256.h>
|
||||||
#include <util.h>
|
#include <util.h>
|
||||||
#include <wallet/wallet.h>
|
|
||||||
|
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
|
@ -57,13 +58,11 @@ struct TxLessThan
|
||||||
class TransactionTablePriv
|
class TransactionTablePriv
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TransactionTablePriv(CWallet *_wallet, TransactionTableModel *_parent) :
|
TransactionTablePriv(TransactionTableModel *_parent) :
|
||||||
wallet(_wallet),
|
|
||||||
parent(_parent)
|
parent(_parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
CWallet *wallet;
|
|
||||||
TransactionTableModel *parent;
|
TransactionTableModel *parent;
|
||||||
|
|
||||||
/* Local cache of wallet.
|
/* Local cache of wallet.
|
||||||
|
@ -74,16 +73,15 @@ public:
|
||||||
|
|
||||||
/* Query entire wallet anew from core.
|
/* Query entire wallet anew from core.
|
||||||
*/
|
*/
|
||||||
void refreshWallet()
|
void refreshWallet(interface::Wallet& wallet)
|
||||||
{
|
{
|
||||||
qDebug() << "TransactionTablePriv::refreshWallet";
|
qDebug() << "TransactionTablePriv::refreshWallet";
|
||||||
cachedWallet.clear();
|
cachedWallet.clear();
|
||||||
{
|
{
|
||||||
LOCK2(cs_main, wallet->cs_wallet);
|
for (const auto& wtx : wallet.getWalletTxs()) {
|
||||||
for (const auto& entry : wallet->mapWallet)
|
if (TransactionRecord::showTransaction()) {
|
||||||
{
|
cachedWallet.append(TransactionRecord::decomposeTransaction(wtx));
|
||||||
if (TransactionRecord::showTransaction(entry.second))
|
}
|
||||||
cachedWallet.append(TransactionRecord::decomposeTransaction(wallet, entry.second));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,7 +91,7 @@ public:
|
||||||
|
|
||||||
Call with transaction that was added, removed or changed.
|
Call with transaction that was added, removed or changed.
|
||||||
*/
|
*/
|
||||||
void updateWallet(const uint256 &hash, int status, bool showTransaction)
|
void updateWallet(interface::Wallet& wallet, const uint256 &hash, int status, bool showTransaction)
|
||||||
{
|
{
|
||||||
qDebug() << "TransactionTablePriv::updateWallet: " + QString::fromStdString(hash.ToString()) + " " + QString::number(status);
|
qDebug() << "TransactionTablePriv::updateWallet: " + QString::fromStdString(hash.ToString()) + " " + QString::number(status);
|
||||||
|
|
||||||
|
@ -128,17 +126,16 @@ public:
|
||||||
}
|
}
|
||||||
if(showTransaction)
|
if(showTransaction)
|
||||||
{
|
{
|
||||||
LOCK2(cs_main, wallet->cs_wallet);
|
|
||||||
// Find transaction in wallet
|
// Find transaction in wallet
|
||||||
std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet.find(hash);
|
interface::WalletTx wtx = wallet.getWalletTx(hash);
|
||||||
if(mi == wallet->mapWallet.end())
|
if(!wtx.tx)
|
||||||
{
|
{
|
||||||
qWarning() << "TransactionTablePriv::updateWallet: Warning: Got CT_NEW, but transaction is not in wallet";
|
qWarning() << "TransactionTablePriv::updateWallet: Warning: Got CT_NEW, but transaction is not in wallet";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Added -- insert at the right position
|
// Added -- insert at the right position
|
||||||
QList<TransactionRecord> toInsert =
|
QList<TransactionRecord> toInsert =
|
||||||
TransactionRecord::decomposeTransaction(wallet, mi->second);
|
TransactionRecord::decomposeTransaction(wtx);
|
||||||
if(!toInsert.isEmpty()) /* only if something to insert */
|
if(!toInsert.isEmpty()) /* only if something to insert */
|
||||||
{
|
{
|
||||||
parent->beginInsertRows(QModelIndex(), lowerIndex, lowerIndex+toInsert.size()-1);
|
parent->beginInsertRows(QModelIndex(), lowerIndex, lowerIndex+toInsert.size()-1);
|
||||||
|
@ -179,7 +176,7 @@ public:
|
||||||
return cachedWallet.size();
|
return cachedWallet.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
TransactionRecord *index(int idx)
|
TransactionRecord *index(interface::Wallet& wallet, int idx)
|
||||||
{
|
{
|
||||||
if(idx >= 0 && idx < cachedWallet.size())
|
if(idx >= 0 && idx < cachedWallet.size())
|
||||||
{
|
{
|
||||||
|
@ -192,61 +189,42 @@ public:
|
||||||
// If a status update is needed (blocks came in since last check),
|
// If a status update is needed (blocks came in since last check),
|
||||||
// update the status of this transaction from the wallet. Otherwise,
|
// update the status of this transaction from the wallet. Otherwise,
|
||||||
// simply re-use the cached status.
|
// simply re-use the cached status.
|
||||||
TRY_LOCK(cs_main, lockMain);
|
interface::WalletTxStatus wtx;
|
||||||
if(lockMain)
|
int numBlocks;
|
||||||
{
|
int64_t adjustedTime;
|
||||||
TRY_LOCK(wallet->cs_wallet, lockWallet);
|
if (wallet.tryGetTxStatus(rec->hash, wtx, numBlocks, adjustedTime) && rec->statusUpdateNeeded(numBlocks)) {
|
||||||
if(lockWallet && rec->statusUpdateNeeded())
|
rec->updateStatus(wtx, numBlocks, adjustedTime);
|
||||||
{
|
|
||||||
std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet.find(rec->hash);
|
|
||||||
|
|
||||||
if(mi != wallet->mapWallet.end())
|
|
||||||
{
|
|
||||||
rec->updateStatus(mi->second);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return rec;
|
return rec;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString describe(TransactionRecord *rec, int unit)
|
QString describe(interface::Node& node, interface::Wallet& wallet, TransactionRecord *rec, int unit)
|
||||||
{
|
{
|
||||||
{
|
return TransactionDesc::toHTML(node, wallet, rec, unit);
|
||||||
LOCK2(cs_main, wallet->cs_wallet);
|
|
||||||
std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet.find(rec->hash);
|
|
||||||
if(mi != wallet->mapWallet.end())
|
|
||||||
{
|
|
||||||
return TransactionDesc::toHTML(wallet, mi->second, rec, unit);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return QString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString getTxHex(TransactionRecord *rec)
|
QString getTxHex(interface::Wallet& wallet, TransactionRecord *rec)
|
||||||
{
|
{
|
||||||
LOCK2(cs_main, wallet->cs_wallet);
|
auto tx = wallet.getTx(rec->hash);
|
||||||
std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet.find(rec->hash);
|
if (tx) {
|
||||||
if(mi != wallet->mapWallet.end())
|
std::string strHex = EncodeHexTx(*tx);
|
||||||
{
|
|
||||||
std::string strHex = EncodeHexTx(*mi->second.tx);
|
|
||||||
return QString::fromStdString(strHex);
|
return QString::fromStdString(strHex);
|
||||||
}
|
}
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
TransactionTableModel::TransactionTableModel(const PlatformStyle *_platformStyle, CWallet* _wallet, WalletModel *parent):
|
TransactionTableModel::TransactionTableModel(const PlatformStyle *_platformStyle, WalletModel *parent):
|
||||||
QAbstractTableModel(parent),
|
QAbstractTableModel(parent),
|
||||||
wallet(_wallet),
|
|
||||||
walletModel(parent),
|
walletModel(parent),
|
||||||
priv(new TransactionTablePriv(_wallet, this)),
|
priv(new TransactionTablePriv(this)),
|
||||||
fProcessingQueuedTransactions(false),
|
fProcessingQueuedTransactions(false),
|
||||||
platformStyle(_platformStyle)
|
platformStyle(_platformStyle)
|
||||||
{
|
{
|
||||||
columns << QString() << QString() << tr("Date") << tr("Type") << tr("Label") << BitcoinUnits::getAmountColumnTitle(walletModel->getOptionsModel()->getDisplayUnit());
|
columns << QString() << QString() << tr("Date") << tr("Type") << tr("Label") << BitcoinUnits::getAmountColumnTitle(walletModel->getOptionsModel()->getDisplayUnit());
|
||||||
priv->refreshWallet();
|
priv->refreshWallet(walletModel->wallet());
|
||||||
|
|
||||||
connect(walletModel->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
|
connect(walletModel->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
|
||||||
|
|
||||||
|
@ -271,7 +249,7 @@ void TransactionTableModel::updateTransaction(const QString &hash, int status, b
|
||||||
uint256 updated;
|
uint256 updated;
|
||||||
updated.SetHex(hash.toStdString());
|
updated.SetHex(hash.toStdString());
|
||||||
|
|
||||||
priv->updateWallet(updated, status, showTransaction);
|
priv->updateWallet(walletModel->wallet(), updated, status, showTransaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TransactionTableModel::updateConfirmations()
|
void TransactionTableModel::updateConfirmations()
|
||||||
|
@ -608,7 +586,7 @@ QVariant TransactionTableModel::data(const QModelIndex &index, int role) const
|
||||||
case WatchonlyDecorationRole:
|
case WatchonlyDecorationRole:
|
||||||
return txWatchonlyDecoration(rec);
|
return txWatchonlyDecoration(rec);
|
||||||
case LongDescriptionRole:
|
case LongDescriptionRole:
|
||||||
return priv->describe(rec, walletModel->getOptionsModel()->getDisplayUnit());
|
return priv->describe(walletModel->node(), walletModel->wallet(), rec, walletModel->getOptionsModel()->getDisplayUnit());
|
||||||
case AddressRole:
|
case AddressRole:
|
||||||
return QString::fromStdString(rec->address);
|
return QString::fromStdString(rec->address);
|
||||||
case LabelRole:
|
case LabelRole:
|
||||||
|
@ -618,7 +596,7 @@ QVariant TransactionTableModel::data(const QModelIndex &index, int role) const
|
||||||
case TxHashRole:
|
case TxHashRole:
|
||||||
return rec->getTxHash();
|
return rec->getTxHash();
|
||||||
case TxHexRole:
|
case TxHexRole:
|
||||||
return priv->getTxHex(rec);
|
return priv->getTxHex(walletModel->wallet(), rec);
|
||||||
case TxPlainTextRole:
|
case TxPlainTextRole:
|
||||||
{
|
{
|
||||||
QString details;
|
QString details;
|
||||||
|
@ -694,10 +672,10 @@ QVariant TransactionTableModel::headerData(int section, Qt::Orientation orientat
|
||||||
QModelIndex TransactionTableModel::index(int row, int column, const QModelIndex &parent) const
|
QModelIndex TransactionTableModel::index(int row, int column, const QModelIndex &parent) const
|
||||||
{
|
{
|
||||||
Q_UNUSED(parent);
|
Q_UNUSED(parent);
|
||||||
TransactionRecord *data = priv->index(row);
|
TransactionRecord *data = priv->index(walletModel->wallet(), row);
|
||||||
if(data)
|
if(data)
|
||||||
{
|
{
|
||||||
return createIndex(row, column, priv->index(row));
|
return createIndex(row, column, priv->index(walletModel->wallet(), row));
|
||||||
}
|
}
|
||||||
return QModelIndex();
|
return QModelIndex();
|
||||||
}
|
}
|
||||||
|
@ -735,13 +713,11 @@ private:
|
||||||
static bool fQueueNotifications = false;
|
static bool fQueueNotifications = false;
|
||||||
static std::vector< TransactionNotification > vQueueNotifications;
|
static std::vector< TransactionNotification > vQueueNotifications;
|
||||||
|
|
||||||
static void NotifyTransactionChanged(TransactionTableModel *ttm, CWallet *wallet, const uint256 &hash, ChangeType status)
|
static void NotifyTransactionChanged(TransactionTableModel *ttm, const uint256 &hash, ChangeType status)
|
||||||
{
|
{
|
||||||
// Find transaction in wallet
|
// Find transaction in wallet
|
||||||
std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet.find(hash);
|
|
||||||
// Determine whether to show transaction or not (determine this here so that no relocking is needed in GUI thread)
|
// Determine whether to show transaction or not (determine this here so that no relocking is needed in GUI thread)
|
||||||
bool inWallet = mi != wallet->mapWallet.end();
|
bool showTransaction = TransactionRecord::showTransaction();
|
||||||
bool showTransaction = (inWallet && TransactionRecord::showTransaction(mi->second));
|
|
||||||
|
|
||||||
TransactionNotification notification(hash, status, showTransaction);
|
TransactionNotification notification(hash, status, showTransaction);
|
||||||
|
|
||||||
|
@ -777,13 +753,13 @@ static void ShowProgress(TransactionTableModel *ttm, const std::string &title, i
|
||||||
void TransactionTableModel::subscribeToCoreSignals()
|
void TransactionTableModel::subscribeToCoreSignals()
|
||||||
{
|
{
|
||||||
// Connect signals to wallet
|
// Connect signals to wallet
|
||||||
wallet->NotifyTransactionChanged.connect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3));
|
m_handler_transaction_changed = walletModel->wallet().handleTransactionChanged(boost::bind(NotifyTransactionChanged, this, _1, _2));
|
||||||
wallet->ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2));
|
m_handler_show_progress = walletModel->wallet().handleShowProgress(boost::bind(ShowProgress, this, _1, _2));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TransactionTableModel::unsubscribeFromCoreSignals()
|
void TransactionTableModel::unsubscribeFromCoreSignals()
|
||||||
{
|
{
|
||||||
// Disconnect signals from wallet
|
// Disconnect signals from wallet
|
||||||
wallet->NotifyTransactionChanged.disconnect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3));
|
m_handler_transaction_changed->disconnect();
|
||||||
wallet->ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2));
|
m_handler_show_progress->disconnect();
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,13 +10,17 @@
|
||||||
#include <QAbstractTableModel>
|
#include <QAbstractTableModel>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace interface {
|
||||||
|
class Handler;
|
||||||
|
}
|
||||||
|
|
||||||
class PlatformStyle;
|
class PlatformStyle;
|
||||||
class TransactionRecord;
|
class TransactionRecord;
|
||||||
class TransactionTablePriv;
|
class TransactionTablePriv;
|
||||||
class WalletModel;
|
class WalletModel;
|
||||||
|
|
||||||
class CWallet;
|
|
||||||
|
|
||||||
/** UI model for the transaction table of a wallet.
|
/** UI model for the transaction table of a wallet.
|
||||||
*/
|
*/
|
||||||
class TransactionTableModel : public QAbstractTableModel
|
class TransactionTableModel : public QAbstractTableModel
|
||||||
|
@ -24,7 +28,7 @@ class TransactionTableModel : public QAbstractTableModel
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit TransactionTableModel(const PlatformStyle *platformStyle, CWallet* wallet, WalletModel *parent = 0);
|
explicit TransactionTableModel(const PlatformStyle *platformStyle, WalletModel *parent = 0);
|
||||||
~TransactionTableModel();
|
~TransactionTableModel();
|
||||||
|
|
||||||
enum ColumnIndex {
|
enum ColumnIndex {
|
||||||
|
@ -80,8 +84,9 @@ public:
|
||||||
bool processingQueuedTransactions() const { return fProcessingQueuedTransactions; }
|
bool processingQueuedTransactions() const { return fProcessingQueuedTransactions; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CWallet* wallet;
|
|
||||||
WalletModel *walletModel;
|
WalletModel *walletModel;
|
||||||
|
std::unique_ptr<interface::Handler> m_handler_transaction_changed;
|
||||||
|
std::unique_ptr<interface::Handler> m_handler_show_progress;
|
||||||
QStringList columns;
|
QStringList columns;
|
||||||
TransactionTablePriv *priv;
|
TransactionTablePriv *priv;
|
||||||
bool fProcessingQueuedTransactions;
|
bool fProcessingQueuedTransactions;
|
||||||
|
|
|
@ -254,7 +254,7 @@ void TransactionView::setModel(WalletModel *_model)
|
||||||
}
|
}
|
||||||
|
|
||||||
// show/hide column Watch-only
|
// show/hide column Watch-only
|
||||||
updateWatchOnlyColumn(_model->haveWatchOnly());
|
updateWatchOnlyColumn(_model->wallet().haveWatchOnly());
|
||||||
|
|
||||||
// Watch-only signal
|
// Watch-only signal
|
||||||
connect(_model, SIGNAL(notifyWatchonlyChanged(bool)), this, SLOT(updateWatchOnlyColumn(bool)));
|
connect(_model, SIGNAL(notifyWatchonlyChanged(bool)), this, SLOT(updateWatchOnlyColumn(bool)));
|
||||||
|
@ -364,7 +364,7 @@ void TransactionView::exportClicked()
|
||||||
// name, column, role
|
// name, column, role
|
||||||
writer.setModel(transactionProxyModel);
|
writer.setModel(transactionProxyModel);
|
||||||
writer.addColumn(tr("Confirmed"), 0, TransactionTableModel::ConfirmedRole);
|
writer.addColumn(tr("Confirmed"), 0, TransactionTableModel::ConfirmedRole);
|
||||||
if (model->haveWatchOnly())
|
if (model->wallet().haveWatchOnly())
|
||||||
writer.addColumn(tr("Watch-only"), TransactionTableModel::Watchonly);
|
writer.addColumn(tr("Watch-only"), TransactionTableModel::Watchonly);
|
||||||
writer.addColumn(tr("Date"), 0, TransactionTableModel::DateRole);
|
writer.addColumn(tr("Date"), 0, TransactionTableModel::DateRole);
|
||||||
writer.addColumn(tr("Type"), TransactionTableModel::Type, Qt::EditRole);
|
writer.addColumn(tr("Type"), TransactionTableModel::Type, Qt::EditRole);
|
||||||
|
@ -393,8 +393,8 @@ void TransactionView::contextualMenu(const QPoint &point)
|
||||||
// check if transaction can be abandoned, disable context menu action in case it doesn't
|
// check if transaction can be abandoned, disable context menu action in case it doesn't
|
||||||
uint256 hash;
|
uint256 hash;
|
||||||
hash.SetHex(selection.at(0).data(TransactionTableModel::TxHashRole).toString().toStdString());
|
hash.SetHex(selection.at(0).data(TransactionTableModel::TxHashRole).toString().toStdString());
|
||||||
abandonAction->setEnabled(model->transactionCanBeAbandoned(hash));
|
abandonAction->setEnabled(model->wallet().transactionCanBeAbandoned(hash));
|
||||||
bumpFeeAction->setEnabled(model->transactionCanBeBumped(hash));
|
bumpFeeAction->setEnabled(model->wallet().transactionCanBeBumped(hash));
|
||||||
|
|
||||||
if(index.isValid())
|
if(index.isValid())
|
||||||
{
|
{
|
||||||
|
@ -414,7 +414,7 @@ void TransactionView::abandonTx()
|
||||||
hash.SetHex(hashQStr.toStdString());
|
hash.SetHex(hashQStr.toStdString());
|
||||||
|
|
||||||
// Abandon the wallet transaction over the walletModel
|
// Abandon the wallet transaction over the walletModel
|
||||||
model->abandonTransaction(hash);
|
model->wallet().abandonTransaction(hash);
|
||||||
|
|
||||||
// Update the table
|
// Update the table
|
||||||
model->getTransactionTableModel()->updateTransaction(hashQStr, CT_UPDATED, false);
|
model->getTransactionTableModel()->updateTransaction(hashQStr, CT_UPDATED, false);
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
#include <clientversion.h>
|
#include <clientversion.h>
|
||||||
#include <init.h>
|
#include <init.h>
|
||||||
|
#include <interface/node.h>
|
||||||
#include <util.h>
|
#include <util.h>
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -31,7 +32,7 @@
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
/** "Help message" or "About" dialog box */
|
/** "Help message" or "About" dialog box */
|
||||||
HelpMessageDialog::HelpMessageDialog(QWidget *parent, bool about) :
|
HelpMessageDialog::HelpMessageDialog(interface::Node& node, QWidget *parent, bool about) :
|
||||||
QDialog(parent),
|
QDialog(parent),
|
||||||
ui(new Ui::HelpMessageDialog)
|
ui(new Ui::HelpMessageDialog)
|
||||||
{
|
{
|
||||||
|
@ -77,7 +78,7 @@ HelpMessageDialog::HelpMessageDialog(QWidget *parent, bool about) :
|
||||||
cursor.insertText(header);
|
cursor.insertText(header);
|
||||||
cursor.insertBlock();
|
cursor.insertBlock();
|
||||||
|
|
||||||
std::string strUsage = HelpMessage(HelpMessageMode::BITCOIN_QT);
|
std::string strUsage = node.helpMessage(HelpMessageMode::BITCOIN_QT);
|
||||||
const bool showDebug = gArgs.GetBoolArg("-help-debug", false);
|
const bool showDebug = gArgs.GetBoolArg("-help-debug", false);
|
||||||
strUsage += HelpMessageGroup(tr("UI Options:").toStdString());
|
strUsage += HelpMessageGroup(tr("UI Options:").toStdString());
|
||||||
if (showDebug) {
|
if (showDebug) {
|
||||||
|
|
|
@ -10,6 +10,10 @@
|
||||||
|
|
||||||
class BitcoinGUI;
|
class BitcoinGUI;
|
||||||
|
|
||||||
|
namespace interface {
|
||||||
|
class Node;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class HelpMessageDialog;
|
class HelpMessageDialog;
|
||||||
}
|
}
|
||||||
|
@ -20,7 +24,7 @@ class HelpMessageDialog : public QDialog
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit HelpMessageDialog(QWidget *parent, bool about);
|
explicit HelpMessageDialog(interface::Node& node, QWidget *parent, bool about);
|
||||||
~HelpMessageDialog();
|
~HelpMessageDialog();
|
||||||
|
|
||||||
void printToConsole();
|
void printToConsole();
|
||||||
|
|
|
@ -5,29 +5,20 @@
|
||||||
#include <qt/walletmodel.h>
|
#include <qt/walletmodel.h>
|
||||||
|
|
||||||
#include <qt/addresstablemodel.h>
|
#include <qt/addresstablemodel.h>
|
||||||
#include <consensus/validation.h>
|
|
||||||
#include <qt/guiconstants.h>
|
#include <qt/guiconstants.h>
|
||||||
#include <qt/guiutil.h>
|
|
||||||
#include <qt/optionsmodel.h>
|
#include <qt/optionsmodel.h>
|
||||||
#include <qt/paymentserver.h>
|
#include <qt/paymentserver.h>
|
||||||
#include <qt/recentrequeststablemodel.h>
|
#include <qt/recentrequeststablemodel.h>
|
||||||
#include <qt/sendcoinsdialog.h>
|
#include <qt/sendcoinsdialog.h>
|
||||||
#include <qt/transactiontablemodel.h>
|
#include <qt/transactiontablemodel.h>
|
||||||
|
|
||||||
#include <chain.h>
|
#include <interface/handler.h>
|
||||||
|
#include <interface/node.h>
|
||||||
#include <key_io.h>
|
#include <key_io.h>
|
||||||
#include <keystore.h>
|
|
||||||
#include <validation.h>
|
|
||||||
#include <net.h> // for g_connman
|
|
||||||
#include <policy/fees.h>
|
|
||||||
#include <policy/rbf.h>
|
|
||||||
#include <sync.h>
|
|
||||||
#include <ui_interface.h>
|
#include <ui_interface.h>
|
||||||
#include <util.h> // for GetBoolArg
|
#include <util.h> // for GetBoolArg
|
||||||
#include <wallet/coincontrol.h>
|
#include <wallet/coincontrol.h>
|
||||||
#include <wallet/feebumper.h>
|
|
||||||
#include <wallet/wallet.h>
|
#include <wallet/wallet.h>
|
||||||
#include <wallet/walletdb.h> // for BackupWallet
|
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
@ -37,21 +28,19 @@
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
|
|
||||||
WalletModel::WalletModel(const PlatformStyle *platformStyle, CWallet *_wallet, OptionsModel *_optionsModel, QObject *parent) :
|
WalletModel::WalletModel(std::unique_ptr<interface::Wallet> wallet, interface::Node& node, const PlatformStyle *platformStyle, OptionsModel *_optionsModel, QObject *parent) :
|
||||||
QObject(parent), wallet(_wallet), optionsModel(_optionsModel), addressTableModel(0),
|
QObject(parent), m_wallet(std::move(wallet)), m_node(node), optionsModel(_optionsModel), addressTableModel(0),
|
||||||
transactionTableModel(0),
|
transactionTableModel(0),
|
||||||
recentRequestsTableModel(0),
|
recentRequestsTableModel(0),
|
||||||
cachedBalance(0), cachedUnconfirmedBalance(0), cachedImmatureBalance(0),
|
|
||||||
cachedWatchOnlyBalance{0}, cachedWatchUnconfBalance{0}, cachedWatchImmatureBalance{0},
|
|
||||||
cachedEncryptionStatus(Unencrypted),
|
cachedEncryptionStatus(Unencrypted),
|
||||||
cachedNumBlocks(0)
|
cachedNumBlocks(0)
|
||||||
{
|
{
|
||||||
fHaveWatchOnly = wallet->HaveWatchOnly();
|
fHaveWatchOnly = m_wallet->haveWatchOnly();
|
||||||
fForceCheckBalanceChanged = false;
|
fForceCheckBalanceChanged = false;
|
||||||
|
|
||||||
addressTableModel = new AddressTableModel(wallet, this);
|
addressTableModel = new AddressTableModel(this);
|
||||||
transactionTableModel = new TransactionTableModel(platformStyle, wallet, this);
|
transactionTableModel = new TransactionTableModel(platformStyle, this);
|
||||||
recentRequestsTableModel = new RecentRequestsTableModel(wallet, this);
|
recentRequestsTableModel = new RecentRequestsTableModel(this);
|
||||||
|
|
||||||
// This timer will be fired repeatedly to update the balance
|
// This timer will be fired repeatedly to update the balance
|
||||||
pollTimer = new QTimer(this);
|
pollTimer = new QTimer(this);
|
||||||
|
@ -66,46 +55,6 @@ WalletModel::~WalletModel()
|
||||||
unsubscribeFromCoreSignals();
|
unsubscribeFromCoreSignals();
|
||||||
}
|
}
|
||||||
|
|
||||||
CAmount WalletModel::getBalance(const CCoinControl *coinControl) const
|
|
||||||
{
|
|
||||||
if (coinControl)
|
|
||||||
{
|
|
||||||
return wallet->GetAvailableBalance(coinControl);
|
|
||||||
}
|
|
||||||
|
|
||||||
return wallet->GetBalance();
|
|
||||||
}
|
|
||||||
|
|
||||||
CAmount WalletModel::getUnconfirmedBalance() const
|
|
||||||
{
|
|
||||||
return wallet->GetUnconfirmedBalance();
|
|
||||||
}
|
|
||||||
|
|
||||||
CAmount WalletModel::getImmatureBalance() const
|
|
||||||
{
|
|
||||||
return wallet->GetImmatureBalance();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WalletModel::haveWatchOnly() const
|
|
||||||
{
|
|
||||||
return fHaveWatchOnly;
|
|
||||||
}
|
|
||||||
|
|
||||||
CAmount WalletModel::getWatchBalance() const
|
|
||||||
{
|
|
||||||
return wallet->GetWatchOnlyBalance();
|
|
||||||
}
|
|
||||||
|
|
||||||
CAmount WalletModel::getWatchUnconfirmedBalance() const
|
|
||||||
{
|
|
||||||
return wallet->GetUnconfirmedWatchOnlyBalance();
|
|
||||||
}
|
|
||||||
|
|
||||||
CAmount WalletModel::getWatchImmatureBalance() const
|
|
||||||
{
|
|
||||||
return wallet->GetImmatureWatchOnlyBalance();
|
|
||||||
}
|
|
||||||
|
|
||||||
void WalletModel::updateStatus()
|
void WalletModel::updateStatus()
|
||||||
{
|
{
|
||||||
EncryptionStatus newEncryptionStatus = getEncryptionStatus();
|
EncryptionStatus newEncryptionStatus = getEncryptionStatus();
|
||||||
|
@ -117,55 +66,34 @@ void WalletModel::updateStatus()
|
||||||
|
|
||||||
void WalletModel::pollBalanceChanged()
|
void WalletModel::pollBalanceChanged()
|
||||||
{
|
{
|
||||||
// Get required locks upfront. This avoids the GUI from getting stuck on
|
// Try to get balances and return early if locks can't be acquired. This
|
||||||
// periodical polls if the core is holding the locks for a longer time -
|
// avoids the GUI from getting stuck on periodical polls if the core is
|
||||||
// for example, during a wallet rescan.
|
// holding the locks for a longer time - for example, during a wallet
|
||||||
TRY_LOCK(cs_main, lockMain);
|
// rescan.
|
||||||
if(!lockMain)
|
interface::WalletBalances new_balances;
|
||||||
return;
|
int numBlocks = -1;
|
||||||
TRY_LOCK(wallet->cs_wallet, lockWallet);
|
if (!m_wallet->tryGetBalances(new_balances, numBlocks)) {
|
||||||
if(!lockWallet)
|
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if(fForceCheckBalanceChanged || chainActive.Height() != cachedNumBlocks)
|
if(fForceCheckBalanceChanged || m_node.getNumBlocks() != cachedNumBlocks)
|
||||||
{
|
{
|
||||||
fForceCheckBalanceChanged = false;
|
fForceCheckBalanceChanged = false;
|
||||||
|
|
||||||
// Balance and number of transactions might have changed
|
// Balance and number of transactions might have changed
|
||||||
cachedNumBlocks = chainActive.Height();
|
cachedNumBlocks = m_node.getNumBlocks();
|
||||||
|
|
||||||
checkBalanceChanged();
|
checkBalanceChanged(new_balances);
|
||||||
if(transactionTableModel)
|
if(transactionTableModel)
|
||||||
transactionTableModel->updateConfirmations();
|
transactionTableModel->updateConfirmations();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WalletModel::checkBalanceChanged()
|
void WalletModel::checkBalanceChanged(const interface::WalletBalances& new_balances)
|
||||||
{
|
{
|
||||||
CAmount newBalance = getBalance();
|
if(new_balances.balanceChanged(m_cached_balances)) {
|
||||||
CAmount newUnconfirmedBalance = getUnconfirmedBalance();
|
m_cached_balances = new_balances;
|
||||||
CAmount newImmatureBalance = getImmatureBalance();
|
Q_EMIT balanceChanged(new_balances);
|
||||||
CAmount newWatchOnlyBalance = 0;
|
|
||||||
CAmount newWatchUnconfBalance = 0;
|
|
||||||
CAmount newWatchImmatureBalance = 0;
|
|
||||||
if (haveWatchOnly())
|
|
||||||
{
|
|
||||||
newWatchOnlyBalance = getWatchBalance();
|
|
||||||
newWatchUnconfBalance = getWatchUnconfirmedBalance();
|
|
||||||
newWatchImmatureBalance = getWatchImmatureBalance();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(cachedBalance != newBalance || cachedUnconfirmedBalance != newUnconfirmedBalance || cachedImmatureBalance != newImmatureBalance ||
|
|
||||||
cachedWatchOnlyBalance != newWatchOnlyBalance || cachedWatchUnconfBalance != newWatchUnconfBalance || cachedWatchImmatureBalance != newWatchImmatureBalance)
|
|
||||||
{
|
|
||||||
cachedBalance = newBalance;
|
|
||||||
cachedUnconfirmedBalance = newUnconfirmedBalance;
|
|
||||||
cachedImmatureBalance = newImmatureBalance;
|
|
||||||
cachedWatchOnlyBalance = newWatchOnlyBalance;
|
|
||||||
cachedWatchUnconfBalance = newWatchUnconfBalance;
|
|
||||||
cachedWatchImmatureBalance = newWatchImmatureBalance;
|
|
||||||
Q_EMIT balanceChanged(newBalance, newUnconfirmedBalance, newImmatureBalance,
|
|
||||||
newWatchOnlyBalance, newWatchUnconfBalance, newWatchImmatureBalance);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,7 +188,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
|
||||||
return DuplicateAddress;
|
return DuplicateAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
CAmount nBalance = getBalance(&coinControl);
|
CAmount nBalance = m_wallet->getAvailableBalance(coinControl);
|
||||||
|
|
||||||
if(total > nBalance)
|
if(total > nBalance)
|
||||||
{
|
{
|
||||||
|
@ -268,22 +196,17 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
LOCK2(cs_main, wallet->cs_wallet);
|
|
||||||
|
|
||||||
transaction.newPossibleKeyChange(wallet);
|
|
||||||
|
|
||||||
CAmount nFeeRequired = 0;
|
CAmount nFeeRequired = 0;
|
||||||
int nChangePosRet = -1;
|
int nChangePosRet = -1;
|
||||||
std::string strFailReason;
|
std::string strFailReason;
|
||||||
|
|
||||||
CTransactionRef& newTx = transaction.getTransaction();
|
auto& newTx = transaction.getWtx();
|
||||||
CReserveKey *keyChange = transaction.getPossibleKeyChange();
|
newTx = m_wallet->createTransaction(vecSend, coinControl, true /* sign */, nChangePosRet, nFeeRequired, strFailReason);
|
||||||
bool fCreated = wallet->CreateTransaction(vecSend, newTx, *keyChange, nFeeRequired, nChangePosRet, strFailReason, coinControl);
|
|
||||||
transaction.setTransactionFee(nFeeRequired);
|
transaction.setTransactionFee(nFeeRequired);
|
||||||
if (fSubtractFeeFromAmount && fCreated)
|
if (fSubtractFeeFromAmount && newTx)
|
||||||
transaction.reassignAmounts(nChangePosRet);
|
transaction.reassignAmounts(nChangePosRet);
|
||||||
|
|
||||||
if(!fCreated)
|
if(!newTx)
|
||||||
{
|
{
|
||||||
if(!fSubtractFeeFromAmount && (total + nFeeRequired) > nBalance)
|
if(!fSubtractFeeFromAmount && (total + nFeeRequired) > nBalance)
|
||||||
{
|
{
|
||||||
|
@ -297,7 +220,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
|
||||||
// reject absurdly high fee. (This can never happen because the
|
// reject absurdly high fee. (This can never happen because the
|
||||||
// wallet caps the fee at maxTxFee. This merely serves as a
|
// wallet caps the fee at maxTxFee. This merely serves as a
|
||||||
// belt-and-suspenders check)
|
// belt-and-suspenders check)
|
||||||
if (nFeeRequired > maxTxFee)
|
if (nFeeRequired > m_node.getMaxTxFee())
|
||||||
return AbsurdFee;
|
return AbsurdFee;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -309,8 +232,6 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran
|
||||||
QByteArray transaction_array; /* store serialized transaction */
|
QByteArray transaction_array; /* store serialized transaction */
|
||||||
|
|
||||||
{
|
{
|
||||||
LOCK2(cs_main, wallet->cs_wallet);
|
|
||||||
|
|
||||||
std::vector<std::pair<std::string, std::string>> vOrderForm;
|
std::vector<std::pair<std::string, std::string>> vOrderForm;
|
||||||
for (const SendCoinsRecipient &rcp : transaction.getRecipients())
|
for (const SendCoinsRecipient &rcp : transaction.getRecipients())
|
||||||
{
|
{
|
||||||
|
@ -330,14 +251,13 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran
|
||||||
vOrderForm.emplace_back("Message", rcp.message.toStdString());
|
vOrderForm.emplace_back("Message", rcp.message.toStdString());
|
||||||
}
|
}
|
||||||
|
|
||||||
CTransactionRef& newTx = transaction.getTransaction();
|
auto& newTx = transaction.getWtx();
|
||||||
CReserveKey *keyChange = transaction.getPossibleKeyChange();
|
std::string rejectReason;
|
||||||
CValidationState state;
|
if (!newTx->commit({} /* mapValue */, std::move(vOrderForm), {} /* fromAccount */, rejectReason))
|
||||||
if (!wallet->CommitTransaction(newTx, {} /* mapValue */, std::move(vOrderForm), {} /* fromAccount */, *keyChange, g_connman.get(), state))
|
return SendCoinsReturn(TransactionCommitFailed, QString::fromStdString(rejectReason));
|
||||||
return SendCoinsReturn(TransactionCommitFailed, QString::fromStdString(state.GetRejectReason()));
|
|
||||||
|
|
||||||
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
|
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
|
||||||
ssTx << newTx;
|
ssTx << newTx->get();
|
||||||
transaction_array.append(&(ssTx[0]), ssTx.size());
|
transaction_array.append(&(ssTx[0]), ssTx.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,24 +272,22 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran
|
||||||
CTxDestination dest = DecodeDestination(strAddress);
|
CTxDestination dest = DecodeDestination(strAddress);
|
||||||
std::string strLabel = rcp.label.toStdString();
|
std::string strLabel = rcp.label.toStdString();
|
||||||
{
|
{
|
||||||
LOCK(wallet->cs_wallet);
|
|
||||||
|
|
||||||
std::map<CTxDestination, CAddressBookData>::iterator mi = wallet->mapAddressBook.find(dest);
|
|
||||||
|
|
||||||
// Check if we have a new address or an updated label
|
// Check if we have a new address or an updated label
|
||||||
if (mi == wallet->mapAddressBook.end())
|
std::string name;
|
||||||
|
if (!m_wallet->getAddress(dest, &name))
|
||||||
{
|
{
|
||||||
wallet->SetAddressBook(dest, strLabel, "send");
|
m_wallet->setAddressBook(dest, strLabel, "send");
|
||||||
}
|
}
|
||||||
else if (mi->second.name != strLabel)
|
else if (name != strLabel)
|
||||||
{
|
{
|
||||||
wallet->SetAddressBook(dest, strLabel, ""); // "" means don't change purpose
|
m_wallet->setAddressBook(dest, strLabel, ""); // "" means don't change purpose
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Q_EMIT coinsSent(wallet, rcp, transaction_array);
|
Q_EMIT coinsSent(this, rcp, transaction_array);
|
||||||
}
|
}
|
||||||
checkBalanceChanged(); // update balance immediately, otherwise there could be a short noticeable delay until pollBalanceChanged hits
|
|
||||||
|
checkBalanceChanged(m_wallet->getBalances()); // update balance immediately, otherwise there could be a short noticeable delay until pollBalanceChanged hits
|
||||||
|
|
||||||
return SendCoinsReturn(OK);
|
return SendCoinsReturn(OK);
|
||||||
}
|
}
|
||||||
|
@ -396,11 +314,11 @@ RecentRequestsTableModel *WalletModel::getRecentRequestsTableModel()
|
||||||
|
|
||||||
WalletModel::EncryptionStatus WalletModel::getEncryptionStatus() const
|
WalletModel::EncryptionStatus WalletModel::getEncryptionStatus() const
|
||||||
{
|
{
|
||||||
if(!wallet->IsCrypted())
|
if(!m_wallet->isCrypted())
|
||||||
{
|
{
|
||||||
return Unencrypted;
|
return Unencrypted;
|
||||||
}
|
}
|
||||||
else if(wallet->IsLocked())
|
else if(m_wallet->isLocked())
|
||||||
{
|
{
|
||||||
return Locked;
|
return Locked;
|
||||||
}
|
}
|
||||||
|
@ -415,7 +333,7 @@ bool WalletModel::setWalletEncrypted(bool encrypted, const SecureString &passphr
|
||||||
if(encrypted)
|
if(encrypted)
|
||||||
{
|
{
|
||||||
// Encrypt
|
// Encrypt
|
||||||
return wallet->EncryptWallet(passphrase);
|
return m_wallet->encryptWallet(passphrase);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -429,39 +347,29 @@ bool WalletModel::setWalletLocked(bool locked, const SecureString &passPhrase)
|
||||||
if(locked)
|
if(locked)
|
||||||
{
|
{
|
||||||
// Lock
|
// Lock
|
||||||
return wallet->Lock();
|
return m_wallet->lock();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Unlock
|
// Unlock
|
||||||
return wallet->Unlock(passPhrase);
|
return m_wallet->unlock(passPhrase);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WalletModel::changePassphrase(const SecureString &oldPass, const SecureString &newPass)
|
bool WalletModel::changePassphrase(const SecureString &oldPass, const SecureString &newPass)
|
||||||
{
|
{
|
||||||
bool retval;
|
m_wallet->lock(); // Make sure wallet is locked before attempting pass change
|
||||||
{
|
return m_wallet->changeWalletPassphrase(oldPass, newPass);
|
||||||
LOCK(wallet->cs_wallet);
|
|
||||||
wallet->Lock(); // Make sure wallet is locked before attempting pass change
|
|
||||||
retval = wallet->ChangeWalletPassphrase(oldPass, newPass);
|
|
||||||
}
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WalletModel::backupWallet(const QString &filename)
|
|
||||||
{
|
|
||||||
return wallet->BackupWallet(filename.toLocal8Bit().data());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handlers for core signals
|
// Handlers for core signals
|
||||||
static void NotifyKeyStoreStatusChanged(WalletModel *walletmodel, CCryptoKeyStore *wallet)
|
static void NotifyKeyStoreStatusChanged(WalletModel *walletmodel)
|
||||||
{
|
{
|
||||||
qDebug() << "NotifyKeyStoreStatusChanged";
|
qDebug() << "NotifyKeyStoreStatusChanged";
|
||||||
QMetaObject::invokeMethod(walletmodel, "updateStatus", Qt::QueuedConnection);
|
QMetaObject::invokeMethod(walletmodel, "updateStatus", Qt::QueuedConnection);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void NotifyAddressBookChanged(WalletModel *walletmodel, CWallet *wallet,
|
static void NotifyAddressBookChanged(WalletModel *walletmodel,
|
||||||
const CTxDestination &address, const std::string &label, bool isMine,
|
const CTxDestination &address, const std::string &label, bool isMine,
|
||||||
const std::string &purpose, ChangeType status)
|
const std::string &purpose, ChangeType status)
|
||||||
{
|
{
|
||||||
|
@ -478,9 +386,8 @@ static void NotifyAddressBookChanged(WalletModel *walletmodel, CWallet *wallet,
|
||||||
Q_ARG(int, status));
|
Q_ARG(int, status));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void NotifyTransactionChanged(WalletModel *walletmodel, CWallet *wallet, const uint256 &hash, ChangeType status)
|
static void NotifyTransactionChanged(WalletModel *walletmodel, const uint256 &hash, ChangeType status)
|
||||||
{
|
{
|
||||||
Q_UNUSED(wallet);
|
|
||||||
Q_UNUSED(hash);
|
Q_UNUSED(hash);
|
||||||
Q_UNUSED(status);
|
Q_UNUSED(status);
|
||||||
QMetaObject::invokeMethod(walletmodel, "updateTransaction", Qt::QueuedConnection);
|
QMetaObject::invokeMethod(walletmodel, "updateTransaction", Qt::QueuedConnection);
|
||||||
|
@ -503,21 +410,21 @@ static void NotifyWatchonlyChanged(WalletModel *walletmodel, bool fHaveWatchonly
|
||||||
void WalletModel::subscribeToCoreSignals()
|
void WalletModel::subscribeToCoreSignals()
|
||||||
{
|
{
|
||||||
// Connect signals to wallet
|
// Connect signals to wallet
|
||||||
wallet->NotifyStatusChanged.connect(boost::bind(&NotifyKeyStoreStatusChanged, this, _1));
|
m_handler_status_changed = m_wallet->handleStatusChanged(boost::bind(&NotifyKeyStoreStatusChanged, this));
|
||||||
wallet->NotifyAddressBookChanged.connect(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4, _5, _6));
|
m_handler_address_book_changed = m_wallet->handleAddressBookChanged(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4, _5));
|
||||||
wallet->NotifyTransactionChanged.connect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3));
|
m_handler_transaction_changed = m_wallet->handleTransactionChanged(boost::bind(NotifyTransactionChanged, this, _1, _2));
|
||||||
wallet->ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2));
|
m_handler_show_progress = m_wallet->handleShowProgress(boost::bind(ShowProgress, this, _1, _2));
|
||||||
wallet->NotifyWatchonlyChanged.connect(boost::bind(NotifyWatchonlyChanged, this, _1));
|
m_handler_watch_only_changed = m_wallet->handleWatchOnlyChanged(boost::bind(NotifyWatchonlyChanged, this, _1));
|
||||||
}
|
}
|
||||||
|
|
||||||
void WalletModel::unsubscribeFromCoreSignals()
|
void WalletModel::unsubscribeFromCoreSignals()
|
||||||
{
|
{
|
||||||
// Disconnect signals from wallet
|
// Disconnect signals from wallet
|
||||||
wallet->NotifyStatusChanged.disconnect(boost::bind(&NotifyKeyStoreStatusChanged, this, _1));
|
m_handler_status_changed->disconnect();
|
||||||
wallet->NotifyAddressBookChanged.disconnect(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4, _5, _6));
|
m_handler_address_book_changed->disconnect();
|
||||||
wallet->NotifyTransactionChanged.disconnect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3));
|
m_handler_transaction_changed->disconnect();
|
||||||
wallet->ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2));
|
m_handler_show_progress->disconnect();
|
||||||
wallet->NotifyWatchonlyChanged.disconnect(boost::bind(NotifyWatchonlyChanged, this, _1));
|
m_handler_watch_only_changed->disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
// WalletModel::UnlockContext implementation
|
// WalletModel::UnlockContext implementation
|
||||||
|
@ -557,80 +464,9 @@ void WalletModel::UnlockContext::CopyFrom(const UnlockContext& rhs)
|
||||||
rhs.relock = false;
|
rhs.relock = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WalletModel::getPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const
|
|
||||||
{
|
|
||||||
return wallet->GetPubKey(address, vchPubKeyOut);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WalletModel::IsSpendable(const CTxDestination& dest) const
|
|
||||||
{
|
|
||||||
return IsMine(*wallet, dest) & ISMINE_SPENDABLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WalletModel::getPrivKey(const CKeyID &address, CKey& vchPrivKeyOut) const
|
|
||||||
{
|
|
||||||
return wallet->GetKey(address, vchPrivKeyOut);
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns a list of COutputs from COutPoints
|
|
||||||
void WalletModel::getOutputs(const std::vector<COutPoint>& vOutpoints, std::vector<COutput>& vOutputs)
|
|
||||||
{
|
|
||||||
LOCK2(cs_main, wallet->cs_wallet);
|
|
||||||
for (const COutPoint& outpoint : vOutpoints)
|
|
||||||
{
|
|
||||||
auto it = wallet->mapWallet.find(outpoint.hash);
|
|
||||||
if (it == wallet->mapWallet.end()) continue;
|
|
||||||
int nDepth = it->second.GetDepthInMainChain();
|
|
||||||
if (nDepth < 0) continue;
|
|
||||||
COutput out(&it->second, outpoint.n, nDepth, true /* spendable */, true /* solvable */, true /* safe */);
|
|
||||||
vOutputs.push_back(out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WalletModel::isSpent(const COutPoint& outpoint) const
|
|
||||||
{
|
|
||||||
LOCK2(cs_main, wallet->cs_wallet);
|
|
||||||
return wallet->IsSpent(outpoint.hash, outpoint.n);
|
|
||||||
}
|
|
||||||
|
|
||||||
// AvailableCoins + LockedCoins grouped by wallet address (put change in one group with wallet address)
|
|
||||||
void WalletModel::listCoins(std::map<QString, std::vector<COutput> >& mapCoins) const
|
|
||||||
{
|
|
||||||
for (auto& group : wallet->ListCoins()) {
|
|
||||||
auto& resultGroup = mapCoins[QString::fromStdString(EncodeDestination(group.first))];
|
|
||||||
for (auto& coin : group.second) {
|
|
||||||
resultGroup.emplace_back(std::move(coin));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WalletModel::isLockedCoin(uint256 hash, unsigned int n) const
|
|
||||||
{
|
|
||||||
LOCK2(cs_main, wallet->cs_wallet);
|
|
||||||
return wallet->IsLockedCoin(hash, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WalletModel::lockCoin(COutPoint& output)
|
|
||||||
{
|
|
||||||
LOCK2(cs_main, wallet->cs_wallet);
|
|
||||||
wallet->LockCoin(output);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WalletModel::unlockCoin(COutPoint& output)
|
|
||||||
{
|
|
||||||
LOCK2(cs_main, wallet->cs_wallet);
|
|
||||||
wallet->UnlockCoin(output);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WalletModel::listLockedCoins(std::vector<COutPoint>& vOutpts)
|
|
||||||
{
|
|
||||||
LOCK2(cs_main, wallet->cs_wallet);
|
|
||||||
wallet->ListLockedCoins(vOutpts);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WalletModel::loadReceiveRequests(std::vector<std::string>& vReceiveRequests)
|
void WalletModel::loadReceiveRequests(std::vector<std::string>& vReceiveRequests)
|
||||||
{
|
{
|
||||||
vReceiveRequests = wallet->GetDestValues("rr"); // receive request
|
vReceiveRequests = m_wallet->getDestValues("rr"); // receive request
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WalletModel::saveReceiveRequest(const std::string &sAddress, const int64_t nId, const std::string &sRequest)
|
bool WalletModel::saveReceiveRequest(const std::string &sAddress, const int64_t nId, const std::string &sRequest)
|
||||||
|
@ -641,27 +477,10 @@ bool WalletModel::saveReceiveRequest(const std::string &sAddress, const int64_t
|
||||||
ss << nId;
|
ss << nId;
|
||||||
std::string key = "rr" + ss.str(); // "rr" prefix = "receive request" in destdata
|
std::string key = "rr" + ss.str(); // "rr" prefix = "receive request" in destdata
|
||||||
|
|
||||||
LOCK(wallet->cs_wallet);
|
|
||||||
if (sRequest.empty())
|
if (sRequest.empty())
|
||||||
return wallet->EraseDestData(dest, key);
|
return m_wallet->eraseDestData(dest, key);
|
||||||
else
|
else
|
||||||
return wallet->AddDestData(dest, key, sRequest);
|
return m_wallet->addDestData(dest, key, sRequest);
|
||||||
}
|
|
||||||
|
|
||||||
bool WalletModel::transactionCanBeAbandoned(uint256 hash) const
|
|
||||||
{
|
|
||||||
return wallet->TransactionCanBeAbandoned(hash);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WalletModel::abandonTransaction(uint256 hash) const
|
|
||||||
{
|
|
||||||
LOCK2(cs_main, wallet->cs_wallet);
|
|
||||||
return wallet->AbandonTransaction(hash);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WalletModel::transactionCanBeBumped(uint256 hash) const
|
|
||||||
{
|
|
||||||
return feebumper::TransactionCanBeBumped(wallet, hash);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WalletModel::bumpFee(uint256 hash)
|
bool WalletModel::bumpFee(uint256 hash)
|
||||||
|
@ -672,7 +491,7 @@ bool WalletModel::bumpFee(uint256 hash)
|
||||||
CAmount old_fee;
|
CAmount old_fee;
|
||||||
CAmount new_fee;
|
CAmount new_fee;
|
||||||
CMutableTransaction mtx;
|
CMutableTransaction mtx;
|
||||||
if (feebumper::CreateTransaction(wallet, hash, coin_control, 0 /* totalFee */, errors, old_fee, new_fee, mtx) != feebumper::Result::OK) {
|
if (!m_wallet->createBumpTransaction(hash, coin_control, 0 /* totalFee */, errors, old_fee, new_fee, mtx)) {
|
||||||
QMessageBox::critical(0, tr("Fee bump error"), tr("Increasing transaction fee failed") + "<br />(" +
|
QMessageBox::critical(0, tr("Fee bump error"), tr("Increasing transaction fee failed") + "<br />(" +
|
||||||
(errors.size() ? QString::fromStdString(errors[0]) : "") +")");
|
(errors.size() ? QString::fromStdString(errors[0]) : "") +")");
|
||||||
return false;
|
return false;
|
||||||
|
@ -711,13 +530,13 @@ bool WalletModel::bumpFee(uint256 hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// sign bumped transaction
|
// sign bumped transaction
|
||||||
if (!feebumper::SignTransaction(wallet, mtx)) {
|
if (!m_wallet->signBumpTransaction(mtx)) {
|
||||||
QMessageBox::critical(0, tr("Fee bump error"), tr("Can't sign transaction."));
|
QMessageBox::critical(0, tr("Fee bump error"), tr("Can't sign transaction."));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// commit the bumped transaction
|
// commit the bumped transaction
|
||||||
uint256 txid;
|
uint256 txid;
|
||||||
if (feebumper::CommitTransaction(wallet, hash, std::move(mtx), errors, txid) != feebumper::Result::OK) {
|
if(!m_wallet->commitBumpTransaction(hash, std::move(mtx), errors, txid)) {
|
||||||
QMessageBox::critical(0, tr("Fee bump error"), tr("Could not commit transaction") + "<br />(" +
|
QMessageBox::critical(0, tr("Fee bump error"), tr("Could not commit transaction") + "<br />(" +
|
||||||
QString::fromStdString(errors[0])+")");
|
QString::fromStdString(errors[0])+")");
|
||||||
return false;
|
return false;
|
||||||
|
@ -730,28 +549,12 @@ bool WalletModel::isWalletEnabled()
|
||||||
return !gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET);
|
return !gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WalletModel::hdEnabled() const
|
|
||||||
{
|
|
||||||
return wallet->IsHDEnabled();
|
|
||||||
}
|
|
||||||
|
|
||||||
OutputType WalletModel::getDefaultAddressType() const
|
|
||||||
{
|
|
||||||
return wallet->m_default_address_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
int WalletModel::getDefaultConfirmTarget() const
|
|
||||||
{
|
|
||||||
return nTxConfirmTarget;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString WalletModel::getWalletName() const
|
QString WalletModel::getWalletName() const
|
||||||
{
|
{
|
||||||
LOCK(wallet->cs_wallet);
|
return QString::fromStdString(m_wallet->getWalletName());
|
||||||
return QString::fromStdString(wallet->GetName());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WalletModel::isMultiwallet()
|
bool WalletModel::isMultiwallet()
|
||||||
{
|
{
|
||||||
return gArgs.GetArgs("-wallet").size() > 1;
|
return m_node.getWallets().size() > 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <qt/paymentrequestplus.h>
|
#include <qt/paymentrequestplus.h>
|
||||||
#include <qt/walletmodeltransaction.h>
|
#include <qt/walletmodeltransaction.h>
|
||||||
|
|
||||||
|
#include <interface/wallet.h>
|
||||||
#include <support/allocators/secure.h>
|
#include <support/allocators/secure.h>
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
@ -34,9 +35,12 @@ class CKeyID;
|
||||||
class COutPoint;
|
class COutPoint;
|
||||||
class COutput;
|
class COutput;
|
||||||
class CPubKey;
|
class CPubKey;
|
||||||
class CWallet;
|
|
||||||
class uint256;
|
class uint256;
|
||||||
|
|
||||||
|
namespace interface {
|
||||||
|
class Node;
|
||||||
|
} // namespace interface
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
class QTimer;
|
class QTimer;
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
@ -107,7 +111,7 @@ class WalletModel : public QObject
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit WalletModel(const PlatformStyle *platformStyle, CWallet *wallet, OptionsModel *optionsModel, QObject *parent = 0);
|
explicit WalletModel(std::unique_ptr<interface::Wallet> wallet, interface::Node& node, const PlatformStyle *platformStyle, OptionsModel *optionsModel, QObject *parent = 0);
|
||||||
~WalletModel();
|
~WalletModel();
|
||||||
|
|
||||||
enum StatusCode // Returned by sendCoins
|
enum StatusCode // Returned by sendCoins
|
||||||
|
@ -136,15 +140,6 @@ public:
|
||||||
TransactionTableModel *getTransactionTableModel();
|
TransactionTableModel *getTransactionTableModel();
|
||||||
RecentRequestsTableModel *getRecentRequestsTableModel();
|
RecentRequestsTableModel *getRecentRequestsTableModel();
|
||||||
|
|
||||||
CWallet *getWallet() const { return wallet; };
|
|
||||||
|
|
||||||
CAmount getBalance(const CCoinControl *coinControl = nullptr) const;
|
|
||||||
CAmount getUnconfirmedBalance() const;
|
|
||||||
CAmount getImmatureBalance() const;
|
|
||||||
bool haveWatchOnly() const;
|
|
||||||
CAmount getWatchBalance() const;
|
|
||||||
CAmount getWatchUnconfirmedBalance() const;
|
|
||||||
CAmount getWatchImmatureBalance() const;
|
|
||||||
EncryptionStatus getEncryptionStatus() const;
|
EncryptionStatus getEncryptionStatus() const;
|
||||||
|
|
||||||
// Check address for validity
|
// Check address for validity
|
||||||
|
@ -173,8 +168,6 @@ public:
|
||||||
// Passphrase only needed when unlocking
|
// Passphrase only needed when unlocking
|
||||||
bool setWalletLocked(bool locked, const SecureString &passPhrase=SecureString());
|
bool setWalletLocked(bool locked, const SecureString &passPhrase=SecureString());
|
||||||
bool changePassphrase(const SecureString &oldPass, const SecureString &newPass);
|
bool changePassphrase(const SecureString &oldPass, const SecureString &newPass);
|
||||||
// Wallet backup
|
|
||||||
bool backupWallet(const QString &filename);
|
|
||||||
|
|
||||||
// RAI object for unlocking wallet, returned by requestUnlock()
|
// RAI object for unlocking wallet, returned by requestUnlock()
|
||||||
class UnlockContext
|
class UnlockContext
|
||||||
|
@ -198,40 +191,28 @@ public:
|
||||||
|
|
||||||
UnlockContext requestUnlock();
|
UnlockContext requestUnlock();
|
||||||
|
|
||||||
bool getPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const;
|
|
||||||
bool IsSpendable(const CTxDestination& dest) const;
|
|
||||||
bool getPrivKey(const CKeyID &address, CKey& vchPrivKeyOut) const;
|
|
||||||
void getOutputs(const std::vector<COutPoint>& vOutpoints, std::vector<COutput>& vOutputs);
|
|
||||||
bool isSpent(const COutPoint& outpoint) const;
|
|
||||||
void listCoins(std::map<QString, std::vector<COutput> >& mapCoins) const;
|
|
||||||
|
|
||||||
bool isLockedCoin(uint256 hash, unsigned int n) const;
|
|
||||||
void lockCoin(COutPoint& output);
|
|
||||||
void unlockCoin(COutPoint& output);
|
|
||||||
void listLockedCoins(std::vector<COutPoint>& vOutpts);
|
|
||||||
|
|
||||||
void loadReceiveRequests(std::vector<std::string>& vReceiveRequests);
|
void loadReceiveRequests(std::vector<std::string>& vReceiveRequests);
|
||||||
bool saveReceiveRequest(const std::string &sAddress, const int64_t nId, const std::string &sRequest);
|
bool saveReceiveRequest(const std::string &sAddress, const int64_t nId, const std::string &sRequest);
|
||||||
|
|
||||||
bool transactionCanBeAbandoned(uint256 hash) const;
|
|
||||||
bool abandonTransaction(uint256 hash) const;
|
|
||||||
|
|
||||||
bool transactionCanBeBumped(uint256 hash) const;
|
|
||||||
bool bumpFee(uint256 hash);
|
bool bumpFee(uint256 hash);
|
||||||
|
|
||||||
static bool isWalletEnabled();
|
static bool isWalletEnabled();
|
||||||
|
|
||||||
bool hdEnabled() const;
|
interface::Node& node() const { return m_node; }
|
||||||
|
interface::Wallet& wallet() const { return *m_wallet; }
|
||||||
OutputType getDefaultAddressType() const;
|
|
||||||
|
|
||||||
int getDefaultConfirmTarget() const;
|
|
||||||
|
|
||||||
QString getWalletName() const;
|
QString getWalletName() const;
|
||||||
|
|
||||||
static bool isMultiwallet();
|
bool isMultiwallet();
|
||||||
private:
|
private:
|
||||||
CWallet *wallet;
|
std::unique_ptr<interface::Wallet> m_wallet;
|
||||||
|
std::unique_ptr<interface::Handler> m_handler_status_changed;
|
||||||
|
std::unique_ptr<interface::Handler> m_handler_address_book_changed;
|
||||||
|
std::unique_ptr<interface::Handler> m_handler_transaction_changed;
|
||||||
|
std::unique_ptr<interface::Handler> m_handler_show_progress;
|
||||||
|
std::unique_ptr<interface::Handler> m_handler_watch_only_changed;
|
||||||
|
interface::Node& m_node;
|
||||||
|
|
||||||
bool fHaveWatchOnly;
|
bool fHaveWatchOnly;
|
||||||
bool fForceCheckBalanceChanged;
|
bool fForceCheckBalanceChanged;
|
||||||
|
|
||||||
|
@ -244,12 +225,7 @@ private:
|
||||||
RecentRequestsTableModel *recentRequestsTableModel;
|
RecentRequestsTableModel *recentRequestsTableModel;
|
||||||
|
|
||||||
// Cache some values to be able to detect changes
|
// Cache some values to be able to detect changes
|
||||||
CAmount cachedBalance;
|
interface::WalletBalances m_cached_balances;
|
||||||
CAmount cachedUnconfirmedBalance;
|
|
||||||
CAmount cachedImmatureBalance;
|
|
||||||
CAmount cachedWatchOnlyBalance;
|
|
||||||
CAmount cachedWatchUnconfBalance;
|
|
||||||
CAmount cachedWatchImmatureBalance;
|
|
||||||
EncryptionStatus cachedEncryptionStatus;
|
EncryptionStatus cachedEncryptionStatus;
|
||||||
int cachedNumBlocks;
|
int cachedNumBlocks;
|
||||||
|
|
||||||
|
@ -257,12 +233,11 @@ private:
|
||||||
|
|
||||||
void subscribeToCoreSignals();
|
void subscribeToCoreSignals();
|
||||||
void unsubscribeFromCoreSignals();
|
void unsubscribeFromCoreSignals();
|
||||||
void checkBalanceChanged();
|
void checkBalanceChanged(const interface::WalletBalances& new_balances);
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
// Signal that balance in wallet changed
|
// Signal that balance in wallet changed
|
||||||
void balanceChanged(const CAmount& balance, const CAmount& unconfirmedBalance, const CAmount& immatureBalance,
|
void balanceChanged(const interface::WalletBalances& balances);
|
||||||
const CAmount& watchOnlyBalance, const CAmount& watchUnconfBalance, const CAmount& watchImmatureBalance);
|
|
||||||
|
|
||||||
// Encryption status of wallet changed
|
// Encryption status of wallet changed
|
||||||
void encryptionStatusChanged();
|
void encryptionStatusChanged();
|
||||||
|
@ -276,7 +251,7 @@ Q_SIGNALS:
|
||||||
void message(const QString &title, const QString &message, unsigned int style);
|
void message(const QString &title, const QString &message, unsigned int style);
|
||||||
|
|
||||||
// Coins sent: from wallet, to recipient, in (serialized) transaction:
|
// Coins sent: from wallet, to recipient, in (serialized) transaction:
|
||||||
void coinsSent(CWallet* wallet, SendCoinsRecipient recipient, QByteArray transaction);
|
void coinsSent(WalletModel* wallet, SendCoinsRecipient recipient, QByteArray transaction);
|
||||||
|
|
||||||
// Show progress dialog e.g. for rescan
|
// Show progress dialog e.g. for rescan
|
||||||
void showProgress(const QString &title, int nProgress);
|
void showProgress(const QString &title, int nProgress);
|
||||||
|
|
|
@ -4,12 +4,11 @@
|
||||||
|
|
||||||
#include <qt/walletmodeltransaction.h>
|
#include <qt/walletmodeltransaction.h>
|
||||||
|
|
||||||
|
#include <interface/node.h>
|
||||||
#include <policy/policy.h>
|
#include <policy/policy.h>
|
||||||
#include <wallet/wallet.h>
|
|
||||||
|
|
||||||
WalletModelTransaction::WalletModelTransaction(const QList<SendCoinsRecipient> &_recipients) :
|
WalletModelTransaction::WalletModelTransaction(const QList<SendCoinsRecipient> &_recipients) :
|
||||||
recipients(_recipients),
|
recipients(_recipients),
|
||||||
walletTransaction(0),
|
|
||||||
fee(0)
|
fee(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -19,14 +18,14 @@ QList<SendCoinsRecipient> WalletModelTransaction::getRecipients() const
|
||||||
return recipients;
|
return recipients;
|
||||||
}
|
}
|
||||||
|
|
||||||
CTransactionRef& WalletModelTransaction::getTransaction()
|
std::unique_ptr<interface::PendingWalletTx>& WalletModelTransaction::getWtx()
|
||||||
{
|
{
|
||||||
return walletTransaction;
|
return wtx;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int WalletModelTransaction::getTransactionSize()
|
unsigned int WalletModelTransaction::getTransactionSize()
|
||||||
{
|
{
|
||||||
return (!walletTransaction ? 0 : ::GetVirtualTransactionSize(*walletTransaction));
|
return wtx ? wtx->getVirtualSize() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
CAmount WalletModelTransaction::getTransactionFee() const
|
CAmount WalletModelTransaction::getTransactionFee() const
|
||||||
|
@ -41,6 +40,7 @@ void WalletModelTransaction::setTransactionFee(const CAmount& newFee)
|
||||||
|
|
||||||
void WalletModelTransaction::reassignAmounts(int nChangePosRet)
|
void WalletModelTransaction::reassignAmounts(int nChangePosRet)
|
||||||
{
|
{
|
||||||
|
const CTransaction* walletTransaction = &wtx->get();
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (QList<SendCoinsRecipient>::iterator it = recipients.begin(); it != recipients.end(); ++it)
|
for (QList<SendCoinsRecipient>::iterator it = recipients.begin(); it != recipients.end(); ++it)
|
||||||
{
|
{
|
||||||
|
@ -80,13 +80,3 @@ CAmount WalletModelTransaction::getTotalTransactionAmount() const
|
||||||
}
|
}
|
||||||
return totalTransactionAmount;
|
return totalTransactionAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WalletModelTransaction::newPossibleKeyChange(CWallet *wallet)
|
|
||||||
{
|
|
||||||
keyChange.reset(new CReserveKey(wallet));
|
|
||||||
}
|
|
||||||
|
|
||||||
CReserveKey *WalletModelTransaction::getPossibleKeyChange()
|
|
||||||
{
|
|
||||||
return keyChange.get();
|
|
||||||
}
|
|
||||||
|
|
|
@ -13,9 +13,10 @@
|
||||||
|
|
||||||
class SendCoinsRecipient;
|
class SendCoinsRecipient;
|
||||||
|
|
||||||
class CReserveKey;
|
namespace interface {
|
||||||
class CWallet;
|
class Node;
|
||||||
class CWalletTx;
|
class PendingWalletTx;
|
||||||
|
}
|
||||||
|
|
||||||
/** Data model for a walletmodel transaction. */
|
/** Data model for a walletmodel transaction. */
|
||||||
class WalletModelTransaction
|
class WalletModelTransaction
|
||||||
|
@ -25,7 +26,7 @@ public:
|
||||||
|
|
||||||
QList<SendCoinsRecipient> getRecipients() const;
|
QList<SendCoinsRecipient> getRecipients() const;
|
||||||
|
|
||||||
CTransactionRef& getTransaction();
|
std::unique_ptr<interface::PendingWalletTx>& getWtx();
|
||||||
unsigned int getTransactionSize();
|
unsigned int getTransactionSize();
|
||||||
|
|
||||||
void setTransactionFee(const CAmount& newFee);
|
void setTransactionFee(const CAmount& newFee);
|
||||||
|
@ -33,15 +34,11 @@ public:
|
||||||
|
|
||||||
CAmount getTotalTransactionAmount() const;
|
CAmount getTotalTransactionAmount() const;
|
||||||
|
|
||||||
void newPossibleKeyChange(CWallet *wallet);
|
|
||||||
CReserveKey *getPossibleKeyChange();
|
|
||||||
|
|
||||||
void reassignAmounts(int nChangePosRet); // needed for the subtract-fee-from-amount feature
|
void reassignAmounts(int nChangePosRet); // needed for the subtract-fee-from-amount feature
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QList<SendCoinsRecipient> recipients;
|
QList<SendCoinsRecipient> recipients;
|
||||||
CTransactionRef walletTransaction;
|
std::unique_ptr<interface::PendingWalletTx> wtx;
|
||||||
std::unique_ptr<CReserveKey> keyChange;
|
|
||||||
CAmount fee;
|
CAmount fee;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include <qt/transactionview.h>
|
#include <qt/transactionview.h>
|
||||||
#include <qt/walletmodel.h>
|
#include <qt/walletmodel.h>
|
||||||
|
|
||||||
|
#include <interface/node.h>
|
||||||
#include <ui_interface.h>
|
#include <ui_interface.h>
|
||||||
|
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
|
@ -158,7 +159,7 @@ void WalletView::setWalletModel(WalletModel *_walletModel)
|
||||||
void WalletView::processNewTransaction(const QModelIndex& parent, int start, int /*end*/)
|
void WalletView::processNewTransaction(const QModelIndex& parent, int start, int /*end*/)
|
||||||
{
|
{
|
||||||
// Prevent balloon-spam when initial block download is in progress
|
// Prevent balloon-spam when initial block download is in progress
|
||||||
if (!walletModel || !clientModel || clientModel->inInitialBlockDownload())
|
if (!walletModel || !clientModel || clientModel->node().isInitialBlockDownload())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
TransactionTableModel *ttm = walletModel->getTransactionTableModel();
|
TransactionTableModel *ttm = walletModel->getTransactionTableModel();
|
||||||
|
@ -257,7 +258,7 @@ void WalletView::backupWallet()
|
||||||
if (filename.isEmpty())
|
if (filename.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!walletModel->backupWallet(filename)) {
|
if (!walletModel->wallet().backupWallet(filename.toLocal8Bit().data())) {
|
||||||
Q_EMIT message(tr("Backup Failed"), tr("There was an error trying to save the wallet data to %1.").arg(filename),
|
Q_EMIT message(tr("Backup Failed"), tr("There was an error trying to save the wallet data to %1.").arg(filename),
|
||||||
CClientUIInterface::MSG_ERROR);
|
CClientUIInterface::MSG_ERROR);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue