aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac30
-rw-r--r--contrib/qos/tc.sh2
-rw-r--r--contrib/verify-commits/README.md17
-rw-r--r--contrib/verify-commits/trusted-keys1
-rwxr-xr-xcontrib/verify-commits/verify-commits.py2
-rw-r--r--doc/developer-notes.md29
-rw-r--r--doc/release-process.md2
-rw-r--r--src/arith_uint256.h3
-rw-r--r--src/bitcoin-cli.cpp3
-rw-r--r--src/bitcoin-tx.cpp4
-rw-r--r--src/chain.h9
-rw-r--r--src/httpserver.cpp32
-rw-r--r--src/net_processing.cpp4
-rw-r--r--src/primitives/transaction.h8
-rw-r--r--src/qt/bitcoin.cpp23
-rw-r--r--src/qt/bitcoingui.cpp4
-rw-r--r--src/qt/guiutil.cpp2
-rwxr-xr-xsrc/qt/res/movies/makespinner.sh2
-rw-r--r--src/qt/splashscreen.cpp4
-rw-r--r--src/qt/splashscreen.h7
-rw-r--r--src/rpc/blockchain.cpp10
-rw-r--r--src/rpc/client.cpp1
-rw-r--r--src/rpc/mining.cpp6
-rw-r--r--src/rpc/misc.cpp8
-rw-r--r--src/rpc/net.cpp10
-rw-r--r--src/rpc/rawtransaction.cpp34
-rw-r--r--src/rpc/server.cpp10
-rw-r--r--src/rpc/util.cpp10
-rw-r--r--src/rpc/util.h7
-rw-r--r--src/streams.h4
-rw-r--r--src/test/rpc_tests.cpp3
-rw-r--r--src/test/serialize_tests.cpp2
-rw-r--r--src/test/sighash_tests.cpp2
-rw-r--r--src/validation.cpp26
-rw-r--r--src/wallet/rpcdump.cpp10
-rw-r--r--src/wallet/rpcwallet.cpp95
-rwxr-xr-xtest/functional/feature_shutdown.py28
-rwxr-xr-xtest/functional/rpc_rawtransaction.py13
-rwxr-xr-xtest/functional/test_framework/test_framework.py8
-rwxr-xr-xtest/functional/test_framework/test_node.py4
-rw-r--r--test/functional/test_framework/util.py2
-rwxr-xr-xtest/functional/test_runner.py3
-rwxr-xr-xtest/lint/commit-script-check.sh18
-rwxr-xr-xtest/lint/lint-python-dead-code.sh2
-rwxr-xr-xtest/lint/lint-shebang.sh (renamed from test/lint/lint-python-shebang.sh)9
45 files changed, 298 insertions, 215 deletions
diff --git a/configure.ac b/configure.ac
index 170e0e06cf..2d34b83047 100644
--- a/configure.ac
+++ b/configure.ac
@@ -214,7 +214,7 @@ AC_ARG_ENABLE([bip70],
[AS_HELP_STRING([--disable-bip70],
[disable BIP70 (payment protocol) support in GUI (enabled by default)])],
[enable_bip70=$enableval],
- [enable_bip70=yes])
+ [enable_bip70=auto])
AC_ARG_WITH([protoc-bindir],[AS_HELP_STRING([--with-protoc-bindir=BIN_DIR],[specify protoc bin path])], [protoc_bin_path=$withval], [])
@@ -1089,7 +1089,7 @@ if test x$use_pkgconfig = xyes; then
PKG_CHECK_MODULES([SSL], [libssl],, [AC_MSG_ERROR(openssl not found.)])
PKG_CHECK_MODULES([CRYPTO], [libcrypto],,[AC_MSG_ERROR(libcrypto not found.)])
if test x$enable_bip70 != xno; then
- BITCOIN_QT_CHECK([PKG_CHECK_MODULES([PROTOBUF], [protobuf], [have_protobuf=yes], [BITCOIN_QT_FAIL(libprotobuf not found)])])
+ BITCOIN_QT_CHECK([PKG_CHECK_MODULES([PROTOBUF], [protobuf], [have_protobuf=yes], [have_protobuf=no])])
fi
if test x$use_qr != xno; then
BITCOIN_QT_CHECK([PKG_CHECK_MODULES([QR], [libqrencode], [have_qrencode=yes], [have_qrencode=no])])
@@ -1151,7 +1151,7 @@ else
fi
if test x$enable_bip70 != xno; then
- BITCOIN_QT_CHECK(AC_CHECK_LIB([protobuf] ,[main],[PROTOBUF_LIBS=-lprotobuf], BITCOIN_QT_FAIL(libprotobuf not found)))
+ BITCOIN_QT_CHECK(AC_CHECK_LIB([protobuf] ,[main],[PROTOBUF_LIBS=-lprotobuf], [have_protobuf=no]))
fi
if test x$use_qr != xno; then
BITCOIN_QT_CHECK([AC_CHECK_LIB([qrencode], [main],[QR_LIBS=-lqrencode], [have_qrencode=no])])
@@ -1230,8 +1230,10 @@ AM_CONDITIONAL([EMBEDDED_UNIVALUE],[test x$need_bundled_univalue = xyes])
AC_SUBST(UNIVALUE_CFLAGS)
AC_SUBST(UNIVALUE_LIBS)
-if test x$enable_bip70 != xno; then
-BITCOIN_QT_PATH_PROGS([PROTOC], [protoc],$protoc_bin_path)
+
+if test x$have_protobuf != xno &&
+ test x$enable_bip70 != xno; then
+ BITCOIN_QT_PATH_PROGS([PROTOC], [protoc],$protoc_bin_path)
fi
AC_MSG_CHECKING([whether to build bitcoind])
@@ -1352,12 +1354,20 @@ if test x$bitcoin_enable_qt != xno; then
fi
AC_MSG_CHECKING([whether to build BIP70 support])
- if test x$enable_bip70 != xno; then
- AC_DEFINE([ENABLE_BIP70],[1],[Define if BIP70 support should be compiled in])
- enable_bip70=yes
- AC_MSG_RESULT([yes])
+ if test x$have_protobuf = xno; then
+ if test x$enable_bip70 = xyes; then
+ AC_MSG_ERROR(protobuf missing)
+ fi
+ enable_bip70=no
+ AC_MSG_RESULT(no)
else
- AC_MSG_RESULT([no])
+ if test x$enable_bip70 != xno; then
+ AC_DEFINE([ENABLE_BIP70],[1],[Define if BIP70 support should be compiled in])
+ enable_bip70=yes
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ fi
fi
fi
diff --git a/contrib/qos/tc.sh b/contrib/qos/tc.sh
index 738ea70dbe..5f9b87d9b2 100644
--- a/contrib/qos/tc.sh
+++ b/contrib/qos/tc.sh
@@ -1,3 +1,5 @@
+#!/usr/bin/env bash
+#
# Copyright (c) 2017 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/contrib/verify-commits/README.md b/contrib/verify-commits/README.md
index aa805ad1b9..27ca15acb4 100644
--- a/contrib/verify-commits/README.md
+++ b/contrib/verify-commits/README.md
@@ -3,7 +3,7 @@ Tooling for verification of PGP signed commits
This is an incomplete work in progress, but currently includes a pre-push hook
script (`pre-push-hook.sh`) for maintainers to ensure that their own commits
-are PGP signed (nearly always merge commits), as well as a script to verify
+are PGP signed (nearly always merge commits), as well as a Python 3 script to verify
commits against a trusted keys list.
@@ -17,9 +17,11 @@ be backdoored. Instead, you need to use a trusted version of verify-commits
prior to checkout to make sure you're checking out only code signed by trusted
keys:
- git fetch origin && \
- ./contrib/verify-commits/verify-commits.py origin/master && \
- git checkout origin/master
+ ```sh
+ git fetch origin && \
+ ./contrib/verify-commits/verify-commits.py origin/master && \
+ git checkout origin/master
+ ```
Note that the above isn't a good UI/UX yet, and needs significant improvements
to make it more convenient and reduce the chance of errors; pull-reqs
@@ -33,6 +35,13 @@ Configuration files
* `trusted-keys`: This file should contain a \n-delimited list of all PGP fingerprints of authorized commit signers (primary, not subkeys).
* `allow-revsig-commits`: This file should contain a \n-delimited list of git commit hashes. See next section for more info.
+Import trusted keys
+-------------------
+In order to check the commit signatures you must add the trusted PGP keys to your machine. This can be done in Linux by running
+```sh
+gpg --recv-keys $(<contrib/verify-commits/trusted-keys)
+```
+
Key expiry/revocation
---------------------
diff --git a/contrib/verify-commits/trusted-keys b/contrib/verify-commits/trusted-keys
index 5610692616..a10da9d822 100644
--- a/contrib/verify-commits/trusted-keys
+++ b/contrib/verify-commits/trusted-keys
@@ -2,3 +2,4 @@
133EAC179436F14A5CF1B794860FEB804E669320
32EE5C4C3FA15CCADB46ABE529D4BCB6416F53EC
B8B3F1C0E58C15DB6A81D30C3648A882F4316B9B
+CA03882CB1FC067B5D3ACFE4D300116E1C875A3D
diff --git a/contrib/verify-commits/verify-commits.py b/contrib/verify-commits/verify-commits.py
index 544f4dc48d..b3c8064ec2 100755
--- a/contrib/verify-commits/verify-commits.py
+++ b/contrib/verify-commits/verify-commits.py
@@ -139,7 +139,7 @@ def main():
if len(parents) == 2 and check_merge and not allow_unclean:
current_tree = subprocess.check_output([GIT, 'show', '--format=%T', current_commit], universal_newlines=True, encoding='utf8').splitlines()[0]
subprocess.call([GIT, 'checkout', '--force', '--quiet', parents[0]])
- subprocess.call([GIT, 'merge', '--no-ff', '--quiet', parents[1]], stdout=subprocess.DEVNULL)
+ subprocess.call([GIT, 'merge', '--no-ff', '--quiet', '--no-gpg-sign', parents[1]], stdout=subprocess.DEVNULL)
recreated_tree = subprocess.check_output([GIT, 'show', '--format=format:%T', 'HEAD'], universal_newlines=True, encoding='utf8').splitlines()[0]
if current_tree != recreated_tree:
print("Merge commit {} is not clean".format(current_commit), file=sys.stderr)
diff --git a/doc/developer-notes.md b/doc/developer-notes.md
index bb477d4be0..a6df17ddd8 100644
--- a/doc/developer-notes.md
+++ b/doc/developer-notes.md
@@ -28,6 +28,8 @@ Developer Notes
- [Strings and formatting](#strings-and-formatting)
- [Variable names](#variable-names)
- [Threads and synchronization](#threads-and-synchronization)
+ - [Scripts](#scripts)
+ - [Shebang](#shebang)
- [Source code organization](#source-code-organization)
- [GUI](#gui)
- [Subtrees](#subtrees)
@@ -602,6 +604,31 @@ TRY_LOCK(cs_vNodes, lockNodes);
}
```
+Scripts
+--------------------------
+
+### Shebang
+
+- Use `#!/usr/bin/env bash` instead of obsolete `#!/bin/bash`.
+
+ - [*Rationale*](https://github.com/dylanaraps/pure-bash-bible#shebang):
+
+ `#!/bin/bash` assumes it is always installed to /bin/ which can cause issues;
+
+ `#!/usr/bin/env bash` searches the user's PATH to find the bash binary.
+
+ OK:
+
+```bash
+#!/usr/bin/env bash
+```
+
+ Wrong:
+
+```bash
+#!/bin/bash
+```
+
Source code organization
--------------------------
@@ -714,7 +741,7 @@ Current subtrees include:
- Upstream at https://github.com/bitcoin-core/ctaes ; actively maintained by Core contributors.
- src/univalue
- - Upstream at https://github.com/jgarzik/univalue ; report important PRs to Core to avoid delay.
+ - Upstream at https://github.com/bitcoin-core/univalue ; actively maintained by Core contributors, deviates from upstream https://github.com/jgarzik/univalue
Upgrading LevelDB
---------------------
diff --git a/doc/release-process.md b/doc/release-process.md
index dafb32512a..97fedb6e24 100644
--- a/doc/release-process.md
+++ b/doc/release-process.md
@@ -87,7 +87,7 @@ Ensure gitian-builder is up-to-date:
pushd ./gitian-builder
mkdir -p inputs
wget -P inputs https://bitcoincore.org/cfields/osslsigncode-Backports-to-1.7.1.patch
- wget -P inputs http://downloads.sourceforge.net/project/osslsigncode/osslsigncode/osslsigncode-1.7.1.tar.gz
+ wget -P inputs https://downloads.sourceforge.net/project/osslsigncode/osslsigncode/osslsigncode-1.7.1.tar.gz
popd
Create the macOS SDK tarball, see the [macOS readme](README_osx.md) for details, and copy it into the inputs directory.
diff --git a/src/arith_uint256.h b/src/arith_uint256.h
index 5cc273be27..bd0360087d 100644
--- a/src/arith_uint256.h
+++ b/src/arith_uint256.h
@@ -8,6 +8,7 @@
#include <assert.h>
#include <cstring>
+#include <limits>
#include <stdexcept>
#include <stdint.h>
#include <string>
@@ -189,7 +190,7 @@ public:
{
// prefix operator
int i = 0;
- while (i < WIDTH && --pn[i] == (uint32_t)-1)
+ while (i < WIDTH && --pn[i] == std::numeric_limits<uint32_t>::max())
i++;
return *this;
}
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index 262458a684..7cdf61ad35 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -492,9 +492,6 @@ static int CommandLineRPC(int argc, char *argv[])
}
} while (fWait);
}
- catch (const boost::thread_interrupted&) {
- throw;
- }
catch (const std::exception& e) {
strPrint = std::string("error: ") + e.what();
nRet = EXIT_FAILURE;
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index bc91ca3641..2e41adc276 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -820,10 +820,6 @@ static int CommandLineRawTx(int argc, char* argv[])
OutputTx(tx);
}
-
- catch (const boost::thread_interrupted&) {
- throw;
- }
catch (const std::exception& e) {
strPrint = std::string("error: ") + e.what();
nRet = EXIT_FAILURE;
diff --git a/src/chain.h b/src/chain.h
index 1c0c5a7e69..3b786664af 100644
--- a/src/chain.h
+++ b/src/chain.h
@@ -294,6 +294,15 @@ public:
return *phashBlock;
}
+ /**
+ * Check whether this block's and all previous blocks' transactions have been
+ * downloaded (and stored to disk) at some point.
+ *
+ * Does not imply the transactions are consensus-valid (ConnectTip might fail)
+ * Does not imply the transactions are still stored on disk. (IsBlockPruned might return true)
+ */
+ bool HaveTxsDownloaded() const { return nChainTx != 0; }
+
int64_t GetBlockTime() const
{
return (int64_t)nTime;
diff --git a/src/httpserver.cpp b/src/httpserver.cpp
index 00434169cd..cb8578927a 100644
--- a/src/httpserver.cpp
+++ b/src/httpserver.cpp
@@ -10,6 +10,7 @@
#include <util/strencodings.h>
#include <netbase.h>
#include <rpc/protocol.h> // For HTTP status codes
+#include <shutdown.h>
#include <sync.h>
#include <ui_interface.h>
@@ -21,7 +22,6 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
-#include <future>
#include <event2/thread.h>
#include <event2/buffer.h>
@@ -421,7 +421,6 @@ bool UpdateHTTPServerLogging(bool enable) {
}
std::thread threadHTTP;
-std::future<bool> threadResult;
static std::vector<std::thread> g_thread_http_workers;
void StartHTTPServer()
@@ -429,9 +428,7 @@ void StartHTTPServer()
LogPrint(BCLog::HTTP, "Starting HTTP server\n");
int rpcThreads = std::max((long)gArgs.GetArg("-rpcthreads", DEFAULT_HTTP_THREADS), 1L);
LogPrintf("HTTP: starting %d worker threads\n", rpcThreads);
- std::packaged_task<bool(event_base*)> task(ThreadHTTP);
- threadResult = task.get_future();
- threadHTTP = std::thread(std::move(task), eventBase);
+ threadHTTP = std::thread(ThreadHTTP, eventBase);
for (int i = 0; i < rpcThreads; i++) {
g_thread_http_workers.emplace_back(HTTPWorkQueueRun, workQueue);
@@ -442,10 +439,6 @@ void InterruptHTTPServer()
{
LogPrint(BCLog::HTTP, "Interrupting HTTP server\n");
if (eventHTTP) {
- // Unlisten sockets
- for (evhttp_bound_socket *socket : boundSockets) {
- evhttp_del_accept_socket(eventHTTP, socket);
- }
// Reject requests on current connections
evhttp_set_gencb(eventHTTP, http_reject_request_cb, nullptr);
}
@@ -465,20 +458,14 @@ void StopHTTPServer()
delete workQueue;
workQueue = nullptr;
}
+ // Unlisten sockets, these are what make the event loop running, which means
+ // that after this and all connections are closed the event loop will quit.
+ for (evhttp_bound_socket *socket : boundSockets) {
+ evhttp_del_accept_socket(eventHTTP, socket);
+ }
+ boundSockets.clear();
if (eventBase) {
LogPrint(BCLog::HTTP, "Waiting for HTTP event thread to exit\n");
- // Exit the event loop as soon as there are no active events.
- event_base_loopexit(eventBase, nullptr);
- // Give event loop a few seconds to exit (to send back last RPC responses), then break it
- // Before this was solved with event_base_loopexit, but that didn't work as expected in
- // at least libevent 2.0.21 and always introduced a delay. In libevent
- // master that appears to be solved, so in the future that solution
- // could be used again (if desirable).
- // (see discussion in https://github.com/bitcoin/bitcoin/pull/6990)
- if (threadResult.valid() && threadResult.wait_for(std::chrono::milliseconds(2000)) == std::future_status::timeout) {
- LogPrintf("HTTP event loop did not exit within allotted time, sending loopbreak\n");
- event_base_loopbreak(eventBase);
- }
threadHTTP.join();
}
if (eventHTTP) {
@@ -583,6 +570,9 @@ void HTTPRequest::WriteHeader(const std::string& hdr, const std::string& value)
void HTTPRequest::WriteReply(int nStatus, const std::string& strReply)
{
assert(!replySent && req);
+ if (ShutdownRequested()) {
+ WriteHeader("Connection", "close");
+ }
// Send event to main http thread to send reply message
struct evbuffer* evb = evhttp_request_get_output_buffer(req);
assert(evb);
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index f4ab3aa153..40c5112578 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -566,7 +566,7 @@ static void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vec
return;
}
if (pindex->nStatus & BLOCK_HAVE_DATA || chainActive.Contains(pindex)) {
- if (pindex->nChainTx)
+ if (pindex->HaveTxsDownloaded())
state->pindexLastCommonBlock = pindex;
} else if (mapBlocksInFlight.count(pindex->GetBlockHash()) == 0) {
// The block is not already downloaded, and not yet in flight.
@@ -1124,7 +1124,7 @@ void static ProcessGetBlockData(CNode* pfrom, const CChainParams& chainparams, c
LOCK(cs_main);
const CBlockIndex* pindex = LookupBlockIndex(inv.hash);
if (pindex) {
- if (pindex->nChainTx && !pindex->IsValid(BLOCK_VALID_SCRIPTS) &&
+ if (pindex->HaveTxsDownloaded() && !pindex->IsValid(BLOCK_VALID_SCRIPTS) &&
pindex->IsValid(BLOCK_VALID_TREE)) {
// If we have the block and all of its parents, but have not yet validated it,
// we might be in the middle of connecting it (ie in the unlock of cs_main
diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h
index 0f834eb8c1..c88d5b1ad3 100644
--- a/src/primitives/transaction.h
+++ b/src/primitives/transaction.h
@@ -21,7 +21,9 @@ public:
uint256 hash;
uint32_t n;
- COutPoint(): n((uint32_t) -1) { }
+ static constexpr uint32_t NULL_INDEX = std::numeric_limits<uint32_t>::max();
+
+ COutPoint(): n(NULL_INDEX) { }
COutPoint(const uint256& hashIn, uint32_t nIn): hash(hashIn), n(nIn) { }
ADD_SERIALIZE_METHODS;
@@ -32,8 +34,8 @@ public:
READWRITE(n);
}
- void SetNull() { hash.SetNull(); n = (uint32_t) -1; }
- bool IsNull() const { return (hash.IsNull() && n == (uint32_t) -1); }
+ void SetNull() { hash.SetNull(); n = NULL_INDEX; }
+ bool IsNull() const { return (hash.IsNull() && n == NULL_INDEX); }
friend bool operator<(const COutPoint& a, const COutPoint& b)
{
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index de236a016f..eaeb93a652 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -71,11 +71,6 @@ Q_DECLARE_METATYPE(bool*)
Q_DECLARE_METATYPE(CAmount)
Q_DECLARE_METATYPE(uint256)
-static void InitMessage(const std::string& message)
-{
- noui_InitMessage(message);
-}
-
/** 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();
@@ -217,7 +212,7 @@ Q_SIGNALS:
void requestedInitialize();
void requestedShutdown();
void stopThread();
- void splashFinished(QWidget *window);
+ void splashFinished();
private:
QThread *coreThread;
@@ -357,9 +352,9 @@ void BitcoinApplication::createSplashScreen(const NetworkStyle *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
- // screen will take care of deleting itself when slotFinish happens.
+ // screen will take care of deleting itself when finish() happens.
splash->show();
- connect(this, &BitcoinApplication::splashFinished, splash, &SplashScreen::slotFinish);
+ connect(this, &BitcoinApplication::splashFinished, splash, &SplashScreen::finish);
connect(this, &BitcoinApplication::requestedShutdown, splash, &QWidget::close);
}
@@ -500,7 +495,7 @@ void BitcoinApplication::initializeResult(bool success)
{
window->show();
}
- Q_EMIT splashFinished(window);
+ Q_EMIT splashFinished();
#ifdef ENABLE_WALLET
// Now that initialization/startup is done, process any command-line
@@ -514,7 +509,7 @@ void BitcoinApplication::initializeResult(bool success)
#endif
pollShutdownTimer->start(200);
} else {
- Q_EMIT splashFinished(window); // Make sure splash screen doesn't stick around during shutdown
+ Q_EMIT splashFinished(); // Make sure splash screen doesn't stick around during shutdown
quit(); // Exit first main loop invocation
}
}
@@ -563,6 +558,11 @@ int main(int argc, char *argv[])
std::unique_ptr<interfaces::Node> node = interfaces::MakeNode();
+ // Subscribe to global signals from core
+ std::unique_ptr<interfaces::Handler> handler_message_box = node->handleMessageBox(noui_ThreadSafeMessageBox);
+ std::unique_ptr<interfaces::Handler> handler_question = node->handleQuestion(noui_ThreadSafeQuestion);
+ std::unique_ptr<interfaces::Handler> handler_init_message = node->handleInitMessage(noui_InitMessage);
+
// Do not refer to data directory yet, this can be overridden by Intro::pickDataDirectory
/// 1. Basic Qt initialization (not dependent on parameters or configuration)
@@ -696,9 +696,6 @@ int main(int argc, char *argv[])
// Load GUI settings from QSettings
app.createOptionsModel(gArgs.GetBoolArg("-resetguisettings", false));
- // Subscribe to global signals from core
- std::unique_ptr<interfaces::Handler> handler = node->handleInitMessage(InitMessage);
-
if (gArgs.GetBoolArg("-splash", DEFAULT_SPLASHSCREEN) && !gArgs.GetBoolArg("-min", false))
app.createSplashScreen(networkStyle.data());
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index ed705d6ba8..a16b2ddebf 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -31,7 +31,6 @@
#include <chainparams.h>
#include <interfaces/handler.h>
#include <interfaces/node.h>
-#include <noui.h>
#include <ui_interface.h>
#include <util/system.h>
@@ -1226,9 +1225,6 @@ void BitcoinGUI::showModalOverlay()
static bool ThreadSafeMessageBox(BitcoinGUI* gui, const std::string& message, const std::string& caption, unsigned int style)
{
- // Redundantly log and print message in non-gui fashion
- noui_ThreadSafeMessageBox(message, caption, style);
-
bool modal = (style & CClientUIInterface::MODAL);
// The SECURE flag has no effect in the Qt GUI.
// bool secure = (style & CClientUIInterface::SECURE);
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index 0e9aca21b1..2fc166b0c5 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -339,7 +339,7 @@ bool checkPoint(const QPoint &p, const QWidget *w)
{
QWidget *atW = QApplication::widgetAt(w->mapToGlobal(p));
if (!atW) return false;
- return atW->topLevelWidget() == w;
+ return atW->window() == w;
}
bool isObscured(QWidget *w)
diff --git a/src/qt/res/movies/makespinner.sh b/src/qt/res/movies/makespinner.sh
index 76e36e4f31..f47c66e02c 100755
--- a/src/qt/res/movies/makespinner.sh
+++ b/src/qt/res/movies/makespinner.sh
@@ -1,3 +1,5 @@
+#!/usr/bin/env bash
+#
# Copyright (c) 2014-2015 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp
index df38285d08..7b952f9fd7 100644
--- a/src/qt/splashscreen.cpp
+++ b/src/qt/splashscreen.cpp
@@ -145,10 +145,8 @@ bool SplashScreen::eventFilter(QObject * obj, QEvent * ev) {
return QObject::eventFilter(obj, ev);
}
-void SplashScreen::slotFinish(QWidget *mainWin)
+void SplashScreen::finish()
{
- Q_UNUSED(mainWin);
-
/* If the window is minimized, hide() will be ignored. */
/* Make sure we de-minimize the splashscreen window before hiding */
if (isMinimized())
diff --git a/src/qt/splashscreen.h b/src/qt/splashscreen.h
index c28b6e5660..f99dd0c701 100644
--- a/src/qt/splashscreen.h
+++ b/src/qt/splashscreen.h
@@ -5,8 +5,7 @@
#ifndef BITCOIN_QT_SPLASHSCREEN_H
#define BITCOIN_QT_SPLASHSCREEN_H
-#include <functional>
-#include <QSplashScreen>
+#include <QWidget>
#include <memory>
@@ -37,8 +36,8 @@ protected:
void closeEvent(QCloseEvent *event);
public Q_SLOTS:
- /** Slot to call finish() method as it's not defined as slot */
- void slotFinish(QWidget *mainWin);
+ /** Hide the splash screen window and schedule the splash screen object for deletion */
+ void finish();
/** Show message and progress */
void showMessage(const QString &message, int alignment, const QColor &color);
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index b53ac63f26..ec87f42c93 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -212,11 +212,9 @@ static UniValue waitfornewblock(const JSONRPCRequest& request)
"\nWaits for a specific new block and returns useful info about it.\n"
"\nReturns the current block on timeout or exit.\n",
{
- {"timeout", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "", ""},
+ {"timeout", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "0", "Time in milliseconds to wait for a response. 0 indicates no timeout."},
}}
.ToString() +
- "\nArguments:\n"
- "1. timeout (int, optional, default=0) Time in milliseconds to wait for a response. 0 indicates no timeout.\n"
"\nResult:\n"
"{ (json object)\n"
" \"hash\" : { (string) The blockhash\n"
@@ -1424,7 +1422,7 @@ static UniValue getchaintips(const JSONRPCRequest& request)
} else if (block->nStatus & BLOCK_FAILED_MASK) {
// This block or one of its ancestors is invalid.
status = "invalid";
- } else if (block->nChainTx == 0) {
+ } else if (!block->HaveTxsDownloaded()) {
// This block cannot be connected because full block data for it or one of its parents is missing.
status = "headers-only";
} else if (block->IsValid(BLOCK_VALID_SCRIPTS)) {
@@ -1609,7 +1607,7 @@ static UniValue getchaintxstats(const JSONRPCRequest& request)
"\nCompute statistics about the total number and rate of transactions in the chain.\n",
{
{"nblocks", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "one month", "Size of the window in number of blocks"},
- {"blockhash", RPCArg::Type::STR_HEX, /* opt */ true, /* default_val */ "", "The hash of the block that ends the window."},
+ {"blockhash", RPCArg::Type::STR_HEX, /* opt */ true, /* default_val */ "chain tip", "The hash of the block that ends the window."},
}}
.ToString() +
"\nResult:\n"
@@ -1743,7 +1741,7 @@ static UniValue getblockstats(const JSONRPCRequest& request)
"It won't work without -txindex for utxo_size_inc, *fee or *feerate stats.\n",
{
{"hash_or_height", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "The block hash or height of the target block", "", {"", "string or numeric"}},
- {"stats", RPCArg::Type::ARR, /* opt */ true, /* default_val */ "", "Values to plot, by default all values (see result below)",
+ {"stats", RPCArg::Type::ARR, /* opt */ true, /* default_val */ "all values", "Values to plot (see result below)",
{
{"height", RPCArg::Type::STR, /* opt */ true, /* default_val */ "", "Selected statistic"},
{"time", RPCArg::Type::STR, /* opt */ true, /* default_val */ "", "Selected statistic"},
diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp
index 2b99808c07..6f1bfb03d1 100644
--- a/src/rpc/client.cpp
+++ b/src/rpc/client.cpp
@@ -162,6 +162,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "rescanblockchain", 1, "stop_height"},
{ "createwallet", 1, "disable_private_keys"},
{ "getnodeaddresses", 0, "count"},
+ { "stop", 0, "wait" },
};
// clang-format on
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index f0a7589cfb..93fa3a2728 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -717,7 +717,7 @@ static UniValue submitblock(const JSONRPCRequest& request)
"See https://en.bitcoin.it/wiki/BIP_0022 for full specification.\n",
{
{"hexdata", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "the hex-encoded block data to submit"},
- {"dummy", RPCArg::Type::STR, /* opt */ true, /* default_val */ "", "dummy value, for compatibility with BIP22. This value is ignored."},
+ {"dummy", RPCArg::Type::STR, /* opt */ true, /* default_val */ "ignored", "dummy value, for compatibility with BIP22. This value is ignored."},
}}
.ToString() +
"\nResult:\n"
@@ -888,9 +888,9 @@ static UniValue estimaterawfee(const JSONRPCRequest& request)
"defined in BIP 141 (witness data is discounted).\n",
{
{"conf_target", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "Confirmation target in blocks (1 - 1008)"},
- {"threshold", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "", "The proportion of transactions in a given feerate range that must have been\n"
+ {"threshold", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "0.95", "The proportion of transactions in a given feerate range that must have been\n"
" confirmed within conf_target in order to consider those feerates as high enough and proceed to check\n"
- " lower buckets. Default: 0.95"},
+ " lower buckets."},
}}
.ToString() +
"\nResult:\n"
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index 71c94ae499..18c867bff3 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -90,7 +90,7 @@ static UniValue createmultisig(const JSONRPCRequest& request)
{
{"key", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The hex-encoded public key"},
}},
- {"address_type", RPCArg::Type::STR, /* opt */ true, /* default_val */ "", "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\". Default is legacy."},
+ {"address_type", RPCArg::Type::STR, /* opt */ true, /* default_val */ "legacy", "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
}}
.ToString() +
"\nResult:\n"
@@ -311,7 +311,7 @@ static UniValue getmemoryinfo(const JSONRPCRequest& request)
RPCHelpMan{"getmemoryinfo",
"Returns an object containing information about memory usage.\n",
{
- {"mode", RPCArg::Type::STR, /* opt */ true, /* default_val */ "", "determines what kind of information is returned. This argument is optional, the default mode is \"stats\".\n"
+ {"mode", RPCArg::Type::STR, /* opt */ true, /* default_val */ "\"stats\"", "determines what kind of information is returned.\n"
" - \"stats\" returns general statistics about memory usage in the daemon.\n"
" - \"mallocinfo\" returns an XML string describing low-level heap state (only available if compiled with glibc 2.10+)."},
}}
@@ -384,11 +384,11 @@ UniValue logging(const JSONRPCRequest& request)
" - \"none\", \"0\" : even if other logging categories are specified, ignore all of them.\n"
,
{
- {"include", RPCArg::Type::ARR, /* opt */ true, /* default_val */ "", "A json array of categories to add debug logging",
+ {"include", RPCArg::Type::ARR, /* opt */ true, /* default_val */ "null", "A json array of categories to add debug logging",
{
{"include_category", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "the valid logging category"},
}},
- {"exclude", RPCArg::Type::ARR, /* opt */ true, /* default_val */ "", "A json array of categories to remove debug logging",
+ {"exclude", RPCArg::Type::ARR, /* opt */ true, /* default_val */ "null", "A json array of categories to remove debug logging",
{
{"exclude_category", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "the valid logging category"},
}},
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index f523ca835f..4d6b260cc7 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -255,8 +255,8 @@ static UniValue disconnectnode(const JSONRPCRequest& request)
"\nStrictly one out of 'address' and 'nodeid' can be provided to identify the node.\n"
"\nTo disconnect by nodeid, either set 'address' to the empty string, or call using the named 'nodeid' argument only.\n",
{
- {"address", RPCArg::Type::STR, /* opt */ true, /* default_val */ "", "The IP address/port of the node"},
- {"nodeid", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "", "The node ID (see getpeerinfo for node IDs)"},
+ {"address", RPCArg::Type::STR, /* opt */ true, /* default_val */ "fallback to nodeid", "The IP address/port of the node"},
+ {"nodeid", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "fallback to address", "The node ID (see getpeerinfo for node IDs)"},
}}
.ToString() +
"\nExamples:\n"
@@ -299,7 +299,7 @@ static UniValue getaddednodeinfo(const JSONRPCRequest& request)
"\nReturns information about the given added node, or all added nodes\n"
"(note that onetry addnodes are not listed here)\n",
{
- {"node", RPCArg::Type::STR, /* opt */ true, /* default_val */ "", "If provided, return information about this specific node, otherwise all nodes are returned."},
+ {"node", RPCArg::Type::STR, /* opt */ true, /* default_val */ "all nodes", "If provided, return information about this specific node, otherwise all nodes are returned."},
}}
.ToString() +
"\nResult:\n"
@@ -518,8 +518,8 @@ static UniValue setban(const JSONRPCRequest& request)
{
{"subnet", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The IP/Subnet (see getpeerinfo for nodes IP) with an optional netmask (default is /32 = single IP)"},
{"command", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "'add' to add an IP/Subnet to the list, 'remove' to remove an IP/Subnet from the list"},
- {"bantime", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "", "time in seconds how long (or until when if [absolute] is set) the IP is banned (0 or empty means using the default time of 24h which can also be overwritten by the -bantime startup argument)"},
- {"absolute", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "", "If set, the bantime must be an absolute timestamp in seconds since epoch (Jan 1 1970 GMT)"},
+ {"bantime", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "0", "time in seconds how long (or until when if [absolute] is set) the IP is banned (0 or empty means using the default time of 24h which can also be overwritten by the -bantime startup argument)"},
+ {"absolute", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "If set, the bantime must be an absolute timestamp in seconds since epoch (Jan 1 1970 GMT)"},
}}
.ToString() +
"\nExamples:\n"
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index f5f6c344ea..370ae8e4d7 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -81,7 +81,7 @@ static UniValue getrawtransaction(const JSONRPCRequest& request)
{
{"txid", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The transaction id"},
{"verbose", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "If false, return a string, otherwise return a json object"},
- {"blockhash", RPCArg::Type::STR_HEX, /* opt */ true, /* default_val */ "", "The block in which to look for the transaction"},
+ {"blockhash", RPCArg::Type::STR_HEX, /* opt */ true, /* default_val */ "null", "The block in which to look for the transaction"},
}}
.ToString() +
"\nResult (if verbose is not set or set to false):\n"
@@ -218,7 +218,7 @@ static UniValue gettxoutproof(const JSONRPCRequest& request)
{"txid", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "A transaction hash"},
},
},
- {"blockhash", RPCArg::Type::STR_HEX, /* opt */ true, /* default_val */ "", "If specified, looks for txid in the block with this hash"},
+ {"blockhash", RPCArg::Type::STR_HEX, /* opt */ true, /* default_val */ "null", "If specified, looks for txid in the block with this hash"},
}}
.ToString() +
"\nResult:\n"
@@ -397,7 +397,6 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal
rawTx.vin.push_back(in);
}
- std::set<CTxDestination> destinations;
if (!outputs_is_obj) {
// Translate array of key-value pairs into dict
UniValue outputs_dict = UniValue(UniValue::VOBJ);
@@ -413,8 +412,17 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal
}
outputs = std::move(outputs_dict);
}
+
+ // Duplicate checking
+ std::set<CTxDestination> destinations;
+ bool has_data{false};
+
for (const std::string& name_ : outputs.getKeys()) {
if (name_ == "data") {
+ if (has_data) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, duplicate key: data");
+ }
+ has_data = true;
std::vector<unsigned char> data = ParseHexV(outputs[name_].getValStr(), "Data");
CTxOut out(0, CScript() << OP_RETURN << data);
@@ -457,16 +465,17 @@ static UniValue createrawtransaction(const JSONRPCRequest& request)
{
{"inputs", RPCArg::Type::ARR, /* opt */ false, /* default_val */ "", "A json array of json objects",
{
- {"", RPCArg::Type::OBJ, /* opt */ false, /* default_val */ "", "",
+ {"", RPCArg::Type::OBJ, /* opt */ true, /* default_val */ "", "",
{
{"txid", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The transaction id"},
{"vout", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "The output number"},
- {"sequence", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "", "The sequence number"},
+ {"sequence", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "depends on the value of the 'replaceable' and 'locktime' arguments", "The sequence number"},
},
},
},
},
- {"outputs", RPCArg::Type::ARR, /* opt */ false, /* default_val */ "", "a json array with outputs (key-value pairs).\n"
+ {"outputs", RPCArg::Type::ARR, /* opt */ false, /* default_val */ "", "a json array with outputs (key-value pairs), where none of the keys are duplicated.\n"
+ "That is, each address can only appear once and there can only be one 'data' object.\n"
"For compatibility reasons, a dictionary, which holds the key-value pairs directly, is also\n"
" accepted as second parameter.",
{
@@ -519,7 +528,7 @@ static UniValue decoderawtransaction(const JSONRPCRequest& request)
"\nReturn a JSON object representing the serialized, hex-encoded transaction.\n",
{
{"hexstring", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The transaction hex string"},
- {"iswitness", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "", "Whether the transaction hex is a serialized witness transaction\n"
+ {"iswitness", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "depends on heuristic tests", "Whether the transaction hex is a serialized witness transaction\n"
" If iswitness is not present, heuristic tests will be used in decoding"},
}}
.ToString() +
@@ -923,14 +932,14 @@ static UniValue signrawtransactionwithkey(const JSONRPCRequest& request)
{"privatekey", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "private key in base58-encoding"},
},
},
- {"prevtxs", RPCArg::Type::ARR, /* opt */ true, /* default_val */ "", "A json array of previous dependent transaction outputs",
+ {"prevtxs", RPCArg::Type::ARR, /* opt */ true, /* default_val */ "null", "A json array of previous dependent transaction outputs",
{
{"", RPCArg::Type::OBJ, /* opt */ true, /* default_val */ "", "",
{
{"txid", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The transaction id"},
{"vout", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "The output number"},
{"scriptPubKey", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "script key"},
- {"redeemScript", RPCArg::Type::STR_HEX, /* opt */ true, /* default_val */ "", "(required for P2SH or P2WSH) redeem script"},
+ {"redeemScript", RPCArg::Type::STR_HEX, /* opt */ true, /* default_val */ "omitted", "(required for P2SH or P2WSH) redeem script"},
{"amount", RPCArg::Type::AMOUNT, /* opt */ false, /* default_val */ "", "The amount spent"},
},
},
@@ -1603,12 +1612,13 @@ UniValue createpsbt(const JSONRPCRequest& request)
{
{"txid", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The transaction id"},
{"vout", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "The output number"},
- {"sequence", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "", "The sequence number"},
+ {"sequence", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "depends on the value of the 'replaceable' and 'locktime' arguments", "The sequence number"},
},
},
},
},
- {"outputs", RPCArg::Type::ARR, /* opt */ false, /* default_val */ "", "a json array with outputs (key-value pairs).\n"
+ {"outputs", RPCArg::Type::ARR, /* opt */ false, /* default_val */ "", "a json array with outputs (key-value pairs), where none of the keys are duplicated.\n"
+ "That is, each address can only appear once and there can only be one 'data' object.\n"
"For compatibility reasons, a dictionary, which holds the key-value pairs directly, is also\n"
" accepted as second parameter.",
{
@@ -1674,7 +1684,7 @@ UniValue converttopsbt(const JSONRPCRequest& request)
{"hexstring", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The hex string of a raw transaction"},
{"permitsigdata", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "If true, any signatures in the input will be discarded and conversion.\n"
" will continue. If false, RPC will fail if any signatures are present."},
- {"iswitness", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "", "Whether the transaction hex is a serialized witness transaction.\n"
+ {"iswitness", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "depends on heuristic tests", "Whether the transaction hex is a serialized witness transaction.\n"
" If iswitness is not present, heuristic tests will be used in decoding. If true, only witness deserializaion\n"
" will be tried. If false, only non-witness deserialization will be tried. Only has an effect if\n"
" permitsigdata is true."},
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index 97745c62d6..733f8601ee 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -203,7 +203,7 @@ UniValue help(const JSONRPCRequest& jsonRequest)
RPCHelpMan{"help",
"\nList all commands, or get help for a specified command.\n",
{
- {"command", RPCArg::Type::STR, /* opt */ true, /* default_val */ "", "The command to get help on"},
+ {"command", RPCArg::Type::STR, /* opt */ true, /* default_val */ "all commands", "The command to get help on"},
}}
.ToString() +
"\nResult:\n"
@@ -221,6 +221,9 @@ UniValue help(const JSONRPCRequest& jsonRequest)
UniValue stop(const JSONRPCRequest& jsonRequest)
{
// Accept the deprecated and ignored 'detach' boolean argument
+ // Also accept the hidden 'wait' integer argument (milliseconds)
+ // For instance, 'stop 1000' makes the call wait 1 second before returning
+ // to the client (intended for testing)
if (jsonRequest.fHelp || jsonRequest.params.size() > 1)
throw std::runtime_error(
RPCHelpMan{"stop",
@@ -229,6 +232,9 @@ UniValue stop(const JSONRPCRequest& jsonRequest)
// Event loop will exit after current HTTP requests have been handled, so
// this reply will get back to the client.
StartShutdown();
+ if (jsonRequest.params[0].isNum()) {
+ MilliSleep(jsonRequest.params[0].get_int());
+ }
return "Bitcoin server stopping";
}
@@ -255,7 +261,7 @@ static const CRPCCommand vRPCCommands[] =
// --------------------- ------------------------ ----------------------- ----------
/* Overall control/query calls */
{ "control", "help", &help, {"command"} },
- { "control", "stop", &stop, {} },
+ { "control", "stop", &stop, {"wait"} },
{ "control", "uptime", &uptime, {} },
};
// clang-format on
diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp
index bb1c315bc7..740f8351fe 100644
--- a/src/rpc/util.cpp
+++ b/src/rpc/util.cpp
@@ -242,6 +242,16 @@ struct Sections {
}
};
+RPCHelpMan::RPCHelpMan(const std::string& name, const std::string& description, const std::vector<RPCArg>& args)
+ : m_name{name}, m_description{description}, m_args{args}
+{
+ std::set<std::string> named_args;
+ for (const auto& arg : m_args) {
+ // Should have unique named arguments
+ assert(named_args.insert(arg.m_name).second);
+ }
+}
+
std::string RPCHelpMan::ToString() const
{
std::string ret;
diff --git a/src/rpc/util.h b/src/rpc/util.h
index 1d1df2c635..9e97b3ae0b 100644
--- a/src/rpc/util.h
+++ b/src/rpc/util.h
@@ -90,7 +90,7 @@ struct RPCArg {
/**
* Return the type string of the argument.
- * Set oneline to allow it to be overrided by a custom oneline type string (m_oneline_description).
+ * Set oneline to allow it to be overridden by a custom oneline type string (m_oneline_description).
*/
std::string ToString(bool oneline) const;
/**
@@ -109,10 +109,7 @@ struct RPCArg {
class RPCHelpMan
{
public:
- RPCHelpMan(const std::string& name, const std::string& description, const std::vector<RPCArg>& args)
- : m_name{name}, m_description{description}, m_args{args}
- {
- }
+ RPCHelpMan(const std::string& name, const std::string& description, const std::vector<RPCArg>& args);
std::string ToString() const;
diff --git a/src/streams.h b/src/streams.h
index dc20f7a9da..d5565fe61f 100644
--- a/src/streams.h
+++ b/src/streams.h
@@ -761,7 +761,7 @@ protected:
public:
CBufferedFile(FILE *fileIn, uint64_t nBufSize, uint64_t nRewindIn, int nTypeIn, int nVersionIn) :
- nType(nTypeIn), nVersion(nVersionIn), nSrcPos(0), nReadPos(0), nReadLimit((uint64_t)(-1)), nRewind(nRewindIn), vchBuf(nBufSize, 0)
+ nType(nTypeIn), nVersion(nVersionIn), nSrcPos(0), nReadPos(0), nReadLimit(std::numeric_limits<uint64_t>::max()), nRewind(nRewindIn), vchBuf(nBufSize, 0)
{
src = fileIn;
}
@@ -846,7 +846,7 @@ public:
// prevent reading beyond a certain position
// no argument removes the limit
- bool SetLimit(uint64_t nPos = (uint64_t)(-1)) {
+ bool SetLimit(uint64_t nPos = std::numeric_limits<uint64_t>::max()) {
if (nPos < nReadPos)
return false;
nReadLimit = nPos;
diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp
index 121b72a5f7..ff48398925 100644
--- a/src/test/rpc_tests.cpp
+++ b/src/test/rpc_tests.cpp
@@ -129,9 +129,6 @@ BOOST_AUTO_TEST_CASE(rpc_createraw_op_return)
{
BOOST_CHECK_NO_THROW(CallRPC("createrawtransaction [{\"txid\":\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\",\"vout\":0}] {\"data\":\"68656c6c6f776f726c64\"}"));
- // Allow more than one data transaction output
- BOOST_CHECK_NO_THROW(CallRPC("createrawtransaction [{\"txid\":\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\",\"vout\":0}] {\"data\":\"68656c6c6f776f726c64\",\"data\":\"68656c6c6f776f726c64\"}"));
-
// Key not "data" (bad address)
BOOST_CHECK_THROW(CallRPC("createrawtransaction [{\"txid\":\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\",\"vout\":0}] {\"somedata\":\"68656c6c6f776f726c64\"}"), std::runtime_error);
diff --git a/src/test/serialize_tests.cpp b/src/test/serialize_tests.cpp
index e754996d2f..002f61f6a2 100644
--- a/src/test/serialize_tests.cpp
+++ b/src/test/serialize_tests.cpp
@@ -200,7 +200,7 @@ BOOST_AUTO_TEST_CASE(varints)
}
for (uint64_t i = 0; i < 100000000000ULL; i += 999999937) {
- uint64_t j = -1;
+ uint64_t j = std::numeric_limits<uint64_t>::max();
ss >> VARINT(j);
BOOST_CHECK_MESSAGE(i == j, "decoded:" << j << " expected:" << i);
}
diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp
index c329844341..773204a00c 100644
--- a/src/test/sighash_tests.cpp
+++ b/src/test/sighash_tests.cpp
@@ -105,7 +105,7 @@ void static RandomTransaction(CMutableTransaction &tx, bool fSingle) {
txin.prevout.hash = InsecureRand256();
txin.prevout.n = InsecureRandBits(2);
RandomScript(txin.scriptSig);
- txin.nSequence = (InsecureRandBool()) ? InsecureRand32() : (unsigned int)-1;
+ txin.nSequence = (InsecureRandBool()) ? InsecureRand32() : std::numeric_limits<uint32_t>::max();
}
for (int out = 0; out < outs; out++) {
tx.vout.push_back(CTxOut());
diff --git a/src/validation.cpp b/src/validation.cpp
index 512a3619ca..e92cbf1b8d 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -2487,7 +2487,7 @@ CBlockIndex* CChainState::FindMostWorkChain() {
CBlockIndex *pindexTest = pindexNew;
bool fInvalidAncestor = false;
while (pindexTest && !chainActive.Contains(pindexTest)) {
- assert(pindexTest->nChainTx || pindexTest->nHeight == 0);
+ assert(pindexTest->HaveTxsDownloaded() || pindexTest->nHeight == 0);
// Pruned nodes may have entries in setBlockIndexCandidates for
// which block files have been deleted. Remove those as candidates
@@ -2777,7 +2777,7 @@ bool CChainState::PreciousBlock(CValidationState& state, const CChainParams& par
// call preciousblock 2**31-1 times on the same set of tips...
nBlockReverseSequenceId--;
}
- if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS) && pindex->nChainTx) {
+ if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS) && pindex->HaveTxsDownloaded()) {
setBlockIndexCandidates.insert(pindex);
PruneBlockIndexCandidates();
}
@@ -2838,7 +2838,7 @@ bool CChainState::InvalidateBlock(CValidationState& state, const CChainParams& c
// add it again.
BlockMap::iterator it = mapBlockIndex.begin();
while (it != mapBlockIndex.end()) {
- if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && it->second->nChainTx && !setBlockIndexCandidates.value_comp()(it->second, chainActive.Tip())) {
+ if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && it->second->HaveTxsDownloaded() && !setBlockIndexCandidates.value_comp()(it->second, chainActive.Tip())) {
setBlockIndexCandidates.insert(it->second);
}
it++;
@@ -2868,7 +2868,7 @@ void CChainState::ResetBlockFailureFlags(CBlockIndex *pindex) {
if (!it->second->IsValid() && it->second->GetAncestor(nHeight) == pindex) {
it->second->nStatus &= ~BLOCK_FAILED_MASK;
setDirtyBlockIndex.insert(it->second);
- if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && it->second->nChainTx && setBlockIndexCandidates.value_comp()(chainActive.Tip(), it->second)) {
+ if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && it->second->HaveTxsDownloaded() && setBlockIndexCandidates.value_comp()(chainActive.Tip(), it->second)) {
setBlockIndexCandidates.insert(it->second);
}
if (it->second == pindexBestInvalid) {
@@ -2946,7 +2946,7 @@ void CChainState::ReceivedBlockTransactions(const CBlock& block, CBlockIndex* pi
pindexNew->RaiseValidity(BLOCK_VALID_TRANSACTIONS);
setDirtyBlockIndex.insert(pindexNew);
- if (pindexNew->pprev == nullptr || pindexNew->pprev->nChainTx) {
+ if (pindexNew->pprev == nullptr || pindexNew->pprev->HaveTxsDownloaded()) {
// If pindexNew is the genesis block or all parents are BLOCK_VALID_TRANSACTIONS.
std::deque<CBlockIndex*> queue;
queue.push_back(pindexNew);
@@ -3819,8 +3819,6 @@ bool CChainState::LoadBlockIndex(const Consensus::Params& consensus_params, CBlo
if (!blocktree.LoadBlockIndexGuts(consensus_params, [this](const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { return this->InsertBlockIndex(hash); }))
return false;
- boost::this_thread::interruption_point();
-
// Calculate nChainWork
std::vector<std::pair<int, CBlockIndex*> > vSortedByHeight;
vSortedByHeight.reserve(mapBlockIndex.size());
@@ -3839,7 +3837,7 @@ bool CChainState::LoadBlockIndex(const Consensus::Params& consensus_params, CBlo
// Pruned nodes may have deleted the block.
if (pindex->nTx > 0) {
if (pindex->pprev) {
- if (pindex->pprev->nChainTx) {
+ if (pindex->pprev->HaveTxsDownloaded()) {
pindex->nChainTx = pindex->pprev->nChainTx + pindex->nTx;
} else {
pindex->nChainTx = 0;
@@ -3853,7 +3851,7 @@ bool CChainState::LoadBlockIndex(const Consensus::Params& consensus_params, CBlo
pindex->nStatus |= BLOCK_FAILED_CHILD;
setDirtyBlockIndex.insert(pindex);
}
- if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS) && (pindex->nChainTx || pindex->pprev == nullptr))
+ if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS) && (pindex->HaveTxsDownloaded() || pindex->pprev == nullptr))
setBlockIndexCandidates.insert(pindex);
if (pindex->nStatus & BLOCK_FAILED_MASK && (!pindexBestInvalid || pindex->nChainWork > pindexBestInvalid->nChainWork))
pindexBestInvalid = pindex;
@@ -4222,7 +4220,7 @@ bool CChainState::RewindBlockIndex(const CChainParams& params)
++ret.first;
}
}
- } else if (pindexIter->IsValid(BLOCK_VALID_TRANSACTIONS) && pindexIter->nChainTx) {
+ } else if (pindexIter->IsValid(BLOCK_VALID_TRANSACTIONS) && pindexIter->HaveTxsDownloaded()) {
setBlockIndexCandidates.insert(pindexIter);
}
}
@@ -4523,7 +4521,7 @@ void CChainState::CheckBlockIndex(const Consensus::Params& consensusParams)
assert(pindex->GetBlockHash() == consensusParams.hashGenesisBlock); // Genesis block's hash must match.
assert(pindex == chainActive.Genesis()); // The current active chain's genesis block must be this block.
}
- if (pindex->nChainTx == 0) assert(pindex->nSequenceId <= 0); // nSequenceId can't be set positive for blocks that aren't linked (negative is used for preciousblock)
+ if (!pindex->HaveTxsDownloaded()) assert(pindex->nSequenceId <= 0); // nSequenceId can't be set positive for blocks that aren't linked (negative is used for preciousblock)
// VALID_TRANSACTIONS is equivalent to nTx > 0 for all nodes (whether or not pruning has occurred).
// HAVE_DATA is only equivalent to nTx > 0 (or VALID_TRANSACTIONS) if no pruning has occurred.
if (!fHavePruned) {
@@ -4536,9 +4534,9 @@ void CChainState::CheckBlockIndex(const Consensus::Params& consensusParams)
}
if (pindex->nStatus & BLOCK_HAVE_UNDO) assert(pindex->nStatus & BLOCK_HAVE_DATA);
assert(((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_TRANSACTIONS) == (pindex->nTx > 0)); // This is pruning-independent.
- // All parents having had data (at some point) is equivalent to all parents being VALID_TRANSACTIONS, which is equivalent to nChainTx being set.
- assert((pindexFirstNeverProcessed != nullptr) == (pindex->nChainTx == 0)); // nChainTx != 0 is used to signal that all parent blocks have been processed (but may have been pruned).
- assert((pindexFirstNotTransactionsValid != nullptr) == (pindex->nChainTx == 0));
+ // All parents having had data (at some point) is equivalent to all parents being VALID_TRANSACTIONS, which is equivalent to HaveTxsDownloaded().
+ assert((pindexFirstNeverProcessed == nullptr) == pindex->HaveTxsDownloaded());
+ assert((pindexFirstNotTransactionsValid == nullptr) == pindex->HaveTxsDownloaded());
assert(pindex->nHeight == nHeight); // nHeight must be consistent.
assert(pindex->pprev == nullptr || pindex->nChainWork >= pindex->pprev->nChainWork); // For every block except the genesis block, the chainwork must be larger than the parent's.
assert(nHeight < 2 || (pindex->pskip && (pindex->pskip->nHeight < nHeight))); // The pskip pointer must point back for all but the first 2 blocks.
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index 0ecfcc1776..647af3eb86 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -1120,14 +1120,14 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
" creation time of all keys being imported by the importmulti call will be scanned.",
/* oneline_description */ "", {"timestamp | \"now\"", "integer / string"}
},
- {"redeemscript", RPCArg::Type::STR, /* opt */ true, /* default_val */ "", "Allowed only if the scriptPubKey is a P2SH or P2SH-P2WSH address/scriptPubKey"},
- {"witnessscript", RPCArg::Type::STR, /* opt */ true, /* default_val */ "", "Allowed only if the scriptPubKey is a P2SH-P2WSH or P2WSH address/scriptPubKey"},
- {"pubkeys", RPCArg::Type::ARR, /* opt */ true, /* default_val */ "", "Array of strings giving pubkeys that must occur in the output or redeemscript",
+ {"redeemscript", RPCArg::Type::STR, /* opt */ true, /* default_val */ "omitted", "Allowed only if the scriptPubKey is a P2SH or P2SH-P2WSH address/scriptPubKey"},
+ {"witnessscript", RPCArg::Type::STR, /* opt */ true, /* default_val */ "omitted", "Allowed only if the scriptPubKey is a P2SH-P2WSH or P2WSH address/scriptPubKey"},
+ {"pubkeys", RPCArg::Type::ARR, /* opt */ true, /* default_val */ "empty array", "Array of strings giving pubkeys that must occur in the output or redeemscript",
{
{"pubKey", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", ""},
}
},
- {"keys", RPCArg::Type::ARR, /* opt */ true, /* default_val */ "", "Array of strings giving private keys whose corresponding public keys must occur in the output or redeemscript",
+ {"keys", RPCArg::Type::ARR, /* opt */ true, /* default_val */ "empty array", "Array of strings giving private keys whose corresponding public keys must occur in the output or redeemscript",
{
{"key", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", ""},
}
@@ -1139,7 +1139,7 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
},
},
"\"requests\""},
- {"options", RPCArg::Type::OBJ, /* opt */ true, /* default_val */ "", "",
+ {"options", RPCArg::Type::OBJ, /* opt */ true, /* default_val */ "null", "",
{
{"rescan", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "true", "Stating if should rescan the blockchain after all imports"},
},
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 4479438238..977aa37e73 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -155,8 +155,8 @@ static UniValue getnewaddress(const JSONRPCRequest& request)
"If 'label' is specified, it is added to the address book \n"
"so payments received with the address will be associated with 'label'.\n",
{
- {"label", RPCArg::Type::STR, /* opt */ true, /* default_val */ "", "The label name for the address to be linked to. If not provided, the default label \"\" is used. It can also be set to the empty string \"\" to represent the default label. The label does not need to exist, it will be created if there is no label by the given name."},
- {"address_type", RPCArg::Type::STR, /* opt */ true, /* default_val */ "", "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\". Default is set by -addresstype."},
+ {"label", RPCArg::Type::STR, /* opt */ true, /* default_val */ "null", "The label name for the address to be linked to. If not provided, the default label \"\" is used. It can also be set to the empty string \"\" to represent the default label. The label does not need to exist, it will be created if there is no label by the given name."},
+ {"address_type", RPCArg::Type::STR, /* opt */ true, /* default_val */ "set by -addresstype", "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
}}
.ToString() +
"\nResult:\n"
@@ -216,7 +216,7 @@ static UniValue getrawchangeaddress(const JSONRPCRequest& request)
"\nReturns a new Bitcoin address, for receiving change.\n"
"This is for use with raw transactions, NOT normal use.\n",
{
- {"address_type", RPCArg::Type::STR, /* opt */ true, /* default_val */ "", "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\". Default is set by -changetype."},
+ {"address_type", RPCArg::Type::STR, /* opt */ true, /* default_val */ "set by -changetype", "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
}}
.ToString() +
"\nResult:\n"
@@ -356,15 +356,15 @@ static UniValue sendtoaddress(const JSONRPCRequest& request)
{
{"address", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The bitcoin address to send to."},
{"amount", RPCArg::Type::AMOUNT, /* opt */ false, /* default_val */ "", "The amount in " + CURRENCY_UNIT + " to send. eg 0.1"},
- {"comment", RPCArg::Type::STR, /* opt */ true, /* default_val */ "", "A comment used to store what the transaction is for.\n"
+ {"comment", RPCArg::Type::STR, /* opt */ true, /* default_val */ "null", "A comment used to store what the transaction is for.\n"
" This is not part of the transaction, just kept in your wallet."},
- {"comment_to", RPCArg::Type::STR, /* opt */ true, /* default_val */ "", "A comment to store the name of the person or organization\n"
+ {"comment_to", RPCArg::Type::STR, /* opt */ true, /* default_val */ "null", "A comment to store the name of the person or organization\n"
" to which you're sending the transaction. This is not part of the \n"
" transaction, just kept in your wallet."},
{"subtractfeefromamount", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "The fee will be deducted from the amount being sent.\n"
" The recipient will receive less bitcoins than you enter in the amount field."},
- {"replaceable", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "", "Allow this transaction to be replaced by a transaction with higher fees via BIP 125"},
- {"conf_target", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "", "Confirmation target (in blocks)"},
+ {"replaceable", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "fallback to wallet's default", "Allow this transaction to be replaced by a transaction with higher fees via BIP 125"},
+ {"conf_target", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "fallback to wallet's default", "Confirmation target (in blocks)"},
{"estimate_mode", RPCArg::Type::STR, /* opt */ true, /* default_val */ "UNSET", "The fee estimate mode, must be one of:\n"
" \"UNSET\"\n"
" \"ECONOMICAL\"\n"
@@ -715,7 +715,7 @@ static UniValue getbalance(const JSONRPCRequest& request)
"The available balance is what the wallet considers currently spendable, and is\n"
"thus affected by options which limit spendability such as -spendzeroconfchange.\n",
{
- {"dummy", RPCArg::Type::STR, /* opt */ true, /* default_val */ "", "Remains for backward compatibility. Must be excluded or set to \"*\"."},
+ {"dummy", RPCArg::Type::STR, /* opt */ true, /* default_val */ "null", "Remains for backward compatibility. Must be excluded or set to \"*\"."},
{"minconf", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "0", "Only include transactions confirmed at least this many times."},
{"include_watchonly", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Also include balance in watch-only addresses (see 'importaddress')"},
}}
@@ -804,8 +804,8 @@ static UniValue sendmany(const JSONRPCRequest& request)
},
},
{"minconf", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "1", "Only use the balance confirmed at least this many times."},
- {"comment", RPCArg::Type::STR, /* opt */ true, /* default_val */ "", "A comment"},
- {"subtractfeefrom", RPCArg::Type::ARR, /* opt */ true, /* default_val */ "", "A json array with addresses.\n"
+ {"comment", RPCArg::Type::STR, /* opt */ true, /* default_val */ "null", "A comment"},
+ {"subtractfeefrom", RPCArg::Type::ARR, /* opt */ true, /* default_val */ "null", "A json array with addresses.\n"
" The fee will be equally deducted from the amount of each selected address.\n"
" Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n"
" If no addresses are specified here, the sender pays the fee.",
@@ -813,8 +813,8 @@ static UniValue sendmany(const JSONRPCRequest& request)
{"address", RPCArg::Type::STR, /* opt */ true, /* default_val */ "", "Subtract fee from this address"},
},
},
- {"replaceable", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "", "Allow this transaction to be replaced by a transaction with higher fees via BIP 125"},
- {"conf_target", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "", "Confirmation target (in blocks)"},
+ {"replaceable", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "fallback to wallet's default", "Allow this transaction to be replaced by a transaction with higher fees via BIP 125"},
+ {"conf_target", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "fallback to wallet's default", "Confirmation target (in blocks)"},
{"estimate_mode", RPCArg::Type::STR, /* opt */ true, /* default_val */ "UNSET", "The fee estimate mode, must be one of:\n"
" \"UNSET\"\n"
" \"ECONOMICAL\"\n"
@@ -962,8 +962,8 @@ static UniValue addmultisigaddress(const JSONRPCRequest& request)
{"key", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "bitcoin address or hex-encoded public key"},
},
},
- {"label", RPCArg::Type::STR, /* opt */ true, /* default_val */ "", "A label to assign the addresses to."},
- {"address_type", RPCArg::Type::STR, /* opt */ true, /* default_val */ "", "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\". Default is set by -addresstype."},
+ {"label", RPCArg::Type::STR, /* opt */ true, /* default_val */ "null", "A label to assign the addresses to."},
+ {"address_type", RPCArg::Type::STR, /* opt */ true, /* default_val */ "set by -addresstype", "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
}}
.ToString() +
"\nResult:\n"
@@ -1195,7 +1195,7 @@ static UniValue listreceivedbyaddress(const JSONRPCRequest& request)
{"minconf", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "1", "The minimum number of confirmations before payments are included."},
{"include_empty", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Whether to include addresses that haven't received any payments."},
{"include_watchonly", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Whether to include watch-only addresses (see 'importaddress')."},
- {"address_filter", RPCArg::Type::STR, /* opt */ true, /* default_val */ "", "If present, only return information on this address."},
+ {"address_filter", RPCArg::Type::STR, /* opt */ true, /* default_val */ "null", "If present, only return information on this address."},
}}
.ToString() +
"\nResult:\n"
@@ -1386,7 +1386,7 @@ UniValue listtransactions(const JSONRPCRequest& request)
"\nIf a label name is provided, this will return only incoming transactions paying to addresses with the specified label.\n"
"\nReturns up to 'count' most recent transactions skipping the first 'from' transactions.\n",
{
- {"label", RPCArg::Type::STR, /* opt */ true, /* default_val */ "", "If set, should be a valid label name to return only incoming transactions\n"
+ {"label", RPCArg::Type::STR, /* opt */ true, /* default_val */ "null", "If set, should be a valid label name to return only incoming transactions\n"
" with the specified label, or \"*\" to disable filtering and return all transactions."},
{"count", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "10", "The number of transactions to return"},
{"skip", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "0", "The number of transactions to skip"},
@@ -1516,7 +1516,7 @@ static UniValue listsinceblock(const JSONRPCRequest& request)
"If \"blockhash\" is no longer a part of the main chain, transactions from the fork point onward are included.\n"
"Additionally, if include_removed is set, transactions affecting the wallet which were removed are returned in the \"removed\" array.\n",
{
- {"blockhash", RPCArg::Type::STR, /* opt */ true, /* default_val */ "", "The block hash to list transactions since"},
+ {"blockhash", RPCArg::Type::STR, /* opt */ true, /* default_val */ "null", "If set, the block hash to list transactions since, otherwise list all transactions."},
{"target_confirmations", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "1", "Return the nth block hash from the main chain. e.g. 1 would mean the best block hash. Note: this is not used as a filter, but only affects [lastblock] in the return value"},
{"include_watchonly", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Include transactions to watch-only addresses (see 'importaddress')"},
{"include_removed", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "true", "Show transactions that were removed due to a reorg in the \"removed\" array\n"
@@ -2136,7 +2136,7 @@ static UniValue lockunspent(const JSONRPCRequest& request)
"Also see the listunspent call\n",
{
{"unlock", RPCArg::Type::BOOL, /* opt */ false, /* default_val */ "", "Whether to unlock (true) or lock (false) the specified transactions"},
- {"transactions", RPCArg::Type::ARR, /* opt */ true, /* default_val */ "", "A json array of objects. Each object the txid (string) vout (numeric)",
+ {"transactions", RPCArg::Type::ARR, /* opt */ true, /* default_val */ "empty array", "A json array of objects. Each object the txid (string) vout (numeric).",
{
{"", RPCArg::Type::OBJ, /* opt */ true, /* default_val */ "", "",
{
@@ -2596,7 +2596,7 @@ static UniValue unloadwallet(const JSONRPCRequest& request)
"Unloads the wallet referenced by the request endpoint otherwise unloads the wallet specified in the argument.\n"
"Specifying the wallet name on a wallet endpoint is invalid.",
{
- {"wallet_name", RPCArg::Type::STR, /* opt */ true, /* default_val */ "", "The name of the wallet to unload."},
+ {"wallet_name", RPCArg::Type::STR, /* opt */ true, /* default_val */ "the wallet name from the RPC request", "The name of the wallet to unload."},
}}
.ToString() +
"\nExamples:\n"
@@ -2697,14 +2697,14 @@ static UniValue listunspent(const JSONRPCRequest& request)
{
{"minconf", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "1", "The minimum confirmations to filter"},
{"maxconf", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "9999999", "The maximum confirmations to filter"},
- {"addresses", RPCArg::Type::ARR, /* opt */ true, /* default_val */ "", "A json array of bitcoin addresses to filter",
+ {"addresses", RPCArg::Type::ARR, /* opt */ true, /* default_val */ "empty array", "A json array of bitcoin addresses to filter",
{
{"address", RPCArg::Type::STR, /* opt */ true, /* default_val */ "", "bitcoin address"},
},
},
{"include_unsafe", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "true", "Include outputs that are not safe to spend\n"
" See description of \"safe\" attribute below."},
- {"query_options", RPCArg::Type::OBJ, /* opt */ true, /* default_val */ "", "JSON with query options",
+ {"query_options", RPCArg::Type::OBJ, /* opt */ true, /* default_val */ "null", "JSON with query options",
{
{"minimumAmount", RPCArg::Type::AMOUNT, /* opt */ true, /* default_val */ "0", "Minimum value of each UTXO in " + CURRENCY_UNIT + ""},
{"maximumAmount", RPCArg::Type::AMOUNT, /* opt */ true, /* default_val */ "unlimited", "Maximum value of each UTXO in " + CURRENCY_UNIT + ""},
@@ -2997,33 +2997,32 @@ static UniValue fundrawtransaction(const JSONRPCRequest& request)
"Only pay-to-pubkey, multisig, and P2SH versions thereof are currently supported for watch-only\n",
{
{"hexstring", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The hex string of the raw transaction"},
- {"options", RPCArg::Type::OBJ, /* opt */ true, /* default_val */ "", "for backward compatibility: passing in a true instead of an object will result in {\"includeWatching\":true}",
+ {"options", RPCArg::Type::OBJ, /* opt */ true, /* default_val */ "null", "for backward compatibility: passing in a true instead of an object will result in {\"includeWatching\":true}",
{
{"changeAddress", RPCArg::Type::STR, /* opt */ true, /* default_val */ "pool address", "The bitcoin address to receive the change"},
{"changePosition", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "random", "The index of the change output"},
- {"change_type", RPCArg::Type::STR, /* opt */ true, /* default_val */ "", "The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\". Default is set by -changetype."},
+ {"change_type", RPCArg::Type::STR, /* opt */ true, /* default_val */ "set by -changetype", "The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
{"includeWatching", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Also select inputs which are watch only"},
{"lockUnspents", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Lock selected unspent outputs"},
{"feeRate", RPCArg::Type::AMOUNT, /* opt */ true, /* default_val */ "not set: makes wallet determine the fee", "Set a specific fee rate in " + CURRENCY_UNIT + "/kB"},
- {"subtractFeeFromOutputs", RPCArg::Type::ARR, /* opt */ true, /* default_val */ "", "A json array of integers.\n"
+ {"subtractFeeFromOutputs", RPCArg::Type::ARR, /* opt */ true, /* default_val */ "empty array", "A json array of integers.\n"
" The fee will be equally deducted from the amount of each specified output.\n"
- " The outputs are specified by their zero-based index, before any change output is added.\n"
" Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n"
" If no outputs are specified here, the sender pays the fee.",
{
{"vout_index", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "", "The zero-based output index, before a change output is added."},
},
},
- {"replaceable", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "", "Marks this transaction as BIP125 replaceable.\n"
+ {"replaceable", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "fallback to wallet's default", "Marks this transaction as BIP125 replaceable.\n"
" Allows this transaction to be replaced by a transaction with higher fees"},
- {"conf_target", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "", "Confirmation target (in blocks)"},
+ {"conf_target", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "fallback to wallet's default", "Confirmation target (in blocks)"},
{"estimate_mode", RPCArg::Type::STR, /* opt */ true, /* default_val */ "UNSET", "The fee estimate mode, must be one of:\n"
" \"UNSET\"\n"
" \"ECONOMICAL\"\n"
" \"CONSERVATIVE\""},
},
"options"},
- {"iswitness", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "", "Whether the transaction hex is a serialized witness transaction \n"
+ {"iswitness", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "depends on heuristic tests", "Whether the transaction hex is a serialized witness transaction \n"
" If iswitness is not present, heuristic tests will be used in decoding"},
}}
.ToString() +
@@ -3084,14 +3083,14 @@ UniValue signrawtransactionwithwallet(const JSONRPCRequest& request)
HelpRequiringPassphrase(pwallet) + "\n",
{
{"hexstring", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The transaction hex string"},
- {"prevtxs", RPCArg::Type::ARR, /* opt */ true, /* default_val */ "", "A json array of previous dependent transaction outputs",
+ {"prevtxs", RPCArg::Type::ARR, /* opt */ true, /* default_val */ "null", "A json array of previous dependent transaction outputs",
{
{"", RPCArg::Type::OBJ, /* opt */ false, /* default_val */ "", "",
{
{"txid", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The transaction id"},
{"vout", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "The output number"},
{"scriptPubKey", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "script key"},
- {"redeemScript", RPCArg::Type::STR_HEX, /* opt */ true, /* default_val */ "", "(required for P2SH or P2WSH)"},
+ {"redeemScript", RPCArg::Type::STR_HEX, /* opt */ true, /* default_val */ "omitted", "(required for P2SH or P2WSH)"},
{"amount", RPCArg::Type::AMOUNT, /* opt */ false, /* default_val */ "", "The amount spent"},
},
},
@@ -3167,10 +3166,10 @@ static UniValue bumpfee(const JSONRPCRequest& request)
"returned by getnetworkinfo) to enter the node's mempool.\n",
{
{"txid", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The txid to be bumped"},
- {"options", RPCArg::Type::OBJ, /* opt */ true, /* default_val */ "", "",
+ {"options", RPCArg::Type::OBJ, /* opt */ true, /* default_val */ "null", "",
{
- {"confTarget", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "", "Confirmation target (in blocks)"},
- {"totalFee", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "", "Total fee (NOT feerate) to pay, in satoshis.\n"
+ {"confTarget", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "fallback to wallet's default", "Confirmation target (in blocks)"},
+ {"totalFee", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "fallback to 'confTarget'", "Total fee (NOT feerate) to pay, in satoshis.\n"
" In rare cases, the actual fee paid might be slightly higher than the specified\n"
" totalFee if the tx change output has to be removed because it is too close to\n"
" the dust threshold."},
@@ -3312,7 +3311,7 @@ UniValue generate(const JSONRPCRequest& request)
"\nMine up to nblocks blocks immediately (before the RPC call returns) to an address in the wallet.\n",
{
{"nblocks", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "How many blocks are generated immediately."},
- {"maxtries", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "", "How many iterations to try (default = 1000000)."},
+ {"maxtries", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "1000000", "How many iterations to try."},
}}
.ToString() +
"\nResult:\n"
@@ -3365,8 +3364,8 @@ UniValue rescanblockchain(const JSONRPCRequest& request)
RPCHelpMan{"rescanblockchain",
"\nRescan the local blockchain for wallet related transactions.\n",
{
- {"start_height", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "", "block height where the rescan should start"},
- {"stop_height", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "", "the last block height that should be scanned"},
+ {"start_height", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "0", "block height where the rescan should start"},
+ {"stop_height", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "tip height", "the last block height that should be scanned"},
}}
.ToString() +
"\nResult:\n"
@@ -3749,7 +3748,7 @@ static UniValue listlabels(const JSONRPCRequest& request)
RPCHelpMan{"listlabels",
"\nReturns the list of all labels, or labels that are assigned to addresses with a specific purpose.\n",
{
- {"purpose", RPCArg::Type::STR, /* opt */ true, /* default_val */ "", "Address purpose to list labels for ('send','receive'). An empty string is the same as not providing this argument."},
+ {"purpose", RPCArg::Type::STR, /* opt */ true, /* default_val */ "null", "Address purpose to list labels for ('send','receive'). An empty string is the same as not providing this argument."},
}}
.ToString() +
"\nResult:\n"
@@ -3812,7 +3811,7 @@ UniValue sethdseed(const JSONRPCRequest& request)
" If true, the next address from getnewaddress and change address from getrawchangeaddress will be from this new seed.\n"
" If false, addresses (including change addresses if the wallet already had HD Chain Split enabled) from the existing\n"
" keypool will be used until it has been depleted."},
- {"seed", RPCArg::Type::STR, /* opt */ true, /* default_val */ "", "The WIF private key to use as the new HD seed; if not provided a random seed will be used.\n"
+ {"seed", RPCArg::Type::STR, /* opt */ true, /* default_val */ "random seed", "The WIF private key to use as the new HD seed.\n"
" The seed value can be retrieved using the dumpwallet command. It is the private key marked hdseed=1"},
}}
.ToString() +
@@ -4023,44 +4022,44 @@ UniValue walletcreatefundedpsbt(const JSONRPCRequest& request)
},
},
},
- {"outputs", RPCArg::Type::ARR, /* opt */ false, /* default_val */ "", "a json array with outputs (key-value pairs).\n"
+ {"outputs", RPCArg::Type::ARR, /* opt */ false, /* default_val */ "", "a json array with outputs (key-value pairs), where none of the keys are duplicated.\n"
+ "That is, each address can only appear once and there can only be one 'data' object.\n"
"For compatibility reasons, a dictionary, which holds the key-value pairs directly, is also\n"
" accepted as second parameter.",
{
{"", RPCArg::Type::OBJ, /* opt */ true, /* default_val */ "", "",
{
- {"address", RPCArg::Type::AMOUNT, /* opt */ true, /* default_val */ "", "A key-value pair. The key (string) is the bitcoin address, the value (float or string) is the amount in " + CURRENCY_UNIT + ""},
+ {"address", RPCArg::Type::AMOUNT, /* opt */ false, /* default_val */ "", "A key-value pair. The key (string) is the bitcoin address, the value (float or string) is the amount in " + CURRENCY_UNIT + ""},
},
},
{"", RPCArg::Type::OBJ, /* opt */ true, /* default_val */ "", "",
{
- {"data", RPCArg::Type::STR_HEX, /* opt */ true, /* default_val */ "", "A key-value pair. The key must be \"data\", the value is hex-encoded data"},
+ {"data", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "A key-value pair. The key must be \"data\", the value is hex-encoded data"},
},
},
},
},
{"locktime", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "0", "Raw locktime. Non-0 value also locktime-activates inputs\n"
" Allows this transaction to be replaced by a transaction with higher fees. If provided, it is an error if explicit sequence numbers are incompatible."},
- {"options", RPCArg::Type::OBJ, /* opt */ true, /* default_val */ "", "",
+ {"options", RPCArg::Type::OBJ, /* opt */ true, /* default_val */ "null", "",
{
{"changeAddress", RPCArg::Type::STR_HEX, /* opt */ true, /* default_val */ "pool address", "The bitcoin address to receive the change"},
{"changePosition", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "random", "The index of the change output"},
- {"change_type", RPCArg::Type::STR, /* opt */ true, /* default_val */ "", "The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\". Default is set by -changetype."},
+ {"change_type", RPCArg::Type::STR, /* opt */ true, /* default_val */ "set by -changetype", "The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
{"includeWatching", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Also select inputs which are watch only"},
{"lockUnspents", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Lock selected unspent outputs"},
{"feeRate", RPCArg::Type::AMOUNT, /* opt */ true, /* default_val */ "not set: makes wallet determine the fee", "Set a specific fee rate in " + CURRENCY_UNIT + "/kB"},
- {"subtractFeeFromOutputs", RPCArg::Type::ARR, /* opt */ true, /* default_val */ "", "A json array of integers.\n"
+ {"subtractFeeFromOutputs", RPCArg::Type::ARR, /* opt */ true, /* default_val */ "empty array", "A json array of integers.\n"
" The fee will be equally deducted from the amount of each specified output.\n"
- " The outputs are specified by their zero-based index, before any change output is added.\n"
" Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n"
" If no outputs are specified here, the sender pays the fee.",
{
- {"vout_index", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "", ""},
+ {"vout_index", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "", "The zero-based output index, before a change output is added."},
},
},
- {"replaceable", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "", "Marks this transaction as BIP125 replaceable.\n"
+ {"replaceable", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Marks this transaction as BIP125 replaceable.\n"
" Allows this transaction to be replaced by a transaction with higher fees"},
- {"conf_target", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "", "Confirmation target (in blocks)"},
+ {"conf_target", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "Fallback to wallet's confirmation target", "Confirmation target (in blocks)"},
{"estimate_mode", RPCArg::Type::STR, /* opt */ true, /* default_val */ "UNSET", "The fee estimate mode, must be one of:\n"
" \"UNSET\"\n"
" \"ECONOMICAL\"\n"
diff --git a/test/functional/feature_shutdown.py b/test/functional/feature_shutdown.py
new file mode 100755
index 0000000000..b633fabb1f
--- /dev/null
+++ b/test/functional/feature_shutdown.py
@@ -0,0 +1,28 @@
+#!/usr/bin/env python3
+# Copyright (c) 2018 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""Test bitcoind shutdown."""
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import assert_equal, get_rpc_proxy
+from threading import Thread
+
+def test_long_call(node):
+ block = node.waitfornewblock()
+ assert_equal(block['height'], 0)
+
+class ShutdownTest(BitcoinTestFramework):
+
+ def set_test_params(self):
+ self.setup_clean_chain = True
+ self.num_nodes = 1
+
+ def run_test(self):
+ node = get_rpc_proxy(self.nodes[0].url, 1, timeout=600, coveragedir=self.nodes[0].coverage_dir)
+ Thread(target=test_long_call, args=(node,)).start()
+ # wait 1 second to ensure event loop waits for current connections to close
+ self.stop_node(0, wait=1000)
+
+if __name__ == '__main__':
+ ShutdownTest().main()
diff --git a/test/functional/rpc_rawtransaction.py b/test/functional/rpc_rawtransaction.py
index 8ed490f552..fc012e6e3a 100755
--- a/test/functional/rpc_rawtransaction.py
+++ b/test/functional/rpc_rawtransaction.py
@@ -100,6 +100,8 @@ class RawTransactionsTest(BitcoinTestFramework):
assert_raises_rpc_error(-3, "Amount out of range", self.nodes[0].createrawtransaction, [], {address: -1})
assert_raises_rpc_error(-8, "Invalid parameter, duplicated address: %s" % address, self.nodes[0].createrawtransaction, [], multidict([(address, 1), (address, 1)]))
assert_raises_rpc_error(-8, "Invalid parameter, duplicated address: %s" % address, self.nodes[0].createrawtransaction, [], [{address: 1}, {address: 1}])
+ assert_raises_rpc_error(-8, "Invalid parameter, duplicate key: data", self.nodes[0].createrawtransaction, [], [{"data": 'aa'}, {"data": "bb"}])
+ assert_raises_rpc_error(-8, "Invalid parameter, duplicate key: data", self.nodes[0].createrawtransaction, [], multidict([("data", 'aa'), ("data", "bb")]))
assert_raises_rpc_error(-8, "Invalid parameter, key-value pair must contain exactly one key", self.nodes[0].createrawtransaction, [], [{'a': 1, 'b': 2}])
assert_raises_rpc_error(-8, "Invalid parameter, key-value pair not an object as expected", self.nodes[0].createrawtransaction, [], [['key-value pair1'], ['2']])
@@ -127,19 +129,12 @@ class RawTransactionsTest(BitcoinTestFramework):
bytes_to_hex_str(tx.serialize()),
self.nodes[2].createrawtransaction(inputs=[{'txid': txid, 'vout': 9}], outputs=[{address: 99}, {address2: 99}]),
)
- # Two data outputs
- tx.deserialize(BytesIO(hex_str_to_bytes(self.nodes[2].createrawtransaction(inputs=[{'txid': txid, 'vout': 9}], outputs=multidict([('data', '99'), ('data', '99')])))))
- assert_equal(len(tx.vout), 2)
- assert_equal(
- bytes_to_hex_str(tx.serialize()),
- self.nodes[2].createrawtransaction(inputs=[{'txid': txid, 'vout': 9}], outputs=[{'data': '99'}, {'data': '99'}]),
- )
# Multiple mixed outputs
- tx.deserialize(BytesIO(hex_str_to_bytes(self.nodes[2].createrawtransaction(inputs=[{'txid': txid, 'vout': 9}], outputs=multidict([(address, 99), ('data', '99'), ('data', '99')])))))
+ tx.deserialize(BytesIO(hex_str_to_bytes(self.nodes[2].createrawtransaction(inputs=[{'txid': txid, 'vout': 9}], outputs=multidict([(address, 99), (address2, 99), ('data', '99')])))))
assert_equal(len(tx.vout), 3)
assert_equal(
bytes_to_hex_str(tx.serialize()),
- self.nodes[2].createrawtransaction(inputs=[{'txid': txid, 'vout': 9}], outputs=[{address: 99}, {'data': '99'}, {'data': '99'}]),
+ self.nodes[2].createrawtransaction(inputs=[{'txid': txid, 'vout': 9}], outputs=[{address: 99}, {address2: 99}, {'data': '99'}]),
)
for type in ["bech32", "p2sh-segwit", "legacy"]:
diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py
index 0dfa9e0d24..10d5c659ad 100755
--- a/test/functional/test_framework/test_framework.py
+++ b/test/functional/test_framework/test_framework.py
@@ -327,16 +327,16 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
for node in self.nodes:
coverage.write_all_rpc_commands(self.options.coveragedir, node.rpc)
- def stop_node(self, i, expected_stderr=''):
+ def stop_node(self, i, expected_stderr='', wait=0):
"""Stop a bitcoind test node"""
- self.nodes[i].stop_node(expected_stderr)
+ self.nodes[i].stop_node(expected_stderr, wait=wait)
self.nodes[i].wait_until_stopped()
- def stop_nodes(self):
+ def stop_nodes(self, wait=0):
"""Stop multiple bitcoind test nodes"""
for node in self.nodes:
# Issue RPC to stop nodes
- node.stop_node()
+ node.stop_node(wait=wait)
for node in self.nodes:
# Wait for nodes to stop
diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py
index 27f99c259c..ebae3faffc 100755
--- a/test/functional/test_framework/test_node.py
+++ b/test/functional/test_framework/test_node.py
@@ -228,13 +228,13 @@ class TestNode():
wallet_path = "wallet/{}".format(urllib.parse.quote(wallet_name))
return self.rpc / wallet_path
- def stop_node(self, expected_stderr=''):
+ def stop_node(self, expected_stderr='', wait=0):
"""Stop the node."""
if not self.running:
return
self.log.debug("Stopping node")
try:
- self.stop()
+ self.stop(wait=wait)
except http.client.CannotSendRequest:
self.log.exception("Unable to stop node.")
diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py
index b355816d8b..d0a78d8dfd 100644
--- a/test/functional/test_framework/util.py
+++ b/test/functional/test_framework/util.py
@@ -326,7 +326,7 @@ def get_auth_cookie(datadir):
if line.startswith("rpcpassword="):
assert password is None # Ensure that there is only one rpcpassword line
password = line.split("=")[1].strip("\n")
- if os.path.isfile(os.path.join(datadir, "regtest", ".cookie")):
+ if os.path.isfile(os.path.join(datadir, "regtest", ".cookie")) and os.access(os.path.join(datadir, "regtest", ".cookie"), os.R_OK):
with open(os.path.join(datadir, "regtest", ".cookie"), 'r', encoding="ascii") as f:
userpass = f.read()
split_userpass = userpass.split(':')
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index 1167b4bba2..a68b544738 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -186,6 +186,7 @@ BASE_SCRIPTS = [
'feature_config_args.py',
'rpc_help.py',
'feature_help.py',
+ 'feature_shutdown.py',
# Don't append tests at the end to avoid merge conflicts
# Put them in a random line within the section that fits their approximate run-time
]
@@ -273,7 +274,7 @@ def main():
if tests:
# Individual tests have been specified. Run specified tests that exist
# in the ALL_SCRIPTS list. Accept the name with or without .py extension.
- tests = [re.sub("\.py$", "", test) + ".py" for test in tests]
+ tests = [test + ".py" if ".py" not in test else test for test in tests]
for test in tests:
if test in ALL_SCRIPTS:
test_list.append(test)
diff --git a/test/lint/commit-script-check.sh b/test/lint/commit-script-check.sh
index f1327469f3..4267f9fa0d 100755
--- a/test/lint/commit-script-check.sh
+++ b/test/lint/commit-script-check.sh
@@ -20,23 +20,23 @@ fi
RET=0
PREV_BRANCH=`git name-rev --name-only HEAD`
PREV_HEAD=`git rev-parse HEAD`
-for i in `git rev-list --reverse $1`; do
- if git rev-list -n 1 --pretty="%s" $i | grep -q "^scripted-diff:"; then
- git checkout --quiet $i^ || exit
- SCRIPT="`git rev-list --format=%b -n1 $i | sed '/^-BEGIN VERIFY SCRIPT-$/,/^-END VERIFY SCRIPT-$/{//!b};d'`"
+for commit in `git rev-list --reverse $1`; do
+ if git rev-list -n 1 --pretty="%s" $commit | grep -q "^scripted-diff:"; then
+ git checkout --quiet $commit^ || exit
+ SCRIPT="`git rev-list --format=%b -n1 $commit | sed '/^-BEGIN VERIFY SCRIPT-$/,/^-END VERIFY SCRIPT-$/{//!b};d'`"
if test "x$SCRIPT" = "x"; then
- echo "Error: missing script for: $i"
+ echo "Error: missing script for: $commit"
echo "Failed"
RET=1
else
- echo "Running script for: $i"
+ echo "Running script for: $commit"
echo "$SCRIPT"
- eval "$SCRIPT"
- git --no-pager diff --exit-code $i && echo "OK" || (echo "Failed"; false) || RET=1
+ (eval "$SCRIPT")
+ git --no-pager diff --exit-code $commit && echo "OK" || (echo "Failed"; false) || RET=1
fi
git reset --quiet --hard HEAD
else
- if git rev-list "--format=%b" -n1 $i | grep -q '^-\(BEGIN\|END\)[ a-zA-Z]*-$'; then
+ if git rev-list "--format=%b" -n1 $commit | grep -q '^-\(BEGIN\|END\)[ a-zA-Z]*-$'; then
echo "Error: script block marker but no scripted-diff in title"
echo "Failed"
RET=1
diff --git a/test/lint/lint-python-dead-code.sh b/test/lint/lint-python-dead-code.sh
index 3341f794f9..4561b0db30 100755
--- a/test/lint/lint-python-dead-code.sh
+++ b/test/lint/lint-python-dead-code.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
#
# Copyright (c) 2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
diff --git a/test/lint/lint-python-shebang.sh b/test/lint/lint-shebang.sh
index 4ff87f0bf7..fda22592d3 100755
--- a/test/lint/lint-python-shebang.sh
+++ b/test/lint/lint-shebang.sh
@@ -1,5 +1,5 @@
#!/usr/bin/env bash
-# Shebang must use python3 (not python or python2)
+# Assert expected shebang lines
export LC_ALL=C
EXIT_CODE=0
@@ -10,4 +10,11 @@ for PYTHON_FILE in $(git ls-files -- "*.py"); do
EXIT_CODE=1
fi
done
+for SHELL_FILE in $(git ls-files -- "*.sh"); do
+ if [[ $(head -n 1 "${SHELL_FILE}") != "#!/usr/bin/env bash" &&
+ $(head -n 1 "${SHELL_FILE}") != "#!/bin/sh" ]]; then
+ echo "Missing expected shebang \"#!/usr/bin/env bash\" or \"#!/bin/sh\" in ${SHELL_FILE}"
+ EXIT_CODE=1
+ fi
+done
exit ${EXIT_CODE}