From 7fe537f7a48675b1d25542bee6f390d665547580 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A8le=20Oul=C3=A8s?= Date: Tue, 18 Oct 2022 11:20:06 +0200 Subject: [PATCH 01/41] Implement CCoinsViewErrorCatcher::HaveCoin --- src/coins.cpp | 16 +++++++++++++--- src/coins.h | 1 + 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/coins.cpp b/src/coins.cpp index 5983a8a39f..37dd71874b 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -292,11 +292,13 @@ const Coin& AccessByTxid(const CCoinsViewCache& view, const uint256& txid) return coinEmpty; } -bool CCoinsViewErrorCatcher::GetCoin(const COutPoint &outpoint, Coin &coin) const { +template +static bool ExecuteBackedWrapper(Func func, const std::vector>& err_callbacks) +{ try { - return CCoinsViewBacked::GetCoin(outpoint, coin); + return func(); } catch(const std::runtime_error& e) { - for (const auto& f : m_err_callbacks) { + for (const auto& f : err_callbacks) { f(); } LogPrintf("Error reading from database: %s\n", e.what()); @@ -307,3 +309,11 @@ bool CCoinsViewErrorCatcher::GetCoin(const COutPoint &outpoint, Coin &coin) cons std::abort(); } } + +bool CCoinsViewErrorCatcher::GetCoin(const COutPoint &outpoint, Coin &coin) const { + return ExecuteBackedWrapper([&]() { return CCoinsViewBacked::GetCoin(outpoint, coin); }, m_err_callbacks); +} + +bool CCoinsViewErrorCatcher::HaveCoin(const COutPoint &outpoint) const { + return ExecuteBackedWrapper([&]() { return CCoinsViewBacked::HaveCoin(outpoint); }, m_err_callbacks); +} diff --git a/src/coins.h b/src/coins.h index 67fecc9785..a4f4776386 100644 --- a/src/coins.h +++ b/src/coins.h @@ -349,6 +349,7 @@ class CCoinsViewErrorCatcher final : public CCoinsViewBacked } bool GetCoin(const COutPoint &outpoint, Coin &coin) const override; + bool HaveCoin(const COutPoint &outpoint) const override; private: /** A list of callbacks to execute upon leveldb read error. */ From ed52e71176fc97c6ed01e3eebd85acdec54b4448 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A8le=20Oul=C3=A8s?= Date: Tue, 18 Oct 2022 10:59:37 +0200 Subject: [PATCH 02/41] Periodically check disk space to avoid corruption --- src/init.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/init.cpp b/src/init.cpp index 8ffab64622..57646c3eeb 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1159,6 +1159,15 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) RandAddPeriodic(); }, std::chrono::minutes{1}); + // Check disk space every 5 minutes to avoid db corruption. + node.scheduler->scheduleEvery([&args]{ + constexpr uint64_t min_disk_space = 50 << 20; // 50 MB + if (!CheckDiskSpace(args.GetBlocksDirPath(), min_disk_space)) { + LogPrintf("Shutting down due to lack of disk space!\n"); + StartShutdown(); + } + }, std::chrono::minutes{5}); + GetMainSignals().RegisterBackgroundSignalScheduler(*node.scheduler); // Create client interfaces for wallets that are supposed to be loaded From a9d070a6f89d855aec5fbe6efe679feef86a21f3 Mon Sep 17 00:00:00 2001 From: fanquake Date: Wed, 4 Oct 2023 16:51:38 +0100 Subject: [PATCH 03/41] kernel: update nMinimumChainWork & defaultAssumeValid for 26.x --- src/kernel/chainparams.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/kernel/chainparams.cpp b/src/kernel/chainparams.cpp index 5e893a3f58..c57e6ea3d5 100644 --- a/src/kernel/chainparams.cpp +++ b/src/kernel/chainparams.cpp @@ -104,8 +104,8 @@ class CMainParams : public CChainParams { consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = 1628640000; // August 11th, 2021 consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].min_activation_height = 709632; // Approximately November 12th, 2021 - consensus.nMinimumChainWork = uint256S("0x000000000000000000000000000000000000000044a50fe819c39ad624021859"); - consensus.defaultAssumeValid = uint256S("0x000000000000000000035c3f0d31e71a5ee24c5aaf3354689f65bd7b07dee632"); // 784000 + consensus.nMinimumChainWork = uint256S("0x000000000000000000000000000000000000000052b2559353df4117b7348b64"); + consensus.defaultAssumeValid = uint256S("0x00000000000000000001a0a448d6cf2546b06801389cc030b2b18c6491266815"); // 804000 /** * The message start string is designed to be unlikely to occur in normal data. @@ -222,8 +222,8 @@ class CTestNetParams : public CChainParams { consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = 1628640000; // August 11th, 2021 consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].min_activation_height = 0; // No activation delay - consensus.nMinimumChainWork = uint256S("0x000000000000000000000000000000000000000000000977edb0244170858d07"); - consensus.defaultAssumeValid = uint256S("0x0000000000000021bc50a89cde4870d4a81ffe0153b3c8de77b435a2fd3f6761"); // 2429000 + consensus.nMinimumChainWork = uint256S("0x000000000000000000000000000000000000000000000b6a51f415a67c0da307"); + consensus.defaultAssumeValid = uint256S("0x0000000000000093bcb68c03a9a168ae252572d348a2eaeba2cdf9231d73206f"); // 2500000 pchMessageStart[0] = 0x0b; pchMessageStart[1] = 0x11; @@ -302,8 +302,8 @@ class SigNetParams : public CChainParams { vSeeds.emplace_back("178.128.221.177"); vSeeds.emplace_back("v7ajjeirttkbnt32wpy3c6w3emwnfr3fkla7hpxcfokr3ysd3kqtzmqd.onion:38333"); - consensus.nMinimumChainWork = uint256S("0x000000000000000000000000000000000000000000000000000001899d8142b0"); - consensus.defaultAssumeValid = uint256S("0x0000004429ef154f7e00b4f6b46bfbe2d2678ecd351d95bbfca437ab9a5b84ec"); // 138000 + consensus.nMinimumChainWork = uint256S("0x000000000000000000000000000000000000000000000000000001ad46be4862"); + consensus.defaultAssumeValid = uint256S("0x0000013d778ba3f914530f11f6b69869c9fab54acff85acd7b8201d111f19b7f"); // 150000 m_assumed_blockchain_size = 1; m_assumed_chain_state_size = 0; chainTxData = ChainTxData{ From a8c2e5e556daf2a8c6b013110c802768b3f4b30e Mon Sep 17 00:00:00 2001 From: fanquake Date: Wed, 4 Oct 2023 17:01:42 +0100 Subject: [PATCH 04/41] kernel: update chainTxData for 26.x --- src/kernel/chainparams.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/kernel/chainparams.cpp b/src/kernel/chainparams.cpp index c57e6ea3d5..8b9b92d725 100644 --- a/src/kernel/chainparams.cpp +++ b/src/kernel/chainparams.cpp @@ -177,10 +177,10 @@ class CMainParams : public CChainParams { }; chainTxData = ChainTxData{ - // Data from RPC: getchaintxstats 4096 000000000000000000035c3f0d31e71a5ee24c5aaf3354689f65bd7b07dee632 - .nTime = 1680665245, - .nTxCount = 820876044, - .dTxRate = 3.672283614033389, + // Data from RPC: getchaintxstats 4096 00000000000000000001a0a448d6cf2546b06801389cc030b2b18c6491266815 + .nTime = 1692502494, + .nTxCount = 881818374, + .dTxRate = 5.521964628130412, }; } }; @@ -276,10 +276,10 @@ class CTestNetParams : public CChainParams { }; chainTxData = ChainTxData{ - // Data from RPC: getchaintxstats 4096 0000000000000021bc50a89cde4870d4a81ffe0153b3c8de77b435a2fd3f6761 - .nTime = 1681542696, - .nTxCount = 65345929, - .dTxRate = 0.09855282814711661, + // Data from RPC: getchaintxstats 4096 0000000000000093bcb68c03a9a168ae252572d348a2eaeba2cdf9231d73206f + .nTime = 1694733634, + .nTxCount = 66484552, + .dTxRate = 0.1804908356632494, }; } }; @@ -307,10 +307,10 @@ class SigNetParams : public CChainParams { m_assumed_blockchain_size = 1; m_assumed_chain_state_size = 0; chainTxData = ChainTxData{ - // Data from RPC: getchaintxstats 4096 0000004429ef154f7e00b4f6b46bfbe2d2678ecd351d95bbfca437ab9a5b84ec - .nTime = 1681127428, - .nTxCount = 2226359, - .dTxRate = 0.006424463050600656, + // Data from RPC: getchaintxstats 4096 0000013d778ba3f914530f11f6b69869c9fab54acff85acd7b8201d111f19b7f + .nTime = 1688366339, + .nTxCount = 2262750, + .dTxRate = 0.003414084572046456, }; } else { bin = *options.challenge; From f12f92b813cd8c29904f36f8ed7ed74649886897 Mon Sep 17 00:00:00 2001 From: fanquake Date: Wed, 4 Oct 2023 17:10:39 +0100 Subject: [PATCH 05/41] kernel: update m_assumed_* chain params for 26.x --- src/kernel/chainparams.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/kernel/chainparams.cpp b/src/kernel/chainparams.cpp index 8b9b92d725..8563d0e8eb 100644 --- a/src/kernel/chainparams.cpp +++ b/src/kernel/chainparams.cpp @@ -118,8 +118,8 @@ class CMainParams : public CChainParams { pchMessageStart[3] = 0xd9; nDefaultPort = 8333; nPruneAfterHeight = 100000; - m_assumed_blockchain_size = 540; - m_assumed_chain_state_size = 7; + m_assumed_blockchain_size = 590; + m_assumed_chain_state_size = 9; genesis = CreateGenesisBlock(1231006505, 2083236893, 0x1d00ffff, 1, 50 * COIN); consensus.hashGenesisBlock = genesis.GetHash(); From b2ede22395ae8ce371433c9611929374dd98908a Mon Sep 17 00:00:00 2001 From: fanquake Date: Thu, 5 Oct 2023 11:36:03 +0100 Subject: [PATCH 06/41] headerssync: update params for 26.x --- contrib/devtools/headerssync-params.py | 4 ++-- src/headerssync.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/contrib/devtools/headerssync-params.py b/contrib/devtools/headerssync-params.py index f0088d6cb9..0198f5db99 100644 --- a/contrib/devtools/headerssync-params.py +++ b/contrib/devtools/headerssync-params.py @@ -12,13 +12,13 @@ # Parameters: # Aim for still working fine at some point in the future. [datetime] -TIME = datetime(2026, 5, 25) +TIME = datetime(2026, 10, 5) # Expected block interval. [timedelta] BLOCK_INTERVAL = timedelta(seconds=600) # The number of headers corresponding to the minchainwork parameter. [headers] -MINCHAINWORK_HEADERS = 784000 +MINCHAINWORK_HEADERS = 804000 # Combined processing bandwidth from all attackers to one victim. [bit/s] # 6 Gbit/s is approximately the speed at which a single thread of a Ryzen 5950X CPU thread can hash diff --git a/src/headerssync.cpp b/src/headerssync.cpp index 1b5d7305e8..b885590c56 100644 --- a/src/headerssync.cpp +++ b/src/headerssync.cpp @@ -13,11 +13,11 @@ // contrib/devtools/headerssync-params.py. //! Store one header commitment per HEADER_COMMITMENT_PERIOD blocks. -constexpr size_t HEADER_COMMITMENT_PERIOD{600}; +constexpr size_t HEADER_COMMITMENT_PERIOD{606}; //! Only feed headers to validation once this many headers on top have been //! received and validated against commitments. -constexpr size_t REDOWNLOAD_BUFFER_SIZE{14308}; // 14308/600 = ~23.8 commitments +constexpr size_t REDOWNLOAD_BUFFER_SIZE{14441}; // 14441/606 = ~23.8 commitments // Our memory analysis assumes 48 bytes for a CompressedHeader (so we should // re-calculate parameters if we compress further) From fac88a874f57bfbedbaffaf43a01b3a74be8d875 Mon Sep 17 00:00:00 2001 From: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz> Date: Thu, 5 Oct 2023 13:45:51 +0200 Subject: [PATCH 07/41] ci: Avoid cache depends/build --- ci/test/04_install.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ci/test/04_install.sh b/ci/test/04_install.sh index 01faf9fff9..b5a84ae08d 100755 --- a/ci/test/04_install.sh +++ b/ci/test/04_install.sh @@ -21,6 +21,8 @@ if [ -z "$DANGER_RUN_CI_ON_HOST" ]; then "${BASE_READ_ONLY_DIR}" docker volume create "${CONTAINER_NAME}_ccache" || true docker volume create "${CONTAINER_NAME}_depends" || true + docker volume create "${CONTAINER_NAME}_depends_sources" || true + docker volume create "${CONTAINER_NAME}_depends_SDKs_android" || true docker volume create "${CONTAINER_NAME}_previous_releases" || true if [ -n "${RESTART_CI_DOCKER_BEFORE_RUN}" ] ; then @@ -36,7 +38,9 @@ if [ -z "$DANGER_RUN_CI_ON_HOST" ]; then 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" \ --mount "type=volume,src=${CONTAINER_NAME}_ccache,dst=$CCACHE_DIR" \ - --mount "type=volume,src=${CONTAINER_NAME}_depends,dst=$DEPENDS_DIR" \ + --mount "type=volume,src=${CONTAINER_NAME}_depends,dst=$DEPENDS_DIR/built" \ + --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 \ --name "$CONTAINER_NAME" \ From 88c8e3a0e4d6bee015a348536c6e12a2c7835896 Mon Sep 17 00:00:00 2001 From: Ryan Ofsky Date: Tue, 3 Oct 2023 08:43:16 -0400 Subject: [PATCH 08/41] github actions: Fix test-one-commit when parent of head is merge commit Instead of figuring out the commit *after* the last merge and rebasing on that with a ~1 suffix, just figure out the last merge commit directly and rebase on it. This way, if HEAD happens to be a merge commit, the rebase just succeeds immediately without blank variables or errors. From https://github.com/bitcoin/bitcoin/pull/28497#issuecomment-1743430631: The problem is that the PR only contains a one commit after the last merge, so the job _should_ be skipped, but the `pull_request.commits != 1` check is not smart enough to skip it because the PR is based on another PR and has merge ancestor commits. So specifically what happens is that after HEAD~ is checked out, the new HEAD is a merge commit, so the range `$(git log --merges -1 --format=%H)..HEAD` is equivalent to HEAD..HEAD, which is empty, so the `COMMIT_AFTER_LAST_MERGE` variable is empty and the rebase command fails. --- .github/workflows/ci.yml | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 28a027b780..cc003d026c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,19 +31,41 @@ jobs: env: MAX_COUNT: 6 steps: - - run: echo "FETCH_DEPTH=$((${{ github.event.pull_request.commits }} + 2))" >> "$GITHUB_ENV" + - name: Determine fetch depth + run: echo "FETCH_DEPTH=$((${{ github.event.pull_request.commits }} + 2))" >> "$GITHUB_ENV" - uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: ${{ env.FETCH_DEPTH }} - - run: | + - name: Determine commit range + run: | + # Checkout HEAD~ and find the test base commit + # Checkout HEAD~ because it would be wasteful to rerun tests on the PR + # head commit that are already run by other jobs. git checkout HEAD~ - echo "COMMIT_AFTER_LAST_MERGE=$(git log $(git log --merges -1 --format=%H)..HEAD --format=%H --max-count=${{ env.MAX_COUNT }} | tail -1)" >> "$GITHUB_ENV" + # Figure out test base commit by listing ancestors of HEAD, excluding + # ancestors of the most recent merge commit, limiting the list to the + # newest MAX_COUNT ancestors, ordering it from oldest to newest, and + # taking the first one. + # + # If the branch contains up to MAX_COUNT ancestor commits after the + # most recent merge commit, all of those commits will be tested. If it + # contains more, only the most recent MAX_COUNT commits will be + # tested. + # + # In the command below, the ^@ suffix is used to refer to all parents + # of the merge commit as described in: + # https://git-scm.com/docs/git-rev-parse#_other_rev_parent_shorthand_notations + # and the ^ prefix is used to exclude these parents and all their + # ancestors from the rev-list output as described in: + # https://git-scm.com/docs/git-rev-list + echo "TEST_BASE=$(git rev-list -n$((${{ env.MAX_COUNT }} + 1)) --reverse HEAD ^$(git rev-list -n1 --merges HEAD)^@ | head -1)" >> "$GITHUB_ENV" - run: sudo apt install clang ccache build-essential libtool autotools-dev automake pkg-config bsdmainutils python3-zmq libevent-dev libboost-dev libsqlite3-dev libdb++-dev systemtap-sdt-dev libminiupnpc-dev libnatpmp-dev libqt5gui5 libqt5core5a libqt5dbus5 qttools5-dev qttools5-dev-tools qtwayland5 libqrencode-dev -y - name: Compile and run tests run: | + # Run tests on commits after the last merge commit and before the PR head commit # Use clang++, because it is a bit faster and uses less memory than g++ - git rebase --exec "echo Running test-one-commit on \$( git log -1 ) && ./autogen.sh && CC=clang CXX=clang++ ./configure && make clean && make -j $(nproc) check && ./test/functional/test_runner.py -j $(( $(nproc) * 2 ))" ${{ env.COMMIT_AFTER_LAST_MERGE }}~1 + git rebase --exec "echo Running test-one-commit on \$( git log -1 ) && ./autogen.sh && CC=clang CXX=clang++ ./configure && make clean && make -j $(nproc) check && ./test/functional/test_runner.py -j $(( $(nproc) * 2 ))" ${{ env.TEST_BASE }} macos-native-x86_64: name: 'macOS 13 native, x86_64, no depends, sqlite only, gui' From bd71f03df75d2c17926b6d575ffa886daa334e3a Mon Sep 17 00:00:00 2001 From: fanquake Date: Thu, 5 Oct 2023 13:40:40 +0100 Subject: [PATCH 09/41] doc: update example pulls in release-process.md --- doc/release-process.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/release-process.md b/doc/release-process.md index 468efeb7e1..c70b0194ab 100644 --- a/doc/release-process.md +++ b/doc/release-process.md @@ -28,7 +28,7 @@ Release Process #### Before branch-off -* Update hardcoded [seeds](/contrib/seeds/README.md), see [this pull request](https://github.com/bitcoin/bitcoin/pull/7415) for an example. +* Update hardcoded [seeds](/contrib/seeds/README.md), see [this pull request](https://github.com/bitcoin/bitcoin/pull/27488) for an example. * Update the following variables in [`src/kernel/chainparams.cpp`](/src/kernel/chainparams.cpp) for mainnet, testnet, and signet: - `m_assumed_blockchain_size` and `m_assumed_chain_state_size` with the current size plus some overhead (see [this](#how-to-calculate-assumed-blockchain-and-chain-state-size) for information on how to calculate them). @@ -36,7 +36,7 @@ Release Process that causes rejection of blocks in the past history. - `chainTxData` with statistics about the transaction count and rate. Use the output of the `getchaintxstats` RPC with an `nBlocks` of 4096 (28 days) and a `bestblockhash` of RPC `getbestblockhash`; see - [this pull request](https://github.com/bitcoin/bitcoin/pull/20263) for an example. Reviewers can verify the results by running + [this pull request](https://github.com/bitcoin/bitcoin/pull/28591) for an example. Reviewers can verify the results by running `getchaintxstats ` with the `window_block_count` and `window_final_block_hash` from your output. - `defaultAssumeValid` with the output of RPC `getblockhash` using the `height` of `window_final_block_height` above (and update the block height comment with that height), taking into account the following: @@ -45,7 +45,7 @@ Release Process - `nMinimumChainWork` with the "chainwork" value of RPC `getblockheader` using the same height as that selected for the previous step. * Consider updating the headers synchronization tuning parameters to account for the chainparams updates. The optimal values change very slowly, so this isn't strictly necessary every release, but doing so doesn't hurt. - - Update configuration variables in [`contrib/devtools/headerssync-params.py`](contrib/devtools/headerssync-params.py): + - Update configuration variables in [`contrib/devtools/headerssync-params.py`](/contrib/devtools/headerssync-params.py): - Set `TIME` to the software's expected supported lifetime -- after this time, its ability to defend against a high bandwidth timewarp attacker will begin to degrade. - Set `MINCHAINWORK_HEADERS` to the height used for the `nMinimumChainWork` calculation above. - Check that the other variables still look reasonable. From 05af4dfa50c229c8533d9a71e046c9387e1cdb27 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Thu, 5 Oct 2023 19:20:30 -0400 Subject: [PATCH 10/41] test: Use feerate higher than minrelay fee in wallet_fundraw The external input weight test in wallet_fundrawtransaction.py made transactions at the minimum relay fee. However due to ECDSA sometimes making a shorter signature than expected, the size estimate (and therefore the funded fee) ends up being a little bit too low, which results in the final transaction being under the min relay fee. We can compensate for this by just using a feerate higher than the minrelayfee as the actual feerate itself does not matter in this test. --- test/functional/wallet_fundrawtransaction.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/functional/wallet_fundrawtransaction.py b/test/functional/wallet_fundrawtransaction.py index ca4feefb2b..9b125d998b 100755 --- a/test/functional/wallet_fundrawtransaction.py +++ b/test/functional/wallet_fundrawtransaction.py @@ -1063,19 +1063,19 @@ def test_external_inputs(self): high_input_weight = input_weight * 2 # Funding should also work if the input weight is provided - funded_tx = wallet.fundrawtransaction(raw_tx, input_weights=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": input_weight}]) + funded_tx = wallet.fundrawtransaction(raw_tx, input_weights=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": input_weight}], fee_rate=2) signed_tx = wallet.signrawtransactionwithwallet(funded_tx["hex"]) signed_tx = self.nodes[0].signrawtransactionwithwallet(signed_tx["hex"]) assert_equal(self.nodes[0].testmempoolaccept([signed_tx["hex"]])[0]["allowed"], True) assert_equal(signed_tx["complete"], True) # Reducing the weight should have a lower fee - funded_tx2 = wallet.fundrawtransaction(raw_tx, input_weights=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": low_input_weight}]) + funded_tx2 = wallet.fundrawtransaction(raw_tx, input_weights=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": low_input_weight}], fee_rate=2) assert_greater_than(funded_tx["fee"], funded_tx2["fee"]) # Increasing the weight should have a higher fee - funded_tx2 = wallet.fundrawtransaction(raw_tx, input_weights=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": high_input_weight}]) + funded_tx2 = wallet.fundrawtransaction(raw_tx, input_weights=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": high_input_weight}], fee_rate=2) assert_greater_than(funded_tx2["fee"], funded_tx["fee"]) # The provided weight should override the calculated weight when solving data is provided - funded_tx3 = wallet.fundrawtransaction(raw_tx, solving_data={"descriptors": [desc]}, input_weights=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": high_input_weight}]) + funded_tx3 = wallet.fundrawtransaction(raw_tx, solving_data={"descriptors": [desc]}, input_weights=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": high_input_weight}], fee_rate=2) assert_equal(funded_tx2["fee"], funded_tx3["fee"]) # The feerate should be met funded_tx4 = wallet.fundrawtransaction(raw_tx, input_weights=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": high_input_weight}], fee_rate=10) @@ -1085,8 +1085,8 @@ def test_external_inputs(self): assert_fee_amount(funded_tx4["fee"], tx4_vsize, Decimal(0.0001)) # Funding with weight at csuint boundaries should not cause problems - funded_tx = wallet.fundrawtransaction(raw_tx, input_weights=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": 255}]) - funded_tx = wallet.fundrawtransaction(raw_tx, input_weights=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": 65539}]) + funded_tx = wallet.fundrawtransaction(raw_tx, input_weights=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": 255}], fee_rate=2) + funded_tx = wallet.fundrawtransaction(raw_tx, input_weights=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": 65539}], fee_rate=2) self.nodes[2].unloadwallet("extfund") From 5f504065544133a47da5a7a240675c23eceb0799 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Sun, 8 Oct 2023 14:01:59 +0100 Subject: [PATCH 11/41] Adjust Gradle properties This change fixes the `apk` target build after bumping Qt version from 5.15.5 to 5.15.10. --- src/qt/android/gradle.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qt/android/gradle.properties b/src/qt/android/gradle.properties index 838870f62d..468f4757c0 100644 --- a/src/qt/android/gradle.properties +++ b/src/qt/android/gradle.properties @@ -1,4 +1,4 @@ -androidBuildToolsVersion=28.0.3 -androidCompileSdkVersion=28 +androidBuildToolsVersion=30.0.3 +androidCompileSdkVersion=30 qt5AndroidDir=new File(".").absolutePath org.gradle.jvmargs=-Xmx4608M From 5c9513ece9234b8f6056312954429832105a10f3 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Mon, 9 Oct 2023 10:08:52 +0100 Subject: [PATCH 12/41] qt: Update translation source file for v26.0 string freeze The diff is produced by running `make -C src translate`. --- src/qt/bitcoinstrings.cpp | 10 +- src/qt/locale/bitcoin_en.ts | 315 ++-- src/qt/locale/bitcoin_en.xlf | 3181 +++++++++++++++++----------------- 3 files changed, 1839 insertions(+), 1667 deletions(-) diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp index 92fb3912d1..d7b1c70c59 100644 --- a/src/qt/bitcoinstrings.cpp +++ b/src/qt/bitcoinstrings.cpp @@ -84,6 +84,9 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" "Error: Unable to produce descriptors for this legacy wallet. Make sure to " "provide the wallet's passphrase if it is encrypted."), QT_TRANSLATE_NOOP("bitcoin-core", "" +"Failed to calculate bump fees, because unconfirmed UTXOs depend on enormous " +"cluster of unconfirmed transactions."), +QT_TRANSLATE_NOOP("bitcoin-core", "" "Failed to rename invalid peers.dat file. Please move or delete it and try " "again."), QT_TRANSLATE_NOOP("bitcoin-core", "" @@ -148,18 +151,11 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" "SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is " "supported"), QT_TRANSLATE_NOOP("bitcoin-core", "" -"The -txindex upgrade started by a previous version cannot be completed. " -"Restart with the previous version or run a full -reindex."), -QT_TRANSLATE_NOOP("bitcoin-core", "" "The block database contains a block which appears to be from the future. " "This may be due to your computer's date and time being set incorrectly. Only " "rebuild the block database if you are sure that your computer's date and " "time are correct"), QT_TRANSLATE_NOOP("bitcoin-core", "" -"The block index db contains a legacy 'txindex'. To clear the occupied disk " -"space, run a full -reindex, otherwise ignore this error. This error message " -"will not be displayed again."), -QT_TRANSLATE_NOOP("bitcoin-core", "" "The inputs size exceeds the maximum weight. Please try sending a smaller " "amount or manually consolidating your wallet's UTXOs"), QT_TRANSLATE_NOOP("bitcoin-core", "" diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts index 8cb5ffbc65..fcba44f809 100644 --- a/src/qt/locale/bitcoin_en.ts +++ b/src/qt/locale/bitcoin_en.ts @@ -55,12 +55,12 @@ - + &Delete &Delete - + Choose the address to send coins to @@ -76,16 +76,6 @@ - Sending addresses - - - - - Receiving addresses - - - - These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins. @@ -111,7 +101,7 @@ Signing is only possible with addresses of the type 'legacy'. - + Export Address List @@ -128,7 +118,17 @@ Signing is only possible with addresses of the type 'legacy'. - + + Sending addresses - %1 + + + + + Receiving addresses - %1 + + + + Exporting Failed @@ -215,12 +215,12 @@ Signing is only possible with addresses of the type 'legacy'. - + Wallet encrypted - + Enter the new passphrase for the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>. @@ -257,41 +257,41 @@ Signing is only possible with addresses of the type 'legacy'. - + Wallet encryption failed - + Wallet encryption failed due to an internal error. Your wallet was not encrypted. - + The supplied passphrases do not match. - + - + Wallet unlock failed - - + + The passphrase entered for the wallet decryption was incorrect. - + The passphrase entered for the wallet decryption is incorrect. It contains a null character (ie - a zero byte). If the passphrase was set with a version of this software prior to 25.0, please try again with only the characters up to — but not including — the first null character. If this is successful, please set a new passphrase to avoid this issue in the future. - + Wallet passphrase was successfully changed. @@ -357,7 +357,7 @@ Signing is only possible with addresses of the type 'legacy'. BitcoinGUI - + &Overview &Overview @@ -417,7 +417,7 @@ Signing is only possible with addresses of the type 'legacy'. - + &Minimize @@ -427,18 +427,18 @@ Signing is only possible with addresses of the type 'legacy'. - + Network activity disabled. A substring of the tooltip. - + Proxy is <b>enabled</b>: %1 - + Send coins to a Bitcoin address Send coins to a Bitcoin address @@ -533,12 +533,12 @@ Signing is only possible with addresses of the type 'legacy'. - + &File &File - + &Settings &Settings @@ -553,7 +553,7 @@ Signing is only possible with addresses of the type 'legacy'. Tabs toolbar - + Syncing Headers (%1%)… @@ -578,7 +578,7 @@ Signing is only possible with addresses of the type 'legacy'. - + Request payments (generates QR codes and bitcoin: URIs) @@ -593,7 +593,7 @@ Signing is only possible with addresses of the type 'legacy'. - + &Command-line options @@ -626,7 +626,7 @@ Signing is only possible with addresses of the type 'legacy'. Transactions after this will not yet be visible. - + Error Error @@ -641,12 +641,12 @@ Signing is only possible with addresses of the type 'legacy'. Information - + Up to date Up to date - + Ctrl+Q @@ -722,6 +722,16 @@ Signing is only possible with addresses of the type 'legacy'. Close all wallets + + + Migrate Wallet + + + + + Migrate a wallet + + Show the %1 help message to get a list with possible Bitcoin command-line options @@ -772,7 +782,7 @@ Signing is only possible with addresses of the type 'legacy'. - + &Window &Window @@ -792,12 +802,12 @@ Signing is only possible with addresses of the type 'legacy'. - + %1 client - + &Hide @@ -845,7 +855,17 @@ Signing is only possible with addresses of the type 'legacy'. - + + Error creating wallet + + + + + Cannot create new wallet, the software was compiled without sqlite support (required for descriptor wallets) + + + + Error: %1 @@ -1115,7 +1135,7 @@ Signing is only possible with addresses of the type 'legacy'. - + Create wallet failed @@ -1143,7 +1163,17 @@ Signing is only possible with addresses of the type 'legacy'. - + + You are one step away from creating your new wallet! + + + + + Please provide a name and, if desired, enable any advanced options + + + + Wallet Name @@ -1168,7 +1198,7 @@ Signing is only possible with addresses of the type 'legacy'. - + Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets. @@ -1189,16 +1219,6 @@ Signing is only possible with addresses of the type 'legacy'. - Use descriptors for scriptPubKey management - - - - - Descriptor Wallet - - - - Use an external signing device such as a hardware wallet. Configure the external signer script in wallet preferences first. @@ -1214,11 +1234,6 @@ Signing is only possible with addresses of the type 'legacy'. - Compiled without sqlite support (required for descriptor wallets) - - - - Compiled without external signing support (required for external signing) "External signing" means using devices such as hardware wallets. @@ -1484,6 +1499,63 @@ Signing is only possible with addresses of the type 'legacy'. + + MigrateWalletActivity + + + Migrate wallet + + + + + Are you sure you wish to migrate the wallet <i>%1</i>? + + + + + Migrating the wallet will convert this wallet to one or more descriptor wallets. A new wallet backup will need to be made. +If this wallet contains any watchonly scripts, a new wallet will be created which contains those watchonly scripts. +If this wallet contains any solvable but not watched scripts, a different and new wallet will be created which contains those scripts. + +The migration process will create a backup of the wallet before migrating. This backup file will be named <wallet name>-<timestamp>.legacy.bak and can be found in the directory for this wallet. In the event of an incorrect migration, the backup can be restored with the "Restore Wallet" functionality. + + + + + Migrate Wallet + + + + + Migrating Wallet <b>%1</b>… + + + + + The wallet '%1' was migrated successfully. + + + + + Watchonly scripts have been migrated to a new wallet named '%1'. + + + + + Solvable but not watched scripts have been migrated to a new wallet named '%1'. + + + + + Migration failed + + + + + Migration Successful + + + ModalOverlay @@ -1587,7 +1659,7 @@ Signing is only possible with addresses of the type 'legacy'. OpenWalletActivity - + Open wallet failed @@ -2675,7 +2747,7 @@ If you are receiving this error you should request the merchant provide a BIP21 - + %1 kB @@ -2774,6 +2846,8 @@ If you are receiving this error you should request the merchant provide a BIP21 + + @@ -2802,7 +2876,7 @@ If you are receiving this error you should request the merchant provide a BIP21 N/A - + Client version Client version @@ -2843,12 +2917,12 @@ If you are receiving this error you should request the merchant provide a BIP21 - + Network Network - + Name @@ -2894,18 +2968,18 @@ If you are receiving this error you should request the merchant provide a BIP21 - + Received - - + + Sent - + &Peers @@ -2921,7 +2995,27 @@ If you are receiving this error you should request the merchant provide a BIP21 - + + The transport layer version: %1 + + + + + Transport + + + + + The BIP324 session ID string in hex, if any. + + + + + Session ID + + + + Version @@ -3002,13 +3096,13 @@ If you are receiving this error you should request the merchant provide a BIP21 - - + + User Agent - + Node window @@ -3048,7 +3142,7 @@ If you are receiving this error you should request the merchant provide a BIP21 - + The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS. @@ -3124,7 +3218,7 @@ If you are receiving this error you should request the merchant provide a BIP21 - + Last block time Last block time @@ -3199,7 +3293,7 @@ If you are receiving this error you should request the merchant provide a BIP21 - + Inbound: initiated by peer Explanatory text for an inbound peer connection. @@ -3234,6 +3328,24 @@ If you are receiving this error you should request the merchant provide a BIP21 Explanatory text for a short-lived outbound peer connection that is used to request addresses from a peer. + + + detecting: peer could be v1 or v2 + Explanatory text for "detecting" transport type. + + + + + v1: unencrypted, plaintext transport protocol + Explanatory text for v1 transport type. + + + + + v2: BIP324 encrypted transport protocol + Explanatory text for v2 transport type. + + we selected the peer for high bandwidth relay @@ -3326,7 +3438,7 @@ If you are receiving this error you should request the merchant provide a BIP21 - + Ctrl+I @@ -3346,7 +3458,7 @@ If you are receiving this error you should request the merchant provide a BIP21 - + Executing command using "%1" wallet @@ -4721,7 +4833,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 TransactionTableModel - + Date Date @@ -4785,11 +4897,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 Sent to - - - Payment to yourself - - Mined @@ -4801,12 +4908,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 - + (n/a) - + (no label) @@ -4886,11 +4993,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 - To yourself - - - - Mined @@ -4910,12 +5012,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 - + Range… - + &Copy address @@ -5058,7 +5160,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 WalletController - + Close wallet @@ -5351,7 +5453,7 @@ Go to File > Open Wallet to load a wallet. - + File %s already exists. If you are sure this is what you want, move it out of the way first. @@ -5416,17 +5518,12 @@ Go to File > Open Wallet to load a wallet. - + The block database contains a block which appears to be from the future. This may be due to your computer's date and time being set incorrectly. Only rebuild the block database if you are sure that your computer's date and time are correct - - The block index db contains a legacy 'txindex'. To clear the occupied disk space, run a full -reindex, otherwise ignore this error. This error message will not be displayed again. - - - - + The transaction amount is too small to send after the fee has been deducted @@ -5551,12 +5648,7 @@ Go to File > Open Wallet to load a wallet. - - The -txindex upgrade started by a previous version cannot be completed. Restart with the previous version or run a full -reindex. - - - - + %s is set very high! Fees this large could be paid on a single transaction. @@ -5592,6 +5684,11 @@ Go to File > Open Wallet to load a wallet. + Failed to calculate bump fees, because unconfirmed UTXOs depend on enormous cluster of unconfirmed transactions. + + + + Failed to rename invalid peers.dat file. Please move or delete it and try again. @@ -5631,7 +5728,7 @@ Go to File > Open Wallet to load a wallet. - + The inputs size exceeds the maximum weight. Please try sending a smaller amount or manually consolidating your wallet's UTXOs diff --git a/src/qt/locale/bitcoin_en.xlf b/src/qt/locale/bitcoin_en.xlf index 9d4a989cf0..b1a01cb4a1 100644 --- a/src/qt/locale/bitcoin_en.xlf +++ b/src/qt/locale/bitcoin_en.xlf @@ -45,7 +45,7 @@ &Delete 101 - ../addressbookpage.cpp127 + ../addressbookpage.cpp117 @@ -53,62 +53,62 @@ Choose the address to send coins to - 89 + 87 Choose the address to receive coins with - 90 + 88 C&hoose - 95 + 93 - Sending addresses - 101 - - - Receiving addresses - 102 - - These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins. - 109 + 99 - + These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses. Signing is only possible with addresses of the type 'legacy'. - 114 + 104 - + &Copy Address - 122 + 112 - + Copy &Label - 123 + 113 - + &Edit - 124 + 114 - + Export Address List - 288 + 279 - + Comma separated file - 291 + 282 Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values. - + There was an error trying to save the address list to %1. Please try again. - 307 + 298 An error message. %1 is a stand-in argument for the name of the file we attempted to save to. + + Sending addresses - %1 + 330 + + + Receiving addresses - %1 + 331 + Exporting Failed - 304 + 295 @@ -185,7 +185,7 @@ Signing is only possible with addresses of the type 'legacy'. Wallet encrypted 126 - 181 + 184 Enter the new passphrase for the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>. @@ -219,7 +219,7 @@ Signing is only possible with addresses of the type 'legacy'. Wallet encryption failed 136 144 - 203 + 206 Wallet encryption failed due to an internal error. Your wallet was not encrypted. @@ -228,18 +228,18 @@ Signing is only possible with addresses of the type 'legacy'. The supplied passphrases do not match. 145 - 204 + 207 Wallet unlock failed 158 161 - 173 + 176 The passphrase entered for the wallet decryption was incorrect. 159 - 190 + 193 The passphrase entered for the wallet decryption is incorrect. It contains a null character (ie - a zero byte). If the passphrase was set with a version of this software prior to 25.0, please try again with only the characters up to — but not including — the first null character. If this is successful, please set a new passphrase to avoid this issue in the future. @@ -247,21 +247,21 @@ Signing is only possible with addresses of the type 'legacy'. Wallet passphrase was successfully changed. - 182 + 185 Passphrase change failed - 189 192 + 195 The old passphrase entered for the wallet decryption is incorrect. It contains a null character (ie - a zero byte). If the passphrase was set with a version of this software prior to 25.0, please try again with only the characters up to — but not including — the first null character. - 193 + 196 Warning: The Caps Lock key is on! - 238 - 271 + 241 + 274 @@ -325,59 +325,59 @@ Signing is only possible with addresses of the type 'legacy'. &Overview - 254 + 250 Show general overview of wallet - 255 + 251 &Transactions - 275 + 271 Browse transaction history - 276 + 272 E&xit - 295 + 291 Quit application - 296 + 292 &About %1 - 299 + 295 Show information about %1 - 300 + 296 About &Qt - 303 + 299 Show information about Qt - 304 + 300 Modify configuration options for %1 - 307 + 303 Create a new wallet - 351 + 347 &Minimize - 515 + 510 Wallet: - 594 + 589 Network activity disabled. @@ -386,99 +386,99 @@ Signing is only possible with addresses of the type 'legacy'. Proxy is <b>enabled</b>: %1 - 1437 + 1452 Send coins to a Bitcoin address - 262 + 258 Backup wallet to another location - 315 + 311 Change the passphrase used for wallet encryption - 317 + 313 &Send - 261 + 257 &Receive - 268 + 264 &Options… - 306 + 302 &Encrypt Wallet… - 311 + 307 Encrypt the private keys that belong to your wallet - 312 + 308 &Backup Wallet… - 314 + 310 &Change Passphrase… - 316 + 312 Sign &message… - 318 + 314 Sign messages with your Bitcoin addresses to prove you own them - 319 + 315 &Verify message… - 320 + 316 Verify messages to ensure they were signed with specified Bitcoin addresses - 321 + 317 &Load PSBT from file… - 322 + 318 Open &URI… - 338 + 334 Close Wallet… - 346 + 342 Create Wallet… - 349 + 345 Close All Wallets… - 359 + 355 &File - 482 + 476 &Settings - 502 + 497 &Help - 563 + 558 Tabs toolbar - 574 + 569 Syncing Headers (%1%)… @@ -502,15 +502,15 @@ Signing is only possible with addresses of the type 'legacy'. Request payments (generates QR codes and bitcoin: URIs) - 269 + 265 Show the list of used sending addresses and labels - 334 + 330 Show the list of used receiving addresses and labels - 336 + 332 &Command-line options @@ -543,15 +543,15 @@ Signing is only possible with addresses of the type 'legacy'. Error - 1200 + 1215 Warning - 1204 + 1219 Information - 1208 + 1223 Up to date @@ -559,309 +559,325 @@ Signing is only possible with addresses of the type 'legacy'. Ctrl+Q - 297 + 293 Load Partially Signed Bitcoin Transaction - 323 + 319 Load PSBT from &clipboard… - 324 + 320 Load Partially Signed Bitcoin Transaction from clipboard - 325 + 321 Node window - 327 + 323 Open node debugging and diagnostic console - 328 + 324 &Sending addresses - 333 + 329 &Receiving addresses - 335 + 331 Open a bitcoin: URI - 339 + 335 Open Wallet - 341 + 337 Open a wallet - 343 + 339 Close wallet - 347 + 343 Restore Wallet… - 354 + 350 Name of the menu item that restores wallet from a backup file. Restore a wallet from a backup file - 357 + 353 Status tip for Restore Wallet menu item Close all wallets - 360 + 356 + Migrate Wallet + 358 + + + Migrate a wallet + 360 + + Show the %1 help message to get a list with possible Bitcoin command-line options 364 - + &Mask values 366 - + Mask the values in the Overview tab 368 - + default wallet 399 - + No wallets available 420 - + Wallet Data 426 Name of the wallet data file format. - + Load Wallet Backup 429 The title for Restore Wallet File Windows - + Restore Wallet 437 Title of pop-up window shown when the user is attempting to restore a wallet. - + Wallet Name 439 Label of the input field where the name of the wallet is entered. - + &Window - 513 + 508 - + Ctrl+M - 516 + 511 - + Zoom - 525 + 520 - + Main Window - 543 + 538 - + %1 client - 815 + 812 - + &Hide 880 - + S&how 881 998 A substring of the tooltip. - + %n active connection(s) to Bitcoin network. - + %n active connection(s) to Bitcoin network. - + Click for more actions. 1008 A substring of the tooltip. "More actions" are available via the context menu. - + Show Peers tab 1025 A context menu item. The "Peers tab" is an element of the "Node window". - + Disable network activity 1033 A context menu item. - + Enable network activity 1035 A context menu item. The network activity was disabled previously. - + Pre-syncing Headers (%1%)… 1052 - + + Error creating wallet + 1191 + + + Cannot create new wallet, the software was compiled without sqlite support (required for descriptor wallets) + 1191 + + Error: %1 - 1201 + 1216 - + Warning: %1 - 1205 + 1220 - + Date: %1 - 1313 + 1328 - + Amount: %1 - 1314 + 1329 - + Wallet: %1 - 1316 + 1331 - + Type: %1 - 1318 + 1333 - + Label: %1 - 1320 + 1335 - + Address: %1 - 1322 + 1337 - + Sent transaction - 1323 + 1338 - + Incoming transaction - 1323 + 1338 - + HD key generation is <b>enabled</b> - 1375 + 1390 - + HD key generation is <b>disabled</b> - 1375 + 1390 - + Private key <b>disabled</b> - 1375 + 1390 - + Wallet is <b>encrypted</b> and currently <b>unlocked</b> - 1398 + 1413 - + Wallet is <b>encrypted</b> and currently <b>locked</b> - 1406 + 1421 - + Original message: - 1525 + 1540 - + Unit to show amounts in. Click to select another unit. - 1564 + 1579 - + Coin Selection 14 - + Quantity: 51 - + Bytes: 80 - + Amount: 125 - + Fee: 170 - + After Fee: 218 - + Change: 250 - + (un)select all 306 - + Tree mode 322 - + List mode 335 - + Amount 391 - + Received with label 396 - + Received with address 401 - + Date 406 - + Confirmations 411 - + Confirmed 414 @@ -869,72 +885,72 @@ Signing is only possible with addresses of the type 'legacy'. - + Copy amount 69 - + &Copy address 58 - + Copy &label 59 - + Copy &amount 60 - + Copy transaction &ID and output index 61 - + L&ock unspent 63 - + &Unlock unspent 64 - + Copy quantity 68 - + Copy fee 70 - + Copy after fee 71 - + Copy bytes 72 - + Copy change 73 - + (%1 locked) 371 - + Can vary +/- %1 satoshi(s) per input. 524 - + (no label) 569 623 - + change from %1 (%2) 616 - + (change) 617 @@ -942,114 +958,160 @@ Signing is only possible with addresses of the type 'legacy'. - + Create Wallet 246 Title of window indicating the progress of creation of a new wallet. - + Creating Wallet <b>%1</b>… 249 Descriptive text of the create wallet progress window which indicates to the user which wallet is currently being created. - + Create wallet failed - 282 + 281 - + Create wallet warning - 284 + 283 - + Can't list signers - 300 + 299 - + Too many external signers found - 303 + 302 - + Load Wallets - 377 + 376 Title of progress window which is displayed when wallets are being loaded. - + Loading wallets… - 380 + 379 Descriptive text of the load wallets progress window which indicates to the user that wallets are currently being loaded. + + + Migrate wallet + 442 + + + Are you sure you wish to migrate the wallet <i>%1</i>? + 443 + + + Migrating the wallet will convert this wallet to one or more descriptor wallets. A new wallet backup will need to be made. +If this wallet contains any watchonly scripts, a new wallet will be created which contains those watchonly scripts. +If this wallet contains any solvable but not watched scripts, a different and new wallet will be created which contains those scripts. + +The migration process will create a backup of the wallet before migrating. This backup file will be named <wallet name>-<timestamp>.legacy.bak and can be found in the directory for this wallet. In the event of an incorrect migration, the backup can be restored with the "Restore Wallet" functionality. + 444 + + + Migrate Wallet + 467 + + + Migrating Wallet <b>%1</b>… + 467 + + + The wallet '%1' was migrated successfully. + 473 + + + Watchonly scripts have been migrated to a new wallet named '%1'. + 475 + + + Solvable but not watched scripts have been migrated to a new wallet named '%1'. + 478 + + + Migration failed + 492 + + + Migration Successful + 494 + + - + Open wallet failed - 334 + 333 - + Open wallet warning - 336 + 335 - + default wallet - 346 + 345 - + Open Wallet - 350 + 349 Title of window indicating the progress of opening of a wallet. - + Opening Wallet <b>%1</b>… - 353 + 352 Descriptive text of the open wallet progress window which indicates to the user which wallet is currently being opened. - + Restore Wallet - 403 + 402 Title of progress window which is displayed when wallets are being restored. - + Restoring Wallet <b>%1</b>… - 406 + 405 Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored. - + Restore wallet failed - 425 + 424 Title of message box which is displayed when the wallet could not be restored. - + Restore wallet warning - 428 + 427 Title of message box which is displayed when the wallet is restored with some warning. - + Restore wallet message - 431 + 430 Title of message box which is displayed when the wallet is successfully restored. - + Close wallet 84 - + Are you sure you wish to close the wallet <i>%1</i>? 85 - + Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled. 86 - + Close all wallets 99 - + Are you sure you wish to close all wallets? 100 @@ -1057,100 +1119,96 @@ Signing is only possible with addresses of the type 'legacy'. - + Create Wallet 14 - + + You are one step away from creating your new wallet! + 29 + + + Please provide a name and, if desired, enable any advanced options + 42 + + Wallet Name - 25 + 67 - + Wallet - 38 + 80 - + Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice. - 47 + 89 - + Encrypt Wallet - 50 + 92 - + Advanced Options - 76 + 118 - + Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets. - 85 + 139 - + Disable Private Keys - 88 + 142 - + Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time. - 95 + 149 - + Make Blank Wallet - 98 - - - Use descriptors for scriptPubKey management - 105 - - - Descriptor Wallet - 108 + 152 - + Use an external signing device such as a hardware wallet. Configure the external signer script in wallet preferences first. - 118 + 159 - + External signer - 121 + 162 - + Create 22 - - Compiled without sqlite support (required for descriptor wallets) - 90 - - + Compiled without external signing support (required for external signing) - 104 + 90 "External signing" means using devices such as hardware wallets. - + Edit Address 14 - + &Label 25 - + The label associated with this address list entry 35 - + The address associated with this address list entry. This can only be modified for sending addresses. 52 - + &Address 42 @@ -1158,35 +1216,35 @@ Signing is only possible with addresses of the type 'legacy'. - + New sending address 29 - + Edit receiving address 32 - + Edit sending address 36 - + The entered address "%1" is not a valid Bitcoin address. 113 - + Address "%1" already exists as a receiving address with label "%2" and so cannot be added as a sending address. 146 - + The entered address "%1" is already in the address book with label "%2". 151 - + Could not unlock wallet. 123 - + New key generation failed. 128 @@ -1194,94 +1252,94 @@ Signing is only possible with addresses of the type 'legacy'. - + A new data directory will be created. 75 - + name 97 - + Directory already exists. Add %1 if you intend to create a new directory here. 99 - + Path already exists, and is not a directory. 102 - + Cannot create data directory here. 109 - + Bitcoin 139 301 - + %n GB of space available - + %n GB of space available 303 - + (of %n GB needed) - + (of %n GB needed) 306 - + (%n GB needed for full chain) - + (%n GB needed for full chain) - + Choose data directory 323 - + At least %1 GB of data will be stored in this directory, and it will grow over time. 378 - + Approximately %1 GB of data will be stored in this directory. 381 390 Explanatory text on the capability of the current prune target. - + (sufficient to restore backups %n day(s) old) - + (sufficient to restore backups %n day(s) old) - + %1 will download and store a copy of the Bitcoin block chain. 392 - + The wallet will also be stored in this directory. 394 - + Error: Specified data directory "%1" cannot be created. 250 - + Error 280 @@ -1289,25 +1347,25 @@ Signing is only possible with addresses of the type 'legacy'. - + version 38 - + About %1 42 - + Command-line options 60 - + %1 is shutting down… 145 - + Do not shut down the computer until this window disappears. 146 @@ -1315,47 +1373,47 @@ Signing is only possible with addresses of the type 'legacy'. - + Welcome 14 - + Welcome to %1. 23 - + As this is the first time the program is launched, you can choose where %1 will store its data. 49 - + Limit block chain storage to 238 - + Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features. 241 - + GB 248 - + This initial synchronisation is very demanding, and may expose hardware problems with your computer that had previously gone unnoticed. Each time you run %1, it will continue downloading where it left off. 216 - + 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. 206 - + 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. 226 - + Use the default data directory 66 - + Use a custom data directory: 73 @@ -1363,54 +1421,54 @@ Signing is only possible with addresses of the type 'legacy'. - + Form 14 - + Recent transactions may not yet be visible, and therefore your wallet's balance might be incorrect. This information will be correct once your wallet has finished synchronizing with the bitcoin network, as detailed below. 133 - + Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network. 152 - + Number of blocks left 215 - + Unknown… 222 248 ../modaloverlay.cpp152 - + calculating… 292 312 - + Last block time 235 - + Progress 261 - + Progress increase per hour 285 - + Estimated time left until synced 305 - + Hide 342 - + Esc 345 @@ -1418,21 +1476,21 @@ Signing is only possible with addresses of the type 'legacy'. - + %1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain. 31 - + Unknown. Syncing Headers (%1, %2%)… 158 - + Unknown. Pre-syncing Headers (%1, %2%)… 163 - + unknown 123 @@ -1440,15 +1498,15 @@ Signing is only possible with addresses of the type 'legacy'. - + Open bitcoin URI 14 - + URI: 22 - + Paste address from clipboard 36 Tooltip text for button that allows you to paste an address that is in your clipboard. @@ -1457,310 +1515,310 @@ Signing is only possible with addresses of the type 'legacy'. - + Options 14 - + &Main 27 - + Automatically start %1 after logging in to the system. 33 - + &Start %1 on system login 36 - + Enabling pruning significantly reduces the disk space required to store transactions. All blocks are still fully validated. Reverting this setting requires re-downloading the entire blockchain. 58 - + Size of &database cache 111 - + Number of script &verification threads 157 - + Full path to a %1 compatible script (e.g. C:\Downloads\hwi.exe or /Users/you/Downloads/hwi.py). Beware: malware can steal your coins! 289 - + IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1) 388 575 - + Shows if the supplied default SOCKS5 proxy is used to reach peers via this network type. 457 480 503 - + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Exit in the menu. 672 - + Options set in this dialog are overridden by the command line: 899 - + Open the %1 configuration file from the working directory. 944 - + Open Configuration File 947 - + Reset all client options to default. 957 - + &Reset Options 960 - + &Network 315 - + Prune &block storage to 61 - + GB 71 - + Reverting this setting requires re-downloading the entire blockchain. 96 - + Maximum database cache size. A larger cache can contribute to faster sync, after which the benefit is less pronounced for most use cases. Lowering the cache size will reduce memory usage. Unused mempool memory is shared for this cache. 108 Tooltip text for Options window setting that sets the size of the database cache. Explains the corresponding effects of increasing/decreasing this value. - + MiB 127 - + Set the number of script verification threads. Negative values correspond to the number of cores you want to leave free to the system. 154 Tooltip text for Options window setting that sets the number of script verification threads. Explains that negative values mean to leave these many cores free to the system. - + (0 = auto, <0 = leave that many cores free) 170 - + This allows you or a third party tool to communicate with the node through command-line and JSON-RPC commands. 192 Tooltip text for Options window setting that enables the RPC server. - + Enable R&PC server 195 An Options window setting to enable the RPC server. - + W&allet 216 - + Whether to set subtract fee from amount as default or not. 222 Tooltip text for Options window setting that sets subtracting the fee from a sending amount as default. - + Subtract &fee from amount by default 225 An Options window setting to set subtracting the fee from a sending amount as default. - + Expert 232 - + Enable coin &control features 241 - + If you disable the spending of unconfirmed change, the change from a transaction cannot be used until that transaction has at least one confirmation. This also affects how your balance is computed. 248 - + &Spend unconfirmed change 251 - + Enable &PSBT controls 258 An options window setting to enable PSBT controls. - + Whether to show PSBT controls. 261 Tooltip text for options window setting that enables PSBT controls. - + External Signer (e.g. hardware wallet) 271 - + &External signer script path 279 - + Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. 321 - + Map port using &UPnP 324 - + Automatically open the Bitcoin client port on the router. This only works when your router supports NAT-PMP and it is enabled. The external port could be random. 331 - + Map port using NA&T-PMP 334 - + Accept connections from outside. 341 - + Allow incomin&g connections 344 - + Connect to the Bitcoin network through a SOCKS5 proxy. 351 - + &Connect through SOCKS5 proxy (default proxy): 354 - + Proxy &IP: 363 550 - + &Port: 395 582 - + Port of the proxy (e.g. 9050) 420 607 - + Used for reaching peers via: 444 - + IPv4 467 - + IPv6 490 - + Tor 513 - + &Window 643 - + Show the icon in the system tray. 649 - + &Show tray icon 652 - + Show only a tray icon after minimizing the window. 662 - + &Minimize to the tray instead of the taskbar 665 - + M&inimize on close 675 - + &Display 696 - + User Interface &language: 704 - + The user interface language can be set here. This setting will take effect after restarting %1. 717 - + &Unit to show amounts in: 728 - + Choose the default subdivision unit to show in the interface and when sending coins. 741 - + Third-party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items. %s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. 752 765 - + &Third-party transaction URLs 755 - + Whether to show coin control features or not. 238 - + Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor onion services. 538 - + Use separate SOCKS&5 proxy to reach peers via Tor onion services: 541 - + Monospaced font in the Overview tab: 777 - + embedded "%1" 785 - + closest matching "%1" 834 - + &OK 1040 - + &Cancel 1053 @@ -1768,71 +1826,71 @@ Signing is only possible with addresses of the type 'legacy'. - + Compiled without external signing support (required for external signing) 96 "External signing" means using devices such as hardware wallets. - + default 108 - + none 194 - + Confirm options reset 301 Window title text of pop-up window shown when the user has chosen to reset options. - + Client restart required to activate changes. 292 371 Text explaining that the settings changed will not come into effect until the client is restarted. - + Current settings will be backed up at "%1". 296 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. - + Client will be shut down. Do you want to proceed? 299 Text asking the user to confirm if they would like to proceed with a client shutdown. - + Configuration options 319 Window title text of pop-up box that allows opening up of configuration file. - + The configuration file is used to specify advanced user options which override GUI settings. Additionally, any command-line options will override this configuration file. 322 Explanatory text about the priority order of instructions considered by client. The order from high to low being: command-line, configuration file, GUI settings. - + Continue 325 - + Cancel 326 - + Error 335 - + The configuration file could not be opened. 335 - + This change would require a client restart. 375 - + The supplied proxy address is invalid. 403 @@ -1840,7 +1898,7 @@ Signing is only possible with addresses of the type 'legacy'. - + Could not read setting "%1", %2. 198 @@ -1848,76 +1906,76 @@ Signing is only possible with addresses of the type 'legacy'. - + Form 14 - + The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet. 76 411 - + Watch-only: 284 - + Available: 294 - + Your current spendable balance 304 - + Pending: 339 - + Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance 139 - + Immature: 239 - + Mined balance that has not yet matured 210 - + Balances 60 - + Total: 200 - + Your current total balance 249 - + Your current balance in watch-only addresses 323 - + Spendable: 346 - + Recent transactions 395 - + Unconfirmed transactions to watch-only addresses 120 - + Mined balance in watch-only addresses that has not yet matured 158 - + Current total balance in watch-only addresses 268 @@ -1925,7 +1983,7 @@ Signing is only possible with addresses of the type 'legacy'. - + Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings->Mask values. 184 @@ -1933,27 +1991,27 @@ Signing is only possible with addresses of the type 'legacy'. - + PSBT Operations 14 - + Sign Tx 86 - + Broadcast Tx 102 - + Copy to Clipboard 122 - + Save… 129 - + Close 136 @@ -1961,112 +2019,112 @@ Signing is only possible with addresses of the type 'legacy'. - + Failed to load transaction: %1 60 - + Failed to sign transaction: %1 85 - + Cannot sign inputs while wallet is locked. 93 - + Could not sign any more inputs. 95 - + Signed %1 inputs, but more signatures are still required. 97 - + Signed transaction successfully. Transaction is ready to broadcast. 100 - + Unknown error processing transaction. 112 - + Transaction broadcast successfully! Transaction ID: %1 122 - + Transaction broadcast failed: %1 125 - + PSBT copied to clipboard. 134 - + Save Transaction Data 157 - + Partially Signed Transaction (Binary) 159 Expanded name of the binary PSBT file format. See: BIP 174. - + PSBT saved to disk. 166 - + * Sends %1 to %2 182 - + own address 186 - + Unable to calculate transaction fee or total transaction amount. 194 - + Pays transaction fee: 196 - + Total Amount 208 - + or 211 - + Transaction has %1 unsigned inputs. 217 - + Transaction is missing some information about inputs. 263 - + Transaction still needs signature(s). 267 - + (But no wallet is loaded.) 270 - + (But this wallet cannot sign transactions.) 273 - + (But this wallet does not have the right keys.) 276 - + Transaction is fully signed and ready for broadcast. 284 - + Transaction status is unknown. 288 @@ -2074,37 +2132,37 @@ Signing is only possible with addresses of the type 'legacy'. - + Payment request error 149 - + Cannot start bitcoin: click-to-pay handler 150 - + URI handling 198 214 220 227 - + 'bitcoin://' is not a valid URI. Use 'bitcoin:' instead. 198 - + Cannot process payment request because BIP70 is not supported. Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored. If you are receiving this error you should request the merchant provide a BIP21 compatible URI. 215 238 - + URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters. 228 - + Payment request file handling 237 @@ -2112,52 +2170,52 @@ If you are receiving this error you should request the merchant provide a BIP21 - + User Agent 112 Title of Peers Table column which contains the peer's User Agent string. - + Ping 103 Title of Peers Table column which indicates the current latency of the connection with the peer. - + Peer 85 Title of Peers Table column which contains a unique number used to identify a connection. - + Age 88 Title of Peers Table column which indicates the duration (length of time) since the peer connection started. - + Direction 94 Title of Peers Table column which indicates the direction the peer connection was initiated from. - + Sent 106 Title of Peers Table column which indicates the total amount of network information we have sent to the peer. - + Received 109 Title of Peers Table column which indicates the total amount of network information we have received from the peer. - + Address 91 Title of Peers Table column which contains the IP/Onion/I2P address of the connected peer. - + Type 97 Title of Peers Table column which describes the type of peer connection. The "type" describes why the connection exists. - + Network 100 Title of Peers Table column which states the network the peer connected through. @@ -2166,12 +2224,12 @@ If you are receiving this error you should request the merchant provide a BIP21 - + Inbound 77 An Inbound Connection from a Peer. - + Outbound 79 An Outbound Connection to a Peer. @@ -2180,7 +2238,7 @@ If you are receiving this error you should request the merchant provide a BIP21 - + Amount 197 @@ -2188,190 +2246,190 @@ If you are receiving this error you should request the merchant provide a BIP21 - + Enter a Bitcoin address (e.g. %1) 133 - + Ctrl+W 421 - + Unroutable 678 - + IPv4 680 network name Name of IPv4 network in peer info - + IPv6 682 network name Name of IPv6 network in peer info - + Onion 684 network name Name of Tor network in peer info - + I2P 686 network name Name of I2P network in peer info - + CJDNS 688 network name Name of CJDNS network in peer info - + Inbound 702 An inbound connection from a peer. An inbound connection is a connection initiated by a peer. - + Outbound 705 An outbound connection to a peer. An outbound connection is a connection initiated by us. - + Full Relay 710 Peer connection type that relays all network information. - + Block Relay 713 Peer connection type that relays network information about blocks and not transactions or addresses. - + Manual 715 Peer connection type established manually through one of several methods. - + Feeler 717 Short-lived peer connection type that tests the aliveness of known addresses. - + Address Fetch 719 Short-lived peer connection type that solicits known addresses from a peer. - + %1 d 732 744 - + %1 h 733 745 - + %1 m 734 746 - + %1 s 736 747 773 - + None 761 - + N/A 767 - + %1 ms 768 786 - + %n second(s) - + %n second(s) 790 - + %n minute(s) - + %n minute(s) 794 - + %n hour(s) - + %n hour(s) 798 - + %n day(s) - + %n day(s) 802 808 - + %n week(s) - + %n week(s) - + %1 and %2 808 808 - + %n year(s) - + %n year(s) - + %1 B 816 - + %1 kB 818 - ../rpcconsole.cpp994 + ../rpcconsole.cpp1004 - + %1 MB 820 - ../rpcconsole.cpp996 + ../rpcconsole.cpp1006 - + %1 GB 822 @@ -2379,31 +2437,31 @@ If you are receiving this error you should request the merchant provide a BIP21 - + &Save Image… 30 - + &Copy Image 31 - + Resulting URI too long, try to reduce the text for label / message. 42 - + Error encoding URI into QR Code. 49 - + QR code support not available. 90 - + Save QR Code 120 - + PNG Image 123 Expanded name of the PNG file format. See: https://en.wikipedia.org/wiki/Portable_Network_Graphics. @@ -2412,7 +2470,7 @@ If you are receiving this error you should request the merchant provide a BIP21 - + N/A 75 101 @@ -2428,316 +2486,334 @@ If you are receiving this error you should request the merchant provide a BIP21 1051 1077 1103 - 1126 - 1149 - 1172 + 1129 + 1155 + 1178 1201 - 1227 - 1250 - 1273 - 1296 - 1319 - 1345 + 1224 + 1253 + 1279 + 1302 + 1325 + 1348 1371 - 1394 - 1417 - 1440 - 1463 - 1486 - 1512 - 1535 - 1558 - 1584 + 1397 + 1423 + 1446 + 1469 + 1492 + 1515 + 1538 + 1564 + 1587 1610 1636 1662 + 1688 + 1714 ../rpcconsole.h147 - + Client version 65 - + &Information 43 - + General 58 - + Datadir 114 - + To specify a non-default location of the data directory use the '%1' option. 124 - + Blocksdir 143 - + To specify a non-default location of the blocks directory use the '%1' option. 153 - + Startup time 172 - + Network 201 - 1093 + 1145 - + Name 208 - + Number of connections 231 - + Block chain 260 - + Memory Pool 319 - + Current number of transactions 326 - + Memory usage 349 - + Wallet: 443 - + (none) 454 - + &Reset 665 - + Received 745 - 1453 + 1505 - + Sent 825 - 1430 + 1482 - + &Peers 866 - + Banned peers 942 - + Select a peer to view detailed information. 1010 - ../rpcconsole.cpp1161 + ../rpcconsole.cpp1171 - - Version + + The transport layer version: %1 + 1090 + + + Transport + 1093 + + + The BIP324 session ID string in hex, if any. 1116 - + + Session ID + 1119 + + + Version + 1168 + + Whether we relay transactions to this peer. - 1188 + 1240 - + Transaction Relay - 1191 + 1243 - + Starting Block - 1240 + 1292 - + Synced Headers - 1263 + 1315 - + Synced Blocks - 1286 + 1338 - + Last Transaction - 1361 + 1413 - + The mapped Autonomous System used for diversifying peer selection. - 1571 + 1623 - + Mapped AS - 1574 + 1626 - + Whether we relay addresses to this peer. - 1597 + 1649 Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No). - + Address Relay - 1600 + 1652 Text title for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No). - + The total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting). - 1623 + 1675 Tooltip text 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). - + The total number of addresses received from this peer that were dropped (not processed) due to rate-limiting. - 1649 + 1701 Tooltip text for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting. - + Addresses Processed - 1626 + 1678 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). - + Addresses Rate-Limited - 1652 + 1704 Text title for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting. - + User Agent 88 - 1139 + 1191 - + Node window 14 - + Current block height 267 - + Open the %1 debug log file from the current data directory. This can take a few seconds for large log files. 397 - + Decrease font size 475 - + Increase font size 495 - + Permissions 1041 - + The direction and type of peer connection: %1 1064 - + Direction/Type 1067 - + The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS. - 1090 + 1142 - + Services - 1162 + 1214 - + High bandwidth BIP152 compact block relay: %1 - 1214 + 1266 - + High Bandwidth - 1217 + 1269 - + Connection Time - 1309 + 1361 - + Elapsed time since a novel block passing initial validity checks was received from this peer. - 1332 + 1384 - + Last Block - 1335 + 1387 - + Elapsed time since a novel transaction accepted into our mempool was received from this peer. - 1358 + 1410 Tooltip text for the Last Transaction field in the peer details area. - + Last Send - 1384 + 1436 - + Last Receive - 1407 + 1459 - + Ping Time - 1476 + 1528 - + The duration of a currently outstanding ping. - 1499 + 1551 - + Ping Wait - 1502 + 1554 - + Min Ping - 1525 + 1577 - + Time Offset - 1548 + 1600 - + Last block time 290 - + &Open 400 - + &Console 426 - + &Network Traffic 613 - + Totals 681 - + Debug log file 390 - + Clear console 515 @@ -2745,139 +2821,154 @@ If you are receiving this error you should request the merchant provide a BIP21 - + In: - 958 + 968 - + Out: - 959 + 969 - + Inbound: initiated by peer - 495 + 496 Explanatory text for an inbound peer connection. - + Outbound Full Relay: default - 499 + 500 Explanatory text for an outbound peer connection that relays all network information. This is the default behavior for outbound connections. - + Outbound Block Relay: does not relay transactions or addresses - 502 + 503 Explanatory text for an outbound peer connection that relays network information about blocks and not transactions or addresses. - + Outbound Manual: added using RPC %1 or %2/%3 configuration options - 507 + 508 Explanatory text for an outbound peer connection that was established manually through one of several methods. The numbered arguments are stand-ins for the methods available to establish manual connections. - + Outbound Feeler: short-lived, for testing addresses - 513 + 514 Explanatory text for a short-lived outbound peer connection that is used to test the aliveness of known addresses. - + Outbound Address Fetch: short-lived, for soliciting addresses - 516 + 517 Explanatory text for a short-lived outbound peer connection that is used to request addresses from a peer. - + + detecting: peer could be v1 or v2 + 522 + Explanatory text for "detecting" transport type. + + + v1: unencrypted, plaintext transport protocol + 524 + Explanatory text for v1 transport type. + + + v2: BIP324 encrypted transport protocol + 526 + Explanatory text for v2 transport type. + + we selected the peer for high bandwidth relay - 520 + 530 - + the peer selected us for high bandwidth relay - 521 + 531 - + no high bandwidth relay selected - 522 + 532 - + Ctrl++ - 535 + 545 Main shortcut to increase the RPC console font size. - + Ctrl+= - 537 + 547 Secondary shortcut to increase the RPC console font size. - + Ctrl+- - 541 + 551 Main shortcut to decrease the RPC console font size. - + Ctrl+_ - 543 + 553 Secondary shortcut to decrease the RPC console font size. - + &Copy address - 694 + 704 Context menu action to copy the address of a peer. - + &Disconnect - 698 + 708 - + 1 &hour - 699 + 709 - + 1 d&ay - 700 + 710 - + 1 &week - 701 + 711 - + 1 &year - 702 + 712 - + &Copy IP/Netmask - 728 + 738 Context menu action to copy the IP/Netmask of a banned peer. IP/Netmask is the combination of a peer's IP address and its Netmask. For IP address, see: https://en.wikipedia.org/wiki/IP_address. - + &Unban - 732 + 742 - + Network activity disabled - 962 + 972 - + Executing command without any wallet - 1041 + 1051 - + Ctrl+I - 1357 + 1376 - + Ctrl+T - 1358 + 1377 - + Ctrl+N - 1359 + 1378 - + Ctrl+P - 1360 + 1379 - + Executing command using "%1" wallet - 1039 + 1049 - + Welcome to the %1 RPC console. Use up and down arrows to navigate history, and %2 to clear screen. Use %3 and %4 to increase or decrease the font size. @@ -2885,51 +2976,51 @@ Type %5 for an overview of available commands. For more information on using this console, type %6. %7WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramifications of a command.%8 - 892 + 902 RPC console welcome message. Placeholders %7 and %8 are style tags for the warning content, and they are not space separated from the rest of the text intentionally. - + Executing… - 1049 + 1059 A console message indicating an entered command is currently being executed. - + (peer: %1) - 1167 + 1177 - + via %1 - 1169 + 1179 - + Yes 146 - + No 146 - + To 146 - + From 146 - + Ban for 147 - + Never 189 - + Unknown 147 @@ -2937,72 +3028,72 @@ For more information on using this console, type %6. - + &Amount: 37 - + &Label: 83 - + &Message: 53 - + An optional message to attach to the payment request, which will be displayed when the request is opened. Note: The message will not be sent with the payment over the Bitcoin network. 50 - + An optional label to associate with the new receiving address. 80 - + Use this form to request payments. All fields are <b>optional</b>. 73 - + An optional amount to request. Leave this empty or zero to not request a specific amount. 34 193 - + An optional label to associate with the new receiving address (used by you to identify an invoice). It is also attached to the payment request. 66 - + An optional message that is attached to the payment request and may be displayed to the sender. 96 - + &Create new receiving address 111 - + Clear all fields of the form. 134 - + Clear 137 - + Requested payments history 273 - + Show the selected request (does the same as double clicking an entry) 298 - + Show 301 - + Remove the selected entries from the list 318 - + Remove 321 @@ -3010,63 +3101,63 @@ For more information on using this console, type %6. - + Copy &URI 46 - + &Copy address 47 - + Copy &label 48 - + Copy &message 49 - + Copy &amount 50 - + Base58 (Legacy) 96 - + Not recommended due to higher fees and less protection against typos. 96 - + Base58 (P2SH-SegWit) 97 - + Generates an address compatible with older wallets. 97 - + Bech32 (SegWit) 98 - + Generates a native segwit address (BIP-173). Some old wallets don't support it. 98 - + Bech32m (Taproot) 100 - + Bech32m (BIP-350) is an upgrade to Bech32, wallet support is still limited. 100 - + Could not unlock wallet. 175 - + Could not generate new %1 address 180 @@ -3074,51 +3165,51 @@ For more information on using this console, type %6. - + Request payment to … 14 - + Address: 90 - + Amount: 119 - + Label: 148 - + Message: 180 - + Wallet: 212 - + Copy &URI 240 - + Copy &Address 250 - + &Verify 260 - + Verify this address on e.g. a hardware wallet screen 263 - + &Save Image… 273 - + Payment information 39 @@ -3126,7 +3217,7 @@ For more information on using this console, type %6. - + Request payment to %1 48 @@ -3134,31 +3225,31 @@ For more information on using this console, type %6. - + Date 32 - + Label 32 - + Message 32 - + (no label) 70 - + (no message) 79 - + (no amount requested) 87 - + Requested 130 @@ -3166,150 +3257,150 @@ For more information on using this console, type %6. - + Send Coins 14 ../sendcoinsdialog.cpp762 - + Coin Control Features 90 - + automatically selected 120 - + Insufficient funds! 139 - + Quantity: 231 - + Bytes: 266 - + Amount: 314 - + Fee: 365 - + After Fee: 419 - + Change: 451 - + If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address. 495 - + Custom change address 498 - + Transaction Fee: 704 - + Using the fallbackfee can result in sending a transaction that will take several hours or days (or never) to confirm. Consider choosing your fee manually or wait until you have validated the complete chain. 742 - + Warning: Fee estimation is currently not possible. 751 - + per kilobyte 833 - + Hide 780 - + Recommended: 892 - + Custom: 922 - + Send to multiple recipients at once 1137 - + Add &Recipient 1140 - + Clear all fields of the form. 1120 - + Inputs… 110 - + Choose… 718 - + Hide transaction fee settings 777 - + Specify a custom fee per kB (1,000 bytes) of the transaction's virtual size. Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satoshis per kvB" for a transaction size of 500 virtual bytes (half of 1 kvB) would ultimately yield a fee of only 50 satoshis. 828 - + When there is less transaction volume than space in the blocks, miners as well as relaying nodes may enforce a minimum fee. Paying only this minimum fee is just fine, but be aware that this can result in a never confirming transaction once there is more demand for bitcoin transactions than the network can process. 863 - + A too low fee might result in a never confirming transaction (read the tooltip) 866 - + (Smart fee not initialized yet. This usually takes a few blocks…) 971 - + Confirmation time target: 997 - + Enable Replace-By-Fee 1055 - + With Replace-By-Fee (BIP-125) you can increase a transaction's fee after it is sent. Without this, a higher fee may be recommended to compensate for increased transaction delay risk. 1058 - + Clear &All 1123 - + Balance: 1178 - + Confirm the send action 1094 - + S&end 1097 @@ -3317,231 +3408,231 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 - + Copy quantity 95 - + Copy amount 96 - + Copy fee 97 - + Copy after fee 98 - + Copy bytes 99 - + Copy change 100 - + %1 (%2 blocks) 172 - + Sign on device 202 "device" usually means a hardware wallet. - + Connect your hardware wallet first. 205 - + Set external signer script path in Options -> Wallet 209 "External signer" means using devices such as hardware wallets. - + Cr&eate Unsigned 212 - + Creates a Partially Signed Bitcoin Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. 213 - + from wallet '%1' 305 - + %1 to '%2' 316 - + %1 to %2 321 - + To review recipient list click "Show Details…" 388 - + Sign failed 450 - + External signer not found 455 "External signer" means using devices such as hardware wallets. - + External signer failure 461 "External signer" means using devices such as hardware wallets. - + Save Transaction Data 425 - + Partially Signed Transaction (Binary) 427 Expanded name of the binary PSBT file format. See: BIP 174. - + PSBT saved 435 Popup message when a PSBT has been saved to a file - + External balance: 708 - + or 384 - + You can increase the fee later (signals Replace-By-Fee, BIP-125). 366 - + Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet. 335 Text to inform a user attempting to create a transaction of their current options. At this stage, a user can only create a PSBT. This string is displayed when private keys are disabled and an external signer is not available. - + Do you want to create this transaction? 329 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. - + Please, review your transaction. You can create and send this transaction or create a Partially Signed Bitcoin Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet. 340 Text to inform a user attempting to create a transaction of their current options. At this stage, a user can send their transaction or create a PSBT. This string is displayed when both private keys and PSBT controls are enabled. - + Please, review your transaction. 343 Text to prompt a user to review the details of the transaction they are attempting to send. - + Transaction fee 351 - + %1 kvB 356 PSBT transaction creation When reviewing a newly created PSBT (via Send flow), the transaction fee is shown, with "virtual size" of the transaction displayed for context - + Not signalling Replace-By-Fee, BIP-125. 368 - + Total Amount 381 - + Unsigned Transaction 405 PSBT copied Caption of "PSBT has been copied" messagebox - + The PSBT has been copied to the clipboard. You can also save it. 406 - + PSBT saved to disk 435 - + Confirm send coins 484 - + Watch-only balance: 711 - + The recipient address is not valid. Please recheck. 735 - + The amount to pay must be larger than 0. 738 - + The amount exceeds your balance. 741 - + The total exceeds your balance when the %1 transaction fee is included. 744 - + Duplicate address found: addresses should only be used once each. 747 - + Transaction creation failed! 750 - + A fee higher than %1 is considered an absurdly high fee. 754 - + %1/kvB 833 868 882 - + Estimated to begin confirmation within %n block(s). - + Estimated to begin confirmation within %n block(s). - + Warning: Invalid Bitcoin address 977 - + Warning: Unknown change address 982 - + Confirm custom change address 985 - + The address you selected for change is not part of this wallet. Any or all funds in your wallet may be sent to this address. Are you sure? 985 - + (no label) 1006 @@ -3549,68 +3640,68 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 - + A&mount: 151 - + Pay &To: 35 - + &Label: 128 - + Choose previously used address 60 - + The Bitcoin address to send the payment to 53 - + Alt+A 76 - + Paste address from clipboard 83 - + Alt+P 99 - + Remove this entry 106 - + The amount to send in the selected unit 166 - + The fee will be deducted from the amount being sent. The recipient will receive less bitcoins than you enter in the amount field. If multiple recipients are selected, the fee is split equally. 173 - + S&ubtract fee from amount 176 - + Use available balance 183 - + Message: 192 - + Enter a label for this address to add it to the list of used addresses 141 144 - + A message that was attached to the bitcoin: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Bitcoin network. 202 @@ -3618,11 +3709,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 - + Send 146 - + Create Unsigned 148 @@ -3630,105 +3721,105 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 - + Signatures - Sign / Verify a Message 14 - + &Sign Message 27 - + You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. 33 - + The Bitcoin address to sign the message with 51 - + Choose previously used address 58 274 - + Alt+A 68 284 - + Paste address from clipboard 78 - + Alt+P 88 - + Enter the message you want to sign here 100 103 - + Signature 110 - + Copy the current signature to the system clipboard 140 - + Sign the message to prove you own this Bitcoin address 161 - + Sign &Message 164 - + Reset all sign message fields 178 - + Clear &All 181 338 - + &Verify Message 240 - + Enter the receiver's address, message (ensure you copy line breaks, spaces, tabs, etc. exactly) and signature below to verify the message. Be careful not to read more into the signature than what is in the signed message itself, to avoid being tricked by a man-in-the-middle attack. Note that this only proves the signing party receives with the address, it cannot prove sendership of any transaction! 246 - + The Bitcoin address the message was signed with 267 - + The signed message to verify 296 299 - + The signature given when the message was signed 306 309 - + Verify the message to ensure it was signed with the specified Bitcoin address 318 - + Verify &Message 321 - + Reset all verify message fields 335 - + Click "Sign Message" to generate signature 125 @@ -3736,61 +3827,61 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 - + The entered address is invalid. 119 218 - + Please check the address and try again. 119 126 219 226 - + The entered address does not refer to a key. 126 225 - + Wallet unlock was cancelled. 134 - + No error 145 - + Private key for the entered address is not available. 148 - + Message signing failed. 151 - + Message signed. 163 - + The signature could not be decoded. 232 - + Please check the signature and try again. 233 240 - + The signature did not match the message digest. 239 - + Message verification failed. 245 - + Message verified. 213 @@ -3798,11 +3889,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 - + (press q to shutdown and continue later) 177 - + press q to shutdown 178 @@ -3810,7 +3901,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 - + kB/s 74 @@ -3818,84 +3909,84 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 - + conflicted with a transaction with %1 confirmations 44 Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction. - + 0/unconfirmed, in memory pool 51 Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is in the memory pool. - + 0/unconfirmed, not in memory pool 56 Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is not in the memory pool. - + abandoned 62 Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction. - + %1/unconfirmed 70 Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks. - + %1 confirmations 75 Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks. - + Status 125 - + Date 128 - + Source 135 - + Generated 135 - + From 140 154 226 - + unknown 154 - + To 155 175 245 - + own address 157 252 - + watch-only 157 226 254 - + label 159 - + Credit 195 207 @@ -3905,98 +3996,98 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 197 - + matures in %n more block(s) - + matures in %n more block(s) - + not accepted 199 - + Debit 259 285 348 - + Total debit 269 - + Total credit 270 - + Transaction fee 275 - + Net amount 297 - + Message 303 315 - + Comment 305 - + Transaction ID 307 - + Transaction total size 308 - + Transaction virtual size 309 - + Output index 310 - + (Certificate was not verified) 326 - + Merchant 329 - + Generated coins must mature %1 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to "not accepted" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours. 337 - + Debug information 345 - + Transaction 353 - + Inputs 356 - + Amount 377 - + true 378 379 - + false 378 379 @@ -4005,7 +4096,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 - + This pane shows a detailed description of the transaction 20 @@ -4013,7 +4104,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 - + Details for %1 18 @@ -4021,306 +4112,298 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 - + Date - 257 + 258 - + Type - 257 + 258 - + Label - 257 + 258 - + Unconfirmed - 317 + 318 - + Abandoned - 320 + 321 - + Confirming (%1 of %2 recommended confirmations) - 323 + 324 - + Confirmed (%1 confirmations) - 326 + 327 - + Conflicted - 329 + 330 - + Immature (%1 confirmations, will be available after %2) - 332 + 333 - + Generated but not accepted - 335 + 336 - + Received with - 374 + 375 - + Received from - 376 + 377 - + Sent to - 379 - - - Payment to yourself - 381 + 380 - + Mined - 383 + 382 - + watch-only - 411 + 410 - + (n/a) - 427 + 424 - + (no label) - 634 + 629 - + Transaction status. Hover over this field to show number of confirmations. - 673 + 668 - + Date and time that the transaction was received. - 675 + 670 - + Type of transaction. - 677 + 672 - + Whether or not a watch-only address is involved in this transaction. - 679 + 674 - + User-defined intent/purpose of the transaction. - 681 + 676 - + Amount removed from or added to balance. - 683 + 678 - + All 73 89 - + Today 74 - + This week 75 - + This month 76 - + Last month 77 - + This year 78 - + Received with 90 - + Sent to 92 - - To yourself - 94 - - + Mined - 95 + 94 - + Other - 96 + 95 - + Enter address, transaction id, or label to search - 101 + 100 - + Min amount - 105 + 104 - + Range… 79 - + &Copy address - 169 + 168 - + Copy &label - 170 + 169 - + Copy &amount - 171 + 170 - + Copy transaction &ID - 172 + 171 - + Copy &raw transaction - 173 + 172 - + Copy full transaction &details - 174 + 173 - + &Show transaction details - 175 + 174 - + Increase transaction &fee - 177 + 176 - + A&bandon transaction - 180 + 179 - + &Edit address label - 181 + 180 - + Show in %1 - 240 + 239 Transactions table context menu action to show the selected transaction in a third-party block explorer. %1 is a stand-in argument for the URL of the explorer. - + Export Transaction History - 359 + 358 - + Comma separated file - 362 + 361 Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values. - + Confirmed - 371 + 370 - + Watch-only - 373 + 372 - + Date - 374 + 373 - + Type - 375 + 374 - + Label - 376 + 375 - + Address - 377 + 376 - + ID - 379 + 378 - + Exporting Failed - 382 + 381 - + There was an error trying to save the transaction history to %1. - 382 + 381 - + Exporting Successful - 386 + 385 - + The transaction history was successfully saved to %1. - 386 + 385 - + Range: - 556 + 555 - + to - 564 + 563 - + No wallet has been loaded. Go to File > Open Wallet to load a wallet. - OR - 45 - + Create a new wallet 50 - + Error 201 211 229 - + Unable to decode PSBT from clipboard (invalid base64) 201 - + Load Transaction Data 207 - + Partially Signed Transaction (*.psbt) 208 - + PSBT file must be smaller than 100 MiB 211 - + Unable to decode PSBT 229 @@ -4328,73 +4411,73 @@ Go to File > Open Wallet to load a wallet. - + Send Coins 228 241 - + Fee bump error 488 543 558 563 - + Increasing transaction fee failed 488 - + Do you want to increase the fee? 495 Asks a user if they would like to manually increase the fee of a transaction that has already been created. - + Current fee: 499 - + Increase: 503 - + New fee: 507 - + Warning: This may pay the additional fee by reducing change outputs or adding inputs, when necessary. It may add a new change output if one does not already exist. These changes may potentially leak privacy. 515 - + Confirm fee bump 520 - + Can't draft transaction. 543 - + PSBT copied 550 - + Copied to clipboard 550 Fee-bump PSBT saved - + Can't sign transaction. 558 - + Could not commit transaction 563 - + Can't display address 577 - + default wallet 595 @@ -4402,40 +4485,40 @@ Go to File > Open Wallet to load a wallet. - + &Export 50 - + Export the data in the current tab to a file 51 - + Backup Wallet 214 - + Wallet Data 216 Name of the wallet data file format. - + Backup Failed 222 - + There was an error trying to save the wallet data to %1. 222 - + Backup Successful 226 - + The wallet data was successfully saved to %1. 226 - + Cancel 263 @@ -4443,874 +4526,870 @@ Go to File > Open Wallet to load a wallet. - + The %s developers 12 - + %s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup. 13 - + %s failed to validate the -assumeutxo snapshot state. This indicates a hardware problem, or a bug in the software, or a bad software modification that allowed an invalid snapshot to be loaded. As a result of this, the node will shut down and stop using any state that was built on the snapshot, resetting the chain height from %d to %d. On the next restart, the node will resume syncing from %d without using any snapshot data. Please report this incident to %s, including how you obtained the snapshot. The invalid snapshot chainstate will be left on disk in case it is helpful in diagnosing the issue that caused this error. 16 - + %s request to listen on port %u. This port is considered "bad" and thus it is unlikely that any peer will connect to it. See doc/p2p-bad-ports.md for details and a full list. 28 - + Cannot downgrade wallet from version %i to version %i. Wallet version unchanged. 32 - + Cannot obtain a lock on data directory %s. %s is probably already running. 35 - + Cannot upgrade a non HD split wallet from version %i to version %i without upgrading to support pre-split keypool. Please use version %i or no version specified. 40 - + Disk space for %s may not accommodate the block files. Approximately %u GB of data will be stored in this directory. 44 - + Distributed under the MIT software license, see the accompanying file %s or %s 47 - + Error loading wallet. Wallet requires blocks to be downloaded, and software does not currently support loading wallets while blocks are being downloaded out of order when using assumeutxo snapshots. Wallet should be able to load successfully after node sync reaches height %s 53 - + Error reading %s! Transaction data may be missing or incorrect. Rescanning wallet. 61 - + Error: Dumpfile format record is incorrect. Got "%s", expected "format". 67 - + Error: Dumpfile identifier record is incorrect. Got "%s", expected "%s". 69 - + Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version %s 71 - + Error: Legacy wallets only support the "legacy", "p2sh-segwit", and "bech32" address types 77 - + Error: Unable to produce descriptors for this legacy wallet. Make sure to provide the wallet's passphrase if it is encrypted. 83 - + File %s already exists. If you are sure this is what you want, move it out of the way first. - 92 + 95 - + Invalid or corrupt peers.dat (%s). If you believe this is a bug, please report it to %s. As a workaround, you can move the file (%s) out of the way (rename, move, or delete) to have a new one created on the next start. - 101 + 104 - + More than one onion bind address is provided. Using %s for the automatically created Tor onion service. - 105 + 108 - + No dump file provided. To use createfromdump, -dumpfile=<filename> must be provided. - 108 + 111 - + No dump file provided. To use dump, -dumpfile=<filename> must be provided. - 111 + 114 - + No wallet file format provided. To use createfromdump, -format=<format> must be provided. - 113 + 116 - + Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly. - 129 + 132 - + Please contribute if you find %s useful. Visit %s for further information about the software. - 132 + 135 - + Prune configured below the minimum of %d MiB. Please use a higher number. - 135 + 138 - + Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead. - 137 + 140 - + Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node) - 140 + 143 - + Rename of '%s' -> '%s' failed. You should resolve this by manually moving or deleting the invalid snapshot directory %s, otherwise you will encounter the same error again on the next startup. - 143 + 146 - + SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported - 147 + 150 - + The block database contains a block which appears to be from the future. This may be due to your computer's date and time being set incorrectly. Only rebuild the block database if you are sure that your computer's date and time are correct 153 - - The block index db contains a legacy 'txindex'. To clear the occupied disk space, run a full -reindex, otherwise ignore this error. This error message will not be displayed again. - 158 - - + The transaction amount is too small to send after the fee has been deducted - 169 + 165 - + This error could occur if this wallet was not shutdown cleanly and was last loaded using a build with a newer version of Berkeley DB. If so, please use the software that last loaded this wallet - 171 + 167 - + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications - 175 + 171 - + This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection. - 178 + 174 - + This is the transaction fee you may discard if change is smaller than dust at this level - 181 + 177 - + This is the transaction fee you may pay when fee estimates are not available. - 184 + 180 - + Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments. - 186 + 182 - + Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate. - 195 + 191 - + Unknown wallet file format "%s" provided. Please provide one of "bdb" or "sqlite". - 205 + 201 - + Unsupported category-specific logging level %1$s=%2$s. Expected %1$s=<category>:<loglevel>. Valid categories: %3$s. Valid loglevels: %4$s. - 213 + 209 - + Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database. - 216 + 212 - + Wallet created successfully. The legacy wallet type is being deprecated and support for creating and opening legacy wallets will be removed in the future. - 219 + 215 - + Wallet loaded successfully. The legacy wallet type is being deprecated and support for creating and opening legacy wallets will be removed in the future. Legacy wallets can be migrated to a descriptor wallet with migratewallet. - 223 + 219 - + Warning: Dumpfile wallet format "%s" does not match command line specified format "%s". - 228 + 224 - + Warning: Private keys detected in wallet {%s} with disabled private keys - 231 + 227 - + Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade. - 233 + 229 - + Witness data for blocks after height %d requires validation. Please restart with -reindex. - 236 + 232 - + You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain - 239 + 235 - + %s is set very high! - 248 + 244 - + -maxmempool must be at least %d MB - 249 + 245 - + A fatal internal error occurred, see debug.log for details - 250 + 246 - + Cannot resolve -%s address: '%s' - 252 + 248 - + Cannot set -forcednsseed to true when setting -dnsseed to false. - 253 + 249 - + Cannot set -peerblockfilters without -blockfilterindex. - 254 + 250 - + Cannot write to data directory '%s'; check permissions. - 255 - - - The -txindex upgrade started by a previous version cannot be completed. Restart with the previous version or run a full -reindex. - 150 + 251 - + %s is set very high! Fees this large could be paid on a single transaction. 26 - + Cannot provide specific connections and have addrman find outgoing connections at the same time. 37 - + Error loading %s: External signer wallet being loaded without external signer support compiled 50 - + Error reading %s! All keys read correctly, but transaction data or address metadata may be missing or incorrect. 58 - + Error: Address book data in wallet cannot be identified to belong to migrated wallets 64 - + Error: Duplicate descriptors created during migration. Your wallet may be corrupted. 74 - + Error: Transaction %s in wallet cannot be identified to belong to migrated wallets 80 - - Failed to rename invalid peers.dat file. Please move or delete it and try again. + + Failed to calculate bump fees, because unconfirmed UTXOs depend on enormous cluster of unconfirmed transactions. 86 - - Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable %s. + + Failed to rename invalid peers.dat file. Please move or delete it and try again. 89 - + + Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable %s. + 92 + + Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6 - 95 + 98 - + Invalid amount for %s=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) - 98 + 101 - + Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided - 116 + 119 - + Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is explicitly forbidden: -onion=0 - 119 + 122 - + Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is not provided: none of -proxy, -onion or -listenonion is given - 122 + 125 - + Outbound connections restricted to i2p (-onlynet=i2p) but -i2psam is not provided - 126 + 129 - + The inputs size exceeds the maximum weight. Please try sending a smaller amount or manually consolidating your wallet's UTXOs - 162 + 158 - + The preselected coins total amount does not cover the transaction target. Please allow other inputs to be automatically selected or include more coins manually - 165 + 161 - + Transaction requires one destination of non-0 value, a non-0 feerate, or a pre-selected input - 189 + 185 - + UTXO snapshot failed to validate. Restart to resume normal initial block download, or try loading a different snapshot. - 192 + 188 - + Unconfirmed UTXOs are available, but spending them creates a chain of transactions that will be rejected by the mempool - 198 + 194 - + Unexpected legacy entry in descriptor wallet found. Loading wallet %s The wallet might have been tampered with or created with malicious intent. - 201 + 197 - + Unrecognized descriptor found. Loading wallet %s The wallet might had been created on a newer version. Please try running the latest software version. - 208 + 204 - + Unable to cleanup failed migration - 242 + 238 - + Unable to restore backup of wallet. - 245 + 241 - + Block verification was interrupted - 251 + 247 - + Config setting for %s only applied on %s network when in [%s] section. - 256 + 252 - + Copyright (C) %i-%i - 257 + 253 - + Corrupted block database detected - 258 + 254 - + Could not find asmap file %s - 259 + 255 - + Could not parse asmap file %s - 260 + 256 - + Disk space is too low! - 261 + 257 - + Do you want to rebuild the block database now? - 262 + 258 - + Done loading - 263 + 259 - + Dump file %s does not exist. - 264 + 260 - + Error creating %s - 265 + 261 - + Error initializing block database - 266 + 262 - + Error initializing wallet database environment %s! - 267 + 263 - + Error loading %s - 268 + 264 - + Error loading %s: Private keys can only be disabled during creation - 269 + 265 - + Error loading %s: Wallet corrupted - 270 + 266 - + Error loading %s: Wallet requires newer version of %s - 271 + 267 - + Error loading block database - 272 + 268 - + Error opening block database - 273 + 269 - + Error reading configuration file: %s - 274 + 270 - + Error reading from database, shutting down. - 275 + 271 - + Error reading next record from wallet database - 276 + 272 - + Error: Cannot extract destination from the generated scriptpubkey - 277 + 273 - + Error: Could not add watchonly tx to watchonly wallet - 278 + 274 - + Error: Could not delete watchonly transactions - 279 + 275 - + Error: Couldn't create cursor into database - 280 + 276 - + Error: Disk space is low for %s - 281 + 277 - + Error: Dumpfile checksum does not match. Computed %s, expected %s - 282 + 278 - + Error: Failed to create new watchonly wallet - 283 + 279 - + Error: Got key that was not hex: %s - 284 + 280 - + Error: Got value that was not hex: %s - 285 + 281 - + Error: Keypool ran out, please call keypoolrefill first - 286 + 282 - + Error: Missing checksum - 287 + 283 - + Error: No %s addresses available. - 288 + 284 - + Error: Not all watchonly txs could be deleted - 289 + 285 - + Error: This wallet already uses SQLite - 290 + 286 - + Error: This wallet is already a descriptor wallet - 291 + 287 - + Error: Unable to begin reading all records in the database - 292 + 288 - + Error: Unable to make a backup of your wallet - 293 + 289 - + Error: Unable to parse version %u as a uint32_t - 294 + 290 - + Error: Unable to read all records in the database - 295 + 291 - + Error: Unable to remove watchonly address book data - 296 + 292 - + Error: Unable to write record to new wallet - 297 + 293 - + Failed to listen on any port. Use -listen=0 if you want this. - 298 + 294 - + Failed to rescan the wallet during initialization - 299 + 295 - + Failed to start indexes, shutting down.. - 300 + 296 - + Failed to verify database - 301 + 297 - + Fee rate (%s) is lower than the minimum fee rate setting (%s) - 302 + 298 - + Ignoring duplicate -wallet %s. - 303 + 299 - + Importing… - 304 + 300 - + Incorrect or no genesis block found. Wrong datadir for network? - 305 + 301 - + Initialization sanity check failed. %s is shutting down. - 306 + 302 - + Input not found or already spent - 307 + 303 - + Insufficient dbcache for block verification - 308 + 304 - + Insufficient funds - 309 + 305 - + Invalid -i2psam address or hostname: '%s' - 310 + 306 - + Invalid -onion address or hostname: '%s' - 311 + 307 - + Invalid -proxy address or hostname: '%s' - 312 + 308 - + Invalid P2P permission: '%s' - 313 + 309 - + Invalid amount for %s=<amount>: '%s' (must be at least %s) - 314 + 310 - + Invalid amount for %s=<amount>: '%s' - 315 + 311 - + Invalid amount for -%s=<amount>: '%s' - 316 + 312 - + Invalid netmask specified in -whitelist: '%s' - 317 + 313 - + Invalid port specified in %s: '%s' - 318 + 314 - + Invalid pre-selected input %s - 319 + 315 - + Listening for incoming connections failed (listen returned error %s) - 320 + 316 - + Loading P2P addresses… - 321 + 317 - + Loading banlist… - 322 + 318 - + Loading block index… - 323 + 319 - + Loading wallet… - 324 + 320 - + Missing amount - 325 + 321 - + Missing solving data for estimating transaction size - 326 + 322 - + Need to specify a port with -whitebind: '%s' - 327 + 323 - + No addresses available - 328 + 324 - + Not enough file descriptors available. - 329 + 325 - + Not found pre-selected input %s - 330 + 326 - + Not solvable pre-selected input %s - 331 + 327 - + Prune cannot be configured with a negative value. - 332 + 328 - + Prune mode is incompatible with -txindex. - 333 + 329 - + Pruning blockstore… - 334 + 330 - + Reducing -maxconnections from %d to %d, because of system limitations. - 335 + 331 - + Replaying blocks… - 336 + 332 - + Rescanning… - 337 + 333 - + SQLiteDatabase: Failed to execute statement to verify database: %s - 338 + 334 - + SQLiteDatabase: Failed to prepare statement to verify database: %s - 339 + 335 - + SQLiteDatabase: Failed to read database verification error: %s - 340 + 336 - + SQLiteDatabase: Unexpected application id. Expected %u, got %u - 341 + 337 - + Section [%s] is not recognized. - 342 + 338 - + Signing transaction failed - 345 + 341 - + Specified -walletdir "%s" does not exist - 346 + 342 - + Specified -walletdir "%s" is a relative path - 347 + 343 - + Specified -walletdir "%s" is not a directory - 348 + 344 - + Specified blocks directory "%s" does not exist. - 349 + 345 - + Specified data directory "%s" does not exist. - 350 + 346 - + Starting network threads… - 351 + 347 - + The source code is available from %s. - 352 + 348 - + The specified config file %s does not exist - 353 + 349 - + The transaction amount is too small to pay the fee - 354 + 350 - + The wallet will avoid paying less than the minimum relay fee. - 355 + 351 - + This is experimental software. - 356 + 352 - + This is the minimum transaction fee you pay on every transaction. - 357 + 353 - + This is the transaction fee you will pay if you send a transaction. - 358 + 354 - + Transaction amount too small - 359 + 355 - + Transaction amounts must not be negative - 360 + 356 - + Transaction change output index out of range - 361 + 357 - + Transaction has too long of a mempool chain - 362 + 358 - + Transaction must have at least one recipient - 363 + 359 - + Transaction needs a change address, but we can't generate it. - 364 + 360 - + Transaction too large - 365 + 361 - + Unable to allocate memory for -maxsigcachesize: '%s' MiB - 366 + 362 - + Unable to bind to %s on this computer (bind returned error %s) - 367 + 363 - + Unable to bind to %s on this computer. %s is probably already running. - 368 + 364 - + Unable to create the PID file '%s': %s - 369 + 365 - + Unable to find UTXO for external input - 370 + 366 - + Unable to generate initial keys - 371 + 367 - + Unable to generate keys - 372 + 368 - + Unable to open %s for writing - 373 + 369 - + Unable to parse -maxuploadtarget: '%s' - 374 + 370 - + Unable to start HTTP server. See debug log for details. - 375 + 371 - + Unable to unload the wallet before migrating - 376 + 372 - + Unknown -blockfilterindex value %s. - 377 + 373 - + Unknown address type '%s' - 378 + 374 - + Unknown change type '%s' - 379 + 375 - + Unknown network specified in -onlynet: '%s' - 380 + 376 - + Unknown new rules activated (versionbit %i) - 381 + 377 - + Unsupported global logging level %s=%s. Valid values: %s. - 382 + 378 - + acceptstalefeeestimates is not supported on %s chain. - 388 + 384 - + Unsupported logging category %s=%s. - 383 + 379 - + User Agent comment (%s) contains unsafe characters. - 384 + 380 - + Verifying blocks… - 385 + 381 - + Verifying wallet(s)… - 386 + 382 - + Wallet needed to be rewritten: restart %s to complete - 387 + 383 - + Settings file could not be read - 343 + 339 - + Settings file could not be written - 344 + 340 From fac9abbf475a1de6f9f39ddede9a6a59bbd1cff4 Mon Sep 17 00:00:00 2001 From: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz> Date: Thu, 28 Sep 2023 11:05:28 +0200 Subject: [PATCH 13/41] ci: Rename 04_install to 02_run_container This reflects what the script does (docker run ...). --- ci/test/{04_install.sh => 02_run_container.sh} | 0 ci/test_run_all.sh | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) rename ci/test/{04_install.sh => 02_run_container.sh} (100%) diff --git a/ci/test/04_install.sh b/ci/test/02_run_container.sh similarity index 100% rename from ci/test/04_install.sh rename to ci/test/02_run_container.sh diff --git a/ci/test_run_all.sh b/ci/test_run_all.sh index 2284a2903b..efc524eb80 100755 --- a/ci/test_run_all.sh +++ b/ci/test_run_all.sh @@ -1,13 +1,13 @@ #!/usr/bin/env bash # -# Copyright (c) 2019-2020 The Bitcoin Core developers +# Copyright (c) 2019-present The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. export LC_ALL=C.UTF-8 set -o errexit; source ./ci/test/00_setup_env.sh -set -o errexit; source ./ci/test/04_install.sh +set -o errexit; source "./ci/test/02_run_container.sh" set -o errexit CI_EXEC "${BASE_ROOT_DIR}/ci/test/06_script_b.sh" From fa09a031c1eb8abcb9a04cacdf5629f95ffc77f8 Mon Sep 17 00:00:00 2001 From: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz> Date: Wed, 4 Oct 2023 17:04:40 +0200 Subject: [PATCH 14/41] ci: Add set -ex to 02_run_container.sh The same is done by the 06 script. --- ci/test/02_run_container.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ci/test/02_run_container.sh b/ci/test/02_run_container.sh index b5a84ae08d..8602353b45 100755 --- a/ci/test/02_run_container.sh +++ b/ci/test/02_run_container.sh @@ -6,6 +6,8 @@ export LC_ALL=C.UTF-8 +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. From fa695b4df069425414fd26b2ddc08d72a6b506f6 Mon Sep 17 00:00:00 2001 From: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz> Date: Thu, 28 Sep 2023 11:18:31 +0200 Subject: [PATCH 15/41] ci: Work around podman stop bug Force remove any containers, pontentially leaving dangling processes, which should be fine. --- ci/test/02_run_container.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ci/test/02_run_container.sh b/ci/test/02_run_container.sh index 8602353b45..96fae73359 100755 --- a/ci/test/02_run_container.sh +++ b/ci/test/02_run_container.sh @@ -29,14 +29,12 @@ if [ -z "$DANGER_RUN_CI_ON_HOST" ]; then if [ -n "${RESTART_CI_DOCKER_BEFORE_RUN}" ] ; then echo "Restart docker before run to stop and clear all containers started with --rm" - podman container stop --all # Similar to "systemctl restart docker" + podman container rm --force --all # Similar to "systemctl restart docker" echo "Prune all dangling images" docker image prune --force fi # 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" \ --mount "type=volume,src=${CONTAINER_NAME}_ccache,dst=$CCACHE_DIR" \ From fa2c894cbb41a64371717139fb3c3ddfb9bb8b19 Mon Sep 17 00:00:00 2001 From: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz> Date: Thu, 28 Sep 2023 13:35:02 +0200 Subject: [PATCH 16/41] ci: move-only CI_CONTAINER_ID to 02_run_container.sh This limits the scope of the CI_CONTAINER_ID symbol. Can be reviewed with --color-moved=dimmed-zebra --- ci/test/02_run_container.sh | 7 +++++++ ci/test_run_all.sh | 8 +------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/ci/test/02_run_container.sh b/ci/test/02_run_container.sh index 96fae73359..a7c1e22a6d 100755 --- a/ci/test/02_run_container.sh +++ b/ci/test/02_run_container.sh @@ -68,3 +68,10 @@ CI_EXEC "${BASE_ROOT_DIR}/ci/test/01_base_install.sh" CI_EXEC git config --global --add safe.directory \"*\" CI_EXEC mkdir -p "${BINS_SCRATCH_DIR}" + +CI_EXEC "${BASE_ROOT_DIR}/ci/test/06_script_b.sh" + +if [ -z "$DANGER_RUN_CI_ON_HOST" ]; then + echo "Stop and remove CI container by ID" + docker container kill "${CI_CONTAINER_ID}" +fi diff --git a/ci/test_run_all.sh b/ci/test_run_all.sh index efc524eb80..3afc47b23e 100755 --- a/ci/test_run_all.sh +++ b/ci/test_run_all.sh @@ -7,11 +7,5 @@ export LC_ALL=C.UTF-8 set -o errexit; source ./ci/test/00_setup_env.sh -set -o errexit; source "./ci/test/02_run_container.sh" set -o errexit -CI_EXEC "${BASE_ROOT_DIR}/ci/test/06_script_b.sh" - -if [ -z "$DANGER_RUN_CI_ON_HOST" ]; then - echo "Stop and remove CI container by ID" - docker container kill "${CI_CONTAINER_ID}" -fi +"./ci/test/02_run_container.sh" From b7485f11ab3a0f1860b261f222362af3301e0781 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Thu, 5 Oct 2023 12:29:22 -0400 Subject: [PATCH 17/41] descriptors: Check result of InferPubkey InferPubkey can return a nullptr, so check it's result before continuing with creating the inferred descriptor. --- src/script/descriptor.cpp | 44 +++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp index ba2334df49..720541c67f 100644 --- a/src/script/descriptor.cpp +++ b/src/script/descriptor.cpp @@ -1491,13 +1491,17 @@ struct KeyParser { if (miniscript::IsTapscript(m_script_ctx) && end - begin == 32) { XOnlyPubKey pubkey; std::copy(begin, end, pubkey.begin()); - m_keys.push_back(InferPubkey(pubkey.GetEvenCorrespondingCPubKey(), ParseContext(), *m_in)); - return key; + if (auto pubkey_provider = InferPubkey(pubkey.GetEvenCorrespondingCPubKey(), ParseContext(), *m_in)) { + m_keys.push_back(std::move(pubkey_provider)); + return key; + } } else if (!miniscript::IsTapscript(m_script_ctx)) { - CPubKey pubkey{begin, end}; + CPubKey pubkey(begin, end); if (pubkey.IsValidNonHybrid()) { - m_keys.push_back(InferPubkey(pubkey, ParseContext(), *m_in)); - return key; + if (auto pubkey_provider = InferPubkey(pubkey, ParseContext(), *m_in)) { + m_keys.push_back(std::move(pubkey_provider)); + return key; + } } } return {}; @@ -1512,9 +1516,11 @@ struct KeyParser { CKeyID keyid(hash); CPubKey pubkey; if (m_in->GetPubKey(keyid, pubkey)) { - Key key = m_keys.size(); - m_keys.push_back(InferPubkey(pubkey, ParseContext(), *m_in)); - return key; + if (auto pubkey_provider = InferPubkey(pubkey, ParseContext(), *m_in)) { + Key key = m_keys.size(); + m_keys.push_back(std::move(pubkey_provider)); + return key; + } } return {}; } @@ -1850,7 +1856,9 @@ std::unique_ptr InferScript(const CScript& script, ParseScriptCo if (txntype == TxoutType::PUBKEY && (ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH || ctx == ParseScriptContext::P2WSH)) { CPubKey pubkey(data[0]); if (pubkey.IsValidNonHybrid()) { - return std::make_unique(InferPubkey(pubkey, ctx, provider)); + if (auto pubkey_provider = InferPubkey(pubkey, ctx, provider)) { + return std::make_unique(std::move(pubkey_provider)); + } } } if (txntype == TxoutType::PUBKEYHASH && (ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH || ctx == ParseScriptContext::P2WSH)) { @@ -1858,7 +1866,9 @@ std::unique_ptr InferScript(const CScript& script, ParseScriptCo CKeyID keyid(hash); CPubKey pubkey; if (provider.GetPubKey(keyid, pubkey)) { - return std::make_unique(InferPubkey(pubkey, ctx, provider)); + if (auto pubkey_provider = InferPubkey(pubkey, ctx, provider)) { + return std::make_unique(std::move(pubkey_provider)); + } } } if (txntype == TxoutType::WITNESS_V0_KEYHASH && (ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH)) { @@ -1866,16 +1876,24 @@ std::unique_ptr InferScript(const CScript& script, ParseScriptCo CKeyID keyid(hash); CPubKey pubkey; if (provider.GetPubKey(keyid, pubkey)) { - return std::make_unique(InferPubkey(pubkey, ctx, provider)); + if (auto pubkey_provider = InferPubkey(pubkey, ctx, provider)) { + return std::make_unique(std::move(pubkey_provider)); + } } } if (txntype == TxoutType::MULTISIG && (ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH || ctx == ParseScriptContext::P2WSH)) { + bool ok = true; std::vector> providers; for (size_t i = 1; i + 1 < data.size(); ++i) { CPubKey pubkey(data[i]); - providers.push_back(InferPubkey(pubkey, ctx, provider)); + if (auto pubkey_provider = InferPubkey(pubkey, ctx, provider)) { + providers.push_back(std::move(pubkey_provider)); + } else { + ok = false; + break; + } } - return std::make_unique((int)data[0][0], std::move(providers)); + if (ok) return std::make_unique((int)data[0][0], std::move(providers)); } if (txntype == TxoutType::SCRIPTHASH && ctx == ParseScriptContext::TOP) { uint160 hash(data[0]); From 37b9b734770e855b9beff3b5085125f1420dd072 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Thu, 5 Oct 2023 12:33:04 -0400 Subject: [PATCH 18/41] descriptors: Move InferScript's pubkey validity checks to InferPubkey --- src/script/descriptor.cpp | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp index 720541c67f..7e62d75583 100644 --- a/src/script/descriptor.cpp +++ b/src/script/descriptor.cpp @@ -1413,8 +1413,16 @@ std::unique_ptr ParsePubkey(uint32_t key_exp_index, const Span(key_exp_index, std::move(info), std::move(provider), apostrophe); } -std::unique_ptr InferPubkey(const CPubKey& pubkey, ParseScriptContext, const SigningProvider& provider) +std::unique_ptr InferPubkey(const CPubKey& pubkey, ParseScriptContext ctx, const SigningProvider& provider) { + // Key cannot be hybrid + if (!pubkey.IsValidNonHybrid()) { + return nullptr; + } + // Uncompressed is only allowed in TOP and P2SH contexts + if (ctx != ParseScriptContext::TOP && ctx != ParseScriptContext::P2SH && !pubkey.IsCompressed()) { + return nullptr; + } std::unique_ptr key_provider = std::make_unique(0, pubkey, false); KeyOriginInfo info; if (provider.GetKeyOrigin(pubkey.GetID(), info)) { @@ -1497,11 +1505,9 @@ struct KeyParser { } } else if (!miniscript::IsTapscript(m_script_ctx)) { CPubKey pubkey(begin, end); - if (pubkey.IsValidNonHybrid()) { - if (auto pubkey_provider = InferPubkey(pubkey, ParseContext(), *m_in)) { - m_keys.push_back(std::move(pubkey_provider)); - return key; - } + if (auto pubkey_provider = InferPubkey(pubkey, ParseContext(), *m_in)) { + m_keys.push_back(std::move(pubkey_provider)); + return key; } } return {}; @@ -1855,10 +1861,8 @@ std::unique_ptr InferScript(const CScript& script, ParseScriptCo if (txntype == TxoutType::PUBKEY && (ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH || ctx == ParseScriptContext::P2WSH)) { CPubKey pubkey(data[0]); - if (pubkey.IsValidNonHybrid()) { - if (auto pubkey_provider = InferPubkey(pubkey, ctx, provider)) { - return std::make_unique(std::move(pubkey_provider)); - } + if (auto pubkey_provider = InferPubkey(pubkey, ctx, provider)) { + return std::make_unique(std::move(pubkey_provider)); } } if (txntype == TxoutType::PUBKEYHASH && (ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH || ctx == ParseScriptContext::P2WSH)) { @@ -1876,7 +1880,7 @@ std::unique_ptr InferScript(const CScript& script, ParseScriptCo CKeyID keyid(hash); CPubKey pubkey; if (provider.GetPubKey(keyid, pubkey)) { - if (auto pubkey_provider = InferPubkey(pubkey, ctx, provider)) { + if (auto pubkey_provider = InferPubkey(pubkey, ParseScriptContext::P2WPKH, provider)) { return std::make_unique(std::move(pubkey_provider)); } } From f895f97014ac5fac46d27725c1ea7decf7ff76d4 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Thu, 5 Oct 2023 12:56:48 -0400 Subject: [PATCH 19/41] test: Scripts with hybrid pubkeys are migrated to watchonly Descriptors disallows hybrid pubkeys. Anything with hybrid pubkeys should becomes a raw() descriptor that shows up in the watchonly wallet. --- test/functional/wallet_migration.py | 60 ++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/test/functional/wallet_migration.py b/test/functional/wallet_migration.py index bcd71197bf..286dcb5fda 100755 --- a/test/functional/wallet_migration.py +++ b/test/functional/wallet_migration.py @@ -6,8 +6,13 @@ import random import shutil -from test_framework.address import script_to_p2sh +from test_framework.address import ( + script_to_p2sh, + key_to_p2pkh, + key_to_p2wpkh, +) from test_framework.descriptors import descsum_create +from test_framework.key import ECPubKey from test_framework.test_framework import BitcoinTestFramework from test_framework.messages import COIN, CTransaction, CTxOut from test_framework.script_util import key_to_p2pkh_script, script_to_p2sh_script, script_to_p2wsh_script @@ -770,6 +775,58 @@ def test_conflict_txs(self): wallet.unloadwallet() + def test_hybrid_pubkey(self): + self.log.info("Test migration when wallet contains a hybrid pubkey") + + wallet = self.create_legacy_wallet("hybrid_keys") + + # Get the hybrid pubkey for one of the keys in the wallet + normal_pubkey = wallet.getaddressinfo(wallet.getnewaddress())["pubkey"] + first_byte = bytes.fromhex(normal_pubkey)[0] + 4 # Get the hybrid pubkey first byte + parsed_pubkey = ECPubKey() + parsed_pubkey.set(bytes.fromhex(normal_pubkey)) + parsed_pubkey.compressed = False + hybrid_pubkey_bytes = bytearray(parsed_pubkey.get_bytes()) + hybrid_pubkey_bytes[0] = first_byte # Make it hybrid + hybrid_pubkey = hybrid_pubkey_bytes.hex() + + # Import the hybrid pubkey + wallet.importpubkey(hybrid_pubkey) + p2pkh_addr = key_to_p2pkh(hybrid_pubkey) + p2pkh_addr_info = wallet.getaddressinfo(p2pkh_addr) + assert_equal(p2pkh_addr_info["iswatchonly"], True) + assert_equal(p2pkh_addr_info["ismine"], False) # Things involving hybrid pubkeys are not spendable + + # Also import the p2wpkh for the pubkey to make sure we don't migrate it + p2wpkh_addr = key_to_p2wpkh(hybrid_pubkey) + wallet.importaddress(p2wpkh_addr) + + migrate_info = wallet.migratewallet() + + # Both addresses should only appear in the watchonly wallet + p2pkh_addr_info = wallet.getaddressinfo(p2pkh_addr) + assert_equal(p2pkh_addr_info["iswatchonly"], False) + assert_equal(p2pkh_addr_info["ismine"], False) + p2wpkh_addr_info = wallet.getaddressinfo(p2wpkh_addr) + assert_equal(p2wpkh_addr_info["iswatchonly"], False) + assert_equal(p2wpkh_addr_info["ismine"], False) + + watchonly_wallet = self.nodes[0].get_wallet_rpc(migrate_info["watchonly_name"]) + watchonly_p2pkh_addr_info = watchonly_wallet.getaddressinfo(p2pkh_addr) + assert_equal(watchonly_p2pkh_addr_info["iswatchonly"], False) + assert_equal(watchonly_p2pkh_addr_info["ismine"], True) + watchonly_p2wpkh_addr_info = watchonly_wallet.getaddressinfo(p2wpkh_addr) + assert_equal(watchonly_p2wpkh_addr_info["iswatchonly"], False) + assert_equal(watchonly_p2wpkh_addr_info["ismine"], True) + + # There should only be raw or addr descriptors + for desc in watchonly_wallet.listdescriptors()["descriptors"]: + if desc["desc"].startswith("raw(") or desc["desc"].startswith("addr("): + continue + assert False, "Hybrid pubkey watchonly wallet has more than just raw() and addr()" + + wallet.unloadwallet() + def run_test(self): self.generate(self.nodes[0], 101) @@ -787,6 +844,7 @@ def run_test(self): self.test_addressbook() self.test_migrate_raw_p2sh() self.test_conflict_txs() + self.test_hybrid_pubkey() if __name__ == '__main__': WalletMigrationTest().main() From 74c77825e5ab68bfa575dad86444506c43ef6c06 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Thu, 5 Oct 2023 13:54:21 -0400 Subject: [PATCH 20/41] test: Unit test for inferring scripts with hybrid and uncompressed keys --- src/test/descriptor_tests.cpp | 61 +++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/src/test/descriptor_tests.cpp b/src/test/descriptor_tests.cpp index 9b48c48ff8..f4f4e39f40 100644 --- a/src/test/descriptor_tests.cpp +++ b/src/test/descriptor_tests.cpp @@ -384,6 +384,54 @@ void Check(const std::string& prv, const std::string& pub, const std::string& no } } +void CheckInferDescriptor(const std::string& script_hex, const std::string& expected_desc, const std::vector& hex_scripts, const std::vector>& origin_pubkeys) +{ + std::vector script_bytes{ParseHex(script_hex)}; + const CScript& script{script_bytes.begin(), script_bytes.end()}; + + FlatSigningProvider provider; + for (const std::string& prov_script_hex : hex_scripts) { + std::vector prov_script_bytes{ParseHex(prov_script_hex)}; + const CScript& prov_script{prov_script_bytes.begin(), prov_script_bytes.end()}; + provider.scripts.emplace(CScriptID(prov_script), prov_script); + } + for (const auto& [pubkey_hex, origin_str] : origin_pubkeys) { + CPubKey origin_pubkey{ParseHex(pubkey_hex)}; + provider.pubkeys.emplace(origin_pubkey.GetID(), origin_pubkey); + + if (!origin_str.empty()) { + using namespace spanparsing; + KeyOriginInfo info; + Span origin_sp{origin_str}; + std::vector> origin_split = Split(origin_sp, "/"); + std::string fpr_str(origin_split[0].begin(), origin_split[0].end()); + auto fpr_bytes = ParseHex(fpr_str); + std::copy(fpr_bytes.begin(), fpr_bytes.end(), info.fingerprint); + for (size_t i = 1; i < origin_split.size(); ++i) { + Span elem = origin_split[i]; + bool hardened = false; + if (elem.size() > 0) { + const char last = elem[elem.size() - 1]; + if (last == '\'' || last == 'h') { + elem = elem.first(elem.size() - 1); + hardened = true; + } + } + uint32_t p; + assert(ParseUInt32(std::string(elem.begin(), elem.end()), &p)); + info.path.push_back(p | (((uint32_t)hardened) << 31)); + } + + provider.origins.emplace(origin_pubkey.GetID(), std::make_pair(origin_pubkey, info)); + } + } + + std::string checksum{GetDescriptorChecksum(expected_desc)}; + + std::unique_ptr desc = InferDescriptor(script, provider); + BOOST_CHECK_EQUAL(desc->ToString(), expected_desc + "#" + checksum); +} + } BOOST_FIXTURE_TEST_SUITE(descriptor_tests, BasicTestingSetup) @@ -594,6 +642,19 @@ BOOST_AUTO_TEST_CASE(descriptor_test) // preimages and the sequence, passes with.) Check("tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,{and_v(and_v(v:hash256(ae253ca2a54debcac7ecf414f6734f48c56421a08bb59182ff9f39a6fffdb588),v:pk(KykUPmR5967F4URzMUeCv9kNMU9CNRWycrPmx3ZvfkWoQLabbimL)),older(42)),multi_a(2,adf586a32ad4b0674a86022b000348b681b4c97a811f67eefe4a6e066e55080c,KztMyyi1pXUtuZfJSB7JzVdmJMAz7wfGVFoSRUR5CVZxXxULXuGR)})", "tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,{and_v(and_v(v:hash256(ae253ca2a54debcac7ecf414f6734f48c56421a08bb59182ff9f39a6fffdb588),v:pk(1c9bc926084382e76da33b5a52d17b1fa153c072aae5fb5228ecc2ccf89d79d5)),older(42)),multi_a(2,adf586a32ad4b0674a86022b000348b681b4c97a811f67eefe4a6e066e55080c,14fa4ad085cdee1e2fc73d491b36a96c192382b1d9a21108eb3533f630364f9f)})", "tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,{and_v(and_v(v:hash256(ae253ca2a54debcac7ecf414f6734f48c56421a08bb59182ff9f39a6fffdb588),v:pk(1c9bc926084382e76da33b5a52d17b1fa153c072aae5fb5228ecc2ccf89d79d5)),older(42)),multi_a(2,adf586a32ad4b0674a86022b000348b681b4c97a811f67eefe4a6e066e55080c,14fa4ad085cdee1e2fc73d491b36a96c192382b1d9a21108eb3533f630364f9f)})", MISSING_PRIVKEYS | XONLY_KEYS | SIGNABLE | SIGNABLE_FAILS, {{"51209a3d79db56fbe3ba4d905d827b62e1ed31cd6df1198b8c759d589c0f4efc27bd"}}, OutputType::BECH32M); Check("tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,{and_v(and_v(v:hash256(ae253ca2a54debcac7ecf414f6734f48c56421a08bb59182ff9f39a6fffdb588),v:pk(KykUPmR5967F4URzMUeCv9kNMU9CNRWycrPmx3ZvfkWoQLabbimL)),older(42)),multi_a(2,adf586a32ad4b0674a86022b000348b681b4c97a811f67eefe4a6e066e55080c,KztMyyi1pXUtuZfJSB7JzVdmJMAz7wfGVFoSRUR5CVZxXxULXuGR)})", "tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,{and_v(and_v(v:hash256(ae253ca2a54debcac7ecf414f6734f48c56421a08bb59182ff9f39a6fffdb588),v:pk(1c9bc926084382e76da33b5a52d17b1fa153c072aae5fb5228ecc2ccf89d79d5)),older(42)),multi_a(2,adf586a32ad4b0674a86022b000348b681b4c97a811f67eefe4a6e066e55080c,14fa4ad085cdee1e2fc73d491b36a96c192382b1d9a21108eb3533f630364f9f)})", "tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,{and_v(and_v(v:hash256(ae253ca2a54debcac7ecf414f6734f48c56421a08bb59182ff9f39a6fffdb588),v:pk(1c9bc926084382e76da33b5a52d17b1fa153c072aae5fb5228ecc2ccf89d79d5)),older(42)),multi_a(2,adf586a32ad4b0674a86022b000348b681b4c97a811f67eefe4a6e066e55080c,14fa4ad085cdee1e2fc73d491b36a96c192382b1d9a21108eb3533f630364f9f)})", MISSING_PRIVKEYS | XONLY_KEYS | SIGNABLE, {{"51209a3d79db56fbe3ba4d905d827b62e1ed31cd6df1198b8c759d589c0f4efc27bd"}}, OutputType::BECH32M, /*op_desc_id=*/{}, {{}}, /*spender_nlocktime=*/0, /*spender_nsequence=*/42, /*preimages=*/{{ParseHex("ae253ca2a54debcac7ecf414f6734f48c56421a08bb59182ff9f39a6fffdb588"), ParseHex("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f")}}); + + // Basic sh(pkh()) with key origin + CheckInferDescriptor("a9141a31ad23bf49c247dd531a623c2ef57da3c400c587", "sh(pkh([deadbeef/0h/0h/0]03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", {"76a9149a1c78a507689f6f54b847ad1cef1e614ee23f1e88ac"}, {{"03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd", "deadbeef/0h/0h/0"}}); + // p2pk script with hybrid key must infer as raw() + CheckInferDescriptor("41069228de6902abb4f541791f6d7f925b10e2078ccb1298856e5ea5cc5fd667f930eac37a00cc07f9a91ef3c2d17bf7a17db04552ff90ac312a5b8b4caca6c97aa4ac", "raw(41069228de6902abb4f541791f6d7f925b10e2078ccb1298856e5ea5cc5fd667f930eac37a00cc07f9a91ef3c2d17bf7a17db04552ff90ac312a5b8b4caca6c97aa4ac)", {}, {{"069228de6902abb4f541791f6d7f925b10e2078ccb1298856e5ea5cc5fd667f930eac37a00cc07f9a91ef3c2d17bf7a17db04552ff90ac312a5b8b4caca6c97aa4", ""}}); + // p2pkh script with hybrid key must infer as addr() + CheckInferDescriptor("76a91445ff7c2327866472639d507334a9a00119dfd32688ac", "addr(17P7ge56F2QcdHxxRBa2NyzmejFggPwBJ9)", {}, {{"069228de6902abb4f541791f6d7f925b10e2078ccb1298856e5ea5cc5fd667f930eac37a00cc07f9a91ef3c2d17bf7a17db04552ff90ac312a5b8b4caca6c97aa4", ""}}); + // p2wpkh script with uncompressed key must infer as addr() + CheckInferDescriptor("001422e363a523947a110d9a9eb114820de183aca313", "addr(bc1qyt3k8ffrj3apzrv6n6c3fqsduxp6egcnk2r66j)", {}, {{"049228de6902abb4f541791f6d7f925b10e2078ccb1298856e5ea5cc5fd667f930eac37a00cc07f9a91ef3c2d17bf7a17db04552ff90ac312a5b8b4caca6c97aa4", ""}}); + // Infer pkh() from p2pkh with uncompressed key + CheckInferDescriptor("76a914a31725c74421fadc50d35520ab8751ed120af80588ac", "pkh(04c56fe4a92d401bcbf1b3dfbe4ac3dac5602ca155a3681497f02c1b9a733b92d704e2da6ec4162e4846af9236ef4171069ac8b7f8234a8405b6cadd96f34f5a31)", {}, {{"04c56fe4a92d401bcbf1b3dfbe4ac3dac5602ca155a3681497f02c1b9a733b92d704e2da6ec4162e4846af9236ef4171069ac8b7f8234a8405b6cadd96f34f5a31", ""}}); + // Infer pk() from p2pk with uncompressed key + CheckInferDescriptor("4104032540df1d3c7070a8ab3a9cdd304dfc7fd1e6541369c53c4c3310b2537d91059afc8b8e7673eb812a32978dabb78c40f2e423f7757dca61d11838c7aeeb5220ac", "pk(04032540df1d3c7070a8ab3a9cdd304dfc7fd1e6541369c53c4c3310b2537d91059afc8b8e7673eb812a32978dabb78c40f2e423f7757dca61d11838c7aeeb5220)", {}, {{"04032540df1d3c7070a8ab3a9cdd304dfc7fd1e6541369c53c4c3310b2537d91059afc8b8e7673eb812a32978dabb78c40f2e423f7757dca61d11838c7aeeb5220", ""}}); } BOOST_AUTO_TEST_SUITE_END() From 4077e43bf62e5afe90d204b9ede9290ef54dee0f Mon Sep 17 00:00:00 2001 From: willcl-ark Date: Mon, 9 Oct 2023 14:38:37 +0100 Subject: [PATCH 21/41] test: fix usdt undeclared function errors on mantis Recently usage of undeclared functions became an error rather than a warning, in C2x. https://reviews.llvm.org/D122983?id=420290 This change has migrated into the build tools of Ubuntu 23.10 which now causes the USDT tests to fail to compile, see https://github.com/bitcoin/bitcoin/issues/28600 Fix this by setting `-Wno-error=implicit-function-declaration` for the tracing programs. --- test/functional/interface_usdt_coinselection.py | 2 +- test/functional/interface_usdt_mempool.py | 9 +++++---- test/functional/interface_usdt_net.py | 2 +- test/functional/interface_usdt_utxocache.py | 8 ++++---- test/functional/interface_usdt_validation.py | 2 +- 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/test/functional/interface_usdt_coinselection.py b/test/functional/interface_usdt_coinselection.py index a3c830bb51..aff90ea5fc 100755 --- a/test/functional/interface_usdt_coinselection.py +++ b/test/functional/interface_usdt_coinselection.py @@ -166,7 +166,7 @@ def run_test(self): ctx.enable_probe(probe="coin_selection:normal_create_tx_internal", fn_name="trace_normal_create_tx") ctx.enable_probe(probe="coin_selection:attempting_aps_create_tx", fn_name="trace_attempt_aps") ctx.enable_probe(probe="coin_selection:aps_create_tx_internal", fn_name="trace_aps_create_tx") - self.bpf = BPF(text=coinselection_tracepoints_program, usdt_contexts=[ctx], debug=0) + self.bpf = BPF(text=coinselection_tracepoints_program, usdt_contexts=[ctx], debug=0, cflags=["-Wno-error=implicit-function-declaration"]) self.log.info("Prepare wallets") self.generate(self.nodes[0], 101) diff --git a/test/functional/interface_usdt_mempool.py b/test/functional/interface_usdt_mempool.py index d1e274480c..0168d9f916 100755 --- a/test/functional/interface_usdt_mempool.py +++ b/test/functional/interface_usdt_mempool.py @@ -119,6 +119,7 @@ replaced_events.perf_submit(ctx, &replaced, sizeof(replaced)); return 0; } + """ @@ -143,7 +144,7 @@ def added_test(self): node = self.nodes[0] ctx = USDT(pid=node.process.pid) ctx.enable_probe(probe="mempool:added", fn_name="trace_added") - bpf = BPF(text=MEMPOOL_TRACEPOINTS_PROGRAM, usdt_contexts=[ctx], debug=0) + bpf = BPF(text=MEMPOOL_TRACEPOINTS_PROGRAM, usdt_contexts=[ctx], debug=0, cflags=["-Wno-error=implicit-function-declaration"]) def handle_added_event(_, data, __): events.append(bpf["added_events"].event(data)) @@ -180,7 +181,7 @@ def removed_test(self): node = self.nodes[0] ctx = USDT(pid=node.process.pid) ctx.enable_probe(probe="mempool:removed", fn_name="trace_removed") - bpf = BPF(text=MEMPOOL_TRACEPOINTS_PROGRAM, usdt_contexts=[ctx], debug=0) + bpf = BPF(text=MEMPOOL_TRACEPOINTS_PROGRAM, usdt_contexts=[ctx], debug=0, cflags=["-Wno-error=implicit-function-declaration"]) def handle_removed_event(_, data, __): events.append(bpf["removed_events"].event(data)) @@ -226,7 +227,7 @@ def replaced_test(self): node = self.nodes[0] ctx = USDT(pid=node.process.pid) ctx.enable_probe(probe="mempool:replaced", fn_name="trace_replaced") - bpf = BPF(text=MEMPOOL_TRACEPOINTS_PROGRAM, usdt_contexts=[ctx], debug=0) + bpf = BPF(text=MEMPOOL_TRACEPOINTS_PROGRAM, usdt_contexts=[ctx], debug=0, cflags=["-Wno-error=implicit-function-declaration"]) def handle_replaced_event(_, data, __): events.append(bpf["replaced_events"].event(data)) @@ -277,7 +278,7 @@ def rejected_test(self): self.log.info("Hooking into mempool:rejected tracepoint...") ctx = USDT(pid=node.process.pid) ctx.enable_probe(probe="mempool:rejected", fn_name="trace_rejected") - bpf = BPF(text=MEMPOOL_TRACEPOINTS_PROGRAM, usdt_contexts=[ctx], debug=0) + bpf = BPF(text=MEMPOOL_TRACEPOINTS_PROGRAM, usdt_contexts=[ctx], debug=0, cflags=["-Wno-error=implicit-function-declaration"]) def handle_rejected_event(_, data, __): events.append(bpf["rejected_events"].event(data)) diff --git a/test/functional/interface_usdt_net.py b/test/functional/interface_usdt_net.py index e15ac3c1f2..5d7c8c2304 100755 --- a/test/functional/interface_usdt_net.py +++ b/test/functional/interface_usdt_net.py @@ -114,7 +114,7 @@ def __repr__(self): fn_name="trace_inbound_message") ctx.enable_probe(probe="net:outbound_message", fn_name="trace_outbound_message") - bpf = BPF(text=net_tracepoints_program, usdt_contexts=[ctx], debug=0) + bpf = BPF(text=net_tracepoints_program, usdt_contexts=[ctx], debug=0, cflags=["-Wno-error=implicit-function-declaration"]) EXPECTED_INOUTBOUND_VERSION_MSG = 1 checked_inbound_version_msg = 0 diff --git a/test/functional/interface_usdt_utxocache.py b/test/functional/interface_usdt_utxocache.py index 2fc5981451..06cdcd10a0 100755 --- a/test/functional/interface_usdt_utxocache.py +++ b/test/functional/interface_usdt_utxocache.py @@ -175,7 +175,7 @@ def test_uncache(self): ctx = USDT(pid=self.nodes[0].process.pid) ctx.enable_probe(probe="utxocache:uncache", fn_name="trace_utxocache_uncache") - bpf = BPF(text=utxocache_changes_program, usdt_contexts=[ctx], debug=0) + bpf = BPF(text=utxocache_changes_program, usdt_contexts=[ctx], debug=0, cflags=["-Wno-error=implicit-function-declaration"]) # The handle_* function is a ctypes callback function called from C. When # we assert in the handle_* function, the AssertError doesn't propagate @@ -244,7 +244,7 @@ def test_add_spent(self): ctx.enable_probe(probe="utxocache:add", fn_name="trace_utxocache_add") ctx.enable_probe(probe="utxocache:spent", fn_name="trace_utxocache_spent") - bpf = BPF(text=utxocache_changes_program, usdt_contexts=[ctx], debug=0) + bpf = BPF(text=utxocache_changes_program, usdt_contexts=[ctx], debug=0, cflags=["-Wno-error=implicit-function-declaration"]) # The handle_* function is a ctypes callback function called from C. When # we assert in the handle_* function, the AssertError doesn't propagate @@ -333,7 +333,7 @@ def test_flush(self): ctx = USDT(pid=self.nodes[0].process.pid) ctx.enable_probe(probe="utxocache:flush", fn_name="trace_utxocache_flush") - bpf = BPF(text=utxocache_flushes_program, usdt_contexts=[ctx], debug=0) + bpf = BPF(text=utxocache_flushes_program, usdt_contexts=[ctx], debug=0, cflags=["-Wno-error=implicit-function-declaration"]) # The handle_* function is a ctypes callback function called from C. When # we assert in the handle_* function, the AssertError doesn't propagate @@ -390,7 +390,7 @@ def handle_utxocache_flush(_, data, __): ctx = USDT(pid=self.nodes[0].process.pid) ctx.enable_probe(probe="utxocache:flush", fn_name="trace_utxocache_flush") - bpf = BPF(text=utxocache_flushes_program, usdt_contexts=[ctx], debug=0) + bpf = BPF(text=utxocache_flushes_program, usdt_contexts=[ctx], debug=0, cflags=["-Wno-error=implicit-function-declaration"]) bpf["utxocache_flush"].open_perf_buffer(handle_utxocache_flush) self.log.info(f"prune blockchain to trigger a flush for pruning") diff --git a/test/functional/interface_usdt_validation.py b/test/functional/interface_usdt_validation.py index e29b2c46eb..30982393d8 100755 --- a/test/functional/interface_usdt_validation.py +++ b/test/functional/interface_usdt_validation.py @@ -94,7 +94,7 @@ def __repr__(self): ctx.enable_probe(probe="validation:block_connected", fn_name="trace_block_connected") bpf = BPF(text=validation_blockconnected_program, - usdt_contexts=[ctx], debug=0) + usdt_contexts=[ctx], debug=0, cflags=["-Wno-error=implicit-function-declaration"]) def handle_blockconnected(_, data, __): event = ctypes.cast(data, ctypes.POINTER(Block)).contents From 57131bfa3cfd9e5826b5c557aba8aa03bf41f833 Mon Sep 17 00:00:00 2001 From: vuittont60 Date: Tue, 10 Oct 2023 15:06:47 +0800 Subject: [PATCH 22/41] docs: fix typo --- contrib/devtools/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/devtools/README.md b/contrib/devtools/README.md index 8bbf39b67f..56eaeef815 100644 --- a/contrib/devtools/README.md +++ b/contrib/devtools/README.md @@ -83,7 +83,7 @@ A small script to automatically create manpages in ../../doc/man by running the This requires help2man which can be found at: https://www.gnu.org/software/help2man/ With in-tree builds this tool can be run from any directory within the -repostitory. To use this tool with out-of-tree builds set `BUILDDIR`. For +repository. To use this tool with out-of-tree builds set `BUILDDIR`. For example: ```bash From 2e31250027ac580a7a72221fe2ff505b30836175 Mon Sep 17 00:00:00 2001 From: Sebastian Falbesoner Date: Tue, 10 Oct 2023 09:28:22 +0200 Subject: [PATCH 23/41] test: check that loading snapshot not matching AssumeUTXO parameters fails --- test/functional/feature_assumeutxo.py | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/test/functional/feature_assumeutxo.py b/test/functional/feature_assumeutxo.py index 6c09a6f5e7..ea93b7ab88 100755 --- a/test/functional/feature_assumeutxo.py +++ b/test/functional/feature_assumeutxo.py @@ -36,7 +36,11 @@ """ from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import assert_equal +from test_framework.util import ( + assert_equal, + assert_raises_rpc_error, +) + START_HEIGHT = 199 SNAPSHOT_BASE_HEIGHT = 299 @@ -62,6 +66,25 @@ def setup_network(self): self.add_nodes(3) self.start_nodes(extra_args=self.extra_args) + def test_invalid_snapshot_scenarios(self, valid_snapshot_path): + self.log.info("Test different scenarios of loading invalid snapshot files") + self.log.info(" - snapshot file refering to a block that is not in the assumeutxo parameters") + with open(valid_snapshot_path, 'rb') as f: + valid_snapshot_contents = f.read() + + # we can only test this with a block that is already known, as otherwise the `loadtxoutset` RPC + # would time out (waiting to see the hash in the headers chain), rather than error immediately + bad_snapshot_height = SNAPSHOT_BASE_HEIGHT - 1 + bad_snapshot_path = valid_snapshot_path + '.mod' + with open(bad_snapshot_path, 'wb') as f: + bad_snapshot_block_hash = self.nodes[0].getblockhash(bad_snapshot_height) + # block hash of the snapshot base is stored right at the start (first 32 bytes) + f.write(bytes.fromhex(bad_snapshot_block_hash)[::-1] + valid_snapshot_contents[32:]) + + expected_log = f"assumeutxo height in snapshot metadata not recognized ({bad_snapshot_height}) - refusing to load snapshot" + with self.nodes[1].assert_debug_log(expected_log): + assert_raises_rpc_error(-32603, "Unable to load UTXO snapshot", self.nodes[1].loadtxoutset, bad_snapshot_path) + def run_test(self): """ Bring up two (disconnected) nodes, mine some new blocks on the first, @@ -120,6 +143,8 @@ def run_test(self): assert_equal(n0.getblockchaininfo()["blocks"], FINAL_HEIGHT) + self.test_invalid_snapshot_scenarios(dump_output['path']) + self.log.info(f"Loading snapshot into second node from {dump_output['path']}") loaded = n1.loadtxoutset(dump_output['path']) assert_equal(loaded['coins_loaded'], SNAPSHOT_BASE_HEIGHT) From ce46b6894176ddb9642b28c139c782c054c09996 Mon Sep 17 00:00:00 2001 From: fanquake Date: Fri, 6 Oct 2023 10:59:16 +0100 Subject: [PATCH 24/41] ci: use LLVM 17.0.2 in MSAN jobs --- ci/test/01_base_install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/test/01_base_install.sh b/ci/test/01_base_install.sh index 424dca52dc..24da80d6fd 100755 --- a/ci/test/01_base_install.sh +++ b/ci/test/01_base_install.sh @@ -42,7 +42,7 @@ if [ -n "$PIP_PACKAGES" ]; then fi if [[ ${USE_MEMORY_SANITIZER} == "true" ]]; then - git clone --depth=1 https://github.com/llvm/llvm-project -b "llvmorg-17.0.0-rc4" /msan/llvm-project + ${CI_RETRY_EXE} git clone --depth=1 https://github.com/llvm/llvm-project -b llvmorg-17.0.2 /msan/llvm-project cmake -G Ninja -B /msan/clang_build/ \ -DLLVM_ENABLE_PROJECTS="clang" \ From 8735e2c1365cba9246918ea167a40ffe44beb3ba Mon Sep 17 00:00:00 2001 From: fanquake Date: Thu, 20 Jul 2023 16:19:48 +0100 Subject: [PATCH 25/41] ci: use LLVM/Clang 17 in tidy job --- ci/test/00_setup_env_native_tidy.sh | 5 +++-- ci/test/01_base_install.sh | 5 +++-- ci/test/06_script_b.sh | 4 ++-- src/.clang-tidy | 1 + 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/ci/test/00_setup_env_native_tidy.sh b/ci/test/00_setup_env_native_tidy.sh index 456166d3be..6b0c708f19 100755 --- a/ci/test/00_setup_env_native_tidy.sh +++ b/ci/test/00_setup_env_native_tidy.sh @@ -8,12 +8,13 @@ export LC_ALL=C.UTF-8 export CI_IMAGE_NAME_TAG="docker.io/ubuntu:23.10" # This version will reach EOL in Jul 2024, and can be replaced by "ubuntu:24.04" (or anything else that ships the wanted clang version). export CONTAINER_NAME=ci_native_tidy -export PACKAGES="clang-16 libclang-16-dev llvm-16-dev libomp-16-dev clang-tidy-16 jq bear cmake libevent-dev libboost-dev libminiupnpc-dev libnatpmp-dev libzmq3-dev systemtap-sdt-dev libqt5gui5 libqt5core5a libqt5dbus5 qttools5-dev qttools5-dev-tools libqrencode-dev libsqlite3-dev libdb++-dev" +export TIDY_LLVM_V="17" +export PACKAGES="clang-${TIDY_LLVM_V} libclang-${TIDY_LLVM_V}-dev llvm-${TIDY_LLVM_V}-dev libomp-${TIDY_LLVM_V}-dev clang-tidy-${TIDY_LLVM_V} jq bear cmake libevent-dev libboost-dev libminiupnpc-dev libnatpmp-dev libzmq3-dev systemtap-sdt-dev libqt5gui5 libqt5core5a libqt5dbus5 qttools5-dev qttools5-dev-tools libqrencode-dev libsqlite3-dev libdb++-dev" export NO_DEPENDS=1 export RUN_UNIT_TESTS=false export RUN_FUNCTIONAL_TESTS=false export RUN_FUZZ_TESTS=false export RUN_TIDY=true export GOAL="install" -export BITCOIN_CONFIG="CC=clang-16 CXX=clang++-16 --with-incompatible-bdb --disable-hardening CFLAGS='-O0 -g0' CXXFLAGS='-O0 -g0 -I/usr/lib/llvm-16/lib/clang/16/include'" +export BITCOIN_CONFIG="CC=clang-${TIDY_LLVM_V} CXX=clang++-${TIDY_LLVM_V} --with-incompatible-bdb --disable-hardening CFLAGS='-O0 -g0' CXXFLAGS='-O0 -g0 -I/usr/lib/llvm-${TIDY_LLVM_V}/lib/clang/${TIDY_LLVM_V}/include'" export CCACHE_MAXSIZE=200M diff --git a/ci/test/01_base_install.sh b/ci/test/01_base_install.sh index 24da80d6fd..596cf510bf 100755 --- a/ci/test/01_base_install.sh +++ b/ci/test/01_base_install.sh @@ -73,8 +73,9 @@ if [[ ${USE_MEMORY_SANITIZER} == "true" ]]; then fi if [[ "${RUN_TIDY}" == "true" ]]; then - git clone --depth=1 https://github.com/include-what-you-use/include-what-you-use -b clang_16 /include-what-you-use - cmake -B /iwyu-build/ -G 'Unix Makefiles' -DCMAKE_PREFIX_PATH=/usr/lib/llvm-16 -S /include-what-you-use + ${CI_RETRY_EXE} git clone https://github.com/include-what-you-use/include-what-you-use -b master /include-what-you-use + git -C /include-what-you-use checkout a138eaac254e5a472464e31d5ec418fe6e6f1fc7 + cmake -B /iwyu-build/ -G 'Unix Makefiles' -DCMAKE_PREFIX_PATH=/usr/lib/llvm-"${TIDY_LLVM_V}" -S /include-what-you-use make -C /iwyu-build/ install "-j$( nproc )" # Use nproc, because MAKEJOBS is the default in docker image builds fi diff --git a/ci/test/06_script_b.sh b/ci/test/06_script_b.sh index 89af61b87f..4d5f31b956 100755 --- a/ci/test/06_script_b.sh +++ b/ci/test/06_script_b.sh @@ -175,13 +175,13 @@ if [ "$RUN_FUNCTIONAL_TESTS" = "true" ]; then fi if [ "${RUN_TIDY}" = "true" ]; then - cmake -B /tidy-build -DLLVM_DIR=/usr/lib/llvm-16/cmake -DCMAKE_BUILD_TYPE=Release -S "${BASE_ROOT_DIR}"/contrib/devtools/bitcoin-tidy + cmake -B /tidy-build -DLLVM_DIR=/usr/lib/llvm-"${TIDY_LLVM_V}"/cmake -DCMAKE_BUILD_TYPE=Release -S "${BASE_ROOT_DIR}"/contrib/devtools/bitcoin-tidy cmake --build /tidy-build "$MAKEJOBS" cmake --build /tidy-build --target bitcoin-tidy-tests "$MAKEJOBS" set -eo pipefail cd "${BASE_BUILD_DIR}/bitcoin-$HOST/src/" - ( run-clang-tidy-16 -quiet -load="/tidy-build/libbitcoin-tidy.so" "${MAKEJOBS}" ) | grep -C5 "error" + ( run-clang-tidy-"${TIDY_LLVM_V}" -quiet -load="/tidy-build/libbitcoin-tidy.so" "${MAKEJOBS}" ) | grep -C5 "error" # Filter out files by regex here, because regex may not be # accepted in src/.bear-tidy-config # Filter out: diff --git a/src/.clang-tidy b/src/.clang-tidy index 4deb5a85a5..9f16553706 100644 --- a/src/.clang-tidy +++ b/src/.clang-tidy @@ -8,6 +8,7 @@ modernize-use-default-member-init, modernize-use-noexcept, modernize-use-nullptr, performance-*, +-performance-avoid-endl, -performance-inefficient-string-concatenation, -performance-no-int-to-ptr, -performance-noexcept-move-constructor, From 36a3004a41aea58f50f3348c5de4eb5a23268788 Mon Sep 17 00:00:00 2001 From: Fabian Jahr Date: Tue, 10 Oct 2023 12:57:54 +0200 Subject: [PATCH 26/41] devtools: test_utxo_snapshots.sh sleep cleanup and documentation --- contrib/devtools/test_utxo_snapshots.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/contrib/devtools/test_utxo_snapshots.sh b/contrib/devtools/test_utxo_snapshots.sh index d4c49bf098..f5918d7738 100755 --- a/contrib/devtools/test_utxo_snapshots.sh +++ b/contrib/devtools/test_utxo_snapshots.sh @@ -72,6 +72,9 @@ server_sleep_til_boot() { client_sleep_til_boot() { while ! client_rpc ping >/dev/null 2>&1; do sleep 0.1; done } +server_sleep_til_shutdown() { + while server_rpc ping >/dev/null 2>&1; do sleep 0.1; done +} mkdir -p "$SERVER_DATADIR" "$CLIENT_DATADIR" @@ -109,7 +112,7 @@ echo "-- IBDing the blocks (height=$BASE_HEIGHT) required to the server node..." echo echo "-- Creating snapshot at ~ height $BASE_HEIGHT ($UTXO_DAT_FILE)..." -sleep 2 +server_sleep_til_shutdown # wait for stopatheight to be hit ./src/bitcoind -logthreadnames=1 $SERVER_PORTS \ -datadir="$SERVER_DATADIR" $EARLY_IBD_FLAGS -connect=0 -listen=0 >/dev/null & SERVER_PID="$!" @@ -124,8 +127,7 @@ RPC_AU=$(jq -r .txoutset_hash < "$DUMP_OUTPUT") RPC_NCHAINTX=$(jq -r .nchaintx < "$DUMP_OUTPUT") RPC_BLOCKHASH=$(jq -r .base_hash < "$DUMP_OUTPUT") -# Wait for server to shutdown... -while server_rpc ping >/dev/null 2>&1; do sleep 0.1; done +server_sleep_til_shutdown echo echo "-- Now: add the following to CMainParams::m_assumeutxo_data" @@ -186,9 +188,7 @@ echo " Press CTRL+C after you're satisfied to exit the demo" echo read -p "Press [enter] to continue" -while kill -0 "$CLIENT_PID"; do - sleep 1 -done +client_sleep_til_boot ./src/bitcoind $CLIENT_PORTS $ALL_INDEXES -logthreadnames=1 -datadir="$CLIENT_DATADIR" -connect=0 \ -addnode=127.0.0.1:$SERVER_PORT "$EARLY_IBD_FLAGS" >/dev/null & CLIENT_PID="$!" From 61a6c3b0e9a8dab5c5f845af4becde817539133c Mon Sep 17 00:00:00 2001 From: fanquake Date: Thu, 18 Nov 2021 14:12:47 +0800 Subject: [PATCH 27/41] build: add `-mbranch-protection=bti` to aarch64 hardening flags This is a simpler (less hardening) version of #24123. Scoped to aarch64 to avoid unused command line option warnings when building on x86_64. Related to #19075. --- configure.ac | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/configure.ac b/configure.ac index 9b4b9bd42b..20358205ca 100644 --- a/configure.ac +++ b/configure.ac @@ -964,6 +964,11 @@ if test "$use_hardening" != "no"; then ;; esac + case $host in + *aarch64*) + AX_CHECK_COMPILE_FLAG([-mbranch-protection=bti], [HARDENED_CXXFLAGS="$HARDENED_CXXFLAGS -mbranch-protection=bti"]) + ;; + esac dnl When enable_debug is yes, all optimizations are disabled. dnl However, FORTIFY_SOURCE requires that there is some level of optimization, otherwise it does nothing and just creates a compiler warning. From bfa0bd632a7ce5d04005e20cba79abb32aec8da8 Mon Sep 17 00:00:00 2001 From: ns-xvrn Date: Sat, 2 Sep 2023 01:09:43 -0400 Subject: [PATCH 28/41] test: Use pathlib over os.path #28362 revert netutil chgs py3.8 compliant fixes based on PR review --- test/functional/feature_blocksdir.py | 16 ++--- test/functional/feature_config_args.py | 63 ++++++++++--------- test/functional/feature_filelock.py | 2 +- test/functional/feature_loadblock.py | 14 ++--- test/functional/feature_settings.py | 7 +-- test/functional/interface_bitcoin_cli.py | 2 +- test/functional/rpc_bind.py | 2 +- test/functional/rpc_dumptxoutset.py | 3 +- .../test_framework/test_framework.py | 4 +- test/functional/test_framework/test_node.py | 34 +++++----- test/functional/test_framework/util.py | 2 +- test/functional/tool_wallet.py | 24 +++---- test/functional/wallet_backup.py | 63 ++++++++----------- test/functional/wallet_blank.py | 3 +- test/functional/wallet_crosschain.py | 10 ++- test/functional/wallet_descriptor.py | 3 +- test/functional/wallet_dump.py | 9 ++- test/functional/wallet_fast_rescan.py | 3 +- test/functional/wallet_hd.py | 21 +++---- test/functional/wallet_keypool_topup.py | 5 +- test/functional/wallet_pruning.py | 11 ++-- test/functional/wallet_reorgsrestore.py | 5 +- 22 files changed, 138 insertions(+), 168 deletions(-) diff --git a/test/functional/feature_blocksdir.py b/test/functional/feature_blocksdir.py index 76b9277e2f..1a60c13c2c 100755 --- a/test/functional/feature_blocksdir.py +++ b/test/functional/feature_blocksdir.py @@ -5,8 +5,8 @@ """Test the blocksdir option. """ -import os import shutil +from pathlib import Path from test_framework.test_framework import BitcoinTestFramework, initialize_datadir @@ -18,20 +18,20 @@ def set_test_params(self): def run_test(self): self.stop_node(0) - assert os.path.isdir(os.path.join(self.nodes[0].blocks_path)) - assert not os.path.isdir(os.path.join(self.nodes[0].datadir, "blocks")) - shutil.rmtree(self.nodes[0].datadir) + assert self.nodes[0].blocks_path.is_dir() + assert not (self.nodes[0].datadir_path / "blocks").is_dir() + shutil.rmtree(self.nodes[0].datadir_path) initialize_datadir(self.options.tmpdir, 0, self.chain) self.log.info("Starting with nonexistent blocksdir ...") - blocksdir_path = os.path.join(self.options.tmpdir, 'blocksdir') + blocksdir_path = Path(self.options.tmpdir) / 'blocksdir' self.nodes[0].assert_start_raises_init_error([f"-blocksdir={blocksdir_path}"], f'Error: Specified blocks directory "{blocksdir_path}" does not exist.') - os.mkdir(blocksdir_path) + blocksdir_path.mkdir() self.log.info("Starting with existing blocksdir ...") self.start_node(0, [f"-blocksdir={blocksdir_path}"]) self.log.info("mining blocks..") self.generatetoaddress(self.nodes[0], 10, self.nodes[0].get_deterministic_priv_key().address) - assert os.path.isfile(os.path.join(blocksdir_path, self.chain, "blocks", "blk00000.dat")) - assert os.path.isdir(os.path.join(self.nodes[0].blocks_path, "index")) + assert (blocksdir_path / self.chain / "blocks" / "blk00000.dat").is_file() + assert (self.nodes[0].blocks_path / "index").is_dir() if __name__ == '__main__': diff --git a/test/functional/feature_config_args.py b/test/functional/feature_config_args.py index 97ee9538dc..dcea662089 100755 --- a/test/functional/feature_config_args.py +++ b/test/functional/feature_config_args.py @@ -5,7 +5,7 @@ """Test various command line arguments and configuration file parameters.""" import os -import pathlib +from pathlib import Path import re import sys import tempfile @@ -39,8 +39,8 @@ def test_config_file_parser(self): extra_args=[f'-conf={bad_conf_file_path}'], expected_msg=conf_in_config_file_err, ) - inc_conf_file_path = os.path.join(self.nodes[0].datadir, 'include.conf') - with open(os.path.join(self.nodes[0].datadir, 'bitcoin.conf'), 'a', encoding='utf-8') as conf: + inc_conf_file_path = self.nodes[0].datadir_path / 'include.conf' + with open(self.nodes[0].datadir_path / 'bitcoin.conf', 'a', encoding='utf-8') as conf: conf.write(f'includeconf={inc_conf_file_path}\n') with open(inc_conf_file_path, 'w', encoding='utf-8') as conf: conf.write('conf=some.conf\n') @@ -97,8 +97,8 @@ def test_config_file_parser(self): conf.write('server=1\nrpcuser=someuser\n[main]\nrpcpassword=some#pass') self.nodes[0].assert_start_raises_init_error(expected_msg='Error: Error reading configuration file: parse error on line 4, using # in rpcpassword can be ambiguous and should be avoided') - inc_conf_file2_path = os.path.join(self.nodes[0].datadir, 'include2.conf') - with open(os.path.join(self.nodes[0].datadir, 'bitcoin.conf'), 'a', encoding='utf-8') as conf: + inc_conf_file2_path = self.nodes[0].datadir_path / 'include2.conf' + with open(self.nodes[0].datadir_path / 'bitcoin.conf', 'a', encoding='utf-8') as conf: conf.write(f'includeconf={inc_conf_file2_path}\n') with open(inc_conf_file_path, 'w', encoding='utf-8') as conf: @@ -123,15 +123,15 @@ def test_config_file_log(self): # Create a temporary directory that will be treated as the default data # directory by bitcoind. - env, default_datadir = util.get_temp_default_datadir(pathlib.Path(self.options.tmpdir, "test_config_file_log")) + env, default_datadir = util.get_temp_default_datadir(Path(self.options.tmpdir, "test_config_file_log")) default_datadir.mkdir(parents=True) # Write a bitcoin.conf file in the default data directory containing a # datadir= line pointing at the node datadir. node = self.nodes[0] - conf_text = pathlib.Path(node.bitcoinconf).read_text() + conf_text = node.bitcoinconf.read_text() conf_path = default_datadir / "bitcoin.conf" - conf_path.write_text(f"datadir={node.datadir}\n{conf_text}") + conf_path.write_text(f"datadir={node.datadir_path}\n{conf_text}") # Drop the node -datadir= argument during this test, because if it is # specified it would take precedence over the datadir setting in the @@ -218,7 +218,8 @@ def test_networkactive(self): def test_seed_peers(self): self.log.info('Test seed peers') - default_data_dir = self.nodes[0].datadir + default_data_dir = self.nodes[0].datadir_path + peer_dat = default_data_dir / 'peers.dat' # Only regtest has no fixed seeds. To avoid connections to random # nodes, regtest is the only network where it is safe to enable # -fixedseeds in tests @@ -229,7 +230,7 @@ def test_seed_peers(self): # We expect the node will use DNS Seeds, but Regtest mode does not have # any valid DNS seeds. So after 60 seconds, the node should fallback to # fixed seeds - assert not os.path.exists(os.path.join(default_data_dir, "peers.dat")) + assert not peer_dat.exists() start = int(time.time()) with self.nodes[0].assert_debug_log( expected_msgs=[ @@ -248,7 +249,7 @@ def test_seed_peers(self): # No peers.dat exists and -dnsseed=0 # We expect the node will fallback immediately to fixed seeds - assert not os.path.exists(os.path.join(default_data_dir, "peers.dat")) + assert not peer_dat.exists() with self.nodes[0].assert_debug_log(expected_msgs=[ "Loaded 0 addresses from peers.dat", "DNS seeding disabled", @@ -260,7 +261,7 @@ def test_seed_peers(self): # No peers.dat exists and dns seeds are disabled. # We expect the node will not add fixed seeds when explicitly disabled. - assert not os.path.exists(os.path.join(default_data_dir, "peers.dat")) + assert not peer_dat.exists() with self.nodes[0].assert_debug_log(expected_msgs=[ "Loaded 0 addresses from peers.dat", "DNS seeding disabled", @@ -271,7 +272,7 @@ def test_seed_peers(self): # No peers.dat exists and -dnsseed=0, but a -addnode is provided # We expect the node will allow 60 seconds prior to using fixed seeds - assert not os.path.exists(os.path.join(default_data_dir, "peers.dat")) + assert not peer_dat.exists() start = int(time.time()) with self.nodes[0].assert_debug_log( expected_msgs=[ @@ -323,16 +324,16 @@ def test_ignored_conf(self): 'because a conflicting -conf file argument is passed.') node = self.nodes[0] with tempfile.NamedTemporaryFile(dir=self.options.tmpdir, mode="wt", delete=False) as temp_conf: - temp_conf.write(f"datadir={node.datadir}\n") + temp_conf.write(f"datadir={node.datadir_path}\n") node.assert_start_raises_init_error([f"-conf={temp_conf.name}"], re.escape( - f'Error: Data directory "{node.datadir}" contains a "bitcoin.conf" file which is ignored, because a ' + f'Error: Data directory "{node.datadir_path}" contains a "bitcoin.conf" file which is ignored, because a ' f'different configuration file "{temp_conf.name}" from command line argument "-conf={temp_conf.name}" ' f'is being used instead.') + r"[\s\S]*", match=ErrorMatch.FULL_REGEX) # Test that passing a redundant -conf command line argument pointing to # the same bitcoin.conf that would be loaded anyway does not trigger an # error. - self.start_node(0, [f'-conf={node.datadir}/bitcoin.conf']) + self.start_node(0, [f'-conf={node.datadir_path}/bitcoin.conf']) self.stop_node(0) def test_ignored_default_conf(self): @@ -346,7 +347,7 @@ def test_ignored_default_conf(self): # Create a temporary directory that will be treated as the default data # directory by bitcoind. - env, default_datadir = util.get_temp_default_datadir(pathlib.Path(self.options.tmpdir, "home")) + env, default_datadir = util.get_temp_default_datadir(Path(self.options.tmpdir, "home")) default_datadir.mkdir(parents=True) # Write a bitcoin.conf file in the default data directory containing a @@ -354,7 +355,7 @@ def test_ignored_default_conf(self): # startup error because the node datadir contains a different # bitcoin.conf that would be ignored. node = self.nodes[0] - (default_datadir / "bitcoin.conf").write_text(f"datadir={node.datadir}\n") + (default_datadir / "bitcoin.conf").write_text(f"datadir={node.datadir_path}\n") # Drop the node -datadir= argument during this test, because if it is # specified it would take precedence over the datadir setting in the @@ -362,7 +363,7 @@ def test_ignored_default_conf(self): node_args = node.args node.args = [arg for arg in node.args if not arg.startswith("-datadir=")] node.assert_start_raises_init_error([], re.escape( - f'Error: Data directory "{node.datadir}" contains a "bitcoin.conf" file which is ignored, because a ' + f'Error: Data directory "{node.datadir_path}" contains a "bitcoin.conf" file which is ignored, because a ' f'different configuration file "{default_datadir}/bitcoin.conf" from data directory "{default_datadir}" ' f'is being used instead.') + r"[\s\S]*", env=env, match=ErrorMatch.FULL_REGEX) node.args = node_args @@ -392,16 +393,16 @@ def run_test(self): # Remove the -datadir argument so it doesn't override the config file self.nodes[0].args = [arg for arg in self.nodes[0].args if not arg.startswith("-datadir")] - default_data_dir = self.nodes[0].datadir - new_data_dir = os.path.join(default_data_dir, 'newdatadir') - new_data_dir_2 = os.path.join(default_data_dir, 'newdatadir2') + default_data_dir = self.nodes[0].datadir_path + new_data_dir = default_data_dir / 'newdatadir' + new_data_dir_2 = default_data_dir / 'newdatadir2' # Check that using -datadir argument on non-existent directory fails - self.nodes[0].datadir = new_data_dir + self.nodes[0].datadir_path = new_data_dir self.nodes[0].assert_start_raises_init_error([f'-datadir={new_data_dir}'], f'Error: Specified data directory "{new_data_dir}" does not exist.') # Check that using non-existent datadir in conf file fails - conf_file = os.path.join(default_data_dir, "bitcoin.conf") + conf_file = default_data_dir / "bitcoin.conf" # datadir needs to be set before [chain] section with open(conf_file, encoding='utf8') as f: @@ -413,20 +414,20 @@ def run_test(self): self.nodes[0].assert_start_raises_init_error([f'-conf={conf_file}'], f'Error: Error reading configuration file: specified data directory "{new_data_dir}" does not exist.') # Check that an explicitly specified config file that cannot be opened fails - none_existent_conf_file = os.path.join(default_data_dir, "none_existent_bitcoin.conf") - self.nodes[0].assert_start_raises_init_error(['-conf=' + none_existent_conf_file], 'Error: Error reading configuration file: specified config file "' + none_existent_conf_file + '" could not be opened.') + none_existent_conf_file = default_data_dir / "none_existent_bitcoin.conf" + self.nodes[0].assert_start_raises_init_error(['-conf=' + f'{none_existent_conf_file}'], 'Error: Error reading configuration file: specified config file "' + f'{none_existent_conf_file}' + '" could not be opened.') # Create the directory and ensure the config file now works - os.mkdir(new_data_dir) + new_data_dir.mkdir() self.start_node(0, [f'-conf={conf_file}']) self.stop_node(0) - assert os.path.exists(os.path.join(new_data_dir, self.chain, 'blocks')) + assert (new_data_dir / self.chain / 'blocks').exists() # Ensure command line argument overrides datadir in conf - os.mkdir(new_data_dir_2) - self.nodes[0].datadir = new_data_dir_2 + new_data_dir_2.mkdir() + self.nodes[0].datadir_path = new_data_dir_2 self.start_node(0, [f'-datadir={new_data_dir_2}', f'-conf={conf_file}']) - assert os.path.exists(os.path.join(new_data_dir_2, self.chain, 'blocks')) + assert (new_data_dir_2 / self.chain / 'blocks').exists() if __name__ == '__main__': diff --git a/test/functional/feature_filelock.py b/test/functional/feature_filelock.py index cf2f21d553..24a68a04bf 100755 --- a/test/functional/feature_filelock.py +++ b/test/functional/feature_filelock.py @@ -28,7 +28,7 @@ def run_test(self): self.log.info("Check that we can't start a second bitcoind instance using the same datadir") expected_msg = f"Error: Cannot obtain a lock on data directory {datadir}. {self.config['environment']['PACKAGE_NAME']} is probably already running." - self.nodes[1].assert_start_raises_init_error(extra_args=[f'-datadir={self.nodes[0].datadir}', '-noserver'], expected_msg=expected_msg) + self.nodes[1].assert_start_raises_init_error(extra_args=[f'-datadir={self.nodes[0].datadir_path}', '-noserver'], expected_msg=expected_msg) if self.is_wallet_compiled(): def check_wallet_filelock(descriptors): diff --git a/test/functional/feature_loadblock.py b/test/functional/feature_loadblock.py index 12d65fde68..5129e0d328 100755 --- a/test/functional/feature_loadblock.py +++ b/test/functional/feature_loadblock.py @@ -10,7 +10,7 @@ in contrib/linearize. """ -import os +from pathlib import Path import subprocess import sys import tempfile @@ -32,10 +32,10 @@ def run_test(self): self.generate(self.nodes[0], COINBASE_MATURITY, sync_fun=self.no_op) # Parsing the url of our node to get settings for config file - data_dir = self.nodes[0].datadir + data_dir = self.nodes[0].datadir_path node_url = urllib.parse.urlparse(self.nodes[0].url) - cfg_file = os.path.join(data_dir, "linearize.cfg") - bootstrap_file = os.path.join(self.options.tmpdir, "bootstrap.dat") + cfg_file = data_dir / "linearize.cfg" + bootstrap_file = Path(self.options.tmpdir) / "bootstrap.dat" genesis_block = self.nodes[0].getblockhash(0) blocks_dir = self.nodes[0].blocks_path hash_list = tempfile.NamedTemporaryFile(dir=data_dir, @@ -58,16 +58,16 @@ def run_test(self): cfg.write(f"hashlist={hash_list.name}\n") base_dir = self.config["environment"]["SRCDIR"] - linearize_dir = os.path.join(base_dir, "contrib", "linearize") + linearize_dir = Path(base_dir) / "contrib" / "linearize" self.log.info("Run linearization of block hashes") - linearize_hashes_file = os.path.join(linearize_dir, "linearize-hashes.py") + linearize_hashes_file = linearize_dir / "linearize-hashes.py" subprocess.run([sys.executable, linearize_hashes_file, cfg_file], stdout=hash_list, check=True) self.log.info("Run linearization of block data") - linearize_data_file = os.path.join(linearize_dir, "linearize-data.py") + linearize_data_file = linearize_dir / "linearize-data.py" subprocess.run([sys.executable, linearize_data_file, cfg_file], check=True) diff --git a/test/functional/feature_settings.py b/test/functional/feature_settings.py index bcae963428..1bacdd447a 100755 --- a/test/functional/feature_settings.py +++ b/test/functional/feature_settings.py @@ -6,7 +6,6 @@ import json -from pathlib import Path from test_framework.test_framework import BitcoinTestFramework from test_framework.test_node import ErrorMatch @@ -21,8 +20,8 @@ def set_test_params(self): def run_test(self): node, = self.nodes - settings = Path(node.chain_path, "settings.json") - conf = Path(node.datadir, "bitcoin.conf") + settings = node.chain_path / "settings.json" + conf = node.datadir_path / "bitcoin.conf" # Assert empty settings file was created self.stop_node(0) @@ -79,7 +78,7 @@ def run_test(self): self.stop_node(0) # Test alternate settings path - altsettings = Path(node.datadir, "altsettings.json") + altsettings = node.datadir_path / "altsettings.json" with altsettings.open("w") as fp: fp.write('{"key": "value"}') with node.assert_debug_log(expected_msgs=['Setting file arg: key = "value"']): diff --git a/test/functional/interface_bitcoin_cli.py b/test/functional/interface_bitcoin_cli.py index 25ea557217..83bb5121e5 100755 --- a/test/functional/interface_bitcoin_cli.py +++ b/test/functional/interface_bitcoin_cli.py @@ -94,7 +94,7 @@ def run_test(self): assert_equal(self.nodes[0].cli("-named", "echo", "arg0=0", "arg1=1", "arg2=2", "arg1=3").send_cli(), ['0', '3', '2']) assert_raises_rpc_error(-8, "Parameter args specified multiple times", self.nodes[0].cli("-named", "echo", "args=[0,1,2,3]", "4", "5", "6", ).send_cli) - user, password = get_auth_cookie(self.nodes[0].datadir, self.chain) + user, password = get_auth_cookie(self.nodes[0].datadir_path, self.chain) self.log.info("Test -stdinrpcpass option") assert_equal(BLOCKS, self.nodes[0].cli(f'-rpcuser={user}', '-stdinrpcpass', input=password).getblockcount()) diff --git a/test/functional/rpc_bind.py b/test/functional/rpc_bind.py index 664a15a5ec..43cd23fc7a 100755 --- a/test/functional/rpc_bind.py +++ b/test/functional/rpc_bind.py @@ -56,7 +56,7 @@ def run_allowip_test(self, allow_ips, rpchost, rpcport): self.nodes[0].rpchost = None self.start_nodes([node_args]) # connect to node through non-loopback interface - node = get_rpc_proxy(rpc_url(self.nodes[0].datadir, 0, self.chain, "%s:%d" % (rpchost, rpcport)), 0, coveragedir=self.options.coveragedir) + node = get_rpc_proxy(rpc_url(self.nodes[0].datadir_path, 0, self.chain, "%s:%d" % (rpchost, rpcport)), 0, coveragedir=self.options.coveragedir) node.getnetworkinfo() self.stop_nodes() diff --git a/test/functional/rpc_dumptxoutset.py b/test/functional/rpc_dumptxoutset.py index 2cae602cc2..f378878181 100755 --- a/test/functional/rpc_dumptxoutset.py +++ b/test/functional/rpc_dumptxoutset.py @@ -4,7 +4,6 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test the generation of UTXO snapshots using `dumptxoutset`. """ -from pathlib import Path from test_framework.blocktools import COINBASE_MATURITY from test_framework.test_framework import BitcoinTestFramework @@ -29,7 +28,7 @@ def run_test(self): FILENAME = 'txoutset.dat' out = node.dumptxoutset(FILENAME) - expected_path = Path(node.datadir) / self.chain / FILENAME + expected_path = node.datadir_path / self.chain / FILENAME assert expected_path.is_file() diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index c46c04c0ec..50444b95bb 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -1006,5 +1006,5 @@ def is_bdb_compiled(self): return self.config["components"].getboolean("USE_BDB") def has_blockfile(self, node, filenum: str): - blocksdir = os.path.join(node.datadir, self.chain, 'blocks', '') - return os.path.isfile(os.path.join(blocksdir, f"blk{filenum}.dat")) + blocksdir = node.datadir_path / self.chain / 'blocks' + return (blocksdir / f"blk{filenum}.dat").is_file() diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index 33a7539641..fc92aa445a 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -67,7 +67,7 @@ class TestNode(): To make things easier for the test writer, any unrecognised messages will be dispatched to the RPC connection.""" - def __init__(self, i, datadir, *, chain, rpchost, timewait, timeout_factor, bitcoind, bitcoin_cli, coverage_dir, cwd, extra_conf=None, extra_args=None, use_cli=False, start_perf=False, use_valgrind=False, version=None, descriptors=False): + def __init__(self, i, datadir_path, *, chain, rpchost, timewait, timeout_factor, bitcoind, bitcoin_cli, coverage_dir, cwd, extra_conf=None, extra_args=None, use_cli=False, start_perf=False, use_valgrind=False, version=None, descriptors=False): """ Kwargs: start_perf (bool): If True, begin profiling the node with `perf` as soon as @@ -76,10 +76,10 @@ def __init__(self, i, datadir, *, chain, rpchost, timewait, timeout_factor, bitc self.index = i self.p2p_conn_index = 1 - self.datadir = datadir - self.bitcoinconf = os.path.join(self.datadir, "bitcoin.conf") - self.stdout_dir = os.path.join(self.datadir, "stdout") - self.stderr_dir = os.path.join(self.datadir, "stderr") + self.datadir_path = datadir_path + self.bitcoinconf = self.datadir_path / "bitcoin.conf" + self.stdout_dir = self.datadir_path / "stdout" + self.stderr_dir = self.datadir_path / "stderr" self.chain = chain self.rpchost = rpchost self.rpc_timeout = timewait @@ -88,7 +88,7 @@ def __init__(self, i, datadir, *, chain, rpchost, timewait, timeout_factor, bitc self.cwd = cwd self.descriptors = descriptors if extra_conf is not None: - append_config(datadir, extra_conf) + append_config(self.datadir_path, extra_conf) # Most callers will just need to add extra args to the standard list below. # For those callers that need more flexibility, they can just set the args property directly. # Note that common args are set in the config file (see initialize_datadir) @@ -99,7 +99,7 @@ def __init__(self, i, datadir, *, chain, rpchost, timewait, timeout_factor, bitc # spam debug.log. self.args = [ self.binary, - "-datadir=" + self.datadir, + f"-datadir={self.datadir_path}", "-logtimemicros", "-debug", "-debugexclude=libevent", @@ -111,9 +111,7 @@ def __init__(self, i, datadir, *, chain, rpchost, timewait, timeout_factor, bitc self.args.append("-disablewallet") if use_valgrind: - default_suppressions_file = os.path.join( - os.path.dirname(os.path.realpath(__file__)), - "..", "..", "..", "contrib", "valgrind.supp") + default_suppressions_file = Path(__file__).parents[3] / "contrib" / "valgrind.supp" suppressions_file = os.getenv("VALGRIND_SUPPRESSIONS_FILE", default_suppressions_file) self.args = ["valgrind", "--suppressions={}".format(suppressions_file), @@ -127,7 +125,7 @@ def __init__(self, i, datadir, *, chain, rpchost, timewait, timeout_factor, bitc if self.version_is_at_least(239000): self.args.append("-loglevel=trace") - self.cli = TestNodeCLI(bitcoin_cli, self.datadir) + self.cli = TestNodeCLI(bitcoin_cli, self.datadir_path) self.use_cli = use_cli self.start_perf = start_perf @@ -213,7 +211,7 @@ def start(self, extra_args=None, *, cwd=None, stdout=None, stderr=None, env=None # Delete any existing cookie file -- if such a file exists (eg due to # unclean shutdown), it will get overwritten anyway by bitcoind, and # potentially interfere with our attempt to authenticate - delete_cookie_file(self.datadir, self.chain) + delete_cookie_file(self.datadir_path, self.chain) # add environment variable LIBC_FATAL_STDERR_=1 so that libc errors are written to stderr and not the terminal subp_env = dict(os.environ, LIBC_FATAL_STDERR_="1") @@ -243,7 +241,7 @@ def wait_for_rpc_connection(self): f'bitcoind exited with status {self.process.returncode} during initialization. {str_error}')) try: rpc = get_rpc_proxy( - rpc_url(self.datadir, self.index, self.chain, self.rpchost), + rpc_url(self.datadir_path, self.index, self.chain, self.rpchost), self.index, timeout=self.rpc_timeout // 2, # Shorter timeout to allow for one retry in case of ETIMEDOUT coveragedir=self.coverage_dir, @@ -307,7 +305,7 @@ def wait_for_cookie_credentials(self): poll_per_s = 4 for _ in range(poll_per_s * self.rpc_timeout): try: - get_auth_cookie(self.datadir, self.chain) + get_auth_cookie(self.datadir_path, self.chain) self.log.debug("Cookie credentials successfully retrieved") return except ValueError: # cookie file not found and no rpcuser or rpcpassword; bitcoind is still starting @@ -424,10 +422,6 @@ def replace_in_config(self, replacements): with open(self.bitcoinconf, 'w', encoding='utf8') as conf: conf.write(conf_data) - @property - def datadir_path(self) -> Path: - return Path(self.datadir) - @property def chain_path(self) -> Path: return self.datadir_path / self.chain @@ -556,7 +550,7 @@ def test_success(cmd): "perf output won't be very useful without debug symbols compiled into bitcoind") output_path = tempfile.NamedTemporaryFile( - dir=self.datadir, + dir=self.datadir_path, prefix="{}.perf.data.".format(profile_name or 'test'), delete=False, ).name @@ -783,7 +777,7 @@ def send_cli(self, command=None, *args, **kwargs): """Run bitcoin-cli command. Deserializes returned string as python object.""" pos_args = [arg_to_cli(arg) for arg in args] named_args = [str(key) + "=" + arg_to_cli(value) for (key, value) in kwargs.items()] - p_args = [self.binary, "-datadir=" + self.datadir] + self.options + p_args = [self.binary, f"-datadir={self.datadir}"] + self.options if named_args: p_args += ["-named"] if command is not None: diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py index 0c10d500af..61346e9d19 100644 --- a/test/functional/test_framework/util.py +++ b/test/functional/test_framework/util.py @@ -413,7 +413,7 @@ def write_config(config_path, *, n, chain, extra_config="", disable_autoconnect= def get_datadir_path(dirname, n): - return os.path.join(dirname, "node" + str(n)) + return pathlib.Path(dirname) / f"node{n}" def get_temp_default_datadir(temp_dir: pathlib.Path) -> Tuple[dict, pathlib.Path]: diff --git a/test/functional/tool_wallet.py b/test/functional/tool_wallet.py index 8b0c8ce405..fc042bca66 100755 --- a/test/functional/tool_wallet.py +++ b/test/functional/tool_wallet.py @@ -32,7 +32,7 @@ def skip_test_if_missing_module(self): self.skip_if_no_wallet_tool() def bitcoin_wallet_process(self, *args): - default_args = ['-datadir={}'.format(self.nodes[0].datadir), '-chain=%s' % self.chain] + default_args = ['-datadir={}'.format(self.nodes[0].datadir_path), '-chain=%s' % self.chain] if not self.options.descriptors and 'create' in args: default_args.append('-legacy') @@ -153,8 +153,8 @@ def assert_dump(self, expected, received): assert_equal(v, r[k]) def do_tool_createfromdump(self, wallet_name, dumpfile, file_format=None): - dumppath = os.path.join(self.nodes[0].datadir, dumpfile) - rt_dumppath = os.path.join(self.nodes[0].datadir, "rt-{}.dump".format(wallet_name)) + dumppath = self.nodes[0].datadir_path / dumpfile + rt_dumppath = self.nodes[0].datadir_path / "rt-{}.dump".format(wallet_name) dump_data = self.read_dump(dumppath) @@ -324,7 +324,7 @@ def test_dump_createfromdump(self): self.assert_raises_tool_error('No dump file provided. To use dump, -dumpfile= must be provided.', '-wallet=todump', 'dump') self.log.info('Checking basic dump') - wallet_dump = os.path.join(self.nodes[0].datadir, "wallet.dump") + wallet_dump = self.nodes[0].datadir_path / "wallet.dump" self.assert_tool_output('The dumpfile may contain private keys. To ensure the safety of your Bitcoin, do not share the dumpfile.\n', '-wallet=todump', '-dumpfile={}'.format(wallet_dump), 'dump') dump_data = self.read_dump(wallet_dump) @@ -339,7 +339,7 @@ def test_dump_createfromdump(self): self.log.info('Checking createfromdump arguments') self.assert_raises_tool_error('No dump file provided. To use createfromdump, -dumpfile= must be provided.', '-wallet=todump', 'createfromdump') - non_exist_dump = os.path.join(self.nodes[0].datadir, "wallet.nodump") + non_exist_dump = self.nodes[0].datadir_path / "wallet.nodump" self.assert_raises_tool_error('Unknown wallet file format "notaformat" provided. Please provide one of "bdb" or "sqlite".', '-wallet=todump', '-format=notaformat', '-dumpfile={}'.format(wallet_dump), 'createfromdump') self.assert_raises_tool_error('Dump file {} does not exist.'.format(non_exist_dump), '-wallet=todump', '-dumpfile={}'.format(non_exist_dump), 'createfromdump') wallet_path = self.nodes[0].wallets_path / "todump2" @@ -354,17 +354,17 @@ def test_dump_createfromdump(self): self.do_tool_createfromdump("load-sqlite", "wallet.dump", "sqlite") self.log.info('Checking createfromdump handling of magic and versions') - bad_ver_wallet_dump = os.path.join(self.nodes[0].datadir, "wallet-bad_ver1.dump") + bad_ver_wallet_dump = self.nodes[0].datadir_path / "wallet-bad_ver1.dump" dump_data["BITCOIN_CORE_WALLET_DUMP"] = "0" self.write_dump(dump_data, bad_ver_wallet_dump) self.assert_raises_tool_error('Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version 0', '-wallet=badload', '-dumpfile={}'.format(bad_ver_wallet_dump), 'createfromdump') assert not (self.nodes[0].wallets_path / "badload").is_dir() - bad_ver_wallet_dump = os.path.join(self.nodes[0].datadir, "wallet-bad_ver2.dump") + bad_ver_wallet_dump = self.nodes[0].datadir_path / "wallet-bad_ver2.dump" dump_data["BITCOIN_CORE_WALLET_DUMP"] = "2" self.write_dump(dump_data, bad_ver_wallet_dump) self.assert_raises_tool_error('Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version 2', '-wallet=badload', '-dumpfile={}'.format(bad_ver_wallet_dump), 'createfromdump') assert not (self.nodes[0].wallets_path / "badload").is_dir() - bad_magic_wallet_dump = os.path.join(self.nodes[0].datadir, "wallet-bad_magic.dump") + bad_magic_wallet_dump = self.nodes[0].datadir_path / "wallet-bad_magic.dump" del dump_data["BITCOIN_CORE_WALLET_DUMP"] dump_data["not_the_right_magic"] = "1" self.write_dump(dump_data, bad_magic_wallet_dump, "not_the_right_magic") @@ -372,19 +372,19 @@ def test_dump_createfromdump(self): assert not (self.nodes[0].wallets_path / "badload").is_dir() self.log.info('Checking createfromdump handling of checksums') - bad_sum_wallet_dump = os.path.join(self.nodes[0].datadir, "wallet-bad_sum1.dump") + bad_sum_wallet_dump = self.nodes[0].datadir_path / "wallet-bad_sum1.dump" dump_data = orig_dump.copy() checksum = dump_data["checksum"] dump_data["checksum"] = "1" * 64 self.write_dump(dump_data, bad_sum_wallet_dump) self.assert_raises_tool_error('Error: Dumpfile checksum does not match. Computed {}, expected {}'.format(checksum, "1" * 64), '-wallet=bad', '-dumpfile={}'.format(bad_sum_wallet_dump), 'createfromdump') assert not (self.nodes[0].wallets_path / "badload").is_dir() - bad_sum_wallet_dump = os.path.join(self.nodes[0].datadir, "wallet-bad_sum2.dump") + bad_sum_wallet_dump = self.nodes[0].datadir_path / "wallet-bad_sum2.dump" del dump_data["checksum"] self.write_dump(dump_data, bad_sum_wallet_dump, skip_checksum=True) self.assert_raises_tool_error('Error: Missing checksum', '-wallet=badload', '-dumpfile={}'.format(bad_sum_wallet_dump), 'createfromdump') assert not (self.nodes[0].wallets_path / "badload").is_dir() - bad_sum_wallet_dump = os.path.join(self.nodes[0].datadir, "wallet-bad_sum3.dump") + bad_sum_wallet_dump = self.nodes[0].datadir_path / "wallet-bad_sum3.dump" dump_data["checksum"] = "2" * 10 self.write_dump(dump_data, bad_sum_wallet_dump) self.assert_raises_tool_error('Error: Checksum is not the correct size', '-wallet=badload', '-dumpfile={}'.format(bad_sum_wallet_dump), 'createfromdump') @@ -452,7 +452,7 @@ def test_chainless_conflicts(self): self.assert_tool_output(expected_output, "-wallet=conflicts", "info") def run_test(self): - self.wallet_path = os.path.join(self.nodes[0].wallets_path, self.default_wallet_name, self.wallet_data_filename) + self.wallet_path = self.nodes[0].wallets_path / self.default_wallet_name / self.wallet_data_filename self.test_invalid_tool_commands_and_args() # Warning: The following tests are order-dependent. self.test_tool_wallet_info() diff --git a/test/functional/wallet_backup.py b/test/functional/wallet_backup.py index 9f6f54c7a6..eb3e0ae728 100755 --- a/test/functional/wallet_backup.py +++ b/test/functional/wallet_backup.py @@ -109,36 +109,35 @@ def stop_three(self): self.stop_node(2) def erase_three(self): - os.remove(os.path.join(self.nodes[0].wallets_path, self.default_wallet_name, self.wallet_data_filename)) - os.remove(os.path.join(self.nodes[1].wallets_path, self.default_wallet_name, self.wallet_data_filename)) - os.remove(os.path.join(self.nodes[2].wallets_path, self.default_wallet_name, self.wallet_data_filename)) + for node_num in range(3): + (self.nodes[node_num].wallets_path / self.default_wallet_name / self.wallet_data_filename).unlink() def restore_invalid_wallet(self): node = self.nodes[3] - invalid_wallet_file = os.path.join(self.nodes[0].datadir, 'invalid_wallet_file.bak') + invalid_wallet_file = self.nodes[0].datadir_path / 'invalid_wallet_file.bak' open(invalid_wallet_file, 'a', encoding="utf8").write('invald wallet') wallet_name = "res0" - not_created_wallet_file = os.path.join(node.wallets_path, wallet_name) + not_created_wallet_file = node.wallets_path / wallet_name error_message = "Wallet file verification failed. Failed to load database path '{}'. Data is not in recognized format.".format(not_created_wallet_file) assert_raises_rpc_error(-18, error_message, node.restorewallet, wallet_name, invalid_wallet_file) - assert not os.path.exists(not_created_wallet_file) + assert not not_created_wallet_file.exists() def restore_nonexistent_wallet(self): node = self.nodes[3] - nonexistent_wallet_file = os.path.join(self.nodes[0].datadir, 'nonexistent_wallet.bak') + nonexistent_wallet_file = self.nodes[0].datadir_path / 'nonexistent_wallet.bak' wallet_name = "res0" assert_raises_rpc_error(-8, "Backup file does not exist", node.restorewallet, wallet_name, nonexistent_wallet_file) - not_created_wallet_file = os.path.join(node.wallets_path, wallet_name) - assert not os.path.exists(not_created_wallet_file) + not_created_wallet_file = node.wallets_path / wallet_name + assert not not_created_wallet_file.exists() def restore_wallet_existent_name(self): node = self.nodes[3] - backup_file = os.path.join(self.nodes[0].datadir, 'wallet.bak') + backup_file = self.nodes[0].datadir_path / 'wallet.bak' wallet_name = "res0" - wallet_file = os.path.join(node.wallets_path, wallet_name) + wallet_file = node.wallets_path / wallet_name error_message = "Failed to create database path '{}'. Database already exists.".format(wallet_file) assert_raises_rpc_error(-36, error_message, node.restorewallet, wallet_name, backup_file) - assert os.path.exists(wallet_file) + assert wallet_file.exists() def run_test(self): self.log.info("Generating initial blockchain") @@ -159,14 +158,12 @@ def run_test(self): self.log.info("Backing up") - self.nodes[0].backupwallet(os.path.join(self.nodes[0].datadir, 'wallet.bak')) - self.nodes[1].backupwallet(os.path.join(self.nodes[1].datadir, 'wallet.bak')) - self.nodes[2].backupwallet(os.path.join(self.nodes[2].datadir, 'wallet.bak')) + for node_num in range(3): + self.nodes[node_num].backupwallet(self.nodes[node_num].datadir_path / 'wallet.bak') if not self.options.descriptors: - self.nodes[0].dumpwallet(os.path.join(self.nodes[0].datadir, 'wallet.dump')) - self.nodes[1].dumpwallet(os.path.join(self.nodes[1].datadir, 'wallet.dump')) - self.nodes[2].dumpwallet(os.path.join(self.nodes[2].datadir, 'wallet.dump')) + for node_num in range(3): + self.nodes[node_num].dumpwallet(self.nodes[node_num].datadir_path / 'wallet.dump') self.log.info("More transactions") for _ in range(5): @@ -193,17 +190,13 @@ def run_test(self): self.restore_invalid_wallet() self.restore_nonexistent_wallet() - backup_file_0 = os.path.join(self.nodes[0].datadir, 'wallet.bak') - backup_file_1 = os.path.join(self.nodes[1].datadir, 'wallet.bak') - backup_file_2 = os.path.join(self.nodes[2].datadir, 'wallet.bak') - - self.nodes[3].restorewallet("res0", backup_file_0) - self.nodes[3].restorewallet("res1", backup_file_1) - self.nodes[3].restorewallet("res2", backup_file_2) + backup_files = [] + for node_num in range(3): + backup_files.append(self.nodes[node_num].datadir_path / 'wallet.bak') - assert os.path.exists(os.path.join(self.nodes[3].wallets_path, "res0")) - assert os.path.exists(os.path.join(self.nodes[3].wallets_path, "res1")) - assert os.path.exists(os.path.join(self.nodes[3].wallets_path, "res2")) + for idx, backup_file in enumerate(backup_files): + self.nodes[3].restorewallet(f'res{idx}', backup_file) + assert (self.nodes[3].wallets_path / f'res{idx}').exists() res0_rpc = self.nodes[3].get_wallet_rpc("res0") res1_rpc = self.nodes[3].get_wallet_rpc("res1") @@ -221,22 +214,16 @@ def run_test(self): self.erase_three() #start node2 with no chain - shutil.rmtree(os.path.join(self.nodes[2].blocks_path)) - shutil.rmtree(os.path.join(self.nodes[2].chain_path, 'chainstate')) + shutil.rmtree(self.nodes[2].blocks_path) + shutil.rmtree(self.nodes[2].chain_path / 'chainstate') self.start_three(["-nowallet"]) # Create new wallets for the three nodes. # We will use this empty wallets to test the 'importwallet()' RPC command below. for node_num in range(3): self.nodes[node_num].createwallet(wallet_name=self.default_wallet_name, descriptors=self.options.descriptors, load_on_startup=True) - - assert_equal(self.nodes[0].getbalance(), 0) - assert_equal(self.nodes[1].getbalance(), 0) - assert_equal(self.nodes[2].getbalance(), 0) - - self.nodes[0].importwallet(os.path.join(self.nodes[0].datadir, 'wallet.dump')) - self.nodes[1].importwallet(os.path.join(self.nodes[1].datadir, 'wallet.dump')) - self.nodes[2].importwallet(os.path.join(self.nodes[2].datadir, 'wallet.dump')) + assert_equal(self.nodes[node_num].getbalance(), 0) + self.nodes[node_num].importwallet(self.nodes[node_num].datadir_path / 'wallet.dump') self.sync_blocks() diff --git a/test/functional/wallet_blank.py b/test/functional/wallet_blank.py index 4836eba3b2..e646d27005 100755 --- a/test/functional/wallet_blank.py +++ b/test/functional/wallet_blank.py @@ -3,7 +3,6 @@ # Distributed under the MIT software license, see the accompanying # file COPYING or https://www.opensource.org/licenses/mit-license.php. -import os from test_framework.test_framework import BitcoinTestFramework from test_framework.address import ( @@ -110,7 +109,7 @@ def test_importwallet(self): assert_equal(info["descriptors"], False) assert_equal(info["blank"], True) - wallet_dump_path = os.path.join(self.nodes[0].datadir, "wallet.dump") + wallet_dump_path = self.nodes[0].datadir_path / "wallet.dump" def_wallet.dumpwallet(wallet_dump_path) wallet.importwallet(wallet_dump_path) diff --git a/test/functional/wallet_crosschain.py b/test/functional/wallet_crosschain.py index 7a1297e65f..4c5d7192ae 100755 --- a/test/functional/wallet_crosschain.py +++ b/test/functional/wallet_crosschain.py @@ -3,8 +3,6 @@ # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. -import os - from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_raises_rpc_error @@ -31,13 +29,13 @@ def setup_network(self): def run_test(self): self.log.info("Creating wallets") - node0_wallet = os.path.join(self.nodes[0].datadir, 'node0_wallet') - node0_wallet_backup = os.path.join(self.nodes[0].datadir, 'node0_wallet.bak') + node0_wallet = self.nodes[0].datadir_path / 'node0_wallet' + node0_wallet_backup = self.nodes[0].datadir_path / 'node0_wallet.bak' self.nodes[0].createwallet(node0_wallet) self.nodes[0].backupwallet(node0_wallet_backup) self.nodes[0].unloadwallet(node0_wallet) - node1_wallet = os.path.join(self.nodes[1].datadir, 'node1_wallet') - node1_wallet_backup = os.path.join(self.nodes[0].datadir, 'node1_wallet.bak') + node1_wallet = self.nodes[1].datadir_path / 'node1_wallet' + node1_wallet_backup = self.nodes[0].datadir_path / 'node1_wallet.bak' self.nodes[1].createwallet(node1_wallet) self.nodes[1].backupwallet(node1_wallet_backup) self.nodes[1].unloadwallet(node1_wallet) diff --git a/test/functional/wallet_descriptor.py b/test/functional/wallet_descriptor.py index 6af01f8cfd..c220675eb6 100755 --- a/test/functional/wallet_descriptor.py +++ b/test/functional/wallet_descriptor.py @@ -3,7 +3,6 @@ # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test descriptor wallet function.""" -import os try: import sqlite3 @@ -234,7 +233,7 @@ def run_test(self): self.log.info("Test that loading descriptor wallet containing legacy key types throws error") self.nodes[0].createwallet(wallet_name="crashme", descriptors=True) self.nodes[0].unloadwallet("crashme") - wallet_db = os.path.join(self.nodes[0].wallets_path, "crashme", self.wallet_data_filename) + wallet_db = self.nodes[0].wallets_path / "crashme" / self.wallet_data_filename conn = sqlite3.connect(wallet_db) with conn: # add "cscript" entry: key type is uint160 (20 bytes), value type is CScript (zero-length here) diff --git a/test/functional/wallet_dump.py b/test/functional/wallet_dump.py index 8c68d03f97..fdce9739eb 100755 --- a/test/functional/wallet_dump.py +++ b/test/functional/wallet_dump.py @@ -4,7 +4,6 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test the dumpwallet RPC.""" import datetime -import os import time from test_framework.test_framework import BitcoinTestFramework @@ -111,8 +110,8 @@ def setup_network(self): def run_test(self): self.nodes[0].createwallet("dump") - wallet_unenc_dump = os.path.join(self.nodes[0].datadir, "wallet.unencrypted.dump") - wallet_enc_dump = os.path.join(self.nodes[0].datadir, "wallet.encrypted.dump") + wallet_unenc_dump = self.nodes[0].datadir_path / "wallet.unencrypted.dump" + wallet_enc_dump = self.nodes[0].datadir_path / "wallet.encrypted.dump" # generate 30 addresses to compare against the dump # - 10 legacy P2PKH @@ -156,7 +155,7 @@ def run_test(self): self.log.info('Dump unencrypted wallet') result = self.nodes[0].dumpwallet(wallet_unenc_dump) - assert_equal(result['filename'], wallet_unenc_dump) + assert_equal(result['filename'], str(wallet_unenc_dump)) found_comments, found_legacy_addr, found_p2sh_segwit_addr, found_bech32_addr, found_script_addr, found_addr_chg, found_addr_rsv, hd_master_addr_unenc = \ read_dump(wallet_unenc_dump, addrs, [multisig_addr], None) @@ -220,7 +219,7 @@ def run_test(self): w3.sendtoaddress(w3.getnewaddress(), 10) w3.unloadwallet() self.nodes[0].loadwallet("w3") - w3.dumpwallet(os.path.join(self.nodes[0].datadir, "w3.dump")) + w3.dumpwallet(self.nodes[0].datadir_path / "w3.dump") if __name__ == '__main__': WalletDumpTest().main() diff --git a/test/functional/wallet_fast_rescan.py b/test/functional/wallet_fast_rescan.py index 112aa25e86..2f9c924e71 100755 --- a/test/functional/wallet_fast_rescan.py +++ b/test/functional/wallet_fast_rescan.py @@ -4,7 +4,6 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test that fast rescan using block filters for descriptor wallets detects top-ups correctly and finds the same transactions than the slow variant.""" -import os from typing import List from test_framework.address import address_to_scriptpubkey @@ -43,7 +42,7 @@ def run_test(self): wallet = MiniWallet(node) self.log.info("Create descriptor wallet with backup") - WALLET_BACKUP_FILENAME = os.path.join(node.datadir, 'wallet.bak') + WALLET_BACKUP_FILENAME = node.datadir_path / 'wallet.bak' node.createwallet(wallet_name='topup_test', descriptors=True) w = node.get_wallet_rpc('topup_test') fixed_key = get_generate_key() diff --git a/test/functional/wallet_hd.py b/test/functional/wallet_hd.py index 62f8301c16..0f4b7cfcb1 100755 --- a/test/functional/wallet_hd.py +++ b/test/functional/wallet_hd.py @@ -4,7 +4,6 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test Hierarchical Deterministic wallet function.""" -import os import shutil from test_framework.blocktools import COINBASE_MATURITY @@ -51,8 +50,8 @@ def run_test(self): self.nodes[1].importprivkey(non_hd_key) # This should be enough to keep the master key and the non-HD key - self.nodes[1].backupwallet(os.path.join(self.nodes[1].datadir, "hd.bak")) - #self.nodes[1].dumpwallet(os.path.join(self.nodes[1].datadir, "hd.dump")) + self.nodes[1].backupwallet(self.nodes[1].datadir_path / "hd.bak") + #self.nodes[1].dumpwallet(self.nodes[1].datadir_path / "hd.dump") # Derive some HD addresses and remember the last # Also send funds to each add @@ -87,11 +86,11 @@ def run_test(self): self.stop_node(1) # we need to delete the complete chain directory # otherwise node1 would auto-recover all funds in flag the keypool keys as used - shutil.rmtree(os.path.join(self.nodes[1].blocks_path)) - shutil.rmtree(os.path.join(self.nodes[1].chain_path, "chainstate")) + shutil.rmtree(self.nodes[1].blocks_path) + shutil.rmtree(self.nodes[1].chain_path / "chainstate") shutil.copyfile( - os.path.join(self.nodes[1].datadir, "hd.bak"), - os.path.join(self.nodes[1].wallets_path, self.default_wallet_name, self.wallet_data_filename), + self.nodes[1].datadir_path / "hd.bak", + self.nodes[1].wallets_path / self.default_wallet_name / self.wallet_data_filename ) self.start_node(1) @@ -115,11 +114,11 @@ def run_test(self): # Try a RPC based rescan self.stop_node(1) - shutil.rmtree(os.path.join(self.nodes[1].blocks_path)) - shutil.rmtree(os.path.join(self.nodes[1].chain_path, "chainstate")) + shutil.rmtree(self.nodes[1].blocks_path) + shutil.rmtree(self.nodes[1].chain_path / "chainstate") shutil.copyfile( - os.path.join(self.nodes[1].datadir, "hd.bak"), - os.path.join(self.nodes[1].wallets_path, self.default_wallet_name, self.wallet_data_filename), + self.nodes[1].datadir_path / "hd.bak", + self.nodes[1].wallets_path / self.default_wallet_name / self.wallet_data_filename ) self.start_node(1, extra_args=self.extra_args[1]) self.connect_nodes(0, 1) diff --git a/test/functional/wallet_keypool_topup.py b/test/functional/wallet_keypool_topup.py index 0f1c33a0c2..48180e8294 100755 --- a/test/functional/wallet_keypool_topup.py +++ b/test/functional/wallet_keypool_topup.py @@ -10,7 +10,6 @@ - Generate 110 keys (enough to drain the keypool). Store key 90 (in the initial keypool) and key 110 (beyond the initial keypool). Send funds to key 90 and key 110. - Stop node1, clear the datadir, move wallet file back into the datadir and restart node1. - connect node1 to node0. Verify that they sync and node1 receives its funds.""" -import os import shutil from test_framework.blocktools import COINBASE_MATURITY @@ -33,8 +32,8 @@ def skip_test_if_missing_module(self): self.skip_if_no_wallet() def run_test(self): - wallet_path = os.path.join(self.nodes[1].wallets_path, self.default_wallet_name, self.wallet_data_filename) - wallet_backup_path = os.path.join(self.nodes[1].datadir, "wallet.bak") + wallet_path = self.nodes[1].wallets_path / self.default_wallet_name / self.wallet_data_filename + wallet_backup_path = self.nodes[1].datadir_path / "wallet.bak" self.generate(self.nodes[0], COINBASE_MATURITY + 1) self.log.info("Make backup of wallet") diff --git a/test/functional/wallet_pruning.py b/test/functional/wallet_pruning.py index 06bd992da7..6e252b5406 100755 --- a/test/functional/wallet_pruning.py +++ b/test/functional/wallet_pruning.py @@ -4,7 +4,6 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test wallet import on pruned node.""" -import os from test_framework.util import assert_equal, assert_raises_rpc_error from test_framework.blocktools import ( @@ -74,7 +73,7 @@ def test_wallet_import_pruned(self, wallet_name): # Import wallet into pruned node self.nodes[1].createwallet(wallet_name="wallet_pruned", descriptors=False, load_on_startup=True) - self.nodes[1].importwallet(os.path.join(self.nodes[0].datadir, wallet_file)) + self.nodes[1].importwallet(self.nodes[0].datadir_path / wallet_file) # Make sure that prune node's wallet correctly accounts for balances assert_equal(self.nodes[1].getbalance(), self.nodes[0].getbalance()) @@ -93,12 +92,12 @@ def test_wallet_import_pruned_with_missing_blocks(self, wallet_name): # Make sure wallet cannot be imported because of missing blocks # This will try to rescan blocks `TIMESTAMP_WINDOW` (2h) before the wallet birthheight. # There are 6 blocks an hour, so 11 blocks (excluding birthheight). - assert_raises_rpc_error(-4, f"Pruned blocks from height {wallet_birthheight - 11} required to import keys. Use RPC call getblockchaininfo to determine your pruned height.", self.nodes[1].importwallet, os.path.join(self.nodes[0].datadir, wallet_file)) + assert_raises_rpc_error(-4, f"Pruned blocks from height {wallet_birthheight - 11} required to import keys. Use RPC call getblockchaininfo to determine your pruned height.", self.nodes[1].importwallet, self.nodes[0].datadir_path / wallet_file) self.log.info("- Done") def get_birthheight(self, wallet_file): """Gets birthheight of a wallet on node0""" - with open(os.path.join(self.nodes[0].datadir, wallet_file), 'r', encoding="utf8") as f: + with open(self.nodes[0].datadir_path / wallet_file, 'r', encoding="utf8") as f: for line in f: if line.startswith('# * Best block at time of backup'): wallet_birthheight = int(line.split(' ')[9]) @@ -106,12 +105,12 @@ def get_birthheight(self, wallet_file): def has_block(self, block_index): """Checks if the pruned node has the specific blk0000*.dat file""" - return os.path.isfile(os.path.join(self.nodes[1].blocks_path, f"blk{block_index:05}.dat")) + return (self.nodes[1].blocks_path / f"blk{block_index:05}.dat").is_file() def create_wallet(self, wallet_name, *, unload=False): """Creates and dumps a wallet on the non-pruned node0 to be later import by the pruned node""" self.nodes[0].createwallet(wallet_name=wallet_name, descriptors=False, load_on_startup=True) - self.nodes[0].dumpwallet(os.path.join(self.nodes[0].datadir, wallet_name + ".dat")) + self.nodes[0].dumpwallet(self.nodes[0].datadir_path / f"{wallet_name}.dat") if (unload): self.nodes[0].unloadwallet(wallet_name) diff --git a/test/functional/wallet_reorgsrestore.py b/test/functional/wallet_reorgsrestore.py index af01b9439f..86a2905c72 100755 --- a/test/functional/wallet_reorgsrestore.py +++ b/test/functional/wallet_reorgsrestore.py @@ -14,7 +14,6 @@ """ from decimal import Decimal -import os import shutil from test_framework.test_framework import BitcoinTestFramework @@ -88,8 +87,8 @@ def run_test(self): # Node0 wallet file is loaded on longest sync'ed node1 self.stop_node(1) - self.nodes[0].backupwallet(os.path.join(self.nodes[0].datadir, 'wallet.bak')) - shutil.copyfile(os.path.join(self.nodes[0].datadir, 'wallet.bak'), os.path.join(self.nodes[1].chain_path, self.default_wallet_name, self.wallet_data_filename)) + self.nodes[0].backupwallet(self.nodes[0].datadir_path / 'wallet.bak') + shutil.copyfile(self.nodes[0].datadir_path / 'wallet.bak', self.nodes[1].chain_path / self.default_wallet_name / self.wallet_data_filename) self.start_node(1) tx_after_reorg = self.nodes[1].gettransaction(txid) # Check that normal confirmed tx is confirmed again but with different blockhash From 78d3062b68988f5094c61a845be756788933c752 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Tue, 10 Oct 2023 19:29:18 +0100 Subject: [PATCH 29/41] ci: Install Android API 31 platform as Qt expects --- ci/test/01_base_install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/test/01_base_install.sh b/ci/test/01_base_install.sh index 424dca52dc..c4095e4c1a 100755 --- a/ci/test/01_base_install.sh +++ b/ci/test/01_base_install.sh @@ -98,7 +98,7 @@ if [ -n "$ANDROID_HOME" ] && [ ! -d "$ANDROID_HOME" ]; then fi mkdir -p "$ANDROID_HOME" unzip -o "$ANDROID_TOOLS_PATH" -d "$ANDROID_HOME" - yes | "${ANDROID_HOME}"/cmdline-tools/bin/sdkmanager --sdk_root="${ANDROID_HOME}" --install "build-tools;${ANDROID_BUILD_TOOLS_VERSION}" "platform-tools" "platforms;android-${ANDROID_API_LEVEL}" "ndk;${ANDROID_NDK_VERSION}" + yes | "${ANDROID_HOME}"/cmdline-tools/bin/sdkmanager --sdk_root="${ANDROID_HOME}" --install "build-tools;${ANDROID_BUILD_TOOLS_VERSION}" "platform-tools" "platforms;android-31" "platforms;android-${ANDROID_API_LEVEL}" "ndk;${ANDROID_NDK_VERSION}" fi git config --global ${CFG_DONE} "true" From 3bb51c29df596aab2c1fde184667cee435597715 Mon Sep 17 00:00:00 2001 From: Sebastian Falbesoner Date: Tue, 10 Oct 2023 19:38:59 +0200 Subject: [PATCH 30/41] test: BIP324: add check for missing garbage terminator detection --- test/functional/p2p_v2_transport.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/functional/p2p_v2_transport.py b/test/functional/p2p_v2_transport.py index dd564fed88..99417a17a9 100755 --- a/test/functional/p2p_v2_transport.py +++ b/test/functional/p2p_v2_transport.py @@ -148,6 +148,19 @@ def run_test(self): with self.nodes[0].assert_debug_log("V2 transport error: V1 peer with wrong MessageStart"): s.sendall(wrong_network_magic_prefix + b"somepayload") + # Check detection of missing garbage terminator (hits after fixed amount of data if terminator never matches garbage) + MAX_KEY_GARB_AND_GARBTERM_LEN = 64 + 4095 + 16 + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + num_peers = len(self.nodes[0].getpeerinfo()) + s.connect(("127.0.0.1", p2p_port(0))) + self.wait_until(lambda: len(self.nodes[0].getpeerinfo()) == num_peers + 1) + s.sendall(b'\x00' * (MAX_KEY_GARB_AND_GARBTERM_LEN - 1)) + self.wait_until(lambda: self.nodes[0].getpeerinfo()[-1]["bytesrecv"] == MAX_KEY_GARB_AND_GARBTERM_LEN - 1) + with self.nodes[0].assert_debug_log("V2 transport error: missing garbage terminator"): + s.sendall(b'\x00') # send out last byte + # should disconnect immediately + self.wait_until(lambda: len(self.nodes[0].getpeerinfo()) == num_peers) + if __name__ == '__main__': V2TransportTest().main() From 850670e3d63ed7d04b417a43cb8ab06292aa2c23 Mon Sep 17 00:00:00 2001 From: Sjors Provoost Date: Mon, 21 Aug 2023 12:08:39 +0200 Subject: [PATCH 31/41] test: don't run old binaries under valgrind This is unnecessary and caused test failures. The backward compatibility tests are meant to find regressions in the current codebase, not to detect bugs in older releases. --- test/functional/test_framework/test_framework.py | 2 +- test/functional/test_framework/test_node.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index 50444b95bb..4e6d245b5f 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -185,7 +185,7 @@ def parse_args(self): parser.add_argument("--perf", dest="perf", default=False, action="store_true", help="profile running nodes with perf for the duration of the test") parser.add_argument("--valgrind", dest="valgrind", default=False, action="store_true", - help="run nodes under the valgrind memory error detector: expect at least a ~10x slowdown. valgrind 3.14 or later required.") + help="run nodes under the valgrind memory error detector: expect at least a ~10x slowdown. valgrind 3.14 or later required. Does not apply to previous release binaries.") parser.add_argument("--randomseed", type=int, help="set a random seed for deterministically reproducing a previous test run") parser.add_argument("--timeout-factor", dest="timeout_factor", type=float, help="adjust test timeouts by a factor. Setting it to 0 disables all timeouts") diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index fc92aa445a..4d7adf322c 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -110,7 +110,8 @@ def __init__(self, i, datadir_path, *, chain, rpchost, timewait, timeout_factor, if self.descriptors is None: self.args.append("-disablewallet") - if use_valgrind: + # Use valgrind, expect for previous release binaries + if use_valgrind and version is None: default_suppressions_file = Path(__file__).parents[3] / "contrib" / "valgrind.supp" suppressions_file = os.getenv("VALGRIND_SUPPRESSIONS_FILE", default_suppressions_file) From faa90f6e7b6b8c531e1ae142a5c2f568b48502a9 Mon Sep 17 00:00:00 2001 From: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz> Date: Thu, 12 Oct 2023 11:11:48 +0200 Subject: [PATCH 32/41] refactor: Remove unused nchaintx from SnapshotMetadata constructor Also, remove wrong nChainTx comment and cast. --- src/node/utxo_snapshot.h | 3 +-- src/rpc/blockchain.cpp | 6 ++---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/node/utxo_snapshot.h b/src/node/utxo_snapshot.h index a6dd3f3f13..1160bb55f0 100644 --- a/src/node/utxo_snapshot.h +++ b/src/node/utxo_snapshot.h @@ -35,8 +35,7 @@ class SnapshotMetadata SnapshotMetadata() { } SnapshotMetadata( const uint256& base_blockhash, - uint64_t coins_count, - unsigned int nchaintx) : + uint64_t coins_count) : m_base_blockhash(base_blockhash), m_coins_count(coins_count) { } diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 31dd8164fe..37a28e414a 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -2667,7 +2667,7 @@ UniValue CreateUTXOSnapshot( tip->nHeight, tip->GetBlockHash().ToString(), fs::PathToString(path), fs::PathToString(temppath))); - SnapshotMetadata metadata{tip->GetBlockHash(), maybe_stats->coins_count, tip->nChainTx}; + SnapshotMetadata metadata{tip->GetBlockHash(), maybe_stats->coins_count}; afile << metadata; @@ -2694,9 +2694,7 @@ UniValue CreateUTXOSnapshot( result.pushKV("base_height", tip->nHeight); result.pushKV("path", path.u8string()); result.pushKV("txoutset_hash", maybe_stats->hashSerialized.ToString()); - // Cast required because univalue doesn't have serialization specified for - // `unsigned int`, nChainTx's type. - result.pushKV("nchaintx", uint64_t{tip->nChainTx}); + result.pushKV("nchaintx", tip->nChainTx); return result; } From fafde92f84fb7c245bc3c1cd946a32c891861e5e Mon Sep 17 00:00:00 2001 From: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz> Date: Thu, 12 Oct 2023 11:21:08 +0200 Subject: [PATCH 33/41] test: Check snapshot file with wrong number of coins Also, fix a bug in an assert_debug_log call. --- test/functional/feature_assumeutxo.py | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/test/functional/feature_assumeutxo.py b/test/functional/feature_assumeutxo.py index ea93b7ab88..c900736ae9 100755 --- a/test/functional/feature_assumeutxo.py +++ b/test/functional/feature_assumeutxo.py @@ -40,7 +40,7 @@ assert_equal, assert_raises_rpc_error, ) - +import struct START_HEIGHT = 199 SNAPSHOT_BASE_HEIGHT = 299 @@ -68,23 +68,35 @@ def setup_network(self): def test_invalid_snapshot_scenarios(self, valid_snapshot_path): self.log.info("Test different scenarios of loading invalid snapshot files") - self.log.info(" - snapshot file refering to a block that is not in the assumeutxo parameters") with open(valid_snapshot_path, 'rb') as f: valid_snapshot_contents = f.read() + bad_snapshot_path = valid_snapshot_path + '.mod' + self.log.info(" - snapshot file refering to a block that is not in the assumeutxo parameters") # we can only test this with a block that is already known, as otherwise the `loadtxoutset` RPC # would time out (waiting to see the hash in the headers chain), rather than error immediately bad_snapshot_height = SNAPSHOT_BASE_HEIGHT - 1 - bad_snapshot_path = valid_snapshot_path + '.mod' with open(bad_snapshot_path, 'wb') as f: bad_snapshot_block_hash = self.nodes[0].getblockhash(bad_snapshot_height) # block hash of the snapshot base is stored right at the start (first 32 bytes) f.write(bytes.fromhex(bad_snapshot_block_hash)[::-1] + valid_snapshot_contents[32:]) expected_log = f"assumeutxo height in snapshot metadata not recognized ({bad_snapshot_height}) - refusing to load snapshot" - with self.nodes[1].assert_debug_log(expected_log): + with self.nodes[1].assert_debug_log([expected_log]): assert_raises_rpc_error(-32603, "Unable to load UTXO snapshot", self.nodes[1].loadtxoutset, bad_snapshot_path) + self.log.info(" - snapshot file with wrong number of coins") + valid_num_coins = struct.unpack(" Date: Thu, 12 Oct 2023 11:01:47 +0100 Subject: [PATCH 34/41] ci: Drop no longer needed `NOLINTNEXTLINE` --- src/test/fuzz/miniscript.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/test/fuzz/miniscript.cpp b/src/test/fuzz/miniscript.cpp index 835b6d8c6b..4d054d7458 100644 --- a/src/test/fuzz/miniscript.cpp +++ b/src/test/fuzz/miniscript.cpp @@ -20,8 +20,6 @@ using NodeRef = miniscript::NodeRef; using Node = miniscript::Node; using Type = miniscript::Type; using MsCtx = miniscript::MiniscriptContext; -// https://github.com/llvm/llvm-project/issues/53444 -// NOLINTNEXTLINE(misc-unused-using-decls) using miniscript::operator"" _mst; //! Some pre-computed data for more efficient string roundtrips and to simulate challenges. From fa2843eba4f195fcc9fdda2d3673fae0d7fc6282 Mon Sep 17 00:00:00 2001 From: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz> Date: Thu, 12 Oct 2023 11:54:31 +0200 Subject: [PATCH 35/41] ci: Bump asan --- .cirrus.yml | 4 ++-- ci/test/00_setup_env_native_asan.sh | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index 96357a103d..3f52adde8a 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -43,7 +43,7 @@ env: # Global defaults # The following specific types should exist, with the following requirements: # - small: For an x86_64 machine, recommended to have 2 CPUs and 8 GB of memory. # - medium: For an x86_64 machine, recommended to have 4 CPUs and 16 GB of memory. -# - lunar: For a machine running the Linux kernel shipped with Ubuntu Lunar 23.04. The machine is recommended to have 4 CPUs and 16 GB of memory. +# - mantic: For a machine running the Linux kernel shipped with exaclty Ubuntu Mantic 23.10. The machine is recommended to have 4 CPUs and 16 GB of memory. # - arm64: For an aarch64 machine, recommended to have 2 CPUs and 8 GB of memory. # https://cirrus-ci.org/guide/tips-and-tricks/#sharing-configuration-between-tasks @@ -165,7 +165,7 @@ task: << : *GLOBAL_TASK_TEMPLATE persistent_worker: labels: - type: lunar # Must use the lunar-specific worker (needed for USDT functional tests) + type: mantic # Must use this specific worker (needed for USDT functional tests) env: FILE_ENV: "./ci/test/00_setup_env_native_asan.sh" diff --git a/ci/test/00_setup_env_native_asan.sh b/ci/test/00_setup_env_native_asan.sh index 0f69ebdd9c..93d84bf17e 100755 --- a/ci/test/00_setup_env_native_asan.sh +++ b/ci/test/00_setup_env_native_asan.sh @@ -16,11 +16,11 @@ else fi export CONTAINER_NAME=ci_native_asan -export PACKAGES="systemtap-sdt-dev clang-16 llvm-16 libclang-rt-16-dev python3-zmq qtbase5-dev qttools5-dev-tools libevent-dev libboost-dev libdb5.3++-dev libminiupnpc-dev libnatpmp-dev libzmq3-dev libqrencode-dev libsqlite3-dev ${BPFCC_PACKAGE}" -export CI_IMAGE_NAME_TAG="docker.io/ubuntu:23.04" # This version will reach EOL in Jan 2024, and can be replaced by "ubuntu:24.04" (or anything else that ships the wanted clang version). +export PACKAGES="systemtap-sdt-dev clang-17 llvm-17 libclang-rt-17-dev python3-zmq qtbase5-dev qttools5-dev-tools libevent-dev libboost-dev libdb5.3++-dev libminiupnpc-dev libnatpmp-dev libzmq3-dev libqrencode-dev libsqlite3-dev ${BPFCC_PACKAGE}" +export CI_IMAGE_NAME_TAG="docker.io/ubuntu:23.10" # This version will reach EOL in Jul 2024, and can be replaced by "ubuntu:24.04" (or anything else that ships the wanted clang version). export NO_DEPENDS=1 export GOAL="install" export BITCOIN_CONFIG="--enable-c++20 --enable-usdt --enable-zmq --with-incompatible-bdb --with-gui=qt5 \ CPPFLAGS='-DARENA_DEBUG -DDEBUG_LOCKORDER' \ --with-sanitizers=address,float-divide-by-zero,integer,undefined \ -CC='clang-16 -ftrivial-auto-var-init=pattern' CXX='clang++-16 -ftrivial-auto-var-init=pattern'" +CC='clang-17 -ftrivial-auto-var-init=pattern' CXX='clang++-17 -ftrivial-auto-var-init=pattern'" From faa190b1efbdfdb9b12a7bfa7f732b5471a02e64 Mon Sep 17 00:00:00 2001 From: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz> Date: Thu, 12 Oct 2023 16:46:55 +0200 Subject: [PATCH 36/41] test: Fuzz merge with -use_value_profile=0 for now --- test/fuzz/test_runner.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/fuzz/test_runner.py b/test/fuzz/test_runner.py index c9975af225..4207c69241 100755 --- a/test/fuzz/test_runner.py +++ b/test/fuzz/test_runner.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2019-2021 The Bitcoin Core developers +# Copyright (c) 2019-present The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Run fuzz test targets. @@ -279,7 +279,11 @@ def merge_inputs(*, fuzz_pool, corpus, test_list, src_dir, build_dir, merge_dir) '-merge=1', '-shuffle=0', '-prefer_small=1', - '-use_value_profile=1', # Also done by oss-fuzz https://github.com/google/oss-fuzz/issues/1406#issuecomment-387790487 + '-use_value_profile=0', + # use_value_profile is enabled by oss-fuzz [0], but disabled for + # now to avoid bloating the qa-assets git repository [1]. + # [0] https://github.com/google/oss-fuzz/issues/1406#issuecomment-387790487 + # [1] https://github.com/bitcoin-core/qa-assets/issues/130#issuecomment-1749075891 os.path.join(corpus, t), os.path.join(merge_dir, t), ] From ce1699706e98201db73209ee495051359b1d0703 Mon Sep 17 00:00:00 2001 From: stickies-v Date: Wed, 31 May 2023 11:34:15 +0100 Subject: [PATCH 37/41] ci: add label to docker images This allows us or the user to perform batch operations on all images produced by the ci, e.g. to prune all dangling images, without affecting non-ci images. --- ci/test/02_run_container.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ci/test/02_run_container.sh b/ci/test/02_run_container.sh index a7c1e22a6d..c842b15f2e 100755 --- a/ci/test/02_run_container.sh +++ b/ci/test/02_run_container.sh @@ -5,6 +5,7 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. export LC_ALL=C.UTF-8 +export CI_IMAGE_LABEL="bitcoin-ci-test" set -ex @@ -19,6 +20,7 @@ if [ -z "$DANGER_RUN_CI_ON_HOST" ]; then --file "${BASE_READ_ONLY_DIR}/ci/test_imagefile" \ --build-arg "CI_IMAGE_NAME_TAG=${CI_IMAGE_NAME_TAG}" \ --build-arg "FILE_ENV=${FILE_ENV}" \ + --label="${CI_IMAGE_LABEL}" \ --tag="${CONTAINER_NAME}" \ "${BASE_READ_ONLY_DIR}" docker volume create "${CONTAINER_NAME}_ccache" || true From e44c574650827f18e12ac0ba378c0a19d23a07b4 Mon Sep 17 00:00:00 2001 From: stickies-v Date: Wed, 31 May 2023 11:35:45 +0100 Subject: [PATCH 38/41] ci: always prune all dangling bitcoin-ci-test images Since all bitcoin-ci-test images are now labeled, we can always prune all dangling images, regardless of whether we are in RESTART_CI_DOCKER_BEFORE_RUN. To be safe, still prune all images if RESTART_CI_DOCKER_BEFORE_RUN in case the filtering doesn't work, or if images were created on an earlier version that did not assign labels. --- ci/test/02_run_container.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ci/test/02_run_container.sh b/ci/test/02_run_container.sh index c842b15f2e..a74226b089 100755 --- a/ci/test/02_run_container.sh +++ b/ci/test/02_run_container.sh @@ -32,9 +32,14 @@ if [ -z "$DANGER_RUN_CI_ON_HOST" ]; then if [ -n "${RESTART_CI_DOCKER_BEFORE_RUN}" ] ; then echo "Restart docker before run to stop and clear all containers started with --rm" podman container rm --force --all # Similar to "systemctl restart docker" + + # Still prune everything in case the filtered pruning doesn't work, or if labels were not set + # on a previous run. Belt and suspenders approach, should be fine to remove in the future. echo "Prune all dangling images" docker image prune --force fi + echo "Prune all dangling $CI_IMAGE_LABEL images" + docker image prune --force --filter "label=$CI_IMAGE_LABEL" # shellcheck disable=SC2086 CI_CONTAINER_ID=$(docker run --cap-add LINUX_IMMUTABLE $CI_CONTAINER_CAP --rm --interactive --detach --tty \ From ac4caf3366a85617641394a97aa9f029550d77d4 Mon Sep 17 00:00:00 2001 From: Sebastian Falbesoner Date: Thu, 12 Oct 2023 17:24:16 +0200 Subject: [PATCH 39/41] test: fix `assert_debug_log` call-site bugs, add type checks Two recently added tests (PR #28625 / commit 2e31250027ac580a7a72221fe2ff505b30836175 and PR #28634 / commit 3bb51c29df596aab2c1fde184667cee435597715) introduced a bug by wrongly using the `assert_debug_log` helper. Instead of passing the expected debug string in a list as expected, it was passed as bare string, which is then interpretered as a list of characters, very likely leading the debug log assertion pass even if the intended message is not appearing. In order to avoid bugs like this in the future, enforce that the `{un}expected_msgs` parameters are lists. --- test/functional/p2p_segwit.py | 4 ++-- test/functional/p2p_v2_transport.py | 4 ++-- test/functional/test_framework/test_node.py | 3 +++ 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py index b398ef51e1..d316c4b602 100755 --- a/test/functional/p2p_segwit.py +++ b/test/functional/p2p_segwit.py @@ -706,14 +706,14 @@ def test_p2sh_witness(self): # segwit activation. Note that older bitcoind's that are not # segwit-aware would also reject this for failing CLEANSTACK. with self.nodes[0].assert_debug_log( - expected_msgs=(spend_tx.hash, 'was not accepted: mandatory-script-verify-flag-failed (Witness program was passed an empty witness)')): + expected_msgs=[spend_tx.hash, 'was not accepted: mandatory-script-verify-flag-failed (Witness program was passed an empty witness)']): test_transaction_acceptance(self.nodes[0], self.test_node, spend_tx, with_witness=False, accepted=False) # Try to put the witness script in the scriptSig, should also fail. spend_tx.vin[0].scriptSig = CScript([p2wsh_pubkey, b'a']) spend_tx.rehash() with self.nodes[0].assert_debug_log( - expected_msgs=(spend_tx.hash, 'was not accepted: mandatory-script-verify-flag-failed (Script evaluated without error but finished with a false/empty top stack element)')): + expected_msgs=[spend_tx.hash, 'was not accepted: mandatory-script-verify-flag-failed (Script evaluated without error but finished with a false/empty top stack element)']): test_transaction_acceptance(self.nodes[0], self.test_node, spend_tx, with_witness=False, accepted=False) # Now put the witness script in the witness, should succeed after diff --git a/test/functional/p2p_v2_transport.py b/test/functional/p2p_v2_transport.py index 99417a17a9..5ad2194b84 100755 --- a/test/functional/p2p_v2_transport.py +++ b/test/functional/p2p_v2_transport.py @@ -145,7 +145,7 @@ def run_test(self): wrong_network_magic_prefix = MAGIC_BYTES["signet"] + V1_PREFIX[4:] with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.connect(("127.0.0.1", p2p_port(0))) - with self.nodes[0].assert_debug_log("V2 transport error: V1 peer with wrong MessageStart"): + with self.nodes[0].assert_debug_log(["V2 transport error: V1 peer with wrong MessageStart"]): s.sendall(wrong_network_magic_prefix + b"somepayload") # Check detection of missing garbage terminator (hits after fixed amount of data if terminator never matches garbage) @@ -156,7 +156,7 @@ def run_test(self): self.wait_until(lambda: len(self.nodes[0].getpeerinfo()) == num_peers + 1) s.sendall(b'\x00' * (MAX_KEY_GARB_AND_GARBTERM_LEN - 1)) self.wait_until(lambda: self.nodes[0].getpeerinfo()[-1]["bytesrecv"] == MAX_KEY_GARB_AND_GARBTERM_LEN - 1) - with self.nodes[0].assert_debug_log("V2 transport error: missing garbage terminator"): + with self.nodes[0].assert_debug_log(["V2 transport error: missing garbage terminator"]): s.sendall(b'\x00') # send out last byte # should disconnect immediately self.wait_until(lambda: len(self.nodes[0].getpeerinfo()) == num_peers) diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index 4d7adf322c..c77cfbdd91 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -448,6 +448,9 @@ def debug_log_size(self, **kwargs) -> int: def assert_debug_log(self, expected_msgs, unexpected_msgs=None, timeout=2): if unexpected_msgs is None: unexpected_msgs = [] + assert_equal(type(expected_msgs), list) + assert_equal(type(unexpected_msgs), list) + time_end = time.time() + timeout * self.timeout_factor prev_size = self.debug_log_size(encoding="utf-8") # Must use same encoding that is used to read() below From 31665ded7775bef981c1c9afc6fa0a2a59b84f4f Mon Sep 17 00:00:00 2001 From: Daniel Kraft Date: Fri, 13 Oct 2023 12:39:16 +0200 Subject: [PATCH 40/41] Fix getheaders for blocks not on disk yet. Unlike upstream Bitcoin, it is impossible in Namecoin and Xaya to convert a CBlockIndex directly to a block header; for this, we need to retrieve the block from disk. With this, it may happen that a node tries (and fails to) load blocks from disk it does not have yet while serving getheaders, e.g. when still syncing with assumeutxo. In this commit, we make it properly catch this situation, and respond by ignoring the request. --- src/net_processing.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 00c37385a8..260c404c16 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -4201,6 +4201,16 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, for (; pindex; pindex = m_chainman.ActiveChain().Next(pindex)) { const CBlockHeader header = pindex->GetBlockHeader(m_chainman.m_blockman); + /* Unlike upstream Bitcoin, we need to get the stored block on disk + to convert pindex to header. This may fail if we are still + in initial sync with assumeutxo (for instance). In this case, + explicitly ignore the request. */ + if (header.IsNull ()) + { + LogPrint(BCLog::NET, "%s: ignoring getheaders request that we do not have on disk yet", __func__); + return; + } + ++nCount; nSize += GetSerializeSize(header, PROTOCOL_VERSION); vHeaders.push_back(header); From fa858d63a0a5d794aab38c26f60c593513fe08de Mon Sep 17 00:00:00 2001 From: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz> Date: Fri, 13 Oct 2023 16:57:11 +0200 Subject: [PATCH 41/41] fuzz: Merge with -set_cover_merge=1 --- test/fuzz/test_runner.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/fuzz/test_runner.py b/test/fuzz/test_runner.py index 4207c69241..446a4551da 100755 --- a/test/fuzz/test_runner.py +++ b/test/fuzz/test_runner.py @@ -276,7 +276,11 @@ def merge_inputs(*, fuzz_pool, corpus, test_list, src_dir, build_dir, merge_dir) for t in test_list: args = [ os.path.join(build_dir, 'src', 'test', 'fuzz', 'fuzz'), - '-merge=1', + '-set_cover_merge=1', + # set_cover_merge is used instead of -merge=1 to reduce the overall + # size of the qa-assets git repository a bit, but more importantly, + # to cut the runtime to iterate over all fuzz inputs [0]. + # [0] https://github.com/bitcoin-core/qa-assets/issues/130#issuecomment-1761760866 '-shuffle=0', '-prefer_small=1', '-use_value_profile=0',