aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build_msvc/libbitcoin_server/libbitcoin_server.vcxproj.in6
-rw-r--r--doc/README.md2
-rw-r--r--src/Makefile.qt.include12
-rw-r--r--src/Makefile.qttest.include3
-rw-r--r--src/addrman.h30
-rw-r--r--src/chainparams.cpp6
-rw-r--r--src/httpserver.cpp1
-rw-r--r--src/index/base.cpp6
-rw-r--r--src/index/txindex.cpp3
-rw-r--r--src/init.cpp8
-rw-r--r--src/net.cpp19
-rw-r--r--src/net.h22
-rw-r--r--src/protocol.h1
-rw-r--r--src/qt/bantablemodel.cpp6
-rw-r--r--src/qt/bitcoin.cpp144
-rw-r--r--src/qt/bitcoin.h127
-rw-r--r--src/qt/bitcoingui.cpp31
-rw-r--r--src/qt/bitcoingui.h11
-rw-r--r--src/qt/main.cpp17
-rw-r--r--src/qt/peertablemodel.cpp6
-rw-r--r--src/qt/recentrequeststablemodel.cpp2
-rw-r--r--src/qt/recentrequeststablemodel.h2
-rw-r--r--src/qt/rpcconsole.cpp44
-rw-r--r--src/qt/rpcconsole.h12
-rw-r--r--src/qt/test/apptests.cpp117
-rw-r--r--src/qt/test/apptests.h50
-rw-r--r--src/qt/test/rpcnestedtests.cpp2
-rw-r--r--src/qt/test/test_main.cpp12
-rw-r--r--src/qt/walletframe.cpp31
-rw-r--r--src/qt/walletframe.h8
-rw-r--r--src/qt/walletmodel.cpp10
-rw-r--r--src/qt/walletmodel.h5
-rw-r--r--src/rpc/blockchain.cpp15
-rw-r--r--src/rpc/net.cpp14
-rw-r--r--src/streams.h20
-rw-r--r--src/support/allocators/secure.h6
-rw-r--r--src/support/lockedpool.cpp3
-rw-r--r--src/support/lockedpool.h2
-rw-r--r--src/test/addrman_tests.cpp4
-rw-r--r--src/test/getarg_tests.cpp3
-rw-r--r--src/test/net_tests.cpp89
-rw-r--r--src/test/streams_tests.cpp10
-rw-r--r--src/test/txindex_tests.cpp7
-rw-r--r--src/uint256.cpp2
-rw-r--r--src/util/moneystr.cpp6
-rw-r--r--src/util/system.cpp4
-rw-r--r--src/wallet/rpcwallet.cpp9
-rw-r--r--src/wallet/test/wallet_tests.cpp4
-rw-r--r--src/wallet/wallet.h8
-rw-r--r--src/wallet/walletdb.cpp20
-rwxr-xr-xtest/functional/feature_block.py55
-rwxr-xr-xtest/functional/feature_config_args.py8
-rwxr-xr-xtest/functional/rpc_invalidateblock.py69
-rw-r--r--test/functional/test_framework/blocktools.py3
-rwxr-xr-xtest/lint/lint-locale-dependence.sh13
-rw-r--r--test/sanitizer_suppressions/ubsan1
56 files changed, 740 insertions, 391 deletions
diff --git a/build_msvc/libbitcoin_server/libbitcoin_server.vcxproj.in b/build_msvc/libbitcoin_server/libbitcoin_server.vcxproj.in
index 0a165d0b75..e66277123a 100644
--- a/build_msvc/libbitcoin_server/libbitcoin_server.vcxproj.in
+++ b/build_msvc/libbitcoin_server/libbitcoin_server.vcxproj.in
@@ -154,12 +154,6 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
- <ClCompile Include="..\..\src\rpc\net.cpp">
- <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)\netrpc.obj</ObjectFileName>
- <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)\netrpc.obj</ObjectFileName>
- <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)\netrpc.obj</ObjectFileName>
- <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)\netrpc.obj</ObjectFileName>
- </ClCompile>
@SOURCE_FILES@
</ItemGroup>
<ItemGroup>
diff --git a/doc/README.md b/doc/README.md
index 344b1be5c4..c91cca5cb4 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -5,7 +5,7 @@ Setup
---------------------
Bitcoin Core is the original Bitcoin client and it builds the backbone of the network. It downloads and, by default, stores the entire history of Bitcoin transactions, which requires a few hundred gigabytes of disk space. Depending on the speed of your computer and network connection, the synchronization process can take anywhere from a few hours to a day or more.
-To download Bitcoin Core, visit [bitcoincore.org](https://bitcoincore.org/en/releases/).
+To download Bitcoin Core, visit [bitcoincore.org](https://bitcoincore.org/en/download/).
Running
---------------------
diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include
index 445849e3d8..f4f84e2a99 100644
--- a/src/Makefile.qt.include
+++ b/src/Makefile.qt.include
@@ -120,6 +120,7 @@ QT_MOC_CPP = \
qt/moc_bantablemodel.cpp \
qt/moc_bitcoinaddressvalidator.cpp \
qt/moc_bitcoinamountfield.cpp \
+ qt/moc_bitcoin.cpp \
qt/moc_bitcoingui.cpp \
qt/moc_bitcoinunits.cpp \
qt/moc_clientmodel.cpp \
@@ -166,7 +167,6 @@ BITCOIN_MM = \
qt/macos_appnap.mm
QT_MOC = \
- qt/bitcoin.moc \
qt/bitcoinamountfield.moc \
qt/intro.moc \
qt/overviewpage.moc \
@@ -194,6 +194,7 @@ BITCOIN_QT_H = \
qt/bantablemodel.h \
qt/bitcoinaddressvalidator.h \
qt/bitcoinamountfield.h \
+ qt/bitcoin.h \
qt/bitcoingui.h \
qt/bitcoinunits.h \
qt/clientmodel.h \
@@ -302,6 +303,7 @@ RES_ICONS = \
BITCOIN_QT_BASE_CPP = \
qt/bantablemodel.cpp \
+ qt/bitcoin.cpp \
qt/bitcoinaddressvalidator.cpp \
qt/bitcoinamountfield.cpp \
qt/bitcoingui.cpp \
@@ -382,6 +384,9 @@ qt_libbitcoinqt_a_OBJCXXFLAGS = $(AM_OBJCXXFLAGS) $(QT_PIE_FLAGS)
qt_libbitcoinqt_a_SOURCES = $(BITCOIN_QT_CPP) $(BITCOIN_QT_H) $(QT_FORMS_UI) \
$(QT_QRC) $(QT_QRC_LOCALE) $(QT_TS) $(PROTOBUF_PROTO) $(RES_ICONS) $(RES_IMAGES) $(RES_MOVIES)
+if TARGET_DARWIN
+ qt_libbitcoinqt_a_SOURCES += $(BITCOIN_MM)
+endif
nodist_qt_libbitcoinqt_a_SOURCES = $(QT_MOC_CPP) $(QT_MOC) $(PROTOBUF_CC) \
$(PROTOBUF_H) $(QT_QRC_CPP) $(QT_QRC_LOCALE_CPP)
@@ -404,10 +409,7 @@ qt_bitcoin_qt_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDE
$(QT_INCLUDES) $(PROTOBUF_CFLAGS) $(QR_CFLAGS)
qt_bitcoin_qt_CXXFLAGS = $(AM_CXXFLAGS) $(QT_PIE_FLAGS)
-qt_bitcoin_qt_SOURCES = qt/bitcoin.cpp
-if TARGET_DARWIN
- qt_bitcoin_qt_SOURCES += $(BITCOIN_MM)
-endif
+qt_bitcoin_qt_SOURCES = qt/main.cpp
if TARGET_WINDOWS
qt_bitcoin_qt_SOURCES += $(BITCOIN_RC)
endif
diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include
index db7873e8b7..61977b50cd 100644
--- a/src/Makefile.qttest.include
+++ b/src/Makefile.qttest.include
@@ -6,6 +6,7 @@ bin_PROGRAMS += qt/test/test_bitcoin-qt
TESTS += qt/test/test_bitcoin-qt
TEST_QT_MOC_CPP = \
+ qt/test/moc_apptests.cpp \
qt/test/moc_compattests.cpp \
qt/test/moc_rpcnestedtests.cpp \
qt/test/moc_uritests.cpp
@@ -22,6 +23,7 @@ endif # ENABLE_WALLET
TEST_QT_H = \
qt/test/addressbooktests.h \
+ qt/test/apptests.h \
qt/test/compattests.h \
qt/test/rpcnestedtests.h \
qt/test/uritests.h \
@@ -40,6 +42,7 @@ qt_test_test_bitcoin_qt_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_
$(QT_INCLUDES) $(QT_TEST_INCLUDES) $(PROTOBUF_CFLAGS)
qt_test_test_bitcoin_qt_SOURCES = \
+ qt/test/apptests.cpp \
qt/test/compattests.cpp \
qt/test/rpcnestedtests.cpp \
qt/test/test_main.cpp \
diff --git a/src/addrman.h b/src/addrman.h
index af5a1d3b23..003bd059f8 100644
--- a/src/addrman.h
+++ b/src/addrman.h
@@ -23,33 +23,31 @@
*/
class CAddrInfo : public CAddress
{
-
-
public:
//! last try whatsoever by us (memory only)
- int64_t nLastTry;
+ int64_t nLastTry{0};
//! last counted attempt (memory only)
- int64_t nLastCountAttempt;
+ int64_t nLastCountAttempt{0};
private:
//! where knowledge about this address first came from
CNetAddr source;
//! last successful connection by us
- int64_t nLastSuccess;
+ int64_t nLastSuccess{0};
//! connection attempts since last successful attempt
- int nAttempts;
+ int nAttempts{0};
//! reference count in new sets (memory only)
- int nRefCount;
+ int nRefCount{0};
//! in tried set? (memory only)
- bool fInTried;
+ bool fInTried{false};
//! position in vRandom
- int nRandomPos;
+ int nRandomPos{-1};
friend class CAddrMan;
@@ -65,25 +63,12 @@ public:
READWRITE(nAttempts);
}
- void Init()
- {
- nLastSuccess = 0;
- nLastTry = 0;
- nLastCountAttempt = 0;
- nAttempts = 0;
- nRefCount = 0;
- fInTried = false;
- nRandomPos = -1;
- }
-
CAddrInfo(const CAddress &addrIn, const CNetAddr &addrSource) : CAddress(addrIn), source(addrSource)
{
- Init();
}
CAddrInfo() : CAddress(), source()
{
- Init();
}
//! Calculate in which "tried" bucket this entry belongs
@@ -106,7 +91,6 @@ public:
//! Calculate the relative chance this entry should be given when selecting nodes to connect to
double GetChance(int64_t nNow = GetAdjustedTime()) const;
-
};
/** Stochastic address manager
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index 4ce1b53880..d334233224 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -272,10 +272,10 @@ public:
strNetworkID = "regtest";
consensus.nSubsidyHalvingInterval = 150;
consensus.BIP16Exception = uint256();
- consensus.BIP34Height = 100000000; // BIP34 has not activated on regtest (far in the future so block v1 are not rejected in tests)
+ consensus.BIP34Height = 500; // BIP34 activated on regtest (Used in functional tests)
consensus.BIP34Hash = uint256();
- consensus.BIP65Height = 1351; // BIP65 activated on regtest (Used in rpc activation tests)
- consensus.BIP66Height = 1251; // BIP66 activated on regtest (Used in rpc activation tests)
+ consensus.BIP65Height = 1351; // BIP65 activated on regtest (Used in functional tests)
+ consensus.BIP66Height = 1251; // BIP66 activated on regtest (Used in functional tests)
consensus.powLimit = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
consensus.nPowTargetSpacing = 10 * 60;
diff --git a/src/httpserver.cpp b/src/httpserver.cpp
index cb8578927a..ca60ea43a7 100644
--- a/src/httpserver.cpp
+++ b/src/httpserver.cpp
@@ -124,7 +124,6 @@ public:
struct HTTPPathHandler
{
- HTTPPathHandler() {}
HTTPPathHandler(std::string _prefix, bool _exactMatch, HTTPRequestHandler _handler):
prefix(_prefix), exactMatch(_exactMatch), handler(_handler)
{
diff --git a/src/index/base.cpp b/src/index/base.cpp
index 4d4a7e1502..f6f59572ce 100644
--- a/src/index/base.cpp
+++ b/src/index/base.cpp
@@ -60,7 +60,11 @@ bool BaseIndex::Init()
}
LOCK(cs_main);
- m_best_block_index = FindForkInGlobalIndex(chainActive, locator);
+ if (locator.IsNull()) {
+ m_best_block_index = nullptr;
+ } else {
+ m_best_block_index = FindForkInGlobalIndex(chainActive, locator);
+ }
m_synced = m_best_block_index.load() == chainActive.Tip();
return true;
}
diff --git a/src/index/txindex.cpp b/src/index/txindex.cpp
index ba1c44765f..10bc8419dd 100644
--- a/src/index/txindex.cpp
+++ b/src/index/txindex.cpp
@@ -245,6 +245,9 @@ bool TxIndex::Init()
bool TxIndex::WriteBlock(const CBlock& block, const CBlockIndex* pindex)
{
+ // Exclude genesis block transaction because outputs are not spendable.
+ if (pindex->nHeight == 0) return true;
+
CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(block.vtx.size()));
std::vector<std::pair<uint256, CDiskTxPos>> vPos;
vPos.reserve(block.vtx.size());
diff --git a/src/init.cpp b/src/init.cpp
index 18c145a023..f4f00ea691 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -1631,8 +1631,14 @@ bool AppInitMain(InitInterfaces& interfaces)
// ********************************************************* Step 11: import blocks
- if (!CheckDiskSpace() && !CheckDiskSpace(0, true))
+ if (!CheckDiskSpace(/* additional_bytes */ 0, /* blocks_dir */ false)) {
+ InitError(strprintf(_("Error: Disk space is low for %s"), GetDataDir()));
return false;
+ }
+ if (!CheckDiskSpace(/* additional_bytes */ 0, /* blocks_dir */ true)) {
+ InitError(strprintf(_("Error: Disk space is low for %s"), GetBlocksDir()));
+ return false;
+ }
// Either install a handler to notify us when genesis activates, or set fHaveGenesis directly.
// No locking, as this happens before any background thread is started.
diff --git a/src/net.cpp b/src/net.cpp
index a288c6e81e..86e5225839 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Copyright (c) 2009-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -80,7 +80,7 @@ enum BindFlags {
// The sleep time needs to be small to avoid new sockets stalling
static const uint64_t SELECT_TIMEOUT_MILLISECONDS = 50;
-const static std::string NET_MESSAGE_COMMAND_OTHER = "*other*";
+const std::string NET_MESSAGE_COMMAND_OTHER = "*other*";
static const uint64_t RANDOMIZER_ID_NETGROUP = 0x6c0edd8036ef4036ULL; // SHA256("netgroup")[0:8]
static const uint64_t RANDOMIZER_ID_LOCALHOSTNONCE = 0xd93e69e2bbfa5735ULL; // SHA256("localhostnonce")[0:8]
@@ -295,15 +295,13 @@ bool IsLocal(const CService& addr)
/** check whether a given network is one we can probably connect to */
bool IsReachable(enum Network net)
{
- LOCK(cs_mapLocalHost);
- return !vfLimited[net];
+ return !IsLimited(net);
}
/** check whether a given address is in a network we can probably connect to */
bool IsReachable(const CNetAddr& addr)
{
- enum Network net = addr.GetNetwork();
- return IsReachable(net);
+ return IsReachable(addr.GetNetwork());
}
@@ -787,7 +785,6 @@ bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes, bool& complete
nBytes -= handled;
if (msg.complete()) {
-
//store received bytes per message command
//to prevent a memory DOS, only allow valid commands
mapMsgCmdSize::iterator i = mapRecvBytesPerMsgCmd.find(msg.hdr.pchCommand);
@@ -2317,14 +2314,6 @@ void CConnman::SetNetworkActive(bool active)
CConnman::CConnman(uint64_t nSeed0In, uint64_t nSeed1In) : nSeed0(nSeed0In), nSeed1(nSeed1In)
{
- fNetworkActive = true;
- setBannedIsDirty = false;
- fAddressesInitialized = false;
- nLastNodeId = 0;
- nPrevNodeCount = 0;
- nSendBufferMaxSize = 0;
- nReceiveFloodSize = 0;
- flagInterruptMsgProc = false;
SetTryNewOutboundPeer(false);
Options connOptions;
diff --git a/src/net.h b/src/net.h
index 915a8e5b35..478f2958af 100644
--- a/src/net.h
+++ b/src/net.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Copyright (c) 2009-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -404,15 +404,15 @@ private:
// whitelisted (as well as those connecting to whitelisted binds).
std::vector<CSubNet> vWhitelistedRange;
- unsigned int nSendBufferMaxSize;
- unsigned int nReceiveFloodSize;
+ unsigned int nSendBufferMaxSize{0};
+ unsigned int nReceiveFloodSize{0};
std::vector<ListenSocket> vhListenSocket;
- std::atomic<bool> fNetworkActive;
+ std::atomic<bool> fNetworkActive{true};
banmap_t setBanned GUARDED_BY(cs_setBanned);
CCriticalSection cs_setBanned;
- bool setBannedIsDirty GUARDED_BY(cs_setBanned);
- bool fAddressesInitialized;
+ bool setBannedIsDirty GUARDED_BY(cs_setBanned){false};
+ bool fAddressesInitialized{false};
CAddrMan addrman;
std::deque<std::string> vOneShots GUARDED_BY(cs_vOneShots);
CCriticalSection cs_vOneShots;
@@ -421,8 +421,8 @@ private:
std::vector<CNode*> vNodes;
std::list<CNode*> vNodesDisconnected;
mutable CCriticalSection cs_vNodes;
- std::atomic<NodeId> nLastNodeId;
- unsigned int nPrevNodeCount;
+ std::atomic<NodeId> nLastNodeId{0};
+ unsigned int nPrevNodeCount{0};
/** Services this instance offers */
ServiceFlags nLocalServices;
@@ -446,7 +446,7 @@ private:
std::condition_variable condMsgProc;
Mutex mutexMsgProc;
- std::atomic<bool> flagInterruptMsgProc;
+ std::atomic<bool> flagInterruptMsgProc{false};
CThreadInterrupt interruptNet;
@@ -550,6 +550,8 @@ struct LocalServiceInfo {
extern CCriticalSection cs_mapLocalHost;
extern std::map<CNetAddr, LocalServiceInfo> mapLocalHost GUARDED_BY(cs_mapLocalHost);
+
+extern const std::string NET_MESSAGE_COMMAND_OTHER;
typedef std::map<std::string, uint64_t> mapMsgCmdSize; //command, total bytes
class CNodeStats
@@ -696,8 +698,8 @@ public:
const uint64_t nKeyedNetGroup;
std::atomic_bool fPauseRecv;
std::atomic_bool fPauseSend;
-protected:
+protected:
mapMsgCmdSize mapSendBytesPerMsgCmd;
mapMsgCmdSize mapRecvBytesPerMsgCmd GUARDED_BY(cs_vRecv);
diff --git a/src/protocol.h b/src/protocol.h
index 50d197415b..a790a06906 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -402,7 +402,6 @@ public:
std::string GetCommand() const;
std::string ToString() const;
- // TODO: make private (improves encapsulation)
public:
int type;
uint256 hash;
diff --git a/src/qt/bantablemodel.cpp b/src/qt/bantablemodel.cpp
index dcfe3dcc57..713db595d5 100644
--- a/src/qt/bantablemodel.cpp
+++ b/src/qt/bantablemodel.cpp
@@ -40,8 +40,8 @@ class BanTablePriv
public:
/** Local cache of peer information */
QList<CCombinedBan> cachedBanlist;
- /** Column to sort nodes by */
- int sortColumn;
+ /** Column to sort nodes by (default to unsorted) */
+ int sortColumn{-1};
/** Order (ascending or descending) to sort nodes by */
Qt::SortOrder sortOrder;
@@ -87,8 +87,6 @@ BanTableModel::BanTableModel(interfaces::Node& node, ClientModel *parent) :
{
columns << tr("IP/Netmask") << tr("Banned Until");
priv.reset(new BanTablePriv());
- // default to unsorted
- priv->sortColumn = -1;
// load initial data
refresh();
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index eaeb93a652..6e08dae3c4 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2018 The Bitcoin Core developers
+// Copyright (c) 2011-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -6,6 +6,7 @@
#include <config/bitcoin-config.h>
#endif
+#include <qt/bitcoin.h>
#include <qt/bitcoingui.h>
#include <chainparams.h>
@@ -71,11 +72,6 @@ Q_DECLARE_METATYPE(bool*)
Q_DECLARE_METATYPE(CAmount)
Q_DECLARE_METATYPE(uint256)
-/** Translate string to current locale using Qt. */
-const std::function<std::string(const char*)> G_TRANSLATION_FUN = [](const char* psz) {
- return QCoreApplication::translate("bitcoin-core", psz).toStdString();
-};
-
static QString GetLangTerritory()
{
QSettings settings;
@@ -140,101 +136,6 @@ void DebugMessageHandler(QtMsgType type, const QMessageLogContext& context, cons
}
}
-/** Class encapsulating Bitcoin Core startup and shutdown.
- * Allows running startup and shutdown in a different thread from the UI thread.
- */
-class BitcoinCore: public QObject
-{
- Q_OBJECT
-public:
- explicit BitcoinCore(interfaces::Node& node);
-
-public Q_SLOTS:
- void initialize();
- void shutdown();
-
-Q_SIGNALS:
- void initializeResult(bool success);
- void shutdownResult();
- void runawayException(const QString &message);
-
-private:
- /// Pass fatal exception message to UI thread
- void handleRunawayException(const std::exception *e);
-
- interfaces::Node& m_node;
-};
-
-/** Main Bitcoin application object */
-class BitcoinApplication: public QApplication
-{
- Q_OBJECT
-public:
- explicit BitcoinApplication(interfaces::Node& node, int &argc, char **argv);
- ~BitcoinApplication();
-
-#ifdef ENABLE_WALLET
- /// Create payment server
- void createPaymentServer();
-#endif
- /// parameter interaction/setup based on rules
- void parameterSetup();
- /// Create options model
- void createOptionsModel(bool resetSettings);
- /// Create main window
- void createWindow(const NetworkStyle *networkStyle);
- /// Create splash screen
- void createSplashScreen(const NetworkStyle *networkStyle);
-
- /// Request core initialization
- void requestInitialize();
- /// Request core shutdown
- void requestShutdown();
-
- /// Get process return value
- int getReturnValue() const { return returnValue; }
-
- /// Get window identifier of QMainWindow (BitcoinGUI)
- WId getMainWinId() const;
-
- /// Setup platform style
- void setupPlatformStyle();
-
-public Q_SLOTS:
- void initializeResult(bool success);
- void shutdownResult();
- /// Handle runaway exceptions. Shows a message box with the problem and quits the program.
- void handleRunawayException(const QString &message);
- void addWallet(WalletModel* walletModel);
- void removeWallet();
-
-Q_SIGNALS:
- void requestedInitialize();
- void requestedShutdown();
- void stopThread();
- void splashFinished();
-
-private:
- QThread *coreThread;
- interfaces::Node& m_node;
- OptionsModel *optionsModel;
- ClientModel *clientModel;
- BitcoinGUI *window;
- QTimer *pollShutdownTimer;
-#ifdef ENABLE_WALLET
- PaymentServer* paymentServer;
- std::vector<WalletModel*> m_wallet_models;
- std::unique_ptr<interfaces::Handler> m_handler_load_wallet;
-#endif
- int returnValue;
- const PlatformStyle *platformStyle;
- std::unique_ptr<QWidget> shutdownWindow;
-
- void startThread();
-};
-
-#include <qt/bitcoin.moc>
-
BitcoinCore::BitcoinCore(interfaces::Node& node) :
QObject(), m_node(node)
{
@@ -358,6 +259,11 @@ void BitcoinApplication::createSplashScreen(const NetworkStyle *networkStyle)
connect(this, &BitcoinApplication::requestedShutdown, splash, &QWidget::close);
}
+bool BitcoinApplication::baseInitialize()
+{
+ return m_node.baseInitialize();
+}
+
void BitcoinApplication::startThread()
{
if(coreThread)
@@ -431,7 +337,7 @@ void BitcoinApplication::addWallet(WalletModel* walletModel)
window->addWallet(walletModel);
if (m_wallet_models.empty()) {
- window->setCurrentWallet(walletModel->getWalletName());
+ window->setCurrentWallet(walletModel);
}
#ifdef ENABLE_BIP70
@@ -467,7 +373,7 @@ void BitcoinApplication::initializeResult(bool success)
#ifdef ENABLE_BIP70
PaymentServer::LoadRootCAs();
#endif
- paymentServer->setOptionsModel(optionsModel);
+ if (paymentServer) paymentServer->setOptionsModel(optionsModel);
#endif
clientModel = new ClientModel(m_node, optionsModel);
@@ -486,26 +392,28 @@ void BitcoinApplication::initializeResult(bool success)
}
#endif
- // If -min option passed, start window minimized.
- if(gArgs.GetBoolArg("-min", false))
- {
- window->showMinimized();
- }
- else
- {
+ // If -min option passed, start window minimized (iconified) or minimized to tray
+ if (!gArgs.GetBoolArg("-min", false)) {
window->show();
+ } else if (clientModel->getOptionsModel()->getMinimizeToTray() && window->hasTrayIcon()) {
+ // do nothing as the window is managed by the tray icon
+ } else {
+ window->showMinimized();
}
Q_EMIT splashFinished();
+ Q_EMIT windowShown(window);
#ifdef ENABLE_WALLET
// Now that initialization/startup is done, process any command-line
// bitcoin: URIs or payment requests:
- connect(paymentServer, &PaymentServer::receivedPaymentRequest, window, &BitcoinGUI::handlePaymentRequest);
- connect(window, &BitcoinGUI::receivedURI, paymentServer, &PaymentServer::handleURIOrFile);
- connect(paymentServer, &PaymentServer::message, [this](const QString& title, const QString& message, unsigned int style) {
- window->message(title, message, style);
- });
- QTimer::singleShot(100, paymentServer, &PaymentServer::uiReady);
+ if (paymentServer) {
+ connect(paymentServer, &PaymentServer::receivedPaymentRequest, window, &BitcoinGUI::handlePaymentRequest);
+ connect(window, &BitcoinGUI::receivedURI, paymentServer, &PaymentServer::handleURIOrFile);
+ connect(paymentServer, &PaymentServer::message, [this](const QString& title, const QString& message, unsigned int style) {
+ window->message(title, message, style);
+ });
+ QTimer::singleShot(100, paymentServer, &PaymentServer::uiReady);
+ }
#endif
pollShutdownTimer->start(200);
} else {
@@ -548,7 +456,7 @@ static void SetupUIArgs()
}
#ifndef BITCOIN_QT_TEST
-int main(int argc, char *argv[])
+int GuiMain(int argc, char* argv[])
{
#ifdef WIN32
util::WinCmdLineArgs winArgs;
@@ -706,7 +614,7 @@ int main(int argc, char *argv[])
// Perform base initialization before spinning up initialization/shutdown thread
// This is acceptable because this function only contains steps that are quick to execute,
// so the GUI thread won't be held up.
- if (node->baseInitialize()) {
+ if (app.baseInitialize()) {
app.requestInitialize();
#if defined(Q_OS_WIN)
WinShutdownMonitor::registerShutdownBlockReason(QObject::tr("%1 didn't yet exit safely...").arg(QObject::tr(PACKAGE_NAME)), (HWND)app.getMainWinId());
diff --git a/src/qt/bitcoin.h b/src/qt/bitcoin.h
new file mode 100644
index 0000000000..48b5907570
--- /dev/null
+++ b/src/qt/bitcoin.h
@@ -0,0 +1,127 @@
+// Copyright (c) 2011-2016 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_QT_BITCOIN_H
+#define BITCOIN_QT_BITCOIN_H
+
+#if defined(HAVE_CONFIG_H)
+#include <config/bitcoin-config.h>
+#endif
+
+#include <QApplication>
+#include <memory>
+#include <vector>
+
+class BitcoinGUI;
+class ClientModel;
+class NetworkStyle;
+class OptionsModel;
+class PaymentServer;
+class PlatformStyle;
+class WalletModel;
+
+namespace interfaces {
+class Handler;
+class Node;
+} // namespace interfaces
+
+/** Class encapsulating Bitcoin Core startup and shutdown.
+ * Allows running startup and shutdown in a different thread from the UI thread.
+ */
+class BitcoinCore: public QObject
+{
+ Q_OBJECT
+public:
+ explicit BitcoinCore(interfaces::Node& node);
+
+public Q_SLOTS:
+ void initialize();
+ void shutdown();
+
+Q_SIGNALS:
+ void initializeResult(bool success);
+ void shutdownResult();
+ void runawayException(const QString &message);
+
+private:
+ /// Pass fatal exception message to UI thread
+ void handleRunawayException(const std::exception *e);
+
+ interfaces::Node& m_node;
+};
+
+/** Main Bitcoin application object */
+class BitcoinApplication: public QApplication
+{
+ Q_OBJECT
+public:
+ explicit BitcoinApplication(interfaces::Node& node, int &argc, char **argv);
+ ~BitcoinApplication();
+
+#ifdef ENABLE_WALLET
+ /// Create payment server
+ void createPaymentServer();
+#endif
+ /// parameter interaction/setup based on rules
+ void parameterSetup();
+ /// Create options model
+ void createOptionsModel(bool resetSettings);
+ /// Create main window
+ void createWindow(const NetworkStyle *networkStyle);
+ /// Create splash screen
+ void createSplashScreen(const NetworkStyle *networkStyle);
+ /// Basic initialization, before starting initialization/shutdown thread. Return true on success.
+ bool baseInitialize();
+
+ /// Request core initialization
+ void requestInitialize();
+ /// Request core shutdown
+ void requestShutdown();
+
+ /// Get process return value
+ int getReturnValue() const { return returnValue; }
+
+ /// Get window identifier of QMainWindow (BitcoinGUI)
+ WId getMainWinId() const;
+
+ /// Setup platform style
+ void setupPlatformStyle();
+
+public Q_SLOTS:
+ void initializeResult(bool success);
+ void shutdownResult();
+ /// Handle runaway exceptions. Shows a message box with the problem and quits the program.
+ void handleRunawayException(const QString &message);
+ void addWallet(WalletModel* walletModel);
+ void removeWallet();
+
+Q_SIGNALS:
+ void requestedInitialize();
+ void requestedShutdown();
+ void stopThread();
+ void splashFinished();
+ void windowShown(BitcoinGUI* window);
+
+private:
+ QThread *coreThread;
+ interfaces::Node& m_node;
+ OptionsModel *optionsModel;
+ ClientModel *clientModel;
+ BitcoinGUI *window;
+ QTimer *pollShutdownTimer;
+#ifdef ENABLE_WALLET
+ PaymentServer* paymentServer;
+ std::vector<WalletModel*> m_wallet_models;
+ std::unique_ptr<interfaces::Handler> m_handler_load_wallet;
+#endif
+ int returnValue;
+ const PlatformStyle *platformStyle;
+ std::unique_ptr<QWidget> shutdownWindow;
+
+ void startThread();
+};
+
+int GuiMain(int argc, char* argv[]);
+
+#endif // BITCOIN_QT_BITCOIN_H
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 70255e058a..155f8efe7f 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2018 The Bitcoin Core developers
+// Copyright (c) 2011-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -110,6 +110,7 @@ BitcoinGUI::BitcoinGUI(interfaces::Node& node, const PlatformStyle *_platformSty
* the central widget is the rpc console.
*/
setCentralWidget(rpcConsole);
+ Q_EMIT consoleShown(rpcConsole);
}
// Accept D&D of URIs
@@ -324,6 +325,7 @@ void BitcoinGUI::createActions()
openRPCConsoleAction->setStatusTip(tr("Open debugging and diagnostic console"));
// initially disable the debug window menu item
openRPCConsoleAction->setEnabled(false);
+ openRPCConsoleAction->setObjectName("openRPCConsoleAction");
usedSendingAddressesAction = new QAction(platformStyle->TextColorIcon(":/icons/address-book"), tr("&Sending addresses"), this);
usedSendingAddressesAction->setStatusTip(tr("Show the list of used sending addresses and labels"));
@@ -569,10 +571,9 @@ bool BitcoinGUI::addWallet(WalletModel *walletModel)
{
if(!walletFrame)
return false;
- const QString name = walletModel->getWalletName();
- QString display_name = name.isEmpty() ? "["+tr("default wallet")+"]" : name;
+ const QString display_name = walletModel->getDisplayName();
setWalletActionsEnabled(true);
- m_wallet_selector->addItem(display_name, name);
+ m_wallet_selector->addItem(display_name, QVariant::fromValue(walletModel));
if (m_wallet_selector->count() == 2) {
m_wallet_selector_label_action->setVisible(true);
m_wallet_selector_action->setVisible(true);
@@ -584,8 +585,7 @@ bool BitcoinGUI::addWallet(WalletModel *walletModel)
bool BitcoinGUI::removeWallet(WalletModel* walletModel)
{
if (!walletFrame) return false;
- QString name = walletModel->getWalletName();
- int index = m_wallet_selector->findData(name);
+ int index = m_wallet_selector->findData(QVariant::fromValue(walletModel));
m_wallet_selector->removeItem(index);
if (m_wallet_selector->count() == 0) {
setWalletActionsEnabled(false);
@@ -594,20 +594,20 @@ bool BitcoinGUI::removeWallet(WalletModel* walletModel)
m_wallet_selector_action->setVisible(false);
}
rpcConsole->removeWallet(walletModel);
- return walletFrame->removeWallet(name);
+ return walletFrame->removeWallet(walletModel);
}
-bool BitcoinGUI::setCurrentWallet(const QString& name)
+bool BitcoinGUI::setCurrentWallet(WalletModel* wallet_model)
{
if(!walletFrame)
return false;
- return walletFrame->setCurrentWallet(name);
+ return walletFrame->setCurrentWallet(wallet_model);
}
bool BitcoinGUI::setCurrentWalletBySelectorIndex(int index)
{
- QString internal_name = m_wallet_selector->itemData(index).toString();
- return setCurrentWallet(internal_name);
+ WalletModel* wallet_model = m_wallet_selector->itemData(index).value<WalletModel*>();
+ return setCurrentWallet(wallet_model);
}
void BitcoinGUI::removeAllWallets()
@@ -642,9 +642,11 @@ void BitcoinGUI::createTrayIcon(const NetworkStyle *networkStyle)
assert(QSystemTrayIcon::isSystemTrayAvailable());
#ifndef Q_OS_MAC
- trayIcon = new QSystemTrayIcon(networkStyle->getTrayAndWindowIcon(), this);
- QString toolTip = tr("%1 client").arg(tr(PACKAGE_NAME)) + " " + networkStyle->getTitleAddText();
- trayIcon->setToolTip(toolTip);
+ if (QSystemTrayIcon::isSystemTrayAvailable()) {
+ trayIcon = new QSystemTrayIcon(networkStyle->getTrayAndWindowIcon(), this);
+ QString toolTip = tr("%1 client").arg(tr(PACKAGE_NAME)) + " " + networkStyle->getTitleAddText();
+ trayIcon->setToolTip(toolTip);
+ }
#endif
}
@@ -724,6 +726,7 @@ void BitcoinGUI::aboutClicked()
void BitcoinGUI::showDebugWindow()
{
GUIUtil::bringToFront(rpcConsole);
+ Q_EMIT consoleShown(rpcConsole);
}
void BitcoinGUI::showDebugWindowActivateConsole()
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index aeff5dae30..9ca9e4c926 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2018 The Bitcoin Core developers
+// Copyright (c) 2011-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -86,6 +86,11 @@ public:
#endif // ENABLE_WALLET
bool enableWallet = false;
+ /** Get the tray icon status.
+ Some systems have not "system tray" or "notification area" available.
+ */
+ bool hasTrayIcon() const { return trayIcon; }
+
protected:
void changeEvent(QEvent *e);
void closeEvent(QCloseEvent *event);
@@ -187,6 +192,8 @@ private:
Q_SIGNALS:
/** Signal raised when a URI was entered or dragged to the GUI */
void receivedURI(const QString &uri);
+ /** Signal raised when RPC console shown */
+ void consoleShown(RPCConsole* console);
public Q_SLOTS:
/** Set number of connections shown in the UI */
@@ -206,7 +213,7 @@ public Q_SLOTS:
void message(const QString &title, const QString &message, unsigned int style, bool *ret = nullptr);
#ifdef ENABLE_WALLET
- bool setCurrentWallet(const QString& name);
+ bool setCurrentWallet(WalletModel* wallet_model);
bool setCurrentWalletBySelectorIndex(int index);
/** Set the UI status indicators based on the currently selected wallet.
*/
diff --git a/src/qt/main.cpp b/src/qt/main.cpp
new file mode 100644
index 0000000000..6a3c2249d1
--- /dev/null
+++ b/src/qt/main.cpp
@@ -0,0 +1,17 @@
+// 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 <qt/bitcoin.h>
+
+#include <QCoreApplication>
+
+#include <functional>
+#include <string>
+
+/** Translate string to current locale using Qt. */
+extern const std::function<std::string(const char*)> G_TRANSLATION_FUN = [](const char* psz) {
+ return QCoreApplication::translate("bitcoin-core", psz).toStdString();
+};
+
+int main(int argc, char* argv[]) { return GuiMain(argc, argv); }
diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp
index 8cfedca57f..e2e78fe81b 100644
--- a/src/qt/peertablemodel.cpp
+++ b/src/qt/peertablemodel.cpp
@@ -49,8 +49,8 @@ class PeerTablePriv
public:
/** Local cache of peer information */
QList<CNodeCombinedStats> cachedNodeStats;
- /** Column to sort nodes by */
- int sortColumn;
+ /** Column to sort nodes by (default to unsorted) */
+ int sortColumn{-1};
/** Order (ascending or descending) to sort nodes by */
Qt::SortOrder sortOrder;
/** Index of rows by node ID */
@@ -108,8 +108,6 @@ PeerTableModel::PeerTableModel(interfaces::Node& node, ClientModel *parent) :
{
columns << tr("NodeId") << tr("Node/Service") << tr("Ping") << tr("Sent") << tr("Received") << tr("User Agent");
priv.reset(new PeerTablePriv());
- // default to unsorted
- priv->sortColumn = -1;
// set up timer for auto refresh
timer = new QTimer(this);
diff --git a/src/qt/recentrequeststablemodel.cpp b/src/qt/recentrequeststablemodel.cpp
index 82ab48ac20..aa746017f3 100644
--- a/src/qt/recentrequeststablemodel.cpp
+++ b/src/qt/recentrequeststablemodel.cpp
@@ -15,8 +15,6 @@
RecentRequestsTableModel::RecentRequestsTableModel(WalletModel *parent) :
QAbstractTableModel(parent), walletModel(parent)
{
- nReceiveRequestsMaxId = 0;
-
// Load entries from wallet
std::vector<std::string> vReceiveRequests;
parent->loadReceiveRequests(vReceiveRequests);
diff --git a/src/qt/recentrequeststablemodel.h b/src/qt/recentrequeststablemodel.h
index ff2c0c8098..8a1140e952 100644
--- a/src/qt/recentrequeststablemodel.h
+++ b/src/qt/recentrequeststablemodel.h
@@ -94,7 +94,7 @@ private:
WalletModel *walletModel;
QStringList columns;
QList<RecentRequestEntry> list;
- int64_t nReceiveRequestsMaxId;
+ int64_t nReceiveRequestsMaxId{0};
/** Updates the column title to "Amount (DisplayUnit)" and emits headerDataChanged() signal for table headers to react. */
void updateAmountColumnTitle();
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 774a0d78e7..d062ea49bd 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2018 The Bitcoin Core developers
+// Copyright (c) 2011-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -18,6 +18,7 @@
#include <netbase.h>
#include <rpc/server.h>
#include <rpc/client.h>
+#include <util/strencodings.h>
#include <util/system.h>
#include <openssl/crypto.h>
@@ -85,7 +86,7 @@ public:
explicit RPCExecutor(interfaces::Node& node) : m_node(node) {}
public Q_SLOTS:
- void request(const QString &command, const QString &walletID);
+ void request(const QString &command, const WalletModel* wallet_model);
Q_SIGNALS:
void reply(int category, const QString &command);
@@ -148,7 +149,7 @@ public:
* @param[out] pstrFilteredOut Command line, filtered to remove any sensitive data
*/
-bool RPCConsole::RPCParseCommandLine(interfaces::Node* node, std::string &strResult, const std::string &strCommand, const bool fExecute, std::string * const pstrFilteredOut, const std::string *walletID)
+bool RPCConsole::RPCParseCommandLine(interfaces::Node* node, std::string &strResult, const std::string &strCommand, const bool fExecute, std::string * const pstrFilteredOut, const WalletModel* wallet_model)
{
std::vector< std::vector<std::string> > stack;
stack.push_back(std::vector<std::string>());
@@ -226,7 +227,7 @@ bool RPCConsole::RPCParseCommandLine(interfaces::Node* node, std::string &strRes
if (lastResult.isArray())
{
for(char argch: curarg)
- if (!std::isdigit(argch))
+ if (!IsDigit(argch))
throw std::runtime_error("Invalid result query");
subelement = lastResult[atoi(curarg.c_str())];
}
@@ -306,8 +307,8 @@ bool RPCConsole::RPCParseCommandLine(interfaces::Node* node, std::string &strRes
std::string method = stack.back()[0];
std::string uri;
#ifdef ENABLE_WALLET
- if (walletID) {
- QByteArray encodedName = QUrl::toPercentEncoding(QString::fromStdString(*walletID));
+ if (wallet_model) {
+ QByteArray encodedName = QUrl::toPercentEncoding(wallet_model->getWalletName());
uri = "/wallet/"+std::string(encodedName.constData(), encodedName.length());
}
#endif
@@ -387,7 +388,7 @@ bool RPCConsole::RPCParseCommandLine(interfaces::Node* node, std::string &strRes
}
}
-void RPCExecutor::request(const QString &command, const QString &walletID)
+void RPCExecutor::request(const QString &command, const WalletModel* wallet_model)
{
try
{
@@ -418,9 +419,7 @@ void RPCExecutor::request(const QString &command, const QString &walletID)
" example: getblock(getblockhash(0),true)[tx][0]\n\n")));
return;
}
- std::string wallet_id = walletID.toStdString();
- if (!RPCConsole::RPCExecuteCommandLine(m_node, result, executableCommand, nullptr, walletID.isNull() ? nullptr : &wallet_id))
- {
+ if (!RPCConsole::RPCExecuteCommandLine(m_node, result, executableCommand, nullptr, wallet_model)) {
Q_EMIT reply(RPCConsole::CMD_ERROR, QString("Parse error: unbalanced ' or \""));
return;
}
@@ -698,10 +697,8 @@ void RPCConsole::setClientModel(ClientModel *model)
#ifdef ENABLE_WALLET
void RPCConsole::addWallet(WalletModel * const walletModel)
{
- const QString name = walletModel->getWalletName();
- // use name for text and internal data object (to allow to move to a wallet id later)
- QString display_name = name.isEmpty() ? "["+tr("default wallet")+"]" : name;
- ui->WalletSelector->addItem(display_name, name);
+ // use name for text and wallet model for internal data object (to allow to move to a wallet id later)
+ ui->WalletSelector->addItem(walletModel->getDisplayName(), QVariant::fromValue(walletModel));
if (ui->WalletSelector->count() == 2 && !isVisible()) {
// First wallet added, set to default so long as the window isn't presently visible (and potentially in use)
ui->WalletSelector->setCurrentIndex(1);
@@ -714,8 +711,7 @@ void RPCConsole::addWallet(WalletModel * const walletModel)
void RPCConsole::removeWallet(WalletModel * const walletModel)
{
- const QString name = walletModel->getWalletName();
- ui->WalletSelector->removeItem(ui->WalletSelector->findData(name));
+ ui->WalletSelector->removeItem(ui->WalletSelector->findData(QVariant::fromValue(walletModel)));
if (ui->WalletSelector->count() == 2) {
ui->WalletSelector->setVisible(false);
ui->WalletSelectorLabel->setVisible(false);
@@ -910,25 +906,25 @@ void RPCConsole::on_lineEdit_returnPressed()
cmdBeforeBrowsing = QString();
- QString walletID;
+ WalletModel* wallet_model{nullptr};
#ifdef ENABLE_WALLET
const int wallet_index = ui->WalletSelector->currentIndex();
if (wallet_index > 0) {
- walletID = (QString)ui->WalletSelector->itemData(wallet_index).value<QString>();
+ wallet_model = ui->WalletSelector->itemData(wallet_index).value<WalletModel*>();
}
- if (m_last_wallet_id != walletID) {
- if (walletID.isNull()) {
- message(CMD_REQUEST, tr("Executing command without any wallet"));
+ if (m_last_wallet_model != wallet_model) {
+ if (wallet_model) {
+ message(CMD_REQUEST, tr("Executing command using \"%1\" wallet").arg(wallet_model->getWalletName()));
} else {
- message(CMD_REQUEST, tr("Executing command using \"%1\" wallet").arg(walletID));
+ message(CMD_REQUEST, tr("Executing command without any wallet"));
}
- m_last_wallet_id = walletID;
+ m_last_wallet_model = wallet_model;
}
#endif
message(CMD_REQUEST, QString::fromStdString(strFilteredCmd));
- Q_EMIT cmdRequest(cmd, walletID);
+ Q_EMIT cmdRequest(cmd, m_last_wallet_model);
cmd = QString::fromStdString(strFilteredCmd);
diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h
index 20dbf5ec95..6c000ba096 100644
--- a/src/qt/rpcconsole.h
+++ b/src/qt/rpcconsole.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2018 The Bitcoin Core developers
+// Copyright (c) 2011-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -41,9 +41,9 @@ public:
explicit RPCConsole(interfaces::Node& node, const PlatformStyle *platformStyle, QWidget *parent);
~RPCConsole();
- static bool RPCParseCommandLine(interfaces::Node* node, std::string &strResult, const std::string &strCommand, bool fExecute, std::string * const pstrFilteredOut = nullptr, const std::string *walletID = nullptr);
- static bool RPCExecuteCommandLine(interfaces::Node& node, std::string &strResult, const std::string &strCommand, std::string * const pstrFilteredOut = nullptr, const std::string *walletID = nullptr) {
- return RPCParseCommandLine(&node, strResult, strCommand, true, pstrFilteredOut, walletID);
+ static bool RPCParseCommandLine(interfaces::Node* node, std::string &strResult, const std::string &strCommand, bool fExecute, std::string * const pstrFilteredOut = nullptr, const WalletModel* wallet_model = nullptr);
+ static bool RPCExecuteCommandLine(interfaces::Node& node, std::string &strResult, const std::string &strCommand, std::string * const pstrFilteredOut = nullptr, const WalletModel* wallet_model = nullptr) {
+ return RPCParseCommandLine(&node, strResult, strCommand, true, pstrFilteredOut, wallet_model);
}
void setClientModel(ClientModel *model);
@@ -133,7 +133,7 @@ public Q_SLOTS:
Q_SIGNALS:
// For RPC command executor
void stopExecutor();
- void cmdRequest(const QString &command, const QString &walletID);
+ void cmdRequest(const QString &command, const WalletModel* wallet_model);
private:
void startExecutor();
@@ -165,7 +165,7 @@ private:
int consoleFontSize = 0;
QCompleter *autoCompleter = nullptr;
QThread thread;
- QString m_last_wallet_id;
+ WalletModel* m_last_wallet_model{nullptr};
/** Update UI with latest network info from model. */
void updateNetworkState();
diff --git a/src/qt/test/apptests.cpp b/src/qt/test/apptests.cpp
new file mode 100644
index 0000000000..2c477a2e98
--- /dev/null
+++ b/src/qt/test/apptests.cpp
@@ -0,0 +1,117 @@
+// 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 <qt/test/apptests.h>
+
+#include <chainparams.h>
+#include <init.h>
+#include <qt/bitcoin.h>
+#include <qt/bitcoingui.h>
+#include <qt/networkstyle.h>
+#include <qt/rpcconsole.h>
+#include <shutdown.h>
+#include <validation.h>
+
+#if defined(HAVE_CONFIG_H)
+#include <config/bitcoin-config.h>
+#endif
+#ifdef ENABLE_WALLET
+#include <wallet/db.h>
+#endif
+
+#include <QAction>
+#include <QEventLoop>
+#include <QLineEdit>
+#include <QScopedPointer>
+#include <QTest>
+#include <QTextEdit>
+#include <QtGlobal>
+#if QT_VERSION >= 0x050000
+#include <QtTest/QtTestWidgets>
+#endif
+#include <QtTest/QtTestGui>
+#include <new>
+#include <string>
+#include <univalue.h>
+
+namespace {
+//! Call getblockchaininfo RPC and check first field of JSON output.
+void TestRpcCommand(RPCConsole* console)
+{
+ QEventLoop loop;
+ QTextEdit* messagesWidget = console->findChild<QTextEdit*>("messagesWidget");
+ QObject::connect(messagesWidget, &QTextEdit::textChanged, &loop, &QEventLoop::quit);
+ QLineEdit* lineEdit = console->findChild<QLineEdit*>("lineEdit");
+ QTest::keyClicks(lineEdit, "getblockchaininfo");
+ QTest::keyClick(lineEdit, Qt::Key_Return);
+ loop.exec();
+ QString output = messagesWidget->toPlainText();
+ UniValue value;
+ value.read(output.right(output.size() - output.lastIndexOf(QChar::ObjectReplacementCharacter) - 1).toStdString());
+ QCOMPARE(value["chain"].get_str(), std::string("regtest"));
+}
+} // namespace
+
+//! Entry point for BitcoinApplication tests.
+void AppTests::appTests()
+{
+#ifdef Q_OS_MAC
+ if (QApplication::platformName() == "minimal") {
+ // Disable for mac on "minimal" platform to avoid crashes inside the Qt
+ // framework when it tries to look up unimplemented cocoa functions,
+ // and fails to handle returned nulls
+ // (https://bugreports.qt.io/browse/QTBUG-49686).
+ QWARN("Skipping AppTests on mac build with 'minimal' platform set due to Qt bugs. To run AppTests, invoke "
+ "with 'test_bitcoin-qt -platform cocoa' on mac, or else use a linux or windows build.");
+ return;
+ }
+#endif
+
+ m_app.parameterSetup();
+ m_app.createOptionsModel(true /* reset settings */);
+ QScopedPointer<const NetworkStyle> style(
+ NetworkStyle::instantiate(QString::fromStdString(Params().NetworkIDString())));
+ m_app.setupPlatformStyle();
+ m_app.createWindow(style.data());
+ connect(&m_app, &BitcoinApplication::windowShown, this, &AppTests::guiTests);
+ expectCallback("guiTests");
+ m_app.baseInitialize();
+ m_app.requestInitialize();
+ m_app.exec();
+ m_app.requestShutdown();
+ m_app.exec();
+
+ // Reset global state to avoid interfering with later tests.
+ AbortShutdown();
+ UnloadBlockIndex();
+}
+
+//! Entry point for BitcoinGUI tests.
+void AppTests::guiTests(BitcoinGUI* window)
+{
+ HandleCallback callback{"guiTests", *this};
+ connect(window, &BitcoinGUI::consoleShown, this, &AppTests::consoleTests);
+ expectCallback("consoleTests");
+ QAction* action = window->findChild<QAction*>("openRPCConsoleAction");
+ action->activate(QAction::Trigger);
+}
+
+//! Entry point for RPCConsole tests.
+void AppTests::consoleTests(RPCConsole* console)
+{
+ HandleCallback callback{"consoleTests", *this};
+ TestRpcCommand(console);
+}
+
+//! Destructor to shut down after the last expected callback completes.
+AppTests::HandleCallback::~HandleCallback()
+{
+ auto& callbacks = m_app_tests.m_callbacks;
+ auto it = callbacks.find(m_callback);
+ assert(it != callbacks.end());
+ callbacks.erase(it);
+ if (callbacks.empty()) {
+ m_app_tests.m_app.quit();
+ }
+}
diff --git a/src/qt/test/apptests.h b/src/qt/test/apptests.h
new file mode 100644
index 0000000000..83bf56f1e4
--- /dev/null
+++ b/src/qt/test/apptests.h
@@ -0,0 +1,50 @@
+// 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_QT_TEST_APPTESTS_H
+#define BITCOIN_QT_TEST_APPTESTS_H
+
+#include <QObject>
+#include <set>
+#include <string>
+#include <utility>
+
+class BitcoinApplication;
+class BitcoinGUI;
+class RPCConsole;
+
+class AppTests : public QObject
+{
+ Q_OBJECT
+public:
+ explicit AppTests(BitcoinApplication& app) : m_app(app) {}
+
+private Q_SLOTS:
+ void appTests();
+ void guiTests(BitcoinGUI* window);
+ void consoleTests(RPCConsole* console);
+
+private:
+ //! Add expected callback name to list of pending callbacks.
+ void expectCallback(std::string callback) { m_callbacks.emplace(std::move(callback)); }
+
+ //! RAII helper to remove no-longer-pending callback.
+ struct HandleCallback
+ {
+ std::string m_callback;
+ AppTests& m_app_tests;
+ ~HandleCallback();
+ };
+
+ //! Bitcoin application.
+ BitcoinApplication& m_app;
+
+ //! Set of pending callback names. Used to track expected callbacks and shut
+ //! down the app after the last callback has been handled and all tests have
+ //! either run or thrown exceptions. This could be a simple int counter
+ //! instead of a set of names, but the names might be useful for debugging.
+ std::multiset<std::string> m_callbacks;
+};
+
+#endif // BITCOIN_QT_TEST_APPTESTS_H
diff --git a/src/qt/test/rpcnestedtests.cpp b/src/qt/test/rpcnestedtests.cpp
index ed453336da..173c814f1e 100644
--- a/src/qt/test/rpcnestedtests.cpp
+++ b/src/qt/test/rpcnestedtests.cpp
@@ -41,7 +41,7 @@ void RPCNestedTests::rpcNestedTests()
TestingSetup test;
- SetRPCWarmupFinished();
+ if (RPCIsInWarmup(nullptr)) SetRPCWarmupFinished();
std::string result;
std::string result2;
diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp
index b6523604fd..a2bf53973b 100644
--- a/src/qt/test/test_main.cpp
+++ b/src/qt/test/test_main.cpp
@@ -7,6 +7,9 @@
#endif
#include <chainparams.h>
+#include <interfaces/node.h>
+#include <qt/bitcoin.h>
+#include <qt/test/apptests.h>
#include <qt/test/rpcnestedtests.h>
#include <util/system.h>
#include <qt/test/uritests.h>
@@ -47,12 +50,13 @@ int main(int argc, char *argv[])
{
SetupEnvironment();
SetupNetworking();
- SelectParams(CBaseChainParams::MAIN);
+ SelectParams(CBaseChainParams::REGTEST);
noui_connect();
ClearDatadirCache();
fs::path pathTemp = fs::temp_directory_path() / strprintf("test_bitcoin-qt_%lu_%i", (unsigned long)GetTime(), (int)GetRand(100000));
fs::create_directories(pathTemp);
gArgs.ForceSetArg("-datadir", pathTemp.string());
+ auto node = interfaces::MakeNode();
bool fInvalid = false;
@@ -67,11 +71,15 @@ int main(int argc, char *argv[])
// Don't remove this, it's needed to access
// QApplication:: and QCoreApplication:: in the tests
- QApplication app(argc, argv);
+ BitcoinApplication app(*node, argc, argv);
app.setApplicationName("Bitcoin-Qt-test");
SSL_library_init();
+ AppTests app_tests(app);
+ if (QTest::qExec(&app_tests) != 0) {
+ fInvalid = true;
+ }
URITests test1;
if (QTest::qExec(&test1) != 0) {
fInvalid = true;
diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp
index d15bd95b8e..4f8b6d363e 100644
--- a/src/qt/walletframe.cpp
+++ b/src/qt/walletframe.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2018 The Bitcoin Core developers
+// Copyright (c) 2011-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -46,8 +46,7 @@ bool WalletFrame::addWallet(WalletModel *walletModel)
return false;
}
- const QString name = walletModel->getWalletName();
- if (mapWalletViews.count(name) > 0) {
+ if (mapWalletViews.count(walletModel) > 0) {
return false;
}
@@ -65,7 +64,7 @@ bool WalletFrame::addWallet(WalletModel *walletModel)
}
walletStack->addWidget(walletView);
- mapWalletViews[name] = walletView;
+ mapWalletViews[walletModel] = walletView;
// Ensure a walletView is able to show the main window
connect(walletView, &WalletView::showNormalIfMinimized, [this]{
@@ -77,24 +76,24 @@ bool WalletFrame::addWallet(WalletModel *walletModel)
return true;
}
-bool WalletFrame::setCurrentWallet(const QString& name)
+bool WalletFrame::setCurrentWallet(WalletModel* wallet_model)
{
- if (mapWalletViews.count(name) == 0)
+ if (mapWalletViews.count(wallet_model) == 0)
return false;
- WalletView *walletView = mapWalletViews.value(name);
+ WalletView *walletView = mapWalletViews.value(wallet_model);
walletStack->setCurrentWidget(walletView);
assert(walletView);
walletView->updateEncryptionStatus();
return true;
}
-bool WalletFrame::removeWallet(const QString &name)
+bool WalletFrame::removeWallet(WalletModel* wallet_model)
{
- if (mapWalletViews.count(name) == 0)
+ if (mapWalletViews.count(wallet_model) == 0)
return false;
- WalletView *walletView = mapWalletViews.take(name);
+ WalletView *walletView = mapWalletViews.take(wallet_model);
walletStack->removeWidget(walletView);
delete walletView;
return true;
@@ -102,7 +101,7 @@ bool WalletFrame::removeWallet(const QString &name)
void WalletFrame::removeAllWallets()
{
- QMap<QString, WalletView*>::const_iterator i;
+ QMap<WalletModel*, WalletView*>::const_iterator i;
for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i)
walletStack->removeWidget(i.value());
mapWalletViews.clear();
@@ -120,35 +119,35 @@ bool WalletFrame::handlePaymentRequest(const SendCoinsRecipient &recipient)
void WalletFrame::showOutOfSyncWarning(bool fShow)
{
bOutOfSync = fShow;
- QMap<QString, WalletView*>::const_iterator i;
+ QMap<WalletModel*, WalletView*>::const_iterator i;
for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i)
i.value()->showOutOfSyncWarning(fShow);
}
void WalletFrame::gotoOverviewPage()
{
- QMap<QString, WalletView*>::const_iterator i;
+ QMap<WalletModel*, WalletView*>::const_iterator i;
for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i)
i.value()->gotoOverviewPage();
}
void WalletFrame::gotoHistoryPage()
{
- QMap<QString, WalletView*>::const_iterator i;
+ QMap<WalletModel*, WalletView*>::const_iterator i;
for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i)
i.value()->gotoHistoryPage();
}
void WalletFrame::gotoReceiveCoinsPage()
{
- QMap<QString, WalletView*>::const_iterator i;
+ QMap<WalletModel*, WalletView*>::const_iterator i;
for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i)
i.value()->gotoReceiveCoinsPage();
}
void WalletFrame::gotoSendCoinsPage(QString addr)
{
- QMap<QString, WalletView*>::const_iterator i;
+ QMap<WalletModel*, WalletView*>::const_iterator i;
for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i)
i.value()->gotoSendCoinsPage(addr);
}
diff --git a/src/qt/walletframe.h b/src/qt/walletframe.h
index 1963e89b24..9fbc8b4d52 100644
--- a/src/qt/walletframe.h
+++ b/src/qt/walletframe.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2018 The Bitcoin Core developers
+// Copyright (c) 2011-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -37,8 +37,8 @@ public:
void setClientModel(ClientModel *clientModel);
bool addWallet(WalletModel *walletModel);
- bool setCurrentWallet(const QString& name);
- bool removeWallet(const QString &name);
+ bool setCurrentWallet(WalletModel* wallet_model);
+ bool removeWallet(WalletModel* wallet_model);
void removeAllWallets();
bool handlePaymentRequest(const SendCoinsRecipient& recipient);
@@ -53,7 +53,7 @@ private:
QStackedWidget *walletStack;
BitcoinGUI *gui;
ClientModel *clientModel;
- QMap<QString, WalletView*> mapWalletViews;
+ QMap<WalletModel*, WalletView*> mapWalletViews;
bool bOutOfSync;
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index ba16fdd5e1..0a5b21f997 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2018 The Bitcoin Core developers
+// Copyright (c) 2011-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -40,8 +40,6 @@ WalletModel::WalletModel(std::unique_ptr<interfaces::Wallet> wallet, interfaces:
cachedNumBlocks(0)
{
fHaveWatchOnly = m_wallet->haveWatchOnly();
- fForceCheckBalanceChanged = false;
-
addressTableModel = new AddressTableModel(this);
transactionTableModel = new TransactionTableModel(platformStyle, this);
recentRequestsTableModel = new RecentRequestsTableModel(this);
@@ -578,6 +576,12 @@ QString WalletModel::getWalletName() const
return QString::fromStdString(m_wallet->getWalletName());
}
+QString WalletModel::getDisplayName() const
+{
+ const QString name = getWalletName();
+ return name.isEmpty() ? "["+tr("default wallet")+"]" : name;
+}
+
bool WalletModel::isMultiwallet()
{
return m_node.getWallets().size() > 1;
diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h
index ec4c5a2a6c..6a6c538157 100644
--- a/src/qt/walletmodel.h
+++ b/src/qt/walletmodel.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2018 The Bitcoin Core developers
+// Copyright (c) 2011-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -219,6 +219,7 @@ public:
interfaces::Wallet& wallet() const { return *m_wallet; }
QString getWalletName() const;
+ QString getDisplayName() const;
bool isMultiwallet();
@@ -234,7 +235,7 @@ private:
interfaces::Node& m_node;
bool fHaveWatchOnly;
- bool fForceCheckBalanceChanged;
+ bool fForceCheckBalanceChanged{false};
// Wallet has an options model for wallet-specific options
// (transaction fee, for example)
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 55282f433f..315f69d46b 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -747,15 +747,20 @@ static UniValue getblockheader(const JSONRPCRequest& request)
+ HelpExampleRpc("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
);
- LOCK(cs_main);
-
uint256 hash(ParseHashV(request.params[0], "hash"));
bool fVerbose = true;
if (!request.params[1].isNull())
fVerbose = request.params[1].get_bool();
- const CBlockIndex* pblockindex = LookupBlockIndex(hash);
+ const CBlockIndex* pblockindex;
+ const CBlockIndex* tip;
+ {
+ LOCK(cs_main);
+ pblockindex = LookupBlockIndex(hash);
+ tip = chainActive.Tip();
+ }
+
if (!pblockindex) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
}
@@ -768,7 +773,7 @@ static UniValue getblockheader(const JSONRPCRequest& request)
return strHex;
}
- return blockheaderToJSON(chainActive.Tip(), pblockindex);
+ return blockheaderToJSON(tip, pblockindex);
}
static CBlock GetBlockChecked(const CBlockIndex* pblockindex)
@@ -1564,7 +1569,7 @@ static UniValue reconsiderblock(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() != 1)
throw std::runtime_error(
RPCHelpMan{"reconsiderblock",
- "\nRemoves invalidity status of a block and its descendants, reconsider them for activation.\n"
+ "\nRemoves invalidity status of a block, its ancestors and its descendants, reconsider them for activation.\n"
"This can be used to undo the effects of invalidateblock.\n",
{
{"blockhash", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "the hash of the block to reconsider"},
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index 4d6b260cc7..cc229367ba 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Copyright (c) 2009-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -109,11 +109,15 @@ static UniValue getpeerinfo(const JSONRPCRequest& request)
" \"whitelisted\": true|false, (boolean) Whether the peer is whitelisted\n"
" \"minfeefilter\": n, (numeric) The minimum fee rate for transactions this peer accepts\n"
" \"bytessent_per_msg\": {\n"
- " \"addr\": n, (numeric) The total bytes sent aggregated by message type\n"
+ " \"msg\": n, (numeric) The total bytes sent aggregated by message type\n"
+ " When a message type is not listed in this json object, the bytes sent are 0.\n"
+ " Only known message types can appear as keys in the object.\n"
" ...\n"
" },\n"
" \"bytesrecv_per_msg\": {\n"
- " \"addr\": n, (numeric) The total bytes received aggregated by message type\n"
+ " \"msg\": n, (numeric) The total bytes received aggregated by message type\n"
+ " When a message type is not listed in this json object, the bytes received are 0.\n"
+ " Only known message types can appear as keys in the object and all bytes received of unknown message types are listed under '"+NET_MESSAGE_COMMAND_OTHER+"'.\n"
" ...\n"
" }\n"
" }\n"
@@ -178,14 +182,14 @@ static UniValue getpeerinfo(const JSONRPCRequest& request)
obj.pushKV("minfeefilter", ValueFromAmount(stats.minFeeFilter));
UniValue sendPerMsgCmd(UniValue::VOBJ);
- for (const mapMsgCmdSize::value_type &i : stats.mapSendBytesPerMsgCmd) {
+ for (const auto& i : stats.mapSendBytesPerMsgCmd) {
if (i.second > 0)
sendPerMsgCmd.pushKV(i.first, i.second);
}
obj.pushKV("bytessent_per_msg", sendPerMsgCmd);
UniValue recvPerMsgCmd(UniValue::VOBJ);
- for (const mapMsgCmdSize::value_type &i : stats.mapRecvBytesPerMsgCmd) {
+ for (const auto& i : stats.mapRecvBytesPerMsgCmd) {
if (i.second > 0)
recvPerMsgCmd.pushKV(i.first, i.second);
}
diff --git a/src/streams.h b/src/streams.h
index 8010a061c7..0809c96be1 100644
--- a/src/streams.h
+++ b/src/streams.h
@@ -120,12 +120,6 @@ class CVectorWriter
{
return nType;
}
- void seek(size_t nSize)
- {
- nPos += nSize;
- if(nPos > vchData.size())
- vchData.resize(nPos);
- }
private:
const int nType;
const int nVersion;
@@ -152,9 +146,11 @@ public:
* @param[in] pos Starting position. Vector index where reads should start.
*/
VectorReader(int type, int version, const std::vector<unsigned char>& data, size_t pos)
- : m_type(type), m_version(version), m_data(data)
+ : m_type(type), m_version(version), m_data(data), m_pos(pos)
{
- seek(pos);
+ if (m_pos > m_data.size()) {
+ throw std::ios_base::failure("VectorReader(...): end of data (m_pos > m_data.size())");
+ }
}
/*
@@ -197,14 +193,6 @@ public:
memcpy(dst, m_data.data() + m_pos, n);
m_pos = pos_next;
}
-
- void seek(size_t n)
- {
- m_pos += n;
- if (m_pos > m_data.size()) {
- throw std::ios_base::failure("VectorReader::seek(): end of data");
- }
- }
};
/** Double ended buffer combining vector and stream-like interfaces.
diff --git a/src/support/allocators/secure.h b/src/support/allocators/secure.h
index 7cd0df135d..57f5b1f733 100644
--- a/src/support/allocators/secure.h
+++ b/src/support/allocators/secure.h
@@ -40,7 +40,11 @@ struct secure_allocator : public std::allocator<T> {
T* allocate(std::size_t n, const void* hint = 0)
{
- return static_cast<T*>(LockedPoolManager::Instance().alloc(sizeof(T) * n));
+ T* allocation = static_cast<T*>(LockedPoolManager::Instance().alloc(sizeof(T) * n));
+ if (!allocation) {
+ throw std::bad_alloc();
+ }
+ return allocation;
}
void deallocate(T* p, std::size_t n)
diff --git a/src/support/lockedpool.cpp b/src/support/lockedpool.cpp
index 8d577cf521..627018083e 100644
--- a/src/support/lockedpool.cpp
+++ b/src/support/lockedpool.cpp
@@ -248,6 +248,9 @@ void *PosixLockedPageAllocator::AllocateLocked(size_t len, bool *lockingSuccess)
void *addr;
len = align_up(len, page_size);
addr = mmap(nullptr, len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+ if (addr == MAP_FAILED) {
+ return nullptr;
+ }
if (addr) {
*lockingSuccess = mlock(addr, len) == 0;
}
diff --git a/src/support/lockedpool.h b/src/support/lockedpool.h
index 48ffd7b307..b420c909fc 100644
--- a/src/support/lockedpool.h
+++ b/src/support/lockedpool.h
@@ -22,7 +22,7 @@ public:
virtual ~LockedPageAllocator() {}
/** Allocate and lock memory pages.
* If len is not a multiple of the system page size, it is rounded up.
- * Returns 0 in case of allocation failure.
+ * Returns nullptr in case of allocation failure.
*
* If locking the memory pages could not be accomplished it will still
* return the memory, however the lockingSuccess flag will be false.
diff --git a/src/test/addrman_tests.cpp b/src/test/addrman_tests.cpp
index 234da5ae4d..22347fbc57 100644
--- a/src/test/addrman_tests.cpp
+++ b/src/test/addrman_tests.cpp
@@ -12,13 +12,9 @@
class CAddrManTest : public CAddrMan
{
- uint64_t state;
-
public:
explicit CAddrManTest(bool makeDeterministic = true)
{
- state = 1;
-
if (makeDeterministic) {
// Set addrman addr placement to be deterministic.
MakeDeterministic();
diff --git a/src/test/getarg_tests.cpp b/src/test/getarg_tests.cpp
index 14ddf4d10e..8048238028 100644
--- a/src/test/getarg_tests.cpp
+++ b/src/test/getarg_tests.cpp
@@ -2,6 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <util/strencodings.h>
#include <util/system.h>
#include <test/test_bitcoin.h>
@@ -17,7 +18,7 @@ static void ResetArgs(const std::string& strArg)
{
std::vector<std::string> vecArg;
if (strArg.size())
- boost::split(vecArg, strArg, boost::is_space(), boost::token_compress_on);
+ boost::split(vecArg, strArg, IsSpace, boost::token_compress_on);
// Insert dummy executable name:
vecArg.insert(vecArg.begin(), "testbitcoin");
diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp
index e7a3c96343..4dc394b86d 100644
--- a/src/test/net_tests.cpp
+++ b/src/test/net_tests.cpp
@@ -227,4 +227,93 @@ BOOST_AUTO_TEST_CASE(ipv4_peer_with_ipv6_addrMe_test)
BOOST_CHECK(1);
}
+
+BOOST_AUTO_TEST_CASE(LimitedAndReachable_Network)
+{
+ SetLimited(NET_IPV4, true);
+ SetLimited(NET_IPV6, true);
+ SetLimited(NET_ONION, true);
+
+ BOOST_CHECK_EQUAL(IsLimited(NET_IPV4), true);
+ BOOST_CHECK_EQUAL(IsLimited(NET_IPV6), true);
+ BOOST_CHECK_EQUAL(IsLimited(NET_ONION), true);
+
+ BOOST_CHECK_EQUAL(IsReachable(NET_IPV4), false);
+ BOOST_CHECK_EQUAL(IsReachable(NET_IPV6), false);
+ BOOST_CHECK_EQUAL(IsReachable(NET_ONION), false);
+
+
+ SetLimited(NET_IPV4, false);
+ SetLimited(NET_IPV6, false);
+ SetLimited(NET_ONION, false);
+
+ BOOST_CHECK_EQUAL(IsLimited(NET_IPV4), false);
+ BOOST_CHECK_EQUAL(IsLimited(NET_IPV6), false);
+ BOOST_CHECK_EQUAL(IsLimited(NET_ONION), false);
+
+ BOOST_CHECK_EQUAL(IsReachable(NET_IPV4), true);
+ BOOST_CHECK_EQUAL(IsReachable(NET_IPV6), true);
+ BOOST_CHECK_EQUAL(IsReachable(NET_ONION), true);
+}
+
+BOOST_AUTO_TEST_CASE(LimitedAndReachable_NetworkCaseUnroutableAndInternal)
+{
+ BOOST_CHECK_EQUAL(IsLimited(NET_UNROUTABLE), false);
+ BOOST_CHECK_EQUAL(IsLimited(NET_INTERNAL), false);
+
+ BOOST_CHECK_EQUAL(IsReachable(NET_UNROUTABLE), true);
+ BOOST_CHECK_EQUAL(IsReachable(NET_INTERNAL), true);
+
+ SetLimited(NET_UNROUTABLE, true);
+ SetLimited(NET_INTERNAL, true);
+
+ BOOST_CHECK_EQUAL(IsLimited(NET_UNROUTABLE), false); // Ignored for both networks
+ BOOST_CHECK_EQUAL(IsLimited(NET_INTERNAL), false);
+
+ BOOST_CHECK_EQUAL(IsReachable(NET_UNROUTABLE), true);
+ BOOST_CHECK_EQUAL(IsReachable(NET_INTERNAL), true);
+}
+
+CNetAddr UtilBuildAddress(unsigned char p1, unsigned char p2, unsigned char p3, unsigned char p4)
+{
+ unsigned char ip[] = {p1, p2, p3, p4};
+
+ struct sockaddr_in sa;
+ memset(&sa, 0, sizeof(sockaddr_in)); // initialize the memory block
+ memcpy(&(sa.sin_addr), &ip, sizeof(ip));
+ return CNetAddr(sa.sin_addr);
+}
+
+
+BOOST_AUTO_TEST_CASE(LimitedAndReachable_CNetAddr)
+{
+ CNetAddr addr = UtilBuildAddress(0x001, 0x001, 0x001, 0x001); // 1.1.1.1
+
+ SetLimited(NET_IPV4, false);
+ BOOST_CHECK_EQUAL(IsLimited(addr), false);
+ BOOST_CHECK_EQUAL(IsReachable(addr), true);
+
+ SetLimited(NET_IPV4, true);
+ BOOST_CHECK_EQUAL(IsLimited(addr), true);
+ BOOST_CHECK_EQUAL(IsReachable(addr), false);
+
+ SetLimited(NET_IPV4, false); // have to reset this, because this is stateful.
+}
+
+
+BOOST_AUTO_TEST_CASE(LocalAddress_BasicLifecycle)
+{
+ CService addr = CService(UtilBuildAddress(0x002, 0x001, 0x001, 0x001), 1000); // 2.1.1.1:1000
+
+ SetLimited(NET_IPV4, false);
+
+ BOOST_CHECK_EQUAL(IsLocal(addr), false);
+ BOOST_CHECK_EQUAL(AddLocal(addr, 1000), true);
+ BOOST_CHECK_EQUAL(IsLocal(addr), true);
+
+ RemoveLocal(addr);
+ BOOST_CHECK_EQUAL(IsLocal(addr), false);
+}
+
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/streams_tests.cpp b/src/test/streams_tests.cpp
index 26cf74830d..a1940eb80e 100644
--- a/src/test/streams_tests.cpp
+++ b/src/test/streams_tests.cpp
@@ -102,15 +102,15 @@ BOOST_AUTO_TEST_CASE(streams_vector_reader)
BOOST_CHECK_THROW(reader >> d, std::ios_base::failure);
// Read a 4 bytes as a signed int from the beginning of the buffer.
- reader.seek(-6);
- reader >> d;
+ VectorReader new_reader(SER_NETWORK, INIT_PROTO_VERSION, vch, 0);
+ new_reader >> d;
BOOST_CHECK_EQUAL(d, 67370753); // 1,255,3,4 in little-endian base-256
- BOOST_CHECK_EQUAL(reader.size(), 2);
- BOOST_CHECK(!reader.empty());
+ BOOST_CHECK_EQUAL(new_reader.size(), 2);
+ BOOST_CHECK(!new_reader.empty());
// Reading after end of byte vector throws an error even if the reader is
// not totally empty.
- BOOST_CHECK_THROW(reader >> d, std::ios_base::failure);
+ BOOST_CHECK_THROW(new_reader >> d, std::ios_base::failure);
}
BOOST_AUTO_TEST_CASE(bitstream_reader_writer)
diff --git a/src/test/txindex_tests.cpp b/src/test/txindex_tests.cpp
index 43e025c58f..0301901bf0 100644
--- a/src/test/txindex_tests.cpp
+++ b/src/test/txindex_tests.cpp
@@ -2,6 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <chainparams.h>
#include <index/txindex.h>
#include <script/standard.h>
#include <test/test_bitcoin.h>
@@ -38,6 +39,12 @@ BOOST_FIXTURE_TEST_CASE(txindex_initial_sync, TestChain100Setup)
MilliSleep(100);
}
+ // Check that txindex excludes genesis block transactions.
+ const CBlock& genesis_block = Params().GenesisBlock();
+ for (const auto& txn : genesis_block.vtx) {
+ BOOST_CHECK(!txindex.FindTx(txn->GetHash(), block_hash, tx_disk));
+ }
+
// Check that txindex has all txs that were in the chain before it started.
for (const auto& txn : m_coinbase_txns) {
if (!txindex.FindTx(txn->GetHash(), block_hash, tx_disk)) {
diff --git a/src/uint256.cpp b/src/uint256.cpp
index d9da668036..b723f9ee54 100644
--- a/src/uint256.cpp
+++ b/src/uint256.cpp
@@ -33,7 +33,7 @@ void base_blob<BITS>::SetHex(const char* psz)
psz++;
// skip 0x
- if (psz[0] == '0' && tolower(psz[1]) == 'x')
+ if (psz[0] == '0' && ToLower((unsigned char)psz[1]) == 'x')
psz += 2;
// hex string to uint
diff --git a/src/util/moneystr.cpp b/src/util/moneystr.cpp
index 4c4de7b729..f4e41eea4f 100644
--- a/src/util/moneystr.cpp
+++ b/src/util/moneystr.cpp
@@ -20,7 +20,7 @@ std::string FormatMoney(const CAmount& n)
// Right-trim excess zeros before the decimal point:
int nTrim = 0;
- for (int i = str.size()-1; (str[i] == '0' && isdigit(str[i-2])); --i)
+ for (int i = str.size()-1; (str[i] == '0' && IsDigit(str[i-2])); --i)
++nTrim;
if (nTrim)
str.erase(str.size()-nTrim, nTrim);
@@ -49,7 +49,7 @@ bool ParseMoney(const char* pszIn, CAmount& nRet)
{
p++;
int64_t nMult = COIN / 10;
- while (isdigit(*p) && (nMult > 0))
+ while (IsDigit(*p) && (nMult > 0))
{
nUnits += nMult * (*p++ - '0');
nMult /= 10;
@@ -58,7 +58,7 @@ bool ParseMoney(const char* pszIn, CAmount& nRet)
}
if (IsSpace(*p))
break;
- if (!isdigit(*p))
+ if (!IsDigit(*p))
return false;
strWhole.insert(strWhole.end(), *p);
}
diff --git a/src/util/system.cpp b/src/util/system.cpp
index 8e201ec590..a4bf126900 100644
--- a/src/util/system.cpp
+++ b/src/util/system.cpp
@@ -443,7 +443,7 @@ bool ArgsManager::ParseParameters(int argc, const char* const argv[], std::strin
key.erase(is_index);
}
#ifdef WIN32
- std::transform(key.begin(), key.end(), key.begin(), ::tolower);
+ std::transform(key.begin(), key.end(), key.begin(), ToLower);
if (key[0] == '/')
key[0] = '-';
#endif
@@ -865,7 +865,7 @@ static bool GetConfigOptions(std::istream& stream, std::string& error, std::vect
} else if ((pos = str.find('=')) != std::string::npos) {
std::string name = prefix + TrimString(str.substr(0, pos), pattern);
std::string value = TrimString(str.substr(pos + 1), pattern);
- if (used_hash && name == "rpcpassword") {
+ if (used_hash && name.find("rpcpassword") != std::string::npos) {
error = strprintf("parse error on line %i, using # in rpcpassword can be ambiguous and should be avoided", linenr);
return false;
}
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index c1cdd0b2ee..38397a3940 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -1020,15 +1020,12 @@ static UniValue addmultisigaddress(const JSONRPCRequest& request)
struct tallyitem
{
- CAmount nAmount;
- int nConf;
+ CAmount nAmount{0};
+ int nConf{std::numeric_limits<int>::max()};
std::vector<uint256> txids;
- bool fIsWatchonly;
+ bool fIsWatchonly{false};
tallyitem()
{
- nAmount = 0;
- nConf = std::numeric_limits<int>::max();
- fIsWatchonly = false;
}
};
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index 1ed1926af2..0db22cf6fe 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2018 The Bitcoin Core developers
+// Copyright (c) 2012-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -47,7 +47,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
auto locked_chain = chain->lock();
- // Verify ScanForWalletTransactions accomodates a null start block.
+ // Verify ScanForWalletTransactions accommodates a null start block.
{
CWallet wallet(*chain, WalletLocation(), WalletDatabase::CreateDummy());
AddKey(wallet, coinbaseKey);
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 95a2c833f8..3a3ec43c9b 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -1178,18 +1178,16 @@ class CReserveKey final : public CReserveScript
{
protected:
CWallet* pwallet;
- int64_t nIndex;
+ int64_t nIndex{-1};
CPubKey vchPubKey;
- bool fInternal;
+ bool fInternal{false};
+
public:
explicit CReserveKey(CWallet* pwalletIn)
{
- nIndex = -1;
pwallet = pwalletIn;
- fInternal = false;
}
- CReserveKey() = default;
CReserveKey(const CReserveKey&) = delete;
CReserveKey& operator=(const CReserveKey&) = delete;
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index 09a33f252c..6e037808e3 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -153,21 +153,17 @@ bool WalletBatch::WriteMinVersion(int nVersion)
class CWalletScanState {
public:
- unsigned int nKeys;
- unsigned int nCKeys;
- unsigned int nWatchKeys;
- unsigned int nKeyMeta;
- unsigned int m_unknown_records;
- bool fIsEncrypted;
- bool fAnyUnordered;
- int nFileVersion;
+ unsigned int nKeys{0};
+ unsigned int nCKeys{0};
+ unsigned int nWatchKeys{0};
+ unsigned int nKeyMeta{0};
+ unsigned int m_unknown_records{0};
+ bool fIsEncrypted{false};
+ bool fAnyUnordered{false};
+ int nFileVersion{0};
std::vector<uint256> vWalletUpgrade;
CWalletScanState() {
- nKeys = nCKeys = nWatchKeys = nKeyMeta = m_unknown_records = 0;
- fIsEncrypted = false;
- fAnyUnordered = false;
- nFileVersion = 0;
}
};
diff --git a/test/functional/feature_block.py b/test/functional/feature_block.py
index 697a0b19ac..5253ff7aaa 100755
--- a/test/functional/feature_block.py
+++ b/test/functional/feature_block.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2018 The Bitcoin Core developers
+# Copyright (c) 2015-2019 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test block processing."""
@@ -137,12 +137,6 @@ class FullBlockTest(BitcoinTestFramework):
for TxTemplate in invalid_txs.iter_all_templates():
template = TxTemplate(spend_tx=attempt_spend_tx)
- # Something about the serialization code for missing inputs creates
- # a different hash in the test client than on bitcoind, resulting
- # in a mismatching merkle root during block validation.
- # Skip until we figure out what's going on.
- if TxTemplate == invalid_txs.InputMissing:
- continue
if template.valid_in_block:
continue
@@ -150,7 +144,22 @@ class FullBlockTest(BitcoinTestFramework):
blockname = "for_invalid.%s" % TxTemplate.__name__
badblock = self.next_block(blockname)
badtx = template.get_tx()
- self.sign_tx(badtx, attempt_spend_tx)
+ if TxTemplate != invalid_txs.InputMissing:
+ self.sign_tx(badtx, attempt_spend_tx)
+ else:
+ # Segwit is active in regtest at this point, so to deserialize a
+ # transaction without any inputs correctly, we set the outputs
+ # to an empty list. This is a hack, as the serialization of an
+ # empty list of outputs is deserialized as flags==0 and thus
+ # deserialization of the outputs is skipped.
+ # A policy check requires "loose" txs to be of a minimum size,
+ # so vtx is not set to be empty in the TxTemplate class and we
+ # only apply the workaround where txs are not "loose", i.e. in
+ # blocks.
+ #
+ # The workaround has the purpose that both sides calculate
+ # the same tx hash in the merkle tree
+ badtx.vout = []
badtx.rehash()
badblock = self.update_block(blockname, [badtx])
self.sync_blocks(
@@ -916,7 +925,7 @@ class FullBlockTest(BitcoinTestFramework):
# \-> b67 (20)
#
#
- self.log.info("Reject a block with a transaction double spending a transaction creted in the same block")
+ self.log.info("Reject a block with a transaction double spending a transaction created in the same block")
self.move_tip(65)
b67 = self.next_block(67)
tx1 = self.create_and_sign_transaction(out[20], out[20].vout[0].nValue)
@@ -1211,7 +1220,7 @@ class FullBlockTest(BitcoinTestFramework):
blocks = []
spend = out[32]
for i in range(89, LARGE_REORG_SIZE + 89):
- b = self.next_block(i, spend)
+ b = self.next_block(i, spend, version=4)
tx = CTransaction()
script_length = MAX_BLOCK_BASE_SIZE - len(b.serialize()) - 69
script_output = CScript([b'\x00' * script_length])
@@ -1230,20 +1239,32 @@ class FullBlockTest(BitcoinTestFramework):
self.move_tip(88)
blocks2 = []
for i in range(89, LARGE_REORG_SIZE + 89):
- blocks2.append(self.next_block("alt" + str(i)))
+ blocks2.append(self.next_block("alt" + str(i), version=4))
self.sync_blocks(blocks2, False, force_send=True)
# extend alt chain to trigger re-org
- block = self.next_block("alt" + str(chain1_tip + 1))
+ block = self.next_block("alt" + str(chain1_tip + 1), version=4)
self.sync_blocks([block], True, timeout=480)
# ... and re-org back to the first chain
self.move_tip(chain1_tip)
- block = self.next_block(chain1_tip + 1)
+ block = self.next_block(chain1_tip + 1, version=4)
self.sync_blocks([block], False, force_send=True)
- block = self.next_block(chain1_tip + 2)
+ block = self.next_block(chain1_tip + 2, version=4)
self.sync_blocks([block], True, timeout=480)
+ self.log.info("Reject a block with an invalid block header version")
+ b_v1 = self.next_block('b_v1', version=1)
+ self.sync_blocks([b_v1], success=False, force_send=True, reject_reason='bad-version(0x00000001)')
+
+ self.move_tip(chain1_tip + 2)
+ b_cb34 = self.next_block('b_cb34', version=4)
+ b_cb34.vtx[0].vin[0].scriptSig = b_cb34.vtx[0].vin[0].scriptSig[:-1]
+ b_cb34.vtx[0].rehash()
+ b_cb34.hashMerkleRoot = b_cb34.calc_merkle_root()
+ b_cb34.solve()
+ self.sync_blocks([b_cb34], success=False, reject_reason='bad-cb-height', reconnect=True)
+
# Helper methods
################
@@ -1271,7 +1292,7 @@ class FullBlockTest(BitcoinTestFramework):
tx.rehash()
return tx
- def next_block(self, number, spend=None, additional_coinbase_value=0, script=CScript([OP_TRUE]), solve=True):
+ def next_block(self, number, spend=None, additional_coinbase_value=0, script=CScript([OP_TRUE]), solve=True, *, version=1):
if self.tip is None:
base_block_hash = self.genesis_hash
block_time = int(time.time()) + 1
@@ -1284,11 +1305,11 @@ class FullBlockTest(BitcoinTestFramework):
coinbase.vout[0].nValue += additional_coinbase_value
coinbase.rehash()
if spend is None:
- block = create_block(base_block_hash, coinbase, block_time)
+ block = create_block(base_block_hash, coinbase, block_time, version=version)
else:
coinbase.vout[0].nValue += spend.vout[0].nValue - 1 # all but one satoshi to fees
coinbase.rehash()
- block = create_block(base_block_hash, coinbase, block_time)
+ block = create_block(base_block_hash, coinbase, block_time, version=version)
tx = self.create_tx(spend, 0, 1, script) # spend 1 satoshi
self.sign_tx(tx, spend)
self.add_transactions_to_block(block, [tx])
diff --git a/test/functional/feature_config_args.py b/test/functional/feature_config_args.py
index d87eabaa6d..4b3f6603a2 100755
--- a/test/functional/feature_config_args.py
+++ b/test/functional/feature_config_args.py
@@ -34,6 +34,14 @@ class ConfArgsTest(BitcoinTestFramework):
self.nodes[0].assert_start_raises_init_error(expected_msg='Error reading configuration file: parse error on line 3, using # in rpcpassword can be ambiguous and should be avoided')
with open(inc_conf_file_path, 'w', encoding='utf-8') as conf:
+ conf.write('server=1\nrpcuser=someuser\nmain.rpcpassword=some#pass')
+ self.nodes[0].assert_start_raises_init_error(expected_msg='Error reading configuration file: parse error on line 3, using # in rpcpassword can be ambiguous and should be avoided')
+
+ with open(inc_conf_file_path, 'w', encoding='utf-8') as conf:
+ conf.write('server=1\nrpcuser=someuser\n[main]\nrpcpassword=some#pass')
+ self.nodes[0].assert_start_raises_init_error(expected_msg='Error reading configuration file: parse error on line 4, using # in rpcpassword can be ambiguous and should be avoided')
+
+ with open(inc_conf_file_path, 'w', encoding='utf-8') as conf:
conf.write('testnot.datadir=1\n[testnet]\n')
self.restart_node(0)
self.nodes[0].stop_node(expected_stderr='Warning: Section [testnet] is not recognized.' + os.linesep + 'Warning: Section [testnot] is not recognized.')
diff --git a/test/functional/rpc_invalidateblock.py b/test/functional/rpc_invalidateblock.py
index d8ecdd573a..d8a1deb2a3 100755
--- a/test/functional/rpc_invalidateblock.py
+++ b/test/functional/rpc_invalidateblock.py
@@ -4,10 +4,15 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the invalidateblock RPC."""
-import time
-
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import assert_equal, connect_nodes_bi, sync_blocks
+from test_framework.address import ADDRESS_BCRT1_UNSPENDABLE
+from test_framework.util import (
+ assert_equal,
+ connect_nodes_bi,
+ sync_blocks,
+ wait_until,
+)
+
class InvalidateTest(BitcoinTestFramework):
def set_test_params(self):
@@ -21,46 +26,66 @@ class InvalidateTest(BitcoinTestFramework):
self.log.info("Make sure we repopulate setBlockIndexCandidates after InvalidateBlock:")
self.log.info("Mine 4 blocks on Node 0")
self.nodes[0].generatetoaddress(4, self.nodes[0].get_deterministic_priv_key().address)
- assert(self.nodes[0].getblockcount() == 4)
- besthash = self.nodes[0].getbestblockhash()
+ assert_equal(self.nodes[0].getblockcount(), 4)
+ besthash_n0 = self.nodes[0].getbestblockhash()
self.log.info("Mine competing 6 blocks on Node 1")
self.nodes[1].generatetoaddress(6, self.nodes[1].get_deterministic_priv_key().address)
- assert(self.nodes[1].getblockcount() == 6)
+ assert_equal(self.nodes[1].getblockcount(), 6)
self.log.info("Connect nodes to force a reorg")
- connect_nodes_bi(self.nodes,0,1)
+ connect_nodes_bi(self.nodes, 0, 1)
sync_blocks(self.nodes[0:2])
- assert(self.nodes[0].getblockcount() == 6)
+ assert_equal(self.nodes[0].getblockcount(), 6)
badhash = self.nodes[1].getblockhash(2)
self.log.info("Invalidate block 2 on node 0 and verify we reorg to node 0's original chain")
self.nodes[0].invalidateblock(badhash)
- newheight = self.nodes[0].getblockcount()
- newhash = self.nodes[0].getbestblockhash()
- if (newheight != 4 or newhash != besthash):
- raise AssertionError("Wrong tip for node0, hash %s, height %d"%(newhash,newheight))
+ assert_equal(self.nodes[0].getblockcount(), 4)
+ assert_equal(self.nodes[0].getbestblockhash(), besthash_n0)
self.log.info("Make sure we won't reorg to a lower work chain:")
- connect_nodes_bi(self.nodes,1,2)
+ connect_nodes_bi(self.nodes, 1, 2)
self.log.info("Sync node 2 to node 1 so both have 6 blocks")
sync_blocks(self.nodes[1:3])
- assert(self.nodes[2].getblockcount() == 6)
+ assert_equal(self.nodes[2].getblockcount(), 6)
self.log.info("Invalidate block 5 on node 1 so its tip is now at 4")
self.nodes[1].invalidateblock(self.nodes[1].getblockhash(5))
- assert(self.nodes[1].getblockcount() == 4)
+ assert_equal(self.nodes[1].getblockcount(), 4)
self.log.info("Invalidate block 3 on node 2, so its tip is now 2")
self.nodes[2].invalidateblock(self.nodes[2].getblockhash(3))
- assert(self.nodes[2].getblockcount() == 2)
+ assert_equal(self.nodes[2].getblockcount(), 2)
self.log.info("..and then mine a block")
self.nodes[2].generatetoaddress(1, self.nodes[2].get_deterministic_priv_key().address)
self.log.info("Verify all nodes are at the right height")
- time.sleep(5)
- assert_equal(self.nodes[2].getblockcount(), 3)
- assert_equal(self.nodes[0].getblockcount(), 4)
- node1height = self.nodes[1].getblockcount()
- if node1height < 4:
- raise AssertionError("Node 1 reorged to a lower height: %d"%node1height)
+ wait_until(lambda: self.nodes[2].getblockcount() == 3, timeout=5)
+ wait_until(lambda: self.nodes[0].getblockcount() == 4, timeout=5)
+ wait_until(lambda: self.nodes[1].getblockcount() == 4, timeout=5)
+
+ self.log.info("Verify that we reconsider all ancestors as well")
+ blocks = self.nodes[1].generatetoaddress(10, ADDRESS_BCRT1_UNSPENDABLE)
+ assert_equal(self.nodes[1].getbestblockhash(), blocks[-1])
+ # Invalidate the two blocks at the tip
+ self.nodes[1].invalidateblock(blocks[-1])
+ self.nodes[1].invalidateblock(blocks[-2])
+ assert_equal(self.nodes[1].getbestblockhash(), blocks[-3])
+ # Reconsider only the previous tip
+ self.nodes[1].reconsiderblock(blocks[-1])
+ # Should be back at the tip by now
+ assert_equal(self.nodes[1].getbestblockhash(), blocks[-1])
+
+ self.log.info("Verify that we reconsider all descendants")
+ blocks = self.nodes[1].generatetoaddress(10, ADDRESS_BCRT1_UNSPENDABLE)
+ assert_equal(self.nodes[1].getbestblockhash(), blocks[-1])
+ # Invalidate the two blocks at the tip
+ self.nodes[1].invalidateblock(blocks[-2])
+ self.nodes[1].invalidateblock(blocks[-4])
+ assert_equal(self.nodes[1].getbestblockhash(), blocks[-5])
+ # Reconsider only the previous tip
+ self.nodes[1].reconsiderblock(blocks[-4])
+ # Should be back at the tip by now
+ assert_equal(self.nodes[1].getbestblockhash(), blocks[-1])
+
if __name__ == '__main__':
InvalidateTest().main()
diff --git a/test/functional/test_framework/blocktools.py b/test/functional/test_framework/blocktools.py
index 7679ea5398..6b47cae4c3 100644
--- a/test/functional/test_framework/blocktools.py
+++ b/test/functional/test_framework/blocktools.py
@@ -46,9 +46,10 @@ MAX_BLOCK_SIGOPS = 20000
# From BIP141
WITNESS_COMMITMENT_HEADER = b"\xaa\x21\xa9\xed"
-def create_block(hashprev, coinbase, ntime=None):
+def create_block(hashprev, coinbase, ntime=None, *, version=1):
"""Create a block (with regtest difficulty)."""
block = CBlock()
+ block.nVersion = version
if ntime is None:
import time
block.nTime = int(time.time() + 600)
diff --git a/test/lint/lint-locale-dependence.sh b/test/lint/lint-locale-dependence.sh
index 44170a6b5a..1534d5ef68 100755
--- a/test/lint/lint-locale-dependence.sh
+++ b/test/lint/lint-locale-dependence.sh
@@ -4,30 +4,21 @@ export LC_ALL=C
KNOWN_VIOLATIONS=(
"src/bitcoin-tx.cpp.*stoul"
"src/bitcoin-tx.cpp.*trim_right"
- "src/bitcoin-tx.cpp:.*atoi"
- "src/core_read.cpp.*is_digit"
"src/dbwrapper.cpp.*stoul"
"src/dbwrapper.cpp:.*vsnprintf"
"src/httprpc.cpp.*trim"
"src/init.cpp:.*atoi"
"src/qt/rpcconsole.cpp:.*atoi"
- "src/qt/rpcconsole.cpp:.*isdigit"
"src/rest.cpp:.*strtol"
"src/test/dbwrapper_tests.cpp:.*snprintf"
- "src/test/getarg_tests.cpp.*split"
"src/torcontrol.cpp:.*atoi"
"src/torcontrol.cpp:.*strtol"
- "src/uint256.cpp:.*tolower"
- "src/util/system.cpp:.*atoi"
- "src/util/system.cpp:.*fprintf"
- "src/util/system.cpp:.*tolower"
- "src/util/moneystr.cpp:.*isdigit"
"src/util/strencodings.cpp:.*atoi"
"src/util/strencodings.cpp:.*strtol"
- "src/util/strencodings.cpp:.*strtoll"
"src/util/strencodings.cpp:.*strtoul"
- "src/util/strencodings.cpp:.*strtoull"
"src/util/strencodings.h:.*atoi"
+ "src/util/system.cpp:.*atoi"
+ "src/util/system.cpp:.*fprintf"
)
REGEXP_IGNORE_EXTERNAL_DEPENDENCIES="^src/(crypto/ctaes/|leveldb/|secp256k1/|tinyformat.h|univalue/)"
diff --git a/test/sanitizer_suppressions/ubsan b/test/sanitizer_suppressions/ubsan
index e90d5c2ac0..f0107f1361 100644
--- a/test/sanitizer_suppressions/ubsan
+++ b/test/sanitizer_suppressions/ubsan
@@ -29,7 +29,6 @@ unsigned-integer-overflow:policy/fees.cpp
unsigned-integer-overflow:prevector.h
unsigned-integer-overflow:script/interpreter.cpp
unsigned-integer-overflow:stl_bvector.h
-unsigned-integer-overflow:streams.h
unsigned-integer-overflow:txmempool.cpp
unsigned-integer-overflow:util/strencodings.cpp
unsigned-integer-overflow:validation.cpp