aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml6
-rwxr-xr-xci/lint/06_script.sh10
-rwxr-xr-xci/test/00_setup_env_i686_centos.sh3
-rwxr-xr-xci/test/00_setup_env_i686_multiprocess.sh2
-rwxr-xr-xci/test/00_setup_env_mac_native_arm64.sh (renamed from ci/test/00_setup_env_mac_native_x86_64.sh)7
-rwxr-xr-xci/test/04_install.sh17
-rw-r--r--configure.ac4
-rw-r--r--doc/bips.md1
-rw-r--r--doc/man/bitcoin-cli.16
-rw-r--r--doc/man/bitcoin-qt.16
-rw-r--r--doc/man/bitcoin-tx.16
-rw-r--r--doc/man/bitcoin-util.16
-rw-r--r--doc/man/bitcoin-wallet.16
-rw-r--r--doc/man/bitcoind.16
-rw-r--r--doc/release-notes-empty-template.md99
-rw-r--r--doc/release-notes.md391
-rw-r--r--src/Makefile.qt_locale.include1
-rw-r--r--src/net_processing.cpp24
-rw-r--r--src/qt/bitcoin_locale.qrc1
-rw-r--r--src/qt/bitcoingui.cpp4
-rw-r--r--src/qt/locale/bitcoin_fa.ts100
-rw-r--r--src/qt/locale/bitcoin_mr_IN.ts97
-rw-r--r--src/qt/locale/bitcoin_nb.ts112
-rw-r--r--src/qt/locale/bitcoin_pa.ts448
-rw-r--r--src/qt/locale/bitcoin_th.ts16
-rw-r--r--src/qt/locale/bitcoin_tr.ts22
-rw-r--r--src/qt/walletframe.cpp2
-rw-r--r--src/script/sign.cpp21
-rw-r--r--src/wallet/rpc/spend.cpp6
-rw-r--r--src/wallet/rpc/wallet.cpp4
-rw-r--r--src/wallet/scriptpubkeyman.cpp35
-rw-r--r--src/wallet/spend.cpp14
-rw-r--r--src/wallet/spend.h2
-rw-r--r--src/wallet/test/coinselector_tests.cpp40
-rw-r--r--src/wallet/test/spend_tests.cpp45
-rw-r--r--src/wallet/wallet.cpp4
-rwxr-xr-xtest/functional/p2p_tx_privacy.py78
-rwxr-xr-xtest/functional/rpc_fundrawtransaction.py45
-rwxr-xr-xtest/functional/test_runner.py1
-rwxr-xr-xtest/functional/wallet_migration.py10
-rwxr-xr-xtest/functional/wallet_taproot.py153
-rwxr-xr-xtest/lint/lint-git-commit-check.py2
-rwxr-xr-xtest/lint/lint-whitespace.py2
43 files changed, 1586 insertions, 279 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index c8ccf6c057..fdecfc1eb6 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -312,16 +312,16 @@ task:
FILE_ENV: "./ci/test/00_setup_env_mac.sh"
task:
- name: 'macOS 12 native x86_64 [gui, system sqlite] [no depends]'
+ name: 'macOS 13 native arm64 [gui, sqlite only] [no depends]'
macos_instance:
# Use latest image, but hardcode version to avoid silent upgrades (and breaks)
- image: monterey-xcode-13.3 # https://cirrus-ci.org/guide/macOS
+ image: ghcr.io/cirruslabs/macos-ventura-xcode:14.1 # https://cirrus-ci.org/guide/macOS
<< : *MACOS_NATIVE_TASK_TEMPLATE
env:
<< : *CIRRUS_EPHEMERAL_WORKER_TEMPLATE_ENV
CI_USE_APT_INSTALL: "no"
PACKAGE_MANAGER_INSTALL: "echo" # Nothing to do
- FILE_ENV: "./ci/test/00_setup_env_mac_native_x86_64.sh"
+ FILE_ENV: "./ci/test/00_setup_env_mac_native_arm64.sh"
task:
name: 'ARM64 Android APK [focal]'
diff --git a/ci/lint/06_script.sh b/ci/lint/06_script.sh
index 4506848740..826888b6cc 100755
--- a/ci/lint/06_script.sh
+++ b/ci/lint/06_script.sh
@@ -9,7 +9,12 @@ export LC_ALL=C
GIT_HEAD=$(git rev-parse HEAD)
if [ -n "$CIRRUS_PR" ]; then
COMMIT_RANGE="${CIRRUS_BASE_SHA}..$GIT_HEAD"
+ echo
+ git log --no-merges --oneline "$COMMIT_RANGE"
+ echo
test/lint/commit-script-check.sh "$COMMIT_RANGE"
+else
+ COMMIT_RANGE="SKIP_EMPTY_NOT_A_PR"
fi
export COMMIT_RANGE
@@ -36,8 +41,3 @@ if [ "$CIRRUS_REPO_FULL_NAME" = "bitcoin/bitcoin" ] && [ "$CIRRUS_PR" = "" ] ; t
${CI_RETRY_EXE} gpg --keyserver hkps://keys.openpgp.org --recv-keys "${KEYS[@]}" &&
./contrib/verify-commits/verify-commits.py;
fi
-
-if [ -n "$COMMIT_RANGE" ]; then
- echo
- git log --no-merges --oneline "$COMMIT_RANGE"
-fi
diff --git a/ci/test/00_setup_env_i686_centos.sh b/ci/test/00_setup_env_i686_centos.sh
index 8f1cc8af29..1ce3261f44 100755
--- a/ci/test/00_setup_env_i686_centos.sh
+++ b/ci/test/00_setup_env_i686_centos.sh
@@ -9,7 +9,8 @@ export LC_ALL=C.UTF-8
export HOST=i686-pc-linux-gnu
export CONTAINER_NAME=ci_i686_centos
export DOCKER_NAME_TAG=quay.io/centos/centos:stream8
-export DOCKER_PACKAGES="gcc-c++ glibc-devel.x86_64 libstdc++-devel.x86_64 glibc-devel.i686 libstdc++-devel.i686 ccache libtool make git python3 python3-zmq which patch lbzip2 xz procps-ng dash rsync coreutils bison"
+export DOCKER_PACKAGES="gcc-c++ glibc-devel.x86_64 libstdc++-devel.x86_64 glibc-devel.i686 libstdc++-devel.i686 ccache libtool make git python3 python3-pip which patch lbzip2 xz procps-ng dash rsync coreutils bison"
+export PIP_PACKAGES="pyzmq"
export GOAL="install"
export BITCOIN_CONFIG="--enable-zmq --with-gui=qt5 --enable-reduce-exports"
export CONFIG_SHELL="/bin/dash"
diff --git a/ci/test/00_setup_env_i686_multiprocess.sh b/ci/test/00_setup_env_i686_multiprocess.sh
index 766424769d..76de87d955 100755
--- a/ci/test/00_setup_env_i686_multiprocess.sh
+++ b/ci/test/00_setup_env_i686_multiprocess.sh
@@ -9,7 +9,7 @@ export LC_ALL=C.UTF-8
export HOST=i686-pc-linux-gnu
export CONTAINER_NAME=ci_i686_multiprocess
export DOCKER_NAME_TAG=ubuntu:20.04
-export PACKAGES="cmake python3 python3-pip llvm clang g++-multilib"
+export PACKAGES="cmake python3 llvm clang g++-multilib"
export DEP_OPTS="DEBUG=1 MULTIPROCESS=1"
export GOAL="install"
export BITCOIN_CONFIG="--enable-debug CC='clang -m32' CXX='clang++ -m32' LDFLAGS='--rtlib=compiler-rt -lgcc_s'"
diff --git a/ci/test/00_setup_env_mac_native_x86_64.sh b/ci/test/00_setup_env_mac_native_arm64.sh
index d176296e76..cb0e13e77c 100755
--- a/ci/test/00_setup_env_mac_native_x86_64.sh
+++ b/ci/test/00_setup_env_mac_native_arm64.sh
@@ -6,12 +6,11 @@
export LC_ALL=C.UTF-8
-export HOST=x86_64-apple-darwin
-export PIP_PACKAGES="zmq lief"
+export HOST=arm64-apple-darwin
+export PIP_PACKAGES="zmq"
export GOAL="install"
-export BITCOIN_CONFIG="--with-gui --enable-reduce-exports"
+export BITCOIN_CONFIG="--with-gui --with-miniupnpc --with-natpmp --enable-reduce-exports"
export CI_OS_NAME="macos"
export NO_DEPENDS=1
export OSX_SDK=""
export CCACHE_SIZE=300M
-export RUN_SECURITY_TESTS="true"
diff --git a/ci/test/04_install.sh b/ci/test/04_install.sh
index b706fb0906..a4f1a8a7ff 100755
--- a/ci/test/04_install.sh
+++ b/ci/test/04_install.sh
@@ -10,12 +10,6 @@ if [[ $QEMU_USER_CMD == qemu-s390* ]]; then
export LC_ALL=C
fi
-if [ "$CI_OS_NAME" == "macos" ]; then
- sudo -H pip3 install --upgrade pip
- # shellcheck disable=SC2086
- IN_GETOPT_BIN="/usr/local/opt/gnu-getopt/bin/getopt" ${CI_RETRY_EXE} pip3 install --user $PIP_PACKAGES
-fi
-
# Create folders that are mounted into the docker
mkdir -p "${CCACHE_DIR}"
mkdir -p "${PREVIOUS_RELEASES_DIR}"
@@ -78,9 +72,16 @@ elif [ "$CI_USE_APT_INSTALL" != "no" ]; then
fi
${CI_RETRY_EXE} CI_EXEC apt-get update
${CI_RETRY_EXE} CI_EXEC apt-get install --no-install-recommends --no-upgrade -y "$PACKAGES" "$DOCKER_PACKAGES"
- if [ -n "$PIP_PACKAGES" ]; then
+fi
+
+if [ -n "$PIP_PACKAGES" ]; then
+ if [ "$CI_OS_NAME" == "macos" ]; then
+ sudo -H pip3 install --upgrade pip
+ # shellcheck disable=SC2086
+ IN_GETOPT_BIN="$(brew --prefix gnu-getopt)/bin/getopt" ${CI_RETRY_EXE} pip3 install --user $PIP_PACKAGES
+ else
# shellcheck disable=SC2086
- ${CI_RETRY_EXE} pip3 install --user $PIP_PACKAGES
+ ${CI_RETRY_EXE} CI_EXEC pip3 install --user $PIP_PACKAGES
fi
fi
diff --git a/configure.ac b/configure.ac
index cb25eae213..87dd0dc81e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,8 +1,8 @@
AC_PREREQ([2.69])
define(_CLIENT_VERSION_MAJOR, 24)
define(_CLIENT_VERSION_MINOR, 0)
-define(_CLIENT_VERSION_BUILD, 0)
-define(_CLIENT_VERSION_RC, 3)
+define(_CLIENT_VERSION_BUILD, 1)
+define(_CLIENT_VERSION_RC, 0)
define(_CLIENT_VERSION_IS_RELEASE, true)
define(_COPYRIGHT_YEAR, 2022)
define(_COPYRIGHT_HOLDERS,[The %s developers])
diff --git a/doc/bips.md b/doc/bips.md
index 25381818e4..1d5c91b8bd 100644
--- a/doc/bips.md
+++ b/doc/bips.md
@@ -28,6 +28,7 @@ BIPs that are implemented by Bitcoin Core (up-to-date up to **v24.0**):
and it is disabled by default at build time since **v0.19.0** ([PR #15584](https://github.com/bitcoin/bitcoin/pull/15584)).
It has been removed as of **v0.20.0** ([PR 17165](https://github.com/bitcoin/bitcoin/pull/17165)).
* [`BIP 84`](https://github.com/bitcoin/bips/blob/master/bip-0084.mediawiki): The experimental descriptor wallets introduced in **v0.21.0** by default use the Hierarchical Deterministic Wallet derivation proposed by BIP 84. ([PR #16528](https://github.com/bitcoin/bitcoin/pull/16528))
+* [`BIP 86`](https://github.com/bitcoin/bips/blob/master/bip-0086.mediawiki): Descriptor wallets by default use the Hierarchical Deterministic Wallet derivation proposed by BIP 86 since **v23.0** ([PR #22364](https://github.com/bitcoin/bitcoin/pull/22364)).
* [`BIP 90`](https://github.com/bitcoin/bips/blob/master/bip-0090.mediawiki): Trigger mechanism for activation of BIPs 34, 65, and 66 has been simplified to block height checks since **v0.14.0** ([PR #8391](https://github.com/bitcoin/bitcoin/pull/8391)).
* [`BIP 111`](https://github.com/bitcoin/bips/blob/master/bip-0111.mediawiki): `NODE_BLOOM` service bit added, and enforced for all peer versions as of **v0.13.0** ([PR #6579](https://github.com/bitcoin/bitcoin/pull/6579) and [PR #6641](https://github.com/bitcoin/bitcoin/pull/6641)).
* [`BIP 112`](https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki): The CHECKSEQUENCEVERIFY opcode has been implemented since **v0.12.1** ([PR #7524](https://github.com/bitcoin/bitcoin/pull/7524)), and has been *buried* since **v0.19.0** ([PR #16060](https://github.com/bitcoin/bitcoin/pull/16060)).
diff --git a/doc/man/bitcoin-cli.1 b/doc/man/bitcoin-cli.1
index 632b624269..af34832fc5 100644
--- a/doc/man/bitcoin-cli.1
+++ b/doc/man/bitcoin-cli.1
@@ -1,7 +1,7 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.2.
-.TH BITCOIN-CLI "1" "October 2022" "bitcoin-cli v24.0.0rc3" "User Commands"
+.TH BITCOIN-CLI "1" "December 2022" "bitcoin-cli v24.0.1" "User Commands"
.SH NAME
-bitcoin-cli \- manual page for bitcoin-cli v24.0.0rc3
+bitcoin-cli \- manual page for bitcoin-cli v24.0.1
.SH SYNOPSIS
.B bitcoin-cli
[\fI\,options\/\fR] \fI\,<command> \/\fR[\fI\,params\/\fR] \fI\,Send command to Bitcoin Core\/\fR
@@ -15,7 +15,7 @@ bitcoin-cli \- manual page for bitcoin-cli v24.0.0rc3
.B bitcoin-cli
[\fI\,options\/\fR] \fI\,help <command> Get help for a command\/\fR
.SH DESCRIPTION
-Bitcoin Core RPC client version v24.0.0rc3
+Bitcoin Core RPC client version v24.0.1
.SH OPTIONS
.HP
\-?
diff --git a/doc/man/bitcoin-qt.1 b/doc/man/bitcoin-qt.1
index 3b22919335..9bbfb9fa8c 100644
--- a/doc/man/bitcoin-qt.1
+++ b/doc/man/bitcoin-qt.1
@@ -1,12 +1,12 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.2.
-.TH BITCOIN-QT "1" "October 2022" "bitcoin-qt v24.0.0rc3" "User Commands"
+.TH BITCOIN-QT "1" "December 2022" "bitcoin-qt v24.0.1" "User Commands"
.SH NAME
-bitcoin-qt \- manual page for bitcoin-qt v24.0.0rc3
+bitcoin-qt \- manual page for bitcoin-qt v24.0.1
.SH SYNOPSIS
.B bitcoin-qt
[\fI\,command-line options\/\fR]
.SH DESCRIPTION
-Bitcoin Core version v24.0.0rc3
+Bitcoin Core version v24.0.1
.SH OPTIONS
.HP
\-?
diff --git a/doc/man/bitcoin-tx.1 b/doc/man/bitcoin-tx.1
index e8fbafaf2f..4b58804c07 100644
--- a/doc/man/bitcoin-tx.1
+++ b/doc/man/bitcoin-tx.1
@@ -1,7 +1,7 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.2.
-.TH BITCOIN-TX "1" "October 2022" "bitcoin-tx v24.0.0rc3" "User Commands"
+.TH BITCOIN-TX "1" "December 2022" "bitcoin-tx v24.0.1" "User Commands"
.SH NAME
-bitcoin-tx \- manual page for bitcoin-tx v24.0.0rc3
+bitcoin-tx \- manual page for bitcoin-tx v24.0.1
.SH SYNOPSIS
.B bitcoin-tx
[\fI\,options\/\fR] \fI\,<hex-tx> \/\fR[\fI\,commands\/\fR] \fI\,Update hex-encoded bitcoin transaction\/\fR
@@ -9,7 +9,7 @@ bitcoin-tx \- manual page for bitcoin-tx v24.0.0rc3
.B bitcoin-tx
[\fI\,options\/\fR] \fI\,-create \/\fR[\fI\,commands\/\fR] \fI\,Create hex-encoded bitcoin transaction\/\fR
.SH DESCRIPTION
-Bitcoin Core bitcoin\-tx utility version v24.0.0rc3
+Bitcoin Core bitcoin\-tx utility version v24.0.1
.SH OPTIONS
.HP
\-?
diff --git a/doc/man/bitcoin-util.1 b/doc/man/bitcoin-util.1
index 8e68a75976..50f98ae3ac 100644
--- a/doc/man/bitcoin-util.1
+++ b/doc/man/bitcoin-util.1
@@ -1,12 +1,12 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.2.
-.TH BITCOIN-UTIL "1" "October 2022" "bitcoin-util v24.0.0rc3" "User Commands"
+.TH BITCOIN-UTIL "1" "December 2022" "bitcoin-util v24.0.1" "User Commands"
.SH NAME
-bitcoin-util \- manual page for bitcoin-util v24.0.0rc3
+bitcoin-util \- manual page for bitcoin-util v24.0.1
.SH SYNOPSIS
.B bitcoin-util
[\fI\,options\/\fR] [\fI\,commands\/\fR] \fI\,Do stuff\/\fR
.SH DESCRIPTION
-Bitcoin Core bitcoin\-util utility version v24.0.0rc3
+Bitcoin Core bitcoin\-util utility version v24.0.1
.SH OPTIONS
.HP
\-?
diff --git a/doc/man/bitcoin-wallet.1 b/doc/man/bitcoin-wallet.1
index 0a5705b204..212844aaf8 100644
--- a/doc/man/bitcoin-wallet.1
+++ b/doc/man/bitcoin-wallet.1
@@ -1,9 +1,9 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.2.
-.TH BITCOIN-WALLET "1" "October 2022" "bitcoin-wallet v24.0.0rc3" "User Commands"
+.TH BITCOIN-WALLET "1" "December 2022" "bitcoin-wallet v24.0.1" "User Commands"
.SH NAME
-bitcoin-wallet \- manual page for bitcoin-wallet v24.0.0rc3
+bitcoin-wallet \- manual page for bitcoin-wallet v24.0.1
.SH DESCRIPTION
-Bitcoin Core bitcoin\-wallet version v24.0.0rc3
+Bitcoin Core bitcoin\-wallet version v24.0.1
.PP
bitcoin\-wallet is an offline tool for creating and interacting with Bitcoin Core wallet files.
By default bitcoin\-wallet will act on wallets in the default mainnet wallet directory in the datadir.
diff --git a/doc/man/bitcoind.1 b/doc/man/bitcoind.1
index 324affe690..1ce173d92c 100644
--- a/doc/man/bitcoind.1
+++ b/doc/man/bitcoind.1
@@ -1,12 +1,12 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.2.
-.TH BITCOIND "1" "October 2022" "bitcoind v24.0.0rc3" "User Commands"
+.TH BITCOIND "1" "December 2022" "bitcoind v24.0.1" "User Commands"
.SH NAME
-bitcoind \- manual page for bitcoind v24.0.0rc3
+bitcoind \- manual page for bitcoind v24.0.1
.SH SYNOPSIS
.B bitcoind
[\fI\,options\/\fR] \fI\,Start Bitcoin Core\/\fR
.SH DESCRIPTION
-Bitcoin Core version v24.0.0rc3
+Bitcoin Core version v24.0.1
.SH OPTIONS
.HP
\-?
diff --git a/doc/release-notes-empty-template.md b/doc/release-notes-empty-template.md
deleted file mode 100644
index 8462714898..0000000000
--- a/doc/release-notes-empty-template.md
+++ /dev/null
@@ -1,99 +0,0 @@
-*The release notes draft is a temporary file that can be added to by anyone. See
-[/doc/developer-notes.md#release-notes](/doc/developer-notes.md#release-notes)
-for the process.*
-
-*version* Release Notes Draft
-===============================
-
-Bitcoin Core version *version* is now available from:
-
- <https://bitcoincore.org/bin/bitcoin-core-*version*/>
-
-This release includes new features, various bug fixes and performance
-improvements, as well as updated translations.
-
-Please report bugs using the issue tracker at GitHub:
-
- <https://github.com/bitcoin/bitcoin/issues>
-
-To receive security and update notifications, please subscribe to:
-
- <https://bitcoincore.org/en/list/announcements/join/>
-
-How to Upgrade
-==============
-
-If you are running an older version, shut it down. Wait until it has completely
-shut down (which might take a few minutes in some cases), then run the
-installer (on Windows) or just copy over `/Applications/Bitcoin-Qt` (on Mac)
-or `bitcoind`/`bitcoin-qt` (on Linux).
-
-Upgrading directly from a version of Bitcoin Core that has reached its EOL is
-possible, but it might take some time if the data directory needs to be migrated. Old
-wallet versions of Bitcoin Core are generally supported.
-
-Compatibility
-==============
-
-Bitcoin Core is supported and extensively tested on operating systems
-using the Linux kernel, macOS 10.15+, and Windows 7 and newer. Bitcoin
-Core should also work on most other Unix-like systems but is not as
-frequently tested on them. It is not recommended to use Bitcoin Core on
-unsupported systems.
-
-Notable changes
-===============
-
-P2P and network changes
------------------------
-
-Updated RPCs
-------------
-
-
-Changes to wallet related RPCs can be found in the Wallet section below.
-
-New RPCs
---------
-
-Build System
-------------
-
-Updated settings
-----------------
-
-
-Changes to GUI or wallet related settings can be found in the GUI or Wallet section below.
-
-New settings
-------------
-
-Tools and Utilities
--------------------
-
-Wallet
-------
-
-GUI changes
------------
-
-Low-level changes
-=================
-
-RPC
----
-
-Tests
------
-
-*version* change log
-====================
-
-Credits
-=======
-
-Thanks to everyone who directly contributed to this release:
-
-
-As well as to everyone that helped with translations on
-[Transifex](https://www.transifex.com/bitcoin/bitcoin/).
diff --git a/doc/release-notes.md b/doc/release-notes.md
new file mode 100644
index 0000000000..24920ba450
--- /dev/null
+++ b/doc/release-notes.md
@@ -0,0 +1,391 @@
+24.0.1 Release Notes
+====================
+
+Due to last-minute issues (#26616), 24.0, although tagged, was never fully
+announced or released.
+
+Bitcoin Core version 24.0.1 is now available from:
+
+ <https://bitcoincore.org/bin/bitcoin-core-24.0.1/>
+
+This release includes new features, various bug fixes and performance
+improvements, as well as updated translations.
+
+Please report bugs using the issue tracker at GitHub:
+
+ <https://github.com/bitcoin/bitcoin/issues>
+
+To receive security and update notifications, please subscribe to:
+
+ <https://bitcoincore.org/en/list/announcements/join/>
+
+How to Upgrade
+==============
+
+If you are running an older version, shut it down. Wait until it has completely
+shut down (which might take a few minutes in some cases), then run the
+installer (on Windows) or just copy over `/Applications/Bitcoin-Qt` (on macOS)
+or `bitcoind`/`bitcoin-qt` (on Linux).
+
+Upgrading directly from a version of Bitcoin Core that has reached its EOL is
+possible, but it might take some time if the data directory needs to be migrated. Old
+wallet versions of Bitcoin Core are generally supported.
+
+Compatibility
+==============
+
+Bitcoin Core is supported and extensively tested on operating systems
+using the Linux kernel, macOS 10.15+, and Windows 7 and newer. Bitcoin
+Core should also work on most other Unix-like systems but is not as
+frequently tested on them. It is not recommended to use Bitcoin Core on
+unsupported systems.
+
+Notice of new option for transaction replacement policies
+=========================================================
+
+This version of Bitcoin Core adds a new `mempoolfullrbf` configuration
+option which allows users to change the policy their individual node
+will use for relaying and mining unconfirmed transactions. The option
+defaults to the same policy that was used in previous releases and no
+changes to node policy will occur if everyone uses the default.
+
+Some Bitcoin services today expect that the first version of an
+unconfirmed transaction that they see will be the version of the
+transaction that ultimately gets confirmed---a transaction acceptance
+policy sometimes called "first-seen".
+
+The Bitcoin Protocol does not, and cannot, provide any assurance that
+the first version of an unconfirmed transaction seen by a particular
+node will be the version that gets confirmed. If there are multiple
+versions of the same unconfirmed transaction available, only the miner
+who includes one of those transactions in a block gets to decide which
+version of the transaction gets confirmed.
+
+Despite this lack of assurance, multiple merchants and services today
+still make this assumption.
+
+There are several benefits to users from removing this *first-seen*
+simplification. One key benefit, the ability for the sender of a
+transaction to replace it with an alternative version paying higher
+fees, was realized in [Bitcoin Core 0.12.0][] (February 2016) with the
+introduction of [BIP125][] opt-in Replace By Fee (RBF).
+
+Since then, there has been discussion about completely removing the
+first-seen simplification and allowing users to replace any of their
+older unconfirmed transactions with newer transactions, a feature called
+*full-RBF*. This release includes a `mempoolfullrbf` configuration
+option that allows enabling full-RBF, although it defaults to off
+(allowing only opt-in RBF).
+
+Several alternative node implementations have already enabled full-RBF by
+default for years, and several contributors to Bitcoin Core are
+advocating for enabling full-RBF by default in a future version of
+Bitcoin Core.
+
+As more nodes that participate in relay and mining begin enabling
+full-RBF, replacement of unconfirmed transactions by ones offering higher
+fees may rapidly become more reliable.
+
+Contributors to this project strongly recommend that merchants and services
+not accept unconfirmed transactions as final, and if they insist on doing so,
+to take the appropriate steps to ensure they have some recourse or plan for
+when their assumptions do not hold.
+
+[Bitcoin Core 0.12.0]: https://bitcoincore.org/en/releases/0.12.0/#opt-in-replace-by-fee-transactions
+[bip125]: https://github.com/bitcoin/bips/blob/master/bip-0125.mediawiki
+
+Notable changes
+===============
+
+P2P and network changes
+-----------------------
+
+- To address a potential denial-of-service, the logic to download headers from peers
+ has been reworked. This is particularly relevant for nodes starting up for the
+ first time (or for nodes which are starting up after being offline for a long time).
+
+ Whenever headers are received from a peer that have a total chainwork that is either
+ less than the node's `-minimumchainwork` value or is sufficiently below the work at
+ the node's tip, a "presync" phase will begin, in which the node will download the
+ peer's headers and verify the cumulative work on the peer's chain, prior to storing
+ those headers permanently. Once that cumulative work is verified to be sufficiently high,
+ the headers will be redownloaded from that peer and fully validated and stored.
+
+ This may result in initial headers sync taking longer for new nodes starting up for
+ the first time, both because the headers will be downloaded twice, and because the effect
+ of a peer disconnecting during the presync phase (or while the node's best headers chain has less
+ than `-minimumchainwork`), will result in the node needing to use the headers presync mechanism
+ with the next peer as well (downloading the headers twice, again). (#25717)
+
+- With I2P connections, a new, transient address is used for each outbound
+ connection if `-i2pacceptincoming=0`. (#25355)
+
+Updated RPCs
+------------
+
+- The `-deprecatedrpc=softforks` configuration option has been removed. The
+ RPC `getblockchaininfo` no longer returns the `softforks` field, which was
+ previously deprecated in 23.0. (#23508) Information on soft fork status is
+ now only available via the `getdeploymentinfo` RPC.
+
+- The `deprecatedrpc=exclude_coinbase` configuration option has been removed.
+ The `receivedby` RPCs (`listreceivedbyaddress`, `listreceivedbylabel`,
+ `getreceivedbyaddress` and `getreceivedbylabel`) now always return results
+ accounting for received coins from coinbase outputs, without an option to
+ change that behaviour. Excluding coinbases was previously deprecated in 23.0.
+ (#25171)
+
+- The `deprecatedrpc=fees` configuration option has been removed. The top-level
+ fee fields `fee`, `modifiedfee`, `ancestorfees` and `descendantfees` are no
+ longer returned by RPCs `getmempoolentry`, `getrawmempool(verbose=true)`,
+ `getmempoolancestors(verbose=true)` and `getmempooldescendants(verbose=true)`.
+ The same fee fields can be accessed through the `fees` object in the result.
+ The top-level fee fields were previously deprecated in 23.0. (#25204)
+
+- The `getpeerinfo` RPC has been updated with a new `presynced_headers` field,
+ indicating the progress on the presync phase mentioned in the
+ "P2P and network changes" section above.
+
+Changes to wallet related RPCs can be found in the Wallet section below.
+
+New RPCs
+--------
+
+- The `sendall` RPC spends specific UTXOs to one or more recipients
+ without creating change. By default, the `sendall` RPC will spend
+ every UTXO in the wallet. `sendall` is useful to empty wallets or to
+ create a changeless payment from select UTXOs. When creating a payment
+ from a specific amount for which the recipient incurs the transaction
+ fee, continue to use the `subtractfeefromamount` option via the
+ `send`, `sendtoaddress`, or `sendmany` RPCs. (#24118)
+
+- A new `gettxspendingprevout` RPC has been added, which scans the mempool to find
+ transactions spending any of the given outpoints. (#24408)
+
+- The `simulaterawtransaction` RPC iterates over the inputs and outputs of the given
+ transactions, and tallies up the balance change for the given wallet. This can be
+ useful e.g. when verifying that a coin join like transaction doesn't contain unexpected
+ inputs that the wallet will then sign for unintentionally. (#22751)
+
+Updated REST APIs
+-----------------
+
+- The `/headers/` and `/blockfilterheaders/` endpoints have been updated to use
+ a query parameter instead of path parameter to specify the result count. The
+ count parameter is now optional, and defaults to 5 for both endpoints. The old
+ endpoints are still functional, and have no documented behaviour change.
+
+ For `/headers`, use
+ `GET /rest/headers/<BLOCK-HASH>.<bin|hex|json>?count=<COUNT=5>`
+ instead of
+ `GET /rest/headers/<COUNT>/<BLOCK-HASH>.<bin|hex|json>` (deprecated)
+
+ For `/blockfilterheaders/`, use
+ `GET /rest/blockfilterheaders/<FILTERTYPE>/<BLOCK-HASH>.<bin|hex|json>?count=<COUNT=5>`
+ instead of
+ `GET /rest/blockfilterheaders/<FILTERTYPE>/<COUNT>/<BLOCK-HASH>.<bin|hex|json>` (deprecated)
+
+ (#24098)
+
+Build System
+------------
+
+- Guix builds are now reproducible across architectures (x86_64 & aarch64). (#21194)
+
+New settings
+------------
+
+- A new `mempoolfullrbf` option has been added, which enables the mempool to
+ accept transaction replacement without enforcing BIP125 replaceability
+ signaling. (#25353)
+
+Wallet
+------
+
+- The `-walletrbf` startup option will now default to `true`. The
+ wallet will now default to opt-in RBF on transactions that it creates. (#25610)
+
+- The `replaceable` option for the `createrawtransaction` and
+ `createpsbt` RPCs will now default to `true`. Transactions created
+ with these RPCs will default to having opt-in RBF enabled. (#25610)
+
+- The `wsh()` output descriptor was extended with Miniscript support. You can import Miniscript
+ descriptors for P2WSH in a watchonly wallet to track coins, but you can't spend from them using
+ the Bitcoin Core wallet yet.
+ You can find more about Miniscript on the [reference website](https://bitcoin.sipa.be/miniscript/). (#24148)
+
+- The `tr()` output descriptor now supports multisig scripts through the `multi_a()` and
+ `sortedmulti_a()` functions. (#24043)
+
+- To help prevent fingerprinting transactions created by the Bitcoin Core wallet, change output
+ amounts are now randomized. (#24494)
+
+- The `listtransactions`, `gettransaction`, and `listsinceblock`
+ RPC methods now include a wtxid field (hash of serialized transaction,
+ including witness data) for each transaction. (#24198)
+
+- The `listsinceblock`, `listtransactions` and `gettransaction` output now contain a new
+ `parent_descs` field for every "receive" entry. (#25504)
+
+- A new optional `include_change` parameter was added to the `listsinceblock` command.
+
+- RPC `getreceivedbylabel` now returns an error, "Label not found
+ in wallet" (-4), if the label is not in the address book. (#25122)
+
+Migrating Legacy Wallets to Descriptor Wallets
+---------------------------------------------
+
+An experimental RPC `migratewallet` has been added to migrate Legacy (non-descriptor) wallets to
+Descriptor wallets. More information about the migration process is available in the
+[documentation](https://github.com/bitcoin/bitcoin/blob/master/doc/managing-wallets.md#migrating-legacy-wallets-to-descriptor-wallets).
+
+GUI changes
+-----------
+
+- A new menu item to restore a wallet from a backup file has been added (gui#471).
+
+- Configuration changes made in the bitcoin GUI (such as the pruning setting,
+proxy settings, UPNP preferences) are now saved to `<datadir>/settings.json`
+file rather than to the Qt settings backend (windows registry or unix desktop
+config files), so these settings will now apply to bitcoind, instead of being
+ignored. (#15936, gui#602)
+
+- Also, the interaction between GUI settings and `bitcoin.conf` settings is
+simplified. Settings from `bitcoin.conf` are now displayed normally in the GUI
+settings dialog, instead of in a separate warning message ("Options set in this
+dialog are overridden by the configuration file: -setting=value"). And these
+settings can now be edited because `settings.json` values take precedence over
+`bitcoin.conf` values. (#15936)
+
+Low-level changes
+=================
+
+RPC
+---
+
+- The `deriveaddresses`, `getdescriptorinfo`, `importdescriptors` and `scantxoutset` commands now
+ accept Miniscript expression within a `wsh()` descriptor. (#24148)
+
+- The `getaddressinfo`, `decodescript`, `listdescriptors` and `listunspent` commands may now output
+ a Miniscript descriptor inside a `wsh()` where a `wsh(raw())` descriptor was previously returned. (#24148)
+
+Credits
+=======
+
+Thanks to everyone who directly contributed to this release:
+
+- /dev/fd0
+- 0xb10c
+- Adam Jonas
+- akankshakashyap
+- Ali Sherief
+- amadeuszpawlik
+- Andreas Kouloumos
+- Andrew Chow
+- Anthony Towns
+- Antoine Poinsot
+- Antoine Riard
+- Aurèle Oulès
+- avirgovi
+- Ayush Sharma
+- Baas
+- Ben Woosley
+- BrokenProgrammer
+- brunoerg
+- brydinh
+- Bushstar
+- Calvin Kim
+- CAnon
+- Carl Dong
+- chinggg
+- Cory Fields
+- Daniel Kraft
+- Daniela Brozzoni
+- darosior
+- Dave Scotese
+- David Bakin
+- dergoegge
+- dhruv
+- Dimitri
+- dontbyte
+- Duncan Dean
+- eugene
+- Eunoia
+- Fabian Jahr
+- furszy
+- Gleb Naumenko
+- glozow
+- Greg Weber
+- Gregory Sanders
+- gruve-p
+- Hennadii Stepanov
+- hiago
+- Igor Bubelov
+- ishaanam
+- Jacob P.
+- Jadi
+- James O'Beirne
+- Janna
+- Jarol Rodriguez
+- Jeremy Rand
+- Jeremy Rubin
+- jessebarton
+- João Barbosa
+- John Newbery
+- Jon Atack
+- Josiah Baker
+- Karl-Johan Alm
+- KevinMusgrave
+- Kiminuo
+- klementtan
+- Kolby Moroz
+- kouloumos
+- Kristaps Kaupe
+- Larry Ruane
+- Luke Dashjr
+- MarcoFalke
+- Marnix
+- Martin Leitner-Ankerl
+- Martin Zumsande
+- Michael Dietz
+- Michael Folkson
+- Michael Ford
+- Murch
+- mutatrum
+- muxator
+- Oskar Mendel
+- Pablo Greco
+- pasta
+- Patrick Strateman
+- Pavol Rusnak
+- Peter Bushnell
+- phyBrackets
+- Pieter Wuille
+- practicalswift
+- randymcmillan
+- Robert Spigler
+- Russell Yanofsky
+- S3RK
+- Samer Afach
+- Sebastian Falbesoner
+- Seibart Nedor
+- Shashwat
+- Sjors Provoost
+- Smlep
+- sogoagain
+- Stacie
+- Stéphan Vuylsteke
+- Suhail Saqan
+- Suhas Daftuar
+- t-bast
+- TakeshiMusgrave
+- Vasil Dimov
+- W. J. van der Laan
+- w0xlt
+- whiteh0rse
+- willcl-ark
+- William Casarin
+- Yancy Ribbens
+
+As well as to everyone that helped with translations on
+[Transifex](https://www.transifex.com/bitcoin/bitcoin/).
diff --git a/src/Makefile.qt_locale.include b/src/Makefile.qt_locale.include
index 63ef39d6b8..3ccbc4fd18 100644
--- a/src/Makefile.qt_locale.include
+++ b/src/Makefile.qt_locale.include
@@ -59,6 +59,7 @@ QT_TS = \
qt/locale/bitcoin_ne.ts \
qt/locale/bitcoin_nl.ts \
qt/locale/bitcoin_no.ts \
+ qt/locale/bitcoin_pa.ts \
qt/locale/bitcoin_pam.ts \
qt/locale/bitcoin_pl.ts \
qt/locale/bitcoin_pt.ts \
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index a6299be403..3edc051034 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -2007,8 +2007,15 @@ void PeerManagerImpl::RelayTransaction(const uint256& txid, const uint256& wtxid
auto tx_relay = peer.GetTxRelay();
if (!tx_relay) continue;
- const uint256& hash{peer.m_wtxid_relay ? wtxid : txid};
LOCK(tx_relay->m_tx_inventory_mutex);
+ // Only queue transactions for announcement once the version handshake
+ // is completed. The time of arrival for these transactions is
+ // otherwise at risk of leaking to a spy, if the spy is able to
+ // distinguish transactions received during the handshake from the rest
+ // in the announcement.
+ if (tx_relay->m_next_inv_send_time == 0s) continue;
+
+ const uint256& hash{peer.m_wtxid_relay ? wtxid : txid};
if (!tx_relay->m_tx_inventory_known_filter.contains(hash)) {
tx_relay->m_tx_inventory_to_send.insert(hash);
}
@@ -3396,6 +3403,21 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// they may wish to request compact blocks from us
m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, /*high_bandwidth=*/false, /*version=*/CMPCTBLOCKS_VERSION));
}
+
+ if (auto tx_relay = peer->GetTxRelay()) {
+ // `TxRelay::m_tx_inventory_to_send` must be empty before the
+ // version handshake is completed as
+ // `TxRelay::m_next_inv_send_time` is first initialised in
+ // `SendMessages` after the verack is received. Any transactions
+ // received during the version handshake would otherwise
+ // immediately be advertised without random delay, potentially
+ // leaking the time of arrival to a spy.
+ Assume(WITH_LOCK(
+ tx_relay->m_tx_inventory_mutex,
+ return tx_relay->m_tx_inventory_to_send.empty() &&
+ tx_relay->m_next_inv_send_time == 0s));
+ }
+
pfrom.fSuccessfullyConnected = true;
return;
}
diff --git a/src/qt/bitcoin_locale.qrc b/src/qt/bitcoin_locale.qrc
index 5edb4a08fe..e87cfe21e2 100644
--- a/src/qt/bitcoin_locale.qrc
+++ b/src/qt/bitcoin_locale.qrc
@@ -60,6 +60,7 @@
<file alias="ne">locale/bitcoin_ne.qm</file>
<file alias="nl">locale/bitcoin_nl.qm</file>
<file alias="no">locale/bitcoin_no.qm</file>
+ <file alias="pa">locale/bitcoin_pa.qm</file>
<file alias="pam">locale/bitcoin_pam.qm</file>
<file alias="pl">locale/bitcoin_pl.qm</file>
<file alias="pt">locale/bitcoin_pt.qm</file>
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 894a401e56..18d374311a 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -512,7 +512,7 @@ void BitcoinGUI::createMenuBar()
connect(minimize_action, &QAction::triggered, [] {
QApplication::activeWindow()->showMinimized();
});
- connect(qApp, &QApplication::focusWindowChanged, [minimize_action] (QWindow* window) {
+ connect(qApp, &QApplication::focusWindowChanged, this, [minimize_action] (QWindow* window) {
minimize_action->setEnabled(window != nullptr && (window->flags() & Qt::Dialog) != Qt::Dialog && window->windowState() != Qt::WindowMinimized);
});
@@ -527,7 +527,7 @@ void BitcoinGUI::createMenuBar()
}
});
- connect(qApp, &QApplication::focusWindowChanged, [zoom_action] (QWindow* window) {
+ connect(qApp, &QApplication::focusWindowChanged, this, [zoom_action] (QWindow* window) {
zoom_action->setEnabled(window != nullptr);
});
#endif
diff --git a/src/qt/locale/bitcoin_fa.ts b/src/qt/locale/bitcoin_fa.ts
index 8f4d7a6d10..5c4fba8ac1 100644
--- a/src/qt/locale/bitcoin_fa.ts
+++ b/src/qt/locale/bitcoin_fa.ts
@@ -259,6 +259,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<context>
<name>BitcoinApplication</name>
<message>
+ <source>Settings file %1 might be corrupt or invalid.</source>
+ <translation type="unfinished">فایل تنظیمات %1 ممکن است خراب یا نامعتبر باشد.</translation>
+ </message>
+ <message>
<source>Runaway exception</source>
<translation type="unfinished">استثناء فراری (این استثناء نشان دهنده این است که هسته بیتکوین نتوانست چیزی را در کیف(والت) بنویسد.)</translation>
</message>
@@ -1013,7 +1017,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>سابقه تراکنش بلوک(های) %n پردازش شد.</numerusform>
</translation>
</message>
<message>
@@ -1087,6 +1091,16 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">کیف پول را ببندید</translation>
</message>
<message>
+ <source>Restore Wallet…</source>
+ <extracomment>Name of the menu item that restores wallet from a backup file.</extracomment>
+ <translation type="unfinished">بازیابی کیف پول…</translation>
+ </message>
+ <message>
+ <source>Restore a wallet from a backup file</source>
+ <extracomment>Status tip for Restore Wallet menu item</extracomment>
+ <translation type="unfinished">بازیابی یک کیف پول از یک فایل پشتیبان</translation>
+ </message>
+ <message>
<source>Close all wallets</source>
<translation type="unfinished">همه‌ی کیف پول‌ها را ببند</translation>
</message>
@@ -1105,6 +1119,16 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">داده های کیف پول</translation>
</message>
<message>
+ <source>Load Wallet Backup</source>
+ <extracomment>The title for Restore Wallet File Windows</extracomment>
+ <translation type="unfinished">بارگیری پشتیبان‌گیری کیف پول</translation>
+ </message>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of pop-up window shown when the user is attempting to restore a wallet.</extracomment>
+ <translation type="unfinished">بازیابی کیف پول</translation>
+ </message>
+ <message>
<source>Wallet Name</source>
<extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
<translation type="unfinished">نام کیف پول</translation>
@@ -1133,7 +1157,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>%n active connection(s) to Bitcoin network.</source>
<extracomment>A substring of the tooltip.</extracomment>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%n اتصال(های) فعال به شبکه بیت کوین.</numerusform>
</translation>
</message>
<message>
@@ -1157,6 +1181,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">فعال‌سازی فعالیت شبکه</translation>
</message>
<message>
+ <source>Pre-syncing Headers (%1%)…</source>
+ <translation type="unfinished">پیش‌همگام‌سازی سرصفحه‌ها (%1%)…</translation>
+ </message>
+ <message>
<source>Error: %1</source>
<translation type="unfinished">خطا: %1</translation>
</message>
@@ -1414,7 +1442,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Can't list signers</source>
<translation type="unfinished">نمی‌توان امضاکنندگان را فهرست کرد</translation>
</message>
- </context>
+ <message>
+ <source>Too many external signers found</source>
+ <translation type="unfinished">تعداد زیادی امضاکننده خارجی پیدا شد</translation>
+ </message>
+</context>
<context>
<name>LoadWalletsActivity</name>
<message>
@@ -1456,6 +1488,34 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
</context>
<context>
+ <name>RestoreWalletActivity</name>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of progress window which is displayed when wallets are being restored.</extracomment>
+ <translation type="unfinished">بازیابی کیف پول</translation>
+ </message>
+ <message>
+ <source>Restoring Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored.</extracomment>
+ <translation type="unfinished">بازیابی کیف پول &lt;b&gt;%1&lt;/b&gt; ...</translation>
+ </message>
+ <message>
+ <source>Restore wallet failed</source>
+ <extracomment>Title of message box which is displayed when the wallet could not be restored.</extracomment>
+ <translation type="unfinished">بازیابی کیف پول انجام نشد</translation>
+ </message>
+ <message>
+ <source>Restore wallet warning</source>
+ <extracomment>Title of message box which is displayed when the wallet is restored with some warning.</extracomment>
+ <translation type="unfinished">هشدار بازیابی کیف پول</translation>
+ </message>
+ <message>
+ <source>Restore wallet message</source>
+ <extracomment>Title of message box which is displayed when the wallet is successfully restored.</extracomment>
+ <translation type="unfinished">بازیابی پیام کیف پول</translation>
+ </message>
+</context>
+<context>
<name>WalletController</name>
<message>
<source>Close wallet</source>
@@ -1611,19 +1671,19 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message numerus="yes">
<source>%n GB of space available</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%n گیگابایت فضای موجود</numerusform>
</translation>
</message>
<message numerus="yes">
<source>(of %n GB needed)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>(از %n گیگابایت مورد نیاز)</numerusform>
</translation>
</message>
<message numerus="yes">
<source>(%n GB needed for full chain)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>(%n گیگابایت برای زنجیره کامل مورد نیاز است)</numerusform>
</translation>
</message>
<message>
@@ -1638,7 +1698,7 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>(sufficient to restore backups %n day(s) old)</source>
<extracomment>Explanatory text on the capability of the current prune target.</extracomment>
<translation type="unfinished">
- <numerusform />
+ <numerusform>(برای بازیابی نسخه‌های پشتیبان %n روز (های) قدیمی کافی است)</numerusform>
</translation>
</message>
<message>
@@ -1674,6 +1734,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">گیگابایت</translation>
</message>
<message>
+ <source>When you click OK, %1 will begin to download and process the full %4 block chain (%2 GB) starting with the earliest transactions in %3 when %4 initially launched.</source>
+ <translation type="unfinished">وقتی تأیید را کلیک می‌کنید، %1 شروع به دانلود و پردازش زنجیره بلاک %4 کامل (%2 گیگابایت) می‌کند که با اولین تراکنش‌ها در %3 شروع می‌شود که %4 در ابتدا راه‌اندازی می شود.</translation>
+ </message>
+ <message>
<source>If you have chosen to limit block chain storage (pruning), the historical data must still be downloaded and processed, but will be deleted afterward to keep your disk usage low.</source>
<translation type="unfinished">اگر تصمیم بگیرید که فضای ذخیره سازی زنجیره بلوک (هرس) را محدود کنید ، داده های تاریخی باید بارگیری و پردازش شود ، اما اگر آن را حذف کنید ، اگر شما دیسک کم استفاده کنید.
 </translation>
@@ -1765,7 +1829,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>Unknown. Syncing Headers (%1, %2%)…</source>
<translation type="unfinished">ناشناخته. هماهنگ‌سازی سربرگ‌ها (%1، %2%) </translation>
</message>
- </context>
+ <message>
+ <source>Unknown. Pre-syncing Headers (%1, %2%)…</source>
+ <translation type="unfinished">ناشناس. پیش‌همگام‌سازی سرصفحه‌ها (%1، %2% )…</translation>
+ </message>
+</context>
<context>
<name>OpenURIDialog</name>
<message>
@@ -1801,6 +1869,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">اندازه کش پایگاه داده.</translation>
</message>
<message>
+ <source>Options set in this dialog are overridden by the command line:</source>
+ <translation type="unfinished">گزینه های تنظیم شده در این گفتگو توسط خط فرمان لغو می شوند:</translation>
+ </message>
+ <message>
<source>Open Configuration File</source>
<translation type="unfinished">بازکردن فایل پیکربندی</translation>
</message>
@@ -2039,6 +2111,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">کلاینت نیازمند ریست شدن است برای فعال کردن تغییرات</translation>
</message>
<message>
+ <source>Current settings will be backed up at "%1".</source>
+ <extracomment>Text explaining to the user that the client's current settings will be backed up at a specific location. %1 is a stand-in argument for the backup location's path.</extracomment>
+ <translation type="unfinished">تنظیمات فعلی در "%1" پشتیبان گیری خواهد شد.</translation>
+ </message>
+ <message>
<source>Client will be shut down. Do you want to proceed?</source>
<extracomment>Text asking the user to confirm if they would like to proceed with a client shutdown.</extracomment>
<translation type="unfinished">کلاینت خاموش خواهد شد.آیا میخواهید ادامه دهید؟</translation>
@@ -2081,6 +2158,13 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
</context>
<context>
+ <name>OptionsModel</name>
+ <message>
+ <source>Could not read setting "%1", %2.</source>
+ <translation type="unfinished">نمی توان تنظیم "%1"، %2 را خواند.</translation>
+ </message>
+</context>
+<context>
<name>OverviewPage</name>
<message>
<source>Form</source>
diff --git a/src/qt/locale/bitcoin_mr_IN.ts b/src/qt/locale/bitcoin_mr_IN.ts
index f1b84c27ea..2641e4586a 100644
--- a/src/qt/locale/bitcoin_mr_IN.ts
+++ b/src/qt/locale/bitcoin_mr_IN.ts
@@ -86,6 +86,11 @@
<translation type="unfinished">पत्त्याची निर्यात करा</translation>
</message>
<message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">कॉमा सेपरेटेड फ़ाइल</translation>
+ </message>
+ <message>
<source>Exporting Failed</source>
<translation type="unfinished">निर्यात अयशस्वी</translation>
</message>
@@ -106,7 +111,22 @@
</message>
</context>
<context>
+ <name>BitcoinApplication</name>
+ <message>
+ <source>A fatal error occurred. %1 can no longer continue safely and will quit.</source>
+ <translation type="unfinished">एक गंभीर त्रुटी आली. %1यापुढे सुरक्षितपणे सुरू ठेवू शकत नाही आणि संपेल.</translation>
+ </message>
+ <message>
+ <source>Internal error</source>
+ <translation type="unfinished">अंतर्गत त्रुटी</translation>
+ </message>
+ </context>
+<context>
<name>QObject</name>
+ <message>
+ <source>%1 didn't yet exit safely…</source>
+ <translation type="unfinished">%1अजून सुरक्षितपणे बाहेर पडलो नाही...</translation>
+ </message>
<message numerus="yes">
<source>%n second(s)</source>
<translation type="unfinished">
@@ -151,7 +171,79 @@
</message>
</context>
<context>
+ <name>bitcoin-core</name>
+ <message>
+ <source>Settings file could not be read</source>
+ <translation type="unfinished">सेटिंग्ज फाइल वाचता आली नाही</translation>
+ </message>
+ <message>
+ <source>Settings file could not be written</source>
+ <translation type="unfinished">सेटिंग्ज फाइल लिहिता आली नाही</translation>
+ </message>
+ </context>
+<context>
<name>BitcoinGUI</name>
+ <message>
+ <source>&amp;Minimize</source>
+ <translation type="unfinished">&amp;मिनीमाइज़</translation>
+ </message>
+ <message>
+ <source>&amp;Options…</source>
+ <translation type="unfinished">&amp;पर्याय</translation>
+ </message>
+ <message>
+ <source>&amp;Encrypt Wallet…</source>
+ <translation type="unfinished">&amp;एनक्रिप्ट वॉलेट</translation>
+ </message>
+ <message>
+ <source>&amp;Backup Wallet…</source>
+ <translation type="unfinished">&amp;बॅकअप वॉलेट…
+ </translation>
+ </message>
+ <message>
+ <source>&amp;Change Passphrase…</source>
+ <translation type="unfinished">&amp;पासफ्रेज बदला...</translation>
+ </message>
+ <message>
+ <source>Sign &amp;message…</source>
+ <translation type="unfinished">स्वाक्षरी आणि संदेश...</translation>
+ </message>
+ <message>
+ <source>&amp;Verify message…</source>
+ <translation type="unfinished">&amp;संदेश सत्यापित करा...</translation>
+ </message>
+ <message>
+ <source>&amp;Load PSBT from file…</source>
+ <translation type="unfinished">फाइलमधून PSBT &amp;लोड करा...</translation>
+ </message>
+ <message>
+ <source>Close Wallet…</source>
+ <translation type="unfinished">वॉलेट बंद करा...</translation>
+ </message>
+ <message>
+ <source>Create Wallet…</source>
+ <translation type="unfinished">वॉलेट तयार करा...</translation>
+ </message>
+ <message>
+ <source>Close All Wallets…</source>
+ <translation type="unfinished">सर्व वॉलेट बंद करा...</translation>
+ </message>
+ <message>
+ <source>Syncing Headers (%1%)…</source>
+ <translation type="unfinished">शीर्षलेख समक्रमित करत आहे (%1%)…</translation>
+ </message>
+ <message>
+ <source>Synchronizing with network…</source>
+ <translation type="unfinished">नेटवर्कसह सिंक्रोनाइझ करत आहे...</translation>
+ </message>
+ <message>
+ <source>Indexing blocks on disk…</source>
+ <translation type="unfinished">डिस्कवर ब्लॉक अनुक्रमित करत आहे...</translation>
+ </message>
+ <message>
+ <source>Processing blocks on disk…</source>
+ <translation type="unfinished">डिस्कवर ब्लॉक्सवर प्रक्रिया करत आहे...</translation>
+ </message>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation type="unfinished">
@@ -264,6 +356,11 @@
<context>
<name>TransactionView</name>
<message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">कॉमा सेपरेटेड फ़ाइल</translation>
+ </message>
+ <message>
<source>Label</source>
<translation type="unfinished">लेबल</translation>
</message>
diff --git a/src/qt/locale/bitcoin_nb.ts b/src/qt/locale/bitcoin_nb.ts
index 777c1157df..c58017288f 100644
--- a/src/qt/locale/bitcoin_nb.ts
+++ b/src/qt/locale/bitcoin_nb.ts
@@ -269,6 +269,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Vil du tilbakestille innstillingene til utgangsverdiene, eller vil du avbryte uten å gjøre endringer?</translation>
</message>
<message>
+ <source>A fatal error occurred. Check that settings file is writable, or try running with -nosettings.</source>
+ <extracomment>Explanatory text shown on startup when the settings file could not be written. Prompts user to check that we have the ability to write to the file. Explains that the user has the option of running without a settings file.</extracomment>
+ <translation type="unfinished">En fatal feil har oppstått. Sjekk at filen med innstillinger er skrivbar eller prøv å kjøre med -nosettings.</translation>
+ </message>
+ <message>
<source>Error: Specified data directory "%1" does not exist.</source>
<translation type="unfinished">Feil: Den spesifiserte datamappen "%1" finnes ikke.</translation>
</message>
@@ -350,36 +355,36 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message numerus="yes">
<source>%n second(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n sekund</numerusform>
+ <numerusform>%n sekunder</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n minute(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n minutt</numerusform>
+ <numerusform>%n minutter</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n hour(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n time</numerusform>
+ <numerusform>%n timer</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n day(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n dag</numerusform>
+ <numerusform>%n dager</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n week(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n uke</numerusform>
+ <numerusform>%n uker</numerusform>
</translation>
</message>
<message>
@@ -389,8 +394,8 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message numerus="yes">
<source>%n year(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>%n år</numerusform>
+ <numerusform>%n år</numerusform>
</translation>
</message>
</context>
@@ -553,6 +558,12 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Kan ikke sette -peerblockfilters uten -blockfilterindex</translation>
</message>
<message>
+ <source>
+Unable to restore backup of wallet.</source>
+ <translation type="unfinished">
+Kunne ikke gjenopprette sikkerhetskopi av lommebok.</translation>
+ </message>
+ <message>
<source>Copyright (C) %i-%i</source>
<translation type="unfinished">Kopirett © %i-%i</translation>
</message>
@@ -749,6 +760,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Må oppgi en port med -whitebind: '%s'</translation>
</message>
<message>
+ <source>No addresses available</source>
+ <translation type="unfinished">Ingen adresser tilgjengelig</translation>
+ </message>
+ <message>
<source>Not enough file descriptors available.</source>
<translation type="unfinished">For få fildeskriptorer tilgjengelig.</translation>
</message>
@@ -1188,6 +1203,16 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Lukk lommebok</translation>
</message>
<message>
+ <source>Restore Wallet…</source>
+ <extracomment>Name of the menu item that restores wallet from a backup file.</extracomment>
+ <translation type="unfinished">Gjenopprett lommebok...</translation>
+ </message>
+ <message>
+ <source>Restore a wallet from a backup file</source>
+ <extracomment>Status tip for Restore Wallet menu item</extracomment>
+ <translation type="unfinished">Gjenopprett en lommebok fra en sikkerhetskopi</translation>
+ </message>
+ <message>
<source>Close all wallets</source>
<translation type="unfinished">Lukk alle lommebøker</translation>
</message>
@@ -1217,6 +1242,16 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Lommebokdata</translation>
</message>
<message>
+ <source>Load Wallet Backup</source>
+ <extracomment>The title for Restore Wallet File Windows</extracomment>
+ <translation type="unfinished">Last lommebok sikkerhetskopi</translation>
+ </message>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of pop-up window shown when the user is attempting to restore a wallet.</extracomment>
+ <translation type="unfinished">Gjenopprett lommebok</translation>
+ </message>
+ <message>
<source>Wallet Name</source>
<extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
<translation type="unfinished">Lommeboknavn</translation>
@@ -1262,6 +1297,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Klikk for å aktivere nettverksaktivitet.</translation>
</message>
<message>
+ <source>Pre-syncing Headers (%1%)…</source>
+ <translation type="unfinished">Synkroniserer blokkhoder (%1%)...</translation>
+ </message>
+ <message>
<source>Error: %1</source>
<translation type="unfinished">Feil: %1</translation>
</message>
@@ -1550,6 +1589,14 @@ Signing is only possible with addresses of the type 'legacy'.</source>
</message>
</context>
<context>
+ <name>RestoreWalletActivity</name>
+ <message>
+ <source>Restore Wallet</source>
+ <extracomment>Title of progress window which is displayed when wallets are being restored.</extracomment>
+ <translation type="unfinished">Gjenopprett lommebok</translation>
+ </message>
+ </context>
+<context>
<name>WalletController</name>
<message>
<source>Close wallet</source>
@@ -1730,15 +1777,15 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<message numerus="yes">
<source>(of %n GB needed)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>(av %n GB som trengs)</numerusform>
+ <numerusform>(av %n GB som trengs)</numerusform>
</translation>
</message>
<message numerus="yes">
<source>(%n GB needed for full chain)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>(%n GB kreves for hele kjeden)</numerusform>
+ <numerusform>(%n GB kreves for hele kjeden)</numerusform>
</translation>
</message>
<message>
@@ -1890,7 +1937,11 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<source>%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.</source>
<translation type="unfinished">%1 synkroniseres for øyeblikket. Den vil laste ned blokkhoder og blokker fra likemenn og validere dem til de når enden av blokkjeden.</translation>
</message>
- </context>
+ <message>
+ <source>Unknown. Pre-syncing Headers (%1, %2%)…</source>
+ <translation type="unfinished">Ukjent.Synkroniser blokkhoder (%1,%2%)...</translation>
+ </message>
+</context>
<context>
<name>OpenURIDialog</name>
<message>
@@ -1942,6 +1993,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Minimer i stedet for å avslutte applikasjonen når vinduet lukkes. Når dette er valgt, vil applikasjonen avsluttes kun etter at Avslutte er valgt i menyen.</translation>
</message>
<message>
+ <source>Options set in this dialog are overridden by the command line:</source>
+ <translation type="unfinished">Alternativer som er satt i denne dialogboksen overstyres av kommandolinjen:</translation>
+ </message>
+ <message>
<source>Open the %1 configuration file from the working directory.</source>
<translation type="unfinished">Åpne %1-oppsettsfila fra arbeidsmappen.</translation>
</message>
@@ -2351,6 +2406,10 @@ Signing is only possible with addresses of the type 'legacy'.</source>
<translation type="unfinished">Transaksjonen trenger signatur(er).</translation>
</message>
<message>
+ <source>(But no wallet is loaded.)</source>
+ <translation type="unfinished">(Men ingen lommebok er lastet.)</translation>
+ </message>
+ <message>
<source>(But this wallet cannot sign transactions.)</source>
<translation type="unfinished">(Men denne lommeboken kan ikke signere transaksjoner.)</translation>
</message>
@@ -2420,6 +2479,11 @@ Hvis du får denne feilen burde du be forretningsdrivende om å tilby en BIP21 k
<translation type="unfinished">Likemann</translation>
</message>
<message>
+ <source>Age</source>
+ <extracomment>Title of Peers Table column which indicates the duration (length of time) since the peer connection started.</extracomment>
+ <translation type="unfinished">Alder</translation>
+ </message>
+ <message>
<source>Direction</source>
<extracomment>Title of Peers Table column which indicates the direction the peer connection was initiated from.</extracomment>
<translation type="unfinished">Retning</translation>
@@ -2602,6 +2666,11 @@ Hvis du får denne feilen burde du be forretningsdrivende om å tilby en BIP21 k
<translation type="unfinished">Kartlagt AS</translation>
</message>
<message>
+ <source>Addresses Processed</source>
+ <extracomment>Text title for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment>
+ <translation type="unfinished">Adresser Prosessert</translation>
+ </message>
+ <message>
<source>User Agent</source>
<translation type="unfinished">Brukeragent</translation>
</message>
@@ -3272,6 +3341,11 @@ Hvis du får denne feilen burde du be forretningsdrivende om å tilby en BIP21 k
<translation type="unfinished">Se over ditt transaksjonsforslag. Dette kommer til å produsere en Delvis Signert Bitcoin Transaksjon (PSBT) som du kan lagre eller kopiere og så signere med f.eks. en offline %1 lommebok, eller en PSBT kompatibel hardware lommebok.</translation>
</message>
<message>
+ <source>Do you want to create this transaction?</source>
+ <extracomment>Message displayed when attempting to create a transaction. Cautionary text to prompt the user to verify that the displayed transaction details represent the transaction the user intends to create.</extracomment>
+ <translation type="unfinished">Vil du lage denne transaksjonen?</translation>
+ </message>
+ <message>
<source>Please, review your transaction.</source>
<extracomment>Text to prompt a user to review the details of the transaction they are attempting to send.</extracomment>
<translation type="unfinished">Vennligst se over transaksjonen din.</translation>
@@ -3637,8 +3711,8 @@ Hvis du får denne feilen burde du be forretningsdrivende om å tilby en BIP21 k
<message numerus="yes">
<source>matures in %n more block(s)</source>
<translation type="unfinished">
- <numerusform />
- <numerusform />
+ <numerusform>modner om %n blokk</numerusform>
+ <numerusform>modner om %n blokker</numerusform>
</translation>
</message>
<message>
diff --git a/src/qt/locale/bitcoin_pa.ts b/src/qt/locale/bitcoin_pa.ts
new file mode 100644
index 0000000000..e72f6a4bf0
--- /dev/null
+++ b/src/qt/locale/bitcoin_pa.ts
@@ -0,0 +1,448 @@
+<TS version="2.1" language="pa">
+<context>
+ <name>AddressBookPage</name>
+ <message>
+ <source>Right-click to edit address or label</source>
+ <translation type="unfinished">ਪਤੇ ਜਾਂ ਲੇਬਲ ਦਾ ਸੰਪਾਦਨ ਕਰਨ ਲਈ ਸੱਜਾ-ਕਲਿੱਕ ਕਰੋ</translation>
+ </message>
+ <message>
+ <source>Create a new address</source>
+ <translation type="unfinished">ਨਵਾਂ ਪਤਾ ਬਣਾਓ</translation>
+ </message>
+ <message>
+ <source>&amp;New</source>
+ <translation type="unfinished">&amp;ਨਵਾਂ</translation>
+ </message>
+ <message>
+ <source>Copy the currently selected address to the system clipboard</source>
+ <translation type="unfinished">ਚੁਣੇ ਪਤੇ ਦੀ ਸਿਸਟਮ ਦੀ ਚੂੰਢੀ-ਤਖਤੀ 'ਤੇ ਨਕਲ ਲਾਹੋ</translation>
+ </message>
+ <message>
+ <source>&amp;Copy</source>
+ <translation type="unfinished">&amp;ਨਕਲ ਲਾਹੋ</translation>
+ </message>
+ <message>
+ <source>C&amp;lose</source>
+ <translation type="unfinished">ਬੰ&amp;ਦ ਕਰੋ</translation>
+ </message>
+ <message>
+ <source>Delete the currently selected address from the list</source>
+ <translation type="unfinished">ਚੁਣੇ ਪਤੇ ਨੂੰ ਸੂਚੀ ਵਿੱਚੋਂ ਮਿਟਾਓ</translation>
+ </message>
+ <message>
+ <source>Enter address or label to search</source>
+ <translation type="unfinished">ਖੋਜਣ ਲਈ ਪਤਾ ਜਾਂ ਲੇਬਲ ਦਾਖਲ ਕਰੋ</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation type="unfinished">ਮੌਜੂਦਾ ਟੈਬ ਵਿੱਚ ਡੇਟਾ ਨੂੰ ਫਾਈਲ ਵਿੱਚ ਐਕਸਪੋਰਟ ਕਰੋ</translation>
+ </message>
+ <message>
+ <source>&amp;Export</source>
+ <translation type="unfinished">&amp;ਨਿਰਯਾਤ</translation>
+ </message>
+ <message>
+ <source>&amp;Delete</source>
+ <translation type="unfinished">&amp;ਮਿਟਾਓ</translation>
+ </message>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation type="unfinished">ਸਿੱਕੇ ਭੇਜਣ ਲਈ ਪਤਾ ਚੁਣੋ</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation type="unfinished">ਸਿੱਕੇ ਪ੍ਰਾਪਤ ਕਰਨ ਲਈ ਪਤਾ ਚੁਣੋ</translation>
+ </message>
+ <message>
+ <source>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</source>
+ <translation type="unfinished">ਇਹ ਭੁਗਤਾਨ ਭੇਜਣ ਲਈ ਤੁਹਾਡੇ ਬਿਟਕੋਇਨ ਪਤੇ ਹਨ। ਸਿੱਕੇ ਭੇਜਣ ਤੋਂ ਪਹਿਲਾਂ ਹਮੇਸ਼ਾਂ ਰਕਮ ਅਤੇ ਪ੍ਰਾਪਤ ਕਰਨ ਵਾਲੇ ਪਤੇ ਦੀ ਜਾਂਚ ਕਰੋ।</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation type="unfinished">&amp;ਕਾਪੀ ਪਤਾ</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation type="unfinished">&amp;ਲੇਬਲ ਕਾਪੀ ਕਰੋ</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation type="unfinished">&amp;ਸੋਧੋ</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation type="unfinished">ਪਤਾ ਸੂਚੀ ਨਿਰਯਾਤ ਕਰੋ</translation>
+ </message>
+ <message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">ਕਾਮੇ ਨਾਲ ਵੱਖ ਕੀਤੀ ਫਾਈਲ</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation type="unfinished">ਨਿਰਯਾਤ ਅਸਫਲ ਰਿਹਾ</translation>
+ </message>
+</context>
+<context>
+ <name>AddressTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation type="unfinished">ਲੇਬਲ</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation type="unfinished">ਪਤਾ</translation>
+ </message>
+ </context>
+<context>
+ <name>AskPassphraseDialog</name>
+ <message>
+ <source>Passphrase Dialog</source>
+ <translation type="unfinished">ਪਾਸਫਰੇਜ ਡਾਇਲਾਗ</translation>
+ </message>
+ <message>
+ <source>Enter passphrase</source>
+ <translation type="unfinished">ਪਾਸਫਰੇਜ ਲਿਖੋ</translation>
+ </message>
+ <message>
+ <source>New passphrase</source>
+ <translation type="unfinished">ਨਵਾਂ ਪਾਸਫਰੇਜ</translation>
+ </message>
+ <message>
+ <source>Repeat new passphrase</source>
+ <translation type="unfinished">ਨਵਾਂ ਪਾਸਫਰੇਜ ਦੁਹਰਾਓ</translation>
+ </message>
+ <message>
+ <source>Show passphrase</source>
+ <translation type="unfinished">ਪਾਸਫਰੇਜ ਦਿਖਾਓ</translation>
+ </message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation type="unfinished">ਵਾਲਿਟ ਐਨਕ੍ਰਿਪਟ ਕਰੋ</translation>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation type="unfinished">ਵਾਲਿਟ ਨੂੰ ਅਨਲੌਕ ਕਰੋ</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation type="unfinished">ਪਾਸਫਰੇਜ ਬਦਲੋ</translation>
+ </message>
+ <message>
+ <source>Confirm wallet encryption</source>
+ <translation type="unfinished">ਵਾਲਿਟ ਇਨਕ੍ਰਿਪਸ਼ਨ ਦੀ ਪੁਸ਼ਟੀ ਕਰੋ</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to encrypt your wallet?</source>
+ <translation type="unfinished">ਕੀ ਤੁਸੀਂ ਯਕੀਨੀ ਤੌਰ 'ਤੇ ਆਪਣੇ ਵਾਲਿਟ ਨੂੰ ਐਨਕ੍ਰਿਪਟ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?</translation>
+ </message>
+ <message>
+ <source>Wallet encrypted</source>
+ <translation type="unfinished">ਵਾਲਿਟ ਨੂੰ ਐਨਕ੍ਰਿਪਟ ਕੀਤਾ ਗਿਆ</translation>
+ </message>
+ <message>
+ <source>Wallet to be encrypted</source>
+ <translation type="unfinished">ਇਨਕ੍ਰਿਪਟਡ ਹੋਣ ਲਈ ਵਾਲਿਟ</translation>
+ </message>
+ <message>
+ <source>Your wallet is about to be encrypted. </source>
+ <translation type="unfinished">ਤੁਹਾਡਾ ਵਾਲਿਟ ਐਨਕ੍ਰਿਪਟ ਹੋਣ ਵਾਲਾ ਹੈ।</translation>
+ </message>
+ <message>
+ <source>Your wallet is now encrypted. </source>
+ <translation type="unfinished">ਤੁਹਾਡਾ ਵਾਲਿਟ ਹੁਣ ਏਨਕ੍ਰਿਪਟ ਹੋ ਗਿਆ ਹੈ।</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed</source>
+ <translation type="unfinished">ਵਾਲਿਟ ਇਨਕ੍ਰਿਪਸ਼ਨ ਅਸਫਲ</translation>
+ </message>
+ <message>
+ <source>The supplied passphrases do not match.</source>
+ <translation type="unfinished">ਸਪਲਾਈ ਕੀਤੇ ਪਾਸਫਰੇਜ਼ ਮੇਲ ਨਹੀਂ ਖਾਂਦੇ।</translation>
+ </message>
+ <message>
+ <source>Wallet unlock failed</source>
+ <translation type="unfinished">ਵਾਲਿਟ ਅਨਲੌਕ ਅਸਫਲ ਰਿਹਾ</translation>
+ </message>
+ <message>
+ <source>Wallet passphrase was successfully changed.</source>
+ <translation type="unfinished">ਵਾਲਿਟ ਪਾਸਫਰੇਜ ਸਫਲਤਾਪੂਰਵਕ ਬਦਲਿਆ ਗਿਆ।</translation>
+ </message>
+ <message>
+ <source>Warning: The Caps Lock key is on!</source>
+ <translation type="unfinished">ਚੇਤਾਵਨੀ: Caps Lock ਕੁੰਜੀ ਚਾਲੂ ਹੈ!</translation>
+ </message>
+</context>
+<context>
+ <name>BitcoinApplication</name>
+ <message>
+ <source>A fatal error occurred. %1 can no longer continue safely and will quit.</source>
+ <translation type="unfinished">ਇੱਕ ਘਾਤਕ ਗਲਤੀ ਆਈ ਹੈ। %1ਹੁਣ ਸੁਰੱਖਿਅਤ ਢੰਗ ਨਾਲ ਜਾਰੀ ਨਹੀਂ ਰਹਿ ਸਕਦਾ ਹੈ ਅਤੇ ਛੱਡ ਦੇਵੇਗਾ।</translation>
+ </message>
+ <message>
+ <source>Internal error</source>
+ <translation type="unfinished">ਅੰਦਰੂਨੀ ਗੜਬੜ</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject</name>
+ <message>
+ <source>Error: %1</source>
+ <translation type="unfinished">ਗਲਤੀ: %1</translation>
+ </message>
+ <message numerus="yes">
+ <source>%n second(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>%n minute(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>%n hour(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>%n day(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>%n week(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>%n year(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ </context>
+<context>
+ <name>bitcoin-core</name>
+ <message>
+ <source>Settings file could not be read</source>
+ <translation type="unfinished">ਸੈਟਿੰਗ ਫਾਈਲ ਨੂੰ ਪੜ੍ਹਨ ਵਿੱਚ ਅਸਫਲ</translation>
+ </message>
+ <message>
+ <source>Settings file could not be written</source>
+ <translation type="unfinished">ਸੈਟਿੰਗ ਫਾਈਲ ਲਿਖਣ ਵਿੱਚ ਅਸਫਲ</translation>
+ </message>
+ </context>
+<context>
+ <name>BitcoinGUI</name>
+ <message>
+ <source>&amp;Overview</source>
+ <translation type="unfinished">&amp;ਓਵਰਵਿਊ</translation>
+ </message>
+ <message>
+ <source>&amp;Transactions</source>
+ <translation type="unfinished">&amp;ਲੈਣ-ਦੇਣ</translation>
+ </message>
+ <message>
+ <source>Browse transaction history</source>
+ <translation type="unfinished">ਲੈਣ-ਦੇਣ ਦਾ ਇਤਿਹਾਸ ਬ੍ਰਾਊਜ਼ ਕਰੋ</translation>
+ </message>
+ <message>
+ <source>Quit application</source>
+ <translation type="unfinished">ਐਪਲੀਕੇਸ਼ਨ ਛੱਡੋ</translation>
+ </message>
+ <message>
+ <source>Create a new wallet</source>
+ <translation type="unfinished">ਨਵਾਂ ਵਾਲਿਟ ਬਣਾਓ</translation>
+ </message>
+ <message>
+ <source>Wallet:</source>
+ <translation type="unfinished">ਬਟੂਆ: </translation>
+ </message>
+ <message>
+ <source>Send coins to a Bitcoin address</source>
+ <translation type="unfinished">ਬਿਟਕੋਇਨ ਪਤੇ 'ਤੇ ਸਿੱਕੇ ਭੇਜੋ</translation>
+ </message>
+ <message>
+ <source>Backup wallet to another location</source>
+ <translation type="unfinished">ਵਾਲਿਟ ਨੂੰ ਕਿਸੇ ਹੋਰ ਥਾਂ 'ਤੇ ਬੈਕਅੱਪ ਕਰੋ</translation>
+ </message>
+ <message>
+ <source>Change the passphrase used for wallet encryption</source>
+ <translation type="unfinished">ਵਾਲਿਟ ਇਨਕ੍ਰਿਪਸ਼ਨ ਲਈ ਵਰਤਿਆ ਜਾਣ ਵਾਲਾ ਪਾਸਫਰੇਜ ਬਦਲੋ</translation>
+ </message>
+ <message>
+ <source>&amp;Send</source>
+ <translation type="unfinished">&amp;ਭੇਜੋ</translation>
+ </message>
+ <message>
+ <source>&amp;Receive</source>
+ <translation type="unfinished">&amp;ਪ੍ਰਾਪਤ ਕਰੋ</translation>
+ </message>
+ <message>
+ <source>&amp;Encrypt Wallet…</source>
+ <translation type="unfinished">&amp;ਵਾਲਿਟ ਇਨਕ੍ਰਿਪਟ ਕਰੋ...</translation>
+ </message>
+ <message>
+ <source>Encrypt the private keys that belong to your wallet</source>
+ <translation type="unfinished">ਨਿੱਜੀ ਕੁੰਜੀਆਂ ਨੂੰ ਐਨਕ੍ਰਿਪਟ ਕਰੋ ਜੋ ਤੁਹਾਡੇ ਵਾਲਿਟ ਨਾਲ ਸਬੰਧਤ ਹਨ</translation>
+ </message>
+ <message>
+ <source>&amp;Backup Wallet…</source>
+ <translation type="unfinished">&amp;ਬੈਕਅੱਪ ਵਾਲਿਟ…</translation>
+ </message>
+ <message>
+ <source>&amp;Change Passphrase…</source>
+ <translation type="unfinished">ਪਾਸਫਰੇਜ &amp;ਬਦਲੋ...</translation>
+ </message>
+ <message numerus="yes">
+ <source>Processed %n block(s) of transaction history.</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>%n active connection(s) to Bitcoin network.</source>
+ <extracomment>A substring of the tooltip.</extracomment>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message>
+ <source>Error: %1</source>
+ <translation type="unfinished">ਗਲਤੀ: %1</translation>
+ </message>
+ </context>
+<context>
+ <name>Intro</name>
+ <message numerus="yes">
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(sufficient to restore backups %n day(s) old)</source>
+ <extracomment>Explanatory text on the capability of the current prune target.</extracomment>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ </context>
+<context>
+ <name>PeerTableModel</name>
+ <message>
+ <source>Address</source>
+ <extracomment>Title of Peers Table column which contains the IP/Onion/I2P address of the connected peer.</extracomment>
+ <translation type="unfinished">ਪਤਾ</translation>
+ </message>
+ </context>
+<context>
+ <name>ReceiveRequestDialog</name>
+ <message>
+ <source>Wallet:</source>
+ <translation type="unfinished">ਬਟੂਆ: </translation>
+ </message>
+ </context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation type="unfinished">ਲੇਬਲ</translation>
+ </message>
+ </context>
+<context>
+ <name>SendCoinsDialog</name>
+ <message numerus="yes">
+ <source>Estimated to begin confirmation within %n block(s).</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ </context>
+<context>
+ <name>TransactionDesc</name>
+ <message numerus="yes">
+ <source>matures in %n more block(s)</source>
+ <translation type="unfinished">
+ <numerusform />
+ <numerusform />
+ </translation>
+ </message>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation type="unfinished">ਲੇਬਲ</translation>
+ </message>
+ </context>
+<context>
+ <name>TransactionView</name>
+ <message>
+ <source>Comma separated file</source>
+ <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment>
+ <translation type="unfinished">ਕਾਮੇ ਨਾਲ ਵੱਖ ਕੀਤੀ ਫਾਈਲ</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation type="unfinished">ਲੇਬਲ</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation type="unfinished">ਪਤਾ</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation type="unfinished">ਨਿਰਯਾਤ ਅਸਫਲ ਰਿਹਾ</translation>
+ </message>
+ </context>
+<context>
+ <name>WalletFrame</name>
+ <message>
+ <source>Create a new wallet</source>
+ <translation type="unfinished">ਨਵਾਂ ਵਾਲਿਟ ਬਣਾਓ</translation>
+ </message>
+ </context>
+<context>
+ <name>WalletView</name>
+ <message>
+ <source>&amp;Export</source>
+ <translation type="unfinished">&amp;ਨਿਰਯਾਤ</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation type="unfinished">ਮੌਜੂਦਾ ਟੈਬ ਵਿੱਚ ਡੇਟਾ ਨੂੰ ਫਾਈਲ ਵਿੱਚ ਐਕਸਪੋਰਟ ਕਰੋ</translation>
+ </message>
+ </context>
+</TS> \ No newline at end of file
diff --git a/src/qt/locale/bitcoin_th.ts b/src/qt/locale/bitcoin_th.ts
index b98dac68f5..44052c6b24 100644
--- a/src/qt/locale/bitcoin_th.ts
+++ b/src/qt/locale/bitcoin_th.ts
@@ -312,31 +312,31 @@ Signing is only possible with addresses of the type 'legacy'</translation>
<message numerus="yes">
<source>%n second(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%nวินาที</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n minute(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%nนาที</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n hour(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%nชั่วโมง</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n day(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%nวัน</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n week(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%nสัปดาห์</numerusform>
</translation>
</message>
<message>
@@ -346,7 +346,7 @@ Signing is only possible with addresses of the type 'legacy'</translation>
<message numerus="yes">
<source>%n year(s)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>%nปี</numerusform>
</translation>
</message>
<message>
@@ -1526,13 +1526,13 @@ Signing is only possible with addresses of the type 'legacy'</translation>
<message numerus="yes">
<source>%n GB of space available</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>มีพื้นที่ว่าง %n GB ที่ใช้งานได้</numerusform>
</translation>
</message>
<message numerus="yes">
<source>(of %n GB needed)</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>(ต้องการพื้นที่ %n GB )</numerusform>
</translation>
</message>
<message numerus="yes">
diff --git a/src/qt/locale/bitcoin_tr.ts b/src/qt/locale/bitcoin_tr.ts
index fc64a8b14b..f7c86ecd4f 100644
--- a/src/qt/locale/bitcoin_tr.ts
+++ b/src/qt/locale/bitcoin_tr.ts
@@ -248,6 +248,10 @@ Cüzdan kilidini aç.</translation>
<context>
<name>BitcoinApplication</name>
<message>
+ <source>Settings file %1 might be corrupt or invalid.</source>
+ <translation type="unfinished">%1 ayar dosyası bozuk veya geçersiz olabilir.</translation>
+ </message>
+ <message>
<source>Runaway exception</source>
<translation type="unfinished">Sızıntı istisnası</translation>
</message>
@@ -985,7 +989,7 @@ Cüzdan kilidini aç.</translation>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation type="unfinished">
- <numerusform />
+ <numerusform>İşlem geçmişinin %n bloğu işlendi.</numerusform>
</translation>
</message>
<message>
@@ -1403,7 +1407,11 @@ Cüzdan kilidini aç.</translation>
<source>Create wallet warning</source>
<translation type="unfinished">Cüzdan oluşturma uyarısı</translation>
</message>
- </context>
+ <message>
+ <source>Too many external signers found</source>
+ <translation type="unfinished">Çok fazla harici imzalayan bulundu</translation>
+ </message>
+</context>
<context>
<name>LoadWalletsActivity</name>
<message>
@@ -1449,6 +1457,16 @@ Cüzdan kilidini aç.</translation>
<extracomment>Title of progress window which is displayed when wallets are being restored.</extracomment>
<translation type="unfinished">Cüzdanı Geri Yükle</translation>
</message>
+ <message>
+ <source>Restore wallet failed</source>
+ <extracomment>Title of message box which is displayed when the wallet could not be restored.</extracomment>
+ <translation type="unfinished">Cüzdan geri yüklenemedi</translation>
+ </message>
+ <message>
+ <source>Restore wallet warning</source>
+ <extracomment>Title of message box which is displayed when the wallet is restored with some warning.</extracomment>
+ <translation type="unfinished">Cüzdan uyarısını geri yükle</translation>
+ </message>
</context>
<context>
<name>WalletController</name>
diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp
index 8dc97e66a2..adc7793916 100644
--- a/src/qt/walletframe.cpp
+++ b/src/qt/walletframe.cpp
@@ -212,7 +212,7 @@ void WalletFrame::gotoLoadPSBT(bool from_clipboard)
return;
}
std::ifstream in{filename.toLocal8Bit().data(), std::ios::binary};
- data.assign(std::istream_iterator<unsigned char>{in}, {});
+ data.assign(std::istreambuf_iterator<char>{in}, {});
// Some psbt files may be base64 strings in the file rather than binary data
std::string b64_str{data.begin(), data.end()};
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
index 5da0d076d8..0d74a661a5 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -146,6 +146,16 @@ static bool CreateSig(const BaseSignatureCreator& creator, SignatureData& sigdat
static bool CreateTaprootScriptSig(const BaseSignatureCreator& creator, SignatureData& sigdata, const SigningProvider& provider, std::vector<unsigned char>& sig_out, const XOnlyPubKey& pubkey, const uint256& leaf_hash, SigVersion sigversion)
{
+ KeyOriginInfo info;
+ if (provider.GetKeyOriginByXOnly(pubkey, info)) {
+ auto it = sigdata.taproot_misc_pubkeys.find(pubkey);
+ if (it == sigdata.taproot_misc_pubkeys.end()) {
+ sigdata.taproot_misc_pubkeys.emplace(pubkey, std::make_pair(std::set<uint256>({leaf_hash}), info));
+ } else {
+ it->second.first.insert(leaf_hash);
+ }
+ }
+
auto lookup_key = std::make_pair(pubkey, leaf_hash);
auto it = sigdata.taproot_script_sigs.find(lookup_key);
if (it != sigdata.taproot_script_sigs.end()) {
@@ -170,17 +180,6 @@ static bool SignTaprootScript(const SigningProvider& provider, const BaseSignatu
// <xonly pubkey> OP_CHECKSIG
if (script.size() == 34 && script[33] == OP_CHECKSIG && script[0] == 0x20) {
XOnlyPubKey pubkey{Span{script}.subspan(1, 32)};
-
- KeyOriginInfo info;
- if (provider.GetKeyOriginByXOnly(pubkey, info)) {
- auto it = sigdata.taproot_misc_pubkeys.find(pubkey);
- if (it == sigdata.taproot_misc_pubkeys.end()) {
- sigdata.taproot_misc_pubkeys.emplace(pubkey, std::make_pair(std::set<uint256>({leaf_hash}), info));
- } else {
- it->second.first.insert(leaf_hash);
- }
- }
-
std::vector<unsigned char> sig;
if (CreateTaprootScriptSig(creator, sigdata, provider, sig, pubkey, leaf_hash, sigversion)) {
result = Vector(std::move(sig));
diff --git a/src/wallet/rpc/spend.cpp b/src/wallet/rpc/spend.cpp
index bc65cbf7bf..7064a50937 100644
--- a/src/wallet/rpc/spend.cpp
+++ b/src/wallet/rpc/spend.cpp
@@ -747,7 +747,7 @@ RPCHelpMan fundrawtransaction()
"If that happens, you will need to fund the transaction with different inputs and republish it."},
{"changeAddress", RPCArg::Type::STR, RPCArg::DefaultHint{"automatic"}, "The bitcoin address to receive the change"},
{"changePosition", RPCArg::Type::NUM, RPCArg::DefaultHint{"random"}, "The index of the change output"},
- {"change_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -changetype"}, "The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
+ {"change_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -changetype"}, "The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", \"bech32\", and \"bech32m\"."},
{"includeWatching", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Also select inputs which are watch only.\n"
"Only solvable inputs can be used. Watch-only destinations are solvable if the public key and/or output script was imported,\n"
"e.g. with 'importpubkey' or 'importmulti' with the 'pubkeys' or 'desc' field."},
@@ -1144,7 +1144,7 @@ RPCHelpMan send()
{"add_to_wallet", RPCArg::Type::BOOL, RPCArg::Default{true}, "When false, returns a serialized transaction which will not be added to the wallet or broadcast"},
{"change_address", RPCArg::Type::STR, RPCArg::DefaultHint{"automatic"}, "The bitcoin address to receive the change"},
{"change_position", RPCArg::Type::NUM, RPCArg::DefaultHint{"random"}, "The index of the change output"},
- {"change_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -changetype"}, "The output type to use. Only valid if change_address is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
+ {"change_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -changetype"}, "The output type to use. Only valid if change_address is not specified. Options are \"legacy\", \"p2sh-segwit\", \"bech32\" and \"bech32m\"."},
{"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
{"include_watching", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Also select inputs which are watch only.\n"
"Only solvable inputs can be used. Watch-only destinations are solvable if the public key and/or output script was imported,\n"
@@ -1597,7 +1597,7 @@ RPCHelpMan walletcreatefundedpsbt()
"If that happens, you will need to fund the transaction with different inputs and republish it."},
{"changeAddress", RPCArg::Type::STR, RPCArg::DefaultHint{"automatic"}, "The bitcoin address to receive the change"},
{"changePosition", RPCArg::Type::NUM, RPCArg::DefaultHint{"random"}, "The index of the change output"},
- {"change_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -changetype"}, "The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
+ {"change_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -changetype"}, "The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", \"bech32\", and \"bech32m\"."},
{"includeWatching", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Also select inputs which are watch only"},
{"lockUnspents", RPCArg::Type::BOOL, RPCArg::Default{false}, "Lock selected unspent outputs"},
{"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
diff --git a/src/wallet/rpc/wallet.cpp b/src/wallet/rpc/wallet.cpp
index 675c4a759d..971814e9cd 100644
--- a/src/wallet/rpc/wallet.cpp
+++ b/src/wallet/rpc/wallet.cpp
@@ -730,7 +730,9 @@ static RPCHelpMan migratewallet()
std::shared_ptr<CWallet> wallet = GetWalletForJSONRPCRequest(request);
if (!wallet) return NullUniValue;
- EnsureWalletIsUnlocked(*wallet);
+ if (wallet->IsCrypted()) {
+ throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: migratewallet on encrypted wallets is currently unsupported.");
+ }
WalletContext& context = EnsureWalletContext(request.context);
diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp
index 41654579c6..3bcc6b4bdc 100644
--- a/src/wallet/scriptpubkeyman.cpp
+++ b/src/wallet/scriptpubkeyman.cpp
@@ -2499,14 +2499,23 @@ TransactionError DescriptorScriptPubKeyMan::FillPSBT(PartiallySignedTransaction&
keys->Merge(std::move(*script_keys));
} else {
// Maybe there are pubkeys listed that we can sign for
- script_keys = std::make_unique<FlatSigningProvider>();
- for (const auto& pk_pair : input.hd_keypaths) {
- const CPubKey& pubkey = pk_pair.first;
- std::unique_ptr<FlatSigningProvider> pk_keys = GetSigningProvider(pubkey);
- if (pk_keys) {
- keys->Merge(std::move(*pk_keys));
- }
+ std::vector<CPubKey> pubkeys;
+
+ // ECDSA Pubkeys
+ for (const auto& [pk, _] : input.hd_keypaths) {
+ pubkeys.push_back(pk);
+ }
+
+ // Taproot output pubkey
+ std::vector<std::vector<unsigned char>> sols;
+ if (Solver(script, sols) == TxoutType::WITNESS_V1_TAPROOT) {
+ sols[0].insert(sols[0].begin(), 0x02);
+ pubkeys.emplace_back(sols[0]);
+ sols[0][0] = 0x03;
+ pubkeys.emplace_back(sols[0]);
}
+
+ // Taproot pubkeys
for (const auto& pk_pair : input.m_tap_bip32_paths) {
const XOnlyPubKey& pubkey = pk_pair.first;
for (unsigned char prefix : {0x02, 0x03}) {
@@ -2514,10 +2523,14 @@ TransactionError DescriptorScriptPubKeyMan::FillPSBT(PartiallySignedTransaction&
std::copy(pubkey.begin(), pubkey.end(), b + 1);
CPubKey fullpubkey;
fullpubkey.Set(b, b + 33);
- std::unique_ptr<FlatSigningProvider> pk_keys = GetSigningProvider(fullpubkey);
- if (pk_keys) {
- keys->Merge(std::move(*pk_keys));
- }
+ pubkeys.push_back(fullpubkey);
+ }
+ }
+
+ for (const auto& pubkey : pubkeys) {
+ std::unique_ptr<FlatSigningProvider> pk_keys = GetSigningProvider(pubkey);
+ if (pk_keys) {
+ keys->Merge(std::move(*pk_keys));
}
}
}
diff --git a/src/wallet/spend.cpp b/src/wallet/spend.cpp
index ce41a4e954..f534e10799 100644
--- a/src/wallet/spend.cpp
+++ b/src/wallet/spend.cpp
@@ -102,15 +102,13 @@ void CoinsResult::Clear() {
coins.clear();
}
-void CoinsResult::Erase(std::set<COutPoint>& preset_coins)
+void CoinsResult::Erase(const std::set<COutPoint>& coins_to_remove)
{
- for (auto& it : coins) {
- auto& vec = it.second;
- auto i = std::find_if(vec.begin(), vec.end(), [&](const COutput &c) { return preset_coins.count(c.outpoint);});
- if (i != vec.end()) {
- vec.erase(i);
- break;
- }
+ for (auto& [type, vec] : coins) {
+ auto remove_it = std::remove_if(vec.begin(), vec.end(), [&](const COutput& coin) {
+ return coins_to_remove.count(coin.outpoint) == 1;
+ });
+ vec.erase(remove_it, vec.end());
}
}
diff --git a/src/wallet/spend.h b/src/wallet/spend.h
index c29e5be5c7..009e680627 100644
--- a/src/wallet/spend.h
+++ b/src/wallet/spend.h
@@ -47,7 +47,7 @@ struct CoinsResult {
* i.e., methods can work with individual OutputType vectors or on the entire object */
size_t Size() const;
void Clear();
- void Erase(std::set<COutPoint>& preset_coins);
+ void Erase(const std::set<COutPoint>& coins_to_remove);
void Shuffle(FastRandomContext& rng_fast);
void Add(OutputType type, const COutput& out);
diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp
index 23f024247d..9bc6fafae7 100644
--- a/src/wallet/test/coinselector_tests.cpp
+++ b/src/wallet/test/coinselector_tests.cpp
@@ -969,5 +969,45 @@ BOOST_AUTO_TEST_CASE(SelectCoins_effective_value_test)
BOOST_CHECK(!result);
}
+BOOST_FIXTURE_TEST_CASE(wallet_coinsresult_test, BasicTestingSetup)
+{
+ // Test case to verify CoinsResult object sanity.
+ CoinsResult available_coins;
+ {
+ std::unique_ptr<CWallet> dummyWallet = std::make_unique<CWallet>(m_node.chain.get(), "dummy", m_args, CreateMockWalletDatabase());
+ BOOST_CHECK_EQUAL(dummyWallet->LoadWallet(), DBErrors::LOAD_OK);
+ LOCK(dummyWallet->cs_wallet);
+ dummyWallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
+ dummyWallet->SetupDescriptorScriptPubKeyMans();
+
+ // Add some coins to 'available_coins'
+ for (int i=0; i<10; i++) {
+ add_coin(available_coins, *dummyWallet, 1 * COIN);
+ }
+ }
+
+ {
+ // First test case, check that 'CoinsResult::Erase' function works as expected.
+ // By trying to erase two elements from the 'available_coins' object.
+ std::set<COutPoint> outs_to_remove;
+ const auto& coins = available_coins.All();
+ for (int i = 0; i < 2; i++) {
+ outs_to_remove.emplace(coins[i].outpoint);
+ }
+ available_coins.Erase(outs_to_remove);
+
+ // Check that the elements were actually removed.
+ const auto& updated_coins = available_coins.All();
+ for (const auto& out: outs_to_remove) {
+ auto it = std::find_if(updated_coins.begin(), updated_coins.end(), [&out](const COutput &coin) {
+ return coin.outpoint == out;
+ });
+ BOOST_CHECK(it == updated_coins.end());
+ }
+ // And verify that no extra element were removed
+ BOOST_CHECK_EQUAL(available_coins.Size(), 8);
+ }
+}
+
BOOST_AUTO_TEST_SUITE_END()
} // namespace wallet
diff --git a/src/wallet/test/spend_tests.cpp b/src/wallet/test/spend_tests.cpp
index a75b014870..81a8883f85 100644
--- a/src/wallet/test/spend_tests.cpp
+++ b/src/wallet/test/spend_tests.cpp
@@ -112,5 +112,50 @@ BOOST_FIXTURE_TEST_CASE(FillInputToWeightTest, BasicTestingSetup)
// Note: We don't test the next boundary because of memory allocation constraints.
}
+BOOST_FIXTURE_TEST_CASE(wallet_duplicated_preset_inputs_test, TestChain100Setup)
+{
+ // Verify that the wallet's Coin Selection process does not include pre-selected inputs twice in a transaction.
+
+ // Add 4 spendable UTXO, 50 BTC each, to the wallet (total balance 200 BTC)
+ for (int i = 0; i < 4; i++) CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
+ auto wallet = CreateSyncedWallet(*m_node.chain, WITH_LOCK(Assert(m_node.chainman)->GetMutex(), return m_node.chainman->ActiveChain()), m_args, coinbaseKey);
+
+ LOCK(wallet->cs_wallet);
+ auto available_coins = AvailableCoins(*wallet);
+ std::vector<COutput> coins = available_coins.All();
+ // Preselect the first 3 UTXO (150 BTC total)
+ std::set<COutPoint> preset_inputs = {coins[0].outpoint, coins[1].outpoint, coins[2].outpoint};
+
+ // Try to create a tx that spends more than what preset inputs + wallet selected inputs are covering for.
+ // The wallet can cover up to 200 BTC, and the tx target is 299 BTC.
+ std::vector<CRecipient> recipients = {{GetScriptForDestination(*Assert(wallet->GetNewDestination(OutputType::BECH32, "dummy"))),
+ /*nAmount=*/299 * COIN, /*fSubtractFeeFromAmount=*/true}};
+ CCoinControl coin_control;
+ coin_control.m_allow_other_inputs = true;
+ for (const auto& outpoint : preset_inputs) {
+ coin_control.Select(outpoint);
+ }
+
+ // Attempt to send 299 BTC from a wallet that only has 200 BTC. The wallet should exclude
+ // the preset inputs from the pool of available coins, realize that there is not enough
+ // money to fund the 299 BTC payment, and fail with "Insufficient funds".
+ //
+ // Even with SFFO, the wallet can only afford to send 200 BTC.
+ // If the wallet does not properly exclude preset inputs from the pool of available coins
+ // prior to coin selection, it may create a transaction that does not fund the full payment
+ // amount or, through SFFO, incorrectly reduce the recipient's amount by the difference
+ // between the original target and the wrongly counted inputs (in this case 99 BTC)
+ // so that the recipient's amount is no longer equal to the user's selected target of 299 BTC.
+
+ // First case, use 'subtract_fee_from_outputs=true'
+ util::Result<CreatedTransactionResult> res_tx = CreateTransaction(*wallet, recipients, /*change_pos*/-1, coin_control);
+ BOOST_CHECK(!res_tx.has_value());
+
+ // Second case, don't use 'subtract_fee_from_outputs'.
+ recipients[0].fSubtractFeeFromAmount = false;
+ res_tx = CreateTransaction(*wallet, recipients, /*change_pos*/-1, coin_control);
+ BOOST_CHECK(!res_tx.has_value());
+}
+
BOOST_AUTO_TEST_SUITE_END()
} // namespace wallet
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index ac7bf46a14..36fe32e54d 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -4102,8 +4102,8 @@ util::Result<MigrationResult> MigrateLegacyToDescriptor(std::shared_ptr<CWallet>
// Make list of wallets to cleanup
std::vector<std::shared_ptr<CWallet>> created_wallets;
- created_wallets.push_back(std::move(res.watchonly_wallet));
- created_wallets.push_back(std::move(res.solvables_wallet));
+ if (res.watchonly_wallet) created_wallets.push_back(std::move(res.watchonly_wallet));
+ if (res.solvables_wallet) created_wallets.push_back(std::move(res.solvables_wallet));
// Get the directories to remove after unloading
for (std::shared_ptr<CWallet>& w : created_wallets) {
diff --git a/test/functional/p2p_tx_privacy.py b/test/functional/p2p_tx_privacy.py
new file mode 100755
index 0000000000..b885ccdf5d
--- /dev/null
+++ b/test/functional/p2p_tx_privacy.py
@@ -0,0 +1,78 @@
+#!/usr/bin/env python3
+# Copyright (c) 2022 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 that transaction announcements are only queued for peers that have
+successfully completed the version handshake.
+
+Topology:
+
+ tx_originator ----> node[0] <---- spy
+
+We test that a transaction sent by tx_originator is only relayed to spy
+if it was received after spy's version handshake completed.
+
+1. Fully connect tx_originator
+2. Connect spy (no version handshake)
+3. tx_originator sends tx1
+4. spy completes the version handshake
+5. tx_originator sends tx2
+6. We check that only tx2 is announced on the spy interface
+"""
+from test_framework.messages import (
+ msg_wtxidrelay,
+ msg_verack,
+ msg_tx,
+ CInv,
+ MSG_WTX,
+)
+from test_framework.p2p import (
+ P2PInterface,
+)
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.wallet import MiniWallet
+
+class P2PTxSpy(P2PInterface):
+ def __init__(self):
+ super().__init__()
+ self.all_invs = []
+
+ def on_version(self, message):
+ self.send_message(msg_wtxidrelay())
+
+ def on_inv(self, message):
+ self.all_invs += message.inv
+
+ def wait_for_inv_match(self, expected_inv):
+ self.wait_until(lambda: len(self.all_invs) == 1 and self.all_invs[0] == expected_inv)
+
+class TxPrivacyTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.num_nodes = 1
+
+ def run_test(self):
+ self.wallet = MiniWallet(self.nodes[0])
+ self.wallet.rescan_utxos()
+
+ tx_originator = self.nodes[0].add_p2p_connection(P2PInterface())
+ spy = self.nodes[0].add_p2p_connection(P2PTxSpy(), wait_for_verack=False)
+ spy.wait_for_verack()
+
+ # tx_originator sends tx1
+ tx1 = self.wallet.create_self_transfer()["tx"]
+ tx_originator.send_and_ping(msg_tx(tx1))
+
+ # Spy sends the verack
+ spy.send_and_ping(msg_verack())
+
+ # tx_originator sends tx2
+ tx2 = self.wallet.create_self_transfer()["tx"]
+ tx_originator.send_and_ping(msg_tx(tx2))
+
+ # Spy should only get an inv for the second transaction as the first
+ # one was received pre-verack with the spy
+ spy.wait_for_inv_match(CInv(MSG_WTX, tx2.calc_sha256(True)))
+
+if __name__ == '__main__':
+ TxPrivacyTest().main()
diff --git a/test/functional/rpc_fundrawtransaction.py b/test/functional/rpc_fundrawtransaction.py
index a963bb5e2d..9a3a356097 100755
--- a/test/functional/rpc_fundrawtransaction.py
+++ b/test/functional/rpc_fundrawtransaction.py
@@ -107,6 +107,7 @@ class RawTransactionsTest(BitcoinTestFramework):
self.generate(self.nodes[0], 121)
self.test_add_inputs_default_value()
+ self.test_preset_inputs_selection()
self.test_weight_calculation()
self.test_change_position()
self.test_simple()
@@ -1189,6 +1190,50 @@ class RawTransactionsTest(BitcoinTestFramework):
self.nodes[2].unloadwallet("test_preset_inputs")
+ def test_preset_inputs_selection(self):
+ self.log.info('Test wallet preset inputs are not double-counted or reused in coin selection')
+
+ # Create and fund the wallet with 4 UTXO of 5 BTC each (20 BTC total)
+ self.nodes[2].createwallet("test_preset_inputs_selection")
+ wallet = self.nodes[2].get_wallet_rpc("test_preset_inputs_selection")
+ outputs = {}
+ for _ in range(4):
+ outputs[wallet.getnewaddress(address_type="bech32")] = 5
+ self.nodes[0].sendmany("", outputs)
+ self.generate(self.nodes[0], 1)
+
+ # Select the preset inputs
+ coins = wallet.listunspent()
+ preset_inputs = [coins[0], coins[1], coins[2]]
+
+ # Now let's create the tx creation options
+ options = {
+ "inputs": preset_inputs,
+ "add_inputs": True, # automatically add coins from the wallet to fulfill the target
+ "subtract_fee_from_outputs": [0], # deduct fee from first output
+ "add_to_wallet": False
+ }
+
+ # Attempt to send 29 BTC from a wallet that only has 20 BTC. The wallet should exclude
+ # the preset inputs from the pool of available coins, realize that there is not enough
+ # money to fund the 29 BTC payment, and fail with "Insufficient funds".
+ #
+ # Even with SFFO, the wallet can only afford to send 20 BTC.
+ # If the wallet does not properly exclude preset inputs from the pool of available coins
+ # prior to coin selection, it may create a transaction that does not fund the full payment
+ # amount or, through SFFO, incorrectly reduce the recipient's amount by the difference
+ # between the original target and the wrongly counted inputs (in this case 9 BTC)
+ # so that the recipient's amount is no longer equal to the user's selected target of 29 BTC.
+
+ # First case, use 'subtract_fee_from_outputs = true'
+ assert_raises_rpc_error(-4, "Insufficient funds", wallet.send, outputs=[{wallet.getnewaddress(address_type="bech32"): 29}], options=options)
+
+ # Second case, don't use 'subtract_fee_from_outputs'
+ del options["subtract_fee_from_outputs"]
+ assert_raises_rpc_error(-4, "Insufficient funds", wallet.send, outputs=[{wallet.getnewaddress(address_type="bech32"): 29}], options=options)
+
+ self.nodes[2].unloadwallet("test_preset_inputs_selection")
+
def test_weight_calculation(self):
self.log.info("Test weight calculation with external inputs")
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index d78c1c634f..caa4af957a 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -316,6 +316,7 @@ BASE_SCRIPTS = [
'rpc_deriveaddresses.py',
'rpc_deriveaddresses.py --usecli',
'p2p_ping.py',
+ 'p2p_tx_privacy.py',
'rpc_scantxoutset.py',
'feature_txindex_compatibility.py',
'feature_unsupported_utxo_db.py',
diff --git a/test/functional/wallet_migration.py b/test/functional/wallet_migration.py
index 3c1cb6ac32..4f060f9960 100755
--- a/test/functional/wallet_migration.py
+++ b/test/functional/wallet_migration.py
@@ -393,6 +393,15 @@ class WalletMigrationTest(BitcoinTestFramework):
assert_equal(bals, wallet.getbalances())
+ def test_encrypted(self):
+ self.log.info("Test migration of an encrypted wallet")
+ wallet = self.create_legacy_wallet("encrypted")
+
+ wallet.encryptwallet("pass")
+
+ assert_raises_rpc_error(-15, "Error: migratewallet on encrypted wallets is currently unsupported.", wallet.migratewallet)
+ # TODO: Fix migratewallet so that we can actually migrate encrypted wallets
+
def run_test(self):
self.generate(self.nodes[0], 101)
@@ -402,6 +411,7 @@ class WalletMigrationTest(BitcoinTestFramework):
self.test_other_watchonly()
self.test_no_privkeys()
self.test_pk_coinbases()
+ self.test_encrypted()
if __name__ == '__main__':
WalletMigrationTest().main()
diff --git a/test/functional/wallet_taproot.py b/test/functional/wallet_taproot.py
index 3c630ba433..c2acafb373 100755
--- a/test/functional/wallet_taproot.py
+++ b/test/functional/wallet_taproot.py
@@ -5,6 +5,7 @@
"""Test generation and spending of P2TR addresses."""
import random
+import uuid
from decimal import Decimal
from test_framework.address import output_key_to_p2tr
@@ -229,17 +230,28 @@ class WalletTaprootTest(BitcoinTestFramework):
def do_test_addr(self, comment, pattern, privmap, treefn, keys):
self.log.info("Testing %s address derivation" % comment)
+
+ # Create wallets
+ wallet_uuid = uuid.uuid4().hex
+ self.nodes[0].createwallet(wallet_name=f"privs_tr_enabled_{wallet_uuid}", descriptors=True, blank=True)
+ self.nodes[0].createwallet(wallet_name=f"pubs_tr_enabled_{wallet_uuid}", descriptors=True, blank=True, disable_private_keys=True)
+ self.nodes[0].createwallet(wallet_name=f"addr_gen_{wallet_uuid}", descriptors=True, disable_private_keys=True, blank=True)
+ privs_tr_enabled = self.nodes[0].get_wallet_rpc(f"privs_tr_enabled_{wallet_uuid}")
+ pubs_tr_enabled = self.nodes[0].get_wallet_rpc(f"pubs_tr_enabled_{wallet_uuid}")
+ addr_gen = self.nodes[0].get_wallet_rpc(f"addr_gen_{wallet_uuid}")
+
desc = self.make_desc(pattern, privmap, keys, False)
desc_pub = self.make_desc(pattern, privmap, keys, True)
assert_equal(self.nodes[0].getdescriptorinfo(desc)['descriptor'], desc_pub)
- result = self.addr_gen.importdescriptors([{"desc": desc_pub, "active": True, "timestamp": "now"}])
+ result = addr_gen.importdescriptors([{"desc": desc_pub, "active": True, "timestamp": "now"}])
assert(result[0]['success'])
+ address_type = "bech32m" if "tr" in pattern else "bech32"
for i in range(4):
- addr_g = self.addr_gen.getnewaddress(address_type='bech32m')
+ addr_g = addr_gen.getnewaddress(address_type=address_type)
if treefn is not None:
addr_r = self.make_addr(treefn, keys, i)
assert_equal(addr_g, addr_r)
- desc_a = self.addr_gen.getaddressinfo(addr_g)['desc']
+ desc_a = addr_gen.getaddressinfo(addr_g)['desc']
if desc.startswith("tr("):
assert desc_a.startswith("tr(")
rederive = self.nodes[1].deriveaddresses(desc_a)
@@ -247,25 +259,37 @@ class WalletTaprootTest(BitcoinTestFramework):
assert_equal(rederive[0], addr_g)
# tr descriptors can be imported
- result = self.privs_tr_enabled.importdescriptors([{"desc": desc, "timestamp": "now"}])
+ result = privs_tr_enabled.importdescriptors([{"desc": desc, "timestamp": "now"}])
assert(result[0]["success"])
- result = self.pubs_tr_enabled.importdescriptors([{"desc": desc_pub, "timestamp": "now"}])
+ result = pubs_tr_enabled.importdescriptors([{"desc": desc_pub, "timestamp": "now"}])
assert(result[0]["success"])
+ # Cleanup
+ privs_tr_enabled.unloadwallet()
+ pubs_tr_enabled.unloadwallet()
+ addr_gen.unloadwallet()
+
def do_test_sendtoaddress(self, comment, pattern, privmap, treefn, keys_pay, keys_change):
self.log.info("Testing %s through sendtoaddress" % comment)
+
+ # Create wallets
+ wallet_uuid = uuid.uuid4().hex
+ self.nodes[0].createwallet(wallet_name=f"rpc_online_{wallet_uuid}", descriptors=True, blank=True)
+ rpc_online = self.nodes[0].get_wallet_rpc(f"rpc_online_{wallet_uuid}")
+
desc_pay = self.make_desc(pattern, privmap, keys_pay)
desc_change = self.make_desc(pattern, privmap, keys_change)
desc_pay_pub = self.make_desc(pattern, privmap, keys_pay, True)
desc_change_pub = self.make_desc(pattern, privmap, keys_change, True)
assert_equal(self.nodes[0].getdescriptorinfo(desc_pay)['descriptor'], desc_pay_pub)
assert_equal(self.nodes[0].getdescriptorinfo(desc_change)['descriptor'], desc_change_pub)
- result = self.rpc_online.importdescriptors([{"desc": desc_pay, "active": True, "timestamp": "now"}])
+ result = rpc_online.importdescriptors([{"desc": desc_pay, "active": True, "timestamp": "now"}])
assert(result[0]['success'])
- result = self.rpc_online.importdescriptors([{"desc": desc_change, "active": True, "timestamp": "now", "internal": True}])
+ result = rpc_online.importdescriptors([{"desc": desc_change, "active": True, "timestamp": "now", "internal": True}])
assert(result[0]['success'])
+ address_type = "bech32m" if "tr" in pattern else "bech32"
for i in range(4):
- addr_g = self.rpc_online.getnewaddress(address_type='bech32m')
+ addr_g = rpc_online.getnewaddress(address_type=address_type)
if treefn is not None:
addr_r = self.make_addr(treefn, keys_pay, i)
assert_equal(addr_g, addr_r)
@@ -273,31 +297,51 @@ class WalletTaprootTest(BitcoinTestFramework):
to_amnt = random.randrange(1000000, boring_balance)
self.boring.sendtoaddress(address=addr_g, amount=Decimal(to_amnt) / 100000000, subtractfeefromamount=True)
self.generatetoaddress(self.nodes[0], 1, self.boring.getnewaddress(), sync_fun=self.no_op)
- test_balance = int(self.rpc_online.getbalance() * 100000000)
+ test_balance = int(rpc_online.getbalance() * 100000000)
ret_amnt = random.randrange(100000, test_balance)
# Increase fee_rate to compensate for the wallet's inability to estimate fees for script path spends.
- res = self.rpc_online.sendtoaddress(address=self.boring.getnewaddress(), amount=Decimal(ret_amnt) / 100000000, subtractfeefromamount=True, fee_rate=200)
+ res = rpc_online.sendtoaddress(address=self.boring.getnewaddress(), amount=Decimal(ret_amnt) / 100000000, subtractfeefromamount=True, fee_rate=200)
self.generatetoaddress(self.nodes[0], 1, self.boring.getnewaddress(), sync_fun=self.no_op)
- assert(self.rpc_online.gettransaction(res)["confirmations"] > 0)
+ assert(rpc_online.gettransaction(res)["confirmations"] > 0)
+
+ # Cleanup
+ txid = rpc_online.sendall(recipients=[self.boring.getnewaddress()])["txid"]
+ self.generatetoaddress(self.nodes[0], 1, self.boring.getnewaddress(), sync_fun=self.no_op)
+ assert(rpc_online.gettransaction(txid)["confirmations"] > 0)
+ rpc_online.unloadwallet()
def do_test_psbt(self, comment, pattern, privmap, treefn, keys_pay, keys_change):
self.log.info("Testing %s through PSBT" % comment)
+
+ # Create wallets
+ wallet_uuid = uuid.uuid4().hex
+ self.nodes[0].createwallet(wallet_name=f"psbt_online_{wallet_uuid}", descriptors=True, disable_private_keys=True, blank=True)
+ self.nodes[1].createwallet(wallet_name=f"psbt_offline_{wallet_uuid}", descriptors=True, blank=True)
+ self.nodes[1].createwallet(f"key_only_wallet_{wallet_uuid}", descriptors=True, blank=True)
+ psbt_online = self.nodes[0].get_wallet_rpc(f"psbt_online_{wallet_uuid}")
+ psbt_offline = self.nodes[1].get_wallet_rpc(f"psbt_offline_{wallet_uuid}")
+ key_only_wallet = self.nodes[1].get_wallet_rpc(f"key_only_wallet_{wallet_uuid}")
+
desc_pay = self.make_desc(pattern, privmap, keys_pay, False)
desc_change = self.make_desc(pattern, privmap, keys_change, False)
desc_pay_pub = self.make_desc(pattern, privmap, keys_pay, True)
desc_change_pub = self.make_desc(pattern, privmap, keys_change, True)
assert_equal(self.nodes[0].getdescriptorinfo(desc_pay)['descriptor'], desc_pay_pub)
assert_equal(self.nodes[0].getdescriptorinfo(desc_change)['descriptor'], desc_change_pub)
- result = self.psbt_online.importdescriptors([{"desc": desc_pay_pub, "active": True, "timestamp": "now"}])
+ result = psbt_online.importdescriptors([{"desc": desc_pay_pub, "active": True, "timestamp": "now"}])
assert(result[0]['success'])
- result = self.psbt_online.importdescriptors([{"desc": desc_change_pub, "active": True, "timestamp": "now", "internal": True}])
+ result = psbt_online.importdescriptors([{"desc": desc_change_pub, "active": True, "timestamp": "now", "internal": True}])
assert(result[0]['success'])
- result = self.psbt_offline.importdescriptors([{"desc": desc_pay, "active": True, "timestamp": "now"}])
+ result = psbt_offline.importdescriptors([{"desc": desc_pay, "active": True, "timestamp": "now"}])
assert(result[0]['success'])
- result = self.psbt_offline.importdescriptors([{"desc": desc_change, "active": True, "timestamp": "now", "internal": True}])
+ result = psbt_offline.importdescriptors([{"desc": desc_change, "active": True, "timestamp": "now", "internal": True}])
assert(result[0]['success'])
+ for key in keys_pay + keys_change:
+ result = key_only_wallet.importdescriptors([{"desc": descsum_create(f"wpkh({key['xprv']}/*)"), "timestamp":"now"}])
+ assert(result[0]["success"])
+ address_type = "bech32m" if "tr" in pattern else "bech32"
for i in range(4):
- addr_g = self.psbt_online.getnewaddress(address_type='bech32m')
+ addr_g = psbt_online.getnewaddress(address_type=address_type)
if treefn is not None:
addr_r = self.make_addr(treefn, keys_pay, i)
assert_equal(addr_g, addr_r)
@@ -305,28 +349,43 @@ class WalletTaprootTest(BitcoinTestFramework):
to_amnt = random.randrange(1000000, boring_balance)
self.boring.sendtoaddress(address=addr_g, amount=Decimal(to_amnt) / 100000000, subtractfeefromamount=True)
self.generatetoaddress(self.nodes[0], 1, self.boring.getnewaddress(), sync_fun=self.no_op)
- test_balance = int(self.psbt_online.getbalance() * 100000000)
+ test_balance = int(psbt_online.getbalance() * 100000000)
ret_amnt = random.randrange(100000, test_balance)
# Increase fee_rate to compensate for the wallet's inability to estimate fees for script path spends.
- psbt = self.psbt_online.walletcreatefundedpsbt([], [{self.boring.getnewaddress(): Decimal(ret_amnt) / 100000000}], None, {"subtractFeeFromOutputs":[0], "fee_rate": 200, "change_type": "bech32m"})['psbt']
- res = self.psbt_offline.walletprocesspsbt(psbt=psbt, finalize=False)
-
- decoded = self.psbt_offline.decodepsbt(res["psbt"])
- if pattern.startswith("tr("):
- for psbtin in decoded["inputs"]:
- assert "non_witness_utxo" not in psbtin
- assert "witness_utxo" in psbtin
- assert "taproot_internal_key" in psbtin
- assert "taproot_bip32_derivs" in psbtin
- assert "taproot_key_path_sig" in psbtin or "taproot_script_path_sigs" in psbtin
- if "taproot_script_path_sigs" in psbtin:
- assert "taproot_merkle_root" in psbtin
- assert "taproot_scripts" in psbtin
-
- rawtx = self.nodes[0].finalizepsbt(res['psbt'])['hex']
+ psbt = psbt_online.walletcreatefundedpsbt([], [{self.boring.getnewaddress(): Decimal(ret_amnt) / 100000000}], None, {"subtractFeeFromOutputs":[0], "fee_rate": 200, "change_type": address_type})['psbt']
+ res = psbt_offline.walletprocesspsbt(psbt=psbt, finalize=False)
+ for wallet in [psbt_offline, key_only_wallet]:
+ res = wallet.walletprocesspsbt(psbt=psbt, finalize=False)
+
+ decoded = wallet.decodepsbt(res["psbt"])
+ if pattern.startswith("tr("):
+ for psbtin in decoded["inputs"]:
+ assert "non_witness_utxo" not in psbtin
+ assert "witness_utxo" in psbtin
+ assert "taproot_internal_key" in psbtin
+ assert "taproot_bip32_derivs" in psbtin
+ assert "taproot_key_path_sig" in psbtin or "taproot_script_path_sigs" in psbtin
+ if "taproot_script_path_sigs" in psbtin:
+ assert "taproot_merkle_root" in psbtin
+ assert "taproot_scripts" in psbtin
+
+ rawtx = self.nodes[0].finalizepsbt(res['psbt'])['hex']
+ res = self.nodes[0].testmempoolaccept([rawtx])
+ assert res[0]["allowed"]
+
txid = self.nodes[0].sendrawtransaction(rawtx)
self.generatetoaddress(self.nodes[0], 1, self.boring.getnewaddress(), sync_fun=self.no_op)
- assert(self.psbt_online.gettransaction(txid)['confirmations'] > 0)
+ assert(psbt_online.gettransaction(txid)['confirmations'] > 0)
+
+ # Cleanup
+ psbt = psbt_online.sendall(recipients=[self.boring.getnewaddress()], options={"psbt": True})["psbt"]
+ res = psbt_offline.walletprocesspsbt(psbt=psbt, finalize=False)
+ rawtx = self.nodes[0].finalizepsbt(res['psbt'])['hex']
+ txid = self.nodes[0].sendrawtransaction(rawtx)
+ self.generatetoaddress(self.nodes[0], 1, self.boring.getnewaddress(), sync_fun=self.no_op)
+ assert(psbt_online.gettransaction(txid)['confirmations'] > 0)
+ psbt_online.unloadwallet()
+ psbt_offline.unloadwallet()
def do_test(self, comment, pattern, privmap, treefn):
nkeys = len(privmap)
@@ -336,21 +395,8 @@ class WalletTaprootTest(BitcoinTestFramework):
self.do_test_psbt(comment, pattern, privmap, treefn, keys[2*nkeys:3*nkeys], keys[3*nkeys:4*nkeys])
def run_test(self):
- self.log.info("Creating wallets...")
- self.nodes[0].createwallet(wallet_name="privs_tr_enabled", descriptors=True, blank=True)
- self.privs_tr_enabled = self.nodes[0].get_wallet_rpc("privs_tr_enabled")
- self.nodes[0].createwallet(wallet_name="pubs_tr_enabled", descriptors=True, blank=True, disable_private_keys=True)
- self.pubs_tr_enabled = self.nodes[0].get_wallet_rpc("pubs_tr_enabled")
self.nodes[0].createwallet(wallet_name="boring")
- self.nodes[0].createwallet(wallet_name="addr_gen", descriptors=True, disable_private_keys=True, blank=True)
- self.nodes[0].createwallet(wallet_name="rpc_online", descriptors=True, blank=True)
- self.nodes[0].createwallet(wallet_name="psbt_online", descriptors=True, disable_private_keys=True, blank=True)
- self.nodes[1].createwallet(wallet_name="psbt_offline", descriptors=True, blank=True)
self.boring = self.nodes[0].get_wallet_rpc("boring")
- self.addr_gen = self.nodes[0].get_wallet_rpc("addr_gen")
- self.rpc_online = self.nodes[0].get_wallet_rpc("rpc_online")
- self.psbt_online = self.nodes[0].get_wallet_rpc("psbt_online")
- self.psbt_offline = self.nodes[1].get_wallet_rpc("psbt_offline")
self.log.info("Mining blocks...")
gen_addr = self.boring.getnewaddress()
@@ -460,18 +506,5 @@ class WalletTaprootTest(BitcoinTestFramework):
lambda k1: key(k1)
)
- self.log.info("Sending everything back...")
-
- txid = self.rpc_online.sendall(recipients=[self.boring.getnewaddress()])["txid"]
- self.generatetoaddress(self.nodes[0], 1, self.boring.getnewaddress(), sync_fun=self.no_op)
- assert(self.rpc_online.gettransaction(txid)["confirmations"] > 0)
-
- psbt = self.psbt_online.sendall(recipients=[self.boring.getnewaddress()], options={"psbt": True})["psbt"]
- res = self.psbt_offline.walletprocesspsbt(psbt=psbt, finalize=False)
- rawtx = self.nodes[0].finalizepsbt(res['psbt'])['hex']
- txid = self.nodes[0].sendrawtransaction(rawtx)
- self.generatetoaddress(self.nodes[0], 1, self.boring.getnewaddress(), sync_fun=self.no_op)
- assert(self.psbt_online.gettransaction(txid)['confirmations'] > 0)
-
if __name__ == '__main__':
WalletTaprootTest().main()
diff --git a/test/lint/lint-git-commit-check.py b/test/lint/lint-git-commit-check.py
index a1d03370e8..049104398a 100755
--- a/test/lint/lint-git-commit-check.py
+++ b/test/lint/lint-git-commit-check.py
@@ -46,6 +46,8 @@ def main():
commit_range = merge_base + "..HEAD"
else:
commit_range = os.getenv("COMMIT_RANGE")
+ if commit_range == "SKIP_EMPTY_NOT_A_PR":
+ sys.exit(0)
commit_hashes = check_output(["git", "log", commit_range, "--format=%H"], universal_newlines=True, encoding="utf8").splitlines()
diff --git a/test/lint/lint-whitespace.py b/test/lint/lint-whitespace.py
index 3fb5b80013..72b7ebc394 100755
--- a/test/lint/lint-whitespace.py
+++ b/test/lint/lint-whitespace.py
@@ -97,6 +97,8 @@ def main():
commit_range = merge_base + "..HEAD"
else:
commit_range = os.getenv("COMMIT_RANGE")
+ if commit_range == "SKIP_EMPTY_NOT_A_PR":
+ sys.exit(0)
whitespace_selection = []
tab_selection = []