aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build-aux/m4/ax_boost_chrono.m48
-rw-r--r--build-aux/m4/ax_boost_unit_test_framework.m410
-rw-r--r--configure.ac18
-rw-r--r--doc/developer-notes.md11
-rw-r--r--src/bitcoin-cli.cpp26
-rw-r--r--src/chain.h8
-rw-r--r--src/net.cpp5
-rw-r--r--src/netbase.cpp2
-rw-r--r--src/qt/addressbookpage.cpp11
-rw-r--r--src/qt/addresstablemodel.cpp2
-rw-r--r--src/qt/addresstablemodel.h4
-rw-r--r--src/qt/editaddressdialog.cpp10
-rw-r--r--src/qt/editaddressdialog.h1
-rw-r--r--src/qt/paymentserver.cpp2
-rw-r--r--src/qt/receivecoinsdialog.cpp8
-rw-r--r--src/qt/test/wallettests.cpp5
-rw-r--r--src/qt/walletmodel.cpp2
-rw-r--r--src/qt/walletmodel.h2
-rw-r--r--src/rpc/blockchain.cpp6
-rw-r--r--src/rpc/server.h9
-rw-r--r--src/serialize.h42
-rw-r--r--src/test/serialize_tests.cpp26
-rw-r--r--src/txdb.cpp4
-rw-r--r--src/undo.h4
-rw-r--r--src/wallet/coincontrol.h6
-rw-r--r--src/wallet/init.cpp14
-rw-r--r--src/wallet/rpcdump.cpp2
-rw-r--r--src/wallet/rpcwallet.cpp26
-rw-r--r--src/wallet/test/wallet_test_fixture.cpp2
-rw-r--r--src/wallet/test/wallet_tests.cpp5
-rw-r--r--src/wallet/wallet.cpp79
-rw-r--r--src/wallet/wallet.h22
-rwxr-xr-xtest/functional/feature_maxuploadtarget.py6
-rwxr-xr-xtest/functional/feature_pruning.py21
-rwxr-xr-xtest/functional/feature_reindex.py7
-rwxr-xr-xtest/functional/interface_bitcoin_cli.py10
-rwxr-xr-xtest/functional/p2p_compactblocks.py10
-rwxr-xr-xtest/functional/p2p_feefilter.py4
-rwxr-xr-xtest/functional/p2p_segwit.py8
-rwxr-xr-xtest/functional/p2p_timeouts.py8
-rwxr-xr-xtest/functional/rpc_net.py10
-rwxr-xr-xtest/functional/test_framework/comptool.py6
-rw-r--r--test/functional/test_framework/util.py11
-rwxr-xr-xtest/functional/test_runner.py12
-rwxr-xr-xtest/functional/wallet_basic.py4
45 files changed, 251 insertions, 248 deletions
diff --git a/build-aux/m4/ax_boost_chrono.m4 b/build-aux/m4/ax_boost_chrono.m4
index 318ecea17f..e9b0f2061c 100644
--- a/build-aux/m4/ax_boost_chrono.m4
+++ b/build-aux/m4/ax_boost_chrono.m4
@@ -1,5 +1,5 @@
# ===========================================================================
-# http://www.gnu.org/software/autoconf-archive/ax_boost_chrono.html
+# https://www.gnu.org/software/autoconf-archive/ax_boost_chrono.html
# ===========================================================================
#
# SYNOPSIS
@@ -8,7 +8,7 @@
#
# DESCRIPTION
#
-# Test for System library from the Boost C++ libraries. The macro requires
+# Test for Chrono library from the Boost C++ libraries. The macro requires
# a preceding call to AX_BOOST_BASE. Further documentation is available at
# <http://randspringer.de/boost/index.html>.
#
@@ -29,7 +29,7 @@
# and this notice are preserved. This file is offered as-is, without any
# warranty.
-#serial 1
+#serial 4
AC_DEFUN([AX_BOOST_CHRONO],
[
@@ -68,7 +68,7 @@ AC_DEFUN([AX_BOOST_CHRONO],
CXXFLAGS_SAVE=$CXXFLAGS
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include <boost/chrono.hpp>]],
- [[boost::chrono::system_clock::time_point time;]])],
+ [[boost::chrono::system_clock::time_point* time = new boost::chrono::system_clock::time_point; delete time;]])],
ax_cv_boost_chrono=yes, ax_cv_boost_chrono=no)
CXXFLAGS=$CXXFLAGS_SAVE
AC_LANG_POP([C++])
diff --git a/build-aux/m4/ax_boost_unit_test_framework.m4 b/build-aux/m4/ax_boost_unit_test_framework.m4
index 4efd1e2f18..0cdbe752cf 100644
--- a/build-aux/m4/ax_boost_unit_test_framework.m4
+++ b/build-aux/m4/ax_boost_unit_test_framework.m4
@@ -1,6 +1,6 @@
-# ================================================================================
-# http://www.gnu.org/software/autoconf-archive/ax_boost_unit_test_framework.html
-# ================================================================================
+# =================================================================================
+# https://www.gnu.org/software/autoconf-archive/ax_boost_unit_test_framework.html
+# =================================================================================
#
# SYNOPSIS
#
@@ -29,7 +29,7 @@
# and this notice are preserved. This file is offered as-is, without any
# warranty.
-#serial 19
+#serial 21
AC_DEFUN([AX_BOOST_UNIT_TEST_FRAMEWORK],
[
@@ -66,7 +66,7 @@ AC_DEFUN([AX_BOOST_UNIT_TEST_FRAMEWORK],
[AC_LANG_PUSH([C++])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include <boost/test/unit_test.hpp>]],
[[using boost::unit_test::test_suite;
- test_suite* test= BOOST_TEST_SUITE( "Unit test example 1" ); return 0;]])],
+ test_suite* test= BOOST_TEST_SUITE( "Unit test example 1" ); if (test == NULL) { return 1; } else { return 0; }]])],
ax_cv_boost_unit_test_framework=yes, ax_cv_boost_unit_test_framework=no)
AC_LANG_POP([C++])
])
diff --git a/configure.ac b/configure.ac
index 18f707f0ba..4f57750a1a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -643,22 +643,6 @@ AC_CHECK_DECLS([bswap_16, bswap_32, bswap_64],,,
AC_CHECK_DECLS([__builtin_clz, __builtin_clzl, __builtin_clzll])
-dnl Check for MSG_NOSIGNAL
-AC_MSG_CHECKING(for MSG_NOSIGNAL)
-AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/socket.h>]],
- [[ int f = MSG_NOSIGNAL; ]])],
- [ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_MSG_NOSIGNAL, 1,[Define this symbol if you have MSG_NOSIGNAL]) ],
- [ AC_MSG_RESULT(no)]
-)
-
-dnl Check for MSG_DONTWAIT
-AC_MSG_CHECKING(for MSG_DONTWAIT)
-AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/socket.h>]],
- [[ int f = MSG_DONTWAIT; ]])],
- [ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_MSG_DONTWAIT, 1,[Define this symbol if you have MSG_DONTWAIT]) ],
- [ AC_MSG_RESULT(no)]
-)
-
dnl Check for malloc_info (for memory statistics information in getmemoryinfo)
AC_MSG_CHECKING(for getmemoryinfo)
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <malloc.h>]],
@@ -771,7 +755,7 @@ dnl Check for libminiupnpc (optional)
if test x$use_upnp != xno; then
AC_CHECK_HEADERS(
[miniupnpc/miniwget.h miniupnpc/miniupnpc.h miniupnpc/upnpcommands.h miniupnpc/upnperrors.h],
- [AC_CHECK_LIB([miniupnpc], [main],[MINIUPNPC_LIBS=-lminiupnpc], [have_miniupnpc=no])],
+ [AC_CHECK_LIB([miniupnpc], [upnpDiscover], [MINIUPNPC_LIBS=-lminiupnpc], [have_miniupnpc=no])],
[have_miniupnpc=no]
)
fi
diff --git a/doc/developer-notes.md b/doc/developer-notes.md
index a5468c3be3..8f06ee4eca 100644
--- a/doc/developer-notes.md
+++ b/doc/developer-notes.md
@@ -710,3 +710,14 @@ A few guidelines for introducing and reviewing new RPC interfaces:
client may be aware of prior to entering a wallet RPC call, we must block
until the wallet is caught up to the chainstate as of the RPC call's entry.
This also makes the API much easier for RPC clients to reason about.
+
+- Be aware of RPC method aliases and generally avoid registering the same
+ callback function pointer for different RPCs.
+
+ - *Rationale*: RPC methods registered with the same function pointer will be
+ considered aliases and only the first method name will show up in the
+ `help` rpc command list.
+
+ - *Exception*: Using RPC method aliases may be appropriate in cases where a
+ new RPC is replacing a deprecated RPC, to avoid both RPCs confusingly
+ showing up in the command list.
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index 41f1e5786c..8bdc210997 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -313,13 +313,11 @@ static UniValue CallRPC(BaseRequestHandler *rh, const std::string& strMethod, co
// Get credentials
std::string strRPCUserColonPass;
+ bool failedToGetAuthCookie = false;
if (gArgs.GetArg("-rpcpassword", "") == "") {
// Try fall back to cookie-based authentication if no password is provided
if (!GetAuthCookie(&strRPCUserColonPass)) {
- throw std::runtime_error(strprintf(
- _("Could not locate RPC credentials. No authentication cookie could be found, and RPC password is not set. See -rpcpassword and -stdinrpcpass. Configuration file: (%s)"),
- GetConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME)).string().c_str()));
-
+ failedToGetAuthCookie = true;
}
} else {
strRPCUserColonPass = gArgs.GetArg("-rpcuser", "") + ":" + gArgs.GetArg("-rpcpassword", "");
@@ -358,11 +356,21 @@ static UniValue CallRPC(BaseRequestHandler *rh, const std::string& strMethod, co
event_base_dispatch(base.get());
- if (response.status == 0)
- throw CConnectionFailed(strprintf("couldn't connect to server: %s (code %d)\n(make sure server is running and you are connecting to the correct RPC port)", http_errorstring(response.error), response.error));
- else if (response.status == HTTP_UNAUTHORIZED)
- throw std::runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
- else if (response.status >= 400 && response.status != HTTP_BAD_REQUEST && response.status != HTTP_NOT_FOUND && response.status != HTTP_INTERNAL_SERVER_ERROR)
+ if (response.status == 0) {
+ std::string responseErrorMessage;
+ if (response.error != -1) {
+ responseErrorMessage = strprintf(" (error code %d - \"%s\")", response.error, http_errorstring(response.error));
+ }
+ throw CConnectionFailed(strprintf("Could not connect to the server %s:%d%s\n\nMake sure the bitcoind server is running and that you are connecting to the correct RPC port.", host, port, responseErrorMessage));
+ } else if (response.status == HTTP_UNAUTHORIZED) {
+ if (failedToGetAuthCookie) {
+ throw std::runtime_error(strprintf(
+ _("Could not locate RPC credentials. No authentication cookie could be found, and RPC password is not set. See -rpcpassword and -stdinrpcpass. Configuration file: (%s)"),
+ GetConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME)).string().c_str()));
+ } else {
+ throw std::runtime_error("Authorization failed: Incorrect rpcuser or rpcpassword");
+ }
+ } else if (response.status >= 400 && response.status != HTTP_BAD_REQUEST && response.status != HTTP_NOT_FOUND && response.status != HTTP_INTERNAL_SERVER_ERROR)
throw std::runtime_error(strprintf("server returned HTTP error %d", response.status));
else if (response.body.empty())
throw std::runtime_error("no response from server");
diff --git a/src/chain.h b/src/chain.h
index 3728f768c4..757840bb23 100644
--- a/src/chain.h
+++ b/src/chain.h
@@ -91,7 +91,7 @@ struct CDiskBlockPos
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
- READWRITE(VARINT(nFile));
+ READWRITE(VARINT(nFile, VarIntMode::NONNEGATIVE_SIGNED));
READWRITE(VARINT(nPos));
}
@@ -386,13 +386,13 @@ public:
inline void SerializationOp(Stream& s, Operation ser_action) {
int _nVersion = s.GetVersion();
if (!(s.GetType() & SER_GETHASH))
- READWRITE(VARINT(_nVersion));
+ READWRITE(VARINT(_nVersion, VarIntMode::NONNEGATIVE_SIGNED));
- READWRITE(VARINT(nHeight));
+ READWRITE(VARINT(nHeight, VarIntMode::NONNEGATIVE_SIGNED));
READWRITE(VARINT(nStatus));
READWRITE(VARINT(nTx));
if (nStatus & (BLOCK_HAVE_DATA | BLOCK_HAVE_UNDO))
- READWRITE(VARINT(nFile));
+ READWRITE(VARINT(nFile, VarIntMode::NONNEGATIVE_SIGNED));
if (nStatus & BLOCK_HAVE_DATA)
READWRITE(VARINT(nDataPos));
if (nStatus & BLOCK_HAVE_UNDO)
diff --git a/src/net.cpp b/src/net.cpp
index 975a1d10a0..342dfbaeb9 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -42,12 +42,13 @@
// We add a random period time (0 to 1 seconds) to feeler connections to prevent synchronization.
#define FEELER_SLEEP_WINDOW 1
-#if !defined(HAVE_MSG_NOSIGNAL)
+// MSG_NOSIGNAL is not available on some platforms, if it doesn't exist define it as 0
+#if !defined(MSG_NOSIGNAL)
#define MSG_NOSIGNAL 0
#endif
// MSG_DONTWAIT is not available on some platforms, if it doesn't exist define it as 0
-#if !defined(HAVE_MSG_DONTWAIT)
+#if !defined(MSG_DONTWAIT)
#define MSG_DONTWAIT 0
#endif
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 3ea3141d5e..92ac1c4c85 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -21,7 +21,7 @@
#include <boost/algorithm/string/case_conv.hpp> // for to_lower()
#include <boost/algorithm/string/predicate.hpp> // for startswith() and endswith()
-#if !defined(HAVE_MSG_NOSIGNAL)
+#if !defined(MSG_NOSIGNAL)
#define MSG_NOSIGNAL 0
#endif
diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp
index 78dc9f81dd..f2ddbf259b 100644
--- a/src/qt/addressbookpage.cpp
+++ b/src/qt/addressbookpage.cpp
@@ -104,10 +104,12 @@ AddressBookPage::AddressBookPage(const PlatformStyle *platformStyle, Mode _mode,
case SendingTab:
ui->labelExplanation->setText(tr("These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins."));
ui->deleteAddress->setVisible(true);
+ ui->newAddress->setVisible(true);
break;
case ReceivingTab:
ui->labelExplanation->setText(tr("These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction."));
ui->deleteAddress->setVisible(false);
+ ui->newAddress->setVisible(false);
break;
}
@@ -211,10 +213,11 @@ void AddressBookPage::on_newAddress_clicked()
if(!model)
return;
- EditAddressDialog dlg(
- tab == SendingTab ?
- EditAddressDialog::NewSendingAddress :
- EditAddressDialog::NewReceivingAddress, this);
+ if (tab == ReceivingTab) {
+ return;
+ }
+
+ EditAddressDialog dlg(EditAddressDialog::NewSendingAddress, this);
dlg.setModel(model);
if(dlg.exec())
{
diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp
index 4f9a79d654..801334483a 100644
--- a/src/qt/addresstablemodel.cpp
+++ b/src/qt/addresstablemodel.cpp
@@ -441,6 +441,8 @@ int AddressTableModel::lookupAddress(const QString &address) const
}
}
+OutputType AddressTableModel::GetDefaultAddressType() const { return wallet->m_default_address_type; };
+
void AddressTableModel::emitDataChanged(int idx)
{
Q_EMIT dataChanged(index(idx, 0, QModelIndex()), index(idx, columns.length()-1, QModelIndex()));
diff --git a/src/qt/addresstablemodel.h b/src/qt/addresstablemodel.h
index 11439e25d5..ed7a4e6f43 100644
--- a/src/qt/addresstablemodel.h
+++ b/src/qt/addresstablemodel.h
@@ -8,7 +8,7 @@
#include <QAbstractTableModel>
#include <QStringList>
-enum OutputType : int;
+enum class OutputType;
class AddressTablePriv;
class WalletModel;
@@ -76,6 +76,8 @@ public:
EditStatus getEditStatus() const { return editStatus; }
+ OutputType GetDefaultAddressType() const;
+
private:
WalletModel *walletModel;
CWallet *wallet;
diff --git a/src/qt/editaddressdialog.cpp b/src/qt/editaddressdialog.cpp
index a945fc6aa0..38411c499f 100644
--- a/src/qt/editaddressdialog.cpp
+++ b/src/qt/editaddressdialog.cpp
@@ -11,7 +11,6 @@
#include <QDataWidgetMapper>
#include <QMessageBox>
-extern OutputType g_address_type;
EditAddressDialog::EditAddressDialog(Mode _mode, QWidget *parent) :
QDialog(parent),
@@ -26,10 +25,6 @@ EditAddressDialog::EditAddressDialog(Mode _mode, QWidget *parent) :
switch(mode)
{
- case NewReceivingAddress:
- setWindowTitle(tr("New receiving address"));
- ui->addressEdit->setEnabled(false);
- break;
case NewSendingAddress:
setWindowTitle(tr("New sending address"));
break;
@@ -74,13 +69,12 @@ bool EditAddressDialog::saveCurrentRow()
switch(mode)
{
- case NewReceivingAddress:
case NewSendingAddress:
address = model->addRow(
- mode == NewSendingAddress ? AddressTableModel::Send : AddressTableModel::Receive,
+ AddressTableModel::Send,
ui->labelEdit->text(),
ui->addressEdit->text(),
- g_address_type);
+ model->GetDefaultAddressType());
break;
case EditReceivingAddress:
case EditSendingAddress:
diff --git a/src/qt/editaddressdialog.h b/src/qt/editaddressdialog.h
index ddb67ece72..41c5d1708a 100644
--- a/src/qt/editaddressdialog.h
+++ b/src/qt/editaddressdialog.h
@@ -25,7 +25,6 @@ class EditAddressDialog : public QDialog
public:
enum Mode {
- NewReceivingAddress,
NewSendingAddress,
EditReceivingAddress,
EditSendingAddress
diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp
index 4b6fdc8d57..92d7d72935 100644
--- a/src/qt/paymentserver.cpp
+++ b/src/qt/paymentserver.cpp
@@ -643,7 +643,7 @@ void PaymentServer::fetchPaymentACK(CWallet* wallet, const SendCoinsRecipient& r
// use for change. Despite an actual payment and not change, this is a close match:
// it's the output type we use subject to privacy issues, but not restricted by what
// other software supports.
- const OutputType change_type = g_change_type != OUTPUT_TYPE_NONE ? g_change_type : g_address_type;
+ const OutputType change_type = wallet->m_default_change_type != OutputType::NONE ? wallet->m_default_change_type : wallet->m_default_address_type;
wallet->LearnRelatedScripts(newKey, change_type);
CTxDestination dest = GetDestinationForKey(newKey, change_type);
wallet->SetAddressBook(dest, strAccount, "refund");
diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp
index 7fd5285467..132fb54d66 100644
--- a/src/qt/receivecoinsdialog.cpp
+++ b/src/qt/receivecoinsdialog.cpp
@@ -95,13 +95,13 @@ void ReceiveCoinsDialog::setModel(WalletModel *_model)
columnResizingFixer = new GUIUtil::TableViewLastColumnResizingFixer(tableView, AMOUNT_MINIMUM_COLUMN_WIDTH, DATE_COLUMN_WIDTH, this);
// configure bech32 checkbox, disable if launched with legacy as default:
- if (model->getDefaultAddressType() == OUTPUT_TYPE_BECH32) {
+ if (model->getDefaultAddressType() == OutputType::BECH32) {
ui->useBech32->setCheckState(Qt::Checked);
} else {
ui->useBech32->setCheckState(Qt::Unchecked);
}
- ui->useBech32->setVisible(model->getDefaultAddressType() != OUTPUT_TYPE_LEGACY);
+ ui->useBech32->setVisible(model->getDefaultAddressType() != OutputType::LEGACY);
}
}
@@ -145,8 +145,8 @@ void ReceiveCoinsDialog::on_receiveButton_clicked()
QString label = ui->reqLabel->text();
/* Generate new receiving address */
OutputType address_type = model->getDefaultAddressType();
- if (address_type != OUTPUT_TYPE_LEGACY) {
- address_type = ui->useBech32->isChecked() ? OUTPUT_TYPE_BECH32 : OUTPUT_TYPE_P2SH_SEGWIT;
+ if (address_type != OutputType::LEGACY) {
+ address_type = ui->useBech32->isChecked() ? OutputType::BECH32 : OutputType::P2SH_SEGWIT;
}
address = model->getAddressTableModel()->addRow(AddressTableModel::Receive, label, "", address_type);
SendCoinsRecipient info(address, label,
diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp
index 976aadc0af..c9898e52ca 100644
--- a/src/qt/test/wallettests.cpp
+++ b/src/qt/test/wallettests.cpp
@@ -150,9 +150,6 @@ void BumpFee(TransactionView& view, const uint256& txid, bool expectDisabled, st
// src/qt/test/test_bitcoin-qt -platform cocoa # macOS
void TestGUI()
{
- g_address_type = OUTPUT_TYPE_P2SH_SEGWIT;
- g_change_type = OUTPUT_TYPE_P2SH_SEGWIT;
-
// Set up wallet and chain with 105 blocks (5 mature blocks for spending).
TestChain100Setup test;
for (int i = 0; i < 5; ++i) {
@@ -163,7 +160,7 @@ void TestGUI()
wallet.LoadWallet(firstRun);
{
LOCK(wallet.cs_wallet);
- wallet.SetAddressBook(GetDestinationForKey(test.coinbaseKey.GetPubKey(), g_address_type), "", "receive");
+ wallet.SetAddressBook(GetDestinationForKey(test.coinbaseKey.GetPubKey(), wallet.m_default_address_type), "", "receive");
wallet.AddKeyPubKey(test.coinbaseKey, test.coinbaseKey.GetPubKey());
}
{
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index b17bc3c91a..d092ebedfb 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -736,7 +736,7 @@ bool WalletModel::hdEnabled() const
OutputType WalletModel::getDefaultAddressType() const
{
- return g_address_type;
+ return wallet->m_default_address_type;
}
int WalletModel::getDefaultConfirmTarget() const
diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h
index 811996b98f..64813e0f5a 100644
--- a/src/qt/walletmodel.h
+++ b/src/qt/walletmodel.h
@@ -20,7 +20,7 @@
#include <QObject>
-enum OutputType : int;
+enum class OutputType;
class AddressTableModel;
class OptionsModel;
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 2077723af5..169caddc59 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -834,18 +834,18 @@ static void ApplyStats(CCoinsStats &stats, CHashWriter& ss, const uint256& hash,
{
assert(!outputs.empty());
ss << hash;
- ss << VARINT(outputs.begin()->second.nHeight * 2 + outputs.begin()->second.fCoinBase);
+ ss << VARINT(outputs.begin()->second.nHeight * 2 + outputs.begin()->second.fCoinBase ? 1u : 0u);
stats.nTransactions++;
for (const auto output : outputs) {
ss << VARINT(output.first + 1);
ss << output.second.out.scriptPubKey;
- ss << VARINT(output.second.out.nValue);
+ ss << VARINT(output.second.out.nValue, VarIntMode::NONNEGATIVE_SIGNED);
stats.nTransactionOutputs++;
stats.nTotalAmount += output.second.out.nValue;
stats.nBogoSize += 32 /* txid */ + 4 /* vout index */ + 4 /* height + coinbase */ + 8 /* amount */ +
2 /* scriptPubKey len */ + output.second.out.scriptPubKey.size() /* scriptPubKey */;
}
- ss << VARINT(0);
+ ss << VARINT(0u);
}
//! Calculate statistics about the unspent transaction output set
diff --git a/src/rpc/server.h b/src/rpc/server.h
index 8b32924fbc..d25268a8ab 100644
--- a/src/rpc/server.h
+++ b/src/rpc/server.h
@@ -165,8 +165,17 @@ public:
/**
* Appends a CRPCCommand to the dispatch table.
+ *
* Returns false if RPC server is already running (dump concurrency protection).
+ *
* Commands cannot be overwritten (returns false).
+ *
+ * Commands with different method names but the same callback function will
+ * be considered aliases, and only the first registered method name will
+ * show up in the help text command listing. Aliased commands do not have
+ * to have the same behavior. Server and client code can distinguish
+ * between calls based on method name, and aliased commands can also
+ * register different names, types, and numbers of parameters.
*/
bool appendCommand(const std::string& name, const CRPCCommand* pcmd);
};
diff --git a/src/serialize.h b/src/serialize.h
index c454ba16b7..91da6b0f80 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -296,9 +296,31 @@ uint64_t ReadCompactSize(Stream& is)
* 2^32: [0x8E 0xFE 0xFE 0xFF 0x00]
*/
-template<typename I>
+/**
+ * Mode for encoding VarInts.
+ *
+ * Currently there is no support for signed encodings. The default mode will not
+ * compile with signed values, and the legacy "nonnegative signed" mode will
+ * accept signed values, but improperly encode and decode them if they are
+ * negative. In the future, the DEFAULT mode could be extended to support
+ * negative numbers in a backwards compatible way, and additional modes could be
+ * added to support different varint formats (e.g. zigzag encoding).
+ */
+enum class VarIntMode { DEFAULT, NONNEGATIVE_SIGNED };
+
+template <VarIntMode Mode, typename I>
+struct CheckVarIntMode {
+ constexpr CheckVarIntMode()
+ {
+ static_assert(Mode != VarIntMode::DEFAULT || std::is_unsigned<I>::value, "Unsigned type required with mode DEFAULT.");
+ static_assert(Mode != VarIntMode::NONNEGATIVE_SIGNED || std::is_signed<I>::value, "Signed type required with mode NONNEGATIVE_SIGNED.");
+ }
+};
+
+template<VarIntMode Mode, typename I>
inline unsigned int GetSizeOfVarInt(I n)
{
+ CheckVarIntMode<Mode, I>();
int nRet = 0;
while(true) {
nRet++;
@@ -312,9 +334,10 @@ inline unsigned int GetSizeOfVarInt(I n)
template<typename I>
inline void WriteVarInt(CSizeComputer& os, I n);
-template<typename Stream, typename I>
+template<typename Stream, VarIntMode Mode, typename I>
void WriteVarInt(Stream& os, I n)
{
+ CheckVarIntMode<Mode, I>();
unsigned char tmp[(sizeof(n)*8+6)/7];
int len=0;
while(true) {
@@ -329,9 +352,10 @@ void WriteVarInt(Stream& os, I n)
} while(len--);
}
-template<typename Stream, typename I>
+template<typename Stream, VarIntMode Mode, typename I>
I ReadVarInt(Stream& is)
{
+ CheckVarIntMode<Mode, I>();
I n = 0;
while(true) {
unsigned char chData = ser_readdata8(is);
@@ -351,7 +375,7 @@ I ReadVarInt(Stream& is)
}
#define FLATDATA(obj) CFlatData((char*)&(obj), (char*)&(obj) + sizeof(obj))
-#define VARINT(obj) WrapVarInt(REF(obj))
+#define VARINT(obj, ...) WrapVarInt<__VA_ARGS__>(REF(obj))
#define COMPACTSIZE(obj) CCompactSize(REF(obj))
#define LIMITED_STRING(obj,n) LimitedString< n >(REF(obj))
@@ -395,7 +419,7 @@ public:
}
};
-template<typename I>
+template<VarIntMode Mode, typename I>
class CVarInt
{
protected:
@@ -405,12 +429,12 @@ public:
template<typename Stream>
void Serialize(Stream &s) const {
- WriteVarInt<Stream,I>(s, n);
+ WriteVarInt<Stream,Mode,I>(s, n);
}
template<typename Stream>
void Unserialize(Stream& s) {
- n = ReadVarInt<Stream,I>(s);
+ n = ReadVarInt<Stream,Mode,I>(s);
}
};
@@ -461,8 +485,8 @@ public:
}
};
-template<typename I>
-CVarInt<I> WrapVarInt(I& n) { return CVarInt<I>(n); }
+template<VarIntMode Mode=VarIntMode::DEFAULT, typename I>
+CVarInt<Mode, I> WrapVarInt(I& n) { return CVarInt<Mode, I>{n}; }
/**
* Forward declarations
diff --git a/src/test/serialize_tests.cpp b/src/test/serialize_tests.cpp
index 42fd59380a..7a79a77e8b 100644
--- a/src/test/serialize_tests.cpp
+++ b/src/test/serialize_tests.cpp
@@ -177,8 +177,8 @@ BOOST_AUTO_TEST_CASE(varints)
CDataStream ss(SER_DISK, 0);
CDataStream::size_type size = 0;
for (int i = 0; i < 100000; i++) {
- ss << VARINT(i);
- size += ::GetSerializeSize(VARINT(i), 0, 0);
+ ss << VARINT(i, VarIntMode::NONNEGATIVE_SIGNED);
+ size += ::GetSerializeSize(VARINT(i, VarIntMode::NONNEGATIVE_SIGNED), 0, 0);
BOOST_CHECK(size == ss.size());
}
@@ -191,7 +191,7 @@ BOOST_AUTO_TEST_CASE(varints)
// decode
for (int i = 0; i < 100000; i++) {
int j = -1;
- ss >> VARINT(j);
+ ss >> VARINT(j, VarIntMode::NONNEGATIVE_SIGNED);
BOOST_CHECK_MESSAGE(i == j, "decoded:" << j << " expected:" << i);
}
@@ -205,21 +205,21 @@ BOOST_AUTO_TEST_CASE(varints)
BOOST_AUTO_TEST_CASE(varints_bitpatterns)
{
CDataStream ss(SER_DISK, 0);
- ss << VARINT(0); BOOST_CHECK_EQUAL(HexStr(ss), "00"); ss.clear();
- ss << VARINT(0x7f); BOOST_CHECK_EQUAL(HexStr(ss), "7f"); ss.clear();
- ss << VARINT((int8_t)0x7f); BOOST_CHECK_EQUAL(HexStr(ss), "7f"); ss.clear();
- ss << VARINT(0x80); BOOST_CHECK_EQUAL(HexStr(ss), "8000"); ss.clear();
+ ss << VARINT(0, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "00"); ss.clear();
+ ss << VARINT(0x7f, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "7f"); ss.clear();
+ ss << VARINT((int8_t)0x7f, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "7f"); ss.clear();
+ ss << VARINT(0x80, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "8000"); ss.clear();
ss << VARINT((uint8_t)0x80); BOOST_CHECK_EQUAL(HexStr(ss), "8000"); ss.clear();
- ss << VARINT(0x1234); BOOST_CHECK_EQUAL(HexStr(ss), "a334"); ss.clear();
- ss << VARINT((int16_t)0x1234); BOOST_CHECK_EQUAL(HexStr(ss), "a334"); ss.clear();
- ss << VARINT(0xffff); BOOST_CHECK_EQUAL(HexStr(ss), "82fe7f"); ss.clear();
+ ss << VARINT(0x1234, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "a334"); ss.clear();
+ ss << VARINT((int16_t)0x1234, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "a334"); ss.clear();
+ ss << VARINT(0xffff, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "82fe7f"); ss.clear();
ss << VARINT((uint16_t)0xffff); BOOST_CHECK_EQUAL(HexStr(ss), "82fe7f"); ss.clear();
- ss << VARINT(0x123456); BOOST_CHECK_EQUAL(HexStr(ss), "c7e756"); ss.clear();
- ss << VARINT((int32_t)0x123456); BOOST_CHECK_EQUAL(HexStr(ss), "c7e756"); ss.clear();
+ ss << VARINT(0x123456, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "c7e756"); ss.clear();
+ ss << VARINT((int32_t)0x123456, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "c7e756"); ss.clear();
ss << VARINT(0x80123456U); BOOST_CHECK_EQUAL(HexStr(ss), "86ffc7e756"); ss.clear();
ss << VARINT((uint32_t)0x80123456U); BOOST_CHECK_EQUAL(HexStr(ss), "86ffc7e756"); ss.clear();
ss << VARINT(0xffffffff); BOOST_CHECK_EQUAL(HexStr(ss), "8efefefe7f"); ss.clear();
- ss << VARINT(0x7fffffffffffffffLL); BOOST_CHECK_EQUAL(HexStr(ss), "fefefefefefefefe7f"); ss.clear();
+ ss << VARINT(0x7fffffffffffffffLL, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "fefefefefefefefe7f"); ss.clear();
ss << VARINT(0xffffffffffffffffULL); BOOST_CHECK_EQUAL(HexStr(ss), "80fefefefefefefefe7f"); ss.clear();
}
diff --git a/src/txdb.cpp b/src/txdb.cpp
index 7a1d920117..91d6c98430 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -324,7 +324,7 @@ public:
void Unserialize(Stream &s) {
unsigned int nCode = 0;
// version
- int nVersionDummy;
+ unsigned int nVersionDummy;
::Unserialize(s, VARINT(nVersionDummy));
// header code
::Unserialize(s, VARINT(nCode));
@@ -351,7 +351,7 @@ public:
::Unserialize(s, CTxOutCompressor(vout[i]));
}
// coinbase height
- ::Unserialize(s, VARINT(nHeight));
+ ::Unserialize(s, VARINT(nHeight, VarIntMode::NONNEGATIVE_SIGNED));
}
};
diff --git a/src/undo.h b/src/undo.h
index 673a1f00ef..f292924165 100644
--- a/src/undo.h
+++ b/src/undo.h
@@ -25,7 +25,7 @@ class TxInUndoSerializer
public:
template<typename Stream>
void Serialize(Stream &s) const {
- ::Serialize(s, VARINT(txout->nHeight * 2 + (txout->fCoinBase ? 1 : 0)));
+ ::Serialize(s, VARINT(txout->nHeight * 2 + (txout->fCoinBase ? 1u : 0u)));
if (txout->nHeight > 0) {
// Required to maintain compatibility with older undo format.
::Serialize(s, (unsigned char)0);
@@ -51,7 +51,7 @@ public:
// Old versions stored the version number for the last spend of
// a transaction's outputs. Non-final spends were indicated with
// height = 0.
- int nVersionDummy;
+ unsigned int nVersionDummy;
::Unserialize(s, VARINT(nVersionDummy));
}
::Unserialize(s, CTxOutCompressor(REF(txout->out)));
diff --git a/src/wallet/coincontrol.h b/src/wallet/coincontrol.h
index 458e770e03..52d6a291c9 100644
--- a/src/wallet/coincontrol.h
+++ b/src/wallet/coincontrol.h
@@ -18,8 +18,8 @@ class CCoinControl
public:
//! Custom change destination, if not set an address is generated
CTxDestination destChange;
- //! Custom change type, ignored if destChange is set, defaults to g_change_type
- OutputType change_type;
+ //! Override the default change type if set, ignored if destChange is set
+ boost::optional<OutputType> m_change_type;
//! If false, allows unselected inputs, but requires all selected inputs be used
bool fAllowOtherInputs;
//! Includes watch only addresses which match the ISMINE_WATCH_SOLVABLE criteria
@@ -43,7 +43,7 @@ public:
void SetNull()
{
destChange = CNoDestination();
- change_type = g_change_type;
+ m_change_type.reset();
fAllowOtherInputs = false;
fAllowWatchOnly = false;
setSelected.clear();
diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp
index e028cf4210..61481e01b6 100644
--- a/src/wallet/init.cpp
+++ b/src/wallet/init.cpp
@@ -17,7 +17,7 @@
std::string GetWalletHelpString(bool showDebug)
{
std::string strUsage = HelpMessageGroup(_("Wallet options:"));
- strUsage += HelpMessageOpt("-addresstype", strprintf("What type of addresses to use (\"legacy\", \"p2sh-segwit\", or \"bech32\", default: \"%s\")", FormatOutputType(OUTPUT_TYPE_DEFAULT)));
+ strUsage += HelpMessageOpt("-addresstype", strprintf("What type of addresses to use (\"legacy\", \"p2sh-segwit\", or \"bech32\", default: \"%s\")", FormatOutputType(DEFAULT_ADDRESS_TYPE)));
strUsage += HelpMessageOpt("-changetype", "What type of change to use (\"legacy\", \"p2sh-segwit\", or \"bech32\"). Default is same as -addresstype, except when -addresstype=p2sh-segwit a native segwit output is used when sending to a native segwit address)");
strUsage += HelpMessageOpt("-disablewallet", _("Do not load the wallet and disable wallet RPC calls"));
strUsage += HelpMessageOpt("-discardfee=<amt>", strprintf(_("The fee rate (in %s/kB) that indicates your tolerance for discarding change by adding it to the fee (default: %s). "
@@ -181,18 +181,6 @@ bool WalletParameterInteraction()
bSpendZeroConfChange = gArgs.GetBoolArg("-spendzeroconfchange", DEFAULT_SPEND_ZEROCONF_CHANGE);
fWalletRbf = gArgs.GetBoolArg("-walletrbf", DEFAULT_WALLET_RBF);
- g_address_type = ParseOutputType(gArgs.GetArg("-addresstype", ""));
- if (g_address_type == OUTPUT_TYPE_NONE) {
- return InitError(strprintf("Unknown address type '%s'", gArgs.GetArg("-addresstype", "")));
- }
-
- // If changetype is set in config file or parameter, check that it's valid.
- // Default to OUTPUT_TYPE_NONE if not set.
- g_change_type = ParseOutputType(gArgs.GetArg("-changetype", ""), OUTPUT_TYPE_NONE);
- if (g_change_type == OUTPUT_TYPE_NONE && !gArgs.GetArg("-changetype", "").empty()) {
- return InitError(strprintf("Unknown change type '%s'", gArgs.GetArg("-changetype", "")));
- }
-
return true;
}
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index 01125dd618..1721bc6df6 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -83,7 +83,7 @@ bool GetWalletAddressesForKey(CWallet * const pwallet, const CKeyID &keyid, std:
}
}
if (!fLabelFound) {
- strAddr = EncodeDestination(GetDestinationForKey(key.GetPubKey(), g_address_type));
+ strAddr = EncodeDestination(GetDestinationForKey(key.GetPubKey(), pwallet->m_default_address_type));
}
return fLabelFound;
}
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 3dbc01c068..0dc6de9564 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -162,10 +162,10 @@ UniValue getnewaddress(const JSONRPCRequest& request)
if (!request.params[0].isNull())
strAccount = AccountFromValue(request.params[0]);
- OutputType output_type = g_address_type;
+ OutputType output_type = pwallet->m_default_address_type;
if (!request.params[1].isNull()) {
- output_type = ParseOutputType(request.params[1].get_str(), g_address_type);
- if (output_type == OUTPUT_TYPE_NONE) {
+ output_type = ParseOutputType(request.params[1].get_str(), pwallet->m_default_address_type);
+ if (output_type == OutputType::NONE) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[1].get_str()));
}
}
@@ -259,10 +259,10 @@ UniValue getrawchangeaddress(const JSONRPCRequest& request)
pwallet->TopUpKeyPool();
}
- OutputType output_type = g_change_type != OUTPUT_TYPE_NONE ? g_change_type : g_address_type;
+ OutputType output_type = pwallet->m_default_change_type != OutputType::NONE ? pwallet->m_default_change_type : pwallet->m_default_address_type;
if (!request.params[0].isNull()) {
output_type = ParseOutputType(request.params[0].get_str(), output_type);
- if (output_type == OUTPUT_TYPE_NONE) {
+ if (output_type == OutputType::NONE) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[0].get_str()));
}
}
@@ -1221,10 +1221,10 @@ UniValue addmultisigaddress(const JSONRPCRequest& request)
}
}
- OutputType output_type = g_address_type;
+ OutputType output_type = pwallet->m_default_address_type;
if (!request.params[3].isNull()) {
output_type = ParseOutputType(request.params[3].get_str(), output_type);
- if (output_type == OUTPUT_TYPE_NONE) {
+ if (output_type == OutputType::NONE) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[3].get_str()));
}
}
@@ -2363,8 +2363,6 @@ UniValue walletpassphrase(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
- if (request.fHelp)
- return true;
if (!pwallet->IsCrypted()) {
throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
}
@@ -2429,8 +2427,6 @@ UniValue walletpassphrasechange(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
- if (request.fHelp)
- return true;
if (!pwallet->IsCrypted()) {
throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
}
@@ -2485,8 +2481,6 @@ UniValue walletlock(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
- if (request.fHelp)
- return true;
if (!pwallet->IsCrypted()) {
throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
}
@@ -2532,8 +2526,6 @@ UniValue encryptwallet(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
- if (request.fHelp)
- return true;
if (pwallet->IsCrypted()) {
throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
}
@@ -3183,8 +3175,8 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
if (options.exists("changeAddress")) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both changeAddress and address_type options");
}
- coinControl.change_type = ParseOutputType(options["change_type"].get_str(), coinControl.change_type);
- if (coinControl.change_type == OUTPUT_TYPE_NONE) {
+ coinControl.m_change_type = ParseOutputType(options["change_type"].get_str(), pwallet->m_default_change_type);
+ if (coinControl.m_change_type == OutputType::NONE) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown change type '%s'", options["change_type"].get_str()));
}
}
diff --git a/src/wallet/test/wallet_test_fixture.cpp b/src/wallet/test/wallet_test_fixture.cpp
index 77ccd0b8d8..5c550742c8 100644
--- a/src/wallet/test/wallet_test_fixture.cpp
+++ b/src/wallet/test/wallet_test_fixture.cpp
@@ -12,8 +12,6 @@ WalletTestingSetup::WalletTestingSetup(const std::string& chainName):
TestingSetup(chainName), m_wallet("mock", CWalletDBWrapper::CreateMock())
{
bool fFirstRun;
- g_address_type = OUTPUT_TYPE_DEFAULT;
- g_change_type = OUTPUT_TYPE_DEFAULT;
m_wallet.LoadWallet(fFirstRun);
RegisterValidationInterface(&m_wallet);
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index d6b0daf4fe..808f8b8838 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -114,9 +114,6 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
// than or equal to key birthday.
BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
{
- g_address_type = OUTPUT_TYPE_DEFAULT;
- g_change_type = OUTPUT_TYPE_DEFAULT;
-
// Create two blocks with same timestamp to verify that importwallet rescan
// will pick up both blocks, not just the first.
const int64_t BLOCK_TIME = chainActive.Tip()->GetBlockTimeMax() + 5;
@@ -272,8 +269,6 @@ public:
ListCoinsTestingSetup()
{
CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
- g_address_type = OUTPUT_TYPE_DEFAULT;
- g_change_type = OUTPUT_TYPE_DEFAULT;
wallet = MakeUnique<CWallet>("mock", CWalletDBWrapper::CreateMock());
bool firstRun;
wallet->LoadWallet(firstRun);
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 0d21570858..611d9bc100 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -42,8 +42,6 @@ CFeeRate payTxFee(DEFAULT_TRANSACTION_FEE);
unsigned int nTxConfirmTarget = DEFAULT_TX_CONFIRM_TARGET;
bool bSpendZeroConfChange = DEFAULT_SPEND_ZEROCONF_CHANGE;
bool fWalletRbf = DEFAULT_WALLET_RBF;
-OutputType g_address_type = OUTPUT_TYPE_NONE;
-OutputType g_change_type = OUTPUT_TYPE_NONE;
bool g_wallet_allow_fallback_fee = true; //<! will be defined via chainparams
const uint32_t BIP32_HARDENED_KEY_LIMIT = 0x80000000;
@@ -823,7 +821,7 @@ bool CWallet::GetAccountDestination(CTxDestination &dest, std::string strAccount
bForceNew = true;
else {
// Check if the current key has been used (TODO: check other addresses with the same key)
- CScript scriptPubKey = GetScriptForDestination(GetDestinationForKey(account.vchPubKey, g_address_type));
+ CScript scriptPubKey = GetScriptForDestination(GetDestinationForKey(account.vchPubKey, m_default_address_type));
for (std::map<uint256, CWalletTx>::iterator it = mapWallet.begin();
it != mapWallet.end() && account.vchPubKey.IsValid();
++it)
@@ -840,12 +838,12 @@ bool CWallet::GetAccountDestination(CTxDestination &dest, std::string strAccount
if (!GetKeyFromPool(account.vchPubKey, false))
return false;
- LearnRelatedScripts(account.vchPubKey, g_address_type);
- dest = GetDestinationForKey(account.vchPubKey, g_address_type);
+ LearnRelatedScripts(account.vchPubKey, m_default_address_type);
+ dest = GetDestinationForKey(account.vchPubKey, m_default_address_type);
SetAddressBook(dest, strAccount, "receive");
walletdb.WriteAccount(strAccount, account);
} else {
- dest = GetDestinationForKey(account.vchPubKey, g_address_type);
+ dest = GetDestinationForKey(account.vchPubKey, m_default_address_type);
}
return true;
@@ -2649,14 +2647,14 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nC
OutputType CWallet::TransactionChangeType(OutputType change_type, const std::vector<CRecipient>& vecSend)
{
// If -changetype is specified, always use that change type.
- if (change_type != OUTPUT_TYPE_NONE) {
+ if (change_type != OutputType::NONE) {
return change_type;
}
- // if g_address_type is legacy, use legacy address as change (even
+ // if m_default_address_type is legacy, use legacy address as change (even
// if some of the outputs are P2WPKH or P2WSH).
- if (g_address_type == OUTPUT_TYPE_LEGACY) {
- return OUTPUT_TYPE_LEGACY;
+ if (m_default_address_type == OutputType::LEGACY) {
+ return OutputType::LEGACY;
}
// if any destination is P2WPKH or P2WSH, use P2WPKH for the change
@@ -2666,12 +2664,12 @@ OutputType CWallet::TransactionChangeType(OutputType change_type, const std::vec
int witnessversion = 0;
std::vector<unsigned char> witnessprogram;
if (recipient.scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) {
- return OUTPUT_TYPE_BECH32;
+ return OutputType::BECH32;
}
}
- // else use g_address_type for change
- return g_address_type;
+ // else use m_default_address_type for change
+ return m_default_address_type;
}
bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransactionRef& tx, CReserveKey& reservekey, CAmount& nFeeRet,
@@ -2768,7 +2766,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac
return false;
}
- const OutputType change_type = TransactionChangeType(coin_control.change_type, vecSend);
+ const OutputType change_type = TransactionChangeType(coin_control.m_change_type ? *coin_control.m_change_type : m_default_change_type, vecSend);
LearnRelatedScripts(vchPubKey, change_type);
scriptChange = GetScriptForDestination(GetDestinationForKey(vchPubKey, change_type));
@@ -4002,8 +4000,7 @@ CWallet* CWallet::CreateWalletFromFile(const std::string& name, const fs::path&
}
walletInstance->SetBestChain(chainActive.GetLocator());
- }
- else if (gArgs.IsArgSet("-usehd")) {
+ } else if (gArgs.IsArgSet("-usehd")) {
bool useHD = gArgs.GetBoolArg("-usehd", true);
if (walletInstance->IsHDEnabled() && !useHD) {
InitError(strprintf(_("Error loading %s: You can't disable HD on an already existing HD wallet"), walletFile));
@@ -4015,6 +4012,20 @@ CWallet* CWallet::CreateWalletFromFile(const std::string& name, const fs::path&
}
}
+ walletInstance->m_default_address_type = ParseOutputType(gArgs.GetArg("-addresstype", ""), DEFAULT_ADDRESS_TYPE);
+ if (walletInstance->m_default_address_type == OutputType::NONE) {
+ InitError(strprintf("Unknown address type '%s'", gArgs.GetArg("-addresstype", "")));
+ return nullptr;
+ }
+
+ // If changetype is set in config file or parameter, check that it's valid.
+ // Default to OutputType::NONE if not set.
+ walletInstance->m_default_change_type = ParseOutputType(gArgs.GetArg("-changetype", ""), OutputType::NONE);
+ if (walletInstance->m_default_change_type == OutputType::NONE && !gArgs.GetArg("-changetype", "").empty()) {
+ InitError(strprintf("Unknown change type '%s'", gArgs.GetArg("-changetype", "")));
+ return nullptr;
+ }
+
LogPrintf(" wallet %15dms\n", GetTimeMillis() - nStart);
// Try to top up keypool. No-op if the wallet is locked.
@@ -4203,29 +4214,29 @@ OutputType ParseOutputType(const std::string& type, OutputType default_type)
if (type.empty()) {
return default_type;
} else if (type == OUTPUT_TYPE_STRING_LEGACY) {
- return OUTPUT_TYPE_LEGACY;
+ return OutputType::LEGACY;
} else if (type == OUTPUT_TYPE_STRING_P2SH_SEGWIT) {
- return OUTPUT_TYPE_P2SH_SEGWIT;
+ return OutputType::P2SH_SEGWIT;
} else if (type == OUTPUT_TYPE_STRING_BECH32) {
- return OUTPUT_TYPE_BECH32;
+ return OutputType::BECH32;
} else {
- return OUTPUT_TYPE_NONE;
+ return OutputType::NONE;
}
}
const std::string& FormatOutputType(OutputType type)
{
switch (type) {
- case OUTPUT_TYPE_LEGACY: return OUTPUT_TYPE_STRING_LEGACY;
- case OUTPUT_TYPE_P2SH_SEGWIT: return OUTPUT_TYPE_STRING_P2SH_SEGWIT;
- case OUTPUT_TYPE_BECH32: return OUTPUT_TYPE_STRING_BECH32;
+ case OutputType::LEGACY: return OUTPUT_TYPE_STRING_LEGACY;
+ case OutputType::P2SH_SEGWIT: return OUTPUT_TYPE_STRING_P2SH_SEGWIT;
+ case OutputType::BECH32: return OUTPUT_TYPE_STRING_BECH32;
default: assert(false);
}
}
void CWallet::LearnRelatedScripts(const CPubKey& key, OutputType type)
{
- if (key.IsCompressed() && (type == OUTPUT_TYPE_P2SH_SEGWIT || type == OUTPUT_TYPE_BECH32)) {
+ if (key.IsCompressed() && (type == OutputType::P2SH_SEGWIT || type == OutputType::BECH32)) {
CTxDestination witdest = WitnessV0KeyHash(key.GetID());
CScript witprog = GetScriptForDestination(witdest);
// Make sure the resulting program is solvable.
@@ -4236,20 +4247,20 @@ void CWallet::LearnRelatedScripts(const CPubKey& key, OutputType type)
void CWallet::LearnAllRelatedScripts(const CPubKey& key)
{
- // OUTPUT_TYPE_P2SH_SEGWIT always adds all necessary scripts for all types.
- LearnRelatedScripts(key, OUTPUT_TYPE_P2SH_SEGWIT);
+ // OutputType::P2SH_SEGWIT always adds all necessary scripts for all types.
+ LearnRelatedScripts(key, OutputType::P2SH_SEGWIT);
}
CTxDestination GetDestinationForKey(const CPubKey& key, OutputType type)
{
switch (type) {
- case OUTPUT_TYPE_LEGACY: return key.GetID();
- case OUTPUT_TYPE_P2SH_SEGWIT:
- case OUTPUT_TYPE_BECH32: {
+ case OutputType::LEGACY: return key.GetID();
+ case OutputType::P2SH_SEGWIT:
+ case OutputType::BECH32: {
if (!key.IsCompressed()) return key.GetID();
CTxDestination witdest = WitnessV0KeyHash(key.GetID());
CScript witprog = GetScriptForDestination(witdest);
- if (type == OUTPUT_TYPE_P2SH_SEGWIT) {
+ if (type == OutputType::P2SH_SEGWIT) {
return CScriptID(witprog);
} else {
return witdest;
@@ -4275,10 +4286,10 @@ CTxDestination CWallet::AddAndGetDestinationForScript(const CScript& script, Out
{
// Note that scripts over 520 bytes are not yet supported.
switch (type) {
- case OUTPUT_TYPE_LEGACY:
+ case OutputType::LEGACY:
return CScriptID(script);
- case OUTPUT_TYPE_P2SH_SEGWIT:
- case OUTPUT_TYPE_BECH32: {
+ case OutputType::P2SH_SEGWIT:
+ case OutputType::BECH32: {
WitnessV0ScriptHash hash;
CSHA256().Write(script.data(), script.size()).Finalize(hash.begin());
CTxDestination witdest = hash;
@@ -4287,7 +4298,7 @@ CTxDestination CWallet::AddAndGetDestinationForScript(const CScript& script, Out
if (!IsSolvable(*this, witprog)) return CScriptID(script);
// Add the redeemscript, so that P2WSH and P2SH-P2WSH outputs are recognized as ours.
AddCScript(witprog);
- if (type == OUTPUT_TYPE_BECH32) {
+ if (type == OutputType::BECH32) {
return witdest;
} else {
return CScriptID(witprog);
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index dc0e8d07d7..5ac8457eb4 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -43,6 +43,7 @@ extern bool bSpendZeroConfChange;
extern bool fWalletRbf;
extern bool g_wallet_allow_fallback_fee;
+//! Default for -keypool
static const unsigned int DEFAULT_KEYPOOL_SIZE = 1000;
//! -paytxfee default
static const CAmount DEFAULT_TRANSACTION_FEE = 0;
@@ -96,18 +97,15 @@ enum WalletFeature
FEATURE_LATEST = FEATURE_COMPRPUBKEY // HD is optional, use FEATURE_COMPRPUBKEY as latest version
};
-enum OutputType : int
-{
- OUTPUT_TYPE_NONE,
- OUTPUT_TYPE_LEGACY,
- OUTPUT_TYPE_P2SH_SEGWIT,
- OUTPUT_TYPE_BECH32,
-
- OUTPUT_TYPE_DEFAULT = OUTPUT_TYPE_P2SH_SEGWIT
+enum class OutputType {
+ NONE,
+ LEGACY,
+ P2SH_SEGWIT,
+ BECH32,
};
-extern OutputType g_address_type;
-extern OutputType g_change_type;
+//! Default for -addresstype
+constexpr OutputType DEFAULT_ADDRESS_TYPE{OutputType::P2SH_SEGWIT};
/** A key pool entry */
@@ -989,6 +987,8 @@ public:
static CFeeRate minTxFee;
static CFeeRate fallbackFee;
static CFeeRate m_discard_rate;
+ OutputType m_default_address_type{DEFAULT_ADDRESS_TYPE};
+ OutputType m_default_change_type{OutputType::NONE}; // Default to OutputType::NONE if not set by -changetype
bool NewKeyPool();
size_t KeypoolCountExternalKeys();
@@ -1232,7 +1232,7 @@ public:
}
};
-OutputType ParseOutputType(const std::string& str, OutputType default_type = OUTPUT_TYPE_DEFAULT);
+OutputType ParseOutputType(const std::string& str, OutputType default_type);
const std::string& FormatOutputType(OutputType type);
/**
diff --git a/test/functional/feature_maxuploadtarget.py b/test/functional/feature_maxuploadtarget.py
index 11c7de2ba0..abe4cb7c8e 100755
--- a/test/functional/feature_maxuploadtarget.py
+++ b/test/functional/feature_maxuploadtarget.py
@@ -17,7 +17,7 @@ from test_framework.mininode import *
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
-class TestNode(P2PInterface):
+class TestP2PConn(P2PInterface):
def __init__(self):
super().__init__()
self.block_receive_map = defaultdict(int)
@@ -55,7 +55,7 @@ class MaxUploadTest(BitcoinTestFramework):
p2p_conns = []
for _ in range(3):
- p2p_conns.append(self.nodes[0].add_p2p_connection(TestNode()))
+ p2p_conns.append(self.nodes[0].add_p2p_connection(TestP2PConn()))
network_thread_start()
for p2pc in p2p_conns:
@@ -147,7 +147,7 @@ class MaxUploadTest(BitcoinTestFramework):
self.start_node(0, ["-whitelist=127.0.0.1", "-maxuploadtarget=1", "-blockmaxsize=999000"])
# Reconnect to self.nodes[0]
- self.nodes[0].add_p2p_connection(TestNode())
+ self.nodes[0].add_p2p_connection(TestP2PConn())
network_thread_start()
self.nodes[0].p2p.wait_for_verack()
diff --git a/test/functional/feature_pruning.py b/test/functional/feature_pruning.py
index 365ff08d28..bb162e6e97 100755
--- a/test/functional/feature_pruning.py
+++ b/test/functional/feature_pruning.py
@@ -11,7 +11,6 @@ This test takes 30 mins or more (up to 2 hours)
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
-import time
import os
MIN_BLOCKS_TO_KEEP = 288
@@ -23,7 +22,7 @@ TIMESTAMP_WINDOW = 2 * 60 * 60
def calc_usage(blockdir):
- return sum(os.path.getsize(blockdir+f) for f in os.listdir(blockdir) if os.path.isfile(blockdir+f)) / (1024. * 1024.)
+ return sum(os.path.getsize(blockdir+f) for f in os.listdir(blockdir) if os.path.isfile(os.path.join(blockdir, f))) / (1024. * 1024.)
class PruneTest(BitcoinTestFramework):
def set_test_params(self):
@@ -70,7 +69,7 @@ class PruneTest(BitcoinTestFramework):
sync_blocks(self.nodes[0:5])
def test_height_min(self):
- if not os.path.isfile(self.prunedir+"blk00000.dat"):
+ if not os.path.isfile(os.path.join(self.prunedir, "blk00000.dat")):
raise AssertionError("blk00000.dat is missing, pruning too early")
self.log.info("Success")
self.log.info("Though we're already using more than 550MiB, current usage: %d" % calc_usage(self.prunedir))
@@ -79,11 +78,8 @@ class PruneTest(BitcoinTestFramework):
for i in range(25):
mine_large_block(self.nodes[0], self.utxo_cache_0)
- waitstart = time.time()
- while os.path.isfile(self.prunedir+"blk00000.dat"):
- time.sleep(0.1)
- if time.time() - waitstart > 30:
- raise AssertionError("blk00000.dat not pruned when it should be")
+ # Wait for blk00000.dat to be pruned
+ wait_until(lambda: not os.path.isfile(os.path.join(self.prunedir, "blk00000.dat")), timeout=30)
self.log.info("Success")
usage = calc_usage(self.prunedir)
@@ -218,11 +214,8 @@ class PruneTest(BitcoinTestFramework):
goalbestheight = first_reorg_height + 1
self.log.info("Verify node 2 reorged back to the main chain, some blocks of which it had to redownload")
- waitstart = time.time()
- while self.nodes[2].getblockcount() < goalbestheight:
- time.sleep(0.1)
- if time.time() - waitstart > 900:
- raise AssertionError("Node 2 didn't reorg to proper height")
+ # Wait for Node 2 to reorg to proper height
+ wait_until(lambda: self.nodes[2].getblockcount() >= goalbestheight, timeout=900)
assert(self.nodes[2].getbestblockhash() == goalbesthash)
# Verify we can now have the data for a block previously pruned
assert(self.nodes[2].getblock(self.forkhash)["height"] == self.forkheight)
@@ -262,7 +255,7 @@ class PruneTest(BitcoinTestFramework):
assert_equal(ret, expected_ret)
def has_block(index):
- return os.path.isfile(self.options.tmpdir + "/node{}/regtest/blocks/blk{:05}.dat".format(node_number, index))
+ return os.path.isfile(os.path.join(self.nodes[node_number].datadir, "regtest", "blocks", "blk{:05}.dat".format(index)))
# should not prune because chain tip of node 3 (995) < PruneAfterHeight (1000)
assert_raises_rpc_error(-1, "Blockchain is too short for pruning", node.pruneblockchain, height(500))
diff --git a/test/functional/feature_reindex.py b/test/functional/feature_reindex.py
index ac67e6e9ba..d1d3f1d7f1 100755
--- a/test/functional/feature_reindex.py
+++ b/test/functional/feature_reindex.py
@@ -10,8 +10,7 @@
"""
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import assert_equal
-import time
+from test_framework.util import wait_until
class ReindexTest(BitcoinTestFramework):
@@ -25,9 +24,7 @@ class ReindexTest(BitcoinTestFramework):
self.stop_nodes()
extra_args = [["-reindex-chainstate" if justchainstate else "-reindex", "-checkblockindex=1"]]
self.start_nodes(extra_args)
- while self.nodes[0].getblockcount() < blockcount:
- time.sleep(0.1)
- assert_equal(self.nodes[0].getblockcount(), blockcount)
+ wait_until(lambda: self.nodes[0].getblockcount() == blockcount)
self.log.info("Success")
def run_test(self):
diff --git a/test/functional/interface_bitcoin_cli.py b/test/functional/interface_bitcoin_cli.py
index d8c80ab34f..e29fdc84e7 100755
--- a/test/functional/interface_bitcoin_cli.py
+++ b/test/functional/interface_bitcoin_cli.py
@@ -29,11 +29,17 @@ class TestBitcoinCli(BitcoinTestFramework):
self.log.info("Test -stdinrpcpass option")
assert_equal(0, self.nodes[0].cli('-rpcuser=%s' % user, '-stdinrpcpass', input=password).getblockcount())
- assert_raises_process_error(1, "incorrect rpcuser or rpcpassword", self.nodes[0].cli('-rpcuser=%s' % user, '-stdinrpcpass', input="foo").echo)
+ assert_raises_process_error(1, "Incorrect rpcuser or rpcpassword", self.nodes[0].cli('-rpcuser=%s' % user, '-stdinrpcpass', input="foo").echo)
self.log.info("Test -stdin and -stdinrpcpass")
assert_equal(["foo", "bar"], self.nodes[0].cli('-rpcuser=%s' % user, '-stdin', '-stdinrpcpass', input=password + "\nfoo\nbar").echo())
- assert_raises_process_error(1, "incorrect rpcuser or rpcpassword", self.nodes[0].cli('-rpcuser=%s' % user, '-stdin', '-stdinrpcpass', input="foo").echo)
+ assert_raises_process_error(1, "Incorrect rpcuser or rpcpassword", self.nodes[0].cli('-rpcuser=%s' % user, '-stdin', '-stdinrpcpass', input="foo").echo)
+
+ self.log.info("Test connecting to a non-existing server")
+ assert_raises_process_error(1, "Could not connect to the server", self.nodes[0].cli('-rpcport=1').echo)
+
+ self.log.info("Test connecting with non-existing RPC cookie file")
+ assert_raises_process_error(1, "Could not locate RPC credentials", self.nodes[0].cli('-rpccookiefile=does-not-exist', '-rpcpassword=').echo)
self.log.info("Make sure that -getinfo with arguments fails")
assert_raises_process_error(1, "-getinfo takes no arguments", self.nodes[0].cli('-getinfo').help)
diff --git a/test/functional/p2p_compactblocks.py b/test/functional/p2p_compactblocks.py
index 8354505b16..1657d97281 100755
--- a/test/functional/p2p_compactblocks.py
+++ b/test/functional/p2p_compactblocks.py
@@ -14,8 +14,8 @@ from test_framework.util import *
from test_framework.blocktools import create_block, create_coinbase, add_witness_commitment
from test_framework.script import CScript, OP_TRUE
-# TestNode: A peer we use to send messages to bitcoind, and store responses.
-class TestNode(P2PInterface):
+# TestP2PConn: A peer we use to send messages to bitcoind, and store responses.
+class TestP2PConn(P2PInterface):
def __init__(self):
super().__init__()
self.last_sendcmpct = []
@@ -788,9 +788,9 @@ class CompactBlocksTest(BitcoinTestFramework):
def run_test(self):
# Setup the p2p connections and start up the network thread.
- self.test_node = self.nodes[0].add_p2p_connection(TestNode())
- self.segwit_node = self.nodes[1].add_p2p_connection(TestNode(), services=NODE_NETWORK|NODE_WITNESS)
- self.old_node = self.nodes[1].add_p2p_connection(TestNode(), services=NODE_NETWORK)
+ self.test_node = self.nodes[0].add_p2p_connection(TestP2PConn())
+ self.segwit_node = self.nodes[1].add_p2p_connection(TestP2PConn(), services=NODE_NETWORK|NODE_WITNESS)
+ self.old_node = self.nodes[1].add_p2p_connection(TestP2PConn(), services=NODE_NETWORK)
network_thread_start()
diff --git a/test/functional/p2p_feefilter.py b/test/functional/p2p_feefilter.py
index 47d9c55160..7c954cdca2 100755
--- a/test/functional/p2p_feefilter.py
+++ b/test/functional/p2p_feefilter.py
@@ -22,7 +22,7 @@ def allInvsMatch(invsExpected, testnode):
time.sleep(1)
return False
-class TestNode(P2PInterface):
+class TestP2PConn(P2PInterface):
def __init__(self):
super().__init__()
self.txinvs = []
@@ -48,7 +48,7 @@ class FeeFilterTest(BitcoinTestFramework):
sync_blocks(self.nodes)
# Setup the p2p connections and start up the network thread.
- self.nodes[0].add_p2p_connection(TestNode())
+ self.nodes[0].add_p2p_connection(TestP2PConn())
network_thread_start()
self.nodes[0].p2p.wait_for_verack()
diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py
index 915f26eda6..8b226c2e9d 100755
--- a/test/functional/p2p_segwit.py
+++ b/test/functional/p2p_segwit.py
@@ -59,7 +59,7 @@ def test_witness_block(rpc, p2p, block, accepted, with_witness=True):
p2p.sync_with_ping()
assert_equal(rpc.getbestblockhash() == block.hash, accepted)
-class TestNode(P2PInterface):
+class TestP2PConn(P2PInterface):
def __init__(self):
super().__init__()
self.getdataset = set()
@@ -1878,11 +1878,11 @@ class SegWitTest(BitcoinTestFramework):
def run_test(self):
# Setup the p2p connections and start up the network thread.
# self.test_node sets NODE_WITNESS|NODE_NETWORK
- self.test_node = self.nodes[0].add_p2p_connection(TestNode(), services=NODE_NETWORK|NODE_WITNESS)
+ self.test_node = self.nodes[0].add_p2p_connection(TestP2PConn(), services=NODE_NETWORK|NODE_WITNESS)
# self.old_node sets only NODE_NETWORK
- self.old_node = self.nodes[0].add_p2p_connection(TestNode(), services=NODE_NETWORK)
+ self.old_node = self.nodes[0].add_p2p_connection(TestP2PConn(), services=NODE_NETWORK)
# self.std_node is for testing node1 (fRequireStandard=true)
- self.std_node = self.nodes[1].add_p2p_connection(TestNode(), services=NODE_NETWORK|NODE_WITNESS)
+ self.std_node = self.nodes[1].add_p2p_connection(TestP2PConn(), services=NODE_NETWORK|NODE_WITNESS)
network_thread_start()
diff --git a/test/functional/p2p_timeouts.py b/test/functional/p2p_timeouts.py
index 6d21095cc6..6a21b693b4 100755
--- a/test/functional/p2p_timeouts.py
+++ b/test/functional/p2p_timeouts.py
@@ -27,7 +27,7 @@ from test_framework.mininode import *
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
-class TestNode(P2PInterface):
+class TestP2PConn(P2PInterface):
def on_version(self, message):
# Don't send a verack in response
pass
@@ -39,9 +39,9 @@ class TimeoutsTest(BitcoinTestFramework):
def run_test(self):
# Setup the p2p connections and start up the network thread.
- no_verack_node = self.nodes[0].add_p2p_connection(TestNode())
- no_version_node = self.nodes[0].add_p2p_connection(TestNode(), send_version=False)
- no_send_node = self.nodes[0].add_p2p_connection(TestNode(), send_version=False)
+ no_verack_node = self.nodes[0].add_p2p_connection(TestP2PConn())
+ no_version_node = self.nodes[0].add_p2p_connection(TestP2PConn(), send_version=False)
+ no_send_node = self.nodes[0].add_p2p_connection(TestP2PConn(), send_version=False)
network_thread_start()
diff --git a/test/functional/rpc_net.py b/test/functional/rpc_net.py
index 5f34b35bfb..d8348432aa 100755
--- a/test/functional/rpc_net.py
+++ b/test/functional/rpc_net.py
@@ -7,8 +7,6 @@
Tests correspond to code in rpc/net.cpp.
"""
-import time
-
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
@@ -62,12 +60,8 @@ class NetTest(BitcoinTestFramework):
self.nodes[0].setnetworkactive(False)
assert_equal(self.nodes[0].getnetworkinfo()['networkactive'], False)
- timeout = 3
- while self.nodes[0].getnetworkinfo()['connections'] != 0:
- # Wait a bit for all sockets to close
- assert timeout > 0, 'not all connections closed in time'
- timeout -= 0.1
- time.sleep(0.1)
+ # Wait a bit for all sockets to close
+ wait_until(lambda: self.nodes[0].getnetworkinfo()['connections'] == 0, timeout=3)
self.nodes[0].setnetworkactive(True)
connect_nodes_bi(self.nodes, 0, 1)
diff --git a/test/functional/test_framework/comptool.py b/test/functional/test_framework/comptool.py
index 61ea2280e2..e0ca78e5d1 100755
--- a/test/functional/test_framework/comptool.py
+++ b/test/functional/test_framework/comptool.py
@@ -8,7 +8,7 @@ To use, create a class that implements get_tests(), and pass it in
as the test generator to TestManager. get_tests() should be a python
generator that returns TestInstance objects. See below for definition.
-TestNode behaves as follows:
+TestP2PConn behaves as follows:
Configure with a BlockStore and TxStore
on_inv: log the message but don't request
on_headers: log the chain tip
@@ -39,7 +39,7 @@ class RejectResult():
def __repr__(self):
return '%i:%s' % (self.code,self.reason or '*')
-class TestNode(P2PInterface):
+class TestP2PConn(P2PInterface):
def __init__(self, block_store, tx_store):
super().__init__()
@@ -170,7 +170,7 @@ class TestManager():
def add_all_connections(self, nodes):
for i in range(len(nodes)):
# Create a p2p connection to each node
- node = TestNode(self.block_store, self.tx_store)
+ node = TestP2PConn(self.block_store, self.tx_store)
node.peer_connect('127.0.0.1', p2p_port(i))
self.p2p_connections.append(node)
diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py
index 7be695550b..68ac97d755 100644
--- a/test/functional/test_framework/util.py
+++ b/test/functional/test_framework/util.py
@@ -340,20 +340,15 @@ def disconnect_nodes(from_connection, node_num):
for peer_id in [peer['id'] for peer in from_connection.getpeerinfo() if "testnode%d" % node_num in peer['subver']]:
from_connection.disconnectnode(nodeid=peer_id)
- for _ in range(50):
- if [peer['id'] for peer in from_connection.getpeerinfo() if "testnode%d" % node_num in peer['subver']] == []:
- break
- time.sleep(0.1)
- else:
- raise AssertionError("timed out waiting for disconnect")
+ # wait to disconnect
+ wait_until(lambda: [peer['id'] for peer in from_connection.getpeerinfo() if "testnode%d" % node_num in peer['subver']] == [], timeout=5)
def connect_nodes(from_connection, node_num):
ip_port = "127.0.0.1:" + str(p2p_port(node_num))
from_connection.addnode(ip_port, "onetry")
# poll until version handshake complete to avoid race conditions
# with transaction relaying
- while any(peer['version'] == 0 for peer in from_connection.getpeerinfo()):
- time.sleep(0.1)
+ wait_until(lambda: all(peer['version'] != 0 for peer in from_connection.getpeerinfo()))
def connect_nodes_bi(nodes, a, b):
connect_nodes(nodes[a], b)
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index 673cdb5066..09f7f50de0 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -433,7 +433,7 @@ class TestHandler:
proc.send_signal(signal.SIGINT)
if proc.poll() is not None:
log_out.seek(0), log_err.seek(0)
- [stdout, stderr] = [file.read().decode('utf-8') for file in (log_out, log_err)]
+ [stdout, stderr] = [log_file.read().decode('utf-8') for log_file in (log_out, log_err)]
log_out.close(), log_err.close()
if proc.returncode == TEST_EXIT_PASSED and stderr == "":
status = "Passed"
@@ -490,7 +490,7 @@ def check_script_list(src_dir):
Check that there are no scripts in the functional tests directory which are
not being run by pull-tester.py."""
script_dir = src_dir + '/test/functional/'
- python_files = set([file for file in os.listdir(script_dir) if file.endswith(".py")])
+ python_files = set([test_file for test_file in os.listdir(script_dir) if test_file.endswith(".py")])
missed_tests = list(python_files - set(map(lambda x: x.split()[0], ALL_SCRIPTS + NON_SCRIPTS)))
if len(missed_tests) != 0:
print("%sWARNING!%s The following scripts are not being run: %s. Check the test lists in test_runner.py." % (BOLD[1], BOLD[0], str(missed_tests)))
@@ -550,8 +550,8 @@ class RPCCoverage():
if not os.path.isfile(coverage_ref_filename):
raise RuntimeError("No coverage reference found")
- with open(coverage_ref_filename, 'r') as file:
- all_cmds.update([line.strip() for line in file.readlines()])
+ with open(coverage_ref_filename, 'r') as coverage_ref_file:
+ all_cmds.update([line.strip() for line in coverage_ref_file.readlines()])
for root, dirs, files in os.walk(self.dir):
for filename in files:
@@ -559,8 +559,8 @@ class RPCCoverage():
coverage_filenames.add(os.path.join(root, filename))
for filename in coverage_filenames:
- with open(filename, 'r') as file:
- covered_cmds.update([line.strip() for line in file.readlines()])
+ with open(filename, 'r') as coverage_file:
+ covered_cmds.update([line.strip() for line in coverage_file.readlines()])
return all_cmds - covered_cmds
diff --git a/test/functional/wallet_basic.py b/test/functional/wallet_basic.py
index 934b9444a0..0436aca6a4 100755
--- a/test/functional/wallet_basic.py
+++ b/test/functional/wallet_basic.py
@@ -379,9 +379,9 @@ class WalletTest(BitcoinTestFramework):
self.start_node(0, [m, "-limitancestorcount="+str(chainlimit)])
self.start_node(1, [m, "-limitancestorcount="+str(chainlimit)])
self.start_node(2, [m, "-limitancestorcount="+str(chainlimit)])
- while m == '-reindex' and [block_count] * 3 != [self.nodes[i].getblockcount() for i in range(3)]:
+ if m == '-reindex':
# reindex will leave rpc warm up "early"; Wait for it to finish
- time.sleep(0.1)
+ wait_until(lambda: [block_count] * 3 == [self.nodes[i].getblockcount() for i in range(3)])
assert_equal(balance_nodes, [self.nodes[i].getbalance() for i in range(3)])
# Exercise listsinceblock with the last two blocks