aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac10
-rw-r--r--contrib/guix/README.md7
-rwxr-xr-xcontrib/guix/guix-build.sh7
-rw-r--r--contrib/guix/libexec/build.sh11
-rw-r--r--doc/external-signer.md2
-rw-r--r--src/Makefile.am1
-rw-r--r--src/qt/bitcoingui.cpp3
-rw-r--r--src/qt/forms/debugwindow.ui90
-rw-r--r--src/qt/receivecoinsdialog.cpp17
-rw-r--r--src/qt/receivecoinsdialog.h3
-rw-r--r--src/qt/rpcconsole.cpp9
-rw-r--r--src/qt/rpcconsole.h5
-rw-r--r--src/qt/transactionview.cpp49
-rw-r--r--src/qt/transactionview.h1
-rw-r--r--src/test/fuzz/addrman.cpp2
-rw-r--r--src/test/fuzz/autofile.cpp2
-rw-r--r--src/test/fuzz/banman.cpp4
-rw-r--r--src/test/fuzz/bloom_filter.cpp2
-rw-r--r--src/test/fuzz/buffered_file.cpp2
-rw-r--r--src/test/fuzz/coins_view.cpp4
-rw-r--r--src/test/fuzz/connman.cpp4
-rw-r--r--src/test/fuzz/crypto.cpp2
-rw-r--r--src/test/fuzz/crypto_chacha20.cpp2
-rw-r--r--src/test/fuzz/crypto_chacha20_poly1305_aead.cpp2
-rw-r--r--src/test/fuzz/data_stream.cpp4
-rw-r--r--src/test/fuzz/deserialize.cpp2
-rw-r--r--src/test/fuzz/fuzz.cpp6
-rw-r--r--src/test/fuzz/fuzz.h2
-rw-r--r--src/test/fuzz/kitchen_sink.cpp2
-rw-r--r--src/test/fuzz/load_external_block_file.cpp4
-rw-r--r--src/test/fuzz/merkleblock.cpp2
-rw-r--r--src/test/fuzz/muhash.cpp2
-rw-r--r--src/test/fuzz/net.cpp4
-rw-r--r--src/test/fuzz/netaddress.cpp2
-rw-r--r--src/test/fuzz/policy_estimator.cpp4
-rw-r--r--src/test/fuzz/policy_estimator_io.cpp4
-rw-r--r--src/test/fuzz/pow.cpp2
-rw-r--r--src/test/fuzz/process_message.cpp4
-rw-r--r--src/test/fuzz/process_messages.cpp4
-rw-r--r--src/test/fuzz/rolling_bloom_filter.cpp2
-rw-r--r--src/test/fuzz/script.cpp2
-rw-r--r--src/test/fuzz/script_assets_test_minimizer.cpp2
-rw-r--r--src/test/fuzz/script_ops.cpp2
-rw-r--r--src/test/fuzz/scriptnum_ops.cpp2
-rw-r--r--src/test/fuzz/signet.cpp4
-rw-r--r--src/test/fuzz/string.cpp2
-rw-r--r--src/test/fuzz/strprintf.cpp2
-rw-r--r--src/test/fuzz/system.cpp2
-rw-r--r--src/test/fuzz/util.h4
-rw-r--r--src/test/transaction_tests.cpp2
-rw-r--r--src/txmempool.cpp23
-rw-r--r--src/txmempool.h55
-rw-r--r--src/util/epochguard.h91
-rw-r--r--src/wallet/init.cpp2
-rw-r--r--src/wallet/rpcdump.cpp8
-rwxr-xr-xtest/functional/feature_blockfilterindex_prune.py55
-rwxr-xr-xtest/functional/feature_config_args.py51
-rwxr-xr-xtest/functional/rpc_blockchain.py13
-rwxr-xr-xtest/functional/test_framework/test_framework.py8
-rw-r--r--test/functional/test_framework/util.py1
-rw-r--r--test/functional/test_framework/wallet.py9
-rwxr-xr-xtest/functional/wallet_listdescriptors.py16
-rwxr-xr-xtest/functional/wallet_txn_clone.py7
-rwxr-xr-xtest/functional/wallet_txn_doublespend.py7
64 files changed, 451 insertions, 210 deletions
diff --git a/configure.ac b/configure.ac
index 239fe13e41..c4ad5fae59 100644
--- a/configure.ac
+++ b/configure.ac
@@ -863,7 +863,7 @@ if test x$use_hardening != xno; then
dnl -fcf-protection used with Clang 7 causes ld to emit warnings:
dnl ld: error: ... <corrupt x86 feature size: 0x8>
- dnl Use CHECK_LINK_FLAG & --fatal-warnings to ensure we wont use the flag in this case.
+ dnl Use CHECK_LINK_FLAG & --fatal-warnings to ensure we won't use the flag in this case.
AX_CHECK_LINK_FLAG([-fcf-protection=full],[HARDENED_CXXFLAGS="$HARDENED_CXXFLAGS -fcf-protection=full"],, [[$LDFLAG_WERROR]])
dnl stack-clash-protection does not work properly when building for Windows.
@@ -1269,7 +1269,7 @@ if test "x$enable_fuzz" = "xyes"; then
[[-fsanitize=$use_sanitizers]],
[AC_MSG_RESULT([no])],
[AC_MSG_RESULT([yes])
- CPPFLAGS="$CPPFLAGS -DPROVIDE_MAIN_FUNCTION"],
+ CPPFLAGS="$CPPFLAGS -DPROVIDE_FUZZ_MAIN_FUNCTION"],
[],
[AC_LANG_PROGRAM([[
#include <cstdint>
@@ -1293,7 +1293,7 @@ else
QT_TEST_INCLUDES=SUPPRESS_WARNINGS($QT_TEST_INCLUDES)
fi
- CPPFLAGS="$CPPFLAGS -DPROVIDE_MAIN_FUNCTION"
+ CPPFLAGS="$CPPFLAGS -DPROVIDE_FUZZ_MAIN_FUNCTION"
fi
if test x$enable_wallet != xno; then
@@ -1902,9 +1902,9 @@ if test "x$enable_wallet" != "xno"; then
echo " with sqlite = $use_sqlite"
echo " with bdb = $use_bdb"
fi
-echo " with gui / qt = $bitcoin_enable_qt"
+echo " with gui / qt = $bitcoin_enable_qt"
if test x$bitcoin_enable_qt != xno; then
- echo " with qr = $use_qr"
+ echo " with qr = $use_qr"
fi
echo " with zmq = $use_zmq"
if test x$enable_fuzz == xno; then
diff --git a/contrib/guix/README.md b/contrib/guix/README.md
index e218ba89a0..e3573b6fe3 100644
--- a/contrib/guix/README.md
+++ b/contrib/guix/README.md
@@ -118,6 +118,13 @@ find output/ -type f -print0 | sort -z | xargs -r0 sha256sum
depends tree. Setting this to the same directory across multiple builds of the
depends tree can eliminate unnecessary building of packages.
+* _**SDK_PATH**_
+
+ Set the path where _extracted_ SDKs can be found. This is passed through to
+ the depends tree. Note that this is should be set to the _parent_ directory of
+ the actual SDK (e.g. SDK_PATH=$HOME/Downloads/macOS-SDKs instead of
+ $HOME/Downloads/macOS-SDKs/Xcode-11.3.1-11C505-extracted-SDK-with-libcxx-headers).
+
* _**MAX_JOBS**_
Override the maximum number of jobs to run simultaneously, you might want to
diff --git a/contrib/guix/guix-build.sh b/contrib/guix/guix-build.sh
index 7af132b240..333e18d4ed 100755
--- a/contrib/guix/guix-build.sh
+++ b/contrib/guix/guix-build.sh
@@ -196,10 +196,11 @@ and untracked files and directories will be wiped, allowing you to start anew.
EOF
}
-# Create SOURCES_PATH and BASE_CACHE if they are non-empty so that we can map
-# them into the container
+# Create SOURCES_PATH, BASE_CACHE, and SDK_PATH if they are non-empty so that we
+# can map them into the container
[ -z "$SOURCES_PATH" ] || mkdir -p "$SOURCES_PATH"
[ -z "$BASE_CACHE" ] || mkdir -p "$BASE_CACHE"
+[ -z "$SDK_PATH" ] || mkdir -p "$SDK_PATH"
# Deterministically build Bitcoin Core
# shellcheck disable=SC2153
@@ -302,6 +303,7 @@ EOF
--expose="$(git rev-parse --git-common-dir)" \
${SOURCES_PATH:+--share="$SOURCES_PATH"} \
${BASE_CACHE:+--share="$BASE_CACHE"} \
+ ${SDK_PATH:+--share="$SDK_PATH"} \
--max-jobs="$MAX_JOBS" \
--keep-failed \
${SUBSTITUTE_URLS:+--substitute-urls="$SUBSTITUTE_URLS"} \
@@ -312,6 +314,7 @@ EOF
${V:+V=1} \
${SOURCES_PATH:+SOURCES_PATH="$SOURCES_PATH"} \
${BASE_CACHE:+BASE_CACHE="$BASE_CACHE"} \
+ ${SDK_PATH:+SDK_PATH="$SDK_PATH"} \
DISTSRC="$(DISTSRC_BASE=/distsrc-base && distsrc_for_host "$HOST")" \
OUTDIR=/outdir \
bash -c "cd /bitcoin && bash contrib/guix/libexec/build.sh"
diff --git a/contrib/guix/libexec/build.sh b/contrib/guix/libexec/build.sh
index 72588c54a7..1e5463aa9d 100644
--- a/contrib/guix/libexec/build.sh
+++ b/contrib/guix/libexec/build.sh
@@ -3,6 +3,16 @@ export LC_ALL=C
set -e -o pipefail
export TZ=UTC
+# Althought Guix _does_ set umask when building its own packages (in our case,
+# this is all packages in manifest.scm), it does not set it for `guix
+# environment`. It does make sense for at least `guix environment --container`
+# to set umask, so if that change gets merged upstream and we bump the
+# time-machine to a commit which includes the aforementioned change, we can
+# remove this line.
+#
+# This line should be placed before any commands which creates files.
+umask 0022
+
if [ -n "$V" ]; then
# Print both unexpanded (-v) and expanded (-x) forms of commands as they are
# read from this file.
@@ -174,6 +184,7 @@ make -C depends --jobs="$MAX_JOBS" HOST="$HOST" \
${V:+V=1} \
${SOURCES_PATH+SOURCES_PATH="$SOURCES_PATH"} \
${BASE_CACHE+BASE_CACHE="$BASE_CACHE"} \
+ ${SDK_PATH+SDK_PATH="$SDK_PATH"} \
i686_linux_CC=i686-linux-gnu-gcc \
i686_linux_CXX=i686-linux-gnu-g++ \
i686_linux_AR=i686-linux-gnu-ar \
diff --git a/doc/external-signer.md b/doc/external-signer.md
index 053752ee2f..c91ea9bab7 100644
--- a/doc/external-signer.md
+++ b/doc/external-signer.md
@@ -168,4 +168,4 @@ It then imports descriptors for all support address types, in a BIP44/49/84 comp
The `displayaddress` RPC reuses some code from `getaddressinfo` on the provided address and obtains the inferred descriptor. It then calls `<cmd> --fingerprint=00000000 displayaddress --desc=<descriptor>`.
-`sendtoaddress` and `sendmany` check `inputs->bip32_derivs` to see if any inputs have the same `master_fingerprint` as the signer. If so, it calls `<cmd> --fingerprint=00000000 signtransaction <psbt>`. It waits for the device to return a (partially) signed psbt, tries to finalize it and broadcasts the transation.
+`sendtoaddress` and `sendmany` check `inputs->bip32_derivs` to see if any inputs have the same `master_fingerprint` as the signer. If so, it calls `<cmd> --fingerprint=00000000 signtransaction <psbt>`. It waits for the device to return a (partially) signed psbt, tries to finalize it and broadcasts the transaction.
diff --git a/src/Makefile.am b/src/Makefile.am
index 8a9ef49a34..eae226b1d4 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -231,6 +231,7 @@ BITCOIN_CORE_H = \
util/bip32.h \
util/bytevectorhash.h \
util/check.h \
+ util/epochguard.h \
util/error.h \
util/fees.h \
util/getuniquepath.h \
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index ccc0a6828c..6677c9e3b5 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -88,6 +88,8 @@ BitcoinGUI::BitcoinGUI(interfaces::Node& node, const PlatformStyle *_platformSty
move(QGuiApplication::primaryScreen()->availableGeometry().center() - frameGeometry().center());
}
+ setContextMenuPolicy(Qt::PreventContextMenu);
+
#ifdef ENABLE_WALLET
enableWallet = WalletModel::isWalletEnabled();
#endif // ENABLE_WALLET
@@ -544,7 +546,6 @@ void BitcoinGUI::createToolBars()
{
QToolBar *toolbar = addToolBar(tr("Tabs toolbar"));
appToolBar = toolbar;
- toolbar->setContextMenuPolicy(Qt::PreventContextMenu);
toolbar->setMovable(false);
toolbar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
toolbar->addAction(overviewAction);
diff --git a/src/qt/forms/debugwindow.ui b/src/qt/forms/debugwindow.ui
index 9e828ce0a6..e45cafe48a 100644
--- a/src/qt/forms/debugwindow.ui
+++ b/src/qt/forms/debugwindow.ui
@@ -1079,7 +1079,7 @@
<item row="1" column="0">
<widget class="QLabel" name="peerConnectionTypeLabel">
<property name="toolTip">
- <string>The direction and type of peer connection: %1</string>
+ <string>The direction and type of peer connection: %1</string>
</property>
<property name="text">
<string>Direction/Type</string>
@@ -1342,13 +1342,65 @@
</widget>
</item>
<item row="12" column="0">
+ <widget class="QLabel" name="peerLastBlockLabel">
+ <property name="toolTip">
+ <string>Elapsed time since a novel block passing initial validity checks was received from this peer.</string>
+ </property>
+ <property name="text">
+ <string>Last Block</string>
+ </property>
+ </widget>
+ </item>
+ <item row="12" column="1">
+ <widget class="QLabel" name="peerLastBlock">
+ <property name="cursor">
+ <cursorShape>IBeamCursor</cursorShape>
+ </property>
+ <property name="text">
+ <string>N/A</string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::PlainText</enum>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="13" column="0">
+ <widget class="QLabel" name="peerLastTxLabel">
+ <property name="toolTip">
+ <string>Elapsed time since a novel transaction accepted into our mempool was received from this peer.</string>
+ </property>
+ <property name="text">
+ <string>Last Tx</string>
+ </property>
+ </widget>
+ </item>
+ <item row="13" column="1">
+ <widget class="QLabel" name="peerLastTx">
+ <property name="cursor">
+ <cursorShape>IBeamCursor</cursorShape>
+ </property>
+ <property name="text">
+ <string>N/A</string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::PlainText</enum>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="14" column="0">
<widget class="QLabel" name="label_15">
<property name="text">
<string>Last Send</string>
</property>
</widget>
</item>
- <item row="12" column="1">
+ <item row="14" column="1">
<widget class="QLabel" name="peerLastSend">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -1364,14 +1416,14 @@
</property>
</widget>
</item>
- <item row="13" column="0">
+ <item row="15" column="0">
<widget class="QLabel" name="label_19">
<property name="text">
<string>Last Receive</string>
</property>
</widget>
</item>
- <item row="13" column="1">
+ <item row="15" column="1">
<widget class="QLabel" name="peerLastRecv">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -1387,14 +1439,14 @@
</property>
</widget>
</item>
- <item row="14" column="0">
+ <item row="16" column="0">
<widget class="QLabel" name="label_18">
<property name="text">
<string>Sent</string>
</property>
</widget>
</item>
- <item row="14" column="1">
+ <item row="16" column="1">
<widget class="QLabel" name="peerBytesSent">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -1410,14 +1462,14 @@
</property>
</widget>
</item>
- <item row="15" column="0">
+ <item row="17" column="0">
<widget class="QLabel" name="label_20">
<property name="text">
<string>Received</string>
</property>
</widget>
</item>
- <item row="15" column="1">
+ <item row="17" column="1">
<widget class="QLabel" name="peerBytesRecv">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -1433,14 +1485,14 @@
</property>
</widget>
</item>
- <item row="16" column="0">
+ <item row="18" column="0">
<widget class="QLabel" name="label_26">
<property name="text">
<string>Ping Time</string>
</property>
</widget>
</item>
- <item row="16" column="1">
+ <item row="18" column="1">
<widget class="QLabel" name="peerPingTime">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -1456,7 +1508,7 @@
</property>
</widget>
</item>
- <item row="17" column="0">
+ <item row="19" column="0">
<widget class="QLabel" name="peerPingWaitLabel">
<property name="toolTip">
<string>The duration of a currently outstanding ping.</string>
@@ -1466,7 +1518,7 @@
</property>
</widget>
</item>
- <item row="17" column="1">
+ <item row="19" column="1">
<widget class="QLabel" name="peerPingWait">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -1482,14 +1534,14 @@
</property>
</widget>
</item>
- <item row="18" column="0">
+ <item row="20" column="0">
<widget class="QLabel" name="peerMinPingLabel">
<property name="text">
<string>Min Ping</string>
</property>
</widget>
</item>
- <item row="18" column="1">
+ <item row="20" column="1">
<widget class="QLabel" name="peerMinPing">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -1505,14 +1557,14 @@
</property>
</widget>
</item>
- <item row="19" column="0">
+ <item row="21" column="0">
<widget class="QLabel" name="label_timeoffset">
<property name="text">
<string>Time Offset</string>
</property>
</widget>
</item>
- <item row="19" column="1">
+ <item row="21" column="1">
<widget class="QLabel" name="timeoffset">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -1528,7 +1580,7 @@
</property>
</widget>
</item>
- <item row="20" column="0">
+ <item row="22" column="0">
<widget class="QLabel" name="peerMappedASLabel">
<property name="toolTip">
<string>The mapped Autonomous System used for diversifying peer selection.</string>
@@ -1538,7 +1590,7 @@
</property>
</widget>
</item>
- <item row="20" column="1">
+ <item row="22" column="1">
<widget class="QLabel" name="peerMappedAS">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -1554,7 +1606,7 @@
</property>
</widget>
</item>
- <item row="21" column="0">
+ <item row="23" column="0">
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp
index 62adaa4e9f..0da12c84fd 100644
--- a/src/qt/receivecoinsdialog.cpp
+++ b/src/qt/receivecoinsdialog.cpp
@@ -45,9 +45,9 @@ ReceiveCoinsDialog::ReceiveCoinsDialog(const PlatformStyle *_platformStyle, QWid
// context menu actions
QAction *copyURIAction = new QAction(tr("Copy URI"), this);
QAction* copyAddressAction = new QAction(tr("Copy address"), this);
- QAction *copyLabelAction = new QAction(tr("Copy label"), this);
- QAction *copyMessageAction = new QAction(tr("Copy message"), this);
- QAction *copyAmountAction = new QAction(tr("Copy amount"), this);
+ copyLabelAction = new QAction(tr("Copy label"), this);
+ copyMessageAction = new QAction(tr("Copy message"), this);
+ copyAmountAction = new QAction(tr("Copy amount"), this);
// context menu
contextMenu = new QMenu(this);
@@ -269,9 +269,18 @@ void ReceiveCoinsDialog::copyColumnToClipboard(int column)
// context menu
void ReceiveCoinsDialog::showMenu(const QPoint &point)
{
- if (!selectedRow().isValid()) {
+ const QModelIndex sel = selectedRow();
+ if (!sel.isValid()) {
return;
}
+
+ // disable context menu actions when appropriate
+ const RecentRequestsTableModel* const submodel = model->getRecentRequestsTableModel();
+ const RecentRequestEntry& req = submodel->entry(sel.row());
+ copyLabelAction->setDisabled(req.recipient.label.isEmpty());
+ copyMessageAction->setDisabled(req.recipient.message.isEmpty());
+ copyAmountAction->setDisabled(req.recipient.amount == 0);
+
contextMenu->exec(QCursor::pos());
}
diff --git a/src/qt/receivecoinsdialog.h b/src/qt/receivecoinsdialog.h
index f12cd8ce0c..fbbccc5a33 100644
--- a/src/qt/receivecoinsdialog.h
+++ b/src/qt/receivecoinsdialog.h
@@ -53,6 +53,9 @@ private:
Ui::ReceiveCoinsDialog *ui;
WalletModel *model;
QMenu *contextMenu;
+ QAction* copyLabelAction;
+ QAction* copyMessageAction;
+ QAction* copyAmountAction;
const PlatformStyle *platformStyle;
QModelIndex selectedRow();
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 4a4b557acc..5acf8b1cf0 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -1120,11 +1120,14 @@ void RPCConsole::updateDetailWidget()
if (stats->nodeStats.m_bip152_highbandwidth_from) bip152_hb_settings += (bip152_hb_settings == "" ? "From" : "/From");
if (bip152_hb_settings == "") bip152_hb_settings = "No";
ui->peerHighBandwidth->setText(bip152_hb_settings);
- ui->peerLastSend->setText(stats->nodeStats.nLastSend ? GUIUtil::formatDurationStr(GetSystemTimeInSeconds() - stats->nodeStats.nLastSend) : tr("never"));
- ui->peerLastRecv->setText(stats->nodeStats.nLastRecv ? GUIUtil::formatDurationStr(GetSystemTimeInSeconds() - stats->nodeStats.nLastRecv) : tr("never"));
+ const int64_t time_now{GetSystemTimeInSeconds()};
+ ui->peerConnTime->setText(GUIUtil::formatDurationStr(time_now - stats->nodeStats.nTimeConnected));
+ ui->peerLastBlock->setText(TimeDurationField(time_now, stats->nodeStats.nLastBlockTime));
+ ui->peerLastTx->setText(TimeDurationField(time_now, stats->nodeStats.nLastTXTime));
+ ui->peerLastSend->setText(TimeDurationField(time_now, stats->nodeStats.nLastSend));
+ ui->peerLastRecv->setText(TimeDurationField(time_now, stats->nodeStats.nLastRecv));
ui->peerBytesSent->setText(GUIUtil::formatBytes(stats->nodeStats.nSendBytes));
ui->peerBytesRecv->setText(GUIUtil::formatBytes(stats->nodeStats.nRecvBytes));
- ui->peerConnTime->setText(GUIUtil::formatDurationStr(GetSystemTimeInSeconds() - stats->nodeStats.nTimeConnected));
ui->peerPingTime->setText(GUIUtil::formatPingTime(stats->nodeStats.m_ping_usec));
ui->peerMinPing->setText(GUIUtil::formatPingTime(stats->nodeStats.m_min_ping_usec));
ui->timeoffset->setText(GUIUtil::formatTimeOffset(stats->nodeStats.nTimeOffset));
diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h
index 5f308dc36d..27d4c42eb4 100644
--- a/src/qt/rpcconsole.h
+++ b/src/qt/rpcconsole.h
@@ -168,6 +168,11 @@ private:
/** Update UI with latest network info from model. */
void updateNetworkState();
+ /** Helper for the output of a time duration field. Inputs are UNIX epoch times. */
+ QString TimeDurationField(uint64_t time_now, uint64_t time_at_event) const {
+ return time_at_event ? GUIUtil::formatDurationStr(time_now - time_at_event) : tr("Never");
+ }
+
private Q_SLOTS:
void updateAlerts(const QString& warnings);
};
diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp
index b568f41158..e1ec7b6ed0 100644
--- a/src/qt/transactionview.cpp
+++ b/src/qt/transactionview.cpp
@@ -172,6 +172,7 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa
QAction *copyTxIDAction = new QAction(tr("Copy transaction ID"), this);
QAction *copyTxHexAction = new QAction(tr("Copy raw transaction"), this);
QAction *copyTxPlainText = new QAction(tr("Copy full transaction details"), this);
+ QAction *editLabelAction = new QAction(tr("Edit address label"), this);
QAction *showDetailsAction = new QAction(tr("Show transaction details"), this);
contextMenu = new QMenu(this);
@@ -186,6 +187,7 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa
contextMenu->addSeparator();
contextMenu->addAction(bumpFeeAction);
contextMenu->addAction(abandonAction);
+ contextMenu->addAction(editLabelAction);
connect(dateWidget, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this, &TransactionView::chooseDate);
connect(typeWidget, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this, &TransactionView::chooseType);
@@ -206,6 +208,7 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa
connect(copyTxIDAction, &QAction::triggered, this, &TransactionView::copyTxID);
connect(copyTxHexAction, &QAction::triggered, this, &TransactionView::copyTxHex);
connect(copyTxPlainText, &QAction::triggered, this, &TransactionView::copyTxPlainText);
+ connect(editLabelAction, &QAction::triggered, this, &TransactionView::editLabel);
connect(showDetailsAction, &QAction::triggered, this, &TransactionView::showDetails);
// Double-clicking on a transaction on the transaction history page shows details
connect(this, &TransactionView::doubleClicked, this, &TransactionView::showDetails);
@@ -474,6 +477,52 @@ void TransactionView::copyTxPlainText()
GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::TxPlainTextRole);
}
+void TransactionView::editLabel()
+{
+ if(!transactionView->selectionModel() ||!model)
+ return;
+ QModelIndexList selection = transactionView->selectionModel()->selectedRows();
+ if(!selection.isEmpty())
+ {
+ AddressTableModel *addressBook = model->getAddressTableModel();
+ if(!addressBook)
+ return;
+ QString address = selection.at(0).data(TransactionTableModel::AddressRole).toString();
+ if(address.isEmpty())
+ {
+ // If this transaction has no associated address, exit
+ return;
+ }
+ // Is address in address book? Address book can miss address when a transaction is
+ // sent from outside the UI.
+ int idx = addressBook->lookupAddress(address);
+ if(idx != -1)
+ {
+ // Edit sending / receiving address
+ QModelIndex modelIdx = addressBook->index(idx, 0, QModelIndex());
+ // Determine type of address, launch appropriate editor dialog type
+ QString type = modelIdx.data(AddressTableModel::TypeRole).toString();
+
+ EditAddressDialog dlg(
+ type == AddressTableModel::Receive
+ ? EditAddressDialog::EditReceivingAddress
+ : EditAddressDialog::EditSendingAddress, this);
+ dlg.setModel(addressBook);
+ dlg.loadRow(idx);
+ dlg.exec();
+ }
+ else
+ {
+ // Add sending address
+ EditAddressDialog dlg(EditAddressDialog::NewSendingAddress,
+ this);
+ dlg.setModel(addressBook);
+ dlg.setAddress(address);
+ dlg.exec();
+ }
+ }
+}
+
void TransactionView::showDetails()
{
if(!transactionView->selectionModel())
diff --git a/src/qt/transactionview.h b/src/qt/transactionview.h
index cd40813461..35ada4aa7a 100644
--- a/src/qt/transactionview.h
+++ b/src/qt/transactionview.h
@@ -90,6 +90,7 @@ private Q_SLOTS:
void dateRangeChanged();
void showDetails();
void copyAddress();
+ void editLabel();
void copyLabel();
void copyAmount();
void copyTxID();
diff --git a/src/test/fuzz/addrman.cpp b/src/test/fuzz/addrman.cpp
index 1ea6b3d01d..b55f1c72b1 100644
--- a/src/test/fuzz/addrman.cpp
+++ b/src/test/fuzz/addrman.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 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/test/fuzz/autofile.cpp b/src/test/fuzz/autofile.cpp
index 9ecd172e19..dbc0b5ab81 100644
--- a/src/test/fuzz/autofile.cpp
+++ b/src/test/fuzz/autofile.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 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/test/fuzz/banman.cpp b/src/test/fuzz/banman.cpp
index e0715f3e29..124439559e 100644
--- a/src/test/fuzz/banman.cpp
+++ b/src/test/fuzz/banman.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -26,7 +26,7 @@ int64_t ConsumeBanTimeOffset(FuzzedDataProvider& fuzzed_data_provider) noexcept
void initialize_banman()
{
- static const auto testing_setup = MakeFuzzingContext<>();
+ static const auto testing_setup = MakeNoLogFileContext<>();
}
FUZZ_TARGET_INIT(banman, initialize_banman)
diff --git a/src/test/fuzz/bloom_filter.cpp b/src/test/fuzz/bloom_filter.cpp
index d43c182644..c5bb8744a4 100644
--- a/src/test/fuzz/bloom_filter.cpp
+++ b/src/test/fuzz/bloom_filter.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 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/test/fuzz/buffered_file.cpp b/src/test/fuzz/buffered_file.cpp
index 3a1b2dbbe7..ffe38f10fc 100644
--- a/src/test/fuzz/buffered_file.cpp
+++ b/src/test/fuzz/buffered_file.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 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/test/fuzz/coins_view.cpp b/src/test/fuzz/coins_view.cpp
index 8ece94d771..19486365f6 100644
--- a/src/test/fuzz/coins_view.cpp
+++ b/src/test/fuzz/coins_view.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -36,7 +36,7 @@ bool operator==(const Coin& a, const Coin& b)
void initialize_coins_view()
{
- static const auto testing_setup = MakeFuzzingContext<const TestingSetup>();
+ static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>();
}
FUZZ_TARGET_INIT(coins_view, initialize_coins_view)
diff --git a/src/test/fuzz/connman.cpp b/src/test/fuzz/connman.cpp
index 71b4b00116..3fb8d8ca06 100644
--- a/src/test/fuzz/connman.cpp
+++ b/src/test/fuzz/connman.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -17,7 +17,7 @@
void initialize_connman()
{
- static const auto testing_setup = MakeFuzzingContext<>();
+ static const auto testing_setup = MakeNoLogFileContext<>();
}
FUZZ_TARGET_INIT(connman, initialize_connman)
diff --git a/src/test/fuzz/crypto.cpp b/src/test/fuzz/crypto.cpp
index 17ac48fca7..eeeac18968 100644
--- a/src/test/fuzz/crypto.cpp
+++ b/src/test/fuzz/crypto.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 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/test/fuzz/crypto_chacha20.cpp b/src/test/fuzz/crypto_chacha20.cpp
index bb8dd4594f..8adfa92420 100644
--- a/src/test/fuzz/crypto_chacha20.cpp
+++ b/src/test/fuzz/crypto_chacha20.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 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/test/fuzz/crypto_chacha20_poly1305_aead.cpp b/src/test/fuzz/crypto_chacha20_poly1305_aead.cpp
index 0e1c44cded..bb4ef22158 100644
--- a/src/test/fuzz/crypto_chacha20_poly1305_aead.cpp
+++ b/src/test/fuzz/crypto_chacha20_poly1305_aead.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 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/test/fuzz/data_stream.cpp b/src/test/fuzz/data_stream.cpp
index f3b6e6af04..d6ef0c6691 100644
--- a/src/test/fuzz/data_stream.cpp
+++ b/src/test/fuzz/data_stream.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -13,7 +13,7 @@
void initialize_data_stream_addr_man()
{
- static const auto testing_setup = MakeFuzzingContext<>();
+ static const auto testing_setup = MakeNoLogFileContext<>();
}
FUZZ_TARGET_INIT(data_stream_addr_man, initialize_data_stream_addr_man)
diff --git a/src/test/fuzz/deserialize.cpp b/src/test/fuzz/deserialize.cpp
index ba5f0c1a75..64c6e49615 100644
--- a/src/test/fuzz/deserialize.cpp
+++ b/src/test/fuzz/deserialize.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2020 The Bitcoin Core developers
+// Copyright (c) 2009-2021 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/test/fuzz/fuzz.cpp b/src/test/fuzz/fuzz.cpp
index edb270d437..1fab46ff13 100644
--- a/src/test/fuzz/fuzz.cpp
+++ b/src/test/fuzz/fuzz.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2020 The Bitcoin Core developers
+// Copyright (c) 2009-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -44,7 +44,7 @@ void initialize()
std::get<1>(it->second)();
}
-#if defined(PROVIDE_MAIN_FUNCTION)
+#if defined(PROVIDE_FUZZ_MAIN_FUNCTION)
static bool read_stdin(std::vector<uint8_t>& data)
{
uint8_t buffer[1024];
@@ -71,7 +71,7 @@ extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv)
return 0;
}
-#if defined(PROVIDE_MAIN_FUNCTION)
+#if defined(PROVIDE_FUZZ_MAIN_FUNCTION)
int main(int argc, char** argv)
{
initialize();
diff --git a/src/test/fuzz/fuzz.h b/src/test/fuzz/fuzz.h
index 4abc52c15a..2bad77bdc1 100644
--- a/src/test/fuzz/fuzz.h
+++ b/src/test/fuzz/fuzz.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2020 The Bitcoin Core developers
+// Copyright (c) 2009-2021 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/test/fuzz/kitchen_sink.cpp b/src/test/fuzz/kitchen_sink.cpp
index fa4024fc38..908e9a1c83 100644
--- a/src/test/fuzz/kitchen_sink.cpp
+++ b/src/test/fuzz/kitchen_sink.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 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/test/fuzz/load_external_block_file.cpp b/src/test/fuzz/load_external_block_file.cpp
index 95597bf082..dbd0c76d42 100644
--- a/src/test/fuzz/load_external_block_file.cpp
+++ b/src/test/fuzz/load_external_block_file.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -15,7 +15,7 @@
void initialize_load_external_block_file()
{
- static const auto testing_setup = MakeFuzzingContext<const TestingSetup>();
+ static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>();
}
FUZZ_TARGET_INIT(load_external_block_file, initialize_load_external_block_file)
diff --git a/src/test/fuzz/merkleblock.cpp b/src/test/fuzz/merkleblock.cpp
index 23e0baa564..1eefd4c521 100644
--- a/src/test/fuzz/merkleblock.cpp
+++ b/src/test/fuzz/merkleblock.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 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/test/fuzz/muhash.cpp b/src/test/fuzz/muhash.cpp
index 2d761cef15..4ea9511870 100644
--- a/src/test/fuzz/muhash.cpp
+++ b/src/test/fuzz/muhash.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 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/test/fuzz/net.cpp b/src/test/fuzz/net.cpp
index 21dca4eb05..b056f46f2e 100644
--- a/src/test/fuzz/net.cpp
+++ b/src/test/fuzz/net.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -22,7 +22,7 @@
void initialize_net()
{
- static const auto testing_setup = MakeFuzzingContext<>(CBaseChainParams::MAIN);
+ static const auto testing_setup = MakeNoLogFileContext<>(CBaseChainParams::MAIN);
}
FUZZ_TARGET_INIT(net, initialize_net)
diff --git a/src/test/fuzz/netaddress.cpp b/src/test/fuzz/netaddress.cpp
index a42080eb66..f9d8129ca9 100644
--- a/src/test/fuzz/netaddress.cpp
+++ b/src/test/fuzz/netaddress.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 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/test/fuzz/policy_estimator.cpp b/src/test/fuzz/policy_estimator.cpp
index fff893fb3f..311550f041 100644
--- a/src/test/fuzz/policy_estimator.cpp
+++ b/src/test/fuzz/policy_estimator.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -16,7 +16,7 @@
void initialize_policy_estimator()
{
- static const auto testing_setup = MakeFuzzingContext<>();
+ static const auto testing_setup = MakeNoLogFileContext<>();
}
FUZZ_TARGET_INIT(policy_estimator, initialize_policy_estimator)
diff --git a/src/test/fuzz/policy_estimator_io.cpp b/src/test/fuzz/policy_estimator_io.cpp
index 73242870a0..c24ad3d49a 100644
--- a/src/test/fuzz/policy_estimator_io.cpp
+++ b/src/test/fuzz/policy_estimator_io.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -12,7 +12,7 @@
void initialize_policy_estimator_io()
{
- static const auto testing_setup = MakeFuzzingContext<>();
+ static const auto testing_setup = MakeNoLogFileContext<>();
}
FUZZ_TARGET_INIT(policy_estimator_io, initialize_policy_estimator_io)
diff --git a/src/test/fuzz/pow.cpp b/src/test/fuzz/pow.cpp
index c4348495bf..53726ca893 100644
--- a/src/test/fuzz/pow.cpp
+++ b/src/test/fuzz/pow.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 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/test/fuzz/process_message.cpp b/src/test/fuzz/process_message.cpp
index 442e32d4ca..e3571e15b7 100644
--- a/src/test/fuzz/process_message.cpp
+++ b/src/test/fuzz/process_message.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -56,7 +56,7 @@ void initialize_process_message()
{
Assert(GetNumMsgTypes() == getAllNetMessageTypes().size()); // If this fails, add or remove the message type below
- static const auto testing_setup = MakeFuzzingContext<const TestingSetup>();
+ static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>();
g_setup = testing_setup.get();
for (int i = 0; i < 2 * COINBASE_MATURITY; i++) {
MineBlock(g_setup->m_node, CScript() << OP_TRUE);
diff --git a/src/test/fuzz/process_messages.cpp b/src/test/fuzz/process_messages.cpp
index ef45196671..f62a0c64ed 100644
--- a/src/test/fuzz/process_messages.cpp
+++ b/src/test/fuzz/process_messages.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -23,7 +23,7 @@ const TestingSetup* g_setup;
void initialize_process_messages()
{
- static const auto testing_setup = MakeFuzzingContext<const TestingSetup>();
+ static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>();
g_setup = testing_setup.get();
for (int i = 0; i < 2 * COINBASE_MATURITY; i++) {
MineBlock(g_setup->m_node, CScript() << OP_TRUE);
diff --git a/src/test/fuzz/rolling_bloom_filter.cpp b/src/test/fuzz/rolling_bloom_filter.cpp
index 2a08b45aa3..07059cce76 100644
--- a/src/test/fuzz/rolling_bloom_filter.cpp
+++ b/src/test/fuzz/rolling_bloom_filter.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 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/test/fuzz/script.cpp b/src/test/fuzz/script.cpp
index 7fadf36f98..193862e847 100644
--- a/src/test/fuzz/script.cpp
+++ b/src/test/fuzz/script.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019-2020 The Bitcoin Core developers
+// Copyright (c) 2019-2021 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/test/fuzz/script_assets_test_minimizer.cpp b/src/test/fuzz/script_assets_test_minimizer.cpp
index 8d9a939dab..5f07acbcc7 100644
--- a/src/test/fuzz/script_assets_test_minimizer.cpp
+++ b/src/test/fuzz/script_assets_test_minimizer.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 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/test/fuzz/script_ops.cpp b/src/test/fuzz/script_ops.cpp
index bdbfe817ff..eb1c808a88 100644
--- a/src/test/fuzz/script_ops.cpp
+++ b/src/test/fuzz/script_ops.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 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/test/fuzz/scriptnum_ops.cpp b/src/test/fuzz/scriptnum_ops.cpp
index bc4867839c..62ed50d13f 100644
--- a/src/test/fuzz/scriptnum_ops.cpp
+++ b/src/test/fuzz/scriptnum_ops.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 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/test/fuzz/signet.cpp b/src/test/fuzz/signet.cpp
index 83effec064..0d1999731f 100644
--- a/src/test/fuzz/signet.cpp
+++ b/src/test/fuzz/signet.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -17,7 +17,7 @@
void initialize_signet()
{
- static const auto testing_setup = MakeFuzzingContext<>(CBaseChainParams::SIGNET);
+ static const auto testing_setup = MakeNoLogFileContext<>(CBaseChainParams::SIGNET);
}
FUZZ_TARGET_INIT(signet, initialize_signet)
diff --git a/src/test/fuzz/string.cpp b/src/test/fuzz/string.cpp
index ec8a3b23db..93b4948a2f 100644
--- a/src/test/fuzz/string.cpp
+++ b/src/test/fuzz/string.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 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/test/fuzz/strprintf.cpp b/src/test/fuzz/strprintf.cpp
index b66a7abfb3..2c92b159a5 100644
--- a/src/test/fuzz/strprintf.cpp
+++ b/src/test/fuzz/strprintf.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 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/test/fuzz/system.cpp b/src/test/fuzz/system.cpp
index 3621702e45..d9571209fa 100644
--- a/src/test/fuzz/system.cpp
+++ b/src/test/fuzz/system.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 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/test/fuzz/util.h b/src/test/fuzz/util.h
index 7a2dcfe84a..f3bc3c78ab 100644
--- a/src/test/fuzz/util.h
+++ b/src/test/fuzz/util.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2020 The Bitcoin Core developers
+// Copyright (c) 2009-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -325,7 +325,7 @@ inline std::unique_ptr<CNode> ConsumeNodeAsUniquePtr(FuzzedDataProvider& fdp, co
void FillNode(FuzzedDataProvider& fuzzed_data_provider, CNode& node, bool init_version) noexcept;
template <class T = const BasicTestingSetup>
-std::unique_ptr<T> MakeFuzzingContext(const std::string& chain_name = CBaseChainParams::REGTEST, const std::vector<const char*>& extra_args = {})
+std::unique_ptr<T> MakeNoLogFileContext(const std::string& chain_name = CBaseChainParams::REGTEST, const std::vector<const char*>& extra_args = {})
{
// Prepend default arguments for fuzzing
const std::vector<const char*> arguments = Cat(
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index d1770f750f..8f1d99b199 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -63,7 +63,7 @@ static std::map<std::string, unsigned int> mapFlagNames = {
unsigned int ParseScriptFlags(std::string strFlags)
{
- if (strFlags.empty() | strFlags == "NONE") return 0;
+ if (strFlags.empty() || strFlags == "NONE") return 0;
unsigned int flags = 0;
std::vector<std::string> words;
boost::algorithm::split(words, strFlags, boost::algorithm::is_any_of(","));
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index 899835019a..48424a75d0 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -23,7 +23,7 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTransactionRef& _tx, const CAmount& _nFe
int64_t _nTime, unsigned int _entryHeight,
bool _spendsCoinbase, int64_t _sigOpsCost, LockPoints lp)
: tx(_tx), nFee(_nFee), nTxWeight(GetTransactionWeight(*tx)), nUsageSize(RecursiveDynamicUsage(tx)), nTime(_nTime), entryHeight(_entryHeight),
- spendsCoinbase(_spendsCoinbase), sigOpCost(_sigOpsCost), lockPoints(lp), m_epoch(0)
+ spendsCoinbase(_spendsCoinbase), sigOpCost(_sigOpsCost), lockPoints(lp)
{
nCountWithDescendants = 1;
nSizeWithDescendants = GetTxSize();
@@ -132,7 +132,7 @@ void CTxMemPool::UpdateTransactionsFromBlock(const std::vector<uint256> &vHashes
// include them, and update their CTxMemPoolEntry::m_parents to include this tx.
// we cache the in-mempool children to avoid duplicate updates
{
- const auto epoch = GetFreshEpoch();
+ WITH_FRESH_EPOCH(m_epoch);
for (; iter != mapNextTx.end() && iter->first->hash == hash; ++iter) {
const uint256 &childHash = iter->second->GetHash();
txiter childIter = mapTx.find(childHash);
@@ -1119,22 +1119,3 @@ void CTxMemPool::SetIsLoaded(bool loaded)
LOCK(cs);
m_is_loaded = loaded;
}
-
-
-CTxMemPool::EpochGuard CTxMemPool::GetFreshEpoch() const
-{
- return EpochGuard(*this);
-}
-CTxMemPool::EpochGuard::EpochGuard(const CTxMemPool& in) : pool(in)
-{
- assert(!pool.m_has_epoch_guard);
- ++pool.m_epoch;
- pool.m_has_epoch_guard = true;
-}
-
-CTxMemPool::EpochGuard::~EpochGuard()
-{
- // prevents stale results being used
- ++pool.m_epoch;
- pool.m_has_epoch_guard = false;
-}
diff --git a/src/txmempool.h b/src/txmempool.h
index b8de326737..143048b205 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -21,6 +21,7 @@
#include <primitives/transaction.h>
#include <random.h>
#include <sync.h>
+#include <util/epochguard.h>
#include <util/hasher.h>
#include <boost/multi_index_container.hpp>
@@ -64,6 +65,7 @@ struct CompareIteratorByHash {
return a->GetTx().GetHash() < b->GetTx().GetHash();
}
};
+
/** \class CTxMemPoolEntry
*
* CTxMemPoolEntry stores data about the corresponding transaction, as well
@@ -156,7 +158,7 @@ public:
Children& GetMemPoolChildren() const { return m_children; }
mutable size_t vTxHashesIdx; //!< Index in mempool's vTxHashes
- mutable uint64_t m_epoch; //!< epoch when last touched, useful for graph algorithms
+ mutable Epoch::Marker m_epoch_marker; //!< epoch when last touched, useful for graph algorithms
};
// Helpers for modifying CTxMemPool::mapTx, which is a boost multi_index.
@@ -486,8 +488,7 @@ private:
mutable int64_t lastRollingFeeUpdate;
mutable bool blockSinceLastRollingFeeBump;
mutable double rollingMinimumFeeRate; //!< minimum fee to get into the pool, decreases exponentially
- mutable uint64_t m_epoch{0};
- mutable bool m_has_epoch_guard{false};
+ mutable Epoch m_epoch GUARDED_BY(cs);
// In-memory counter for external mempool tracking purposes.
// This number is incremented once every time a transaction
@@ -666,7 +667,7 @@ public:
* for). Note: vHashesToUpdate should be the set of transactions from the
* disconnected block that have been accepted back into the mempool.
*/
- void UpdateTransactionsFromBlock(const std::vector<uint256>& vHashesToUpdate) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main);
+ void UpdateTransactionsFromBlock(const std::vector<uint256>& vHashesToUpdate) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main) LOCKS_EXCLUDED(m_epoch);
/** Try to calculate all in-mempool ancestors of entry.
* (these are all calculated including the tx itself)
@@ -827,52 +828,22 @@ private:
*/
void removeUnchecked(txiter entry, MemPoolRemovalReason reason) EXCLUSIVE_LOCKS_REQUIRED(cs);
public:
- /** EpochGuard: RAII-style guard for using epoch-based graph traversal algorithms.
- * When walking ancestors or descendants, we generally want to avoid
- * visiting the same transactions twice. Some traversal algorithms use
- * std::set (or setEntries) to deduplicate the transaction we visit.
- * However, use of std::set is algorithmically undesirable because it both
- * adds an asymptotic factor of O(log n) to traverals cost and triggers O(n)
- * more dynamic memory allocations.
- * In many algorithms we can replace std::set with an internal mempool
- * counter to track the time (or, "epoch") that we began a traversal, and
- * check + update a per-transaction epoch for each transaction we look at to
- * determine if that transaction has not yet been visited during the current
- * traversal's epoch.
- * Algorithms using std::set can be replaced on a one by one basis.
- * Both techniques are not fundamentally incompatible across the codebase.
- * Generally speaking, however, the remaining use of std::set for mempool
- * traversal should be viewed as a TODO for replacement with an epoch based
- * traversal, rather than a preference for std::set over epochs in that
- * algorithm.
- */
- class EpochGuard {
- const CTxMemPool& pool;
- public:
- explicit EpochGuard(const CTxMemPool& in);
- ~EpochGuard();
- };
- // N.B. GetFreshEpoch modifies mutable state via the EpochGuard construction
- // (and later destruction)
- EpochGuard GetFreshEpoch() const EXCLUSIVE_LOCKS_REQUIRED(cs);
-
/** visited marks a CTxMemPoolEntry as having been traversed
- * during the lifetime of the most recently created EpochGuard
+ * during the lifetime of the most recently created Epoch::Guard
* and returns false if we are the first visitor, true otherwise.
*
- * An EpochGuard must be held when visited is called or an assert will be
+ * An Epoch::Guard must be held when visited is called or an assert will be
* triggered.
*
*/
- bool visited(txiter it) const EXCLUSIVE_LOCKS_REQUIRED(cs) {
- assert(m_has_epoch_guard);
- bool ret = it->m_epoch >= m_epoch;
- it->m_epoch = std::max(it->m_epoch, m_epoch);
- return ret;
+ bool visited(const txiter it) const EXCLUSIVE_LOCKS_REQUIRED(cs, m_epoch)
+ {
+ return m_epoch.visited(it->m_epoch_marker);
}
- bool visited(Optional<txiter> it) const EXCLUSIVE_LOCKS_REQUIRED(cs) {
- assert(m_has_epoch_guard);
+ bool visited(Optional<txiter> it) const EXCLUSIVE_LOCKS_REQUIRED(cs, m_epoch)
+ {
+ assert(m_epoch.guarded()); // verify guard even when it==nullopt
return !it || visited(*it);
}
};
diff --git a/src/util/epochguard.h b/src/util/epochguard.h
new file mode 100644
index 0000000000..1570ec4eb4
--- /dev/null
+++ b/src/util/epochguard.h
@@ -0,0 +1,91 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2020 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_UTIL_EPOCHGUARD_H
+#define BITCOIN_UTIL_EPOCHGUARD_H
+
+#include <threadsafety.h>
+
+#include <cassert>
+
+/** Epoch: RAII-style guard for using epoch-based graph traversal algorithms.
+ * When walking ancestors or descendants, we generally want to avoid
+ * visiting the same transactions twice. Some traversal algorithms use
+ * std::set (or setEntries) to deduplicate the transaction we visit.
+ * However, use of std::set is algorithmically undesirable because it both
+ * adds an asymptotic factor of O(log n) to traversals cost and triggers O(n)
+ * more dynamic memory allocations.
+ * In many algorithms we can replace std::set with an internal mempool
+ * counter to track the time (or, "epoch") that we began a traversal, and
+ * check + update a per-transaction epoch for each transaction we look at to
+ * determine if that transaction has not yet been visited during the current
+ * traversal's epoch.
+ * Algorithms using std::set can be replaced on a one by one basis.
+ * Both techniques are not fundamentally incompatible across the codebase.
+ * Generally speaking, however, the remaining use of std::set for mempool
+ * traversal should be viewed as a TODO for replacement with an epoch based
+ * traversal, rather than a preference for std::set over epochs in that
+ * algorithm.
+ */
+
+class LOCKABLE Epoch
+{
+private:
+ uint64_t m_raw_epoch = 0;
+ bool m_guarded = false;
+
+public:
+ Epoch() = default;
+ Epoch(const Epoch&) = delete;
+ Epoch& operator=(const Epoch&) = delete;
+
+ bool guarded() const { return m_guarded; }
+
+ class Marker
+ {
+ private:
+ uint64_t m_marker = 0;
+
+ // only allow modification via Epoch member functions
+ friend class Epoch;
+ Marker& operator=(const Marker&) = delete;
+ };
+
+ class SCOPED_LOCKABLE Guard
+ {
+ private:
+ Epoch& m_epoch;
+
+ public:
+ explicit Guard(Epoch& epoch) EXCLUSIVE_LOCK_FUNCTION(epoch) : m_epoch(epoch)
+ {
+ assert(!m_epoch.m_guarded);
+ ++m_epoch.m_raw_epoch;
+ m_epoch.m_guarded = true;
+ }
+ ~Guard() UNLOCK_FUNCTION()
+ {
+ assert(m_epoch.m_guarded);
+ ++m_epoch.m_raw_epoch; // ensure clear separation between epochs
+ m_epoch.m_guarded = false;
+ }
+ };
+
+ bool visited(Marker& marker) const EXCLUSIVE_LOCKS_REQUIRED(*this)
+ {
+ assert(m_guarded);
+ if (marker.m_marker < m_raw_epoch) {
+ // marker is from a previous epoch, so this is its first visit
+ marker.m_marker = m_raw_epoch;
+ return false;
+ } else {
+ return true;
+ }
+ }
+};
+
+#define WITH_FRESH_EPOCH(epoch) const Epoch::Guard PASTE2(epoch_guard_, __COUNTER__)(epoch)
+
+#endif // BITCOIN_UTIL_EPOCHGUARD_H
diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp
index fc530ee286..f3e24384df 100644
--- a/src/wallet/init.cpp
+++ b/src/wallet/init.cpp
@@ -62,7 +62,7 @@ void WalletInit::AddWalletOptions(ArgsManager& argsman) const
CURRENCY_UNIT, FormatMoney(CFeeRate{DEFAULT_PAY_TX_FEE}.GetFeePerK())), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
argsman.AddArg("-rescan", "Rescan the block chain for missing wallet transactions on startup", ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
#ifdef ENABLE_EXTERNAL_SIGNER
- argsman.AddArg("-signer=<cmd>", "External signing tool, see docs/external-signer.md", ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
+ argsman.AddArg("-signer=<cmd>", "External signing tool, see doc/external-signer.md", ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
#endif
argsman.AddArg("-spendzeroconfchange", strprintf("Spend unconfirmed change when sending transactions (default: %u)", DEFAULT_SPEND_ZEROCONF_CHANGE), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
argsman.AddArg("-txconfirmtarget=<n>", strprintf("If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)", DEFAULT_TX_CONFIRM_TARGET), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index 99803a91d2..a2872f10ae 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -1775,6 +1775,8 @@ RPCHelpMan listdescriptors()
throw JSONRPCError(RPC_WALLET_ERROR, "listdescriptors is not available for non-descriptor wallets");
}
+ EnsureWalletIsUnlocked(wallet.get());
+
LOCK(wallet->cs_wallet);
UniValue response(UniValue::VARR);
@@ -1787,7 +1789,11 @@ RPCHelpMan listdescriptors()
UniValue spk(UniValue::VOBJ);
LOCK(desc_spk_man->cs_desc_man);
const auto& wallet_descriptor = desc_spk_man->GetWalletDescriptor();
- spk.pushKV("desc", wallet_descriptor.descriptor->ToString());
+ std::string descriptor;
+ if (!desc_spk_man->GetDescriptorString(descriptor, false)) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Can't get normalized descriptor string.");
+ }
+ spk.pushKV("desc", descriptor);
spk.pushKV("timestamp", wallet_descriptor.creation_time);
const bool active = active_spk_mans.count(desc_spk_man) != 0;
spk.pushKV("active", active);
diff --git a/test/functional/feature_blockfilterindex_prune.py b/test/functional/feature_blockfilterindex_prune.py
index 455073ef9c..d13d191b20 100755
--- a/test/functional/feature_blockfilterindex_prune.py
+++ b/test/functional/feature_blockfilterindex_prune.py
@@ -5,49 +5,60 @@
"""Test blockfilterindex in conjunction with prune."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
- assert_raises_rpc_error,
+ assert_equal,
assert_greater_than,
+ assert_raises_rpc_error,
)
class FeatureBlockfilterindexPruneTest(BitcoinTestFramework):
def set_test_params(self):
- self.num_nodes = 2
- self.extra_args = [["-fastprune", "-prune=1"], ["-fastprune", "-prune=1", "-blockfilterindex=1"]]
+ self.num_nodes = 1
+ self.extra_args = [["-fastprune", "-prune=1", "-blockfilterindex=1"]]
+
+ def sync_index(self, height):
+ expected = {'basic block filter index': {'synced': True, 'best_block_height': height}}
+ self.wait_until(lambda: self.nodes[0].getindexinfo() == expected)
def run_test(self):
- # test basic pruning compatibility & filter access of pruned blocks
self.log.info("check if we can access a blockfilter when pruning is enabled but no blocks are actually pruned")
- assert len(self.nodes[1].getblockfilter(self.nodes[1].getbestblockhash())['filter']) > 0
+ self.sync_index(height=200)
+ assert_greater_than(len(self.nodes[0].getblockfilter(self.nodes[0].getbestblockhash())['filter']), 0)
# Mine two batches of blocks to avoid hitting NODE_NETWORK_LIMITED_MIN_BLOCKS disconnection
- self.nodes[1].generate(250)
+ self.nodes[0].generate(250)
self.sync_all()
- self.nodes[1].generate(250)
+ self.nodes[0].generate(250)
self.sync_all()
+ self.sync_index(height=700)
+
self.log.info("prune some blocks")
- pruneheight = self.nodes[1].pruneblockchain(400)
- assert pruneheight != 0
+ pruneheight = self.nodes[0].pruneblockchain(400)
+ assert_equal(pruneheight, 250)
+
self.log.info("check if we can access the tips blockfilter when we have pruned some blocks")
- assert len(self.nodes[1].getblockfilter(self.nodes[1].getbestblockhash())['filter']) > 0
+ assert_greater_than(len(self.nodes[0].getblockfilter(self.nodes[0].getbestblockhash())['filter']), 0)
+
self.log.info("check if we can access the blockfilter of a pruned block")
- assert len(self.nodes[1].getblockfilter(self.nodes[1].getblockhash(2))['filter']) > 0
+ assert_greater_than(len(self.nodes[0].getblockfilter(self.nodes[0].getblockhash(2))['filter']), 0)
+
self.log.info("start node without blockfilterindex")
- self.stop_node(1)
- self.start_node(1, extra_args=self.extra_args[0])
+ self.restart_node(0, extra_args=["-fastprune", "-prune=1"])
+
self.log.info("make sure accessing the blockfilters throws an error")
- assert_raises_rpc_error(-1, "Index is not enabled for filtertype basic", self.nodes[1].getblockfilter, self.nodes[1].getblockhash(2))
- self.nodes[1].generate(1000)
+ assert_raises_rpc_error(-1, "Index is not enabled for filtertype basic", self.nodes[0].getblockfilter, self.nodes[0].getblockhash(2))
+ self.nodes[0].generate(1000)
+
self.log.info("prune below the blockfilterindexes best block while blockfilters are disabled")
- pruneheight_new = self.nodes[1].pruneblockchain(1000)
+ pruneheight_new = self.nodes[0].pruneblockchain(1000)
assert_greater_than(pruneheight_new, pruneheight)
- self.stop_node(1)
+ self.stop_node(0)
+
self.log.info("make sure we get an init error when starting the node again with block filters")
- with self.nodes[1].assert_debug_log(["basic block filter index best block of the index goes beyond pruned data. Please disable the index or reindex (which will download the whole blockchain again)"]):
- self.nodes[1].assert_start_raises_init_error(extra_args=self.extra_args[1])
+ with self.nodes[0].assert_debug_log(["basic block filter index best block of the index goes beyond pruned data. Please disable the index or reindex (which will download the whole blockchain again)"]):
+ self.nodes[0].assert_start_raises_init_error(extra_args=["-fastprune", "-prune=1", "-blockfilterindex=1"])
+
self.log.info("make sure the node starts again with the -reindex arg")
- reindex_args = self.extra_args[1]
- reindex_args.append("-reindex")
- self.start_node(1, extra_args=reindex_args)
+ self.start_node(0, extra_args = ["-fastprune", "-prune=1", "-blockfilterindex", "-reindex"])
if __name__ == '__main__':
diff --git a/test/functional/feature_config_args.py b/test/functional/feature_config_args.py
index 573760a8cb..a0bcd9f12a 100755
--- a/test/functional/feature_config_args.py
+++ b/test/functional/feature_config_args.py
@@ -19,7 +19,7 @@ class ConfArgsTest(BitcoinTestFramework):
self.wallet_names = []
def test_config_file_parser(self):
- # Assume node is stopped
+ self.stop_node(0)
inc_conf_file_path = os.path.join(self.nodes[0].datadir, 'include.conf')
with open(os.path.join(self.nodes[0].datadir, 'bitcoin.conf'), 'a', encoding='utf-8') as conf:
@@ -89,11 +89,12 @@ class ConfArgsTest(BitcoinTestFramework):
)
def test_log_buffer(self):
+ self.stop_node(0)
with self.nodes[0].assert_debug_log(expected_msgs=['Warning: parsed potentially confusing double-negative -connect=0\n']):
self.start_node(0, extra_args=['-noconnect=0'])
- self.stop_node(0)
def test_args_log(self):
+ self.stop_node(0)
self.log.info('Test config args logging')
with self.nodes[0].assert_debug_log(
expected_msgs=[
@@ -120,37 +121,41 @@ class ConfArgsTest(BitcoinTestFramework):
'-rpcuser=secret-rpcuser',
'-torpassword=secret-torpassword',
])
- self.stop_node(0)
def test_networkactive(self):
self.log.info('Test -networkactive option')
+ self.stop_node(0)
with self.nodes[0].assert_debug_log(expected_msgs=['SetNetworkActive: true\n']):
self.start_node(0)
- self.stop_node(0)
+ self.stop_node(0)
with self.nodes[0].assert_debug_log(expected_msgs=['SetNetworkActive: true\n']):
self.start_node(0, extra_args=['-networkactive'])
- self.stop_node(0)
+ self.stop_node(0)
with self.nodes[0].assert_debug_log(expected_msgs=['SetNetworkActive: true\n']):
self.start_node(0, extra_args=['-networkactive=1'])
- self.stop_node(0)
+ self.stop_node(0)
with self.nodes[0].assert_debug_log(expected_msgs=['SetNetworkActive: false\n']):
self.start_node(0, extra_args=['-networkactive=0'])
- self.stop_node(0)
+ self.stop_node(0)
with self.nodes[0].assert_debug_log(expected_msgs=['SetNetworkActive: false\n']):
self.start_node(0, extra_args=['-nonetworkactive'])
- self.stop_node(0)
+ self.stop_node(0)
with self.nodes[0].assert_debug_log(expected_msgs=['SetNetworkActive: false\n']):
self.start_node(0, extra_args=['-nonetworkactive=1'])
- self.stop_node(0)
def test_seed_peers(self):
self.log.info('Test seed peers')
default_data_dir = self.nodes[0].datadir
+ # Only regtest has no fixed seeds. To avoid connections to random
+ # nodes, regtest is the only network where it is safe to enable
+ # -fixedseeds in tests
+ util.assert_equal(self.nodes[0].getblockchaininfo()['chain'],'regtest')
+ self.stop_node(0)
# No peers.dat exists and -dnsseed=1
# We expect the node will use DNS Seeds, but Regtest mode has 0 DNS seeds
@@ -159,10 +164,12 @@ class ConfArgsTest(BitcoinTestFramework):
start = int(time.time())
with self.nodes[0].assert_debug_log(expected_msgs=[
"Loaded 0 addresses from peers.dat",
- "0 addresses found from DNS seeds"]):
- self.start_node(0, extra_args=['-dnsseed=1 -mocktime={}'.format(start)])
+ "0 addresses found from DNS seeds",
+ ]):
+ self.start_node(0, extra_args=['-dnsseed=1', '-fixedseeds=1', f'-mocktime={start}'])
with self.nodes[0].assert_debug_log(expected_msgs=[
- "Adding fixed seeds as 60 seconds have passed and addrman is empty"]):
+ "Adding fixed seeds as 60 seconds have passed and addrman is empty",
+ ]):
self.nodes[0].setmocktime(start + 65)
self.stop_node(0)
@@ -173,8 +180,9 @@ class ConfArgsTest(BitcoinTestFramework):
with self.nodes[0].assert_debug_log(expected_msgs=[
"Loaded 0 addresses from peers.dat",
"DNS seeding disabled",
- "Adding fixed seeds as -dnsseed=0, -addnode is not provided and all -seednode(s) attempted\n"]):
- self.start_node(0, extra_args=['-dnsseed=0'])
+ "Adding fixed seeds as -dnsseed=0, -addnode is not provided and all -seednode(s) attempted\n",
+ ]):
+ self.start_node(0, extra_args=['-dnsseed=0', '-fixedseeds=1'])
assert time.time() - start < 60
self.stop_node(0)
@@ -185,7 +193,8 @@ class ConfArgsTest(BitcoinTestFramework):
with self.nodes[0].assert_debug_log(expected_msgs=[
"Loaded 0 addresses from peers.dat",
"DNS seeding disabled",
- "Fixed seeds are disabled"]):
+ "Fixed seeds are disabled",
+ ]):
self.start_node(0, extra_args=['-dnsseed=0', '-fixedseeds=0'])
assert time.time() - start < 60
self.stop_node(0)
@@ -196,17 +205,15 @@ class ConfArgsTest(BitcoinTestFramework):
start = int(time.time())
with self.nodes[0].assert_debug_log(expected_msgs=[
"Loaded 0 addresses from peers.dat",
- "DNS seeding disabled"]):
- self.start_node(0, extra_args=['-dnsseed=0', '-addnode=fakenodeaddr -mocktime={}'.format(start)])
+ "DNS seeding disabled",
+ ]):
+ self.start_node(0, extra_args=['-dnsseed=0', '-fixedseeds=1', '-addnode=fakenodeaddr', f'-mocktime={start}'])
with self.nodes[0].assert_debug_log(expected_msgs=[
- "Adding fixed seeds as 60 seconds have passed and addrman is empty"]):
+ "Adding fixed seeds as 60 seconds have passed and addrman is empty",
+ ]):
self.nodes[0].setmocktime(start + 65)
- self.stop_node(0)
-
def run_test(self):
- self.stop_node(0)
-
self.test_log_buffer()
self.test_args_log()
self.test_seed_peers()
diff --git a/test/functional/rpc_blockchain.py b/test/functional/rpc_blockchain.py
index a6afbad0fc..e090030205 100755
--- a/test/functional/rpc_blockchain.py
+++ b/test/functional/rpc_blockchain.py
@@ -23,6 +23,7 @@ import http.client
import os
import subprocess
+from test_framework.address import ADDRESS_BCRT1_P2WSH_OP_TRUE
from test_framework.blocktools import (
create_block,
create_coinbase,
@@ -71,11 +72,10 @@ class BlockchainTest(BitcoinTestFramework):
def mine_chain(self):
self.log.info('Create some old blocks')
- address = self.nodes[0].get_deterministic_priv_key().address
for t in range(TIME_GENESIS_BLOCK, TIME_GENESIS_BLOCK + 200 * 600, 600):
# ten-minute steps from genesis block time
self.nodes[0].setmocktime(t)
- self.nodes[0].generatetoaddress(1, address)
+ self.nodes[0].generatetoaddress(1, ADDRESS_BCRT1_P2WSH_OP_TRUE)
assert_equal(self.nodes[0].getblockchaininfo()['blocks'], 200)
def _test_getblockchaininfo(self):
@@ -227,7 +227,7 @@ class BlockchainTest(BitcoinTestFramework):
assert_equal(res['transactions'], 200)
assert_equal(res['height'], 200)
assert_equal(res['txouts'], 200)
- assert_equal(res['bogosize'], 15000),
+ assert_equal(res['bogosize'], 16800),
assert_equal(res['bestblock'], node.getblockhash(200))
size = res['disk_size']
assert size > 6400
@@ -332,12 +332,12 @@ class BlockchainTest(BitcoinTestFramework):
def _test_stopatheight(self):
assert_equal(self.nodes[0].getblockcount(), 200)
- self.nodes[0].generatetoaddress(6, self.nodes[0].get_deterministic_priv_key().address)
+ self.nodes[0].generatetoaddress(6, ADDRESS_BCRT1_P2WSH_OP_TRUE)
assert_equal(self.nodes[0].getblockcount(), 206)
self.log.debug('Node should not stop at this height')
assert_raises(subprocess.TimeoutExpired, lambda: self.nodes[0].process.wait(timeout=3))
try:
- self.nodes[0].generatetoaddress(1, self.nodes[0].get_deterministic_priv_key().address)
+ self.nodes[0].generatetoaddress(1, ADDRESS_BCRT1_P2WSH_OP_TRUE)
except (ConnectionError, http.client.BadStatusLine):
pass # The node already shut down before response
self.log.debug('Node should stop at this height...')
@@ -387,8 +387,7 @@ class BlockchainTest(BitcoinTestFramework):
node = self.nodes[0]
miniwallet = MiniWallet(node)
- miniwallet.generate(5)
- node.generate(100)
+ miniwallet.scan_blocks(num=5)
fee_per_byte = Decimal('0.00000010')
fee_per_kb = 1000 * fee_per_byte
diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py
index f7eaaa548f..02eb10b5a4 100755
--- a/test/functional/test_framework/test_framework.py
+++ b/test/functional/test_framework/test_framework.py
@@ -19,6 +19,7 @@ import tempfile
import time
from typing import List
+from .address import ADDRESS_BCRT1_P2WSH_OP_TRUE
from .authproxy import JSONRPCException
from . import coverage
from .p2p import NetworkThread
@@ -732,16 +733,17 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
# Set a time in the past, so that blocks don't end up in the future
cache_node.setmocktime(cache_node.getblockheader(cache_node.getbestblockhash())['time'])
- # Create a 199-block-long chain; each of the 4 first nodes
+ # Create a 199-block-long chain; each of the 3 first nodes
# gets 25 mature blocks and 25 immature.
- # The 4th node gets only 24 immature blocks so that the very last
+ # The 4th address gets 25 mature and only 24 immature blocks so that the very last
# block in the cache does not age too much (have an old tip age).
# This is needed so that we are out of IBD when the test starts,
# see the tip age check in IsInitialBlockDownload().
+ gen_addresses = [k.address for k in TestNode.PRIV_KEYS] + [ADDRESS_BCRT1_P2WSH_OP_TRUE]
for i in range(8):
cache_node.generatetoaddress(
nblocks=25 if i != 7 else 24,
- address=TestNode.PRIV_KEYS[i % 4].address,
+ address=gen_addresses[i % 4],
)
assert_equal(cache_node.getblockchaininfo()["blocks"], 199)
diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py
index 123c48852c..d335d4ea79 100644
--- a/test/functional/test_framework/util.py
+++ b/test/functional/test_framework/util.py
@@ -368,6 +368,7 @@ def write_config(config_path, *, n, chain, extra_config=""):
f.write("keypool=1\n")
f.write("discover=0\n")
f.write("dnsseed=0\n")
+ f.write("fixedseeds=0\n")
f.write("listenonion=0\n")
f.write("printtoconsole=0\n")
f.write("upnp=0\n")
diff --git a/test/functional/test_framework/wallet.py b/test/functional/test_framework/wallet.py
index edd7792608..38fbf3c1a6 100644
--- a/test/functional/test_framework/wallet.py
+++ b/test/functional/test_framework/wallet.py
@@ -32,6 +32,15 @@ class MiniWallet:
self._address = ADDRESS_BCRT1_P2WSH_OP_TRUE
self._scriptPubKey = hex_str_to_bytes(self._test_node.validateaddress(self._address)['scriptPubKey'])
+ def scan_blocks(self, *, start=1, num):
+ """Scan the blocks for self._address outputs and add them to self._utxos"""
+ for i in range(start, start + num):
+ block = self._test_node.getblock(blockhash=self._test_node.getblockhash(i), verbosity=2)
+ for tx in block['tx']:
+ for out in tx['vout']:
+ if out['scriptPubKey']['hex'] == self._scriptPubKey.hex():
+ self._utxos.append({'txid': tx['txid'], 'vout': out['n'], 'value': out['value']})
+
def generate(self, num_blocks):
"""Generate blocks with coinbase outputs to the internal address, and append the outputs to the internal list"""
blocks = self._test_node.generatetoaddress(num_blocks, self._address)
diff --git a/test/functional/wallet_listdescriptors.py b/test/functional/wallet_listdescriptors.py
index 9f8c341bc7..8d02949ff4 100755
--- a/test/functional/wallet_listdescriptors.py
+++ b/test/functional/wallet_listdescriptors.py
@@ -50,6 +50,22 @@ class ListDescriptorsTest(BitcoinTestFramework):
assert item['range'] == [0, 0]
assert item['timestamp'] is not None
+ self.log.info('Test descriptors with hardened derivations are listed in importable form.')
+ xprv = 'tprv8ZgxMBicQKsPeuVhWwi6wuMQGfPKi9Li5GtX35jVNknACgqe3CY4g5xgkfDDJcmtF7o1QnxWDRYw4H5P26PXq7sbcUkEqeR4fg3Kxp2tigg'
+ xpub_acc = 'tpubDCMVLhErorrAGfApiJSJzEKwqeaf2z3NrkVMxgYQjZLzMjXMBeRw2muGNYbvaekAE8rUFLftyEar4LdrG2wXyyTJQZ26zptmeTEjPTaATts'
+ hardened_path = '/84\'/1\'/0\''
+ wallet = node.get_wallet_rpc('w2')
+ wallet.importdescriptors([{
+ 'desc': descsum_create('wpkh(' + xprv + hardened_path + '/0/*)'),
+ 'timestamp': 1296688602,
+ }])
+ expected = {'desc': descsum_create('wpkh([80002067' + hardened_path + ']' + xpub_acc + '/0/*)'),
+ 'timestamp': 1296688602,
+ 'active': False,
+ 'range': [0, 0],
+ 'next': 0}
+ assert_equal([expected], wallet.listdescriptors())
+
self.log.info('Test non-active non-range combo descriptor')
node.createwallet(wallet_name='w4', blank=True, descriptors=True)
wallet = node.get_wallet_rpc('w4')
diff --git a/test/functional/wallet_txn_clone.py b/test/functional/wallet_txn_clone.py
index 893a2d9617..6fc1d13c53 100755
--- a/test/functional/wallet_txn_clone.py
+++ b/test/functional/wallet_txn_clone.py
@@ -11,9 +11,10 @@ from test_framework.util import (
)
from test_framework.messages import CTransaction, COIN
+
class TxnMallTest(BitcoinTestFramework):
def set_test_params(self):
- self.num_nodes = 4
+ self.num_nodes = 3
self.supports_cli = False
def skip_test_if_missing_module(self):
@@ -38,9 +39,8 @@ class TxnMallTest(BitcoinTestFramework):
# All nodes should start with 1,250 BTC:
starting_balance = 1250
- for i in range(4):
+ for i in range(3):
assert_equal(self.nodes[i].getbalance(), starting_balance)
- self.nodes[i].getnewaddress() # bug workaround, coins generated assigned to first getnewaddress!
self.nodes[0].settxfee(.001)
@@ -139,5 +139,6 @@ class TxnMallTest(BitcoinTestFramework):
expected -= 50
assert_equal(self.nodes[0].getbalance(), expected)
+
if __name__ == '__main__':
TxnMallTest().main()
diff --git a/test/functional/wallet_txn_doublespend.py b/test/functional/wallet_txn_doublespend.py
index c7f7a8546a..0cb7328948 100755
--- a/test/functional/wallet_txn_doublespend.py
+++ b/test/functional/wallet_txn_doublespend.py
@@ -11,9 +11,10 @@ from test_framework.util import (
find_output,
)
+
class TxnMallTest(BitcoinTestFramework):
def set_test_params(self):
- self.num_nodes = 4
+ self.num_nodes = 3
self.supports_cli = False
def skip_test_if_missing_module(self):
@@ -39,9 +40,8 @@ class TxnMallTest(BitcoinTestFramework):
for n in self.nodes:
assert n.getblockchaininfo()["initialblockdownload"] == False
- for i in range(4):
+ for i in range(3):
assert_equal(self.nodes[i].getbalance(), starting_balance)
- self.nodes[i].getnewaddress("") # bug workaround, coins generated assigned to first getnewaddress!
# Assign coins to foo and bar addresses:
node0_address_foo = self.nodes[0].getnewaddress()
@@ -136,5 +136,6 @@ class TxnMallTest(BitcoinTestFramework):
# Node1's balance should be its initial balance (1250 for 25 block rewards) plus the doublespend:
assert_equal(self.nodes[1].getbalance(), 1250 + 1240)
+
if __name__ == '__main__':
TxnMallTest().main()