diff --git a/.cirrus.yml b/.cirrus.yml index 6628d0bbbb..3c59e41a13 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -22,7 +22,7 @@ env: # Global defaults # - The ./ci/ depedencies (with cirrus-cli) should be installed: # # ``` -# apt update && apt install screen python3 bash podman-docker curl -y && curl -L -o cirrus "https://github.com/cirruslabs/cirrus-cli/releases/latest/download/cirrus-linux-$(dpkg --print-architecture)" && mv cirrus /usr/local/bin/cirrus && chmod +x /usr/local/bin/cirrus +# apt update && apt install git screen python3 bash podman-docker curl -y && curl -L -o cirrus "https://github.com/cirruslabs/cirrus-cli/releases/latest/download/cirrus-linux-$(dpkg --print-architecture)" && mv cirrus /usr/local/bin/cirrus && chmod +x /usr/local/bin/cirrus # ``` # # - There are no strict requirements on the hardware, because having less CPUs @@ -55,7 +55,7 @@ base_template: &BASE_TEMPLATE << : *FILTER_TEMPLATE merge_base_script: # Unconditionally install git (used in fingerprint_script). - - bash -c "$PACKAGE_MANAGER_INSTALL git" + - git --version || bash -c "$PACKAGE_MANAGER_INSTALL git" - if [ "$CIRRUS_PR" = "" ]; then exit 0; fi - git fetch --depth=1 $CIRRUS_REPO_CLONE_URL "pull/${CIRRUS_PR}/merge" - git checkout FETCH_HEAD # Use merged changes to detect silent merge conflicts diff --git a/ci/README.md b/ci/README.md index 7cf3b1f563..b4edd4b191 100644 --- a/ci/README.md +++ b/ci/README.md @@ -14,10 +14,10 @@ testing compared to other parts of the codebase. If you want to keep the work tr system in a virtual machine with a Linux operating system of your choice. To allow for a wide range of tested environments, but also ensure reproducibility to some extent, the test stage -requires `bash`, `docker`, and `python3` to be installed. To install all requirements on Ubuntu, run +requires `bash`, `docker`, and `python3` to be installed. To run on different architectures than the host `qemu` is also required. To install all requirements on Ubuntu, run ``` -sudo apt install bash docker.io python3 +sudo apt install bash docker.io python3 qemu-user-static ``` It is recommended to run the ci system in a clean env. To run the test stage diff --git a/ci/test/02_run_container.sh b/ci/test/02_run_container.sh index 8a7a978994..e6c4a61341 100755 --- a/ci/test/02_run_container.sh +++ b/ci/test/02_run_container.sh @@ -12,9 +12,9 @@ set -ex if [ -z "$DANGER_RUN_CI_ON_HOST" ]; then # Export all env vars to avoid missing some. # Though, exclude those with newlines to avoid parsing problems. - python3 -c 'import os; [print(f"{key}={value}") for key, value in os.environ.items() if "\n" not in value and "HOME" != key and "PATH" != key and "USER" != key]' | tee /tmp/env + python3 -c 'import os; [print(f"{key}={value}") for key, value in os.environ.items() if "\n" not in value and "HOME" != key and "PATH" != key and "USER" != key]' | tee "/tmp/env-$USER-$CONTAINER_NAME" # System-dependent env vars must be kept as is. So read them from the container. - docker run --rm "${CI_IMAGE_NAME_TAG}" bash -c "env | grep --extended-regexp '^(HOME|PATH|USER)='" | tee --append /tmp/env + docker run --rm "${CI_IMAGE_NAME_TAG}" bash -c "env | grep --extended-regexp '^(HOME|PATH|USER)='" | tee --append "/tmp/env-$USER-$CONTAINER_NAME" echo "Creating $CI_IMAGE_NAME_TAG container to run in" DOCKER_BUILDKIT=1 docker build \ --file "${BASE_READ_ONLY_DIR}/ci/test_imagefile" \ @@ -44,6 +44,8 @@ if [ -z "$DANGER_RUN_CI_ON_HOST" ]; then # When detecting podman-docker, `--external` should be added. docker image prune --force --filter "label=$CI_IMAGE_LABEL" + # Append $USER to /tmp/env to support multi-user systems and $CONTAINER_NAME + # to allow support starting multiple runs simultaneously by the same user. # shellcheck disable=SC2086 CI_CONTAINER_ID=$(docker run --cap-add LINUX_IMMUTABLE $CI_CONTAINER_CAP --rm --interactive --detach --tty \ --mount "type=bind,src=$BASE_READ_ONLY_DIR,dst=$BASE_READ_ONLY_DIR,readonly" \ @@ -52,7 +54,7 @@ if [ -z "$DANGER_RUN_CI_ON_HOST" ]; then --mount "type=volume,src=${CONTAINER_NAME}_depends_sources,dst=$DEPENDS_DIR/sources" \ --mount "type=volume,src=${CONTAINER_NAME}_depends_SDKs_android,dst=$DEPENDS_DIR/SDKs/android" \ --mount "type=volume,src=${CONTAINER_NAME}_previous_releases,dst=$PREVIOUS_RELEASES_DIR" \ - --env-file /tmp/env \ + --env-file /tmp/env-$USER-$CONTAINER_NAME \ --name "$CONTAINER_NAME" \ "$CONTAINER_NAME") export CI_CONTAINER_ID diff --git a/doc/bips.md b/doc/bips.md index 952d289daa..8309ee7e92 100644 --- a/doc/bips.md +++ b/doc/bips.md @@ -49,7 +49,7 @@ BIPs that are implemented by Bitcoin Core: * [`BIP 173`](https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki): Bech32 addresses for native Segregated Witness outputs are supported as of **v0.16.0** ([PR 11167](https://github.com/bitcoin/bitcoin/pull/11167)). Bech32 addresses are generated by default as of **v0.20.0** ([PR 16884](https://github.com/bitcoin/bitcoin/pull/16884)). * [`BIP 174`](https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki): RPCs to operate on Partially Signed Bitcoin Transactions (PSBT) are present as of **v0.17.0** ([PR 13557](https://github.com/bitcoin/bitcoin/pull/13557)). * [`BIP 176`](https://github.com/bitcoin/bips/blob/master/bip-0176.mediawiki): Bits Denomination [QT only] is supported as of **v0.16.0** ([PR 12035](https://github.com/bitcoin/bitcoin/pull/12035)). -* [`BIP 324`](https://github.com/bitcoin/bips/blob/master/bip-0324.mediawiki): The v2 transport protocol specified by BIP324 and the associated `NODE_P2P_V2` service bit are supported as of **v26.0**, but off by default ([PR 28331](https://github.com/bitcoin/bitcoin/pull/28331)). +* [`BIP 324`](https://github.com/bitcoin/bips/blob/master/bip-0324.mediawiki): The v2 transport protocol specified by BIP324 and the associated `NODE_P2P_V2` service bit are supported as of **v26.0**, but off by default ([PR 28331](https://github.com/bitcoin/bitcoin/pull/28331)). On by default as of **v27.0** ([PR 29347](https://github.com/bitcoin/bitcoin/pull/29347)). * [`BIP 325`](https://github.com/bitcoin/bips/blob/master/bip-0325.mediawiki): Signet test network is supported as of **v0.21.0** ([PR 18267](https://github.com/bitcoin/bitcoin/pull/18267)). * [`BIP 339`](https://github.com/bitcoin/bips/blob/master/bip-0339.mediawiki): Relay of transactions by wtxid is supported as of **v0.21.0** ([PR 18044](https://github.com/bitcoin/bitcoin/pull/18044)). * [`BIP 340`](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki) diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include index 1c16463656..7c8070296a 100644 --- a/src/Makefile.bench.include +++ b/src/Makefile.bench.include @@ -88,6 +88,8 @@ bench_bench_namecoin_SOURCES += bench/wallet_balance.cpp bench_bench_namecoin_SOURCES += bench/wallet_create.cpp bench_bench_namecoin_SOURCES += bench/wallet_loading.cpp bench_bench_namecoin_SOURCES += bench/wallet_create_tx.cpp +bench_bench_namecoin_SOURCES += bench/wallet_ismine.cpp + bench_bench_namecoin_LDADD += $(BDB_LIBS) $(SQLITE_LIBS) endif diff --git a/src/addrdb.cpp b/src/addrdb.cpp index 8cf932bcb6..fd2a363b8a 100644 --- a/src/addrdb.cpp +++ b/src/addrdb.cpp @@ -3,6 +3,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include +#endif + #include #include diff --git a/src/addrman.cpp b/src/addrman.cpp index 5b2375bc9a..ef8ed92bb5 100644 --- a/src/addrman.cpp +++ b/src/addrman.cpp @@ -3,6 +3,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include +#endif + #include #include diff --git a/src/bench/verify_script.cpp b/src/bench/verify_script.cpp index 6d33fad4d4..a41a5e1231 100644 --- a/src/bench/verify_script.cpp +++ b/src/bench/verify_script.cpp @@ -2,6 +2,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include +#endif + #include #include #if defined(HAVE_CONSENSUS_LIB) diff --git a/src/bench/wallet_create.cpp b/src/bench/wallet_create.cpp index 993c4c4b3f..32f55f51e1 100644 --- a/src/bench/wallet_create.cpp +++ b/src/bench/wallet_create.cpp @@ -2,6 +2,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or https://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include +#endif + #include #include #include diff --git a/src/bench/wallet_ismine.cpp b/src/bench/wallet_ismine.cpp new file mode 100644 index 0000000000..261c95c7c8 --- /dev/null +++ b/src/bench/wallet_ismine.cpp @@ -0,0 +1,74 @@ +// 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. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace wallet { +static void WalletIsMine(benchmark::Bench& bench, bool legacy_wallet, int num_combo = 0) +{ + const auto test_setup = MakeNoLogFileContext(); + + WalletContext context; + context.args = &test_setup->m_args; + context.chain = test_setup->m_node.chain.get(); + + // Setup the wallet + // Loading the wallet will also create it + uint64_t create_flags = 0; + if (!legacy_wallet) { + create_flags = WALLET_FLAG_DESCRIPTORS; + } + auto database = CreateMockableWalletDatabase(); + auto wallet = TestLoadWallet(std::move(database), context, create_flags); + + // For a descriptor wallet, fill with num_combo combo descriptors with random keys + // This benchmarks a non-HD wallet migrated to descriptors + if (!legacy_wallet && num_combo > 0) { + LOCK(wallet->cs_wallet); + for (int i = 0; i < num_combo; ++i) { + CKey key; + key.MakeNewKey(/*fCompressed=*/true); + FlatSigningProvider keys; + std::string error; + std::unique_ptr desc = Parse("combo(" + EncodeSecret(key) + ")", keys, error, /*require_checksum=*/false); + WalletDescriptor w_desc(std::move(desc), /*creation_time=*/0, /*range_start=*/0, /*range_end=*/0, /*next_index=*/0); + auto spkm = wallet->AddWalletDescriptor(w_desc, keys, /*label=*/"", /*internal=*/false); + assert(spkm); + } + } + + const CScript script = GetScriptForDestination(DecodeDestination(ADDRESS_BCRT1_UNSPENDABLE)); + + bench.run([&] { + LOCK(wallet->cs_wallet); + isminetype mine = wallet->IsMine(script); + assert(mine == ISMINE_NO); + }); + + TestUnloadWallet(std::move(wallet)); +} + +#ifdef USE_BDB +static void WalletIsMineLegacy(benchmark::Bench& bench) { WalletIsMine(bench, /*legacy_wallet=*/true); } +BENCHMARK(WalletIsMineLegacy, benchmark::PriorityLevel::LOW); +#endif + +#ifdef USE_SQLITE +static void WalletIsMineDescriptors(benchmark::Bench& bench) { WalletIsMine(bench, /*legacy_wallet=*/false); } +static void WalletIsMineMigratedDescriptors(benchmark::Bench& bench) { WalletIsMine(bench, /*legacy_wallet=*/false, /*num_combo=*/2000); } +BENCHMARK(WalletIsMineDescriptors, benchmark::PriorityLevel::LOW); +BENCHMARK(WalletIsMineMigratedDescriptors, benchmark::PriorityLevel::LOW); +#endif +} // namespace wallet diff --git a/src/bench/wallet_loading.cpp b/src/bench/wallet_loading.cpp index b17c7fe05a..6305126c7d 100644 --- a/src/bench/wallet_loading.cpp +++ b/src/bench/wallet_loading.cpp @@ -2,6 +2,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include +#endif + #include #include #include diff --git a/src/clientversion.cpp b/src/clientversion.cpp index 187c27f7d1..cf596ab936 100644 --- a/src/clientversion.cpp +++ b/src/clientversion.cpp @@ -2,6 +2,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include +#endif + #include #include diff --git a/src/common/system.cpp b/src/common/system.cpp index ba42c6df50..1fa53a5f34 100644 --- a/src/common/system.cpp +++ b/src/common/system.cpp @@ -3,6 +3,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include +#endif + #include #include diff --git a/src/compat/compat.h b/src/compat/compat.h index 435a403552..9ff9a335f8 100644 --- a/src/compat/compat.h +++ b/src/compat/compat.h @@ -6,10 +6,6 @@ #ifndef BITCOIN_COMPAT_COMPAT_H #define BITCOIN_COMPAT_COMPAT_H -#if defined(HAVE_CONFIG_H) -#include -#endif - // Windows defines FD_SETSIZE to 64 (see _fd_types.h in mingw-w64), // which is too small for our usage, but allows us to redefine it safely. // We redefine it to be 1024, to match glibc, see typesizes.h. diff --git a/src/crypto/chacha20poly1305.cpp b/src/crypto/chacha20poly1305.cpp index 59671d304c..3e8051c2dc 100644 --- a/src/crypto/chacha20poly1305.cpp +++ b/src/crypto/chacha20poly1305.cpp @@ -2,6 +2,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include +#endif + #include #include diff --git a/src/crypto/muhash.h b/src/crypto/muhash.h index 53c5a91a03..cb53e1743e 100644 --- a/src/crypto/muhash.h +++ b/src/crypto/muhash.h @@ -5,10 +5,6 @@ #ifndef BITCOIN_CRYPTO_MUHASH_H #define BITCOIN_CRYPTO_MUHASH_H -#if defined(HAVE_CONFIG_H) -#include -#endif - #include #include diff --git a/src/crypto/sha256.cpp b/src/crypto/sha256.cpp index 11aabeb1da..36ef6d9a1a 100644 --- a/src/crypto/sha256.cpp +++ b/src/crypto/sha256.cpp @@ -2,6 +2,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include +#endif + #include #include diff --git a/src/netaddress.h b/src/netaddress.h index 0bbde43dd7..c697b7e0a3 100644 --- a/src/netaddress.h +++ b/src/netaddress.h @@ -5,10 +5,6 @@ #ifndef BITCOIN_NETADDRESS_H #define BITCOIN_NETADDRESS_H -#if defined(HAVE_CONFIG_H) -#include -#endif - #include #include #include diff --git a/src/netbase.h b/src/netbase.h index 8523f59b4d..1bd95ba0d9 100644 --- a/src/netbase.h +++ b/src/netbase.h @@ -5,10 +5,6 @@ #ifndef BITCOIN_NETBASE_H #define BITCOIN_NETBASE_H -#if defined(HAVE_CONFIG_H) -#include -#endif - #include #include #include diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp index 27283ea912..de7fcfdc7d 100644 --- a/src/qt/addressbookpage.cpp +++ b/src/qt/addressbookpage.cpp @@ -2,10 +2,6 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#if defined(HAVE_CONFIG_H) -#include -#endif - #include #include diff --git a/src/qt/askpassphrasedialog.cpp b/src/qt/askpassphrasedialog.cpp index 1d24360dd1..9e71f4ce6e 100644 --- a/src/qt/askpassphrasedialog.cpp +++ b/src/qt/askpassphrasedialog.cpp @@ -2,10 +2,6 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#if defined(HAVE_CONFIG_H) -#include -#endif - #include #include diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index b15583c814..63b3d92d52 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -2,6 +2,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include +#endif + #include #include diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index ff7405d139..c31e06e88e 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -2,6 +2,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include +#endif + #include #include diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 00b8e2a8d3..a2b9c53d99 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -2,10 +2,6 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#if defined(HAVE_CONFIG_H) -#include -#endif - #include #include diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 600890efae..b8032e065f 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -2,6 +2,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include +#endif + #include #include diff --git a/src/qt/modaloverlay.cpp b/src/qt/modaloverlay.cpp index b09e230bce..667db06574 100644 --- a/src/qt/modaloverlay.cpp +++ b/src/qt/modaloverlay.cpp @@ -2,6 +2,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include +#endif + #include #include diff --git a/src/qt/notificator.cpp b/src/qt/notificator.cpp index 88bc33098a..2021e5f9dc 100644 --- a/src/qt/notificator.cpp +++ b/src/qt/notificator.cpp @@ -2,6 +2,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include +#endif + #include #include diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index 592e591edb..d4c325b7b1 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -2,10 +2,6 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#if defined(HAVE_CONFIG_H) -#include -#endif - #include #include diff --git a/src/qt/paymentserver.h b/src/qt/paymentserver.h index f73aa1e61e..b9ea97d5ec 100644 --- a/src/qt/paymentserver.h +++ b/src/qt/paymentserver.h @@ -32,10 +32,6 @@ // sends them to the server. // -#if defined(HAVE_CONFIG_H) -#include -#endif - #include #include diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 417842e2d0..a6913a4229 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -406,6 +406,7 @@ void SendCoinsDialog::presentPSBT(PartiallySignedTransaction& psbtx) msgBox.setInformativeText(tr("The PSBT has been copied to the clipboard. You can also save it.")); msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard); msgBox.setDefaultButton(QMessageBox::Discard); + msgBox.setObjectName("psbt_copied_message"); switch (msgBox.exec()) { case QMessageBox::Save: { QString selectedFilter; diff --git a/src/qt/sendcoinsentry.cpp b/src/qt/sendcoinsentry.cpp index 0536635c84..d8102c1dca 100644 --- a/src/qt/sendcoinsentry.cpp +++ b/src/qt/sendcoinsentry.cpp @@ -2,10 +2,6 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#if defined(HAVE_CONFIG_H) -#include -#endif - #include #include diff --git a/src/qt/sendcoinsrecipient.h b/src/qt/sendcoinsrecipient.h index 787a52b8b3..aa2ea0498e 100644 --- a/src/qt/sendcoinsrecipient.h +++ b/src/qt/sendcoinsrecipient.h @@ -5,10 +5,6 @@ #ifndef BITCOIN_QT_SENDCOINSRECIPIENT_H #define BITCOIN_QT_SENDCOINSRECIPIENT_H -#if defined(HAVE_CONFIG_H) -#include -#endif - #include #include diff --git a/src/qt/test/apptests.cpp b/src/qt/test/apptests.cpp index 9007b183aa..10abcb00eb 100644 --- a/src/qt/test/apptests.cpp +++ b/src/qt/test/apptests.cpp @@ -14,10 +14,6 @@ #include #include -#if defined(HAVE_CONFIG_H) -#include -#endif - #include #include #include diff --git a/src/qt/test/optiontests.cpp b/src/qt/test/optiontests.cpp index 7100603616..b76e9ef499 100644 --- a/src/qt/test/optiontests.cpp +++ b/src/qt/test/optiontests.cpp @@ -2,6 +2,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include +#endif + #include #include #include diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp index 134ab613af..028dca15ce 100644 --- a/src/qt/test/wallettests.cpp +++ b/src/qt/test/wallettests.cpp @@ -418,7 +418,7 @@ void TestGUIWatchOnly(interfaces::Node& node, TestChain100Setup& test) timer.setInterval(500); QObject::connect(&timer, &QTimer::timeout, [&](){ for (QWidget* widget : QApplication::topLevelWidgets()) { - if (widget->inherits("QMessageBox")) { + if (widget->inherits("QMessageBox") && widget->objectName().compare("psbt_copied_message") == 0) { QMessageBox* dialog = qobject_cast(widget); QAbstractButton* button = dialog->button(QMessageBox::Discard); button->setEnabled(true); diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index a916e4ead6..b848b8fe94 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -2,10 +2,6 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#ifdef HAVE_CONFIG_H -#include -#endif - #include #include diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index c7e88e382f..26d5e25832 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -2,10 +2,6 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#if defined(HAVE_CONFIG_H) -#include -#endif - #include #include diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index f6deca4a9b..17578d46f1 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -5,10 +5,6 @@ #ifndef BITCOIN_QT_WALLETMODEL_H #define BITCOIN_QT_WALLETMODEL_H -#if defined(HAVE_CONFIG_H) -#include -#endif - #include #include diff --git a/src/qt/walletmodeltransaction.cpp b/src/qt/walletmodeltransaction.cpp index 61ccd9dd82..8222672bf3 100644 --- a/src/qt/walletmodeltransaction.cpp +++ b/src/qt/walletmodeltransaction.cpp @@ -2,10 +2,6 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#ifdef HAVE_CONFIG_H -#include -#endif - #include #include diff --git a/src/random.cpp b/src/random.cpp index ce4266a567..4fc9099704 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -3,6 +3,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include +#endif + #include #include diff --git a/src/rest.cpp b/src/rest.cpp index 8af66a48e7..d0c0ef22dc 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -3,6 +3,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include +#endif + #include #include diff --git a/src/rpc/external_signer.cpp b/src/rpc/external_signer.cpp index 310eec5f15..8d06ae4258 100644 --- a/src/rpc/external_signer.cpp +++ b/src/rpc/external_signer.cpp @@ -2,6 +2,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include +#endif + #include #include #include diff --git a/src/rpc/mempool.cpp b/src/rpc/mempool.cpp index c1753a1f6e..25bfec2d45 100644 --- a/src/rpc/mempool.cpp +++ b/src/rpc/mempool.cpp @@ -45,7 +45,7 @@ static RPCHelpMan sendrawtransaction() {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex string of the raw transaction"}, {"maxfeerate", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK())}, "Reject transactions whose fee rate is higher than the specified value, expressed in " + CURRENCY_UNIT + - "/kvB.\nSet to 0 to accept any fee rate."}, + "/kvB.\nFee rates larger than 1BTC/kvB are rejected.\nSet to 0 to accept any fee rate."}, {"maxburnamount", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(0)}, "Reject transactions with provably unspendable outputs (e.g. 'datacarrier' outputs that use the OP_RETURN opcode) greater than the specified value, expressed in " + CURRENCY_UNIT + ".\n" "If burning funds through unspendable outputs is desired, increase this value.\n" @@ -81,9 +81,7 @@ static RPCHelpMan sendrawtransaction() CTransactionRef tx(MakeTransactionRef(std::move(mtx))); - const CFeeRate max_raw_tx_fee_rate = request.params[1].isNull() ? - DEFAULT_MAX_RAW_TX_FEE_RATE : - CFeeRate(AmountFromValue(request.params[1])); + const CFeeRate max_raw_tx_fee_rate{ParseFeeRate(self.Arg(1))}; int64_t virtual_size = GetVirtualTransactionSize(*tx); CAmount max_raw_tx_fee = max_raw_tx_fee_rate.GetFee(virtual_size); @@ -117,7 +115,8 @@ static RPCHelpMan testmempoolaccept() }, }, {"maxfeerate", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK())}, - "Reject transactions whose fee rate is higher than the specified value, expressed in " + CURRENCY_UNIT + "/kvB\n"}, + "Reject transactions whose fee rate is higher than the specified value, expressed in " + CURRENCY_UNIT + + "/kvB.\nFee rates larger than 1BTC/kvB are rejected.\nSet to 0 to accept any fee rate."}, }, RPCResult{ RPCResult::Type::ARR, "", "The result of the mempool acceptance test for each raw transaction in the input array.\n" @@ -162,9 +161,7 @@ static RPCHelpMan testmempoolaccept() "Array must contain between 1 and " + ToString(MAX_PACKAGE_COUNT) + " transactions."); } - const CFeeRate max_raw_tx_fee_rate = request.params[1].isNull() ? - DEFAULT_MAX_RAW_TX_FEE_RATE : - CFeeRate(AmountFromValue(request.params[1])); + const CFeeRate max_raw_tx_fee_rate{ParseFeeRate(self.Arg(1))}; std::vector txns; txns.reserve(raw_transactions.size()); diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index db15d9097f..5c7bad5d6f 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -3,6 +3,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include +#endif + #include #include #include diff --git a/src/rpc/node.cpp b/src/rpc/node.cpp index 507fb1198d..5a8e7fc4f8 100644 --- a/src/rpc/node.cpp +++ b/src/rpc/node.cpp @@ -3,6 +3,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include +#endif + #include #include #include diff --git a/src/rpc/register.h b/src/rpc/register.h index 9e9c89b46a..802a548e8d 100644 --- a/src/rpc/register.h +++ b/src/rpc/register.h @@ -5,6 +5,10 @@ #ifndef BITCOIN_RPC_REGISTER_H #define BITCOIN_RPC_REGISTER_H +#if defined(HAVE_CONFIG_H) +#include +#endif + /** These are in one header file to avoid creating tons of single-function * headers for everything under src/rpc/ */ class CRPCTable; diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index e1ac510cba..e7d1e3db4e 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -3,6 +3,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include +#endif + #include #include diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp index 109390a5cc..18d75d0adf 100644 --- a/src/rpc/util.cpp +++ b/src/rpc/util.cpp @@ -2,6 +2,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include +#endif + #include #include #include @@ -75,6 +79,13 @@ CAmount AmountFromValue(const UniValue& value, int decimals) return amount; } +CFeeRate ParseFeeRate(const UniValue& json) +{ + CAmount val{AmountFromValue(json)}; + if (val >= COIN) throw JSONRPCError(RPC_INVALID_PARAMETER, "Fee rates larger than or equal to 1BTC/kvB are not accepted"); + return CFeeRate{val}; +} + uint256 ParseHashV(const UniValue& v, std::string_view name) { const std::string& strHex(v.get_str()); @@ -678,11 +689,13 @@ static void CheckRequiredOrDefault(const RPCArg& param) void force_semicolon(ret_type) // Optional arg (without default). Can also be called on required args, if needed. +TMPL_INST(nullptr, const UniValue*, maybe_arg;); TMPL_INST(nullptr, std::optional, maybe_arg ? std::optional{maybe_arg->get_real()} : std::nullopt;); TMPL_INST(nullptr, std::optional, maybe_arg ? std::optional{maybe_arg->get_bool()} : std::nullopt;); TMPL_INST(nullptr, const std::string*, maybe_arg ? &maybe_arg->get_str() : nullptr;); // Required arg or optional arg with default value. +TMPL_INST(CheckRequiredOrDefault, const UniValue&, *CHECK_NONFATAL(maybe_arg);); TMPL_INST(CheckRequiredOrDefault, bool, CHECK_NONFATAL(maybe_arg)->get_bool();); TMPL_INST(CheckRequiredOrDefault, int, CHECK_NONFATAL(maybe_arg)->getInt();); TMPL_INST(CheckRequiredOrDefault, uint64_t, CHECK_NONFATAL(maybe_arg)->getInt();); diff --git a/src/rpc/util.h b/src/rpc/util.h index e2d5ed333c..ad3ed97b2e 100644 --- a/src/rpc/util.h +++ b/src/rpc/util.h @@ -103,6 +103,11 @@ std::vector ParseHexO(const UniValue& o, std::string_view strKey) * @returns a CAmount if the various checks pass. */ CAmount AmountFromValue(const UniValue& value, int decimals = 8); +/** + * Parse a json number or string, denoting BTC/kvB, into a CFeeRate (sat/kvB). + * Reject negative values or rates larger than 1BTC/kvB. + */ +CFeeRate ParseFeeRate(const UniValue& json); using RPCArgList = std::vector>; std::string HelpExampleCli(const std::string& methodname, const std::string& args); diff --git a/src/serialize.h b/src/serialize.h index a0b012b25c..7b336ce1af 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -6,6 +6,10 @@ #ifndef BITCOIN_SERIALIZE_H #define BITCOIN_SERIALIZE_H +#if defined(HAVE_CONFIG_H) +#include +#endif + #include #include // IWYU pragma: keep #include diff --git a/src/support/lockedpool.cpp b/src/support/lockedpool.cpp index f92d1d8fb7..fe3ba38cde 100644 --- a/src/support/lockedpool.cpp +++ b/src/support/lockedpool.cpp @@ -5,10 +5,6 @@ #include #include -#if defined(HAVE_CONFIG_H) -#include -#endif - #ifdef WIN32 #include #else diff --git a/src/sync.cpp b/src/sync.cpp index 58752a9f18..a8bdfc1dea 100644 --- a/src/sync.cpp +++ b/src/sync.cpp @@ -2,10 +2,6 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#if defined(HAVE_CONFIG_H) -#include -#endif - #include #include diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index 5362c998d5..2316806a60 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -2,6 +2,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include +#endif + #include #include diff --git a/src/test/system_tests.cpp b/src/test/system_tests.cpp index 6a96b60db0..76a8f80ba1 100644 --- a/src/test/system_tests.cpp +++ b/src/test/system_tests.cpp @@ -2,6 +2,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. // + +#if defined(HAVE_CONFIG_H) +#include +#endif #include #include #include diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index 98449a5ebc..01adaaff9c 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -2,6 +2,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include +#endif + #include #include diff --git a/src/validation.cpp b/src/validation.cpp index e05851a4cf..a442fef8ee 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -3,6 +3,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include +#endif + #include #include diff --git a/src/validation.h b/src/validation.h index 635a16ebc4..38ab3d5dab 100644 --- a/src/validation.h +++ b/src/validation.h @@ -6,10 +6,6 @@ #ifndef BITCOIN_VALIDATION_H #define BITCOIN_VALIDATION_H -#if defined(HAVE_CONFIG_H) -#include -#endif - #include #include #include diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp index 088343458c..f151fad740 100644 --- a/src/wallet/init.cpp +++ b/src/wallet/init.cpp @@ -3,6 +3,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include +#endif + #include #include #include diff --git a/src/wallet/rpc/addresses.cpp b/src/wallet/rpc/addresses.cpp index 995fe567d3..b016def3d0 100644 --- a/src/wallet/rpc/addresses.cpp +++ b/src/wallet/rpc/addresses.cpp @@ -2,6 +2,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include +#endif + #include #include #include diff --git a/src/wallet/rpc/backup.cpp b/src/wallet/rpc/backup.cpp index 32ac5cfe9e..19aa6b8ebf 100644 --- a/src/wallet/rpc/backup.cpp +++ b/src/wallet/rpc/backup.cpp @@ -2,6 +2,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include +#endif + #include #include #include diff --git a/src/wallet/rpc/wallet.cpp b/src/wallet/rpc/wallet.cpp index df2be79bb0..781ab19223 100644 --- a/src/wallet/rpc/wallet.cpp +++ b/src/wallet/rpc/wallet.cpp @@ -3,6 +3,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include +#endif + #include #include #include diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp index 38f9b83902..0f4a0e3783 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -1294,6 +1294,9 @@ bool LegacyScriptPubKeyMan::TopUp(unsigned int kpSize) } if (!batch.TxnCommit()) throw std::runtime_error(strprintf("Error during keypool top up. Cannot commit changes for wallet %s", m_storage.GetDisplayName())); NotifyCanGetAddressesChanged(); + // Note: Unlike with DescriptorSPKM, LegacySPKM does not need to call + // m_storage.TopUpCallback() as we do not know what new scripts the LegacySPKM is + // watching for. CWallet's scriptPubKey cache is not used for LegacySPKMs. return true; } @@ -2164,6 +2167,7 @@ bool DescriptorScriptPubKeyMan::TopUp(unsigned int size) bool DescriptorScriptPubKeyMan::TopUpWithDB(WalletBatch& batch, unsigned int size) { LOCK(cs_desc_man); + std::set new_spks; unsigned int target_size; if (size > 0) { target_size = size; @@ -2194,6 +2198,7 @@ bool DescriptorScriptPubKeyMan::TopUpWithDB(WalletBatch& batch, unsigned int siz if (!m_wallet_descriptor.descriptor->Expand(i, provider, scripts_temp, out_keys, &temp_cache)) return false; } // Add all of the scriptPubKeys to the scriptPubKey set + new_spks.insert(scripts_temp.begin(), scripts_temp.end()); for (const CScript& script : scripts_temp) { m_map_script_pub_keys[script] = i; } @@ -2219,6 +2224,7 @@ bool DescriptorScriptPubKeyMan::TopUpWithDB(WalletBatch& batch, unsigned int siz // By this point, the cache size should be the size of the entire range assert(m_wallet_descriptor.range_end - 1 == m_max_cached_index); + m_storage.TopUpCallback(new_spks, this); NotifyCanGetAddressesChanged(); return true; } @@ -2643,6 +2649,7 @@ uint256 DescriptorScriptPubKeyMan::GetID() const void DescriptorScriptPubKeyMan::SetCache(const DescriptorCache& cache) { LOCK(cs_desc_man); + std::set new_spks; m_wallet_descriptor.cache = cache; for (int32_t i = m_wallet_descriptor.range_start; i < m_wallet_descriptor.range_end; ++i) { FlatSigningProvider out_keys; @@ -2651,6 +2658,7 @@ void DescriptorScriptPubKeyMan::SetCache(const DescriptorCache& cache) throw std::runtime_error("Error: Unable to expand wallet descriptor from cache"); } // Add all of the scriptPubKeys to the scriptPubKey set + new_spks.insert(scripts_temp.begin(), scripts_temp.end()); for (const CScript& script : scripts_temp) { if (m_map_script_pub_keys.count(script) != 0) { throw std::runtime_error(strprintf("Error: Already loaded script at index %d as being at index %d", i, m_map_script_pub_keys[script])); @@ -2668,6 +2676,8 @@ void DescriptorScriptPubKeyMan::SetCache(const DescriptorCache& cache) } m_max_cached_index++; } + // Make sure the wallet knows about our new spks + m_storage.TopUpCallback(new_spks, this); } bool DescriptorScriptPubKeyMan::AddKey(const CKeyID& key_id, const CKey& key) diff --git a/src/wallet/scriptpubkeyman.h b/src/wallet/scriptpubkeyman.h index d686c27a8e..7ceb95fbe4 100644 --- a/src/wallet/scriptpubkeyman.h +++ b/src/wallet/scriptpubkeyman.h @@ -31,6 +31,7 @@ struct bilingual_str; namespace wallet { struct MigrationData; +class ScriptPubKeyMan; // Wallet storage things that ScriptPubKeyMans need in order to be able to store things to the wallet database. // It provides access to things that are part of the entire wallet and not specific to a ScriptPubKeyMan such as @@ -51,6 +52,8 @@ class WalletStorage virtual bool WithEncryptionKey(std::function cb) const = 0; virtual bool HasEncryptionKeys() const = 0; virtual bool IsLocked() const = 0; + //! Callback function for after TopUp completes containining any scripts that were added by a SPKMan + virtual void TopUpCallback(const std::set&, ScriptPubKeyMan*) = 0; }; //! Constant representing an unknown spkm creation time diff --git a/src/wallet/spend.cpp b/src/wallet/spend.cpp index 428ab7222a..52fbe95fb5 100644 --- a/src/wallet/spend.cpp +++ b/src/wallet/spend.cpp @@ -48,6 +48,14 @@ static bool UseMaxSig(const std::optional& txin, const CCoinControl* coin return coin_control && (coin_control->fAllowWatchOnly || (txin && coin_control->IsExternalSelected(txin->prevout))); } +/** Strips the name prefix off the script of a txout. This is irrelevant + for fee calculation / signed size. */ +static CScript StripNamePrefix(const CTxOut& txo) +{ + const CNameScript nameOp(txo.scriptPubKey); + return nameOp.getAddress(); +} + /** Get the size of an input (in witness units) once it's signed. * * @param desc The output script descriptor of the coin spent by this input. @@ -83,7 +91,7 @@ int CalculateMaximumSignedInputSize(const CTxOut& txout, const COutPoint outpoin { if (!provider) return -1; - if (const auto desc = InferDescriptor(txout.scriptPubKey, *provider)) { + if (const auto desc = InferDescriptor(StripNamePrefix(txout), *provider)) { if (const auto weight = MaxInputWeight(*desc, {}, coin_control, true, can_grind_r)) { return static_cast(GetVirtualTransactionSize(*weight, 0, 0)); } @@ -124,7 +132,7 @@ static std::optional GetSignedTxinWeight(const CWallet* wallet, const C } // Otherwise, use the maximum satisfaction size provided by the descriptor. - std::unique_ptr desc{GetDescriptor(wallet, coin_control, txo.scriptPubKey)}; + std::unique_ptr desc{GetDescriptor(wallet, coin_control, StripNamePrefix(txo))}; if (desc) return MaxInputWeight(*desc, {txin}, coin_control, tx_is_segwit, can_grind_r); return {}; diff --git a/src/wallet/sqlite.cpp b/src/wallet/sqlite.cpp index 2cbeedbde6..34f18bf0b1 100644 --- a/src/wallet/sqlite.cpp +++ b/src/wallet/sqlite.cpp @@ -2,6 +2,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include +#endif + #include #include diff --git a/src/wallet/test/db_tests.cpp b/src/wallet/test/db_tests.cpp index c933366354..f783424df8 100644 --- a/src/wallet/test/db_tests.cpp +++ b/src/wallet/test/db_tests.cpp @@ -2,6 +2,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include +#endif + #include #include diff --git a/src/wallet/test/fuzz/coinselection.cpp b/src/wallet/test/fuzz/coinselection.cpp index 3ffeecdf34..297432de9e 100644 --- a/src/wallet/test/fuzz/coinselection.cpp +++ b/src/wallet/test/fuzz/coinselection.cpp @@ -158,7 +158,7 @@ FUZZ_TARGET(coin_grinder_is_optimal) // Only make UTXOs with positive effective value const CAmount input_fee = coin_params.m_effective_feerate.GetFee(n_input_bytes); // Ensure that each UTXO has at least an effective value of 1 sat - const CAmount eff_value{fuzzed_data_provider.ConsumeIntegralInRange(1, MAX_MONEY - max_spendable - max_output_groups + group_pos.size())}; + const CAmount eff_value{fuzzed_data_provider.ConsumeIntegralInRange(1, MAX_MONEY + group_pos.size() - max_spendable - max_output_groups)}; const CAmount amount{eff_value + input_fee}; std::vector temp_utxo_pool; diff --git a/src/wallet/test/util.h b/src/wallet/test/util.h index 8bd238648f..9f2974ece6 100644 --- a/src/wallet/test/util.h +++ b/src/wallet/test/util.h @@ -5,6 +5,10 @@ #ifndef BITCOIN_WALLET_TEST_UTIL_H #define BITCOIN_WALLET_TEST_UTIL_H +#if defined(HAVE_CONFIG_H) +#include +#endif + #include #include diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index aa87c59d34..839a88d746 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1242,8 +1242,9 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, const SyncTxS // loop though all outputs for (const CTxOut& txout: tx.vout) { - for (const auto& spk_man : GetScriptPubKeyMans(txout.scriptPubKey)) { - for (auto &dest : spk_man->MarkUnusedAddresses(txout.scriptPubKey)) { + const CScript script = CNameScript(txout.scriptPubKey).getAddress(); + for (const auto& spk_man : GetScriptPubKeyMans(script)) { + for (auto &dest : spk_man->MarkUnusedAddresses(script)) { // If internal flag is not defined try to infer it from the ScriptPubKeyMan if (!dest.internal.has_value()) { dest.internal = IsInternalScriptPubKeyMan(spk_man); @@ -1602,14 +1603,26 @@ isminetype CWallet::IsMine(const CTxDestination& dest) const return IsMine(GetScriptForDestination(dest)); } -isminetype CWallet::IsMine(const CScript& script) const +isminetype CWallet::IsMine(const CScript& fullScript) const { AssertLockHeld(cs_wallet); - isminetype result = ISMINE_NO; - for (const auto& spk_man_pair : m_spk_managers) { - result = std::max(result, spk_man_pair.second->IsMine(script)); + const CScript script = CNameScript(fullScript).getAddress(); + + // Search the cache so that IsMine is called only on the relevant SPKMs instead of on everything in m_spk_managers + const auto& it = m_cached_spks.find(script); + if (it != m_cached_spks.end()) { + isminetype res = ISMINE_NO; + for (const auto& spkm : it->second) { + res = std::max(res, spkm->IsMine(script)); + } + Assume(res == ISMINE_SPENDABLE); + return res; } - return result; + + // Legacy wallet + if (IsLegacy()) return GetLegacyScriptPubKeyMan()->IsMine(script); + + return ISMINE_NO; } bool CWallet::IsMine(const CTransaction& tx) const @@ -3587,12 +3600,18 @@ ScriptPubKeyMan* CWallet::GetScriptPubKeyMan(const OutputType& type, bool intern std::set CWallet::GetScriptPubKeyMans(const CScript& script) const { std::set spk_mans; - SignatureData sigdata; - for (const auto& spk_man_pair : m_spk_managers) { - if (spk_man_pair.second->CanProvide(script, sigdata)) { - spk_mans.insert(spk_man_pair.second.get()); - } + + // Search the cache for relevant SPKMs instead of iterating m_spk_managers + const auto& it = m_cached_spks.find(script); + if (it != m_cached_spks.end()) { + spk_mans.insert(it->second.begin(), it->second.end()); } + SignatureData sigdata; + Assume(std::all_of(spk_mans.begin(), spk_mans.end(), [&script, &sigdata](ScriptPubKeyMan* spkm) { return spkm->CanProvide(script, sigdata); })); + + // Legacy wallet + if (IsLegacy() && GetLegacyScriptPubKeyMan()->CanProvide(script, sigdata)) spk_mans.insert(GetLegacyScriptPubKeyMan()); + return spk_mans; } @@ -3610,13 +3629,21 @@ std::unique_ptr CWallet::GetSolvingProvider(const CScript& scri return GetSolvingProvider(script, sigdata); } -std::unique_ptr CWallet::GetSolvingProvider(const CScript& script, SignatureData& sigdata) const +std::unique_ptr CWallet::GetSolvingProvider(const CScript& fullScript, SignatureData& sigdata) const { - for (const auto& spk_man_pair : m_spk_managers) { - if (spk_man_pair.second->CanProvide(script, sigdata)) { - return spk_man_pair.second->GetSolvingProvider(script); - } + const CScript script = CNameScript(fullScript).getAddress(); + + // Search the cache for relevant SPKMs instead of iterating m_spk_managers + const auto& it = m_cached_spks.find(script); + if (it != m_cached_spks.end()) { + // All spkms for a given script must already be able to make a SigningProvider for the script, so just return the first one. + Assume(it->second.at(0)->CanProvide(script, sigdata)); + return it->second.at(0)->GetSolvingProvider(script); } + + // Legacy wallet + if (IsLegacy() && GetLegacyScriptPubKeyMan()->CanProvide(script, sigdata)) return GetLegacyScriptPubKeyMan()->GetSolvingProvider(script); + return nullptr; } @@ -3695,15 +3722,16 @@ void CWallet::ConnectScriptPubKeyManNotifiers() } } -void CWallet::LoadDescriptorScriptPubKeyMan(uint256 id, WalletDescriptor& desc) +DescriptorScriptPubKeyMan& CWallet::LoadDescriptorScriptPubKeyMan(uint256 id, WalletDescriptor& desc) { + DescriptorScriptPubKeyMan* spk_manager; if (IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER)) { - auto spk_manager = std::unique_ptr(new ExternalSignerScriptPubKeyMan(*this, desc, m_keypool_size)); - AddScriptPubKeyMan(id, std::move(spk_manager)); + spk_manager = new ExternalSignerScriptPubKeyMan(*this, desc, m_keypool_size); } else { - auto spk_manager = std::unique_ptr(new DescriptorScriptPubKeyMan(*this, desc, m_keypool_size)); - AddScriptPubKeyMan(id, std::move(spk_manager)); + spk_manager = new DescriptorScriptPubKeyMan(*this, desc, m_keypool_size); } + AddScriptPubKeyMan(id, std::unique_ptr(spk_manager)); + return *spk_manager; } void CWallet::SetupDescriptorScriptPubKeyMans(const CExtKey& master_key) @@ -4058,6 +4086,8 @@ bool CWallet::ApplyMigrationData(MigrationData& data, bilingual_str& error) if (ExtractDestination(script, dest)) not_migrated_dests.emplace(dest); } + Assume(!m_cached_spks.empty()); + for (auto& desc_spkm : data.desc_spkms) { if (m_spk_managers.count(desc_spkm->GetID()) > 0) { error = _("Error: Duplicate descriptors created during migration. Your wallet may be corrupted."); @@ -4541,4 +4571,17 @@ util::Result MigrateLegacyToDescriptor(const std::string& walle } return res; } + +void CWallet::CacheNewScriptPubKeys(const std::set& spks, ScriptPubKeyMan* spkm) +{ + for (const auto& script : spks) { + m_cached_spks[script].push_back(spkm); + } +} + +void CWallet::TopUpCallback(const std::set& spks, ScriptPubKeyMan* spkm) +{ + // Update scriptPubKey cache + CacheNewScriptPubKeys(spks, spkm); +} } // namespace wallet diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 5d6c078961..e1dcb165f8 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -428,6 +428,9 @@ class CWallet final : public WalletStorage, public interfaces::Chain::Notificati // Same as 'AddActiveScriptPubKeyMan' but designed for use within a batch transaction context void AddActiveScriptPubKeyManWithDb(WalletBatch& batch, uint256 id, OutputType type, bool internal); + //! Cache of descriptor ScriptPubKeys used for IsMine. Maps ScriptPubKey to set of spkms + std::unordered_map, SaltedSipHasher> m_cached_spks; + /** * Catch wallet up to current chain, scanning new blocks, updating the best * block locator and m_last_block_processed, and registering for @@ -1004,7 +1007,7 @@ class CWallet final : public WalletStorage, public interfaces::Chain::Notificati void ConnectScriptPubKeyManNotifiers(); //! Instantiate a descriptor ScriptPubKeyMan from the WalletDescriptor and load it - void LoadDescriptorScriptPubKeyMan(uint256 id, WalletDescriptor& desc); + DescriptorScriptPubKeyMan& LoadDescriptorScriptPubKeyMan(uint256 id, WalletDescriptor& desc); //! Adds the active ScriptPubKeyMan for the specified type and internal. Writes it to the wallet file //! @param[in] id The unique id for the ScriptPubKeyMan @@ -1056,6 +1059,11 @@ class CWallet final : public WalletStorage, public interfaces::Chain::Notificati //! Whether the (external) signer performs R-value signature grinding bool CanGrindR() const; + //! Add scriptPubKeys for this ScriptPubKeyMan into the scriptPubKey cache + void CacheNewScriptPubKeys(const std::set& spks, ScriptPubKeyMan* spkm); + + void TopUpCallback(const std::set& spks, ScriptPubKeyMan* spkm) override; + std::map queuedTransactionMap; bool QueuedTransactionExists(const uint256 &txid) const; diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 1a4ba07769..4cb4221d86 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -3,6 +3,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include +#endif + #include #include @@ -832,10 +836,10 @@ static DBErrors LoadDescriptorWalletRecords(CWallet* pwallet, DatabaseBatch& bat strErr = strprintf("%s\nDetails: %s", strErr, e.what()); return DBErrors::UNKNOWN_DESCRIPTOR; } - pwallet->LoadDescriptorScriptPubKeyMan(id, desc); + DescriptorScriptPubKeyMan& spkm = pwallet->LoadDescriptorScriptPubKeyMan(id, desc); // Prior to doing anything with this spkm, verify ID compatibility - if (id != pwallet->GetDescriptorScriptPubKeyMan(desc)->GetID()) { + if (id != spkm.GetID()) { strErr = "The descriptor ID calculated by the wallet differs from the one in DB"; return DBErrors::CORRUPT; } diff --git a/src/warnings.cpp b/src/warnings.cpp index cb73c7aea2..84b021dad5 100644 --- a/src/warnings.cpp +++ b/src/warnings.cpp @@ -3,6 +3,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include +#endif + #include #include diff --git a/test/functional/mempool_accept.py b/test/functional/mempool_accept.py index 2bc1e1841c..16b566bc9a 100755 --- a/test/functional/mempool_accept.py +++ b/test/functional/mempool_accept.py @@ -90,9 +90,17 @@ def run_test(self): txid_in_block = self.wallet.sendrawtransaction(from_node=node, tx_hex=raw_tx_in_block) self.generate(node, 1) self.mempool_size = 0 + # Also check feerate. 1BTC/kvB fails + assert_raises_rpc_error(-8, "Fee rates larger than or equal to 1BTC/kvB are not accepted", lambda: self.check_mempool_result( + result_expected=None, + rawtxs=[raw_tx_in_block], + maxfeerate=1, + )) + # ... 0.99 passes self.check_mempool_result( result_expected=[{'txid': txid_in_block, 'allowed': False, 'reject-reason': 'txn-already-known'}], rawtxs=[raw_tx_in_block], + maxfeerate=0.99, ) self.log.info('A transaction not in the mempool') diff --git a/test/functional/p2p_v2_transport.py b/test/functional/p2p_v2_transport.py index ec43fc5a97..fe2449124d 100755 --- a/test/functional/p2p_v2_transport.py +++ b/test/functional/p2p_v2_transport.py @@ -12,6 +12,7 @@ from test_framework.util import ( assert_equal, p2p_port, + assert_raises_rpc_error ) @@ -59,6 +60,11 @@ def run_test(self): # V1 nodes can sync with each other assert_equal(self.nodes[2].getblockcount(), 0) assert_equal(self.nodes[3].getblockcount(), 0) + + # addnode rpc error when v2transport requested but not enabled + ip_port = "127.0.0.1:{}".format(p2p_port(3)) + assert_raises_rpc_error(-8, "Error: v2transport requested but not enabled (see -v2transport)", self.nodes[2].addnode, node=ip_port, command='add', v2transport=True) + with self.nodes[2].assert_debug_log(expected_msgs=[], unexpected_msgs=[sending_handshake, downgrading_to_v1]): self.connect_nodes(2, 3, peer_advertises_v2=False) diff --git a/test/functional/test_framework/script.py b/test/functional/test_framework/script.py index db08f8046b..5d74a1474d 100644 --- a/test/functional/test_framework/script.py +++ b/test/functional/test_framework/script.py @@ -750,7 +750,7 @@ def SegwitV0SignatureMsg(script, txTo, inIdx, hashtype, amount): ss += struct.pack("