mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-01-31 10:41:08 +00:00
Merge bitcoin/bitcoin#33609: [30.x] Backports
b2cb203af05743ea5c130913afa7549c02d1bae5 doc: update release notes for 30.x (fanquake) 39d53dd8bf2a19dfdc6976e9d8e9c562065adc1d interfaces: add interruptWait method (ismaelsadeeq) 577ddf6f5d1e7b01c496350206ac8fc33178e416 depends: Add patch for Windows11Style plugin (Hennadii Stepanov) a0a2b0770164b606780c707d6d0a82a02ff9039f scripted-diff: Remove obsolete comment (Hennadii Stepanov) e2c71c4fca44e14366653eedb8a15183d6a0444b doc: Correct `pkgin` command usage on NetBSD (Hennadii Stepanov) c0d851e6c69ba8fc1d70b89e0660831c8fb9e633 qt: Modernize custom filtering (Hennadii Stepanov) 34576c45747214e02b34cac5de71f5139888661f ci: fix configure docker action inputs (will) 8f8c7cf7fa957337d9f5715ae28835dbba12698d ci: fix lint docker caching (will) 049bf100f114db3ec95eebbc56621ab5bce2cabd qt: add createwallet, createwalletdescriptor, and migratewallet to history filter (WakeTrainDev) 3afd5a9729d78f38d2cac7b34f3ef44c79b4bf9a miner: fix empty mempool case for waitNext() (Sjors Provoost) 23ac752d0966317894ae5279a59a12dd6f9f616a bitcoin: Make wrapper not require -m (Ryan Ofsky) cd7937ce2d313715f380eafd15b20d429b65c83c test: add tool_bitcoin to test bitcoin wrapper behavior (Ryan Ofsky) 42d4847fdff3e1c3b0644de5f503db80ef3ff2a1 init: add exe name to bitcoind, bitcoin-node -version output to be able to distinguish these in tests (Ryan Ofsky) 96110f884604ab85db04170f22e9a4bd936c59d7 [doc] correct topology requirements in submitpackage helptext (glozow) 729e4c2abd4ab4eda4051579c57410dd64d4e7a9 multiprocess: align our logging with libmultiprocess's (Cory Fields) f8db6f6ce7d30c1b6db8646eedc9160ded556823 multiprocess: update multiprocess EventLoop construction to use options (Cory Fields) 5e389959b9bacae60da64d6e0213ae12242b4c2e test: change log rate limit version gate from 299900 to 290100 (Eugene Siegel) c48d3a6ad8e884bdb595d5608d914f7de688b7af ci: expose all ACTIONS_* vars (willcl-ark) 73ed57a35e624c6eb4c5dca2687303920fa792bc depends: Use $(package)_file_name when downloading from the fallback (Ava Chow) 72d1141bd8ded704cc6b881a7d26d9103ec813df ci: Use native platform for win-cross task (MarcoFalke) c9fa661131c336a844109a5d8627b7419280bf52 ci: Properly include $FILE_ENV in DEPENDS_HASH (Ava Chow) Pull request description: Backports: * #33229 * #33508 * #33517 * #33558 * #33566 * #33580 * #33581 * #33612 * #33630 * #33676 * #33744 * #33826 * #33827 * #33906 * https://github.com/bitcoin-core/gui/pull/899 * https://github.com/bitcoin-core/gui/pull/901 ACKs for top commit: willcl-ark: ACK b2cb203af05743ea5c130913afa7549c02d1bae5 marcofleon: Lgtm, ACK b2cb203af05743ea5c130913afa7549c02d1bae5 Tree-SHA512: cde3584c7ad9bc6034a54527c1f5e84f0c5e314520109342a5cbb3c6c703286e2bed26f2b24fbf0ba7bcc9cbc140d79921e9d63def6b5c4782fd2e208f51948a
This commit is contained in:
commit
72675b8f55
23
.github/actions/configure-docker/action.yml
vendored
23
.github/actions/configure-docker/action.yml
vendored
@ -4,12 +4,21 @@ inputs:
|
||||
cache-provider:
|
||||
description: 'gha or cirrus cache provider'
|
||||
required: true
|
||||
options:
|
||||
- gh
|
||||
- cirrus
|
||||
runs:
|
||||
using: 'composite'
|
||||
steps:
|
||||
- name: Check inputs
|
||||
shell: bash
|
||||
run: |
|
||||
# We expect only gha or cirrus as inputs to cache-provider
|
||||
case "${{ inputs.cache-provider }}" in
|
||||
gha|cirrus)
|
||||
;;
|
||||
*)
|
||||
echo "::warning title=Unknown input to configure docker action::Provided value was ${{ inputs.cache-provider }}"
|
||||
;;
|
||||
esac
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
@ -22,8 +31,12 @@ runs:
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
script: |
|
||||
core.exportVariable('ACTIONS_CACHE_URL', process.env['ACTIONS_CACHE_URL'])
|
||||
core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env['ACTIONS_RUNTIME_TOKEN'])
|
||||
Object.keys(process.env).forEach(function (key) {
|
||||
if (key.startsWith('ACTIONS_')) {
|
||||
core.info(`Exporting ${key}`);
|
||||
core.exportVariable(key, process.env[key]);
|
||||
}
|
||||
});
|
||||
|
||||
- name: Construct docker build cache args
|
||||
shell: bash
|
||||
|
||||
@ -17,7 +17,7 @@ runs:
|
||||
- name: Set cache hashes
|
||||
shell: bash
|
||||
run: |
|
||||
echo "DEPENDS_HASH=$(git ls-tree HEAD depends "ci/test/$FILE_ENV" | sha256sum | cut -d' ' -f1)" >> $GITHUB_ENV
|
||||
echo "DEPENDS_HASH=$(git ls-tree HEAD depends "$FILE_ENV" | sha256sum | cut -d' ' -f1)" >> $GITHUB_ENV
|
||||
echo "PREVIOUS_RELEASES_HASH=$(git ls-tree HEAD test/get_previous_releases.py | sha256sum | cut -d' ' -f1)" >> $GITHUB_ENV
|
||||
|
||||
- name: Get container name
|
||||
|
||||
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@ -536,7 +536,7 @@ jobs:
|
||||
lint:
|
||||
name: 'lint'
|
||||
needs: runners
|
||||
runs-on: ${{ needs.runners.outputs.use-cirrus-runners == 'true' && 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-xs' || 'ubuntu-24.04' }}
|
||||
runs-on: ${{ needs.runners.outputs.provider == 'cirrus' && 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-xs' || 'ubuntu-24.04' }}
|
||||
if: ${{ vars.SKIP_BRANCH_PUSH != 'true' || github.event_name == 'pull_request' }}
|
||||
timeout-minutes: 20
|
||||
env:
|
||||
|
||||
@ -8,7 +8,6 @@ export LC_ALL=C.UTF-8
|
||||
|
||||
export CONTAINER_NAME=ci_win64
|
||||
export CI_IMAGE_NAME_TAG="mirror.gcr.io/ubuntu:24.04" # Check that https://packages.ubuntu.com/noble/g++-mingw-w64-x86-64-posix (version 13.x, similar to guix) can cross-compile
|
||||
export CI_IMAGE_PLATFORM="linux/amd64"
|
||||
export HOST=x86_64-w64-mingw32
|
||||
export PACKAGES="g++-mingw-w64-x86-64-posix nsis"
|
||||
export RUN_UNIT_TESTS=false
|
||||
|
||||
@ -38,7 +38,7 @@ endef
|
||||
define fetch_file
|
||||
( test -f $$($(1)_source_dir)/$(4) || \
|
||||
( $(call fetch_file_inner,$(1),$(2),$(3),$(4),$(5)) || \
|
||||
$(call fetch_file_inner,$(1),$(FALLBACK_DOWNLOAD_PATH),$(3),$(4),$(5))))
|
||||
$(call fetch_file_inner,$(1),$(FALLBACK_DOWNLOAD_PATH),$(4),$(4),$(5))))
|
||||
endef
|
||||
|
||||
# Shell script to create a source tarball in $(1)_source from local directory
|
||||
|
||||
@ -16,6 +16,7 @@ $(package)_patches += qtbase_avoid_native_float16.patch
|
||||
$(package)_patches += qtbase_avoid_qmain.patch
|
||||
$(package)_patches += qtbase_platformsupport.patch
|
||||
$(package)_patches += qtbase_plugins_cocoa.patch
|
||||
$(package)_patches += qtbase_plugins_windows11style.patch
|
||||
$(package)_patches += qtbase_skip_tools.patch
|
||||
$(package)_patches += rcc_hardcode_timestamp.patch
|
||||
$(package)_patches += qttools_skip_dependencies.patch
|
||||
@ -261,6 +262,7 @@ define $(package)_preprocess_cmds
|
||||
patch -p1 -i $($(package)_patch_dir)/qtbase_avoid_qmain.patch && \
|
||||
patch -p1 -i $($(package)_patch_dir)/qtbase_platformsupport.patch && \
|
||||
patch -p1 -i $($(package)_patch_dir)/qtbase_plugins_cocoa.patch && \
|
||||
patch -p1 -i $($(package)_patch_dir)/qtbase_plugins_windows11style.patch && \
|
||||
patch -p1 -i $($(package)_patch_dir)/qtbase_skip_tools.patch && \
|
||||
patch -p1 -i $($(package)_patch_dir)/rcc_hardcode_timestamp.patch
|
||||
endef
|
||||
|
||||
113
depends/patches/qt/qtbase_plugins_windows11style.patch
Normal file
113
depends/patches/qt/qtbase_plugins_windows11style.patch
Normal file
@ -0,0 +1,113 @@
|
||||
QWindows11Style: Calculate Spinbox size based on CommonStyle size
|
||||
Use the calculation from Commonstyle and add the increased padding and
|
||||
horizontally layouted buttons to the horizontal size hint.
|
||||
|
||||
Fixes: QTBUG-130288
|
||||
Change-Id: I7932b782e7873a0178091a51379f17453eb585fd
|
||||
|
||||
Upstream commits:
|
||||
- Qt 6.8.1: 9107817eaceaacc968dbc767c24594566d637b8c
|
||||
- Qt 6.9.0: 96d46cad43517adefa2eb7cb8819a0b2cc9241e6
|
||||
|
||||
--- a/qtbase/src/plugins/styles/modernwindows/qwindows11style.cpp
|
||||
+++ b/qtbase/src/plugins/styles/modernwindows/qwindows11style.cpp
|
||||
@@ -2048,39 +2048,22 @@ QSize QWindows11Style::sizeFromContents(ContentsType type, const QStyleOption *o
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
+#if QT_CONFIG(spinbox)
|
||||
case QStyle::CT_SpinBox: {
|
||||
if (const auto *spinBoxOpt = qstyleoption_cast<const QStyleOptionSpinBox *>(option)) {
|
||||
// Add button + frame widths
|
||||
- int width = 0;
|
||||
-
|
||||
- if (const QDateTimeEdit *spinBox = qobject_cast<const QDateTimeEdit *>(widget)) {
|
||||
- const QSize textSizeMin = spinBoxOpt->fontMetrics.size(Qt::TextSingleLine, spinBox->minimumDateTime().toString(spinBox->displayFormat()));
|
||||
- const QSize textSizeMax = spinBoxOpt->fontMetrics.size(Qt::TextSingleLine, spinBox->maximumDateTime().toString(spinBox->displayFormat()));
|
||||
- width = qMax(textSizeMin.width(),textSizeMax.width());
|
||||
- } else if (const QSpinBox *spinBox = qobject_cast<const QSpinBox *>(widget)) {
|
||||
- const QSize textSizeMin = spinBoxOpt->fontMetrics.size(Qt::TextSingleLine, QString::number(spinBox->minimum()));
|
||||
- const QSize textSizeMax = spinBoxOpt->fontMetrics.size(Qt::TextSingleLine, QString::number(spinBox->maximum()));
|
||||
- width = qMax(textSizeMin.width(),textSizeMax.width());
|
||||
- width += spinBoxOpt->fontMetrics.size(Qt::TextSingleLine, spinBox->prefix()).width();
|
||||
- width += spinBoxOpt->fontMetrics.size(Qt::TextSingleLine, spinBox->suffix()).width();
|
||||
-
|
||||
- } else if (const QDoubleSpinBox *spinBox = qobject_cast<const QDoubleSpinBox *>(widget)) {
|
||||
- const QSize textSizeMin = spinBoxOpt->fontMetrics.size(Qt::TextSingleLine, QString::number(spinBox->minimum()));
|
||||
- const QSize textSizeMax = spinBoxOpt->fontMetrics.size(Qt::TextSingleLine, QString::number(spinBox->maximum()));
|
||||
- width = qMax(textSizeMin.width(),textSizeMax.width());
|
||||
- width += spinBoxOpt->fontMetrics.size(Qt::TextSingleLine, spinBox->prefix()).width();
|
||||
- width += spinBoxOpt->fontMetrics.size(Qt::TextSingleLine, spinBox->suffix()).width();
|
||||
- }
|
||||
const qreal dpi = QStyleHelper::dpi(option);
|
||||
const bool hasButtons = (spinBoxOpt->buttonSymbols != QAbstractSpinBox::NoButtons);
|
||||
- const int buttonWidth = hasButtons ? 2 * qRound(QStyleHelper::dpiScaled(16, dpi)) : 0;
|
||||
+ const int margins = 8;
|
||||
+ const int buttonWidth = hasButtons ? qRound(QStyleHelper::dpiScaled(16, dpi)) : 0;
|
||||
const int frameWidth = spinBoxOpt->frame ? proxy()->pixelMetric(PM_SpinBoxFrameWidth,
|
||||
spinBoxOpt, widget) : 0;
|
||||
- contentSize.setWidth(2 * 12 + width);
|
||||
- contentSize += QSize(buttonWidth + 2 * frameWidth, 2 * frameWidth);
|
||||
+
|
||||
+ contentSize += QSize(2 * buttonWidth + 2 * frameWidth + 2 * margins, 2 * frameWidth);
|
||||
}
|
||||
break;
|
||||
}
|
||||
+#endif
|
||||
default:
|
||||
contentSize = QWindowsVistaStyle::sizeFromContents(type, option, size, widget);
|
||||
break;
|
||||
|
||||
|
||||
Windows11Style: don't set minimum width for QAbstractSpinBox
|
||||
|
||||
There is no need to set a minimum width for QAbstractSpinBox in
|
||||
QWindows11Style::polish() as this might override the user preferences.
|
||||
Also the minimum size handling is now properly done within
|
||||
sizeFromContents().
|
||||
|
||||
Change-Id: Ibc1fd7a6f862fc85e3739025b9de581aa235d74c
|
||||
|
||||
Upstream commits:
|
||||
- Qt 6.8.3: f86da3d3f853adb1a5b823c1cc7be6db4a0265f3
|
||||
- Qt 6.9.0: b93a8dfdfe6900cb542fdc587dd2682007a6ac53
|
||||
- Qt 6.10.0: 2ec4c28470de115c16944653a5d4f6209452d56c
|
||||
|
||||
--- a/qtbase/src/plugins/styles/modernwindows/qwindows11style.cpp
|
||||
+++ b/qtbase/src/plugins/styles/modernwindows/qwindows11style.cpp
|
||||
@@ -29,7 +29,6 @@ QT_BEGIN_NAMESPACE
|
||||
|
||||
const static int topLevelRoundingRadius = 8; //Radius for toplevel items like popups for round corners
|
||||
const static int secondLevelRoundingRadius = 4; //Radius for second level items like hovered menu item round corners
|
||||
-constexpr QLatin1StringView originalWidthProperty("_q_windows11_style_original_width");
|
||||
|
||||
enum WINUI3Color {
|
||||
subtleHighlightColor, //Subtle highlight based on alpha used for hovered elements
|
||||
@@ -2140,13 +2139,6 @@ void QWindows11Style::polish(QWidget* widget)
|
||||
pal.setColor(QPalette::ButtonText, pal.text().color());
|
||||
pal.setColor(QPalette::BrightText, pal.text().color());
|
||||
widget->setPalette(pal);
|
||||
- } else if (widget->inherits("QAbstractSpinBox")) {
|
||||
- const int minWidth = 2 * 24 + 40;
|
||||
- const int originalWidth = widget->size().width();
|
||||
- if (originalWidth < minWidth) {
|
||||
- widget->resize(minWidth, widget->size().height());
|
||||
- widget->setProperty(originalWidthProperty.constData(), originalWidth);
|
||||
- }
|
||||
} else if (widget->inherits("QAbstractButton") || widget->inherits("QToolButton")) {
|
||||
widget->setAutoFillBackground(false);
|
||||
auto pal = widget->palette();
|
||||
@@ -2191,13 +2183,6 @@ void QWindows11Style::unpolish(QWidget *widget)
|
||||
scrollarea->viewport()->setPalette(pal);
|
||||
scrollarea->viewport()->setProperty("_q_original_background_palette", QVariant());
|
||||
}
|
||||
- if (widget->inherits("QAbstractSpinBox")) {
|
||||
- const QVariant originalWidth = widget->property(originalWidthProperty.constData());
|
||||
- if (originalWidth.isValid()) {
|
||||
- widget->resize(originalWidth.toInt(), widget->size().height());
|
||||
- widget->setProperty(originalWidthProperty.constData(), QVariant());
|
||||
- }
|
||||
- }
|
||||
}
|
||||
|
||||
/*
|
||||
@ -101,5 +101,5 @@ cmake -B build -DENABLE_WALLET=OFF
|
||||
|
||||
```bash
|
||||
cmake --build build # Append "-j N" for N parallel jobs.
|
||||
ctest --test-dir build # Append "-j N" for N parallel tests. Some tests are disabled if Python 3 is not available.
|
||||
ctest --test-dir build # Append "-j N" for N parallel tests.
|
||||
```
|
||||
|
||||
@ -34,7 +34,7 @@ cmake -B build
|
||||
SQLite is required for the wallet:
|
||||
|
||||
```bash
|
||||
pkgin sqlite3
|
||||
pkgin install sqlite3
|
||||
```
|
||||
|
||||
To build Bitcoin Core without the wallet, use `-DENABLE_WALLET=OFF`.
|
||||
@ -42,7 +42,7 @@ To build Bitcoin Core without the wallet, use `-DENABLE_WALLET=OFF`.
|
||||
Cap'n Proto is needed for IPC functionality (see [multiprocess.md](multiprocess.md)):
|
||||
|
||||
```bash
|
||||
pkgin capnproto
|
||||
pkgin install capnproto
|
||||
```
|
||||
|
||||
Compile with `-DENABLE_IPC=OFF` if you do not need IPC functionality.
|
||||
@ -84,7 +84,7 @@ Otherwise, if you don't need QR encoding support, use the `-DWITH_QRENCODE=OFF`
|
||||
|
||||
Bitcoin Core can provide notifications via ZeroMQ. If the package is installed, support will be compiled in.
|
||||
```bash
|
||||
pkgin zeromq
|
||||
pkgin install zeromq
|
||||
```
|
||||
|
||||
#### Test Suite Dependencies
|
||||
@ -115,5 +115,5 @@ Build and run the tests:
|
||||
|
||||
```bash
|
||||
cmake --build build # Append "-j N" for N parallel jobs.
|
||||
ctest --test-dir build # Append "-j N" for N parallel tests. Some tests are disabled if Python 3 is not available.
|
||||
ctest --test-dir build # Append "-j N" for N parallel tests.
|
||||
```
|
||||
|
||||
@ -93,7 +93,7 @@ Run `cmake -B build -LH` to see the full list of available options.
|
||||
|
||||
```bash
|
||||
cmake --build build # Append "-j N" for N parallel jobs.
|
||||
ctest --test-dir build # Append "-j N" for N parallel tests. Some tests are disabled if Python 3 is not available.
|
||||
ctest --test-dir build # Append "-j N" for N parallel tests.
|
||||
```
|
||||
|
||||
## Resource limits
|
||||
|
||||
@ -170,7 +170,7 @@ Run the following in your terminal to compile Bitcoin Core:
|
||||
|
||||
``` bash
|
||||
cmake --build build # Append "-j N" here for N parallel jobs.
|
||||
ctest --test-dir build # Append "-j N" for N parallel tests. Some tests are disabled if Python 3 is not available.
|
||||
ctest --test-dir build # Append "-j N" for N parallel tests.
|
||||
```
|
||||
|
||||
### 3. Deploy (optional)
|
||||
|
||||
@ -55,7 +55,7 @@ In the following instructions, the "Debug" configuration can be specified instea
|
||||
```
|
||||
cmake -B build --preset vs2022-static # It might take a while if the vcpkg binary cache is unpopulated or invalidated.
|
||||
cmake --build build --config Release # Append "-j N" for N parallel jobs.
|
||||
ctest --test-dir build --build-config Release # Append "-j N" for N parallel tests. Some tests are disabled if Python 3 is not available.
|
||||
ctest --test-dir build --build-config Release # Append "-j N" for N parallel tests.
|
||||
cmake --install build --config Release # Optional.
|
||||
```
|
||||
|
||||
@ -64,7 +64,7 @@ cmake --install build --config Release # Optional.
|
||||
```
|
||||
cmake -B build --preset vs2022 -DBUILD_GUI=OFF # It might take a while if the vcpkg binary cache is unpopulated or invalidated.
|
||||
cmake --build build --config Release # Append "-j N" for N parallel jobs.
|
||||
ctest --test-dir build --build-config Release # Append "-j N" for N parallel tests. Some tests are disabled if Python 3 is not available.
|
||||
ctest --test-dir build --build-config Release # Append "-j N" for N parallel tests.
|
||||
```
|
||||
|
||||
### 6. vcpkg-specific Issues and Workarounds
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
v30.0 Release Notes
|
||||
v30.x Release Notes
|
||||
===================
|
||||
|
||||
Bitcoin Core version v30.0 is now available from:
|
||||
Bitcoin Core version v30.x is now available from:
|
||||
|
||||
<https://bitcoincore.org/bin/bitcoin-core-30.0/>
|
||||
<https://bitcoincore.org/bin/bitcoin-core-30.x/>
|
||||
|
||||
This release includes new features, various bug fixes and performance
|
||||
improvements, as well as updated translations.
|
||||
@ -40,399 +40,57 @@ unsupported systems.
|
||||
Notable changes
|
||||
===============
|
||||
|
||||
Policy
|
||||
------
|
||||
### Build
|
||||
|
||||
- The maximum number of potentially executed legacy signature operations in a
|
||||
single standard transaction is now limited to 2500. Signature operations in all
|
||||
previous output scripts, in all input scripts, as well as all P2SH redeem
|
||||
scripts (if there are any) are counted toward the limit. The new limit is
|
||||
assumed to not affect any known typically formed standard transactions. The
|
||||
change was done to prepare for a possible BIP54 deployment in the future. (#32521)
|
||||
- #33580 depends: Use `$(package)_file_name` when downloading from the fallback
|
||||
- #33906 depends: Add patch for Windows11Style plugin
|
||||
|
||||
- `-datacarriersize` is increased to 100,000 by default, which effectively uncaps
|
||||
the limit (as the maximum transaction size limit will be hit first). It can be
|
||||
overridden with `-datacarriersize=83` to revert to the limit enforced in previous
|
||||
versions. (#32406)
|
||||
### IPC
|
||||
|
||||
- Multiple data carrier (OP_RETURN) outputs in a transaction are now permitted for
|
||||
relay and mining. The `-datacarriersize` limit applies to the aggregate size of
|
||||
the scriptPubKeys across all such outputs in a transaction, not including the
|
||||
scriptPubKey size itself. (#32406)
|
||||
- #33229 multiprocess: Don't require bitcoin -m argument when IPC options are used
|
||||
- #33517 multiprocess: Fix high overhead from message logging
|
||||
- #33519 Update libmultiprocess subtree in 30.x branch
|
||||
- #33566 miner: fix empty mempool case for waitNext()
|
||||
- #33676 interfaces: enable cancelling running waitNext calls
|
||||
|
||||
- The minimum block feerate (`-blockmintxfee`) has been changed to 0.001 satoshi per
|
||||
vB. It can still be changed using the configuration option. This option can be used
|
||||
by miners to set a minimum feerate on packages added to block templates. (#33106)
|
||||
### GUI
|
||||
|
||||
- The default minimum relay feerate (`-minrelaytxfee`) and incremental relay feerate
|
||||
(`-incrementalrelayfee`) have been changed to 0.1 satoshis per vB. They can still
|
||||
be changed using their respective configuration options, but it is recommended to
|
||||
change both together if you decide to do so. (#33106)
|
||||
- gui#899 qt: Modernize custom filtering
|
||||
- gui#901 Add createwallet, createwalletdescriptor, and migratewallet to history filter
|
||||
|
||||
Other minimum feerates (e.g. the dust feerate, the minimum returned by the fee
|
||||
estimator, and all feerates used by the wallet) remain unchanged. The mempool minimum
|
||||
feerate still changes in response to high volume.
|
||||
### Test
|
||||
|
||||
Note that unless these lower defaults are widely adopted across the network, transactions
|
||||
created with lower fee rates are not guaranteed to propagate or confirm. The wallet
|
||||
feerates remain unchanged; `-mintxfee` must be changed before attempting to create
|
||||
transactions with lower feerates using the wallet. (#33106)
|
||||
- #33612 test: change log rate limit version gate
|
||||
|
||||
P2P and network changes
|
||||
-----------------------
|
||||
### Doc
|
||||
|
||||
- Opportunistic 1-parent-1-child package relay has been improved to handle
|
||||
situations when the child already has unconfirmed parent(s) in the mempool.
|
||||
This means that 1p1c packages can be accepted and propagate, even if they are
|
||||
connected to broader topologies: multi-parent-1-child (where only 1 parent
|
||||
requires fee-bumping), grandparent-parent-child (where only parent requires
|
||||
fee-bumping) etc. (#31385)
|
||||
- #33630 doc: correct topology requirements in submitpackage helptext
|
||||
- #33826 scripted-diff: Remove obsolete comment
|
||||
- #33827 doc: Correct pkgin command usage on NetBSD
|
||||
|
||||
- The transaction orphanage, which holds transactions with missing inputs temporarily
|
||||
while the node attempts to fetch its parents, now has improved Denial of Service protections.
|
||||
Previously, it enforced a maximum number of unique transactions (default 100,
|
||||
configurable using `-maxorphantx`). Now, its limits are as follows: the number of
|
||||
entries (unique by wtxid and peer), plus each unique transaction's input count divided
|
||||
by 10, must not exceed 3,000. The total weight of unique transactions must not exceed
|
||||
`404,000` Wu multiplied by the number of peers. (#31829)
|
||||
### Misc
|
||||
|
||||
- The `-maxorphantx` option no longer has any effect, since the orphanage no longer
|
||||
limits the number of unique transactions. Users should remove this configuration
|
||||
option if they were using it, as the setting will cause an error in future versions
|
||||
when it is no longer recognized. (#31829)
|
||||
|
||||
New `bitcoin` command
|
||||
---------------------
|
||||
|
||||
- A new `bitcoin` command line tool has been added to make features more discoverable
|
||||
and convenient to use. The `bitcoin` tool just calls other executables and does not
|
||||
implement any functionality on its own. Specifically `bitcoin node` is a synonym for
|
||||
`bitcoind`, `bitcoin gui` is a synonym for `bitcoin-qt`, and `bitcoin rpc` is a synonym
|
||||
for `bitcoin-cli -named`. Other commands and options can be listed with `bitcoin help`.
|
||||
The new `bitcoin` command is an alternative to calling other commands directly, but it
|
||||
doesn't replace them, and there are no plans to deprecate existing commands. (#31375)
|
||||
|
||||
External Signing
|
||||
----------------
|
||||
|
||||
- Support for external signing on Windows has been re-enabled. (#29868)
|
||||
|
||||
IPC Mining Interface
|
||||
--------------------
|
||||
|
||||
- The new `bitcoin` command does support one new feature: an (experimental) IPC Mining
|
||||
Interface that allows the node to work with Stratum v2 or other mining client software,
|
||||
see (#31098). When the node is started with `bitcoin -m node -ipcbind=unix` it will
|
||||
listen on a unix socket for IPC client connections, allowing clients to request block
|
||||
templates and submit mined blocks. The `-m` option launches a new internal binary
|
||||
(`bitcoin-node` instead of `bitcoind`) and is currently required but will become optional
|
||||
in the future (with [#33229](https://github.com/bitcoin/bitcoin/pull/33229)).
|
||||
|
||||
- IPC connectivity introduces new dependencies (see [multiprocess.md](https://github.com/bitcoin/bitcoin/blob/master/doc/multiprocess.md)),
|
||||
which can be turned off with the `-DENABLE_IPC=OFF` build option if you do not intend
|
||||
to use IPC. (#31802)
|
||||
|
||||
Install changes
|
||||
---------------
|
||||
|
||||
- The `test_bitcoin` executable is now installed in `libexec/` instead of `bin/`.
|
||||
It can still be executed directly, or accessed through the new `bitcoin` command
|
||||
as `bitcoin test`. The `libexec/` directory also contains new `bitcoin-node` and
|
||||
`bitcoin-gui` binaries which support IPC features and are called through the
|
||||
`bitcoin` tool. In source builds only, `test_bitcoin-qt`, `bench_bitcoin`, and
|
||||
`bitcoin-chainstate` are also now installed to `libexec/` instead of `bin/` and
|
||||
can be accessed through the new `bitcoin` command. See `bitcoin help` output for
|
||||
details. (#31679)
|
||||
|
||||
- On Windows, the installer no longer adds a “(64-bit)” suffix to entries in the
|
||||
Start Menu (#32132), and it now automatically removes obsolete artifacts during
|
||||
upgrades (#33422).
|
||||
|
||||
Indexes
|
||||
-------
|
||||
|
||||
- The implementation of coinstatsindex was changed to prevent an overflow bug that
|
||||
could already be observed on the default Signet. The new version of the index will
|
||||
need to be synced from scratch when starting the upgraded node for the first time.
|
||||
|
||||
The new version is stored in `/indexes/coinstatsindex/` in contrast to the old version
|
||||
which was stored at `/indexes/coinstats/`. The old version of the index is not deleted
|
||||
by the upgraded node in case the user chooses to downgrade their node in the future.
|
||||
If the user does not plan to downgrade it is safe for them to remove `/indexes/coinstats/`
|
||||
from their datadir. A future release of Bitcoin Core may remove the old version of the
|
||||
index automatically. (#30469)
|
||||
|
||||
Logging
|
||||
-------
|
||||
- Unconditional logging to disk is now rate limited by giving each source location
|
||||
a quota of 1MiB per hour. Unconditional logging is any logging with a log level
|
||||
higher than debug, that is `info`, `warning`, and `error`. All logs will be
|
||||
prefixed with `[*]` if there is at least one source location that is currently
|
||||
being suppressed. (#32604)
|
||||
|
||||
- When `-logsourcelocations` is enabled, the log output now contains the entire
|
||||
function signature instead of just the function name. (#32604)
|
||||
|
||||
Updated RPCs
|
||||
------------
|
||||
|
||||
- The `-paytxfee` startup option and the `settxfee` RPC are now deprecated and
|
||||
will be removed in Bitcoin Core 31.0. They allowed the user to set a static fee
|
||||
rate for wallet transactions, which could potentially lead to overpaying or underpaying.
|
||||
Users should instead rely on fee estimation or specify a fee rate per transaction
|
||||
using the `fee_rate` argument in RPCs such as `fundrawtransaction`, `sendtoaddress`,
|
||||
`send`, `sendall`, and `sendmany`. (#31278)
|
||||
|
||||
- Any RPC in which one of the parameters is a descriptor will throw an error
|
||||
if the provided descriptor contains a whitespace at the beginning or the end
|
||||
of the public key within a fragment - e.g. `pk( KEY)` or `pk(KEY )`. (#31603)
|
||||
|
||||
- The `submitpackage` RPC, which allows submissions of child-with-parents
|
||||
packages, no longer requires that all unconfirmed parents be present. The
|
||||
package may contain other in-mempool ancestors as well. (#31385)
|
||||
|
||||
- The `waitfornewblock` RPC now takes an optional `current_tip` argument. It
|
||||
is also no longer hidden. (#30635)
|
||||
|
||||
- The `waitforblock` and `waitforblockheight` RPCs are no longer hidden. (#30635)
|
||||
|
||||
- The `psbtbumpfee` and `bumpfee` RPCs allow a replacement under fullrbf and no
|
||||
longer require BIP-125 signalling. (#31953)
|
||||
|
||||
- Transaction Script validation errors used to return the reason for the error
|
||||
prefixed by either `mandatory-script-verify-flag-failed` if it was a consensus
|
||||
error, or `non-mandatory-script-verify-flag` (without "-failed") if it was a
|
||||
standardness error. This has been changed to `block-script-verify-flag-failed`
|
||||
and `mempool-script-verify-flag-failed` for all block and mempool errors
|
||||
respectively. (#33183)
|
||||
|
||||
- The `getmininginfo` RPC now returns "blockmintxfee" result specifying the value of
|
||||
`-blockmintxfee` configuration. (#33189)
|
||||
|
||||
- The `getmempoolinfo` RPC now returns an additional "permitbaremultisig" and
|
||||
"maxdatacarriersize" field, reflecting the `-permitbaremultisig` and `-datacarriersize`
|
||||
config values. (#29954)
|
||||
|
||||
Changes to wallet-related RPCs can be found in the Wallet section below.
|
||||
|
||||
New RPCs
|
||||
--------
|
||||
|
||||
- A new REST API endpoint (`/rest/spenttxouts/BLOCKHASH`) has been introduced for
|
||||
efficiently fetching spent transaction outputs using the block's undo data (#32540).
|
||||
|
||||
Build System
|
||||
------------
|
||||
|
||||
Updated settings
|
||||
----------------
|
||||
|
||||
- The `-maxmempool` and `-dbcache` startup parameters are now capped on 32-bit systems
|
||||
to 500MB and 1GiB respectively. (#32530)
|
||||
|
||||
- The `-natpmp` option is now set to `1` by default. This means nodes with `-listen`
|
||||
enabled (the default) but running behind a firewall, such as a local network router,
|
||||
will be reachable if the firewall/router supports any of the `PCP` or `NAT-PMP`
|
||||
protocols. (#33004)
|
||||
|
||||
- The `-upnp` setting has now been fully removed. Use `-natpmp` instead. (#32500)
|
||||
|
||||
- Previously, `-proxy` specified the proxy for all networks (except I2P which
|
||||
uses `-i2psam`) and only the Tor proxy could have been specified separately
|
||||
via `-onion`. Now, the syntax of `-proxy` has been extended and it is possible
|
||||
to specify separately the proxy for IPv4, IPv6, Tor and CJDNS by appending `=`
|
||||
followed by the network name, for example `-proxy=127.0.0.1:5555=ipv6`
|
||||
configures a proxy only for IPv6. The `-proxy` option can be used multiple
|
||||
times to define different proxies for different networks, such as
|
||||
`-proxy=127.0.0.1:4444=ipv4 -proxy=10.0.0.1:6666=ipv6`. Later settings
|
||||
override earlier ones for the same network; this can be used to remove an
|
||||
earlier all-networks proxy and use direct connections only for a given
|
||||
network, for example `-proxy=127.0.0.1:5555 -proxy=0=cjdns`. (#32425)
|
||||
|
||||
- The `-blockmaxweight` startup option has been updated to be debug-only.
|
||||
It is still available to users, but now hidden from the default `-help` text
|
||||
and shown only in `-help-debug` (#32654).
|
||||
|
||||
Changes to GUI or wallet related settings can be found in the GUI or Wallet section below.
|
||||
|
||||
Wallet
|
||||
------
|
||||
|
||||
- BDB legacy wallets can no longer be created or loaded. They can be migrated
|
||||
to the new descriptor wallet format. Refer to the `migratewallet` RPC for more
|
||||
details.
|
||||
|
||||
- The legacy wallet removal drops redundant options in the bitcoin-wallet tool,
|
||||
such as `-withinternalbdb`, `-legacy`, and `-descriptors`. Moreover, the
|
||||
legacy-only RPCs `addmultisigaddress`, `dumpprivkey`, `dumpwallet`,
|
||||
`importaddress`, `importmulti`, `importprivkey`, `importpubkey`,
|
||||
`importwallet`, `newkeypool`, `sethdseed`, and `upgradewallet`, are removed.
|
||||
(#32944, #28710, #32438, #31250)
|
||||
|
||||
- Support has been added for spending TRUC transactions received by the
|
||||
wallet, as well as creating TRUC transactions. The wallet ensures that
|
||||
TRUC policy rules are being met. The wallet will throw an error if the
|
||||
user is trying to spend TRUC utxos with utxos of other versions.
|
||||
Additionally, the wallet will treat unconfirmed TRUC sibling
|
||||
transactions as mempool conflicts. The wallet will also ensure that
|
||||
transactions spending TRUC utxos meet the required size restrictions. (#32896)
|
||||
|
||||
- Since descriptor wallets do not allow mixing watchonly and non-watchonly descriptors,
|
||||
the `include_watchonly` option (and its variants in naming) are removed from all RPCs
|
||||
that had it. (#32618)
|
||||
|
||||
- The `iswatchonly` field is removed from any RPCs that returned it. (#32618)
|
||||
|
||||
- `unloadwallet` - Return RPC_INVALID_PARAMETER when both the RPC wallet endpoint
|
||||
and wallet_name parameters are unspecified. Previously the RPC failed with a JSON
|
||||
parsing error. (#32845)
|
||||
|
||||
- `getdescriptoractivity` - Mark blockhashes and scanobjects arguments as required,
|
||||
so the user receives a clear help message when either is missing. As in `unloadwallet`,
|
||||
previously the RPC failed with a JSON parsing error. (#32845)
|
||||
|
||||
- `getwalletinfo` - Removes the fields `balance`, `immature_balance` and
|
||||
`unconfirmed_balance`. (#32721)
|
||||
|
||||
- `getunconfirmedbalance` - Removes this RPC command. You can query the `getbalances`
|
||||
RPC and inspect the `["mine"]["untrusted_pending"]` entry within the JSON
|
||||
response. (#32721)
|
||||
|
||||
- The following RPCs now contain a `version` parameter that allows
|
||||
the user to create transactions of any standard version number (1-3):
|
||||
- `createrawtransaction`
|
||||
- `createpsbt`
|
||||
- `send`
|
||||
- `sendall`
|
||||
- `walletcreatefundedpsbt`
|
||||
(#32896)
|
||||
|
||||
GUI changes
|
||||
-----------
|
||||
|
||||
- The GUI has been migrated from Qt 5 to Qt 6. On Windows, dark mode is now supported.
|
||||
On macOS, the Metal backend is now used. (#30997)
|
||||
|
||||
- A transaction's fee bump is allowed under fullrbf and no longer requires
|
||||
BIP-125 signalling. (#31953)
|
||||
|
||||
- Custom column widths in the Transactions tab are reset as a side-effect of legacy
|
||||
wallet removal. (#32459)
|
||||
|
||||
Low-level changes
|
||||
=================
|
||||
|
||||
- Logs now include which peer sent us a header. Additionally there are fewer
|
||||
redundant header log messages. A side-effect of this change is that for
|
||||
some untypical cases new headers aren't logged anymore, e.g. a direct
|
||||
`BLOCK` message with a previously unknown header and `submitheader` RPC. (#27826)
|
||||
- #33508 ci: fix buildx gha cache authentication on forks
|
||||
- #33558 ci: Use native platform for win-cross task
|
||||
- #33581 ci: Properly include $FILE_ENV in DEPENDS_HASH
|
||||
- #33744 ci: Fix lint runner selection (and docker cache)
|
||||
|
||||
Credits
|
||||
=======
|
||||
|
||||
Thanks to everyone who directly contributed to this release:
|
||||
|
||||
- 0xb10c
|
||||
- amisha
|
||||
- Andrew Toth
|
||||
- Anthony Towns
|
||||
- Antoine Poinsot
|
||||
- Ava Chow
|
||||
- benthecarman
|
||||
- Brandon Odiwuor
|
||||
- brunoerg
|
||||
- Bue-von-hon
|
||||
- Bufo
|
||||
- Chandra Pratap
|
||||
- Chris Stewart
|
||||
- Cory Fields
|
||||
- Daniel Pfeifer
|
||||
- Daniela Brozzoni
|
||||
- David Gumberg
|
||||
- deadmanoz
|
||||
- dennsikl
|
||||
- dergoegge
|
||||
- enoch
|
||||
- Ethan Heilman
|
||||
- Eugene Siegel
|
||||
- Eunovo
|
||||
- Eval EXEC
|
||||
- Fabian Jahr
|
||||
- fanquake
|
||||
- Florian Schmaus
|
||||
- fuder.eth
|
||||
- furszy
|
||||
- glozow
|
||||
- Greg Sanders
|
||||
- Hao Xu
|
||||
- Haoran Peng
|
||||
- Haowen Liu
|
||||
- Hennadii Stepanov
|
||||
- Hodlinator
|
||||
- hoffman
|
||||
- ishaanam
|
||||
- ismaelsadeeq
|
||||
- Jameson Lopp
|
||||
- janb84
|
||||
- Jiri Jakes
|
||||
- John Bampton
|
||||
- Jon Atack
|
||||
- josibake
|
||||
- jurraca
|
||||
- kevkevin
|
||||
- kevkevinpal
|
||||
- kilavvy
|
||||
- Kristaps Kaupe
|
||||
- l0rinc
|
||||
- laanwj
|
||||
- leopardracer
|
||||
- Lőrinc
|
||||
- Luis Schwab
|
||||
- Luke Dashjr
|
||||
- MarcoFalke
|
||||
- marcofleon
|
||||
- Martin Zumsande
|
||||
- Matt Corallo
|
||||
- Matthew Zipkin
|
||||
- Max Edwards
|
||||
- monlovesmango
|
||||
- Murch
|
||||
- naiyoma
|
||||
- nervana21
|
||||
- Nicola Leonardo Susca
|
||||
- Novo
|
||||
- pablomartin4btc
|
||||
- Peter Todd
|
||||
- Pieter Wuille
|
||||
- Pol Espinasa
|
||||
- Prabhat Verma
|
||||
- rkrux
|
||||
- Roman Zeyde
|
||||
- Ryan Ofsky
|
||||
- Saikiran
|
||||
- Salvatore Ingala
|
||||
- Sebastian Falbesoner
|
||||
- Sergi Delgado Segura
|
||||
- Shunsuke Shimizu
|
||||
- Sjors Provoost
|
||||
- stickies-v
|
||||
- stratospher
|
||||
- stringintech
|
||||
- strmfos
|
||||
- stutxo
|
||||
- tdb3
|
||||
- TheCharlatan
|
||||
- Tomás Andróil
|
||||
- UdjinM6
|
||||
- Vasil Dimov
|
||||
- VolodymyrBg
|
||||
- w0xlt
|
||||
- will
|
||||
- WakeTrainDev
|
||||
- willcl-ark
|
||||
- William Casarin
|
||||
- woltx
|
||||
- yancy
|
||||
- zaidmstrr
|
||||
|
||||
As well as to everyone that helped with translations on
|
||||
[Transifex](https://explore.transifex.com/bitcoin/bitcoin/).
|
||||
|
||||
@ -292,7 +292,7 @@ if(BUILD_BITCOIN_BIN)
|
||||
add_executable(bitcoin bitcoin.cpp)
|
||||
add_windows_resources(bitcoin bitcoin-res.rc)
|
||||
add_windows_application_manifest(bitcoin)
|
||||
target_link_libraries(bitcoin core_interface bitcoin_util)
|
||||
target_link_libraries(bitcoin core_interface bitcoin_common bitcoin_util)
|
||||
install_binary_component(bitcoin HAS_MANPAGE)
|
||||
endif()
|
||||
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#include <bitcoin-build-config.h> // IWYU pragma: keep
|
||||
|
||||
#include <clientversion.h>
|
||||
#include <common/args.h>
|
||||
#include <util/fs.h>
|
||||
#include <util/exec.h>
|
||||
#include <util/strencodings.h>
|
||||
@ -47,7 +48,7 @@ Run '%s help' to see additional commands (e.g. for testing and debugging).
|
||||
)";
|
||||
|
||||
struct CommandLine {
|
||||
bool use_multiprocess{false};
|
||||
std::optional<bool> use_multiprocess;
|
||||
bool show_version{false};
|
||||
bool show_help{false};
|
||||
std::string_view command;
|
||||
@ -55,6 +56,7 @@ struct CommandLine {
|
||||
};
|
||||
|
||||
CommandLine ParseCommandLine(int argc, char* argv[]);
|
||||
bool UseMultiprocess(const CommandLine& cmd);
|
||||
static void ExecCommand(const std::vector<const char*>& args, std::string_view argv0);
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
@ -78,9 +80,9 @@ int main(int argc, char* argv[])
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
} else if (cmd.command == "gui") {
|
||||
args.emplace_back(cmd.use_multiprocess ? "bitcoin-gui" : "bitcoin-qt");
|
||||
args.emplace_back(UseMultiprocess(cmd) ? "bitcoin-gui" : "bitcoin-qt");
|
||||
} else if (cmd.command == "node") {
|
||||
args.emplace_back(cmd.use_multiprocess ? "bitcoin-node" : "bitcoind");
|
||||
args.emplace_back(UseMultiprocess(cmd) ? "bitcoin-node" : "bitcoind");
|
||||
} else if (cmd.command == "rpc") {
|
||||
args.emplace_back("bitcoin-cli");
|
||||
// Since "bitcoin rpc" is a new interface that doesn't need to be
|
||||
@ -143,6 +145,30 @@ CommandLine ParseCommandLine(int argc, char* argv[])
|
||||
return cmd;
|
||||
}
|
||||
|
||||
bool UseMultiprocess(const CommandLine& cmd)
|
||||
{
|
||||
// If -m or -M options were explicitly specified, there is no need to
|
||||
// further parse arguments to determine which to use.
|
||||
if (cmd.use_multiprocess) return *cmd.use_multiprocess;
|
||||
|
||||
ArgsManager args;
|
||||
args.SetDefaultFlags(ArgsManager::ALLOW_ANY);
|
||||
std::string error_message;
|
||||
auto argv{cmd.args};
|
||||
argv.insert(argv.begin(), nullptr);
|
||||
if (!args.ParseParameters(argv.size(), argv.data(), error_message)) {
|
||||
tfm::format(std::cerr, "Warning: failed to parse subcommand command line options: %s\n", error_message);
|
||||
}
|
||||
if (!args.ReadConfigFiles(error_message, true)) {
|
||||
tfm::format(std::cerr, "Warning: failed to parse subcommand config: %s\n", error_message);
|
||||
}
|
||||
args.SelectConfigNetwork(args.GetChainTypeString());
|
||||
|
||||
// If any -ipc* options are set these need to be processed by a
|
||||
// multiprocess-capable binary.
|
||||
return args.IsArgSet("-ipcbind") || args.IsArgSet("-ipcconnect") || args.IsArgSet("-ipcfd");
|
||||
}
|
||||
|
||||
//! Execute the specified bitcoind, bitcoin-qt or other command line in `args`
|
||||
//! using src, bin and libexec directory paths relative to this executable, where
|
||||
//! the path to this executable is specified in `wrapper_argv0`.
|
||||
|
||||
@ -132,11 +132,16 @@ static bool ParseArgs(NodeContext& node, int argc, char* argv[])
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ProcessInitCommands(ArgsManager& args)
|
||||
static bool ProcessInitCommands(interfaces::Init& init, ArgsManager& args)
|
||||
{
|
||||
// Process help and version before taking care about datadir
|
||||
if (HelpRequested(args) || args.GetBoolArg("-version", false)) {
|
||||
std::string strUsage = CLIENT_NAME " daemon version " + FormatFullVersion() + "\n";
|
||||
std::string strUsage = CLIENT_NAME " daemon version " + FormatFullVersion();
|
||||
if (const char* exe_name{init.exeName()}) {
|
||||
strUsage += " ";
|
||||
strUsage += exe_name;
|
||||
}
|
||||
strUsage += "\n";
|
||||
|
||||
if (args.GetBoolArg("-version", false)) {
|
||||
strUsage += FormatParagraph(LicenseInfo());
|
||||
@ -277,7 +282,7 @@ MAIN_FUNCTION
|
||||
ArgsManager& args = *Assert(node.args);
|
||||
if (!ParseArgs(node, argc, argv)) return EXIT_FAILURE;
|
||||
// Process early info return commands such as -help or -version
|
||||
if (ProcessInitCommands(args)) return EXIT_SUCCESS;
|
||||
if (ProcessInitCommands(*init, args)) return EXIT_SUCCESS;
|
||||
|
||||
// Start application
|
||||
if (!AppInit(node) || !Assert(node.shutdown_signal)->wait()) {
|
||||
|
||||
@ -266,7 +266,13 @@ std::optional<unsigned int> ArgsManager::GetArgFlags(const std::string& name) co
|
||||
return search->second.m_flags;
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
return m_default_flags;
|
||||
}
|
||||
|
||||
void ArgsManager::SetDefaultFlags(std::optional<unsigned int> flags)
|
||||
{
|
||||
LOCK(cs_args);
|
||||
m_default_flags = flags;
|
||||
}
|
||||
|
||||
fs::path ArgsManager::GetPathArg(std::string arg, const fs::path& default_value) const
|
||||
|
||||
@ -137,6 +137,7 @@ protected:
|
||||
std::string m_network GUARDED_BY(cs_args);
|
||||
std::set<std::string> m_network_only_args GUARDED_BY(cs_args);
|
||||
std::map<OptionsCategory, std::map<std::string, Arg>> m_available_args GUARDED_BY(cs_args);
|
||||
std::optional<unsigned int> m_default_flags GUARDED_BY(cs_args){};
|
||||
bool m_accept_any_command GUARDED_BY(cs_args){true};
|
||||
std::list<SectionInfo> m_config_sections GUARDED_BY(cs_args);
|
||||
std::optional<fs::path> m_config_path GUARDED_BY(cs_args);
|
||||
@ -375,10 +376,15 @@ protected:
|
||||
|
||||
/**
|
||||
* Return Flags for known arg.
|
||||
* Return nullopt for unknown arg.
|
||||
* Return default flags for unknown arg.
|
||||
*/
|
||||
std::optional<unsigned int> GetArgFlags(const std::string& name) const;
|
||||
|
||||
/**
|
||||
* Set default flags to return for an unknown arg.
|
||||
*/
|
||||
void SetDefaultFlags(std::optional<unsigned int>);
|
||||
|
||||
/**
|
||||
* Get settings file path, or return false if read-write settings were
|
||||
* disabled with -nosettings.
|
||||
|
||||
@ -39,6 +39,7 @@ public:
|
||||
// bitcoin-node accepts the option, and bitcoin-gui accepts all bitcoin-node
|
||||
// options and will start the node with those options.
|
||||
bool canListenIpc() override { return true; }
|
||||
const char* exeName() override { return EXE_NAME; }
|
||||
node::NodeContext m_node;
|
||||
std::unique_ptr<interfaces::Ipc> m_ipc;
|
||||
};
|
||||
|
||||
@ -38,6 +38,7 @@ public:
|
||||
std::unique_ptr<interfaces::Echo> makeEcho() override { return interfaces::MakeEcho(); }
|
||||
interfaces::Ipc* ipc() override { return m_ipc.get(); }
|
||||
bool canListenIpc() override { return true; }
|
||||
const char* exeName() override { return EXE_NAME; }
|
||||
node::NodeContext& m_node;
|
||||
std::unique_ptr<interfaces::Ipc> m_ipc;
|
||||
};
|
||||
|
||||
@ -16,6 +16,8 @@
|
||||
|
||||
namespace init {
|
||||
namespace {
|
||||
const char* EXE_NAME = "bitcoin-qt";
|
||||
|
||||
class BitcoinQtInit : public interfaces::Init
|
||||
{
|
||||
public:
|
||||
@ -32,6 +34,7 @@ public:
|
||||
return MakeWalletLoader(chain, *Assert(m_node.args));
|
||||
}
|
||||
std::unique_ptr<interfaces::Echo> makeEcho() override { return interfaces::MakeEcho(); }
|
||||
const char* exeName() override { return EXE_NAME; }
|
||||
node::NodeContext m_node;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
@ -18,6 +18,8 @@ using node::NodeContext;
|
||||
|
||||
namespace init {
|
||||
namespace {
|
||||
const char* EXE_NAME = "bitcoind";
|
||||
|
||||
class BitcoindInit : public interfaces::Init
|
||||
{
|
||||
public:
|
||||
@ -34,6 +36,7 @@ public:
|
||||
return MakeWalletLoader(chain, *Assert(m_node.args));
|
||||
}
|
||||
std::unique_ptr<interfaces::Echo> makeEcho() override { return interfaces::MakeEcho(); }
|
||||
const char* exeName() override { return EXE_NAME; }
|
||||
NodeContext& m_node;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
@ -38,6 +38,7 @@ public:
|
||||
virtual std::unique_ptr<Echo> makeEcho() { return nullptr; }
|
||||
virtual Ipc* ipc() { return nullptr; }
|
||||
virtual bool canListenIpc() { return false; }
|
||||
virtual const char* exeName() { return nullptr; }
|
||||
};
|
||||
|
||||
//! Return implementation of Init interface for the node process. If the argv
|
||||
|
||||
@ -72,6 +72,11 @@ public:
|
||||
* the tip is more than 20 minutes old.
|
||||
*/
|
||||
virtual std::unique_ptr<BlockTemplate> waitNext(const node::BlockWaitOptions options = {}) = 0;
|
||||
|
||||
/**
|
||||
* Interrupts the current wait for the next block template.
|
||||
*/
|
||||
virtual void interruptWait() = 0;
|
||||
};
|
||||
|
||||
//! Interface giving clients (RPC, Stratum v2 Template Provider in the future)
|
||||
|
||||
@ -33,6 +33,7 @@ interface BlockTemplate $Proxy.wrap("interfaces::BlockTemplate") {
|
||||
getCoinbaseMerklePath @8 (context: Proxy.Context) -> (result: List(Data));
|
||||
submitSolution @9 (context: Proxy.Context, version: UInt32, timestamp: UInt32, nonce: UInt32, coinbase :Data) -> (result: Bool);
|
||||
waitNext @10 (context: Proxy.Context, options: BlockWaitOptions) -> (result: BlockTemplate);
|
||||
interruptWait @11() -> ();
|
||||
}
|
||||
|
||||
struct BlockCreateOptions $Proxy.wrap("node::BlockCreateOptions") {
|
||||
|
||||
@ -30,10 +30,36 @@
|
||||
namespace ipc {
|
||||
namespace capnp {
|
||||
namespace {
|
||||
void IpcLogFn(bool raise, std::string message)
|
||||
|
||||
BCLog::Level ConvertIPCLogLevel(mp::Log level)
|
||||
{
|
||||
LogDebug(BCLog::IPC, "%s\n", message);
|
||||
if (raise) throw Exception(message);
|
||||
switch (level) {
|
||||
case mp::Log::Trace: return BCLog::Level::Trace;
|
||||
case mp::Log::Debug: return BCLog::Level::Debug;
|
||||
case mp::Log::Info: return BCLog::Level::Info;
|
||||
case mp::Log::Warning: return BCLog::Level::Warning;
|
||||
case mp::Log::Error: return BCLog::Level::Error;
|
||||
case mp::Log::Raise: return BCLog::Level::Error;
|
||||
} // no default case, so the compiler can warn about missing cases
|
||||
|
||||
// Be conservative and assume that if MP ever adds a new log level, it
|
||||
// should only be shown at our most verbose level.
|
||||
return BCLog::Level::Trace;
|
||||
}
|
||||
|
||||
mp::Log GetRequestedIPCLogLevel()
|
||||
{
|
||||
if (LogAcceptCategory(BCLog::IPC, BCLog::Level::Trace)) return mp::Log::Trace;
|
||||
if (LogAcceptCategory(BCLog::IPC, BCLog::Level::Debug)) return mp::Log::Debug;
|
||||
|
||||
// Info, Warning, and Error are logged unconditionally
|
||||
return mp::Log::Info;
|
||||
}
|
||||
|
||||
void IpcLogFn(mp::LogMessage message)
|
||||
{
|
||||
LogPrintLevel(BCLog::IPC, ConvertIPCLogLevel(message.level), "%s\n", message.message);
|
||||
if (message.level == mp::Log::Raise) throw Exception(message.message);
|
||||
}
|
||||
|
||||
class CapnpProtocol : public Protocol
|
||||
@ -62,7 +88,11 @@ public:
|
||||
{
|
||||
assert(!m_loop);
|
||||
mp::g_thread_context.thread_name = mp::ThreadName(exe_name);
|
||||
m_loop.emplace(exe_name, &IpcLogFn, &m_context);
|
||||
mp::LogOptions opts = {
|
||||
.log_fn = IpcLogFn,
|
||||
.log_level = GetRequestedIPCLogLevel()
|
||||
};
|
||||
m_loop.emplace(exe_name, std::move(opts), &m_context);
|
||||
if (ready_fn) ready_fn();
|
||||
mp::ServeStream<messages::Init>(*m_loop, fd, init);
|
||||
m_parent_connection = &m_loop->m_incoming_connections.back();
|
||||
@ -90,7 +120,11 @@ public:
|
||||
std::promise<void> promise;
|
||||
m_loop_thread = std::thread([&] {
|
||||
util::ThreadRename("capnp-loop");
|
||||
m_loop.emplace(exe_name, &IpcLogFn, &m_context);
|
||||
mp::LogOptions opts = {
|
||||
.log_fn = IpcLogFn,
|
||||
.log_level = GetRequestedIPCLogLevel()
|
||||
};
|
||||
m_loop.emplace(exe_name, std::move(opts), &m_context);
|
||||
m_loop_ref.emplace(*m_loop);
|
||||
promise.set_value();
|
||||
m_loop->loop();
|
||||
|
||||
@ -918,15 +918,21 @@ public:
|
||||
|
||||
std::unique_ptr<BlockTemplate> waitNext(BlockWaitOptions options) override
|
||||
{
|
||||
auto new_template = WaitAndCreateNewBlock(chainman(), notifications(), m_node.mempool.get(), m_block_template, options, m_assemble_options);
|
||||
auto new_template = WaitAndCreateNewBlock(chainman(), notifications(), m_node.mempool.get(), m_block_template, options, m_assemble_options, m_interrupt_wait);
|
||||
if (new_template) return std::make_unique<BlockTemplateImpl>(m_assemble_options, std::move(new_template), m_node);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void interruptWait() override
|
||||
{
|
||||
InterruptWait(notifications(), m_interrupt_wait);
|
||||
}
|
||||
|
||||
const BlockAssembler::Options m_assemble_options;
|
||||
|
||||
const std::unique_ptr<CBlockTemplate> m_block_template;
|
||||
|
||||
bool m_interrupt_wait{false};
|
||||
ChainstateManager& chainman() { return *Assert(m_node.chainman); }
|
||||
KernelNotifications& notifications() { return *Assert(m_node.notifications); }
|
||||
NodeContext& m_node;
|
||||
|
||||
@ -29,6 +29,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
#include <numeric>
|
||||
|
||||
namespace node {
|
||||
|
||||
@ -453,12 +454,20 @@ void AddMerkleRootAndCoinbase(CBlock& block, CTransactionRef coinbase, uint32_t
|
||||
block.hashMerkleRoot = BlockMerkleRoot(block);
|
||||
}
|
||||
|
||||
void InterruptWait(KernelNotifications& kernel_notifications, bool& interrupt_wait)
|
||||
{
|
||||
LOCK(kernel_notifications.m_tip_block_mutex);
|
||||
interrupt_wait = true;
|
||||
kernel_notifications.m_tip_block_cv.notify_all();
|
||||
}
|
||||
|
||||
std::unique_ptr<CBlockTemplate> WaitAndCreateNewBlock(ChainstateManager& chainman,
|
||||
KernelNotifications& kernel_notifications,
|
||||
CTxMemPool* mempool,
|
||||
const std::unique_ptr<CBlockTemplate>& block_template,
|
||||
const BlockWaitOptions& options,
|
||||
const BlockAssembler::Options& assemble_options)
|
||||
const BlockAssembler::Options& assemble_options,
|
||||
bool& interrupt_wait)
|
||||
{
|
||||
// Delay calculating the current template fees, just in case a new block
|
||||
// comes in before the next tick.
|
||||
@ -483,8 +492,12 @@ std::unique_ptr<CBlockTemplate> WaitAndCreateNewBlock(ChainstateManager& chainma
|
||||
// method on BlockTemplate and no template could have been
|
||||
// generated before a tip exists.
|
||||
tip_changed = Assume(tip_block) && tip_block != block_template->block.hashPrevBlock;
|
||||
return tip_changed || chainman.m_interrupt;
|
||||
return tip_changed || chainman.m_interrupt || interrupt_wait;
|
||||
});
|
||||
if (interrupt_wait) {
|
||||
interrupt_wait = false;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (chainman.m_interrupt) return nullptr;
|
||||
@ -522,18 +535,13 @@ std::unique_ptr<CBlockTemplate> WaitAndCreateNewBlock(ChainstateManager& chainma
|
||||
|
||||
// Calculate the original template total fees if we haven't already
|
||||
if (current_fees == -1) {
|
||||
current_fees = 0;
|
||||
for (CAmount fee : block_template->vTxFees) {
|
||||
current_fees += fee;
|
||||
}
|
||||
current_fees = std::accumulate(block_template->vTxFees.begin(), block_template->vTxFees.end(), CAmount{0});
|
||||
}
|
||||
|
||||
CAmount new_fees = 0;
|
||||
for (CAmount fee : new_tmpl->vTxFees) {
|
||||
new_fees += fee;
|
||||
Assume(options.fee_threshold != MAX_MONEY);
|
||||
if (new_fees >= current_fees + options.fee_threshold) return new_tmpl;
|
||||
}
|
||||
// Check if fees increased enough to return the new template
|
||||
const CAmount new_fees = std::accumulate(new_tmpl->vTxFees.begin(), new_tmpl->vTxFees.end(), CAmount{0});
|
||||
Assume(options.fee_threshold != MAX_MONEY);
|
||||
if (new_fees >= current_fees + options.fee_threshold) return new_tmpl;
|
||||
}
|
||||
|
||||
now = NodeClock::now();
|
||||
|
||||
@ -238,6 +238,9 @@ void ApplyArgsManOptions(const ArgsManager& gArgs, BlockAssembler::Options& opti
|
||||
/* Compute the block's merkle root, insert or replace the coinbase transaction and the merkle root into the block */
|
||||
void AddMerkleRootAndCoinbase(CBlock& block, CTransactionRef coinbase, uint32_t version, uint32_t timestamp, uint32_t nonce);
|
||||
|
||||
|
||||
/* Interrupt the current wait for the next block template. */
|
||||
void InterruptWait(KernelNotifications& kernel_notifications, bool& interrupt_wait);
|
||||
/**
|
||||
* Return a new block template when fees rise to a certain threshold or after a
|
||||
* new tip; return nullopt if timeout is reached.
|
||||
@ -247,7 +250,8 @@ std::unique_ptr<CBlockTemplate> WaitAndCreateNewBlock(ChainstateManager& chainma
|
||||
CTxMemPool* mempool,
|
||||
const std::unique_ptr<CBlockTemplate>& block_template,
|
||||
const BlockWaitOptions& options,
|
||||
const BlockAssembler::Options& assemble_options);
|
||||
const BlockAssembler::Options& assemble_options,
|
||||
bool& interrupt_wait);
|
||||
|
||||
/* Locks cs_main and returns the block hash and block height of the active chain if it exists; otherwise, returns nullopt.*/
|
||||
std::optional<BlockRef> GetTip(ChainstateManager& chainman);
|
||||
|
||||
@ -72,6 +72,9 @@ namespace {
|
||||
|
||||
// don't add private key handling cmd's to the history
|
||||
const QStringList historyFilter = QStringList()
|
||||
<< "createwallet"
|
||||
<< "createwalletdescriptor"
|
||||
<< "migratewallet"
|
||||
<< "signmessagewithprivkey"
|
||||
<< "signrawtransactionwithkey"
|
||||
<< "walletpassphrase"
|
||||
|
||||
@ -52,32 +52,78 @@ bool TransactionFilterProxy::filterAcceptsRow(int sourceRow, const QModelIndex &
|
||||
|
||||
void TransactionFilterProxy::setDateRange(const std::optional<QDateTime>& from, const std::optional<QDateTime>& to)
|
||||
{
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0)
|
||||
beginFilterChange();
|
||||
#endif
|
||||
|
||||
dateFrom = from;
|
||||
dateTo = to;
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0)
|
||||
endFilterChange(QSortFilterProxyModel::Direction::Rows);
|
||||
#else
|
||||
invalidateFilter();
|
||||
#endif
|
||||
}
|
||||
|
||||
void TransactionFilterProxy::setSearchString(const QString &search_string)
|
||||
{
|
||||
if (m_search_string == search_string) return;
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0)
|
||||
beginFilterChange();
|
||||
#endif
|
||||
|
||||
m_search_string = search_string;
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0)
|
||||
endFilterChange(QSortFilterProxyModel::Direction::Rows);
|
||||
#else
|
||||
invalidateFilter();
|
||||
#endif
|
||||
}
|
||||
|
||||
void TransactionFilterProxy::setTypeFilter(quint32 modes)
|
||||
{
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0)
|
||||
beginFilterChange();
|
||||
#endif
|
||||
|
||||
this->typeFilter = modes;
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0)
|
||||
endFilterChange(QSortFilterProxyModel::Direction::Rows);
|
||||
#else
|
||||
invalidateFilter();
|
||||
#endif
|
||||
}
|
||||
|
||||
void TransactionFilterProxy::setMinAmount(const CAmount& minimum)
|
||||
{
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0)
|
||||
beginFilterChange();
|
||||
#endif
|
||||
|
||||
this->minAmount = minimum;
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0)
|
||||
endFilterChange(QSortFilterProxyModel::Direction::Rows);
|
||||
#else
|
||||
invalidateFilter();
|
||||
#endif
|
||||
}
|
||||
|
||||
void TransactionFilterProxy::setShowInactive(bool _showInactive)
|
||||
{
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0)
|
||||
beginFilterChange();
|
||||
#endif
|
||||
|
||||
this->showInactive = _showInactive;
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0)
|
||||
endFilterChange(QSortFilterProxyModel::Direction::Rows);
|
||||
#else
|
||||
invalidateFilter();
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -936,8 +936,9 @@ static RPCHelpMan submitpackage()
|
||||
,
|
||||
{
|
||||
{"package", RPCArg::Type::ARR, RPCArg::Optional::NO, "An array of raw transactions.\n"
|
||||
"The package must solely consist of a child transaction and all of its unconfirmed parents, if any. None of the parents may depend on each other.\n"
|
||||
"The package must be topologically sorted, with the child being the last element in the array.",
|
||||
"The package must consist of a transaction with (some, all, or none of) its unconfirmed parents. A single transaction is permitted.\n"
|
||||
"None of the parents may depend on each other. Parents that are already in mempool do not need to be present in the package.\n"
|
||||
"The package must be topologically sorted, with the child being the last element in the array if there are multiple elements.",
|
||||
{
|
||||
{"rawtx", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, ""},
|
||||
},
|
||||
|
||||
@ -113,6 +113,22 @@ void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const
|
||||
options.coinbase_output_script = scriptPubKey;
|
||||
|
||||
LOCK(tx_mempool.cs);
|
||||
BOOST_CHECK(tx_mempool.size() == 0);
|
||||
|
||||
// Block template should only have a coinbase when there's nothing in the mempool
|
||||
std::unique_ptr<BlockTemplate> block_template = mining->createNewBlock(options);
|
||||
BOOST_REQUIRE(block_template);
|
||||
CBlock block{block_template->getBlock()};
|
||||
BOOST_REQUIRE_EQUAL(block.vtx.size(), 1U);
|
||||
|
||||
// waitNext() on an empty mempool should return nullptr because there is no better template
|
||||
auto should_be_nullptr = block_template->waitNext({.timeout = MillisecondsDouble{0}, .fee_threshold = 1});
|
||||
BOOST_REQUIRE(should_be_nullptr == nullptr);
|
||||
|
||||
// Unless fee_threshold is 0
|
||||
block_template = block_template->waitNext({.timeout = MillisecondsDouble{0}, .fee_threshold = 0});
|
||||
BOOST_REQUIRE(block_template);
|
||||
|
||||
// Test the ancestor feerate transaction selection.
|
||||
TestMemPoolEntryHelper entry;
|
||||
|
||||
@ -144,9 +160,9 @@ void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const
|
||||
const auto high_fee_tx{entry.Fee(50000).Time(Now<NodeSeconds>()).SpendsCoinbase(false).FromTx(tx)};
|
||||
AddToMempool(tx_mempool, high_fee_tx);
|
||||
|
||||
std::unique_ptr<BlockTemplate> block_template = mining->createNewBlock(options);
|
||||
block_template = mining->createNewBlock(options);
|
||||
BOOST_REQUIRE(block_template);
|
||||
CBlock block{block_template->getBlock()};
|
||||
block = block_template->getBlock();
|
||||
BOOST_REQUIRE_EQUAL(block.vtx.size(), 4U);
|
||||
BOOST_CHECK(block.vtx[1]->GetHash() == hashParentTx);
|
||||
BOOST_CHECK(block.vtx[2]->GetHash() == hashHighFeeTx);
|
||||
@ -184,7 +200,7 @@ void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const
|
||||
AddToMempool(tx_mempool, entry.Fee(feeToUse).FromTx(tx));
|
||||
|
||||
// waitNext() should return nullptr because there is no better template
|
||||
auto should_be_nullptr = block_template->waitNext({.timeout = MillisecondsDouble{0}, .fee_threshold = 1});
|
||||
should_be_nullptr = block_template->waitNext({.timeout = MillisecondsDouble{0}, .fee_threshold = 1});
|
||||
BOOST_REQUIRE(should_be_nullptr == nullptr);
|
||||
|
||||
block = block_template->getBlock();
|
||||
|
||||
@ -153,6 +153,7 @@ class IPCInterfaceTest(BitcoinTestFramework):
|
||||
self.log.debug("Wait for a new template")
|
||||
waitoptions = self.capnp_modules['mining'].BlockWaitOptions()
|
||||
waitoptions.timeout = timeout
|
||||
waitoptions.feeThreshold = 1
|
||||
waitnext = template.result.waitNext(ctx, waitoptions)
|
||||
self.generate(self.nodes[0], 1)
|
||||
template2 = await waitnext
|
||||
@ -168,6 +169,7 @@ class IPCInterfaceTest(BitcoinTestFramework):
|
||||
block3 = await self.parse_and_deserialize_block(template4, ctx)
|
||||
assert_equal(len(block3.vtx), 2)
|
||||
self.log.debug("Wait again, this should return the same template, since the fee threshold is zero")
|
||||
waitoptions.feeThreshold = 0
|
||||
template5 = await template4.result.waitNext(ctx, waitoptions)
|
||||
block4 = await self.parse_and_deserialize_block(template5, ctx)
|
||||
assert_equal(len(block4.vtx), 2)
|
||||
@ -182,6 +184,28 @@ class IPCInterfaceTest(BitcoinTestFramework):
|
||||
template7 = await template6.result.waitNext(ctx, waitoptions)
|
||||
assert_equal(template7.to_dict(), {})
|
||||
|
||||
self.log.debug("interruptWait should abort the current wait")
|
||||
wait_started = asyncio.Event()
|
||||
async def wait_for_block():
|
||||
new_waitoptions = self.capnp_modules['mining'].BlockWaitOptions()
|
||||
new_waitoptions.timeout = waitoptions.timeout * 60 # 1 minute wait
|
||||
new_waitoptions.feeThreshold = 1
|
||||
wait_started.set()
|
||||
return await template6.result.waitNext(ctx, new_waitoptions)
|
||||
|
||||
async def interrupt_wait():
|
||||
await wait_started.wait() # Wait for confirmation wait started
|
||||
await asyncio.sleep(0.1) # Minimal buffer
|
||||
template6.result.interruptWait()
|
||||
miniwallet.send_self_transfer(fee_rate=10, from_node=self.nodes[0])
|
||||
|
||||
wait_task = asyncio.create_task(wait_for_block())
|
||||
interrupt_task = asyncio.create_task(interrupt_wait())
|
||||
|
||||
result = await wait_task
|
||||
await interrupt_task
|
||||
assert_equal(result.to_dict(), {})
|
||||
|
||||
current_block_height = self.nodes[0].getchaintips()[0]["height"]
|
||||
check_opts = self.capnp_modules['mining'].BlockCheckOptions()
|
||||
template = await mining.result.createNewBlock(opts)
|
||||
|
||||
@ -161,7 +161,7 @@ class TestNode():
|
||||
self.args.append("-logsourcelocations")
|
||||
if self.version_is_at_least(239000):
|
||||
self.args.append("-loglevel=trace")
|
||||
if self.version_is_at_least(299900):
|
||||
if self.version_is_at_least(290100):
|
||||
self.args.append("-nologratelimit")
|
||||
|
||||
# Default behavior from global -v2transport flag is added to args to persist it over restarts.
|
||||
|
||||
@ -336,6 +336,7 @@ BASE_SCRIPTS = [
|
||||
'p2p_tx_privacy.py',
|
||||
'rpc_getdescriptoractivity.py',
|
||||
'rpc_scanblocks.py',
|
||||
'tool_bitcoin.py',
|
||||
'p2p_sendtxrcncl.py',
|
||||
'rpc_scantxoutset.py',
|
||||
'feature_unsupported_utxo_db.py',
|
||||
|
||||
111
test/functional/tool_bitcoin.py
Executable file
111
test/functional/tool_bitcoin.py
Executable file
@ -0,0 +1,111 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (c) The Bitcoin Core developers
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
"""Test the bitcoin wrapper tool."""
|
||||
from test_framework.test_framework import (
|
||||
BitcoinTestFramework,
|
||||
SkipTest,
|
||||
)
|
||||
from test_framework.util import (
|
||||
append_config,
|
||||
assert_equal,
|
||||
)
|
||||
|
||||
import platform
|
||||
import re
|
||||
|
||||
|
||||
class ToolBitcoinTest(BitcoinTestFramework):
|
||||
def set_test_params(self):
|
||||
self.setup_clean_chain = True
|
||||
self.num_nodes = 1
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
# Skip test on windows because currently when `bitcoin node -version` is
|
||||
# run on windows, python doesn't capture output from the child
|
||||
# `bitcoind` and `bitcoin-node` process started with _wexecvp, and
|
||||
# stdout/stderr are always empty. See
|
||||
# https://github.com/bitcoin/bitcoin/pull/33229#issuecomment-3265524908
|
||||
if platform.system() == "Windows":
|
||||
raise SkipTest("Test does not currently work on windows")
|
||||
|
||||
def setup_network(self):
|
||||
"""Set up nodes normally, but save a copy of their arguments before starting them."""
|
||||
self.add_nodes(self.num_nodes, self.extra_args)
|
||||
node_argv = self.get_binaries().node_argv()
|
||||
self.node_options = [node.args[len(node_argv):] for node in self.nodes]
|
||||
assert all(node.args[:len(node_argv)] == node_argv for node in self.nodes)
|
||||
|
||||
def set_cmd_args(self, node, args):
|
||||
"""Set up node so it will be started through bitcoin wrapper command with specified arguments."""
|
||||
node.args = [self.binary_paths.bitcoin_bin] + args + ["node"] + self.node_options[node.index]
|
||||
|
||||
def test_args(self, cmd_args, node_args, expect_exe=None, expect_error=None):
|
||||
node = self.nodes[0]
|
||||
self.set_cmd_args(node, cmd_args)
|
||||
extra_args = node_args + ["-version"]
|
||||
if expect_error is not None:
|
||||
node.assert_start_raises_init_error(expected_msg=expect_error, extra_args=extra_args)
|
||||
else:
|
||||
assert expect_exe
|
||||
node.start(extra_args=extra_args)
|
||||
ret, out, err = get_node_output(node)
|
||||
try:
|
||||
assert_equal(get_exe_name(out), expect_exe.encode())
|
||||
assert_equal(err, b"")
|
||||
except Exception as e:
|
||||
raise RuntimeError(f"Unexpected output from {node.args + extra_args}: {out=!r} {err=!r} {ret=!r}") from e
|
||||
|
||||
def run_test(self):
|
||||
node = self.nodes[0]
|
||||
|
||||
self.log.info("Ensure bitcoin node command invokes bitcoind by default")
|
||||
self.test_args([], [], expect_exe="bitcoind")
|
||||
|
||||
self.log.info("Ensure bitcoin -M invokes bitcoind")
|
||||
self.test_args(["-M"], [], expect_exe="bitcoind")
|
||||
|
||||
self.log.info("Ensure bitcoin -M does not accept -ipcbind")
|
||||
self.test_args(["-M"], ["-ipcbind=unix"], expect_error='Error: Error parsing command line arguments: Invalid parameter -ipcbind=unix')
|
||||
|
||||
if self.is_ipc_compiled():
|
||||
self.log.info("Ensure bitcoin -m invokes bitcoin-node")
|
||||
self.test_args(["-m"], [], expect_exe="bitcoin-node")
|
||||
|
||||
self.log.info("Ensure bitcoin -m does accept -ipcbind")
|
||||
self.test_args(["-m"], ["-ipcbind=unix"], expect_exe="bitcoin-node")
|
||||
|
||||
self.log.info("Ensure bitcoin accepts -ipcbind by default")
|
||||
self.test_args([], ["-ipcbind=unix"], expect_exe="bitcoin-node")
|
||||
|
||||
self.log.info("Ensure bitcoin recognizes -ipcbind in config file")
|
||||
append_config(node.datadir_path, ["ipcbind=unix"])
|
||||
self.test_args([], [], expect_exe="bitcoin-node")
|
||||
|
||||
|
||||
def get_node_output(node):
|
||||
ret = node.process.wait(timeout=60)
|
||||
node.stdout.seek(0)
|
||||
node.stderr.seek(0)
|
||||
out = node.stdout.read()
|
||||
err = node.stderr.read()
|
||||
node.stdout.close()
|
||||
node.stderr.close()
|
||||
|
||||
# Clean up TestNode state
|
||||
node.running = False
|
||||
node.process = None
|
||||
node.rpc_connected = False
|
||||
node.rpc = None
|
||||
|
||||
return ret, out, err
|
||||
|
||||
|
||||
def get_exe_name(version_str):
|
||||
"""Get exe name from last word of first line of version string."""
|
||||
return re.match(rb".*?(\S+)\s*?(?:\n|$)", version_str.strip()).group(1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
ToolBitcoinTest(__file__).main()
|
||||
@ -23,7 +23,7 @@ CMD_GREP_WALLET_ARGS = r"git grep --function-context 'void WalletInit::AddWallet
|
||||
CMD_GREP_WALLET_HIDDEN_ARGS = r"git grep --function-context 'void DummyWalletInit::AddWalletOptions' -- {}".format(CMD_ROOT_DIR)
|
||||
CMD_GREP_DOCS = r"git grep --perl-regexp '{}' {}".format(REGEX_DOC, CMD_ROOT_DIR)
|
||||
# list unsupported, deprecated and duplicate args as they need no documentation
|
||||
SET_DOC_OPTIONAL = set(['-h', '-?', '-dbcrashratio', '-forcecompactdb'])
|
||||
SET_DOC_OPTIONAL = set(['-h', '-?', '-dbcrashratio', '-forcecompactdb', '-ipcconnect', '-ipcfd'])
|
||||
|
||||
|
||||
def lint_missing_argument_documentation():
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user