aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml54
-rw-r--r--.github/ISSUE_TEMPLATE.md6
-rw-r--r--.github/ISSUE_TEMPLATE/gui_issue.md11
-rw-r--r--.github/PULL_REQUEST_TEMPLATE.md4
-rw-r--r--.travis.yml28
-rw-r--r--CONTRIBUTING.md20
-rw-r--r--README.md9
-rw-r--r--ci/README.md39
-rw-r--r--ci/test/00_setup_env_mac_host.sh1
-rw-r--r--ci/test/00_setup_env_native_asan.sh6
-rw-r--r--ci/test/00_setup_env_native_multiprocess.sh1
-rw-r--r--ci/test/00_setup_env_native_nowallet.sh1
-rw-r--r--ci/test/00_setup_env_native_qt5.sh1
-rw-r--r--ci/test/00_setup_env_win64.sh1
-rw-r--r--configure.ac3
-rw-r--r--src/bench/coin_selection.cpp4
-rw-r--r--src/bench/wallet_balance.cpp2
-rw-r--r--src/init.cpp8
-rw-r--r--src/net.cpp8
-rw-r--r--src/net.h22
-rw-r--r--src/net_processing.cpp202
-rw-r--r--src/netmessagemaker.h8
-rw-r--r--src/qt/bitcoinamountfield.cpp8
-rw-r--r--src/qt/bitcoinunits.cpp2
-rw-r--r--src/qt/bitcoinunits.h14
-rw-r--r--src/qt/guiutil.cpp2
-rw-r--r--src/qt/overviewpage.cpp34
-rw-r--r--src/qt/recentrequeststablemodel.cpp2
-rw-r--r--src/qt/test/addressbooktests.cpp2
-rw-r--r--src/qt/test/wallettests.cpp6
-rw-r--r--src/qt/transactiontablemodel.cpp6
-rw-r--r--src/qt/transactiontablemodel.h2
-rw-r--r--src/script/descriptor.cpp6
-rw-r--r--src/script/interpreter.cpp2
-rw-r--r--src/script/standard.cpp52
-rw-r--r--src/span.h112
-rw-r--r--src/test/fuzz/process_message.cpp17
-rw-r--r--src/test/fuzz/process_messages.cpp2
-rw-r--r--src/test/fuzz/span.cpp4
-rw-r--r--src/test/fuzz/spanparsing.cpp2
-rw-r--r--src/test/util_tests.cpp22
-rw-r--r--src/wallet/bdb.cpp64
-rw-r--r--src/wallet/bdb.h65
-rw-r--r--src/wallet/salvage.cpp2
-rw-r--r--src/wallet/test/coinselector_tests.cpp4
-rw-r--r--src/wallet/test/ismine_tests.cpp40
-rw-r--r--src/wallet/test/scriptpubkeyman_tests.cpp2
-rw-r--r--src/wallet/test/wallet_test_fixture.cpp2
-rw-r--r--src/wallet/test/wallet_tests.cpp20
-rw-r--r--src/wallet/wallet.cpp6
-rw-r--r--src/wallet/walletdb.cpp19
-rw-r--r--src/wallet/walletdb.h9
-rw-r--r--src/wallet/wallettool.cpp6
-rwxr-xr-xtest/functional/feature_notifications.py1
-rwxr-xr-xtest/functional/p2p_invalid_messages.py32
55 files changed, 615 insertions, 393 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index 44b49bb397..9c2598d606 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -1,3 +1,36 @@
+# Global defaults
+timeout_in: 120m # https://cirrus-ci.org/faq/#instance-timed-out
+container:
+ # https://cirrus-ci.org/faq/#are-there-any-limits
+ # Each project has 16 CPU in total, assign 2 to each container, so that 8 tasks run in parallel
+ cpu: 2
+ memory: 6G # https://cirrus-ci.org/guide/linux/#linux-containers
+env:
+ PACKAGE_MANAGER_INSTALL : "apt-get update && apt-get install -y"
+ MAKEJOBS: "-j4"
+ DANGER_RUN_CI_ON_HOST: "1" # Containers will be discarded after the run, so there is no risk that the ci scripts modify the system
+ TEST_RUNNER_PORT_MIN: "14000" # Must be larger than 12321, which is used for the http cache. See https://cirrus-ci.org/guide/writing-tasks/#http-cache
+ CCACHE_SIZE: "200M"
+ CCACHE_DIR: "/tmp/ccache_dir"
+# Global task template
+# https://cirrus-ci.org/guide/tips-and-tricks/#sharing-configuration-between-tasks
+global_task_template: &GLOBAL_TASK_TEMPLATE
+ ccache_cache:
+ folder: "/tmp/ccache_dir"
+ depends_built_cache:
+ folder: "/tmp/cirrus-ci-build/depends/built"
+ depends_sdk_cache:
+ folder: "/tmp/cirrus-ci-build/depends/sdk-sources"
+ depends_releases_cache:
+ folder: "/tmp/cirrus-ci-build/releases"
+ merge_base_script:
+ - bash -c "$PACKAGE_MANAGER_INSTALL git"
+ - git fetch $CIRRUS_REPO_CLONE_URL $CIRRUS_BASE_BRANCH
+ - git config --global user.email "ci@ci.ci"
+ - git config --global user.name "ci"
+ - git merge FETCH_HEAD # Merge base to detect silent merge conflicts
+ ci_script:
+ - ./ci/test_run_all.sh
#task:
# name: "Windows"
# windows_container:
@@ -13,22 +46,11 @@
# VCPKG_COMMIT_ID: 'ed0df8ecc4ed7e755ea03e18aaf285fd9b4b4a74'
# install_script:
# - choco install python --version=3.7.7 -y
+
task:
- name: "x86_64 Linux [GOAL: install] [bionic] [Using ./ci/ system]"
+ name: 'x86_64 Linux [GOAL: install] [focal] [no depends, only system libs, sanitizers: address/leak (ASan + LSan) + undefined (UBSan) + integer]'
+ << : *GLOBAL_TASK_TEMPLATE
container:
- image: ubuntu:18.04
- cpu: 8
- memory: 8G
- timeout_in: 60m
+ image: ubuntu:focal
env:
- MAKEJOBS: "-j9"
- DANGER_RUN_CI_ON_HOST: "1"
- TEST_RUNNER_PORT_MIN: "14000" # Must be larger than 12321, which is used for the http cache. See https://cirrus-ci.org/guide/writing-tasks/#http-cache
- CCACHE_SIZE: "200M"
- CCACHE_DIR: "/tmp/ccache_dir"
- ccache_cache:
- folder: "/tmp/ccache_dir"
- depends_built_cache:
- folder: "/tmp/cirrus-ci-build/depends/built"
- ci_script:
- - ./ci/test_run_all.sh
+ FILE_ENV: "./ci/test/00_setup_env_native_asan.sh"
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
index 35b42424ad..eedeeb4e54 100644
--- a/.github/ISSUE_TEMPLATE.md
+++ b/.github/ISSUE_TEMPLATE.md
@@ -4,7 +4,11 @@ General bitcoin questions and/or support requests are best directed to the Bitco
For reporting security issues, please read instructions at https://bitcoincore.org/en/contact/.
-If the node is "stuck" during sync or giving "block checksum mismatch" errors, please ensure your hardware is stable by running memtest and observe CPU temperature with a load-test tool such as linpack before creating an issue! -->
+If the node is "stuck" during sync or giving "block checksum mismatch" errors, please ensure your hardware is stable by running memtest and observe CPU temperature with a load-test tool such as linpack before creating an issue!
+
+Any report, issue or feature request related to the GUI should be reported at
+https://github.com/bitcoin-core/gui/issues/
+-->
<!-- Describe the issue -->
<!--- What behavior did you expect? -->
diff --git a/.github/ISSUE_TEMPLATE/gui_issue.md b/.github/ISSUE_TEMPLATE/gui_issue.md
new file mode 100644
index 0000000000..37acc81e21
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/gui_issue.md
@@ -0,0 +1,11 @@
+---
+name: An issue or feature request related to the GUI
+about: Any report, issue or feature request related to the GUI should be reported at https://github.com/bitcoin-core/gui/issues/
+title: Any report, issue or feature request related to the GUI should be reported at https://github.com/bitcoin-core/gui/issues/
+labels: GUI
+assignees: ''
+
+---
+
+Any report, issue or feature request related to the GUI should be reported at
+https://github.com/bitcoin-core/gui/issues/
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index d2c3b23375..ae92fc78f2 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -3,6 +3,10 @@
Pull requests without a rationale and clear improvement may be closed
immediately.
+
+GUI-related pull requests should be opened against
+https://github.com/bitcoin-core/gui
+first. See CONTRIBUTING.md
-->
<!--
diff --git a/.travis.yml b/.travis.yml
index 283df78633..9ab2227116 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,18 +1,4 @@
-# The test build matrix (stage: test) is constructed to test a wide range of
-# configurations, rather than a single pass/fail. This helps to catch build
-# failures and logic errors that present on platforms other than the ones the
-# author has tested.
-#
-# Some builders use the dependency-generator in `./depends`, rather than using
-# apt-get to install build dependencies. This guarantees that the tester is
-# using the same versions as Gitian, so the build results are nearly identical
-# to what would be found in a final release.
-#
-# In order to avoid rebuilding all dependencies for each build, the binaries
-# are cached and re-used when possible. Changes in the dependency-generator
-# will trigger cache-invalidation and rebuilds as necessary.
-#
-# These caches can be manually removed if necessary. This is one of the very
+# Travis caches can be manually removed if necessary. This is one of the very
# few manual operations that is possible with Travis, and it can be done by a
# Bitcoin Core GitHub member via the Travis web interface [0].
#
@@ -27,7 +13,7 @@
version: ~> 1.0
-dist: xenial
+dist: bionic
os: linux
language: minimal
arch: amd64
@@ -121,23 +107,17 @@ jobs:
FILE_ENV="./ci/test/00_setup_env_native_tsan.sh"
- stage: test
- name: 'x86_64 Linux [GOAL: install] [bionic] [no depends, only system libs, sanitizers: address/leak (ASan + LSan) + undefined (UBSan) + integer]'
- env: >-
- FILE_ENV="./ci/test/00_setup_env_native_asan.sh"
-
- - stage: test
name: 'x86_64 Linux [GOAL: install] [focal] [no depends, only system libs, sanitizers: fuzzer,address,undefined]'
env: >-
FILE_ENV="./ci/test/00_setup_env_native_fuzz.sh"
- stage: test
- name: 'x86_64 Linux [GOAL: install] [bionic] [multiprocess]'
- if: type != pull_request OR commit_message =~ /depends:|multiprocess:/ # Skip on non-depends, non-multiprocess PRs
+ name: 'x86_64 Linux [GOAL: install] [focal] [multiprocess]'
env: >-
FILE_ENV="./ci/test/00_setup_env_native_multiprocess.sh"
- stage: test
- name: 'x86_64 Linux [GOAL: install] [bionic] [no wallet]'
+ name: 'x86_64 Linux [GOAL: install] [xenial] [no wallet]'
env: >-
FILE_ENV="./ci/test/00_setup_env_native_nowallet.sh"
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index f34b1e1e15..65bc45a00b 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -84,6 +84,26 @@ To contribute a patch, the workflow is as follows:
1. Create topic branch
1. Commit patches
+For GUI-related issues or pull requests, the https://github.com/bitcoin-core/gui repository should be used.
+For all other issues and pull requests, the https://github.com/bitcoin/bitcoin node repository should be used.
+
+The master branch for all monotree repositories is identical.
+
+As a rule of thumb, everything that only modifies `src/qt` is a GUI-only pull
+request. However:
+
+* For global refactoring or other transversal changes the node repository
+ should be used.
+* For GUI-related build system changes, the node repository should be used
+ because the change needs review by the build systems reviewers.
+* Changes in `src/interfaces` need to go to the node repository because they
+ might affect other components like the wallet.
+
+For large GUI changes that include build system and interface changes, it is
+recommended to first open a pull request against the GUI repository. When there
+is agreement to proceed with the changes, a pull request with the build system
+and interfaces changes can be submitted to the node repository.
+
The project coding conventions in the [developer notes](doc/developer-notes.md)
must be followed.
diff --git a/README.md b/README.md
index 9213471c41..312e2d00ec 100644
--- a/README.md
+++ b/README.md
@@ -25,9 +25,14 @@ information or see https://opensource.org/licenses/MIT.
Development Process
-------------------
-The `master` branch is regularly built (see doc/build-*.md for instructions) and tested, but is not guaranteed to be
+The `master` branch is regularly built (see `doc/build-*.md` for instructions) and tested, but it is not guaranteed to be
completely stable. [Tags](https://github.com/bitcoin/bitcoin/tags) are created
-regularly to indicate new official, stable release versions of Bitcoin Core.
+regularly from release branches to indicate new official, stable release versions of Bitcoin Core.
+
+The https://github.com/bitcoin-core/gui repository is used exclusively for the
+development of the GUI. Its master branch is identical in all monotree
+repositories. Release branches and tags do not exist, so please do not fork
+that repository unless it is for development reasons.
The contribution workflow is described in [CONTRIBUTING.md](CONTRIBUTING.md)
and useful hints for developers can be found in [doc/developer-notes.md](doc/developer-notes.md).
diff --git a/ci/README.md b/ci/README.md
index d2ea255b4b..3c5f04c39e 100644
--- a/ci/README.md
+++ b/ci/README.md
@@ -1,12 +1,8 @@
-## ci scripts
+## CI Scripts
This directory contains scripts for each build step in each build stage.
-Currently three stages `lint`, `extended_lint` and `test` are defined. Each stage has its own lifecycle, similar to the
-[Travis CI lifecycle](https://docs.travis-ci.com/user/job-lifecycle#the-job-lifecycle). Every script in here is named
-and numbered according to which stage and lifecycle step it belongs to.
-
-### Running a stage locally
+### Running a Stage Locally
Be aware that the tests will be built and run in-place, so please run at your own risk.
If the repository is not a fresh git clone, you might have to clean files from previous builds or test runs first.
@@ -36,3 +32,34 @@ To run the test stage with a specific configuration,
```
FILE_ENV="./ci/test/00_setup_env_arm.sh" ./ci/test_run_all.sh
```
+
+### Configurations
+
+The test files (`FILE_ENV`) are constructed to test a wide range of
+configurations, rather than a single pass/fail. This helps to catch build
+failures and logic errors that present on platforms other than the ones the
+author has tested.
+
+Some builders use the dependency-generator in `./depends`, rather than using
+the system package manager to install build dependencies. This guarantees that
+the tester is using the same versions as the release builds, which also use
+`./depends`.
+
+If no `FILE_ENV` has been specified or values are left out, `00_setup_env.sh`
+is used as the default configuration with fallback values.
+
+It is also possible to force a specific configuration without modifying the
+file. For example,
+
+```
+MAKEJOBS="-j1" FILE_ENV="./ci/test/00_setup_env_arm.sh" ./ci/test_run_all.sh
+```
+
+The files starting with `0n` (`n` greater than 0) are the scripts that are run
+in order.
+
+### Cache
+
+In order to avoid rebuilding all dependencies for each build, the binaries are
+cached and re-used when possible. Changes in the dependency-generator will
+trigger cache-invalidation and rebuilds as necessary.
diff --git a/ci/test/00_setup_env_mac_host.sh b/ci/test/00_setup_env_mac_host.sh
index b24dc7278d..f50efcc33a 100644
--- a/ci/test/00_setup_env_mac_host.sh
+++ b/ci/test/00_setup_env_mac_host.sh
@@ -7,6 +7,7 @@
export LC_ALL=C.UTF-8
export HOST=x86_64-apple-darwin16
+export DOCKER_NAME_TAG=ubuntu:18.04 # Check that bionic can cross-compile to macos (bionic is used in the gitian build as well)
export PIP_PACKAGES="zmq"
export GOAL="install"
export BITCOIN_CONFIG="--enable-gui --enable-reduce-exports --enable-werror"
diff --git a/ci/test/00_setup_env_native_asan.sh b/ci/test/00_setup_env_native_asan.sh
index 28c63f1cf6..225f77df92 100644
--- a/ci/test/00_setup_env_native_asan.sh
+++ b/ci/test/00_setup_env_native_asan.sh
@@ -7,8 +7,8 @@
export LC_ALL=C.UTF-8
export CONTAINER_NAME=ci_native_asan
-export PACKAGES="clang-8 llvm-8 python3-zmq qtbase5-dev qttools5-dev-tools libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-test-dev libboost-thread-dev libdb5.3++-dev libminiupnpc-dev libzmq3-dev libqrencode-dev"
-# Use clang-8 instead of default clang (which is clang-6 on Bionic) to avoid spurious segfaults when running on ppc64le
+export PACKAGES="clang llvm python3-zmq qtbase5-dev qttools5-dev-tools libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-test-dev libboost-thread-dev libdb5.3++-dev libminiupnpc-dev libzmq3-dev libqrencode-dev"
+export DOCKER_NAME_TAG=ubuntu:20.04
export NO_DEPENDS=1
export GOAL="install"
-export BITCOIN_CONFIG="--enable-zmq --with-incompatible-bdb --with-gui=qt5 CPPFLAGS='-DARENA_DEBUG -DDEBUG_LOCKORDER' --with-sanitizers=address,integer,undefined CC=clang-8 CXX=clang++-8"
+export BITCOIN_CONFIG="--enable-zmq --with-incompatible-bdb --with-gui=qt5 CPPFLAGS='-DARENA_DEBUG -DDEBUG_LOCKORDER' --with-sanitizers=address,integer,undefined CC=clang CXX=clang++"
diff --git a/ci/test/00_setup_env_native_multiprocess.sh b/ci/test/00_setup_env_native_multiprocess.sh
index 0fc989085c..786f0f927f 100644
--- a/ci/test/00_setup_env_native_multiprocess.sh
+++ b/ci/test/00_setup_env_native_multiprocess.sh
@@ -7,6 +7,7 @@
export LC_ALL=C.UTF-8
export CONTAINER_NAME=ci_native_multiprocess
+export DOCKER_NAME_TAG=ubuntu:20.04
export PACKAGES="cmake python3"
export DEP_OPTS="MULTIPROCESS=1"
export GOAL="install"
diff --git a/ci/test/00_setup_env_native_nowallet.sh b/ci/test/00_setup_env_native_nowallet.sh
index 9c2be4cfac..553dab1491 100644
--- a/ci/test/00_setup_env_native_nowallet.sh
+++ b/ci/test/00_setup_env_native_nowallet.sh
@@ -7,6 +7,7 @@
export LC_ALL=C.UTF-8
export CONTAINER_NAME=ci_native_nowallet
+export DOCKER_NAME_TAG=ubuntu:16.04 # Use xenial to have one config run the tests in python3.5, see doc/dependencies.md
export PACKAGES="python3-zmq"
export DEP_OPTS="NO_WALLET=1"
export GOAL="install"
diff --git a/ci/test/00_setup_env_native_qt5.sh b/ci/test/00_setup_env_native_qt5.sh
index 496251a125..6e2ff729a2 100644
--- a/ci/test/00_setup_env_native_qt5.sh
+++ b/ci/test/00_setup_env_native_qt5.sh
@@ -7,6 +7,7 @@
export LC_ALL=C.UTF-8
export CONTAINER_NAME=ci_native_qt5
+export DOCKER_NAME_TAG=ubuntu:18.04 # Check that bionic can compile our c++17 and run our functional tests in python3
export PACKAGES="python3-zmq qtbase5-dev qttools5-dev-tools libdbus-1-dev libharfbuzz-dev"
export DEP_OPTS="NO_QT=1 NO_UPNP=1 DEBUG=1 ALLOW_HOST_PACKAGES=1"
export TEST_RUNNER_EXTRA="--previous-releases --coverage --extended --exclude feature_dbcrash" # Run extended tests so that coverage does not fail, but exclude the very slow dbcrash
diff --git a/ci/test/00_setup_env_win64.sh b/ci/test/00_setup_env_win64.sh
index 90c3ebd28e..eb8b870dd6 100644
--- a/ci/test/00_setup_env_win64.sh
+++ b/ci/test/00_setup_env_win64.sh
@@ -7,6 +7,7 @@
export LC_ALL=C.UTF-8
export CONTAINER_NAME=ci_win64
+export DOCKER_NAME_TAG=ubuntu:18.04 # Check that bionic can cross-compile to win64 (bionic is used in the gitian build as well)
export HOST=x86_64-w64-mingw32
export PACKAGES="python3 nsis g++-mingw-w64-x86-64 wine-binfmt wine64"
export RUN_FUNCTIONAL_TESTS=false
diff --git a/configure.ac b/configure.ac
index 474d8a7919..12bece6903 100644
--- a/configure.ac
+++ b/configure.ac
@@ -111,9 +111,6 @@ AC_PATH_TOOL(READELF, readelf)
AC_PATH_TOOL(CPPFILT, c++filt)
AC_PATH_TOOL(OBJCOPY, objcopy)
AC_PATH_PROG(DOXYGEN, doxygen)
-if test -z "$DOXYGEN"; then
- AC_MSG_WARN([Doxygen not found])
-fi
AM_CONDITIONAL([HAVE_DOXYGEN], [test -n "$DOXYGEN"])
AC_ARG_VAR(PYTHONPATH, Augments the default search path for python module files)
diff --git a/src/bench/coin_selection.cpp b/src/bench/coin_selection.cpp
index d6d5e67c5b..f2d12531d7 100644
--- a/src/bench/coin_selection.cpp
+++ b/src/bench/coin_selection.cpp
@@ -31,7 +31,7 @@ static void CoinSelection(benchmark::State& state)
{
NodeContext node;
auto chain = interfaces::MakeChain(node);
- CWallet wallet(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ CWallet wallet(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
wallet.SetupLegacyScriptPubKeyMan();
std::vector<std::unique_ptr<CWalletTx>> wtxs;
LOCK(wallet.cs_wallet);
@@ -65,7 +65,7 @@ static void CoinSelection(benchmark::State& state)
typedef std::set<CInputCoin> CoinSet;
static NodeContext testNode;
static auto testChain = interfaces::MakeChain(testNode);
-static CWallet testWallet(testChain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+static CWallet testWallet(testChain.get(), WalletLocation(), CreateDummyWalletDatabase());
std::vector<std::unique_ptr<CWalletTx>> wtxn;
// Copied from src/wallet/test/coinselector_tests.cpp
diff --git a/src/bench/wallet_balance.cpp b/src/bench/wallet_balance.cpp
index 810c344ab5..05cfb3438e 100644
--- a/src/bench/wallet_balance.cpp
+++ b/src/bench/wallet_balance.cpp
@@ -26,7 +26,7 @@ static void WalletBalance(benchmark::State& state, const bool set_dirty, const b
NodeContext node;
std::unique_ptr<interfaces::Chain> chain = interfaces::MakeChain(node);
- CWallet wallet{chain.get(), WalletLocation(), WalletDatabase::CreateMock()};
+ CWallet wallet{chain.get(), WalletLocation(), CreateMockWalletDatabase()};
{
wallet.SetupLegacyScriptPubKeyMan();
bool first_run;
diff --git a/src/init.cpp b/src/init.cpp
index fd7c8d0f80..8d9566edc3 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -152,6 +152,8 @@ NODISCARD static bool CreatePidFile()
static std::unique_ptr<ECCVerifyHandle> globalVerifyHandle;
+static std::thread g_load_block;
+
static boost::thread_group threadGroup;
void Interrupt(NodeContext& node)
@@ -214,8 +216,9 @@ void Shutdown(NodeContext& node)
StopTorControl();
// After everything has been shut down, but before things get flushed, stop the
- // CScheduler/checkqueue threadGroup
+ // CScheduler/checkqueue, threadGroup and load block thread.
if (node.scheduler) node.scheduler->stop();
+ if (g_load_block.joinable()) g_load_block.join();
threadGroup.interrupt_all();
threadGroup.join_all();
@@ -680,7 +683,6 @@ static void CleanupBlockRevFiles()
static void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImportFiles)
{
const CChainParams& chainparams = Params();
- util::ThreadRename("loadblk");
ScheduleBatchPriority();
{
@@ -1842,7 +1844,7 @@ bool AppInitMain(const util::Ref& context, NodeContext& node)
vImportFiles.push_back(strFile);
}
- threadGroup.create_thread([=, &chainman] { ThreadImport(chainman, vImportFiles); });
+ g_load_block = std::thread(&TraceThread<std::function<void()>>, "loadblk", [=, &chainman]{ ThreadImport(chainman, vImportFiles); });
// Wait for genesis block to be processed
{
diff --git a/src/net.cpp b/src/net.cpp
index f3b7e8dab1..371fbeed59 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -737,7 +737,7 @@ void V1TransportSerializer::prepareForTransport(CSerializedNetMsg& msg, std::vec
uint256 hash = Hash(msg.data.begin(), msg.data.end());
// create header
- CMessageHeader hdr(Params().MessageStart(), msg.command.c_str(), msg.data.size());
+ CMessageHeader hdr(Params().MessageStart(), msg.m_type.c_str(), msg.data.size());
memcpy(hdr.pchChecksum, hash.begin(), CMessageHeader::CHECKSUM_SIZE);
// serialize header
@@ -2794,7 +2794,7 @@ bool CConnman::NodeFullyConnected(const CNode* pnode)
void CConnman::PushMessage(CNode* pnode, CSerializedNetMsg&& msg)
{
size_t nMessageSize = msg.data.size();
- LogPrint(BCLog::NET, "sending %s (%d bytes) peer=%d\n", SanitizeString(msg.command), nMessageSize, pnode->GetId());
+ LogPrint(BCLog::NET, "sending %s (%d bytes) peer=%d\n", SanitizeString(msg.m_type), nMessageSize, pnode->GetId());
// make sure we use the appropriate network transport format
std::vector<unsigned char> serializedHeader;
@@ -2806,8 +2806,8 @@ void CConnman::PushMessage(CNode* pnode, CSerializedNetMsg&& msg)
LOCK(pnode->cs_vSend);
bool optimisticSend(pnode->vSendMsg.empty());
- //log total amount of bytes per command
- pnode->mapSendBytesPerMsgCmd[msg.command] += nTotalSize;
+ //log total amount of bytes per message type
+ pnode->mapSendBytesPerMsgCmd[msg.m_type] += nTotalSize;
pnode->nSendSize += nTotalSize;
if (pnode->nSendSize > nSendBufferMaxSize)
diff --git a/src/net.h b/src/net.h
index 517445e8f4..b461470f1f 100644
--- a/src/net.h
+++ b/src/net.h
@@ -110,7 +110,7 @@ struct CSerializedNetMsg
CSerializedNetMsg& operator=(const CSerializedNetMsg&) = delete;
std::vector<unsigned char> data;
- std::string command;
+ std::string m_type;
};
@@ -973,19 +973,21 @@ public:
}
}
- void PushInventory(const CInv& inv)
+ void PushTxInventory(const uint256& hash)
{
- if (inv.type == MSG_TX && m_tx_relay != nullptr) {
- LOCK(m_tx_relay->cs_tx_inventory);
- if (!m_tx_relay->filterInventoryKnown.contains(inv.hash)) {
- m_tx_relay->setInventoryTxToSend.insert(inv.hash);
- }
- } else if (inv.type == MSG_BLOCK) {
- LOCK(cs_inventory);
- vInventoryBlockToSend.push_back(inv.hash);
+ if (m_tx_relay == nullptr) return;
+ LOCK(m_tx_relay->cs_tx_inventory);
+ if (!m_tx_relay->filterInventoryKnown.contains(hash)) {
+ m_tx_relay->setInventoryTxToSend.insert(hash);
}
}
+ void PushBlockInventory(const uint256& hash)
+ {
+ LOCK(cs_inventory);
+ vInventoryBlockToSend.push_back(hash);
+ }
+
void PushBlockHash(const uint256 &hash)
{
LOCK(cs_inventory);
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index aa5c9668e3..d7fbf6941d 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -1419,10 +1419,9 @@ bool static AlreadyHave(const CInv& inv, const CTxMemPool& mempool) EXCLUSIVE_LO
void RelayTransaction(const uint256& txid, const CConnman& connman)
{
- CInv inv(MSG_TX, txid);
- connman.ForEachNode([&inv](CNode* pnode)
+ connman.ForEachNode([&txid](CNode* pnode)
{
- pnode->PushInventory(inv);
+ pnode->PushTxInventory(txid);
});
}
@@ -1608,7 +1607,7 @@ void static ProcessGetBlockData(CNode& pfrom, const CChainParams& chainparams, c
// Trigger the peer node to send a getblocks request for the next batch of inventory
if (inv.hash == pfrom.hashContinue)
{
- // Bypass PushInventory, this must send even if redundant,
+ // Bypass PushBlockInventory, this must send even if redundant,
// and we want it right after the last block so they don't
// wait for other stuff first.
std::vector<CInv> vInv;
@@ -1746,14 +1745,14 @@ inline void static SendBlockTransactions(const CBlock& block, const BlockTransac
connman->PushMessage(&pfrom, msgMaker.Make(nSendFlags, NetMsgType::BLOCKTXN, resp));
}
-bool static ProcessHeadersMessage(CNode& pfrom, CConnman* connman, ChainstateManager& chainman, CTxMemPool& mempool, const std::vector<CBlockHeader>& headers, const CChainParams& chainparams, bool via_compact_block)
+static void ProcessHeadersMessage(CNode& pfrom, CConnman* connman, ChainstateManager& chainman, CTxMemPool& mempool, const std::vector<CBlockHeader>& headers, const CChainParams& chainparams, bool via_compact_block)
{
const CNetMsgMaker msgMaker(pfrom.GetSendVersion());
size_t nCount = headers.size();
if (nCount == 0) {
// Nothing interesting. Stop asking this peers for more headers.
- return true;
+ return;
}
bool received_new_header = false;
@@ -1786,14 +1785,14 @@ bool static ProcessHeadersMessage(CNode& pfrom, CConnman* connman, ChainstateMan
if (nodestate->nUnconnectingHeaders % MAX_UNCONNECTING_HEADERS == 0) {
Misbehaving(pfrom.GetId(), 20);
}
- return true;
+ return;
}
uint256 hashLastBlock;
for (const CBlockHeader& header : headers) {
if (!hashLastBlock.IsNull() && header.hashPrevBlock != hashLastBlock) {
Misbehaving(pfrom.GetId(), 20, "non-continuous headers sequence");
- return false;
+ return;
}
hashLastBlock = header.GetHash();
}
@@ -1809,7 +1808,7 @@ bool static ProcessHeadersMessage(CNode& pfrom, CConnman* connman, ChainstateMan
if (!chainman.ProcessNewBlockHeaders(headers, state, chainparams, &pindexLast)) {
if (state.IsInvalid()) {
MaybePunishNodeForBlock(pfrom.GetId(), state, via_compact_block, "invalid header received");
- return false;
+ return;
}
}
@@ -1925,7 +1924,7 @@ bool static ProcessHeadersMessage(CNode& pfrom, CConnman* connman, ChainstateMan
}
}
- return true;
+ return;
}
void static ProcessOrphanTx(CConnman* connman, CTxMemPool& mempool, std::set<uint256>& orphan_work_set, std::list<CTransactionRef>& removed_txn) EXCLUSIVE_LOCKS_REQUIRED(cs_main, g_cs_orphans)
@@ -2205,13 +2204,23 @@ static void ProcessGetCFCheckPt(CNode& pfrom, CDataStream& vRecv, const CChainPa
connman.PushMessage(&pfrom, std::move(msg));
}
-bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams, ChainstateManager& chainman, CTxMemPool& mempool, CConnman* connman, BanMan* banman, const std::atomic<bool>& interruptMsgProc)
+void ProcessMessage(
+ CNode& pfrom,
+ const std::string& msg_type,
+ CDataStream& vRecv,
+ int64_t nTimeReceived,
+ const CChainParams& chainparams,
+ ChainstateManager& chainman,
+ CTxMemPool& mempool,
+ CConnman* connman,
+ BanMan* banman,
+ const std::atomic<bool>& interruptMsgProc)
{
LogPrint(BCLog::NET, "received: %s (%u bytes) peer=%d\n", SanitizeString(msg_type), vRecv.size(), pfrom.GetId());
if (gArgs.IsArgSet("-dropmessagestest") && GetRand(gArgs.GetArg("-dropmessagestest", 0)) == 0)
{
LogPrintf("dropmessagestest DROPPING RECV MESSAGE\n");
- return true;
+ return;
}
@@ -2221,7 +2230,7 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
{
LOCK(cs_main);
Misbehaving(pfrom.GetId(), 1);
- return false;
+ return;
}
int64_t nTime;
@@ -2247,14 +2256,14 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
{
LogPrint(BCLog::NET, "peer=%d does not offer the expected services (%08x offered, %08x expected); disconnecting\n", pfrom.GetId(), nServices, GetDesirableServiceFlags(nServices));
pfrom.fDisconnect = true;
- return false;
+ return;
}
if (nVersion < MIN_PEER_PROTO_VERSION) {
// disconnect from peers older than this proto version
LogPrint(BCLog::NET, "peer=%d using obsolete version %i; disconnecting\n", pfrom.GetId(), nVersion);
pfrom.fDisconnect = true;
- return false;
+ return;
}
if (!vRecv.empty())
@@ -2274,7 +2283,7 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
{
LogPrintf("connected to self at %s, disconnecting\n", pfrom.addr.ToString());
pfrom.fDisconnect = true;
- return true;
+ return;
}
if (pfrom.fInbound && addrMe.IsRoutable())
@@ -2374,14 +2383,14 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
assert(pfrom.fInbound == false);
pfrom.fDisconnect = true;
}
- return true;
+ return;
}
if (pfrom.nVersion == 0) {
// Must have a version message before anything else
LOCK(cs_main);
Misbehaving(pfrom.GetId(), 1);
- return false;
+ return;
}
// At this point, the outgoing message serialization version can't change.
@@ -2422,14 +2431,14 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
connman->PushMessage(&pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion));
}
pfrom.fSuccessfullyConnected = true;
- return true;
+ return;
}
if (!pfrom.fSuccessfullyConnected) {
// Must have a verack message before anything else
LOCK(cs_main);
Misbehaving(pfrom.GetId(), 1);
- return false;
+ return;
}
if (msg_type == NetMsgType::ADDR) {
@@ -2438,15 +2447,15 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
// Don't want addr from older versions unless seeding
if (pfrom.nVersion < CADDR_TIME_VERSION && connman->GetAddressCount() > 1000)
- return true;
+ return;
if (!pfrom.IsAddrRelayPeer()) {
- return true;
+ return;
}
if (vAddr.size() > 1000)
{
LOCK(cs_main);
Misbehaving(pfrom.GetId(), 20, strprintf("message addr size() = %u", vAddr.size()));
- return false;
+ return;
}
// Store the new addresses
@@ -2456,7 +2465,7 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
for (CAddress& addr : vAddr)
{
if (interruptMsgProc)
- return true;
+ return;
// We only bother storing full nodes, though this may include
// things which we would not make an outbound connection to, in
@@ -2483,13 +2492,13 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
pfrom.fGetAddr = false;
if (pfrom.fOneShot)
pfrom.fDisconnect = true;
- return true;
+ return;
}
if (msg_type == NetMsgType::SENDHEADERS) {
LOCK(cs_main);
State(pfrom.GetId())->fPreferHeaders = true;
- return true;
+ return;
}
if (msg_type == NetMsgType::SENDCMPCT) {
@@ -2512,7 +2521,7 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
State(pfrom.GetId())->fSupportsDesiredCmpctVersion = (nCMPCTBLOCKVersion == 1);
}
}
- return true;
+ return;
}
if (msg_type == NetMsgType::INV) {
@@ -2522,7 +2531,7 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
{
LOCK(cs_main);
Misbehaving(pfrom.GetId(), 20, strprintf("message inv size() = %u", vInv.size()));
- return false;
+ return;
}
// We won't accept tx inv's if we're in blocks-only mode, or this is a
@@ -2542,7 +2551,7 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
for (CInv &inv : vInv)
{
if (interruptMsgProc)
- return true;
+ return;
bool fAlreadyHave = AlreadyHave(inv, mempool);
LogPrint(BCLog::NET, "got inv: %s %s peer=%d\n", inv.ToString(), fAlreadyHave ? "have" : "new", pfrom.GetId());
@@ -2566,7 +2575,7 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
if (fBlocksOnly) {
LogPrint(BCLog::NET, "transaction (%s) inv sent in violation of protocol, disconnecting peer=%d\n", inv.hash.ToString(), pfrom.GetId());
pfrom.fDisconnect = true;
- return true;
+ return;
} else if (!fAlreadyHave && !fImporting && !fReindex && !::ChainstateActive().IsInitialBlockDownload()) {
RequestTx(State(pfrom.GetId()), inv.hash, current_time);
}
@@ -2578,7 +2587,7 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
LogPrint(BCLog::NET, "getheaders (%d) %s to peer=%d\n", pindexBestHeader->nHeight, best_block->ToString(), pfrom.GetId());
}
- return true;
+ return;
}
if (msg_type == NetMsgType::GETDATA) {
@@ -2588,7 +2597,7 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
{
LOCK(cs_main);
Misbehaving(pfrom.GetId(), 20, strprintf("message getdata size() = %u", vInv.size()));
- return false;
+ return;
}
LogPrint(BCLog::NET, "received getdata (%u invsz) peer=%d\n", vInv.size(), pfrom.GetId());
@@ -2599,7 +2608,7 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
pfrom.vRecvGetData.insert(pfrom.vRecvGetData.end(), vInv.begin(), vInv.end());
ProcessGetData(pfrom, chainparams, connman, mempool, interruptMsgProc);
- return true;
+ return;
}
if (msg_type == NetMsgType::GETBLOCKS) {
@@ -2610,7 +2619,7 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
if (locator.vHave.size() > MAX_LOCATOR_SZ) {
LogPrint(BCLog::NET, "getblocks locator size %lld > %d, disconnect peer=%d\n", locator.vHave.size(), MAX_LOCATOR_SZ, pfrom.GetId());
pfrom.fDisconnect = true;
- return true;
+ return;
}
// We might have announced the currently-being-connected tip using a
@@ -2657,7 +2666,7 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
LogPrint(BCLog::NET, " getblocks stopping, pruned or too old block at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
break;
}
- pfrom.PushInventory(CInv(MSG_BLOCK, pindex->GetBlockHash()));
+ pfrom.PushBlockInventory(pindex->GetBlockHash());
if (--nLimit <= 0)
{
// When this block is requested, we'll send an inv that'll
@@ -2667,7 +2676,7 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
break;
}
}
- return true;
+ return;
}
if (msg_type == NetMsgType::GETBLOCKTXN) {
@@ -2683,7 +2692,7 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
}
if (recent_block) {
SendBlockTransactions(*recent_block, req, pfrom, connman);
- return true;
+ return;
}
LOCK(cs_main);
@@ -2691,7 +2700,7 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
const CBlockIndex* pindex = LookupBlockIndex(req.blockhash);
if (!pindex || !(pindex->nStatus & BLOCK_HAVE_DATA)) {
LogPrint(BCLog::NET, "Peer %d sent us a getblocktxn for a block we don't have\n", pfrom.GetId());
- return true;
+ return;
}
if (pindex->nHeight < ::ChainActive().Height() - MAX_BLOCKTXN_DEPTH) {
@@ -2708,7 +2717,7 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
inv.hash = req.blockhash;
pfrom.vRecvGetData.push_back(inv);
// The message processing loop will go around again (without pausing) and we'll respond then (without cs_main)
- return true;
+ return;
}
CBlock block;
@@ -2716,7 +2725,7 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
assert(ret);
SendBlockTransactions(block, req, pfrom, connman);
- return true;
+ return;
}
if (msg_type == NetMsgType::GETHEADERS) {
@@ -2727,13 +2736,13 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
if (locator.vHave.size() > MAX_LOCATOR_SZ) {
LogPrint(BCLog::NET, "getheaders locator size %lld > %d, disconnect peer=%d\n", locator.vHave.size(), MAX_LOCATOR_SZ, pfrom.GetId());
pfrom.fDisconnect = true;
- return true;
+ return;
}
LOCK(cs_main);
if (::ChainstateActive().IsInitialBlockDownload() && !pfrom.HasPermission(PF_NOBAN)) {
LogPrint(BCLog::NET, "Ignoring getheaders from peer=%d because node is in initial block download\n", pfrom.GetId());
- return true;
+ return;
}
CNodeState *nodestate = State(pfrom.GetId());
@@ -2743,12 +2752,12 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
// If locator is null, return the hashStop block
pindex = LookupBlockIndex(hashStop);
if (!pindex) {
- return true;
+ return;
}
if (!BlockRequestAllowed(pindex, chainparams.GetConsensus())) {
LogPrint(BCLog::NET, "%s: ignoring request from peer=%i for old block header that isn't in the main chain\n", __func__, pfrom.GetId());
- return true;
+ return;
}
}
else
@@ -2783,7 +2792,7 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
// in the SendMessages logic.
nodestate->pindexBestHeaderSent = pindex ? pindex : ::ChainActive().Tip();
connman->PushMessage(&pfrom, msgMaker.Make(NetMsgType::HEADERS, vHeaders));
- return true;
+ return;
}
if (msg_type == NetMsgType::TX) {
@@ -2794,7 +2803,7 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
{
LogPrint(BCLog::NET, "transaction sent in violation of protocol peer=%d\n", pfrom.GetId());
pfrom.fDisconnect = true;
- return true;
+ return;
}
CTransactionRef ptx;
@@ -2925,7 +2934,7 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
state.ToString());
MaybePunishNodeForTx(pfrom.GetId(), state);
}
- return true;
+ return;
}
if (msg_type == NetMsgType::CMPCTBLOCK)
@@ -2933,7 +2942,7 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
// Ignore cmpctblock received while importing
if (fImporting || fReindex) {
LogPrint(BCLog::NET, "Unexpected cmpctblock message received from peer %d\n", pfrom.GetId());
- return true;
+ return;
}
CBlockHeaderAndShortTxIDs cmpctblock;
@@ -2948,7 +2957,7 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
// Doesn't connect (or is genesis), instead of DoSing in AcceptBlockHeader, request deeper headers
if (!::ChainstateActive().IsInitialBlockDownload())
connman->PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexBestHeader), uint256()));
- return true;
+ return;
}
if (!LookupBlockIndex(cmpctblock.header.GetHash())) {
@@ -2961,7 +2970,7 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
if (!chainman.ProcessNewBlockHeaders({cmpctblock.header}, state, chainparams, &pindex)) {
if (state.IsInvalid()) {
MaybePunishNodeForBlock(pfrom.GetId(), state, /*via_compact_block*/ true, "invalid header via cmpctblock");
- return true;
+ return;
}
}
@@ -2999,7 +3008,7 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
bool fAlreadyInFlight = blockInFlightIt != mapBlocksInFlight.end();
if (pindex->nStatus & BLOCK_HAVE_DATA) // Nothing to do here
- return true;
+ return;
if (pindex->nChainWork <= ::ChainActive().Tip()->nChainWork || // We know something better
pindex->nTx != 0) { // We had this block at some point, but pruned it
@@ -3010,17 +3019,17 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
vInv[0] = CInv(MSG_BLOCK | GetFetchFlags(pfrom), cmpctblock.header.GetHash());
connman->PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv));
}
- return true;
+ return;
}
// If we're not close to tip yet, give up and let parallel block fetch work its magic
if (!fAlreadyInFlight && !CanDirectFetch(chainparams.GetConsensus()))
- return true;
+ return;
if (IsWitnessEnabled(pindex->pprev, chainparams.GetConsensus()) && !nodestate->fSupportsDesiredCmpctVersion) {
// Don't bother trying to process compact blocks from v1 peers
// after segwit activates.
- return true;
+ return;
}
// We want to be a bit conservative just to be extra careful about DoS
@@ -3035,7 +3044,7 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
else {
// The block was already in flight using compact blocks from the same peer
LogPrint(BCLog::NET, "Peer sent us compact block we were already syncing!\n");
- return true;
+ return;
}
}
@@ -3044,13 +3053,13 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
if (status == READ_STATUS_INVALID) {
MarkBlockAsReceived(pindex->GetBlockHash()); // Reset in-flight state in case of whitelist
Misbehaving(pfrom.GetId(), 100, strprintf("Peer %d sent us invalid compact block\n", pfrom.GetId()));
- return true;
+ return;
} else if (status == READ_STATUS_FAILED) {
// Duplicate txindexes, the block is now in-flight, so just request it
std::vector<CInv> vInv(1);
vInv[0] = CInv(MSG_BLOCK | GetFetchFlags(pfrom), cmpctblock.header.GetHash());
connman->PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv));
- return true;
+ return;
}
BlockTransactionsRequest req;
@@ -3078,7 +3087,7 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
ReadStatus status = tempBlock.InitData(cmpctblock, vExtraTxnForCompact);
if (status != READ_STATUS_OK) {
// TODO: don't ignore failures
- return true;
+ return;
}
std::vector<CTransactionRef> dummy;
status = tempBlock.FillBlock(*pblock, dummy);
@@ -3093,7 +3102,7 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
std::vector<CInv> vInv(1);
vInv[0] = CInv(MSG_BLOCK | GetFetchFlags(pfrom), cmpctblock.header.GetHash());
connman->PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv));
- return true;
+ return;
} else {
// If this was an announce-cmpctblock, we want the same treatment as a header message
fRevertToHeaderProcessing = true;
@@ -3146,7 +3155,7 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
MarkBlockAsReceived(pblock->GetHash());
}
}
- return true;
+ return;
}
if (msg_type == NetMsgType::BLOCKTXN)
@@ -3154,7 +3163,7 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
// Ignore blocktxn received while importing
if (fImporting || fReindex) {
LogPrint(BCLog::NET, "Unexpected blocktxn message received from peer %d\n", pfrom.GetId());
- return true;
+ return;
}
BlockTransactions resp;
@@ -3169,7 +3178,7 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
if (it == mapBlocksInFlight.end() || !it->second.second->partialBlock ||
it->second.first != pfrom.GetId()) {
LogPrint(BCLog::NET, "Peer %d sent us block transactions for block we weren't expecting\n", pfrom.GetId());
- return true;
+ return;
}
PartiallyDownloadedBlock& partialBlock = *it->second.second->partialBlock;
@@ -3177,7 +3186,7 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
if (status == READ_STATUS_INVALID) {
MarkBlockAsReceived(resp.blockhash); // Reset in-flight state in case of whitelist
Misbehaving(pfrom.GetId(), 100, strprintf("Peer %d sent us invalid compact block/non-matching block transactions\n", pfrom.GetId()));
- return true;
+ return;
} else if (status == READ_STATUS_FAILED) {
// Might have collided, fall back to getdata now :(
std::vector<CInv> invs;
@@ -3228,7 +3237,7 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
mapBlockSource.erase(pblock->GetHash());
}
}
- return true;
+ return;
}
if (msg_type == NetMsgType::HEADERS)
@@ -3236,7 +3245,7 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
// Ignore headers received while importing
if (fImporting || fReindex) {
LogPrint(BCLog::NET, "Unexpected headers message received from peer %d\n", pfrom.GetId());
- return true;
+ return;
}
std::vector<CBlockHeader> headers;
@@ -3246,7 +3255,7 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
if (nCount > MAX_HEADERS_RESULTS) {
LOCK(cs_main);
Misbehaving(pfrom.GetId(), 20, strprintf("headers message size = %u", nCount));
- return false;
+ return;
}
headers.resize(nCount);
for (unsigned int n = 0; n < nCount; n++) {
@@ -3262,7 +3271,7 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
// Ignore block received while importing
if (fImporting || fReindex) {
LogPrint(BCLog::NET, "Unexpected block message received from peer %d\n", pfrom.GetId());
- return true;
+ return;
}
std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
@@ -3290,7 +3299,7 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
LOCK(cs_main);
mapBlockSource.erase(pblock->GetHash());
}
- return true;
+ return;
}
if (msg_type == NetMsgType::GETADDR) {
@@ -3301,18 +3310,18 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
// the getaddr message mitigates the attack.
if (!pfrom.fInbound) {
LogPrint(BCLog::NET, "Ignoring \"getaddr\" from outbound connection. peer=%d\n", pfrom.GetId());
- return true;
+ return;
}
if (!pfrom.IsAddrRelayPeer()) {
LogPrint(BCLog::NET, "Ignoring \"getaddr\" from block-relay-only connection. peer=%d\n", pfrom.GetId());
- return true;
+ return;
}
// Only send one GetAddr response per connection to reduce resource waste
// and discourage addr stamping of INV announcements.
if (pfrom.fSentAddr) {
LogPrint(BCLog::NET, "Ignoring repeated \"getaddr\". peer=%d\n", pfrom.GetId());
- return true;
+ return;
}
pfrom.fSentAddr = true;
@@ -3324,7 +3333,7 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
pfrom.PushAddress(addr, insecure_rand);
}
}
- return true;
+ return;
}
if (msg_type == NetMsgType::MEMPOOL) {
@@ -3335,7 +3344,7 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
LogPrint(BCLog::NET, "mempool request with bloom filters disabled, disconnect peer=%d\n", pfrom.GetId());
pfrom.fDisconnect = true;
}
- return true;
+ return;
}
if (connman->OutboundTargetReached(false) && !pfrom.HasPermission(PF_MEMPOOL))
@@ -3345,14 +3354,14 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
LogPrint(BCLog::NET, "mempool request with bandwidth limit reached, disconnect peer=%d\n", pfrom.GetId());
pfrom.fDisconnect = true;
}
- return true;
+ return;
}
if (pfrom.m_tx_relay != nullptr) {
LOCK(pfrom.m_tx_relay->cs_tx_inventory);
pfrom.m_tx_relay->fSendMempool = true;
}
- return true;
+ return;
}
if (msg_type == NetMsgType::PING) {
@@ -3373,7 +3382,7 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
// return very quickly.
connman->PushMessage(&pfrom, msgMaker.Make(NetMsgType::PONG, nonce));
}
- return true;
+ return;
}
if (msg_type == NetMsgType::PONG) {
@@ -3429,13 +3438,13 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
if (bPingFinished) {
pfrom.nPingNonceSent = 0;
}
- return true;
+ return;
}
if (msg_type == NetMsgType::FILTERLOAD) {
if (!(pfrom.GetLocalServices() & NODE_BLOOM)) {
pfrom.fDisconnect = true;
- return true;
+ return;
}
CBloomFilter filter;
vRecv >> filter;
@@ -3452,13 +3461,13 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
pfrom.m_tx_relay->pfilter.reset(new CBloomFilter(filter));
pfrom.m_tx_relay->fRelayTxes = true;
}
- return true;
+ return;
}
if (msg_type == NetMsgType::FILTERADD) {
if (!(pfrom.GetLocalServices() & NODE_BLOOM)) {
pfrom.fDisconnect = true;
- return true;
+ return;
}
std::vector<unsigned char> vData;
vRecv >> vData;
@@ -3480,21 +3489,21 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
LOCK(cs_main);
Misbehaving(pfrom.GetId(), 100);
}
- return true;
+ return;
}
if (msg_type == NetMsgType::FILTERCLEAR) {
if (!(pfrom.GetLocalServices() & NODE_BLOOM)) {
pfrom.fDisconnect = true;
- return true;
+ return;
}
if (pfrom.m_tx_relay == nullptr) {
- return true;
+ return;
}
LOCK(pfrom.m_tx_relay->cs_filter);
pfrom.m_tx_relay->pfilter = nullptr;
pfrom.m_tx_relay->fRelayTxes = true;
- return true;
+ return;
}
if (msg_type == NetMsgType::FEEFILTER) {
@@ -3507,22 +3516,22 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
}
LogPrint(BCLog::NET, "received: feefilter of %s from peer=%d\n", CFeeRate(newFeeFilter).ToString(), pfrom.GetId());
}
- return true;
+ return;
}
if (msg_type == NetMsgType::GETCFILTERS) {
ProcessGetCFilters(pfrom, vRecv, chainparams, *connman);
- return true;
+ return;
}
if (msg_type == NetMsgType::GETCFHEADERS) {
ProcessGetCFHeaders(pfrom, vRecv, chainparams, *connman);
- return true;
+ return;
}
if (msg_type == NetMsgType::GETCFCHECKPT) {
ProcessGetCFCheckPt(pfrom, vRecv, chainparams, *connman);
- return true;
+ return;
}
if (msg_type == NetMsgType::NOTFOUND) {
@@ -3547,12 +3556,12 @@ bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRec
}
}
}
- return true;
+ return;
}
// Ignore unknown commands for extensibility
LogPrint(BCLog::NET, "Unknown command \"%s\" from peer=%d\n", SanitizeString(msg_type), pfrom.GetId());
- return true;
+ return;
}
bool PeerLogicValidation::CheckIfBanned(CNode& pnode)
@@ -3660,11 +3669,8 @@ bool PeerLogicValidation::ProcessMessages(CNode* pfrom, std::atomic<bool>& inter
return fMoreWork;
}
- // Process message
- bool fRet = false;
- try
- {
- fRet = ProcessMessage(*pfrom, msg_type, vRecv, msg.m_time, chainparams, m_chainman, m_mempool, connman, m_banman, interruptMsgProc);
+ try {
+ ProcessMessage(*pfrom, msg_type, vRecv, msg.m_time, chainparams, m_chainman, m_mempool, connman, m_banman, interruptMsgProc);
if (interruptMsgProc)
return false;
if (!pfrom->vRecvGetData.empty())
@@ -3675,10 +3681,6 @@ bool PeerLogicValidation::ProcessMessages(CNode* pfrom, std::atomic<bool>& inter
LogPrint(BCLog::NET, "%s(%s, %u bytes): Unknown exception caught\n", __func__, SanitizeString(msg_type), nMessageSize);
}
- if (!fRet) {
- LogPrint(BCLog::NET, "%s(%s, %u bytes) FAILED peer=%d\n", __func__, SanitizeString(msg_type), nMessageSize, pfrom->GetId());
- }
-
LOCK(cs_main);
CheckIfBanned(*pfrom);
@@ -4081,7 +4083,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
// If the peer's chain has this block, don't inv it back.
if (!PeerHasHeader(&state, pindex)) {
- pto->PushInventory(CInv(MSG_BLOCK, hashToAnnounce));
+ pto->PushBlockInventory(hashToAnnounce);
LogPrint(BCLog::NET, "%s: sending inv peer=%d hash=%s\n", __func__,
pto->GetId(), hashToAnnounce.ToString());
}
diff --git a/src/netmessagemaker.h b/src/netmessagemaker.h
index 2efb384a7b..ffb3fe2f29 100644
--- a/src/netmessagemaker.h
+++ b/src/netmessagemaker.h
@@ -15,18 +15,18 @@ public:
explicit CNetMsgMaker(int nVersionIn) : nVersion(nVersionIn){}
template <typename... Args>
- CSerializedNetMsg Make(int nFlags, std::string sCommand, Args&&... args) const
+ CSerializedNetMsg Make(int nFlags, std::string msg_type, Args&&... args) const
{
CSerializedNetMsg msg;
- msg.command = std::move(sCommand);
+ msg.m_type = std::move(msg_type);
CVectorWriter{ SER_NETWORK, nFlags | nVersion, msg.data, 0, std::forward<Args>(args)... };
return msg;
}
template <typename... Args>
- CSerializedNetMsg Make(std::string sCommand, Args&&... args) const
+ CSerializedNetMsg Make(std::string msg_type, Args&&... args) const
{
- return Make(0, std::move(sCommand), std::forward<Args>(args)...);
+ return Make(0, std::move(msg_type), std::forward<Args>(args)...);
}
private:
diff --git a/src/qt/bitcoinamountfield.cpp b/src/qt/bitcoinamountfield.cpp
index 4c57f1e352..a953c991bc 100644
--- a/src/qt/bitcoinamountfield.cpp
+++ b/src/qt/bitcoinamountfield.cpp
@@ -56,7 +56,7 @@ public:
if (valid) {
val = qBound(m_min_amount, val, m_max_amount);
- input = BitcoinUnits::format(currentUnit, val, false, BitcoinUnits::separatorAlways);
+ input = BitcoinUnits::format(currentUnit, val, false, BitcoinUnits::SeparatorStyle::ALWAYS);
lineEdit()->setText(input);
}
}
@@ -68,7 +68,7 @@ public:
void setValue(const CAmount& value)
{
- lineEdit()->setText(BitcoinUnits::format(currentUnit, value, false, BitcoinUnits::separatorAlways));
+ lineEdit()->setText(BitcoinUnits::format(currentUnit, value, false, BitcoinUnits::SeparatorStyle::ALWAYS));
Q_EMIT valueChanged();
}
@@ -102,7 +102,7 @@ public:
CAmount val = value(&valid);
currentUnit = unit;
- lineEdit()->setPlaceholderText(BitcoinUnits::format(currentUnit, m_min_amount, false, BitcoinUnits::separatorAlways));
+ lineEdit()->setPlaceholderText(BitcoinUnits::format(currentUnit, m_min_amount, false, BitcoinUnits::SeparatorStyle::ALWAYS));
if(valid)
setValue(val);
else
@@ -122,7 +122,7 @@ public:
const QFontMetrics fm(fontMetrics());
int h = lineEdit()->minimumSizeHint().height();
- int w = GUIUtil::TextWidth(fm, BitcoinUnits::format(BitcoinUnits::BTC, BitcoinUnits::maxMoney(), false, BitcoinUnits::separatorAlways));
+ int w = GUIUtil::TextWidth(fm, BitcoinUnits::format(BitcoinUnits::BTC, BitcoinUnits::maxMoney(), false, BitcoinUnits::SeparatorStyle::ALWAYS));
w += 2; // cursor blinking space
QStyleOptionSpinBox opt;
diff --git a/src/qt/bitcoinunits.cpp b/src/qt/bitcoinunits.cpp
index 318a6dcbfd..fd55c547fc 100644
--- a/src/qt/bitcoinunits.cpp
+++ b/src/qt/bitcoinunits.cpp
@@ -114,7 +114,7 @@ QString BitcoinUnits::format(int unit, const CAmount& nIn, bool fPlus, Separator
// confused with the decimal marker.
QChar thin_sp(THIN_SP_CP);
int q_size = quotient_str.size();
- if (separators == separatorAlways || (separators == separatorStandard && q_size > 4))
+ if (separators == SeparatorStyle::ALWAYS || (separators == SeparatorStyle::STANDARD && q_size > 4))
for (int i = 3; i < q_size; i += 3)
quotient_str.insert(q_size - i, thin_sp);
diff --git a/src/qt/bitcoinunits.h b/src/qt/bitcoinunits.h
index dac5484393..e22ba0a938 100644
--- a/src/qt/bitcoinunits.h
+++ b/src/qt/bitcoinunits.h
@@ -46,11 +46,11 @@ public:
SAT
};
- enum SeparatorStyle
+ enum class SeparatorStyle
{
- separatorNever,
- separatorStandard,
- separatorAlways
+ NEVER,
+ STANDARD,
+ ALWAYS
};
//! @name Static API
@@ -72,11 +72,11 @@ public:
//! Number of decimals left
static int decimals(int unit);
//! Format as string
- static QString format(int unit, const CAmount& amount, bool plussign = false, SeparatorStyle separators = separatorStandard, bool justify = false);
+ static QString format(int unit, const CAmount& amount, bool plussign = false, SeparatorStyle separators = SeparatorStyle::STANDARD, bool justify = false);
//! Format as string (with unit)
- static QString formatWithUnit(int unit, const CAmount& amount, bool plussign=false, SeparatorStyle separators=separatorStandard);
+ static QString formatWithUnit(int unit, const CAmount& amount, bool plussign=false, SeparatorStyle separators=SeparatorStyle::STANDARD);
//! Format as HTML string (with unit)
- static QString formatHtmlWithUnit(int unit, const CAmount& amount, bool plussign=false, SeparatorStyle separators=separatorStandard);
+ static QString formatHtmlWithUnit(int unit, const CAmount& amount, bool plussign=false, SeparatorStyle separators=SeparatorStyle::STANDARD);
//! Format as string (with unit) of fixed length to preserve privacy, if it is set.
static QString formatWithPrivacy(int unit, const CAmount& amount, SeparatorStyle separators, bool privacy);
//! Parse string to coin amount
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index ce44d4f3a5..3cadac2f2f 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -188,7 +188,7 @@ QString formatBitcoinURI(const SendCoinsRecipient &info)
if (info.amount)
{
- ret += QString("?amount=%1").arg(BitcoinUnits::format(BitcoinUnits::BTC, info.amount, false, BitcoinUnits::separatorNever));
+ ret += QString("?amount=%1").arg(BitcoinUnits::format(BitcoinUnits::BTC, info.amount, false, BitcoinUnits::SeparatorStyle::NEVER));
paramCount++;
}
diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp
index 0af70f2735..b536567c8b 100644
--- a/src/qt/overviewpage.cpp
+++ b/src/qt/overviewpage.cpp
@@ -88,7 +88,7 @@ public:
foreground = option.palette.color(QPalette::Text);
}
painter->setPen(foreground);
- QString amountText = BitcoinUnits::formatWithUnit(unit, amount, true, BitcoinUnits::separatorAlways);
+ QString amountText = BitcoinUnits::formatWithUnit(unit, amount, true, BitcoinUnits::SeparatorStyle::ALWAYS);
if(!confirmed)
{
amountText = QString("[") + amountText + QString("]");
@@ -180,25 +180,25 @@ void OverviewPage::setBalance(const interfaces::WalletBalances& balances)
m_balances = balances;
if (walletModel->wallet().isLegacy()) {
if (walletModel->wallet().privateKeysDisabled()) {
- ui->labelBalance->setText(BitcoinUnits::formatWithPrivacy(unit, balances.watch_only_balance, BitcoinUnits::separatorAlways, m_privacy));
- ui->labelUnconfirmed->setText(BitcoinUnits::formatWithPrivacy(unit, balances.unconfirmed_watch_only_balance, BitcoinUnits::separatorAlways, m_privacy));
- ui->labelImmature->setText(BitcoinUnits::formatWithPrivacy(unit, balances.immature_watch_only_balance, BitcoinUnits::separatorAlways, m_privacy));
- ui->labelTotal->setText(BitcoinUnits::formatWithPrivacy(unit, balances.watch_only_balance + balances.unconfirmed_watch_only_balance + balances.immature_watch_only_balance, BitcoinUnits::separatorAlways, m_privacy));
+ ui->labelBalance->setText(BitcoinUnits::formatWithPrivacy(unit, balances.watch_only_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
+ ui->labelUnconfirmed->setText(BitcoinUnits::formatWithPrivacy(unit, balances.unconfirmed_watch_only_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
+ ui->labelImmature->setText(BitcoinUnits::formatWithPrivacy(unit, balances.immature_watch_only_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
+ ui->labelTotal->setText(BitcoinUnits::formatWithPrivacy(unit, balances.watch_only_balance + balances.unconfirmed_watch_only_balance + balances.immature_watch_only_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
} else {
- ui->labelBalance->setText(BitcoinUnits::formatWithPrivacy(unit, balances.balance, BitcoinUnits::separatorAlways, m_privacy));
- ui->labelUnconfirmed->setText(BitcoinUnits::formatWithPrivacy(unit, balances.unconfirmed_balance, BitcoinUnits::separatorAlways, m_privacy));
- ui->labelImmature->setText(BitcoinUnits::formatWithPrivacy(unit, balances.immature_balance, BitcoinUnits::separatorAlways, m_privacy));
- ui->labelTotal->setText(BitcoinUnits::formatWithPrivacy(unit, balances.balance + balances.unconfirmed_balance + balances.immature_balance, BitcoinUnits::separatorAlways, m_privacy));
- ui->labelWatchAvailable->setText(BitcoinUnits::formatWithPrivacy(unit, balances.watch_only_balance, BitcoinUnits::separatorAlways, m_privacy));
- ui->labelWatchPending->setText(BitcoinUnits::formatWithPrivacy(unit, balances.unconfirmed_watch_only_balance, BitcoinUnits::separatorAlways, m_privacy));
- ui->labelWatchImmature->setText(BitcoinUnits::formatWithPrivacy(unit, balances.immature_watch_only_balance, BitcoinUnits::separatorAlways, m_privacy));
- ui->labelWatchTotal->setText(BitcoinUnits::formatWithPrivacy(unit, balances.watch_only_balance + balances.unconfirmed_watch_only_balance + balances.immature_watch_only_balance, BitcoinUnits::separatorAlways, m_privacy));
+ ui->labelBalance->setText(BitcoinUnits::formatWithPrivacy(unit, balances.balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
+ ui->labelUnconfirmed->setText(BitcoinUnits::formatWithPrivacy(unit, balances.unconfirmed_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
+ ui->labelImmature->setText(BitcoinUnits::formatWithPrivacy(unit, balances.immature_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
+ ui->labelTotal->setText(BitcoinUnits::formatWithPrivacy(unit, balances.balance + balances.unconfirmed_balance + balances.immature_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
+ ui->labelWatchAvailable->setText(BitcoinUnits::formatWithPrivacy(unit, balances.watch_only_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
+ ui->labelWatchPending->setText(BitcoinUnits::formatWithPrivacy(unit, balances.unconfirmed_watch_only_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
+ ui->labelWatchImmature->setText(BitcoinUnits::formatWithPrivacy(unit, balances.immature_watch_only_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
+ ui->labelWatchTotal->setText(BitcoinUnits::formatWithPrivacy(unit, balances.watch_only_balance + balances.unconfirmed_watch_only_balance + balances.immature_watch_only_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
}
} else {
- ui->labelBalance->setText(BitcoinUnits::formatWithPrivacy(unit, balances.balance, BitcoinUnits::separatorAlways, m_privacy));
- ui->labelUnconfirmed->setText(BitcoinUnits::formatWithPrivacy(unit, balances.unconfirmed_balance, BitcoinUnits::separatorAlways, m_privacy));
- ui->labelImmature->setText(BitcoinUnits::formatWithPrivacy(unit, balances.immature_balance, BitcoinUnits::separatorAlways, m_privacy));
- ui->labelTotal->setText(BitcoinUnits::formatWithPrivacy(unit, balances.balance + balances.unconfirmed_balance + balances.immature_balance, BitcoinUnits::separatorAlways, m_privacy));
+ ui->labelBalance->setText(BitcoinUnits::formatWithPrivacy(unit, balances.balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
+ ui->labelUnconfirmed->setText(BitcoinUnits::formatWithPrivacy(unit, balances.unconfirmed_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
+ ui->labelImmature->setText(BitcoinUnits::formatWithPrivacy(unit, balances.immature_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
+ ui->labelTotal->setText(BitcoinUnits::formatWithPrivacy(unit, balances.balance + balances.unconfirmed_balance + balances.immature_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
}
// only show immature (newly mined) balance if it's non-zero, so as not to complicate things
// for the non-mining users
diff --git a/src/qt/recentrequeststablemodel.cpp b/src/qt/recentrequeststablemodel.cpp
index 7419297a96..3e20368a36 100644
--- a/src/qt/recentrequeststablemodel.cpp
+++ b/src/qt/recentrequeststablemodel.cpp
@@ -82,7 +82,7 @@ QVariant RecentRequestsTableModel::data(const QModelIndex &index, int role) cons
if (rec->recipient.amount == 0 && role == Qt::DisplayRole)
return tr("(no amount requested)");
else if (role == Qt::EditRole)
- return BitcoinUnits::format(walletModel->getOptionsModel()->getDisplayUnit(), rec->recipient.amount, false, BitcoinUnits::separatorNever);
+ return BitcoinUnits::format(walletModel->getOptionsModel()->getDisplayUnit(), rec->recipient.amount, false, BitcoinUnits::SeparatorStyle::NEVER);
else
return BitcoinUnits::format(walletModel->getOptionsModel()->getDisplayUnit(), rec->recipient.amount);
}
diff --git a/src/qt/test/addressbooktests.cpp b/src/qt/test/addressbooktests.cpp
index 476128520c..9347ff9e42 100644
--- a/src/qt/test/addressbooktests.cpp
+++ b/src/qt/test/addressbooktests.cpp
@@ -59,7 +59,7 @@ void EditAddressAndSubmit(
void TestAddAddressesToSendBook(interfaces::Node& node)
{
TestChain100Setup test;
- std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(node.context()->chain.get(), WalletLocation(), WalletDatabase::CreateMock());
+ std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(node.context()->chain.get(), WalletLocation(), CreateMockWalletDatabase());
wallet->SetupLegacyScriptPubKeyMan();
bool firstRun;
wallet->LoadWallet(firstRun);
diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp
index 8da0250e57..6648029bae 100644
--- a/src/qt/test/wallettests.cpp
+++ b/src/qt/test/wallettests.cpp
@@ -140,7 +140,7 @@ void TestGUI(interfaces::Node& node)
}
node.context()->connman = std::move(test.m_node.connman);
node.context()->mempool = std::move(test.m_node.mempool);
- std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(node.context()->chain.get(), WalletLocation(), WalletDatabase::CreateMock());
+ std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(node.context()->chain.get(), WalletLocation(), CreateMockWalletDatabase());
bool firstRun;
wallet->LoadWallet(firstRun);
{
@@ -178,7 +178,7 @@ void TestGUI(interfaces::Node& node)
QString balanceText = balanceLabel->text();
int unit = walletModel.getOptionsModel()->getDisplayUnit();
CAmount balance = walletModel.wallet().getBalance();
- QString balanceComparison = BitcoinUnits::formatWithUnit(unit, balance, false, BitcoinUnits::separatorAlways);
+ QString balanceComparison = BitcoinUnits::formatWithUnit(unit, balance, false, BitcoinUnits::SeparatorStyle::ALWAYS);
QCOMPARE(balanceText, balanceComparison);
}
@@ -204,7 +204,7 @@ void TestGUI(interfaces::Node& node)
QString balanceText = balanceLabel->text().trimmed();
int unit = walletModel.getOptionsModel()->getDisplayUnit();
CAmount balance = walletModel.wallet().getBalance();
- QString balanceComparison = BitcoinUnits::formatWithUnit(unit, balance, false, BitcoinUnits::separatorAlways);
+ QString balanceComparison = BitcoinUnits::formatWithUnit(unit, balance, false, BitcoinUnits::SeparatorStyle::ALWAYS);
QCOMPARE(balanceText, balanceComparison);
// Check Request Payment button
diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp
index 04eb1ae706..327a489488 100644
--- a/src/qt/transactiontablemodel.cpp
+++ b/src/qt/transactiontablemodel.cpp
@@ -524,7 +524,7 @@ QVariant TransactionTableModel::data(const QModelIndex &index, int role) const
case ToAddress:
return formatTxToAddress(rec, false);
case Amount:
- return formatTxAmount(rec, true, BitcoinUnits::separatorAlways);
+ return formatTxAmount(rec, true, BitcoinUnits::SeparatorStyle::ALWAYS);
}
break;
case Qt::EditRole:
@@ -614,14 +614,14 @@ QVariant TransactionTableModel::data(const QModelIndex &index, int role) const
details.append(QString::fromStdString(rec->address));
details.append(" ");
}
- details.append(formatTxAmount(rec, false, BitcoinUnits::separatorNever));
+ details.append(formatTxAmount(rec, false, BitcoinUnits::SeparatorStyle::NEVER));
return details;
}
case ConfirmedRole:
return rec->status.status == TransactionStatus::Status::Confirming || rec->status.status == TransactionStatus::Status::Confirmed;
case FormattedAmountRole:
// Used for copy/export, so don't include separators
- return formatTxAmount(rec, false, BitcoinUnits::separatorNever);
+ return formatTxAmount(rec, false, BitcoinUnits::SeparatorStyle::NEVER);
case StatusRole:
return rec->status.status;
}
diff --git a/src/qt/transactiontablemodel.h b/src/qt/transactiontablemodel.h
index f06f0ea15f..4b699d4d7d 100644
--- a/src/qt/transactiontablemodel.h
+++ b/src/qt/transactiontablemodel.h
@@ -101,7 +101,7 @@ private:
QString formatTxDate(const TransactionRecord *wtx) const;
QString formatTxType(const TransactionRecord *wtx) const;
QString formatTxToAddress(const TransactionRecord *wtx, bool tooltip) const;
- QString formatTxAmount(const TransactionRecord *wtx, bool showUnconfirmed=true, BitcoinUnits::SeparatorStyle separators=BitcoinUnits::separatorStandard) const;
+ QString formatTxAmount(const TransactionRecord *wtx, bool showUnconfirmed=true, BitcoinUnits::SeparatorStyle separators=BitcoinUnits::SeparatorStyle::STANDARD) const;
QString formatTooltip(const TransactionRecord *rec) const;
QVariant txStatusDecoration(const TransactionRecord *wtx) const;
QVariant txWatchonlyDecoration(const TransactionRecord *wtx) const;
diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp
index ed0175bb10..7a5421ab6f 100644
--- a/src/script/descriptor.cpp
+++ b/src/script/descriptor.cpp
@@ -139,7 +139,7 @@ std::string DescriptorChecksum(const Span<const char>& span)
return ret;
}
-std::string AddChecksum(const std::string& str) { return str + "#" + DescriptorChecksum(MakeSpan(str)); }
+std::string AddChecksum(const std::string& str) { return str + "#" + DescriptorChecksum(str); }
////////////////////////////////////////////////////////////////////////////
// Internal representation //
@@ -1087,7 +1087,7 @@ bool CheckChecksum(Span<const char>& sp, bool require_checksum, std::string& err
std::unique_ptr<Descriptor> Parse(const std::string& descriptor, FlatSigningProvider& out, std::string& error, bool require_checksum)
{
- Span<const char> sp(descriptor.data(), descriptor.size());
+ Span<const char> sp{descriptor};
if (!CheckChecksum(sp, require_checksum, error)) return nullptr;
auto ret = ParseScript(0, sp, ParseScriptContext::TOP, out, error);
if (sp.size() == 0 && ret) return std::unique_ptr<Descriptor>(std::move(ret));
@@ -1098,7 +1098,7 @@ std::string GetDescriptorChecksum(const std::string& descriptor)
{
std::string ret;
std::string error;
- Span<const char> sp(descriptor.data(), descriptor.size());
+ Span<const char> sp{descriptor};
if (!CheckChecksum(sp, false, error, &ret)) return "";
return ret;
}
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index 23d5b72a5c..9415bba585 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -1522,7 +1522,7 @@ static bool ExecuteWitnessScript(const Span<const valtype>& stack_span, const CS
static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, const std::vector<unsigned char>& program, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror)
{
CScript scriptPubKey;
- Span<const valtype> stack = MakeSpan(witness.stack);
+ Span<const valtype> stack{witness.stack};
if (witversion == 0) {
if (program.size() == WITNESS_V0_SCRIPTHASH_SIZE) {
diff --git a/src/script/standard.cpp b/src/script/standard.cpp
index c90c2c24a0..d199a84cee 100644
--- a/src/script/standard.cpp
+++ b/src/script/standard.cpp
@@ -241,59 +241,47 @@ bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::
namespace
{
-class CScriptVisitor : public boost::static_visitor<bool>
+class CScriptVisitor : public boost::static_visitor<CScript>
{
-private:
- CScript *script;
public:
- explicit CScriptVisitor(CScript *scriptin) { script = scriptin; }
-
- bool operator()(const CNoDestination &dest) const {
- script->clear();
- return false;
+ CScript operator()(const CNoDestination& dest) const
+ {
+ return CScript();
}
- bool operator()(const PKHash &keyID) const {
- script->clear();
- *script << OP_DUP << OP_HASH160 << ToByteVector(keyID) << OP_EQUALVERIFY << OP_CHECKSIG;
- return true;
+ CScript operator()(const PKHash& keyID) const
+ {
+ return CScript() << OP_DUP << OP_HASH160 << ToByteVector(keyID) << OP_EQUALVERIFY << OP_CHECKSIG;
}
- bool operator()(const ScriptHash &scriptID) const {
- script->clear();
- *script << OP_HASH160 << ToByteVector(scriptID) << OP_EQUAL;
- return true;
+ CScript operator()(const ScriptHash& scriptID) const
+ {
+ return CScript() << OP_HASH160 << ToByteVector(scriptID) << OP_EQUAL;
}
- bool operator()(const WitnessV0KeyHash& id) const
+ CScript operator()(const WitnessV0KeyHash& id) const
{
- script->clear();
- *script << OP_0 << ToByteVector(id);
- return true;
+ return CScript() << OP_0 << ToByteVector(id);
}
- bool operator()(const WitnessV0ScriptHash& id) const
+ CScript operator()(const WitnessV0ScriptHash& id) const
{
- script->clear();
- *script << OP_0 << ToByteVector(id);
- return true;
+ return CScript() << OP_0 << ToByteVector(id);
}
- bool operator()(const WitnessUnknown& id) const
+ CScript operator()(const WitnessUnknown& id) const
{
- script->clear();
- *script << CScript::EncodeOP_N(id.version) << std::vector<unsigned char>(id.program, id.program + id.length);
- return true;
+ return CScript() << CScript::EncodeOP_N(id.version) << std::vector<unsigned char>(id.program, id.program + id.length);
}
};
+
+const CScriptVisitor g_script_visitor;
+
} // namespace
CScript GetScriptForDestination(const CTxDestination& dest)
{
- CScript script;
-
- boost::apply_visitor(CScriptVisitor(&script), dest);
- return script;
+ return boost::apply_visitor(::g_script_visitor, dest);
}
CScript GetScriptForRawPubKey(const CPubKey& pubKey)
diff --git a/src/span.h b/src/span.h
index 73b37e35f3..4931507719 100644
--- a/src/span.h
+++ b/src/span.h
@@ -10,6 +10,14 @@
#include <algorithm>
#include <assert.h>
+#ifdef DEBUG
+#define CONSTEXPR_IF_NOT_DEBUG
+#define ASSERT_IF_DEBUG(x) assert((x))
+#else
+#define CONSTEXPR_IF_NOT_DEBUG constexpr
+#define ASSERT_IF_DEBUG(x)
+#endif
+
/** A Span is an object that can refer to a contiguous sequence of objects.
*
* It implements a subset of C++20's std::span.
@@ -18,12 +26,29 @@ template<typename C>
class Span
{
C* m_data;
- std::ptrdiff_t m_size;
+ std::size_t m_size;
public:
constexpr Span() noexcept : m_data(nullptr), m_size(0) {}
- constexpr Span(C* data, std::ptrdiff_t size) noexcept : m_data(data), m_size(size) {}
- constexpr Span(C* data, C* end) noexcept : m_data(data), m_size(end - data) {}
+
+ /** Construct a span from a begin pointer and a size.
+ *
+ * This implements a subset of the iterator-based std::span constructor in C++20,
+ * which is hard to implement without std::address_of.
+ */
+ template <typename T, typename std::enable_if<std::is_convertible<T (*)[], C (*)[]>::value, int>::type = 0>
+ constexpr Span(T* begin, std::size_t size) noexcept : m_data(begin), m_size(size) {}
+
+ /** Construct a span from a begin and end pointer.
+ *
+ * This implements a subset of the iterator-based std::span constructor in C++20,
+ * which is hard to implement without std::address_of.
+ */
+ template <typename T, typename std::enable_if<std::is_convertible<T (*)[], C (*)[]>::value, int>::type = 0>
+ CONSTEXPR_IF_NOT_DEBUG Span(T* begin, T* end) noexcept : m_data(begin), m_size(end - begin)
+ {
+ ASSERT_IF_DEBUG(end >= begin);
+ }
/** Implicit conversion of spans between compatible types.
*
@@ -42,18 +67,59 @@ public:
/** Default assignment operator. */
Span& operator=(const Span& other) noexcept = default;
+ /** Construct a Span from an array. This matches the corresponding C++20 std::span constructor. */
+ template <int N>
+ constexpr Span(C (&a)[N]) noexcept : m_data(a), m_size(N) {}
+
+ /** Construct a Span for objects with .data() and .size() (std::string, std::array, std::vector, ...).
+ *
+ * This implements a subset of the functionality provided by the C++20 std::span range-based constructor.
+ *
+ * To prevent surprises, only Spans for constant value types are supported when passing in temporaries.
+ * Note that this restriction does not exist when converting arrays or other Spans (see above).
+ */
+ template <typename V, typename std::enable_if<(std::is_const<C>::value || std::is_lvalue_reference<V>::value) && std::is_convertible<typename std::remove_pointer<decltype(std::declval<V&>().data())>::type (*)[], C (*)[]>::value && std::is_convertible<decltype(std::declval<V&>().size()), std::size_t>::value, int>::type = 0>
+ constexpr Span(V&& v) noexcept : m_data(v.data()), m_size(v.size()) {}
+
constexpr C* data() const noexcept { return m_data; }
constexpr C* begin() const noexcept { return m_data; }
constexpr C* end() const noexcept { return m_data + m_size; }
- constexpr C& front() const noexcept { return m_data[0]; }
- constexpr C& back() const noexcept { return m_data[m_size - 1]; }
- constexpr std::ptrdiff_t size() const noexcept { return m_size; }
- constexpr C& operator[](std::ptrdiff_t pos) const noexcept { return m_data[pos]; }
-
- constexpr Span<C> subspan(std::ptrdiff_t offset) const noexcept { return Span<C>(m_data + offset, m_size - offset); }
- constexpr Span<C> subspan(std::ptrdiff_t offset, std::ptrdiff_t count) const noexcept { return Span<C>(m_data + offset, count); }
- constexpr Span<C> first(std::ptrdiff_t count) const noexcept { return Span<C>(m_data, count); }
- constexpr Span<C> last(std::ptrdiff_t count) const noexcept { return Span<C>(m_data + m_size - count, count); }
+ CONSTEXPR_IF_NOT_DEBUG C& front() const noexcept
+ {
+ ASSERT_IF_DEBUG(size() > 0);
+ return m_data[0];
+ }
+ CONSTEXPR_IF_NOT_DEBUG C& back() const noexcept
+ {
+ ASSERT_IF_DEBUG(size() > 0);
+ return m_data[m_size - 1];
+ }
+ constexpr std::size_t size() const noexcept { return m_size; }
+ CONSTEXPR_IF_NOT_DEBUG C& operator[](std::size_t pos) const noexcept
+ {
+ ASSERT_IF_DEBUG(size() > pos);
+ return m_data[pos];
+ }
+ CONSTEXPR_IF_NOT_DEBUG Span<C> subspan(std::size_t offset) const noexcept
+ {
+ ASSERT_IF_DEBUG(size() >= offset);
+ return Span<C>(m_data + offset, m_size - offset);
+ }
+ CONSTEXPR_IF_NOT_DEBUG Span<C> subspan(std::size_t offset, std::size_t count) const noexcept
+ {
+ ASSERT_IF_DEBUG(size() >= offset + count);
+ return Span<C>(m_data + offset, count);
+ }
+ CONSTEXPR_IF_NOT_DEBUG Span<C> first(std::size_t count) const noexcept
+ {
+ ASSERT_IF_DEBUG(size() >= count);
+ return Span<C>(m_data, count);
+ }
+ CONSTEXPR_IF_NOT_DEBUG Span<C> last(std::size_t count) const noexcept
+ {
+ ASSERT_IF_DEBUG(size() >= count);
+ return Span<C>(m_data + m_size - count, count);
+ }
friend constexpr bool operator==(const Span& a, const Span& b) noexcept { return a.size() == b.size() && std::equal(a.begin(), a.end(), b.begin()); }
friend constexpr bool operator!=(const Span& a, const Span& b) noexcept { return !(a == b); }
@@ -65,26 +131,20 @@ public:
template <typename O> friend class Span;
};
-/** Create a span to a container exposing data() and size().
- *
- * This correctly deals with constness: the returned Span's element type will be
- * whatever data() returns a pointer to. If either the passed container is const,
- * or its element type is const, the resulting span will have a const element type.
- *
- * std::span will have a constructor that implements this functionality directly.
- */
-template<typename A, int N>
-constexpr Span<A> MakeSpan(A (&a)[N]) { return Span<A>(a, N); }
-
-template<typename V>
-constexpr Span<typename std::remove_pointer<decltype(std::declval<V>().data())>::type> MakeSpan(V& v) { return Span<typename std::remove_pointer<decltype(std::declval<V>().data())>::type>(v.data(), v.size()); }
+// MakeSpan helps constructing a Span of the right type automatically.
+/** MakeSpan for arrays: */
+template <typename A, int N> Span<A> constexpr MakeSpan(A (&a)[N]) { return Span<A>(a, N); }
+/** MakeSpan for temporaries / rvalue references, only supporting const output. */
+template <typename V> constexpr auto MakeSpan(V&& v) -> typename std::enable_if<!std::is_lvalue_reference<V>::value, Span<const typename std::remove_pointer<decltype(v.data())>::type>>::type { return std::forward<V>(v); }
+/** MakeSpan for (lvalue) references, supporting mutable output. */
+template <typename V> constexpr auto MakeSpan(V& v) -> Span<typename std::remove_pointer<decltype(v.data())>::type> { return v; }
/** Pop the last element off a span, and return a reference to that element. */
template <typename T>
T& SpanPopBack(Span<T>& span)
{
size_t size = span.size();
- assert(size > 0);
+ ASSERT_IF_DEBUG(size > 0);
T& back = span[size - 1];
span = Span<T>(span.data(), size - 1);
return back;
diff --git a/src/test/fuzz/process_message.cpp b/src/test/fuzz/process_message.cpp
index 211a84b5f2..2fa751b987 100644
--- a/src/test/fuzz/process_message.cpp
+++ b/src/test/fuzz/process_message.cpp
@@ -30,7 +30,17 @@
#include <string>
#include <vector>
-bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams, ChainstateManager& chainman, CTxMemPool& mempool, CConnman* connman, BanMan* banman, const std::atomic<bool>& interruptMsgProc);
+void ProcessMessage(
+ CNode& pfrom,
+ const std::string& msg_type,
+ CDataStream& vRecv,
+ int64_t nTimeReceived,
+ const CChainParams& chainparams,
+ ChainstateManager& chainman,
+ CTxMemPool& mempool,
+ CConnman* connman,
+ BanMan* banman,
+ const std::atomic<bool>& interruptMsgProc);
namespace {
@@ -77,7 +87,10 @@ void test_one_input(const std::vector<uint8_t>& buffer)
connman.AddTestNode(p2p_node);
g_setup->m_node.peer_logic->InitializeNode(&p2p_node);
try {
- (void)ProcessMessage(p2p_node, random_message_type, random_bytes_data_stream, GetTimeMillis(), Params(), *g_setup->m_node.chainman, *g_setup->m_node.mempool, g_setup->m_node.connman.get(), g_setup->m_node.banman.get(), std::atomic<bool>{false});
+ ProcessMessage(p2p_node, random_message_type, random_bytes_data_stream, GetTimeMillis(),
+ Params(), *g_setup->m_node.chainman, *g_setup->m_node.mempool,
+ g_setup->m_node.connman.get(), g_setup->m_node.banman.get(),
+ std::atomic<bool>{false});
} catch (const std::ios_base::failure&) {
}
SyncWithValidationInterfaceQueue();
diff --git a/src/test/fuzz/process_messages.cpp b/src/test/fuzz/process_messages.cpp
index ad6c115a49..91ebf9fb1b 100644
--- a/src/test/fuzz/process_messages.cpp
+++ b/src/test/fuzz/process_messages.cpp
@@ -62,7 +62,7 @@ void test_one_input(const std::vector<uint8_t>& buffer)
const std::string random_message_type{fuzzed_data_provider.ConsumeBytesAsString(CMessageHeader::COMMAND_SIZE).c_str()};
CSerializedNetMsg net_msg;
- net_msg.command = random_message_type;
+ net_msg.m_type = random_message_type;
net_msg.data = ConsumeRandomLengthByteVector(fuzzed_data_provider);
CNode& random_node = *peers.at(fuzzed_data_provider.ConsumeIntegralInRange<int>(0, peers.size() - 1));
diff --git a/src/test/fuzz/span.cpp b/src/test/fuzz/span.cpp
index 4aea530ef2..f6b6e8f6f0 100644
--- a/src/test/fuzz/span.cpp
+++ b/src/test/fuzz/span.cpp
@@ -18,7 +18,7 @@ void test_one_input(const std::vector<uint8_t>& buffer)
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
std::string str = fuzzed_data_provider.ConsumeBytesAsString(32);
- const Span<const char> span = MakeSpan(str);
+ const Span<const char> span{str};
(void)span.data();
(void)span.begin();
(void)span.end();
@@ -32,7 +32,7 @@ void test_one_input(const std::vector<uint8_t>& buffer)
}
std::string another_str = fuzzed_data_provider.ConsumeBytesAsString(32);
- const Span<const char> another_span = MakeSpan(another_str);
+ const Span<const char> another_span{another_str};
assert((span <= another_span) != (span > another_span));
assert((span == another_span) != (span != another_span));
assert((span >= another_span) != (span < another_span));
diff --git a/src/test/fuzz/spanparsing.cpp b/src/test/fuzz/spanparsing.cpp
index 8e5e7dad11..e5bf5dd608 100644
--- a/src/test/fuzz/spanparsing.cpp
+++ b/src/test/fuzz/spanparsing.cpp
@@ -12,7 +12,7 @@ void test_one_input(const std::vector<uint8_t>& buffer)
const size_t query_size = fuzzed_data_provider.ConsumeIntegral<size_t>();
const std::string query = fuzzed_data_provider.ConsumeBytesAsString(std::min<size_t>(query_size, 1024 * 1024));
const std::string span_str = fuzzed_data_provider.ConsumeRemainingBytesAsString();
- const Span<const char> const_span = MakeSpan(span_str);
+ const Span<const char> const_span{span_str};
Span<const char> mut_span = const_span;
(void)spanparsing::Const(query, mut_span);
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index cf26ca3adb..257328974b 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -1829,7 +1829,7 @@ BOOST_AUTO_TEST_CASE(test_spanparsing)
// Const(...): parse a constant, update span to skip it if successful
input = "MilkToastHoney";
- sp = MakeSpan(input);
+ sp = input;
success = Const("", sp); // empty
BOOST_CHECK(success);
BOOST_CHECK_EQUAL(SpanToStr(sp), "MilkToastHoney");
@@ -1854,7 +1854,7 @@ BOOST_AUTO_TEST_CASE(test_spanparsing)
// Func(...): parse a function call, update span to argument if successful
input = "Foo(Bar(xy,z()))";
- sp = MakeSpan(input);
+ sp = input;
success = Func("FooBar", sp);
BOOST_CHECK(!success);
@@ -1877,31 +1877,31 @@ BOOST_AUTO_TEST_CASE(test_spanparsing)
Span<const char> result;
input = "(n*(n-1))/2";
- sp = MakeSpan(input);
+ sp = input;
result = Expr(sp);
BOOST_CHECK_EQUAL(SpanToStr(result), "(n*(n-1))/2");
BOOST_CHECK_EQUAL(SpanToStr(sp), "");
input = "foo,bar";
- sp = MakeSpan(input);
+ sp = input;
result = Expr(sp);
BOOST_CHECK_EQUAL(SpanToStr(result), "foo");
BOOST_CHECK_EQUAL(SpanToStr(sp), ",bar");
input = "(aaaaa,bbbbb()),c";
- sp = MakeSpan(input);
+ sp = input;
result = Expr(sp);
BOOST_CHECK_EQUAL(SpanToStr(result), "(aaaaa,bbbbb())");
BOOST_CHECK_EQUAL(SpanToStr(sp), ",c");
input = "xyz)foo";
- sp = MakeSpan(input);
+ sp = input;
result = Expr(sp);
BOOST_CHECK_EQUAL(SpanToStr(result), "xyz");
BOOST_CHECK_EQUAL(SpanToStr(sp), ")foo");
input = "((a),(b),(c)),xxx";
- sp = MakeSpan(input);
+ sp = input;
result = Expr(sp);
BOOST_CHECK_EQUAL(SpanToStr(result), "((a),(b),(c))");
BOOST_CHECK_EQUAL(SpanToStr(sp), ",xxx");
@@ -1910,7 +1910,7 @@ BOOST_AUTO_TEST_CASE(test_spanparsing)
std::vector<Span<const char>> results;
input = "xxx";
- results = Split(MakeSpan(input), 'x');
+ results = Split(input, 'x');
BOOST_CHECK_EQUAL(results.size(), 4U);
BOOST_CHECK_EQUAL(SpanToStr(results[0]), "");
BOOST_CHECK_EQUAL(SpanToStr(results[1]), "");
@@ -1918,19 +1918,19 @@ BOOST_AUTO_TEST_CASE(test_spanparsing)
BOOST_CHECK_EQUAL(SpanToStr(results[3]), "");
input = "one#two#three";
- results = Split(MakeSpan(input), '-');
+ results = Split(input, '-');
BOOST_CHECK_EQUAL(results.size(), 1U);
BOOST_CHECK_EQUAL(SpanToStr(results[0]), "one#two#three");
input = "one#two#three";
- results = Split(MakeSpan(input), '#');
+ results = Split(input, '#');
BOOST_CHECK_EQUAL(results.size(), 3U);
BOOST_CHECK_EQUAL(SpanToStr(results[0]), "one");
BOOST_CHECK_EQUAL(SpanToStr(results[1]), "two");
BOOST_CHECK_EQUAL(SpanToStr(results[2]), "three");
input = "*foo*bar*";
- results = Split(MakeSpan(input), '*');
+ results = Split(input, '*');
BOOST_CHECK_EQUAL(results.size(), 4U);
BOOST_CHECK_EQUAL(SpanToStr(results[0]), "");
BOOST_CHECK_EQUAL(SpanToStr(results[1]), "foo");
diff --git a/src/wallet/bdb.cpp b/src/wallet/bdb.cpp
index 7ed9c88122..125bf004e4 100644
--- a/src/wallet/bdb.cpp
+++ b/src/wallet/bdb.cpp
@@ -803,3 +803,67 @@ std::string BerkeleyDatabaseVersion()
{
return DbEnv::version(nullptr, nullptr, nullptr);
}
+
+bool BerkeleyBatch::ReadKey(CDataStream& key, CDataStream& value)
+{
+ if (!pdb)
+ return false;
+
+ // Key
+ SafeDbt datKey(key.data(), key.size());
+
+ // Read
+ SafeDbt datValue;
+ int ret = pdb->get(activeTxn, datKey, datValue, 0);
+ if (ret == 0 && datValue.get_data() != nullptr) {
+ value.write((char*)datValue.get_data(), datValue.get_size());
+ return true;
+ }
+ return false;
+}
+
+bool BerkeleyBatch::WriteKey(CDataStream& key, CDataStream& value, bool overwrite)
+{
+ if (!pdb)
+ return true;
+ if (fReadOnly)
+ assert(!"Write called on database in read-only mode");
+
+ // Key
+ SafeDbt datKey(key.data(), key.size());
+
+ // Value
+ SafeDbt datValue(value.data(), value.size());
+
+ // Write
+ int ret = pdb->put(activeTxn, datKey, datValue, (overwrite ? 0 : DB_NOOVERWRITE));
+ return (ret == 0);
+}
+
+bool BerkeleyBatch::EraseKey(CDataStream& key)
+{
+ if (!pdb)
+ return false;
+ if (fReadOnly)
+ assert(!"Erase called on database in read-only mode");
+
+ // Key
+ SafeDbt datKey(key.data(), key.size());
+
+ // Erase
+ int ret = pdb->del(activeTxn, datKey, 0);
+ return (ret == 0 || ret == DB_NOTFOUND);
+}
+
+bool BerkeleyBatch::HasKey(CDataStream& key)
+{
+ if (!pdb)
+ return false;
+
+ // Key
+ SafeDbt datKey(key.data(), key.size());
+
+ // Exists
+ int ret = pdb->exists(activeTxn, datKey, 0);
+ return ret == 0;
+}
diff --git a/src/wallet/bdb.h b/src/wallet/bdb.h
index 5ed364344b..c121bb4228 100644
--- a/src/wallet/bdb.h
+++ b/src/wallet/bdb.h
@@ -120,25 +120,6 @@ public:
}
}
- /** Return object for accessing database at specified path. */
- static std::unique_ptr<BerkeleyDatabase> Create(const fs::path& path)
- {
- std::string filename;
- return MakeUnique<BerkeleyDatabase>(GetWalletEnv(path, filename), std::move(filename));
- }
-
- /** Return object for accessing dummy database with no read/write capabilities. */
- static std::unique_ptr<BerkeleyDatabase> CreateDummy()
- {
- return MakeUnique<BerkeleyDatabase>();
- }
-
- /** Return object for accessing temporary in-memory database. */
- static std::unique_ptr<BerkeleyDatabase> CreateMock()
- {
- return MakeUnique<BerkeleyDatabase>(std::make_shared<BerkeleyEnvironment>(), "");
- }
-
/** Rewrite the entire database on disk, with the exception of key pszSkip if non-zero
*/
bool Rewrite(const char* pszSkip=nullptr);
@@ -207,6 +188,12 @@ class BerkeleyBatch
operator Dbt*();
};
+private:
+ bool ReadKey(CDataStream& key, CDataStream& value);
+ bool WriteKey(CDataStream& key, CDataStream& value, bool overwrite=true);
+ bool EraseKey(CDataStream& key);
+ bool HasKey(CDataStream& key);
+
protected:
Db* pdb;
std::string strFile;
@@ -236,91 +223,65 @@ public:
template <typename K, typename T>
bool Read(const K& key, T& value)
{
- if (!pdb)
- return false;
-
// Key
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
ssKey.reserve(1000);
ssKey << key;
- SafeDbt datKey(ssKey.data(), ssKey.size());
- // Read
- SafeDbt datValue;
- int ret = pdb->get(activeTxn, datKey, datValue, 0);
+ CDataStream ssValue(SER_DISK, CLIENT_VERSION);
bool success = false;
- if (datValue.get_data() != nullptr) {
+ bool ret = ReadKey(ssKey, ssValue);
+ if (ret) {
// Unserialize value
try {
- CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK, CLIENT_VERSION);
ssValue >> value;
success = true;
} catch (const std::exception&) {
// In this case success remains 'false'
}
}
- return ret == 0 && success;
+ return ret && success;
}
template <typename K, typename T>
bool Write(const K& key, const T& value, bool fOverwrite = true)
{
- if (!pdb)
- return true;
- if (fReadOnly)
- assert(!"Write called on database in read-only mode");
-
// Key
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
ssKey.reserve(1000);
ssKey << key;
- SafeDbt datKey(ssKey.data(), ssKey.size());
// Value
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
ssValue.reserve(10000);
ssValue << value;
- SafeDbt datValue(ssValue.data(), ssValue.size());
// Write
- int ret = pdb->put(activeTxn, datKey, datValue, (fOverwrite ? 0 : DB_NOOVERWRITE));
- return (ret == 0);
+ return WriteKey(ssKey, ssValue, fOverwrite);
}
template <typename K>
bool Erase(const K& key)
{
- if (!pdb)
- return false;
- if (fReadOnly)
- assert(!"Erase called on database in read-only mode");
-
// Key
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
ssKey.reserve(1000);
ssKey << key;
- SafeDbt datKey(ssKey.data(), ssKey.size());
// Erase
- int ret = pdb->del(activeTxn, datKey, 0);
- return (ret == 0 || ret == DB_NOTFOUND);
+ return EraseKey(ssKey);
}
template <typename K>
bool Exists(const K& key)
{
- if (!pdb)
- return false;
-
// Key
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
ssKey.reserve(1000);
ssKey << key;
- SafeDbt datKey(ssKey.data(), ssKey.size());
// Exists
- int ret = pdb->exists(activeTxn, datKey, 0);
- return (ret == 0);
+ return HasKey(ssKey);
}
Dbc* GetCursor();
diff --git a/src/wallet/salvage.cpp b/src/wallet/salvage.cpp
index 70067ebef0..d42950ee42 100644
--- a/src/wallet/salvage.cpp
+++ b/src/wallet/salvage.cpp
@@ -116,7 +116,7 @@ bool RecoverDatabaseFile(const fs::path& file_path)
}
DbTxn* ptxn = env->TxnBegin();
- CWallet dummyWallet(nullptr, WalletLocation(), WalletDatabase::CreateDummy());
+ CWallet dummyWallet(nullptr, WalletLocation(), CreateDummyWalletDatabase());
for (KeyValPair& row : salvagedData)
{
/* Filter for only private key type KV pairs to be added to the salvaged wallet */
diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp
index 657d0828f2..1deedede4c 100644
--- a/src/wallet/test/coinselector_tests.cpp
+++ b/src/wallet/test/coinselector_tests.cpp
@@ -29,7 +29,7 @@ typedef std::set<CInputCoin> CoinSet;
static std::vector<COutput> vCoins;
static NodeContext testNode;
static auto testChain = interfaces::MakeChain(testNode);
-static CWallet testWallet(testChain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+static CWallet testWallet(testChain.get(), WalletLocation(), CreateDummyWalletDatabase());
static CAmount balance = 0;
CoinEligibilityFilter filter_standard(1, 6, 0);
@@ -283,7 +283,7 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
// Make sure that can use BnB when there are preset inputs
empty_wallet();
{
- std::unique_ptr<CWallet> wallet = MakeUnique<CWallet>(m_chain.get(), WalletLocation(), WalletDatabase::CreateMock());
+ std::unique_ptr<CWallet> wallet = MakeUnique<CWallet>(m_chain.get(), WalletLocation(), CreateMockWalletDatabase());
bool firstRun;
wallet->LoadWallet(firstRun);
wallet->SetupLegacyScriptPubKeyMan();
diff --git a/src/wallet/test/ismine_tests.cpp b/src/wallet/test/ismine_tests.cpp
index 4c0e4dc653..cdb0522920 100644
--- a/src/wallet/test/ismine_tests.cpp
+++ b/src/wallet/test/ismine_tests.cpp
@@ -35,7 +35,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2PK compressed
{
- CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
scriptPubKey = GetScriptForRawPubKey(pubkeys[0]);
@@ -52,7 +52,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2PK uncompressed
{
- CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
scriptPubKey = GetScriptForRawPubKey(uncompressedPubkey);
@@ -69,7 +69,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2PKH compressed
{
- CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
scriptPubKey = GetScriptForDestination(PKHash(pubkeys[0]));
@@ -86,7 +86,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2PKH uncompressed
{
- CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
scriptPubKey = GetScriptForDestination(PKHash(uncompressedPubkey));
@@ -103,7 +103,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2SH
{
- CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
@@ -127,7 +127,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// (P2PKH inside) P2SH inside P2SH (invalid)
{
- CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
@@ -145,7 +145,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// (P2PKH inside) P2SH inside P2WSH (invalid)
{
- CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
@@ -163,7 +163,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2WPKH inside P2WSH (invalid)
{
- CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
@@ -179,7 +179,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// (P2PKH inside) P2WSH inside P2WSH (invalid)
{
- CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
@@ -197,7 +197,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2WPKH compressed
{
- CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
@@ -212,7 +212,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2WPKH uncompressed
{
- CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
@@ -231,7 +231,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// scriptPubKey multisig
{
- CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
@@ -262,7 +262,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2SH multisig
{
- CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
@@ -283,7 +283,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2WSH multisig with compressed keys
{
- CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
@@ -309,7 +309,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2WSH multisig with uncompressed key
{
- CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
@@ -335,7 +335,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2WSH multisig wrapped in P2SH
{
- CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
@@ -362,7 +362,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// OP_RETURN
{
- CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
@@ -376,7 +376,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// witness unspendable
{
- CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
@@ -390,7 +390,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// witness unknown
{
- CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
@@ -404,7 +404,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// Nonstandard
{
- CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
diff --git a/src/wallet/test/scriptpubkeyman_tests.cpp b/src/wallet/test/scriptpubkeyman_tests.cpp
index 757865ea37..4f12079768 100644
--- a/src/wallet/test/scriptpubkeyman_tests.cpp
+++ b/src/wallet/test/scriptpubkeyman_tests.cpp
@@ -19,7 +19,7 @@ BOOST_AUTO_TEST_CASE(CanProvide)
// Set up wallet and keyman variables.
NodeContext node;
std::unique_ptr<interfaces::Chain> chain = interfaces::MakeChain(node);
- CWallet wallet(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ CWallet wallet(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
LegacyScriptPubKeyMan& keyman = *wallet.GetOrCreateLegacyScriptPubKeyMan();
// Make a 1 of 2 multisig script
diff --git a/src/wallet/test/wallet_test_fixture.cpp b/src/wallet/test/wallet_test_fixture.cpp
index 7ba3148ff3..44f9eb5ddd 100644
--- a/src/wallet/test/wallet_test_fixture.cpp
+++ b/src/wallet/test/wallet_test_fixture.cpp
@@ -6,7 +6,7 @@
WalletTestingSetup::WalletTestingSetup(const std::string& chainName)
: TestingSetup(chainName),
- m_wallet(m_chain.get(), WalletLocation(), WalletDatabase::CreateMock())
+ m_wallet(m_chain.get(), WalletLocation(), CreateMockWalletDatabase())
{
bool fFirstRun;
m_wallet.LoadWallet(fFirstRun);
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index 6f8c973f25..497ccd14bb 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -80,7 +80,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
// Verify ScanForWalletTransactions fails to read an unknown start block.
{
- CWallet wallet(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ CWallet wallet(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
{
LOCK(wallet.cs_wallet);
wallet.SetLastBlockProcessed(::ChainActive().Height(), ::ChainActive().Tip()->GetBlockHash());
@@ -99,7 +99,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
// Verify ScanForWalletTransactions picks up transactions in both the old
// and new block files.
{
- CWallet wallet(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ CWallet wallet(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
{
LOCK(wallet.cs_wallet);
wallet.SetLastBlockProcessed(::ChainActive().Height(), ::ChainActive().Tip()->GetBlockHash());
@@ -125,7 +125,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
// Verify ScanForWalletTransactions only picks transactions in the new block
// file.
{
- CWallet wallet(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ CWallet wallet(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
{
LOCK(wallet.cs_wallet);
wallet.SetLastBlockProcessed(::ChainActive().Height(), ::ChainActive().Tip()->GetBlockHash());
@@ -150,7 +150,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
// Verify ScanForWalletTransactions scans no blocks.
{
- CWallet wallet(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ CWallet wallet(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
{
LOCK(wallet.cs_wallet);
wallet.SetLastBlockProcessed(::ChainActive().Height(), ::ChainActive().Tip()->GetBlockHash());
@@ -189,7 +189,7 @@ BOOST_FIXTURE_TEST_CASE(importmulti_rescan, TestChain100Setup)
// before the missing block, and success for a key whose creation time is
// after.
{
- std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
wallet->SetupLegacyScriptPubKeyMan();
WITH_LOCK(wallet->cs_wallet, wallet->SetLastBlockProcessed(newTip->nHeight, newTip->GetBlockHash()));
AddWallet(wallet);
@@ -254,7 +254,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
// Import key into wallet and call dumpwallet to create backup file.
{
- std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
{
auto spk_man = wallet->GetOrCreateLegacyScriptPubKeyMan();
LOCK2(wallet->cs_wallet, spk_man->cs_KeyStore);
@@ -276,7 +276,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
// Call importwallet RPC and verify all blocks with timestamps >= BLOCK_TIME
// were scanned, and no prior blocks were scanned.
{
- std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
LOCK(wallet->cs_wallet);
wallet->SetupLegacyScriptPubKeyMan();
@@ -312,7 +312,7 @@ BOOST_FIXTURE_TEST_CASE(coin_mark_dirty_immature_credit, TestChain100Setup)
NodeContext node;
auto chain = interfaces::MakeChain(node);
- CWallet wallet(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ CWallet wallet(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
auto spk_man = wallet.GetOrCreateLegacyScriptPubKeyMan();
CWalletTx wtx(&wallet, m_coinbase_txns.back());
@@ -486,7 +486,7 @@ public:
ListCoinsTestingSetup()
{
CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
- wallet = MakeUnique<CWallet>(m_chain.get(), WalletLocation(), WalletDatabase::CreateMock());
+ wallet = MakeUnique<CWallet>(m_chain.get(), WalletLocation(), CreateMockWalletDatabase());
{
LOCK2(wallet->cs_wallet, ::cs_main);
wallet->SetLastBlockProcessed(::ChainActive().Height(), ::ChainActive().Tip()->GetBlockHash());
@@ -604,7 +604,7 @@ BOOST_FIXTURE_TEST_CASE(wallet_disableprivkeys, TestChain100Setup)
{
NodeContext node;
auto chain = interfaces::MakeChain(node);
- std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
wallet->SetupLegacyScriptPubKeyMan();
wallet->SetMinVersion(FEATURE_LATEST);
wallet->SetWalletFlag(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index cf42c1cb3c..4037e23b69 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -3705,7 +3705,7 @@ bool CWallet::Verify(interfaces::Chain& chain, const WalletLocation& location, b
}
// Keep same database environment instance across Verify/Recover calls below.
- std::unique_ptr<WalletDatabase> database = WalletDatabase::Create(wallet_path);
+ std::unique_ptr<WalletDatabase> database = CreateWalletDatabase(wallet_path);
try {
if (!WalletBatch::VerifyEnvironment(wallet_path, error_string)) {
@@ -3729,7 +3729,7 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
if (gArgs.GetBoolArg("-zapwallettxes", false)) {
chain.initMessage(_("Zapping all transactions from wallet...").translated);
- std::unique_ptr<CWallet> tempWallet = MakeUnique<CWallet>(&chain, location, WalletDatabase::Create(location.GetPath()));
+ std::unique_ptr<CWallet> tempWallet = MakeUnique<CWallet>(&chain, location, CreateWalletDatabase(location.GetPath()));
DBErrors nZapWalletRet = tempWallet->ZapWalletTx(vWtx);
if (nZapWalletRet != DBErrors::LOAD_OK) {
error = strprintf(_("Error loading %s: Wallet corrupted"), walletFile);
@@ -3743,7 +3743,7 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
bool fFirstRun = true;
// TODO: Can't use std::make_shared because we need a custom deleter but
// should be possible to use std::allocate_shared.
- std::shared_ptr<CWallet> walletInstance(new CWallet(&chain, location, WalletDatabase::Create(location.GetPath())), ReleaseWallet);
+ std::shared_ptr<CWallet> walletInstance(new CWallet(&chain, location, CreateWalletDatabase(location.GetPath())), ReleaseWallet);
DBErrors nLoadWalletRet = walletInstance->LoadWallet(fFirstRun);
if (nLoadWalletRet != DBErrors::LOAD_OK) {
if (nLoadWalletRet == DBErrors::CORRUPT) {
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index 2f6c2b883a..6f38398076 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -1023,3 +1023,22 @@ bool IsWalletLoaded(const fs::path& wallet_path)
{
return IsBDBWalletLoaded(wallet_path);
}
+
+/** Return object for accessing database at specified path. */
+std::unique_ptr<BerkeleyDatabase> CreateWalletDatabase(const fs::path& path)
+{
+ std::string filename;
+ return MakeUnique<BerkeleyDatabase>(GetWalletEnv(path, filename), std::move(filename));
+}
+
+/** Return object for accessing dummy database with no read/write capabilities. */
+std::unique_ptr<BerkeleyDatabase> CreateDummyWalletDatabase()
+{
+ return MakeUnique<BerkeleyDatabase>();
+}
+
+/** Return object for accessing temporary in-memory database. */
+std::unique_ptr<BerkeleyDatabase> CreateMockWalletDatabase()
+{
+ return MakeUnique<BerkeleyDatabase>(std::make_shared<BerkeleyEnvironment>(), "");
+}
diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h
index 1037bd579f..61e0f19e56 100644
--- a/src/wallet/walletdb.h
+++ b/src/wallet/walletdb.h
@@ -293,4 +293,13 @@ bool ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, st
/** Return whether a wallet database is currently loaded. */
bool IsWalletLoaded(const fs::path& wallet_path);
+/** Return object for accessing database at specified path. */
+std::unique_ptr<BerkeleyDatabase> CreateWalletDatabase(const fs::path& path);
+
+/** Return object for accessing dummy database with no read/write capabilities. */
+std::unique_ptr<BerkeleyDatabase> CreateDummyWalletDatabase();
+
+/** Return object for accessing temporary in-memory database. */
+std::unique_ptr<BerkeleyDatabase> CreateMockWalletDatabase();
+
#endif // BITCOIN_WALLET_WALLETDB_H
diff --git a/src/wallet/wallettool.cpp b/src/wallet/wallettool.cpp
index be07c28503..77ed6beb5d 100644
--- a/src/wallet/wallettool.cpp
+++ b/src/wallet/wallettool.cpp
@@ -28,7 +28,7 @@ static std::shared_ptr<CWallet> CreateWallet(const std::string& name, const fs::
return nullptr;
}
// dummy chain interface
- std::shared_ptr<CWallet> wallet_instance(new CWallet(nullptr /* chain */, WalletLocation(name), WalletDatabase::Create(path)), WalletToolReleaseWallet);
+ std::shared_ptr<CWallet> wallet_instance(new CWallet(nullptr /* chain */, WalletLocation(name), CreateWalletDatabase(path)), WalletToolReleaseWallet);
LOCK(wallet_instance->cs_wallet);
bool first_run = true;
DBErrors load_wallet_ret = wallet_instance->LoadWallet(first_run);
@@ -57,7 +57,7 @@ static std::shared_ptr<CWallet> LoadWallet(const std::string& name, const fs::pa
}
// dummy chain interface
- std::shared_ptr<CWallet> wallet_instance(new CWallet(nullptr /* chain */, WalletLocation(name), WalletDatabase::Create(path)), WalletToolReleaseWallet);
+ std::shared_ptr<CWallet> wallet_instance(new CWallet(nullptr /* chain */, WalletLocation(name), CreateWalletDatabase(path)), WalletToolReleaseWallet);
DBErrors load_wallet_ret;
try {
bool first_run;
@@ -107,7 +107,7 @@ static void WalletShowInfo(CWallet* wallet_instance)
static bool SalvageWallet(const fs::path& path)
{
// Create a Database handle to allow for the db to be initialized before recovery
- std::unique_ptr<WalletDatabase> database = WalletDatabase::Create(path);
+ std::unique_ptr<WalletDatabase> database = CreateWalletDatabase(path);
// Initialize the environment before recovery
bilingual_str error_string;
diff --git a/test/functional/feature_notifications.py b/test/functional/feature_notifications.py
index 33a308ad1b..dd4c318cee 100755
--- a/test/functional/feature_notifications.py
+++ b/test/functional/feature_notifications.py
@@ -93,6 +93,7 @@ class NotificationsTest(BitcoinTestFramework):
self.nodes[0].sethdseed(seed=self.nodes[1].dumpprivkey(keyhash_to_p2pkh(hex_str_to_bytes(self.nodes[1].getwalletinfo()['hdseedid'])[::-1])))
self.nodes[0].rescanblockchain()
self.nodes[0].generatetoaddress(100, ADDRESS_BCRT1_UNSPENDABLE)
+ self.sync_blocks()
# Generate transaction on node 0, sync mempools, and check for
# notification on node 1.
diff --git a/test/functional/p2p_invalid_messages.py b/test/functional/p2p_invalid_messages.py
index 402f72685c..d99bc621de 100755
--- a/test/functional/p2p_invalid_messages.py
+++ b/test/functional/p2p_invalid_messages.py
@@ -3,12 +3,14 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test node responses to invalid network messages."""
+
from test_framework.messages import (
CBlockHeader,
CInv,
msg_getdata,
msg_headers,
msg_inv,
+ msg_ping,
MSG_TX,
ser_string,
)
@@ -17,6 +19,10 @@ from test_framework.mininode import (
P2PInterface,
)
from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (
+ assert_equal,
+ wait_until,
+)
MSG_LIMIT = 4 * 1000 * 1000 # 4MB, per MAX_PROTOCOL_MESSAGE_LENGTH
VALID_DATA_LIMIT = MSG_LIMIT - 5 # Account for the 5-byte length prefix
@@ -42,6 +48,7 @@ class InvalidMessagesTest(BitcoinTestFramework):
self.setup_clean_chain = True
def run_test(self):
+ self.test_buffer()
self.test_magic_bytes()
self.test_checksum()
self.test_size()
@@ -49,6 +56,25 @@ class InvalidMessagesTest(BitcoinTestFramework):
self.test_large_inv()
self.test_resource_exhaustion()
+ def test_buffer(self):
+ self.log.info("Test message with header split across two buffers, should be received")
+ conn = self.nodes[0].add_p2p_connection(P2PDataStore())
+ # Create valid message
+ msg = conn.build_message(msg_ping(nonce=12345))
+ cut_pos = 12 # Chosen at an arbitrary position within the header
+ # Send message in two pieces
+ before = int(self.nodes[0].getnettotals()['totalbytesrecv'])
+ conn.send_raw_message(msg[:cut_pos])
+ # Wait until node has processed the first half of the message
+ wait_until(lambda: int(self.nodes[0].getnettotals()['totalbytesrecv']) != before)
+ middle = int(self.nodes[0].getnettotals()['totalbytesrecv'])
+ # If this assert fails, we've hit an unlikely race
+ # where the test framework sent a message in between the two halves
+ assert_equal(middle, before + cut_pos)
+ conn.send_raw_message(msg[cut_pos:])
+ conn.sync_with_ping(timeout=1)
+ self.nodes[0].disconnect_p2ps()
+
def test_magic_bytes(self):
conn = self.nodes[0].add_p2p_connection(P2PDataStore())
with self.nodes[0].assert_debug_log(['PROCESSMESSAGE: INVALID MESSAGESTART badmsg']):
@@ -95,13 +121,13 @@ class InvalidMessagesTest(BitcoinTestFramework):
def test_large_inv(self):
conn = self.nodes[0].add_p2p_connection(P2PInterface())
- with self.nodes[0].assert_debug_log(['Misbehaving', 'peer=4 (0 -> 20): message inv size() = 50001']):
+ with self.nodes[0].assert_debug_log(['Misbehaving', '(0 -> 20): message inv size() = 50001']):
msg = msg_inv([CInv(MSG_TX, 1)] * 50001)
conn.send_and_ping(msg)
- with self.nodes[0].assert_debug_log(['Misbehaving', 'peer=4 (20 -> 40): message getdata size() = 50001']):
+ with self.nodes[0].assert_debug_log(['Misbehaving', '(20 -> 40): message getdata size() = 50001']):
msg = msg_getdata([CInv(MSG_TX, 1)] * 50001)
conn.send_and_ping(msg)
- with self.nodes[0].assert_debug_log(['Misbehaving', 'peer=4 (40 -> 60): headers message size = 2001']):
+ with self.nodes[0].assert_debug_log(['Misbehaving', '(40 -> 60): headers message size = 2001']):
msg = msg_headers([CBlockHeader()] * 2001)
conn.send_and_ping(msg)
self.nodes[0].disconnect_p2ps()