diff --git a/.cirrus.yml b/.cirrus.yml
index 48bb168e9bc7..bdca5ce9f63e 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -18,11 +18,8 @@ persistent_worker_template: &PERSISTENT_WORKER_TEMPLATE
base_template: &BASE_TEMPLATE
merge_base_script:
- # Unconditionally install git (used in fingerprint_script) and set the
- # default git author name (used in verify-commits.py)
+ # Unconditionally install git (used in fingerprint_script).
- bash -c "$PACKAGE_MANAGER_INSTALL git"
- - git config --global user.email "ci@ci.ci"
- - git config --global user.name "ci"
- if [ "$CIRRUS_PR" = "" ]; then exit 0; fi
- git fetch $CIRRUS_REPO_CLONE_URL "pull/${CIRRUS_PR}/merge"
- git checkout FETCH_HEAD # Use merged changes to detect silent merge conflicts
@@ -97,7 +94,7 @@ task:
env:
PATH: 'C:\jom;C:\Python39;C:\Python39\Scripts;C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\MSBuild\Current\Bin;%PATH%'
PYTHONUTF8: 1
- CI_VCPKG_TAG: '2022.06.16.1'
+ CI_VCPKG_TAG: '2022.09.27'
VCPKG_DOWNLOADS: 'C:\Users\ContainerAdministrator\AppData\Local\vcpkg\downloads'
VCPKG_DEFAULT_BINARY_CACHE: 'C:\Users\ContainerAdministrator\AppData\Local\vcpkg\archives'
CCACHE_DIR: 'C:\Users\ContainerAdministrator\AppData\Local\ccache'
@@ -105,14 +102,7 @@ task:
x64_NATIVE_TOOLS: '"C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvars64.bat"'
IgnoreWarnIntDirInTempDetected: 'true'
merge_script:
- - git config --global user.email "ci@ci.ci"
- - git config --global user.name "ci"
- # Windows filesystem loses the executable bit, and all of the executable
- # files are considered "modified" now. It will break the following `git merge`
- # command. The next two commands make git ignore this issue.
- - git config core.filemode false
- - git reset --hard
- - PowerShell -NoLogo -Command if ($env:CIRRUS_PR -ne $null) { git fetch $env:CIRRUS_REPO_CLONE_URL $env:CIRRUS_BASE_BRANCH; git merge FETCH_HEAD; }
+ - PowerShell -NoLogo -Command if ($env:CIRRUS_PR -ne $null) { git fetch $env:CIRRUS_REPO_CLONE_URL pull/$env:CIRRUS_PR/merge; git reset --hard FETCH_HEAD; }
vcpkg_tools_cache:
folder: '%VCPKG_DOWNLOADS%\tools'
reupload_on_changes: false
@@ -152,9 +142,9 @@ task:
- python build_msvc\msvc-autogen.py
- msbuild build_msvc\bitcoin.sln -property:CLToolExe=%WRAPPED_CL% -property:Configuration=Release -maxCpuCount -verbosity:minimal -noLogo
- ccache --show-stats
- unit_tests_script:
+ check_script:
- src\test_navcoin.exe -l test_suite
- - src\bench_navcoin.exe > NUL
+ - src\bench_navcoin.exe --sanity-check > NUL
- python test\util\test_runner.py
- python test\util\rpcauth-test.py
functional_tests_script:
diff --git a/build_msvc/common.init.vcxproj.in b/build_msvc/common.init.vcxproj.in
index f36e503cd6c3..0de75f7e6fe2 100644
--- a/build_msvc/common.init.vcxproj.in
+++ b/build_msvc/common.init.vcxproj.in
@@ -88,7 +88,7 @@
Level3
NotUsing
/utf-8 /Zc:__cplusplus /std:c++20 %(AdditionalOptions)
- 4018;4244;4267;4334;4715;4805;4834
+ 4018;4244;4267;4715;4805
true
_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;ZMQ_STATIC;NOMINMAX;WIN32;HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_CONSOLE;_WIN32_WINNT=0x0601;_WIN32_IE=0x0501;WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions)
..\..\src;..\..\src\minisketch\include;..\..\src\univalue\include;..\..\src\secp256k1\include;..\..\src\leveldb\include;..\..\src\leveldb\helpers\memenv;..\..\src\bls\include;..\..\src\bls\mcl\include;%(AdditionalIncludeDirectories)
diff --git a/ci/lint/04_install.sh b/ci/lint/04_install.sh
index 2b57411c3feb..6f9a4709dde8 100755
--- a/ci/lint/04_install.sh
+++ b/ci/lint/04_install.sh
@@ -7,7 +7,7 @@
export LC_ALL=C
${CI_RETRY_EXE} apt-get update
-${CI_RETRY_EXE} apt-get install -y clang-format-9 python3-pip curl git gawk jq
+${CI_RETRY_EXE} apt-get install -y python3-pip curl git gawk jq
(
# Temporary workaround for https://github.com/bitcoin/bitcoin/pull/26130#issuecomment-1260499544
# Can be removed once the underlying image is bumped to something that includes git2.34 or later
@@ -15,8 +15,6 @@ ${CI_RETRY_EXE} apt-get install -y clang-format-9 python3-pip curl git gawk jq
${CI_RETRY_EXE} apt-get update
${CI_RETRY_EXE} apt-get install -y --reinstall git
)
-update-alternatives --install /usr/bin/clang-format clang-format "$(which clang-format-9 )" 100
-update-alternatives --install /usr/bin/clang-format-diff clang-format-diff "$(which clang-format-diff-9)" 100
${CI_RETRY_EXE} pip3 install codespell==2.2.1
${CI_RETRY_EXE} pip3 install flake8==4.0.1
diff --git a/ci/lint/06_script.sh b/ci/lint/06_script.sh
index 5b6e42d894ce..ec6531198ee6 100755
--- a/ci/lint/06_script.sh
+++ b/ci/lint/06_script.sh
@@ -31,6 +31,8 @@ if [ "$CIRRUS_REPO_FULL_NAME" = "navcoin/navcoin" ] && [ "$CIRRUS_PR" = "" ] ; t
git log HEAD~10 -1 --format='%H' > ./contrib/verify-commits/trusted-sha512-root-commit
git log HEAD~10 -1 --format='%H' > ./contrib/verify-commits/trusted-git-root
mapfile -t KEYS < contrib/verify-commits/trusted-keys
+ git config user.email "ci@ci.ci"
+ git config user.name "ci"
${CI_RETRY_EXE} gpg --keyserver hkps://keys.openpgp.org --recv-keys "${KEYS[@]}" &&
./contrib/verify-commits/verify-commits.py;
fi
diff --git a/ci/test/00_setup_env_i686_centos.sh b/ci/test/00_setup_env_i686_centos.sh
index dd01d2f9c888..65ebec31d733 100755
--- a/ci/test/00_setup_env_i686_centos.sh
+++ b/ci/test/00_setup_env_i686_centos.sh
@@ -9,7 +9,8 @@ export LC_ALL=C.UTF-8
export HOST=i686-pc-linux-gnu
export CONTAINER_NAME=ci_i686_centos
export DOCKER_NAME_TAG=quay.io/centos/centos:stream8
-export DOCKER_PACKAGES="gcc-c++ glibc-devel.x86_64 libstdc++-devel.x86_64 glibc-devel.i686 libstdc++-devel.i686 ccache libtool make git python3 python3-zmq which patch lbzip2 xz procps-ng dash rsync coreutils bison"
+export DOCKER_PACKAGES="gcc-c++ glibc-devel.x86_64 libstdc++-devel.x86_64 glibc-devel.i686 libstdc++-devel.i686 ccache libtool make git python3 python3-pip which patch lbzip2 xz procps-ng dash rsync coreutils bison"
+export PIP_PACKAGES="pyzmq"
export GOAL="install"
export BITCOIN_CONFIG="--enable-zmq --enable-reduce-exports"
export CONFIG_SHELL="/bin/dash"
diff --git a/ci/test/00_setup_env_i686_multiprocess.sh b/ci/test/00_setup_env_i686_multiprocess.sh
index c73cebe161fb..6a5d3a112e25 100755
--- a/ci/test/00_setup_env_i686_multiprocess.sh
+++ b/ci/test/00_setup_env_i686_multiprocess.sh
@@ -9,7 +9,7 @@ export LC_ALL=C.UTF-8
export HOST=i686-pc-linux-gnu
export CONTAINER_NAME=ci_i686_multiprocess
export DOCKER_NAME_TAG=ubuntu:20.04
-export PACKAGES="cmake python3 python3-pip llvm clang g++-multilib"
+export PACKAGES="cmake python3 llvm clang g++-multilib"
export DEP_OPTS="DEBUG=1 MULTIPROCESS=1"
export GOAL="install"
export BITCOIN_CONFIG="--enable-debug CC='clang -m32' CXX='clang++ -m32' LDFLAGS='--rtlib=compiler-rt -lgcc_s'"
diff --git a/ci/test/04_install.sh b/ci/test/04_install.sh
old mode 100755
new mode 100644
index 002644ce1627..b256ae21a5d0
--- a/ci/test/04_install.sh
+++ b/ci/test/04_install.sh
@@ -10,12 +10,6 @@ if [[ $QEMU_USER_CMD == qemu-s390* ]]; then
export LC_ALL=C
fi
-if [ "$CI_OS_NAME" == "macos" ]; then
- sudo -H pip3 install --upgrade pip
- # shellcheck disable=SC2086
- IN_GETOPT_BIN="$(brew --prefix gnu-getopt)/bin/getopt" ${CI_RETRY_EXE} pip3 install --user $PIP_PACKAGES
-fi
-
# Create folders that are mounted into the docker
mkdir -p "${CCACHE_DIR}"
mkdir -p "${PREVIOUS_RELEASES_DIR}"
@@ -78,9 +72,16 @@ elif [ "$CI_USE_APT_INSTALL" != "no" ]; then
fi
${CI_RETRY_EXE} CI_EXEC apt-get update
${CI_RETRY_EXE} CI_EXEC apt-get install --no-install-recommends --no-upgrade -y "$PACKAGES" "$DOCKER_PACKAGES"
- if [ -n "$PIP_PACKAGES" ]; then
+fi
+
+if [ -n "$PIP_PACKAGES" ]; then
+ if [ "$CI_OS_NAME" == "macos" ]; then
+ sudo -H pip3 install --upgrade pip
+ # shellcheck disable=SC2086
+ IN_GETOPT_BIN="/usr/local/opt/gnu-getopt/bin/getopt" ${CI_RETRY_EXE} pip3 install --user $PIP_PACKAGES
+ else
# shellcheck disable=SC2086
- ${CI_RETRY_EXE} pip3 install --user $PIP_PACKAGES
+ ${CI_RETRY_EXE} CI_EXEC pip3 install --user $PIP_PACKAGES
fi
fi
diff --git a/ci/test/06_script_b.sh b/ci/test/06_script_b.sh
index fccb2cb93e98..faffbd1c089c 100755
--- a/ci/test/06_script_b.sh
+++ b/ci/test/06_script_b.sh
@@ -68,6 +68,7 @@ if [ "${RUN_TIDY}" = "true" ]; then
" src/util/string.cpp"\
" src/util/syserror.cpp"\
" src/util/url.cpp"\
+ " src/zmq"\
" -p . ${MAKEJOBS} -- -Xiwyu --cxx17ns -Xiwyu --mapping_file=${BASE_BUILD_DIR}/navcoin-$HOST/contrib/devtools/iwyu/bitcoin.core.imp"
fi
diff --git a/configure.ac b/configure.ac
index 684dcf80d7ba..79eba8ebbf0e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -575,8 +575,8 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
CXXFLAGS="$TEMP_CXXFLAGS"
# ARM
-AX_CHECK_COMPILE_FLAG([-march=armv8-a+crc+crypto], [ARM_CRC_CXXFLAGS="-march=armv8-a+crc+crypto"], [], [$CXXFLAG_WERROR])
-AX_CHECK_COMPILE_FLAG([-march=armv8-a+crc+crypto], [ARM_SHANI_CXXFLAGS="-march=armv8-a+crc+crypto"], [], [$CXXFLAG_WERROR])
+AX_CHECK_COMPILE_FLAG([-march=armv8-a+crc], [ARM_CRC_CXXFLAGS="-march=armv8-a+crc"], [], [$CXXFLAG_WERROR])
+AX_CHECK_COMPILE_FLAG([-march=armv8-a+crypto], [ARM_SHANI_CXXFLAGS="-march=armv8-a+crypto"], [], [$CXXFLAG_WERROR])
TEMP_CXXFLAGS="$CXXFLAGS"
CXXFLAGS="$ARM_CRC_CXXFLAGS $CXXFLAGS"
diff --git a/contrib/signet/getcoins.py b/contrib/signet/getcoins.py
index 147d12600df6..a069f5fad3de 100755
--- a/contrib/signet/getcoins.py
+++ b/contrib/signet/getcoins.py
@@ -129,7 +129,7 @@ def bitcoin_cli(rpc_command_and_params):
# Convert SVG image to PPM, and load it
try:
- rv = subprocess.run([args.imagemagick, 'svg:-', '-depth', '8', 'ppm:-'], input=res.content, check=True, capture_output=True)
+ rv = subprocess.run([args.imagemagick, 'svg:-', '-depth', '8', 'ppm:-'], input=res.content, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
except FileNotFoundError:
raise SystemExit(f"The binary {args.imagemagick} could not be found. Please make sure ImageMagick (or a compatible fork) is installed and that the correct path is specified.")
diff --git a/contrib/signet/miner b/contrib/signet/miner
index fdcd20ae3b4e..61d9f62be718 100755
--- a/contrib/signet/miner
+++ b/contrib/signet/miner
@@ -225,7 +225,7 @@ def seconds_to_hms(s):
out = "-" + out
return out
-def next_block_delta(last_nbits, last_hash, ultimate_target, do_poisson):
+def next_block_delta(last_nbits, last_hash, ultimate_target, do_poisson, max_interval):
# strategy:
# 1) work out how far off our desired target we are
# 2) cap it to a factor of 4 since that's the best we can do in a single retarget period
@@ -248,7 +248,7 @@ def next_block_delta(last_nbits, last_hash, ultimate_target, do_poisson):
this_interval_variance = 1
this_interval = avg_interval * this_interval_variance
- this_interval = max(1, min(this_interval, 3600))
+ this_interval = max(1, min(this_interval, max_interval))
return this_interval
@@ -308,6 +308,10 @@ def do_generate(args):
return 1
my_blocks = (start-1, stop, total)
+ if args.max_interval < 960:
+ logging.error("--max-interval must be at least 960 (16 minutes)")
+ return 1
+
ultimate_target = nbits_to_target(int(args.nbits,16))
mined_blocks = 0
@@ -324,7 +328,7 @@ def do_generate(args):
if lastheader is None:
lastheader = bestheader["hash"]
elif bestheader["hash"] != lastheader:
- next_delta = next_block_delta(int(bestheader["bits"], 16), bestheader["hash"], ultimate_target, args.poisson)
+ next_delta = next_block_delta(int(bestheader["bits"], 16), bestheader["hash"], ultimate_target, args.poisson, args.max_interval)
next_delta += bestheader["time"] - time.time()
next_is_mine = next_block_is_mine(bestheader["hash"], my_blocks)
logging.info("Received new block at height %d; next in %s (%s)", bestheader["height"], seconds_to_hms(next_delta), ("mine" if next_is_mine else "backup"))
@@ -338,14 +342,14 @@ def do_generate(args):
action_time = now
is_mine = True
elif bestheader["height"] == 0:
- time_delta = next_block_delta(int(bestheader["bits"], 16), bci["bestblockhash"], ultimate_target, args.poisson)
+ time_delta = next_block_delta(int(bestheader["bits"], 16), bci["bestblockhash"], ultimate_target, args.poisson, args.max_interval)
time_delta *= 100 # 100 blocks
logging.info("Backdating time for first block to %d minutes ago" % (time_delta/60))
mine_time = now - time_delta
action_time = now
is_mine = True
else:
- time_delta = next_block_delta(int(bestheader["bits"], 16), bci["bestblockhash"], ultimate_target, args.poisson)
+ time_delta = next_block_delta(int(bestheader["bits"], 16), bci["bestblockhash"], ultimate_target, args.poisson, args.max_interval)
mine_time = bestheader["time"] + time_delta
is_mine = next_block_is_mine(bci["bestblockhash"], my_blocks)
@@ -419,7 +423,7 @@ def do_generate(args):
# report
bstr = "block" if is_mine else "backup block"
- next_delta = next_block_delta(block.nBits, block.hash, ultimate_target, args.poisson)
+ next_delta = next_block_delta(block.nBits, block.hash, ultimate_target, args.poisson, args.max_interval)
next_delta += block.nTime - time.time()
next_is_mine = next_block_is_mine(block.hash, my_blocks)
@@ -497,6 +501,7 @@ def main():
generate.add_argument("--multiminer", default=None, type=str, help="Specify which set of blocks to mine (eg: 1-40/100 for the first 40%%, 2/3 for the second 3rd)")
generate.add_argument("--backup-delay", default=300, type=int, help="Seconds to delay before mining blocks reserved for other miners (default=300)")
generate.add_argument("--standby-delay", default=0, type=int, help="Seconds to delay before mining blocks (default=0)")
+ generate.add_argument("--max-interval", default=1800, type=int, help="Maximum interblock interval (seconds)")
calibrate = cmds.add_parser("calibrate", help="Calibrate difficulty")
calibrate.set_defaults(fn=do_calibrate)
diff --git a/depends/packages/capnp.mk b/depends/packages/capnp.mk
index 8a3a14810d6e..f4778c1ecdc3 100644
--- a/depends/packages/capnp.mk
+++ b/depends/packages/capnp.mk
@@ -6,8 +6,15 @@ $(package)_file_name=$(native_$(package)_file_name)
$(package)_sha256_hash=$(native_$(package)_sha256_hash)
$(package)_dependencies=native_$(package)
+define $(package)_set_vars :=
+$(package)_config_opts := --with-external-capnp
+$(package)_config_opts += CAPNP="$$(native_capnp_prefixbin)/capnp"
+$(package)_config_opts += CAPNP_CXX="$$(native_capnp_prefixbin)/capnp-c++"
+$(package)_config_opts_android := --disable-shared
+endef
+
define $(package)_config_cmds
- $($(package)_autoconf) --with-external-capnp
+ $($(package)_autoconf)
endef
define $(package)_build_cmds
diff --git a/doc/REST-interface.md b/doc/REST-interface.md
index 09d40573ef3b..dd5925acce2d 100644
--- a/doc/REST-interface.md
+++ b/doc/REST-interface.md
@@ -31,6 +31,7 @@ Supported API
`GET /rest/tx/.`
Given a transaction hash: returns a transaction in binary, hex-encoded binary, or JSON formats.
+Responds with 404 if the transaction doesn't exist.
By default, this endpoint will only search the mempool.
To query for a confirmed transaction, enable the transaction index via "txindex=1" command line / configuration option.
@@ -76,6 +77,7 @@ Responds with 404 if the block doesn't exist.
`GET /rest/blockhashbyheight/.`
Given a height: returns hash of block in best-block-chain at height provided.
+Responds with 404 if block not found.
#### Chaininfos
`GET /rest/chaininfo.json`
diff --git a/doc/bips.md b/doc/bips.md
index ddc2205fabf1..25381818e487 100644
--- a/doc/bips.md
+++ b/doc/bips.md
@@ -1,4 +1,4 @@
-BIPs that are implemented by Bitcoin Core (up-to-date up to **v23.0**):
+BIPs that are implemented by Bitcoin Core (up-to-date up to **v24.0**):
* [`BIP 9`](https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki): The changes allowing multiple soft-forks to be deployed in parallel have been implemented since **v0.12.1** ([PR #7575](https://github.com/bitcoin/bitcoin/pull/7575))
* [`BIP 11`](https://github.com/bitcoin/bips/blob/master/bip-0011.mediawiki): Multisig outputs are standard since **v0.6.0** ([PR #669](https://github.com/bitcoin/bitcoin/pull/669)).
diff --git a/doc/release-notes/release-notes-0.20.2.md b/doc/release-notes/release-notes-0.20.2.md
new file mode 100644
index 000000000000..ad001bc9c12c
--- /dev/null
+++ b/doc/release-notes/release-notes-0.20.2.md
@@ -0,0 +1,165 @@
+0.20.2 Release Notes
+====================
+
+Bitcoin Core version 0.20.2 is now available from:
+
+
+
+This minor release includes various bug fixes and performance
+improvements, as well as updated translations.
+
+Please report bugs using the issue tracker at GitHub:
+
+
+
+To receive security and update notifications, please subscribe to:
+
+
+
+How to Upgrade
+==============
+
+If you are running an older version, shut it down. Wait until it has completely
+shut down (which might take a few minutes in some cases), then run the
+installer (on Windows) or just copy over `/Applications/Bitcoin-Qt` (on Mac)
+or `bitcoind`/`bitcoin-qt` (on Linux).
+
+Upgrading directly from a version of Bitcoin Core that has reached its EOL is
+possible, but it might take some time if the data directory needs to be migrated. Old
+wallet versions of Bitcoin Core are generally supported.
+
+Compatibility
+==============
+
+Bitcoin Core is supported and extensively tested on operating systems
+using the Linux kernel, macOS 10.12+, and Windows 7 and newer. Bitcoin
+Core should also work on most other Unix-like systems but is not as
+frequently tested on them. It is not recommended to use Bitcoin Core on
+unsupported systems.
+
+From Bitcoin Core 0.20.0 onwards, macOS versions earlier than 10.12 are no
+longer supported. Additionally, Bitcoin Core does not yet change appearance
+when macOS "dark mode" is activated.
+
+Known Bugs
+==========
+
+The process for generating the source code release ("tarball") has changed in an
+effort to make it more complete, however, there are a few regressions in
+this release:
+
+- The generated `configure` script is currently missing, and you will need to
+ install autotools and run `./autogen.sh` before you can run
+ `./configure`. This is the same as when checking out from git.
+
+- Instead of running `make` simply, you should instead run
+ `BITCOIN_GENBUILD_NO_GIT=1 make`.
+
+Notable changes
+===============
+
+Changes regarding misbehaving peers
+-----------------------------------
+
+Peers that misbehave (e.g. send us invalid blocks) are now referred to as
+discouraged nodes in log output, as they're not (and weren't) strictly banned:
+incoming connections are still allowed from them, but they're preferred for
+eviction.
+
+Furthermore, a few additional changes are introduced to how discouraged
+addresses are treated:
+
+- Discouraging an address does not time out automatically after 24 hours
+ (or the `-bantime` setting). Depending on traffic from other peers,
+ discouragement may time out at an indeterminate time.
+
+- Discouragement is not persisted over restarts.
+
+- There is no method to list discouraged addresses. They are not returned by
+ the `listbanned` RPC. That RPC also no longer reports the `ban_reason`
+ field, as `"manually added"` is the only remaining option.
+
+- Discouragement cannot be removed with the `setban remove` RPC command.
+ If you need to remove a discouragement, you can remove all discouragements by
+ stop-starting your node.
+
+Notification changes
+--------------------
+
+`-walletnotify` notifications are now sent for wallet transactions that are
+removed from the mempool because they conflict with a new block. These
+notifications were sent previously before the v0.19 release, but had been
+broken since that release (bug
+[#18325](https://github.com/bitcoin/bitcoin/issues/18325)).
+
+PSBT changes
+------------
+
+PSBTs will contain both the non-witness utxo and the witness utxo for segwit
+inputs in order to restore compatibility with wallet software that are now
+requiring the full previous transaction for segwit inputs. The witness utxo
+is still provided to maintain compatibility with software which relied on its
+existence to determine whether an input was segwit.
+
+0.20.2 change log
+=================
+
+### P2P protocol and network code
+
+- #19620 Add txids with non-standard inputs to reject filter (sdaftuar)
+- #20146 Send post-verack handshake messages at most once (MarcoFalke)
+
+### Wallet
+
+- #19740 Simplify and fix CWallet::SignTransaction (achow101)
+
+### RPC and other APIs
+
+- #19836 Properly deserialize txs with witness before signing (MarcoFalke)
+- #20731 Add missing description of vout in getrawtransaction help text (benthecarman)
+
+### Build system
+
+- #20142 build: set minimum required Boost to 1.48.0 (fanquake)
+- #20298 use the new plistlib API (jonasschnelli)
+- #20880 gitian: Use custom MacOS code signing tool (achow101)
+- #22190 Use latest signapple commit (achow101)
+
+### Tests and QA
+
+- #19839 Set appveyor vm version to previous Visual Studio 2019 release. (sipsorcery)
+- #19842 Update the vcpkg checkout commit ID in appveyor config. (sipsorcery)
+- #20562 Test that a fully signed tx given to signrawtx is unchanged (achow101)
+
+### Miscellaneous
+
+- #19192 Extract net permissions doc (MarcoFalke)
+- #19777 Correct description for getblockstats's txs field (shesek)
+- #20080 Strip any trailing / in -datadir and -blocksdir paths (hebasto)
+- #20082 fixes read buffer to use min rather than max (EthanHeilman)
+- #20141 Avoid the use of abs64 in timedata (sipa)
+- #20756 Add missing field (permissions) to the getpeerinfo help (amitiuttarwar)
+- #20861 BIP 350: Implement Bech32m and use it for v1+ segwit addresses (sipa)
+- #22124 Update translations after closing 0.20.x on Transifex (hebasto)
+- #21471 fix bech32_encode calls in gen_key_io_test_vectors.py (sipa)
+- #22837 mention bech32m/BIP350 in doc/descriptors.md (sipa)
+
+Credits
+=======
+
+Thanks to everyone who directly contributed to this release:
+
+- Aaron Clauson
+- Amiti Uttarwar
+- Andrew Chow
+- Ethan Heilman
+- fanquake
+- Hennadii Stepanov
+- Jonas Schnelli
+- MarcoFalke
+- Nadav Ivgi
+- Pieter Wuille
+- Suhas Daftuar
+
+As well as to everyone that helped with translations on
+[Transifex](https://www.transifex.com/bitcoin/bitcoin/).
diff --git a/doc/release-notes/release-notes-0.21.2.md b/doc/release-notes/release-notes-0.21.2.md
new file mode 100644
index 000000000000..3b33c48a2698
--- /dev/null
+++ b/doc/release-notes/release-notes-0.21.2.md
@@ -0,0 +1,109 @@
+0.21.2 Release Notes
+====================
+
+Bitcoin Core version 0.21.2 is now available from:
+
+
+
+This minor release includes various bug fixes and performance
+improvements, as well as updated translations.
+
+Please report bugs using the issue tracker at GitHub:
+
+
+
+To receive security and update notifications, please subscribe to:
+
+
+
+How to Upgrade
+==============
+
+If you are running an older version, shut it down. Wait until it has completely
+shut down (which might take a few minutes in some cases), then run the
+installer (on Windows) or just copy over `/Applications/Bitcoin-Qt` (on Mac)
+or `bitcoind`/`bitcoin-qt` (on Linux).
+
+Upgrading directly from a version of Bitcoin Core that has reached its EOL is
+possible, but it might take some time if the data directory needs to be migrated. Old
+wallet versions of Bitcoin Core are generally supported.
+
+Compatibility
+==============
+
+Bitcoin Core is supported and extensively tested on operating systems
+using the Linux kernel, macOS 10.12+, and Windows 7 and newer. Bitcoin
+Core should also work on most other Unix-like systems but is not as
+frequently tested on them. It is not recommended to use Bitcoin Core on
+unsupported systems.
+
+From Bitcoin Core 0.20.0 onwards, macOS versions earlier than 10.12 are no
+longer supported. Additionally, Bitcoin Core does not yet change appearance
+when macOS "dark mode" is activated.
+
+
+0.21.2 change log
+=================
+
+### P2P protocol and network code
+
+- #21644 use NetPermissions::HasFlag() in CConnman::Bind() (jonatack)
+- #22569 Rate limit the processing of rumoured addresses (sipa)
+
+### Wallet
+
+- #21907 Do not iterate a directory if having an error while accessing it (hebasto)
+
+### RPC
+
+- #19361 Reset scantxoutset progress before inferring descriptors (prusnak)
+
+### Build System
+
+- #21932 depends: update Qt 5.9 source url (kittywhiskers)
+- #22017 Update Windows code signing certificate (achow101)
+- #22191 Use custom MacOS code signing tool (achow101)
+- #22713 Fix build with Boost 1.77.0 (sizeofvoid)
+
+### Tests and QA
+
+- #20182 Build with --enable-werror by default, and document exceptions (hebasto)
+- #20535 Fix intermittent feature_taproot issue (MarcoFalke)
+- #21663 Fix macOS brew install command (hebasto)
+- #22279 add missing ECCVerifyHandle to base_encode_decode (apoelstra)
+- #22730 Run fuzzer task for the master branch only (hebasto)
+
+### GUI
+
+- #277 Do not use QClipboard::Selection on Windows and macOS. (hebasto)
+- #280 Remove user input from URI error message (prayank23)
+- #365 Draw "eye" sign at the beginning of watch-only addresses (hebasto)
+
+### Miscellaneous
+
+- #22002 Fix crash when parsing command line with -noincludeconf=0 (MarcoFalke)
+- #22137 util: Properly handle -noincludeconf on command line (take 2) (MarcoFalke)
+
+
+Credits
+=======
+
+Thanks to everyone who directly contributed to this release:
+
+- Andrew Chow
+- Andrew Poelstra
+- fanquake
+- Hennadii Stepanov
+- Jon Atack
+- Kittywhiskers Van Gogh
+- Luke Dashjr
+- MarcoFalke
+- Pavol Rusnak
+- Pieter Wuille
+- prayank23
+- Rafael Sadowski
+- W. J. van der Laan
+
+
+As well as to everyone that helped with translations on
+[Transifex](https://www.transifex.com/bitcoin/bitcoin/).
diff --git a/src/Makefile.am b/src/Makefile.am
index 5859aac9a8f8..c00ed056d138 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -178,6 +178,7 @@ BITCOIN_CORE_H = \
clientversion.h \
coins.h \
common/bloom.h \
+ common/run_command.h \
compat/assumptions.h \
compat/byteswap.h \
compat/compat.h \
@@ -675,7 +676,7 @@ libbitcoin_consensus_a_SOURCES = \
version.h
# common: shared between navcoind and non-server tools
-libbitcoin_common_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
+libbitcoin_common_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS)
libbitcoin_common_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_common_a_SOURCES = \
base58.cpp \
@@ -683,6 +684,7 @@ libbitcoin_common_a_SOURCES = \
chainparams.cpp \
coins.cpp \
common/bloom.cpp \
+ common/run_command.cpp \
compressor.cpp \
core_read.cpp \
core_write.cpp \
@@ -1000,7 +1002,6 @@ libbitcoinkernel_la_SOURCES = \
txdb.cpp \
txmempool.cpp \
uint256.cpp \
- util/bytevectorhash.cpp \
util/check.cpp \
util/getuniquepath.cpp \
util/hasher.cpp \
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 29ea3c152ab7..c833a22865ab 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -187,6 +187,7 @@ BITCOIN_TESTS += \
wallet/test/availablecoins_tests.cpp \
wallet/test/init_tests.cpp \
wallet/test/ismine_tests.cpp \
+ wallet/test/rpc_util_tests.cpp \
wallet/test/scriptpubkeyman_tests.cpp \
wallet/test/walletload_tests.cpp
@@ -199,7 +200,8 @@ BITCOIN_TESTS += wallet/test/db_tests.cpp
endif
FUZZ_WALLET_SRC = \
- wallet/test/fuzz/coinselection.cpp
+ wallet/test/fuzz/coinselection.cpp \
+ wallet/test/fuzz/parse_iso8601.cpp
if USE_SQLITE
FUZZ_WALLET_SRC += \
@@ -301,7 +303,6 @@ test_fuzz_fuzz_SOURCES = \
test/fuzz/node_eviction.cpp \
test/fuzz/p2p_transport_serialization.cpp \
test/fuzz/parse_hd_keypath.cpp \
- test/fuzz/parse_iso8601.cpp \
test/fuzz/parse_numbers.cpp \
test/fuzz/parse_script.cpp \
test/fuzz/parse_univalue.cpp \
diff --git a/src/Makefile.test_fuzz.include b/src/Makefile.test_fuzz.include
index 11b5c12062c3..b35d713d579f 100644
--- a/src/Makefile.test_fuzz.include
+++ b/src/Makefile.test_fuzz.include
@@ -10,12 +10,13 @@ EXTRA_LIBRARIES += \
TEST_FUZZ_H = \
test/fuzz/fuzz.h \
test/fuzz/FuzzedDataProvider.h \
- test/fuzz/mempool_utils.h \
- test/fuzz/util.h
+ test/fuzz/util.h \
+ test/fuzz/util/mempool.h
libtest_fuzz_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS)
libtest_fuzz_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libtest_fuzz_a_SOURCES = \
test/fuzz/fuzz.cpp \
test/fuzz/util.cpp \
+ test/fuzz/util/mempool.cpp \
$(TEST_FUZZ_H)
diff --git a/src/bech32.cpp b/src/bech32.cpp
index dce9b2e4cc3f..8e0025b8f42b 100644
--- a/src/bech32.cpp
+++ b/src/bech32.cpp
@@ -241,7 +241,7 @@ constexpr std::array GenerateSyndromeConstants() {
std::array SYNDROME_CONSTS{};
for (int k = 1; k < 6; ++k) {
for (int shift = 0; shift < 5; ++shift) {
- int16_t b = GF1024_LOG.at(1 << shift);
+ int16_t b = GF1024_LOG.at(size_t{1} << shift);
int16_t c0 = GF1024_EXP.at((997*k + b) % 1023);
int16_t c1 = GF1024_EXP.at((998*k + b) % 1023);
int16_t c2 = GF1024_EXP.at((999*k + b) % 1023);
diff --git a/src/common/run_command.cpp b/src/common/run_command.cpp
new file mode 100644
index 000000000000..6ad9f75b5d99
--- /dev/null
+++ b/src/common/run_command.cpp
@@ -0,0 +1,64 @@
+// Copyright (c) 2022 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#if defined(HAVE_CONFIG_H)
+#include
+#endif
+
+#include
+
+#include
+#include
+
+#ifdef ENABLE_EXTERNAL_SIGNER
+#if defined(__GNUC__)
+// Boost 1.78 requires the following workaround.
+// See: https://github.com/boostorg/process/issues/235
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wnarrowing"
+#endif
+#include
+#if defined(__GNUC__)
+#pragma GCC diagnostic pop
+#endif
+#endif // ENABLE_EXTERNAL_SIGNER
+
+UniValue RunCommandParseJSON(const std::string& str_command, const std::string& str_std_in)
+{
+#ifdef ENABLE_EXTERNAL_SIGNER
+ namespace bp = boost::process;
+
+ UniValue result_json;
+ bp::opstream stdin_stream;
+ bp::ipstream stdout_stream;
+ bp::ipstream stderr_stream;
+
+ if (str_command.empty()) return UniValue::VNULL;
+
+ bp::child c(
+ str_command,
+ bp::std_out > stdout_stream,
+ bp::std_err > stderr_stream,
+ bp::std_in < stdin_stream
+ );
+ if (!str_std_in.empty()) {
+ stdin_stream << str_std_in << std::endl;
+ }
+ stdin_stream.pipe().close();
+
+ std::string result;
+ std::string error;
+ std::getline(stdout_stream, result);
+ std::getline(stderr_stream, error);
+
+ c.wait();
+ const int n_error = c.exit_code();
+ if (n_error) throw std::runtime_error(strprintf("RunCommandParseJSON error: process(%s) returned %d: %s\n", str_command, n_error, error));
+ if (!result_json.read(result)) throw std::runtime_error("Unable to parse JSON: " + result);
+
+ return result_json;
+#else
+ throw std::runtime_error("Compiled without external signing support (required for external signing).");
+#endif // ENABLE_EXTERNAL_SIGNER
+}
diff --git a/src/common/run_command.h b/src/common/run_command.h
new file mode 100644
index 000000000000..2fbdc071eeca
--- /dev/null
+++ b/src/common/run_command.h
@@ -0,0 +1,21 @@
+// Copyright (c) 2022 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_COMMON_RUN_COMMAND_H
+#define BITCOIN_COMMON_RUN_COMMAND_H
+
+#include
+
+class UniValue;
+
+/**
+ * Execute a command which returns JSON, and parse the result.
+ *
+ * @param str_command The command to execute, including any arguments
+ * @param str_std_in string to pass to stdin
+ * @return parsed JSON
+ */
+UniValue RunCommandParseJSON(const std::string& str_command, const std::string& str_std_in="");
+
+#endif // BITCOIN_COMMON_RUN_COMMAND_H
diff --git a/src/external_signer.cpp b/src/external_signer.cpp
index 094314e87845..0e582629f749 100644
--- a/src/external_signer.cpp
+++ b/src/external_signer.cpp
@@ -3,10 +3,10 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include
+#include
#include
#include
#include
-#include
#include
#include
diff --git a/src/index/base.cpp b/src/index/base.cpp
index 88c2ce98faa7..3eea09b17d9f 100644
--- a/src/index/base.cpp
+++ b/src/index/base.cpp
@@ -298,6 +298,10 @@ void BaseIndex::BlockConnected(const std::shared_ptr& block, const
}
interfaces::BlockInfo block_info = kernel::MakeBlockInfo(pindex, block.get());
if (CustomAppend(block_info)) {
+ // Setting the best block index is intentionally the last step of this
+ // function, so BlockUntilSyncedToCurrentChain callers waiting for the
+ // best block index to be updated can rely on the block being fully
+ // processed, and the index object being safe to delete.
SetBestBlockIndex(pindex);
} else {
FatalError("%s: Failed to write block %s to index",
@@ -414,10 +418,17 @@ IndexSummary BaseIndex::GetSummary() const
void BaseIndex::SetBestBlockIndex(const CBlockIndex* block) {
assert(!node::fPruneMode || AllowPrune());
- m_best_block_index = block;
if (AllowPrune() && block) {
node::PruneLockInfo prune_lock;
prune_lock.height_first = block->nHeight;
WITH_LOCK(::cs_main, m_chainstate->m_blockman.UpdatePruneLock(GetName(), prune_lock));
}
+
+ // Intentionally set m_best_block_index as the last step in this function,
+ // after updating prune locks above, and after making any other references
+ // to *this, so the BlockUntilSyncedToCurrentChain function (which checks
+ // m_best_block_index as an optimization) can be used to wait for the last
+ // BlockConnected notification and safely assume that prune locks are
+ // updated and that the index object is safe to delete.
+ m_best_block_index = block;
}
diff --git a/src/index/blockfilterindex.h b/src/index/blockfilterindex.h
index 5af467109107..9e69388dc82e 100644
--- a/src/index/blockfilterindex.h
+++ b/src/index/blockfilterindex.h
@@ -12,6 +12,8 @@
#include
#include
+static const char* const DEFAULT_BLOCKFILTERINDEX = "0";
+
/** Interval between compact filter checkpoints. See BIP 157. */
static constexpr int CFCHECKPT_INTERVAL = 1000;
diff --git a/src/index/coinstatsindex.h b/src/index/coinstatsindex.h
index fa59cb1ab181..aa0d7f9fd5cc 100644
--- a/src/index/coinstatsindex.h
+++ b/src/index/coinstatsindex.h
@@ -14,6 +14,8 @@ namespace kernel {
struct CCoinsStats;
}
+static constexpr bool DEFAULT_COINSTATSINDEX{false};
+
/**
* CoinStatsIndex maintains statistics on the UTXO set.
*/
diff --git a/src/index/txindex.h b/src/index/txindex.h
index 8c1aa0003396..4cea35045df7 100644
--- a/src/index/txindex.h
+++ b/src/index/txindex.h
@@ -7,6 +7,8 @@
#include
+static constexpr bool DEFAULT_TXINDEX{false};
+
/**
* TxIndex is used to look up transactions included in the blockchain by hash.
* The index is written to a LevelDB database and records the filesystem
diff --git a/src/kernel/mempool_limits.h b/src/kernel/mempool_limits.h
index e192e7e6cdee..8d4495c3cb1c 100644
--- a/src/kernel/mempool_limits.h
+++ b/src/kernel/mempool_limits.h
@@ -24,6 +24,15 @@ struct MemPoolLimits {
int64_t descendant_count{DEFAULT_DESCENDANT_LIMIT};
//! The maximum allowed size in virtual bytes of an entry and its descendants within a package.
int64_t descendant_size_vbytes{DEFAULT_DESCENDANT_SIZE_LIMIT_KVB * 1'000};
+
+ /**
+ * @return MemPoolLimits with all the limits set to the maximum
+ */
+ static constexpr MemPoolLimits NoLimits()
+ {
+ int64_t no_limit{std::numeric_limits::max()};
+ return {no_limit, no_limit, no_limit, no_limit};
+ }
};
} // namespace kernel
diff --git a/src/leveldb/util/env_windows.cc b/src/leveldb/util/env_windows.cc
index 4dcba222a1b5..aafcdcc3be50 100644
--- a/src/leveldb/util/env_windows.cc
+++ b/src/leveldb/util/env_windows.cc
@@ -194,7 +194,7 @@ class WindowsRandomAccessFile : public RandomAccessFile {
Status Read(uint64_t offset, size_t n, Slice* result,
char* scratch) const override {
DWORD bytes_read = 0;
- OVERLAPPED overlapped = {0};
+ OVERLAPPED overlapped = {};
overlapped.OffsetHigh = static_cast(offset >> 32);
overlapped.Offset = static_cast(offset);
diff --git a/src/net.cpp b/src/net.cpp
index b194be326501..0736f3ef1b0d 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -91,13 +91,12 @@ static constexpr auto FEELER_SLEEP_WINDOW{1s};
/** Used to pass flags to the Bind() function */
enum BindFlags {
BF_NONE = 0,
- BF_EXPLICIT = (1U << 0),
- BF_REPORT_ERROR = (1U << 1),
+ BF_REPORT_ERROR = (1U << 0),
/**
* Do not call AddLocal() for our special addresses, e.g., for incoming
* Tor connections, to prevent gossiping them over the network.
*/
- BF_DONT_ADVERTISE = (1U << 2),
+ BF_DONT_ADVERTISE = (1U << 1),
};
// The set of sockets cannot be modified while waiting
@@ -2231,9 +2230,6 @@ bool CConnman::Bind(const CService& addr_, unsigned int flags, NetPermissionFlag
{
const CService addr{MaybeFlipIPv6toCJDNS(addr_)};
- if (!(flags & BF_EXPLICIT) && !IsReachable(addr)) {
- return false;
- }
bilingual_str strError;
if (!BindListenPort(addr, strError, permissions)) {
if ((flags & BF_REPORT_ERROR) && m_client_interface) {
@@ -2253,13 +2249,13 @@ bool CConnman::InitBinds(const Options& options)
{
bool fBound = false;
for (const auto& addrBind : options.vBinds) {
- fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR), NetPermissionFlags::None);
+ fBound |= Bind(addrBind, BF_REPORT_ERROR, NetPermissionFlags::None);
}
for (const auto& addrBind : options.vWhiteBinds) {
- fBound |= Bind(addrBind.m_service, (BF_EXPLICIT | BF_REPORT_ERROR), addrBind.m_flags);
+ fBound |= Bind(addrBind.m_service, BF_REPORT_ERROR, addrBind.m_flags);
}
for (const auto& addr_bind : options.onion_binds) {
- fBound |= Bind(addr_bind, BF_EXPLICIT | BF_DONT_ADVERTISE, NetPermissionFlags::None);
+ fBound |= Bind(addr_bind, BF_DONT_ADVERTISE, NetPermissionFlags::None);
}
if (options.bind_on_any) {
struct in_addr inaddr_any;
diff --git a/src/node/caches.cpp b/src/node/caches.cpp
index f168332ee657..a39ad7aeb661 100644
--- a/src/node/caches.cpp
+++ b/src/node/caches.cpp
@@ -4,9 +4,9 @@
#include
+#include
#include
#include
-#include
namespace node {
CacheSizes CalculateCacheSizes(const ArgsManager& args, size_t n_indexes)
diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp
index aa7ddec77017..8a0011a629ef 100644
--- a/src/node/interfaces.cpp
+++ b/src/node/interfaces.cpp
@@ -660,8 +660,7 @@ class ChainImpl : public Chain
std::string unused_error_string;
LOCK(m_node.mempool->cs);
return m_node.mempool->CalculateMemPoolAncestors(
- entry, ancestors, limits.ancestor_count, limits.ancestor_size_vbytes,
- limits.descendant_count, limits.descendant_size_vbytes, unused_error_string);
+ entry, ancestors, limits, unused_error_string);
}
CFeeRate estimateSmartFee(int num_blocks, bool conservative, FeeCalculation* calc) override
{
diff --git a/src/node/miner.cpp b/src/node/miner.cpp
index b277188c1fd5..e11ec5b0f1f5 100644
--- a/src/node/miner.cpp
+++ b/src/node/miner.cpp
@@ -105,7 +105,7 @@ void BlockAssembler::resetBlock()
std::unique_ptr BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn)
{
- int64_t nTimeStart = GetTimeMicros();
+ const auto time_start{SteadyClock::now()};
resetBlock();
@@ -143,7 +143,7 @@ std::unique_ptr BlockAssembler::CreateNewBlock(const CScript& sc
addPackageTxs(*m_mempool, nPackagesSelected, nDescendantsUpdated);
}
- int64_t nTime1 = GetTimeMicros();
+ const auto time_1{SteadyClock::now()};
m_last_block_num_txs = nBlockTx;
m_last_block_weight = nBlockWeight;
@@ -173,9 +173,12 @@ std::unique_ptr BlockAssembler::CreateNewBlock(const CScript& sc
if (!TestBlockValidity(state, chainparams, m_chainstate, *pblock, pindexPrev, GetAdjustedTime, false, false)) {
throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", __func__, state.ToString()));
}
- int64_t nTime2 = GetTimeMicros();
+ const auto time_2{SteadyClock::now()};
- LogPrint(BCLog::BENCH, "CreateNewBlock() packages: %.2fms (%d packages, %d updated descendants), validity: %.2fms (total %.2fms)\n", 0.001 * (nTime1 - nTimeStart), nPackagesSelected, nDescendantsUpdated, 0.001 * (nTime2 - nTime1), 0.001 * (nTime2 - nTimeStart));
+ LogPrint(BCLog::BENCH, "CreateNewBlock() packages: %.2fms (%d packages, %d updated descendants), validity: %.2fms (total %.2fms)\n",
+ Ticks(time_1 - time_start), nPackagesSelected, nDescendantsUpdated,
+ Ticks(time_2 - time_1),
+ Ticks(time_2 - time_start));
return std::move(pblocktemplate);
}
@@ -257,13 +260,9 @@ static int UpdatePackagesForAdded(const CTxMemPool& mempool,
modtxiter mit = mapModifiedTx.find(desc);
if (mit == mapModifiedTx.end()) {
CTxMemPoolModifiedEntry modEntry(desc);
- modEntry.nSizeWithAncestors -= it->GetTxSize();
- modEntry.nModFeesWithAncestors -= it->GetModifiedFee();
- modEntry.nSigOpCostWithAncestors -= it->GetSigOpCost();
- mapModifiedTx.insert(modEntry);
- } else {
- mapModifiedTx.modify(mit, update_for_parent_inclusion(it));
+ mit = mapModifiedTx.insert(modEntry).first;
}
+ mapModifiedTx.modify(mit, update_for_parent_inclusion(it));
}
}
return nDescendantsUpdated;
@@ -396,9 +395,8 @@ void BlockAssembler::addPackageTxs(const CTxMemPool& mempool, int& nPackagesSele
}
CTxMemPool::setEntries ancestors;
- uint64_t nNoLimit = std::numeric_limits::max();
std::string dummy;
- mempool.CalculateMemPoolAncestors(*iter, ancestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy, false);
+ mempool.CalculateMemPoolAncestors(*iter, ancestors, CTxMemPool::Limits::NoLimits(), dummy, false);
onlyUnconfirmed(ancestors);
ancestors.insert(iter);
diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp
index 2b940be07ed0..22defb91a995 100644
--- a/src/policy/fees.cpp
+++ b/src/policy/fees.cpp
@@ -997,8 +997,9 @@ bool CBlockPolicyEstimator::Read(AutoFile& filein)
return true;
}
-void CBlockPolicyEstimator::FlushUnconfirmed() {
- int64_t startclear = GetTimeMicros();
+void CBlockPolicyEstimator::FlushUnconfirmed()
+{
+ const auto startclear{SteadyClock::now()};
LOCK(m_cs_fee_estimator);
size_t num_entries = mapMemPoolTxs.size();
// Remove every entry in mapMemPoolTxs
@@ -1006,8 +1007,8 @@ void CBlockPolicyEstimator::FlushUnconfirmed() {
auto mi = mapMemPoolTxs.begin();
_removeTx(mi->first, false); // this calls erase() on mapMemPoolTxs
}
- int64_t endclear = GetTimeMicros();
- LogPrint(BCLog::ESTIMATEFEE, "Recorded %u unconfirmed txs from mempool in %gs\n", num_entries, (endclear - startclear)*0.000001);
+ const auto endclear{SteadyClock::now()};
+ LogPrint(BCLog::ESTIMATEFEE, "Recorded %u unconfirmed txs from mempool in %gs\n", num_entries, Ticks(endclear - startclear));
}
FeeFilterRounder::FeeFilterRounder(const CFeeRate& minIncrementalFee)
diff --git a/src/policy/rbf.cpp b/src/policy/rbf.cpp
index 6098caced9fc..55f47f485bb1 100644
--- a/src/policy/rbf.cpp
+++ b/src/policy/rbf.cpp
@@ -36,10 +36,9 @@ RBFTransactionState IsRBFOptIn(const CTransaction& tx, const CTxMemPool& pool)
// If all the inputs have nSequence >= maxint-1, it still might be
// signaled for RBF if any unconfirmed parents have signaled.
- uint64_t noLimit = std::numeric_limits::max();
std::string dummy;
CTxMemPoolEntry entry = *pool.mapTx.find(tx.GetHash());
- pool.CalculateMemPoolAncestors(entry, ancestors, noLimit, noLimit, noLimit, noLimit, dummy, false);
+ pool.CalculateMemPoolAncestors(entry, ancestors, CTxMemPool::Limits::NoLimits(), dummy, false);
for (CTxMemPool::txiter it : ancestors) {
if (SignalsOptInRBF(it->GetTx())) {
diff --git a/src/rpc/mempool.cpp b/src/rpc/mempool.cpp
index e390a7c15c0a..706d7839427e 100644
--- a/src/rpc/mempool.cpp
+++ b/src/rpc/mempool.cpp
@@ -449,9 +449,8 @@ static RPCHelpMan getmempoolancestors()
}
CTxMemPool::setEntries setAncestors;
- uint64_t noLimit = std::numeric_limits::max();
std::string dummy;
- mempool.CalculateMemPoolAncestors(*it, setAncestors, noLimit, noLimit, noLimit, noLimit, dummy, false);
+ mempool.CalculateMemPoolAncestors(*it, setAncestors, CTxMemPool::Limits::NoLimits(), dummy, false);
if (!fVerbose) {
UniValue o(UniValue::VARR);
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index c4bd03fa9f09..98383fdaca79 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -730,10 +730,10 @@ static RPCHelpMan getblocktemplate()
// Update block
static CBlockIndex* pindexPrev;
- static int64_t nStart;
+ static int64_t time_start;
static std::unique_ptr pblocktemplate;
if (pindexPrev != active_chain.Tip() ||
- (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 5))
+ (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - time_start > 5))
{
// Clear pindexPrev so future calls make a new block, despite any failures from here on
pindexPrev = nullptr;
@@ -741,7 +741,7 @@ static RPCHelpMan getblocktemplate()
// Store the pindexBest used before CreateNewBlock, to avoid races
nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
CBlockIndex* pindexPrevNew = active_chain.Tip();
- nStart = GetTime();
+ time_start = GetTime();
// Create new block
CScript scriptDummy = CScript() << OP_TRUE;
diff --git a/src/streams.h b/src/streams.h
index 24778ab331aa..ce1ba26d45ba 100644
--- a/src/streams.h
+++ b/src/streams.h
@@ -269,7 +269,6 @@ class CDataStream
// Stream subset
//
bool eof() const { return size() == 0; }
- CDataStream* rdbuf() { return this; }
int in_avail() const { return size(); }
void SetType(int n) { nType = n; }
diff --git a/src/sync.h b/src/sync.h
index c34d969041ef..1f4e19121439 100644
--- a/src/sync.h
+++ b/src/sync.h
@@ -111,7 +111,7 @@ class LOCKABLE AnnotatedMixin : public PARENT
return PARENT::try_lock();
}
- using UniqueLock = std::unique_lock;
+ using unique_lock = std::unique_lock;
#ifdef __clang__
//! For negative capabilities in the Clang Thread Safety Analysis.
//! A negative requirement uses the EXCLUSIVE_LOCKS_REQUIRED attribute, in conjunction
@@ -147,11 +147,13 @@ inline void AssertLockNotHeldInline(const char* name, const char* file, int line
inline void AssertLockNotHeldInline(const char* name, const char* file, int line, GlobalMutex* cs) LOCKS_EXCLUDED(cs) { AssertLockNotHeldInternal(name, file, line, cs); }
#define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs)
-/** Wrapper around std::unique_lock style lock for Mutex. */
-template
-class SCOPED_LOCKABLE UniqueLock : public Base
+/** Wrapper around std::unique_lock style lock for MutexType. */
+template
+class SCOPED_LOCKABLE UniqueLock : public MutexType::unique_lock
{
private:
+ using Base = typename MutexType::unique_lock;
+
void Enter(const char* pszName, const char* pszFile, int nLine)
{
EnterCritical(pszName, pszFile, nLine, Base::mutex());
@@ -165,15 +167,15 @@ class SCOPED_LOCKABLE UniqueLock : public Base
bool TryEnter(const char* pszName, const char* pszFile, int nLine)
{
EnterCritical(pszName, pszFile, nLine, Base::mutex(), true);
- Base::try_lock();
- if (!Base::owns_lock()) {
- LeaveCritical();
+ if (Base::try_lock()) {
+ return true;
}
- return Base::owns_lock();
+ LeaveCritical();
+ return false;
}
public:
- UniqueLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : Base(mutexIn, std::defer_lock)
+ UniqueLock(MutexType& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : Base(mutexIn, std::defer_lock)
{
if (fTry)
TryEnter(pszName, pszFile, nLine);
@@ -181,7 +183,7 @@ class SCOPED_LOCKABLE UniqueLock : public Base
Enter(pszName, pszFile, nLine);
}
- UniqueLock(Mutex* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn)
+ UniqueLock(MutexType* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn)
{
if (!pmutexIn) return;
@@ -241,29 +243,24 @@ class SCOPED_LOCKABLE UniqueLock : public Base
#define REVERSE_LOCK(g) typename std::decay::type::reverse_lock UNIQUE_NAME(revlock)(g, #g, __FILE__, __LINE__)
-template
-using DebugLock = UniqueLock::type>::type>;
-
// When locking a Mutex, require negative capability to ensure the lock
// is not already held
inline Mutex& MaybeCheckNotHeld(Mutex& cs) EXCLUSIVE_LOCKS_REQUIRED(!cs) LOCK_RETURNED(cs) { return cs; }
inline Mutex* MaybeCheckNotHeld(Mutex* cs) EXCLUSIVE_LOCKS_REQUIRED(!cs) LOCK_RETURNED(cs) { return cs; }
-// When locking a GlobalMutex, just check it is not locked in the surrounding scope
-inline GlobalMutex& MaybeCheckNotHeld(GlobalMutex& cs) LOCKS_EXCLUDED(cs) LOCK_RETURNED(cs) { return cs; }
-inline GlobalMutex* MaybeCheckNotHeld(GlobalMutex* cs) LOCKS_EXCLUDED(cs) LOCK_RETURNED(cs) { return cs; }
-
-// When locking a RecursiveMutex, it's okay to already hold the lock
-// but check that it is not known to be locked in the surrounding scope anyway
-inline RecursiveMutex& MaybeCheckNotHeld(RecursiveMutex& cs) LOCKS_EXCLUDED(cs) LOCK_RETURNED(cs) { return cs; }
-inline RecursiveMutex* MaybeCheckNotHeld(RecursiveMutex* cs) LOCKS_EXCLUDED(cs) LOCK_RETURNED(cs) { return cs; }
+// When locking a GlobalMutex or RecursiveMutex, just check it is not
+// locked in the surrounding scope.
+template
+inline MutexType& MaybeCheckNotHeld(MutexType& m) LOCKS_EXCLUDED(m) LOCK_RETURNED(m) { return m; }
+template
+inline MutexType* MaybeCheckNotHeld(MutexType* m) LOCKS_EXCLUDED(m) LOCK_RETURNED(m) { return m; }
-#define LOCK(cs) DebugLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
+#define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
#define LOCK2(cs1, cs2) \
- DebugLock criticalblock1(MaybeCheckNotHeld(cs1), #cs1, __FILE__, __LINE__); \
- DebugLock criticalblock2(MaybeCheckNotHeld(cs2), #cs2, __FILE__, __LINE__)
-#define TRY_LOCK(cs, name) DebugLock name(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__, true)
-#define WAIT_LOCK(cs, name) DebugLock name(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
+ UniqueLock criticalblock1(MaybeCheckNotHeld(cs1), #cs1, __FILE__, __LINE__); \
+ UniqueLock criticalblock2(MaybeCheckNotHeld(cs2), #cs2, __FILE__, __LINE__)
+#define TRY_LOCK(cs, name) UniqueLock name(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__, true)
+#define WAIT_LOCK(cs, name) UniqueLock name(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
#define ENTER_CRITICAL_SECTION(cs) \
{ \
diff --git a/src/test/banman_tests.cpp b/src/test/banman_tests.cpp
index 27ce9ad63825..ecf60834ce84 100644
--- a/src/test/banman_tests.cpp
+++ b/src/test/banman_tests.cpp
@@ -27,7 +27,7 @@ BOOST_AUTO_TEST_CASE(file)
" { \"version\": 1, \"ban_created\": 0, \"banned_until\": 778, \"address\": \"1.0.0.0/8\" }"
"] }",
};
- assert(WriteBinaryFile(banlist_path + ".json", entries_write));
+ BOOST_REQUIRE(WriteBinaryFile(banlist_path + ".json", entries_write));
{
// The invalid entries will be dropped, but the valid one remains
ASSERT_DEBUG_LOG("Dropping entry with unparseable address or subnet (aaaaaaaaa) from ban list");
@@ -35,7 +35,7 @@ BOOST_AUTO_TEST_CASE(file)
BanMan banman{banlist_path, /*client_interface=*/nullptr, /*default_ban_time=*/0};
banmap_t entries_read;
banman.GetBanned(entries_read);
- assert(entries_read.size() == 1);
+ BOOST_CHECK_EQUAL(entries_read.size(), 1);
}
}
}
diff --git a/src/test/fuzz/integer.cpp b/src/test/fuzz/integer.cpp
index c52fca5fe85e..f05248ab4714 100644
--- a/src/test/fuzz/integer.cpp
+++ b/src/test/fuzz/integer.cpp
@@ -12,6 +12,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/src/test/fuzz/policy_estimator.cpp b/src/test/fuzz/policy_estimator.cpp
index 637ba503c685..a3d57dbdd58d 100644
--- a/src/test/fuzz/policy_estimator.cpp
+++ b/src/test/fuzz/policy_estimator.cpp
@@ -8,6 +8,7 @@
#include
#include
#include
+#include
#include
#include
diff --git a/src/test/fuzz/rbf.cpp b/src/test/fuzz/rbf.cpp
index 1a06ae886ee2..e06e57d9197c 100644
--- a/src/test/fuzz/rbf.cpp
+++ b/src/test/fuzz/rbf.cpp
@@ -9,6 +9,7 @@
#include
#include
#include
+#include
#include
#include
diff --git a/src/test/fuzz/tx_pool.cpp b/src/test/fuzz/tx_pool.cpp
index 283a146369e2..a34e501fcc07 100644
--- a/src/test/fuzz/tx_pool.cpp
+++ b/src/test/fuzz/tx_pool.cpp
@@ -8,8 +8,8 @@
#include
#include
#include
-#include
#include
+#include
#include
#include
#include
diff --git a/src/test/fuzz/txorphan.cpp b/src/test/fuzz/txorphan.cpp
index 943f3f5fdf4b..55060f31cf48 100644
--- a/src/test/fuzz/txorphan.cpp
+++ b/src/test/fuzz/txorphan.cpp
@@ -45,7 +45,7 @@ FUZZ_TARGET_INIT(txorphan, initialize_orphanage)
// if true, allow duplicate input when constructing tx
const bool duplicate_input = fuzzed_data_provider.ConsumeBool();
- LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10 * DEFAULT_MAX_ORPHAN_TRANSACTIONS)
+ LIMITED_WHILE(outpoints.size() < 200'000 && fuzzed_data_provider.ConsumeBool(), 10 * DEFAULT_MAX_ORPHAN_TRANSACTIONS)
{
// construct transaction
const CTransactionRef tx = [&] {
diff --git a/src/test/fuzz/util.cpp b/src/test/fuzz/util.cpp
index 38626d4bcfce..0080b1e56e6e 100644
--- a/src/test/fuzz/util.cpp
+++ b/src/test/fuzz/util.cpp
@@ -307,8 +307,8 @@ CAmount ConsumeMoney(FuzzedDataProvider& fuzzed_data_provider, const std::option
int64_t ConsumeTime(FuzzedDataProvider& fuzzed_data_provider, const std::optional& min, const std::optional& max) noexcept
{
// Avoid t=0 (1970-01-01T00:00:00Z) since SetMockTime(0) disables mocktime.
- static const int64_t time_min{ParseISO8601DateTime("2000-01-01T00:00:01Z")};
- static const int64_t time_max{ParseISO8601DateTime("2100-12-31T23:59:59Z")};
+ static const int64_t time_min{946684801}; // 2000-01-01T00:00:01Z
+ static const int64_t time_max{4133980799}; // 2100-12-31T23:59:59Z
return fuzzed_data_provider.ConsumeIntegralInRange(min.value_or(time_min), max.value_or(time_max));
}
@@ -478,21 +478,6 @@ CTxDestination ConsumeTxDestination(FuzzedDataProvider& fuzzed_data_provider) no
return tx_destination;
}
-CTxMemPoolEntry ConsumeTxMemPoolEntry(FuzzedDataProvider& fuzzed_data_provider, const CTransaction& tx) noexcept
-{
- // Avoid:
- // policy/feerate.cpp:28:34: runtime error: signed integer overflow: 34873208148477500 * 1000 cannot be represented in type 'long'
- //
- // Reproduce using CFeeRate(348732081484775, 10).GetFeePerK()
- const CAmount fee = std::min(ConsumeMoney(fuzzed_data_provider), std::numeric_limits::max() / static_cast(100000));
- assert(MoneyRange(fee));
- const int64_t time = fuzzed_data_provider.ConsumeIntegral();
- const unsigned int entry_height = fuzzed_data_provider.ConsumeIntegral();
- const bool spends_coinbase = fuzzed_data_provider.ConsumeBool();
- const unsigned int sig_op_cost = fuzzed_data_provider.ConsumeIntegralInRange(0, MAX_BLOCK_SIGOPS_COST);
- return CTxMemPoolEntry{MakeTransactionRef(tx), fee, time, entry_height, spends_coinbase, sig_op_cost, {}};
-}
-
bool ContainsSpentInput(const CTransaction& tx, const CCoinsViewCache& inputs) noexcept
{
for (const CTxIn& tx_in : tx.vin) {
diff --git a/src/test/fuzz/util.h b/src/test/fuzz/util.h
index 36d55079cbb4..a354df2bf7a2 100644
--- a/src/test/fuzz/util.h
+++ b/src/test/fuzz/util.h
@@ -23,7 +23,6 @@
#include
#include
#include
-#include
#include
#include
@@ -213,8 +212,6 @@ template
return UintToArith256(ConsumeUInt256(fuzzed_data_provider));
}
-[[nodiscard]] CTxMemPoolEntry ConsumeTxMemPoolEntry(FuzzedDataProvider& fuzzed_data_provider, const CTransaction& tx) noexcept;
-
[[nodiscard]] CTxDestination ConsumeTxDestination(FuzzedDataProvider& fuzzed_data_provider) noexcept;
template
diff --git a/src/test/fuzz/util/mempool.cpp b/src/test/fuzz/util/mempool.cpp
new file mode 100644
index 000000000000..d0053f77d2a0
--- /dev/null
+++ b/src/test/fuzz/util/mempool.cpp
@@ -0,0 +1,27 @@
+// Copyright (c) 2022 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+CTxMemPoolEntry ConsumeTxMemPoolEntry(FuzzedDataProvider& fuzzed_data_provider, const CTransaction& tx) noexcept
+{
+ // Avoid:
+ // policy/feerate.cpp:28:34: runtime error: signed integer overflow: 34873208148477500 * 1000 cannot be represented in type 'long'
+ //
+ // Reproduce using CFeeRate(348732081484775, 10).GetFeePerK()
+ const CAmount fee{ConsumeMoney(fuzzed_data_provider, /*max=*/std::numeric_limits::max() / CAmount{100'000})};
+ assert(MoneyRange(fee));
+ const int64_t time = fuzzed_data_provider.ConsumeIntegral();
+ const unsigned int entry_height = fuzzed_data_provider.ConsumeIntegral();
+ const bool spends_coinbase = fuzzed_data_provider.ConsumeBool();
+ const unsigned int sig_op_cost = fuzzed_data_provider.ConsumeIntegralInRange(0, MAX_BLOCK_SIGOPS_COST);
+ return CTxMemPoolEntry{MakeTransactionRef(tx), fee, time, entry_height, spends_coinbase, sig_op_cost, {}};
+}
diff --git a/src/test/fuzz/mempool_utils.h b/src/test/fuzz/util/mempool.h
similarity index 50%
rename from src/test/fuzz/mempool_utils.h
rename to src/test/fuzz/util/mempool.h
index c172e8c4b7d0..4304e5294e03 100644
--- a/src/test/fuzz/mempool_utils.h
+++ b/src/test/fuzz/util/mempool.h
@@ -2,9 +2,12 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#ifndef BITCOIN_TEST_FUZZ_MEMPOOL_UTILS_H
-#define BITCOIN_TEST_FUZZ_MEMPOOL_UTILS_H
+#ifndef BITCOIN_TEST_FUZZ_UTIL_MEMPOOL_H
+#define BITCOIN_TEST_FUZZ_UTIL_MEMPOOL_H
+#include
+#include
+#include
#include
class DummyChainState final : public Chainstate
@@ -16,4 +19,6 @@ class DummyChainState final : public Chainstate
}
};
-#endif // BITCOIN_TEST_FUZZ_MEMPOOL_UTILS_H
+[[nodiscard]] CTxMemPoolEntry ConsumeTxMemPoolEntry(FuzzedDataProvider& fuzzed_data_provider, const CTransaction& tx) noexcept;
+
+#endif // BITCOIN_TEST_FUZZ_UTIL_MEMPOOL_H
diff --git a/src/test/fuzz/validation_load_mempool.cpp b/src/test/fuzz/validation_load_mempool.cpp
index 8241dff18972..d96609416b5d 100644
--- a/src/test/fuzz/validation_load_mempool.cpp
+++ b/src/test/fuzz/validation_load_mempool.cpp
@@ -9,8 +9,8 @@
#include
#include
#include
-#include
#include
+#include
#include
#include
#include
diff --git a/src/test/mempool_tests.cpp b/src/test/mempool_tests.cpp
index 8c745b07b9a1..19f457b8ddd0 100644
--- a/src/test/mempool_tests.cpp
+++ b/src/test/mempool_tests.cpp
@@ -203,7 +203,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
CTxMemPool::setEntries setAncestorsCalculated;
std::string dummy;
- BOOST_CHECK_EQUAL(pool.CalculateMemPoolAncestors(entry.Fee(2000000LL).FromTx(tx7), setAncestorsCalculated, 100, 1000000, 1000, 1000000, dummy), true);
+ BOOST_CHECK_EQUAL(pool.CalculateMemPoolAncestors(entry.Fee(2'000'000LL).FromTx(tx7), setAncestorsCalculated, CTxMemPool::Limits::NoLimits(), dummy), true);
BOOST_CHECK(setAncestorsCalculated == setAncestors);
pool.addUnchecked(entry.FromTx(tx7), setAncestors);
@@ -261,7 +261,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
tx10.vout[0].nValue = 10 * COIN;
setAncestorsCalculated.clear();
- BOOST_CHECK_EQUAL(pool.CalculateMemPoolAncestors(entry.Fee(200000LL).Time(4).FromTx(tx10), setAncestorsCalculated, 100, 1000000, 1000, 1000000, dummy), true);
+ BOOST_CHECK_EQUAL(pool.CalculateMemPoolAncestors(entry.Fee(200'000LL).Time(4).FromTx(tx10), setAncestorsCalculated, CTxMemPool::Limits::NoLimits(), dummy), true);
BOOST_CHECK(setAncestorsCalculated == setAncestors);
pool.addUnchecked(entry.FromTx(tx10), setAncestors);
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index 9f5fb17b6068..696a799872ac 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -2,7 +2,6 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include
#include
#include
#include
@@ -30,15 +29,24 @@ using node::CBlockTemplate;
namespace miner_tests {
struct MinerTestingSetup : public TestingSetup {
- void TestPackageSelection(const CChainParams& chainparams, const CScript& scriptPubKey, const std::vector& txFirst) EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_node.mempool->cs);
- void TestBasicMining(const CChainParams& chainparams, const CScript& scriptPubKey, const std::vector& txFirst, int baseheight) EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_node.mempool->cs);
- void TestPrioritisedMining(const CChainParams& chainparams, const CScript& scriptPubKey, const std::vector& txFirst) EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_node.mempool->cs);
- bool TestSequenceLocks(const CTransaction& tx) EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_node.mempool->cs)
+ void TestPackageSelection(const CScript& scriptPubKey, const std::vector& txFirst) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
+ void TestBasicMining(const CScript& scriptPubKey, const std::vector& txFirst, int baseheight) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
+ void TestPrioritisedMining(const CScript& scriptPubKey, const std::vector& txFirst) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
+ bool TestSequenceLocks(const CTransaction& tx, CTxMemPool& tx_mempool) EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
{
- CCoinsViewMemPool view_mempool(&m_node.chainman->ActiveChainstate().CoinsTip(), *m_node.mempool);
+ CCoinsViewMemPool view_mempool{&m_node.chainman->ActiveChainstate().CoinsTip(), tx_mempool};
return CheckSequenceLocksAtTip(m_node.chainman->ActiveChain().Tip(), view_mempool, tx);
}
- BlockAssembler AssemblerForTest(const CChainParams& params);
+ CTxMemPool& MakeMempool()
+ {
+ // Delete the previous mempool to ensure with valgrind that the old
+ // pointer is not accessed, when the new one should be accessed
+ // instead.
+ m_node.mempool.reset();
+ m_node.mempool = std::make_unique(MemPoolOptionsForTest(m_node));
+ return *m_node.mempool;
+ }
+ BlockAssembler AssemblerForTest(CTxMemPool& tx_mempool);
};
} // namespace miner_tests
@@ -46,13 +54,13 @@ BOOST_FIXTURE_TEST_SUITE(miner_tests, MinerTestingSetup)
static CFeeRate blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE);
-BlockAssembler MinerTestingSetup::AssemblerForTest(const CChainParams& params)
+BlockAssembler MinerTestingSetup::AssemblerForTest(CTxMemPool& tx_mempool)
{
BlockAssembler::Options options;
options.nBlockMaxWeight = MAX_BLOCK_WEIGHT;
options.blockMinFeeRate = blockMinFeeRate;
- return BlockAssembler{m_node.chainman->ActiveChainstate(), m_node.mempool.get(), options};
+ return BlockAssembler{m_node.chainman->ActiveChainstate(), &tx_mempool, options};
}
constexpr static struct {
@@ -89,8 +97,10 @@ static CBlockIndex CreateBlockIndex(int nHeight, CBlockIndex* active_chain_tip)
// Test suite for ancestor feerate transaction selection.
// Implemented as an additional function, rather than a separate test case,
// to allow reusing the blockchain created in CreateNewBlock_validity.
-void MinerTestingSetup::TestPackageSelection(const CChainParams& chainparams, const CScript& scriptPubKey, const std::vector& txFirst)
+void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const std::vector& txFirst)
{
+ CTxMemPool& tx_mempool{MakeMempool()};
+ LOCK(tx_mempool.cs);
// Test the ancestor feerate transaction selection.
TestMemPoolEntryHelper entry;
@@ -105,21 +115,21 @@ void MinerTestingSetup::TestPackageSelection(const CChainParams& chainparams, co
tx.vout[0].nValue = 5000000000LL - 1000;
// This tx has a low fee: 1000 satoshis
uint256 hashParentTx = tx.GetHash(); // save this txid for later use
- m_node.mempool->addUnchecked(entry.Fee(1000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
+ tx_mempool.addUnchecked(entry.Fee(1000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
// This tx has a medium fee: 10000 satoshis
tx.vin[0].prevout.hash = txFirst[1]->GetHash();
tx.vout[0].nValue = 5000000000LL - 10000;
uint256 hashMediumFeeTx = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Fee(10000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
+ tx_mempool.addUnchecked(entry.Fee(10000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
// This tx has a high fee, but depends on the first transaction
tx.vin[0].prevout.hash = hashParentTx;
tx.vout[0].nValue = 5000000000LL - 1000 - 50000; // 50k satoshi fee
uint256 hashHighFeeTx = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Fee(50000).Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
+ tx_mempool.addUnchecked(entry.Fee(50000).Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
- std::unique_ptr pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey);
+ std::unique_ptr pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey);
BOOST_REQUIRE_EQUAL(pblocktemplate->block.vtx.size(), 4U);
BOOST_CHECK(pblocktemplate->block.vtx[1]->GetHash() == hashParentTx);
BOOST_CHECK(pblocktemplate->block.vtx[2]->GetHash() == hashHighFeeTx);
@@ -129,7 +139,7 @@ void MinerTestingSetup::TestPackageSelection(const CChainParams& chainparams, co
tx.vin[0].prevout.hash = hashHighFeeTx;
tx.vout[0].nValue = 5000000000LL - 1000 - 50000; // 0 fee
uint256 hashFreeTx = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Fee(0).FromTx(tx));
+ tx_mempool.addUnchecked(entry.Fee(0).FromTx(tx));
size_t freeTxSize = ::GetSerializeSize(tx, PROTOCOL_VERSION);
// Calculate a fee on child transaction that will put the package just
@@ -139,8 +149,8 @@ void MinerTestingSetup::TestPackageSelection(const CChainParams& chainparams, co
tx.vin[0].prevout.hash = hashFreeTx;
tx.vout[0].nValue = 5000000000LL - 1000 - 50000 - feeToUse;
uint256 hashLowFeeTx = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Fee(feeToUse).FromTx(tx));
- pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey);
+ tx_mempool.addUnchecked(entry.Fee(feeToUse).FromTx(tx));
+ pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey);
// Verify that the free tx and the low fee tx didn't get selected
for (size_t i=0; iblock.vtx.size(); ++i) {
BOOST_CHECK(pblocktemplate->block.vtx[i]->GetHash() != hashFreeTx);
@@ -150,11 +160,11 @@ void MinerTestingSetup::TestPackageSelection(const CChainParams& chainparams, co
// Test that packages above the min relay fee do get included, even if one
// of the transactions is below the min relay fee
// Remove the low fee transaction and replace with a higher fee transaction
- m_node.mempool->removeRecursive(CTransaction(tx), MemPoolRemovalReason::REPLACED);
+ tx_mempool.removeRecursive(CTransaction(tx), MemPoolRemovalReason::REPLACED);
tx.vout[0].nValue -= 2; // Now we should be just over the min relay fee
hashLowFeeTx = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Fee(feeToUse+2).FromTx(tx));
- pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey);
+ tx_mempool.addUnchecked(entry.Fee(feeToUse + 2).FromTx(tx));
+ pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey);
BOOST_REQUIRE_EQUAL(pblocktemplate->block.vtx.size(), 6U);
BOOST_CHECK(pblocktemplate->block.vtx[4]->GetHash() == hashFreeTx);
BOOST_CHECK(pblocktemplate->block.vtx[5]->GetHash() == hashLowFeeTx);
@@ -167,7 +177,7 @@ void MinerTestingSetup::TestPackageSelection(const CChainParams& chainparams, co
tx.vout[0].nValue = 5000000000LL - 100000000;
tx.vout[1].nValue = 100000000; // 1BTC output
uint256 hashFreeTx2 = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Fee(0).SpendsCoinbase(true).FromTx(tx));
+ tx_mempool.addUnchecked(entry.Fee(0).SpendsCoinbase(true).FromTx(tx));
// This tx can't be mined by itself
tx.vin[0].prevout.hash = hashFreeTx2;
@@ -175,8 +185,8 @@ void MinerTestingSetup::TestPackageSelection(const CChainParams& chainparams, co
feeToUse = blockMinFeeRate.GetFee(freeTxSize);
tx.vout[0].nValue = 5000000000LL - 100000000 - feeToUse;
uint256 hashLowFeeTx2 = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Fee(feeToUse).SpendsCoinbase(false).FromTx(tx));
- pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey);
+ tx_mempool.addUnchecked(entry.Fee(feeToUse).SpendsCoinbase(false).FromTx(tx));
+ pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey);
// Verify that this tx isn't selected.
for (size_t i=0; iblock.vtx.size(); ++i) {
@@ -188,13 +198,13 @@ void MinerTestingSetup::TestPackageSelection(const CChainParams& chainparams, co
// as well.
tx.vin[0].prevout.n = 1;
tx.vout[0].nValue = 100000000 - 10000; // 10k satoshi fee
- m_node.mempool->addUnchecked(entry.Fee(10000).FromTx(tx));
- pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey);
+ tx_mempool.addUnchecked(entry.Fee(10000).FromTx(tx));
+ pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey);
BOOST_REQUIRE_EQUAL(pblocktemplate->block.vtx.size(), 9U);
BOOST_CHECK(pblocktemplate->block.vtx[8]->GetHash() == hashLowFeeTx2);
}
-void MinerTestingSetup::TestBasicMining(const CChainParams& chainparams, const CScript& scriptPubKey, const std::vector& txFirst, int baseheight)
+void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std::vector& txFirst, int baseheight)
{
uint256 hash;
CMutableTransaction tx;
@@ -202,172 +212,205 @@ void MinerTestingSetup::TestBasicMining(const CChainParams& chainparams, const C
entry.nFee = 11;
entry.nHeight = 11;
- // Just to make sure we can still make simple blocks
- auto pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey);
- BOOST_CHECK(pblocktemplate);
-
- const CAmount BLOCKSUBSIDY = 50*COIN;
+ const CAmount BLOCKSUBSIDY = 50 * COIN;
const CAmount LOWFEE = CENT;
const CAmount HIGHFEE = COIN;
- const CAmount HIGHERFEE = 4*COIN;
+ const CAmount HIGHERFEE = 4 * COIN;
- // block sigops > limit: 1000 CHECKMULTISIG + 1
- tx.vin.resize(1);
- // NOTE: OP_NOP is used to force 20 SigOps for the CHECKMULTISIG
- tx.vin[0].scriptSig = CScript() << OP_0 << OP_0 << OP_0 << OP_NOP << OP_CHECKMULTISIG << OP_1;
- tx.vin[0].prevout.hash = txFirst[0]->GetHash();
- tx.vin[0].prevout.n = 0;
- tx.vout.resize(1);
- tx.vout[0].nValue = BLOCKSUBSIDY;
- for (unsigned int i = 0; i < 1001; ++i)
{
- tx.vout[0].nValue -= LOWFEE;
- hash = tx.GetHash();
- bool spendsCoinbase = i == 0; // only first tx spends coinbase
- // If we don't set the # of sig ops in the CTxMemPoolEntry, template creation fails
- m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx));
- tx.vin[0].prevout.hash = hash;
+ CTxMemPool& tx_mempool{MakeMempool()};
+ LOCK(tx_mempool.cs);
+
+ // Just to make sure we can still make simple blocks
+ auto pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey);
+ BOOST_CHECK(pblocktemplate);
+
+ // block sigops > limit: 1000 CHECKMULTISIG + 1
+ tx.vin.resize(1);
+ // NOTE: OP_NOP is used to force 20 SigOps for the CHECKMULTISIG
+ tx.vin[0].scriptSig = CScript() << OP_0 << OP_0 << OP_0 << OP_NOP << OP_CHECKMULTISIG << OP_1;
+ tx.vin[0].prevout.hash = txFirst[0]->GetHash();
+ tx.vin[0].prevout.n = 0;
+ tx.vout.resize(1);
+ tx.vout[0].nValue = BLOCKSUBSIDY;
+ for (unsigned int i = 0; i < 1001; ++i) {
+ tx.vout[0].nValue -= LOWFEE;
+ hash = tx.GetHash();
+ bool spendsCoinbase = i == 0; // only first tx spends coinbase
+ // If we don't set the # of sig ops in the CTxMemPoolEntry, template creation fails
+ tx_mempool.addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx));
+ tx.vin[0].prevout.hash = hash;
+ }
+
+ BOOST_CHECK_EXCEPTION(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-blk-sigops"));
}
- BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-blk-sigops"));
- m_node.mempool->clear();
+ {
+ CTxMemPool& tx_mempool{MakeMempool()};
+ LOCK(tx_mempool.cs);
+
+ tx.vin[0].prevout.hash = txFirst[0]->GetHash();
+ tx.vout[0].nValue = BLOCKSUBSIDY;
+ for (unsigned int i = 0; i < 1001; ++i) {
+ tx.vout[0].nValue -= LOWFEE;
+ hash = tx.GetHash();
+ bool spendsCoinbase = i == 0; // only first tx spends coinbase
+ // If we do set the # of sig ops in the CTxMemPoolEntry, template creation passes
+ tx_mempool.addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).SigOpsCost(80).FromTx(tx));
+ tx.vin[0].prevout.hash = hash;
+ }
+ BOOST_CHECK(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey));
+ }
- tx.vin[0].prevout.hash = txFirst[0]->GetHash();
- tx.vout[0].nValue = BLOCKSUBSIDY;
- for (unsigned int i = 0; i < 1001; ++i)
{
- tx.vout[0].nValue -= LOWFEE;
- hash = tx.GetHash();
- bool spendsCoinbase = i == 0; // only first tx spends coinbase
- // If we do set the # of sig ops in the CTxMemPoolEntry, template creation passes
- m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).SigOpsCost(80).FromTx(tx));
- tx.vin[0].prevout.hash = hash;
+ CTxMemPool& tx_mempool{MakeMempool()};
+ LOCK(tx_mempool.cs);
+
+ // block size > limit
+ tx.vin[0].scriptSig = CScript();
+ // 18 * (520char + DROP) + OP_1 = 9433 bytes
+ std::vector vchData(520);
+ for (unsigned int i = 0; i < 18; ++i) {
+ tx.vin[0].scriptSig << vchData << OP_DROP;
+ }
+ tx.vin[0].scriptSig << OP_1;
+ tx.vin[0].prevout.hash = txFirst[0]->GetHash();
+ tx.vout[0].nValue = BLOCKSUBSIDY;
+ for (unsigned int i = 0; i < 128; ++i) {
+ tx.vout[0].nValue -= LOWFEE;
+ hash = tx.GetHash();
+ bool spendsCoinbase = i == 0; // only first tx spends coinbase
+ tx_mempool.addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx));
+ tx.vin[0].prevout.hash = hash;
+ }
+ BOOST_CHECK(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey));
}
- BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
- m_node.mempool->clear();
-
- // block size > limit
- tx.vin[0].scriptSig = CScript();
- // 18 * (520char + DROP) + OP_1 = 9433 bytes
- std::vector vchData(520);
- for (unsigned int i = 0; i < 18; ++i)
- tx.vin[0].scriptSig << vchData << OP_DROP;
- tx.vin[0].scriptSig << OP_1;
- tx.vin[0].prevout.hash = txFirst[0]->GetHash();
- tx.vout[0].nValue = BLOCKSUBSIDY;
- for (unsigned int i = 0; i < 128; ++i)
+
{
- tx.vout[0].nValue -= LOWFEE;
+ CTxMemPool& tx_mempool{MakeMempool()};
+ LOCK(tx_mempool.cs);
+
+ // orphan in tx_mempool, template creation fails
hash = tx.GetHash();
- bool spendsCoinbase = i == 0; // only first tx spends coinbase
- m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx));
- tx.vin[0].prevout.hash = hash;
+ tx_mempool.addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).FromTx(tx));
+ BOOST_CHECK_EXCEPTION(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-txns-inputs-missingorspent"));
}
- BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
- m_node.mempool->clear();
-
- // orphan in *m_node.mempool, template creation fails
- hash = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).FromTx(tx));
- BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-txns-inputs-missingorspent"));
- m_node.mempool->clear();
- // child with higher feerate than parent
- tx.vin[0].scriptSig = CScript() << OP_1;
- tx.vin[0].prevout.hash = txFirst[1]->GetHash();
- tx.vout[0].nValue = BLOCKSUBSIDY-HIGHFEE;
- hash = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
- tx.vin[0].prevout.hash = hash;
- tx.vin.resize(2);
- tx.vin[1].scriptSig = CScript() << OP_1;
- tx.vin[1].prevout.hash = txFirst[0]->GetHash();
- tx.vin[1].prevout.n = 0;
- tx.vout[0].nValue = tx.vout[0].nValue+BLOCKSUBSIDY-HIGHERFEE; //First txn output + fresh coinbase - new txn fee
- hash = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Fee(HIGHERFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
- BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
- m_node.mempool->clear();
+ {
+ CTxMemPool& tx_mempool{MakeMempool()};
+ LOCK(tx_mempool.cs);
- // coinbase in *m_node.mempool, template creation fails
- tx.vin.resize(1);
- tx.vin[0].prevout.SetNull();
- tx.vin[0].scriptSig = CScript() << OP_0 << OP_1;
- tx.vout[0].nValue = 0;
- hash = tx.GetHash();
- // give it a fee so it'll get mined
- m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
- // Should throw bad-cb-multiple
- BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-cb-multiple"));
- m_node.mempool->clear();
+ // child with higher feerate than parent
+ tx.vin[0].scriptSig = CScript() << OP_1;
+ tx.vin[0].prevout.hash = txFirst[1]->GetHash();
+ tx.vout[0].nValue = BLOCKSUBSIDY - HIGHFEE;
+ hash = tx.GetHash();
+ tx_mempool.addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
+ tx.vin[0].prevout.hash = hash;
+ tx.vin.resize(2);
+ tx.vin[1].scriptSig = CScript() << OP_1;
+ tx.vin[1].prevout.hash = txFirst[0]->GetHash();
+ tx.vin[1].prevout.n = 0;
+ tx.vout[0].nValue = tx.vout[0].nValue + BLOCKSUBSIDY - HIGHERFEE; // First txn output + fresh coinbase - new txn fee
+ hash = tx.GetHash();
+ tx_mempool.addUnchecked(entry.Fee(HIGHERFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
+ BOOST_CHECK(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey));
+ }
- // double spend txn pair in *m_node.mempool, template creation fails
- tx.vin[0].prevout.hash = txFirst[0]->GetHash();
- tx.vin[0].scriptSig = CScript() << OP_1;
- tx.vout[0].nValue = BLOCKSUBSIDY-HIGHFEE;
- tx.vout[0].scriptPubKey = CScript() << OP_1;
- hash = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
- tx.vout[0].scriptPubKey = CScript() << OP_2;
- hash = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
- BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-txns-inputs-missingorspent"));
- m_node.mempool->clear();
-
- // subsidy changing
- int nHeight = m_node.chainman->ActiveChain().Height();
- // Create an actual 209999-long block chain (without valid blocks).
- while (m_node.chainman->ActiveChain().Tip()->nHeight < 209999) {
- CBlockIndex* prev = m_node.chainman->ActiveChain().Tip();
- CBlockIndex* next = new CBlockIndex();
- next->phashBlock = new uint256(InsecureRand256());
- m_node.chainman->ActiveChainstate().CoinsTip().SetBestBlock(next->GetBlockHash());
- next->pprev = prev;
- next->nHeight = prev->nHeight + 1;
- next->BuildSkip();
- m_node.chainman->ActiveChain().SetTip(*next);
+ {
+ CTxMemPool& tx_mempool{MakeMempool()};
+ LOCK(tx_mempool.cs);
+
+ // coinbase in tx_mempool, template creation fails
+ tx.vin.resize(1);
+ tx.vin[0].prevout.SetNull();
+ tx.vin[0].scriptSig = CScript() << OP_0 << OP_1;
+ tx.vout[0].nValue = 0;
+ hash = tx.GetHash();
+ // give it a fee so it'll get mined
+ tx_mempool.addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
+ // Should throw bad-cb-multiple
+ BOOST_CHECK_EXCEPTION(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-cb-multiple"));
}
- BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
- // Extend to a 210000-long block chain.
- while (m_node.chainman->ActiveChain().Tip()->nHeight < 210000) {
- CBlockIndex* prev = m_node.chainman->ActiveChain().Tip();
- CBlockIndex* next = new CBlockIndex();
- next->phashBlock = new uint256(InsecureRand256());
- m_node.chainman->ActiveChainstate().CoinsTip().SetBestBlock(next->GetBlockHash());
- next->pprev = prev;
- next->nHeight = prev->nHeight + 1;
- next->BuildSkip();
- m_node.chainman->ActiveChain().SetTip(*next);
+
+ {
+ CTxMemPool& tx_mempool{MakeMempool()};
+ LOCK(tx_mempool.cs);
+
+ // double spend txn pair in tx_mempool, template creation fails
+ tx.vin[0].prevout.hash = txFirst[0]->GetHash();
+ tx.vin[0].scriptSig = CScript() << OP_1;
+ tx.vout[0].nValue = BLOCKSUBSIDY - HIGHFEE;
+ tx.vout[0].scriptPubKey = CScript() << OP_1;
+ hash = tx.GetHash();
+ tx_mempool.addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
+ tx.vout[0].scriptPubKey = CScript() << OP_2;
+ hash = tx.GetHash();
+ tx_mempool.addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
+ BOOST_CHECK_EXCEPTION(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-txns-inputs-missingorspent"));
}
- BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
- // invalid p2sh txn in *m_node.mempool, template creation fails
- tx.vin[0].prevout.hash = txFirst[0]->GetHash();
- tx.vin[0].prevout.n = 0;
- tx.vin[0].scriptSig = CScript() << OP_1;
- tx.vout[0].nValue = BLOCKSUBSIDY-LOWFEE;
- CScript script = CScript() << OP_0;
- tx.vout[0].scriptPubKey = GetScriptForDestination(ScriptHash(script));
- hash = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
- tx.vin[0].prevout.hash = hash;
- tx.vin[0].scriptSig = CScript() << std::vector(script.begin(), script.end());
- tx.vout[0].nValue -= LOWFEE;
- hash = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
- // Should throw block-validation-failed
- BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("block-validation-failed"));
- m_node.mempool->clear();
-
- // Delete the dummy blocks again.
- while (m_node.chainman->ActiveChain().Tip()->nHeight > nHeight) {
- CBlockIndex* del = m_node.chainman->ActiveChain().Tip();
- m_node.chainman->ActiveChain().SetTip(*Assert(del->pprev));
- m_node.chainman->ActiveChainstate().CoinsTip().SetBestBlock(del->pprev->GetBlockHash());
- delete del->phashBlock;
- delete del;
+ {
+ CTxMemPool& tx_mempool{MakeMempool()};
+ LOCK(tx_mempool.cs);
+
+ // subsidy changing
+ int nHeight = m_node.chainman->ActiveChain().Height();
+ // Create an actual 209999-long block chain (without valid blocks).
+ while (m_node.chainman->ActiveChain().Tip()->nHeight < 209999) {
+ CBlockIndex* prev = m_node.chainman->ActiveChain().Tip();
+ CBlockIndex* next = new CBlockIndex();
+ next->phashBlock = new uint256(InsecureRand256());
+ m_node.chainman->ActiveChainstate().CoinsTip().SetBestBlock(next->GetBlockHash());
+ next->pprev = prev;
+ next->nHeight = prev->nHeight + 1;
+ next->BuildSkip();
+ m_node.chainman->ActiveChain().SetTip(*next);
+ }
+ BOOST_CHECK(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey));
+ // Extend to a 210000-long block chain.
+ while (m_node.chainman->ActiveChain().Tip()->nHeight < 210000) {
+ CBlockIndex* prev = m_node.chainman->ActiveChain().Tip();
+ CBlockIndex* next = new CBlockIndex();
+ next->phashBlock = new uint256(InsecureRand256());
+ m_node.chainman->ActiveChainstate().CoinsTip().SetBestBlock(next->GetBlockHash());
+ next->pprev = prev;
+ next->nHeight = prev->nHeight + 1;
+ next->BuildSkip();
+ m_node.chainman->ActiveChain().SetTip(*next);
+ }
+ BOOST_CHECK(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey));
+
+ // invalid p2sh txn in tx_mempool, template creation fails
+ tx.vin[0].prevout.hash = txFirst[0]->GetHash();
+ tx.vin[0].prevout.n = 0;
+ tx.vin[0].scriptSig = CScript() << OP_1;
+ tx.vout[0].nValue = BLOCKSUBSIDY - LOWFEE;
+ CScript script = CScript() << OP_0;
+ tx.vout[0].scriptPubKey = GetScriptForDestination(ScriptHash(script));
+ hash = tx.GetHash();
+ tx_mempool.addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
+ tx.vin[0].prevout.hash = hash;
+ tx.vin[0].scriptSig = CScript() << std::vector(script.begin(), script.end());
+ tx.vout[0].nValue -= LOWFEE;
+ hash = tx.GetHash();
+ tx_mempool.addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
+ // Should throw block-validation-failed
+ BOOST_CHECK_EXCEPTION(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("block-validation-failed"));
+
+ // Delete the dummy blocks again.
+ while (m_node.chainman->ActiveChain().Tip()->nHeight > nHeight) {
+ CBlockIndex* del = m_node.chainman->ActiveChain().Tip();
+ m_node.chainman->ActiveChain().SetTip(*Assert(del->pprev));
+ m_node.chainman->ActiveChainstate().CoinsTip().SetBestBlock(del->pprev->GetBlockHash());
+ delete del->phashBlock;
+ delete del;
+ }
}
+ CTxMemPool& tx_mempool{MakeMempool()};
+ LOCK(tx_mempool.cs);
+
// non-final txs in mempool
SetMockTime(m_node.chainman->ActiveChain().Tip()->GetMedianTimePast() + 1);
const int flags{LOCKTIME_VERIFY_SEQUENCE};
@@ -388,9 +431,9 @@ void MinerTestingSetup::TestBasicMining(const CChainParams& chainparams, const C
tx.vout[0].scriptPubKey = CScript() << OP_1;
tx.nLockTime = 0;
hash = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
+ tx_mempool.addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
BOOST_CHECK(CheckFinalTxAtTip(*Assert(m_node.chainman->ActiveChain().Tip()), CTransaction{tx})); // Locktime passes
- BOOST_CHECK(!TestSequenceLocks(CTransaction{tx})); // Sequence locks fail
+ BOOST_CHECK(!TestSequenceLocks(CTransaction{tx}, tx_mempool)); // Sequence locks fail
{
CBlockIndex* active_chain_tip = m_node.chainman->ActiveChain().Tip();
@@ -402,9 +445,9 @@ void MinerTestingSetup::TestBasicMining(const CChainParams& chainparams, const C
tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | (((m_node.chainman->ActiveChain().Tip()->GetMedianTimePast()+1-m_node.chainman->ActiveChain()[1]->GetMedianTimePast()) >> CTxIn::SEQUENCE_LOCKTIME_GRANULARITY) + 1); // txFirst[1] is the 3rd block
prevheights[0] = baseheight + 2;
hash = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Time(GetTime()).FromTx(tx));
+ tx_mempool.addUnchecked(entry.Time(GetTime()).FromTx(tx));
BOOST_CHECK(CheckFinalTxAtTip(*Assert(m_node.chainman->ActiveChain().Tip()), CTransaction{tx})); // Locktime passes
- BOOST_CHECK(!TestSequenceLocks(CTransaction{tx})); // Sequence locks fail
+ BOOST_CHECK(!TestSequenceLocks(CTransaction{tx}, tx_mempool)); // Sequence locks fail
const int SEQUENCE_LOCK_TIME = 512; // Sequence locks pass 512 seconds later
for (int i = 0; i < CBlockIndex::nMedianTimeSpan; ++i)
@@ -425,9 +468,9 @@ void MinerTestingSetup::TestBasicMining(const CChainParams& chainparams, const C
prevheights[0] = baseheight + 3;
tx.nLockTime = m_node.chainman->ActiveChain().Tip()->nHeight + 1;
hash = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Time(GetTime()).FromTx(tx));
+ tx_mempool.addUnchecked(entry.Time(GetTime()).FromTx(tx));
BOOST_CHECK(!CheckFinalTxAtTip(*Assert(m_node.chainman->ActiveChain().Tip()), CTransaction{tx})); // Locktime fails
- BOOST_CHECK(TestSequenceLocks(CTransaction{tx})); // Sequence locks pass
+ BOOST_CHECK(TestSequenceLocks(CTransaction{tx}, tx_mempool)); // Sequence locks pass
BOOST_CHECK(IsFinalTx(CTransaction(tx), m_node.chainman->ActiveChain().Tip()->nHeight + 2, m_node.chainman->ActiveChain().Tip()->GetMedianTimePast())); // Locktime passes on 2nd block
// absolute time locked
@@ -436,9 +479,9 @@ void MinerTestingSetup::TestBasicMining(const CChainParams& chainparams, const C
prevheights.resize(1);
prevheights[0] = baseheight + 4;
hash = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Time(GetTime()).FromTx(tx));
+ tx_mempool.addUnchecked(entry.Time(GetTime()).FromTx(tx));
BOOST_CHECK(!CheckFinalTxAtTip(*Assert(m_node.chainman->ActiveChain().Tip()), CTransaction{tx})); // Locktime fails
- BOOST_CHECK(TestSequenceLocks(CTransaction{tx})); // Sequence locks pass
+ BOOST_CHECK(TestSequenceLocks(CTransaction{tx}, tx_mempool)); // Sequence locks pass
BOOST_CHECK(IsFinalTx(CTransaction(tx), m_node.chainman->ActiveChain().Tip()->nHeight + 2, m_node.chainman->ActiveChain().Tip()->GetMedianTimePast() + 1)); // Locktime passes 1 second later
// mempool-dependent transactions (not added)
@@ -447,15 +490,16 @@ void MinerTestingSetup::TestBasicMining(const CChainParams& chainparams, const C
tx.nLockTime = 0;
tx.vin[0].nSequence = 0;
BOOST_CHECK(CheckFinalTxAtTip(*Assert(m_node.chainman->ActiveChain().Tip()), CTransaction{tx})); // Locktime passes
- BOOST_CHECK(TestSequenceLocks(CTransaction{tx})); // Sequence locks pass
+ BOOST_CHECK(TestSequenceLocks(CTransaction{tx}, tx_mempool)); // Sequence locks pass
tx.vin[0].nSequence = 1;
- BOOST_CHECK(!TestSequenceLocks(CTransaction{tx})); // Sequence locks fail
+ BOOST_CHECK(!TestSequenceLocks(CTransaction{tx}, tx_mempool)); // Sequence locks fail
tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG;
- BOOST_CHECK(TestSequenceLocks(CTransaction{tx})); // Sequence locks pass
+ BOOST_CHECK(TestSequenceLocks(CTransaction{tx}, tx_mempool)); // Sequence locks pass
tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | 1;
- BOOST_CHECK(!TestSequenceLocks(CTransaction{tx})); // Sequence locks fail
+ BOOST_CHECK(!TestSequenceLocks(CTransaction{tx}, tx_mempool)); // Sequence locks fail
- BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
+ auto pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey);
+ BOOST_CHECK(pblocktemplate);
// None of the of the absolute height/time locked tx should have made
// it into the template because we still check IsFinalTx in CreateNewBlock,
@@ -470,12 +514,15 @@ void MinerTestingSetup::TestBasicMining(const CChainParams& chainparams, const C
m_node.chainman->ActiveChain().Tip()->nHeight++;
SetMockTime(m_node.chainman->ActiveChain().Tip()->GetMedianTimePast() + 1);
- BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
+ BOOST_CHECK(pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey));
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 5U);
}
-void MinerTestingSetup::TestPrioritisedMining(const CChainParams& chainparams, const CScript& scriptPubKey, const std::vector& txFirst)
+void MinerTestingSetup::TestPrioritisedMining(const CScript& scriptPubKey, const std::vector& txFirst)
{
+ CTxMemPool& tx_mempool{MakeMempool()};
+ LOCK(tx_mempool.cs);
+
TestMemPoolEntryHelper entry;
// Test that a tx below min fee but prioritised is included
@@ -487,29 +534,29 @@ void MinerTestingSetup::TestPrioritisedMining(const CChainParams& chainparams, c
tx.vout.resize(1);
tx.vout[0].nValue = 5000000000LL; // 0 fee
uint256 hashFreePrioritisedTx = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Fee(0).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
- m_node.mempool->PrioritiseTransaction(hashFreePrioritisedTx, 5 * COIN);
+ tx_mempool.addUnchecked(entry.Fee(0).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
+ tx_mempool.PrioritiseTransaction(hashFreePrioritisedTx, 5 * COIN);
tx.vin[0].prevout.hash = txFirst[1]->GetHash();
tx.vin[0].prevout.n = 0;
tx.vout[0].nValue = 5000000000LL - 1000;
// This tx has a low fee: 1000 satoshis
uint256 hashParentTx = tx.GetHash(); // save this txid for later use
- m_node.mempool->addUnchecked(entry.Fee(1000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
+ tx_mempool.addUnchecked(entry.Fee(1000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
// This tx has a medium fee: 10000 satoshis
tx.vin[0].prevout.hash = txFirst[2]->GetHash();
tx.vout[0].nValue = 5000000000LL - 10000;
uint256 hashMediumFeeTx = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Fee(10000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
- m_node.mempool->PrioritiseTransaction(hashMediumFeeTx, -5 * COIN);
+ tx_mempool.addUnchecked(entry.Fee(10000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
+ tx_mempool.PrioritiseTransaction(hashMediumFeeTx, -5 * COIN);
// This tx also has a low fee, but is prioritised
tx.vin[0].prevout.hash = hashParentTx;
tx.vout[0].nValue = 5000000000LL - 1000 - 1000; // 1000 satoshi fee
uint256 hashPrioritsedChild = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Fee(1000).Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
- m_node.mempool->PrioritiseTransaction(hashPrioritsedChild, 2 * COIN);
+ tx_mempool.addUnchecked(entry.Fee(1000).Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
+ tx_mempool.PrioritiseTransaction(hashPrioritsedChild, 2 * COIN);
// Test that transaction selection properly updates ancestor fee calculations as prioritised
// parents get included in a block. Create a transaction with two prioritised ancestors, each
@@ -520,21 +567,21 @@ void MinerTestingSetup::TestPrioritisedMining(const CChainParams& chainparams, c
tx.vin[0].prevout.hash = txFirst[3]->GetHash();
tx.vout[0].nValue = 5000000000LL; // 0 fee
uint256 hashFreeParent = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Fee(0).SpendsCoinbase(true).FromTx(tx));
- m_node.mempool->PrioritiseTransaction(hashFreeParent, 10 * COIN);
+ tx_mempool.addUnchecked(entry.Fee(0).SpendsCoinbase(true).FromTx(tx));
+ tx_mempool.PrioritiseTransaction(hashFreeParent, 10 * COIN);
tx.vin[0].prevout.hash = hashFreeParent;
tx.vout[0].nValue = 5000000000LL; // 0 fee
uint256 hashFreeChild = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Fee(0).SpendsCoinbase(false).FromTx(tx));
- m_node.mempool->PrioritiseTransaction(hashFreeChild, 1 * COIN);
+ tx_mempool.addUnchecked(entry.Fee(0).SpendsCoinbase(false).FromTx(tx));
+ tx_mempool.PrioritiseTransaction(hashFreeChild, 1 * COIN);
tx.vin[0].prevout.hash = hashFreeChild;
tx.vout[0].nValue = 5000000000LL; // 0 fee
uint256 hashFreeGrandchild = tx.GetHash();
- m_node.mempool->addUnchecked(entry.Fee(0).SpendsCoinbase(false).FromTx(tx));
+ tx_mempool.addUnchecked(entry.Fee(0).SpendsCoinbase(false).FromTx(tx));
- auto pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey);
+ auto pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey);
BOOST_REQUIRE_EQUAL(pblocktemplate->block.vtx.size(), 6U);
BOOST_CHECK(pblocktemplate->block.vtx[1]->GetHash() == hashFreeParent);
BOOST_CHECK(pblocktemplate->block.vtx[2]->GetHash() == hashFreePrioritisedTx);
@@ -553,15 +600,12 @@ void MinerTestingSetup::TestPrioritisedMining(const CChainParams& chainparams, c
BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
{
// Note that by default, these tests run with size accounting enabled.
- const auto chainParams = CreateChainParams(*m_node.args, CBaseChainParams::MAIN);
- const CChainParams& chainparams = *chainParams;
CScript scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG;
std::unique_ptr pblocktemplate;
- fCheckpointsEnabled = false;
-
+ CTxMemPool& tx_mempool{*m_node.mempool};
// Simple block creation, nothing special yet:
- BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
+ BOOST_CHECK(pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey));
// We can't make transactions until we have inputs
// Therefore, load 110 blocks :)
@@ -593,23 +637,18 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
}
LOCK(cs_main);
- LOCK(m_node.mempool->cs);
- TestBasicMining(chainparams, scriptPubKey, txFirst, baseheight);
+ TestBasicMining(scriptPubKey, txFirst, baseheight);
m_node.chainman->ActiveChain().Tip()->nHeight--;
SetMockTime(0);
- m_node.mempool->clear();
- TestPackageSelection(chainparams, scriptPubKey, txFirst);
+ TestPackageSelection(scriptPubKey, txFirst);
m_node.chainman->ActiveChain().Tip()->nHeight--;
SetMockTime(0);
- m_node.mempool->clear();
-
- TestPrioritisedMining(chainparams, scriptPubKey, txFirst);
- fCheckpointsEnabled = true;
+ TestPrioritisedMining(scriptPubKey, txFirst);
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/minisketch_tests.cpp b/src/test/minisketch_tests.cpp
index 9c53ace633f2..81f2aad62309 100644
--- a/src/test/minisketch_tests.cpp
+++ b/src/test/minisketch_tests.cpp
@@ -40,7 +40,7 @@ BOOST_AUTO_TEST_CASE(minisketch_test)
Minisketch sketch_c = std::move(sketch_ar);
sketch_c.Merge(sketch_br);
auto dec = sketch_c.Decode(errors);
- BOOST_CHECK(dec.has_value());
+ BOOST_REQUIRE(dec.has_value());
auto sols = std::move(*dec);
std::sort(sols.begin(), sols.end());
for (uint32_t i = 0; i < a_not_b; ++i) BOOST_CHECK_EQUAL(sols[i], start_a + i);
diff --git a/src/test/system_tests.cpp b/src/test/system_tests.cpp
index f160bb08a559..11f4be7fef60 100644
--- a/src/test/system_tests.cpp
+++ b/src/test/system_tests.cpp
@@ -3,7 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
#include
-#include
+#include
#include
#ifdef ENABLE_EXTERNAL_SIGNER
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index 25dea1e3ea50..bb69102d8610 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -282,14 +282,10 @@ BOOST_AUTO_TEST_CASE(util_TrimString)
BOOST_CHECK_EQUAL(TrimStringView(std::string("\x05\x04\x03\x02\x01\x00", 6), std::string("\x05\x04\x03\x02\x01\x00", 6)), "");
}
-BOOST_AUTO_TEST_CASE(util_FormatParseISO8601DateTime)
+BOOST_AUTO_TEST_CASE(util_FormatISO8601DateTime)
{
BOOST_CHECK_EQUAL(FormatISO8601DateTime(1317425777), "2011-09-30T23:36:17Z");
BOOST_CHECK_EQUAL(FormatISO8601DateTime(0), "1970-01-01T00:00:00Z");
-
- BOOST_CHECK_EQUAL(ParseISO8601DateTime("1970-01-01T00:00:00Z"), 0);
- BOOST_CHECK_EQUAL(ParseISO8601DateTime("1960-01-01T00:00:00Z"), 0);
- BOOST_CHECK_EQUAL(ParseISO8601DateTime("2011-09-30T23:36:17Z"), 1317425777);
}
BOOST_AUTO_TEST_CASE(util_FormatISO8601Date)
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index e1288b734611..84ed2e9ef528 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -145,7 +145,7 @@ void CTxMemPool::UpdateTransactionsFromBlock(const std::vector& vHashes
// Iterate in reverse, so that whenever we are looking at a transaction
// we are sure that all in-mempool descendants have already been processed.
// This maximizes the benefit of the descendant cache and guarantees that
- // CTxMemPool::m_children will be updated, an assumption made in
+ // CTxMemPoolEntry::m_children will be updated, an assumption made in
// UpdateForDescendants.
for (const uint256 &hash : reverse_iterate(vHashesToUpdate)) {
// calculate children from mapNextTx
@@ -154,7 +154,7 @@ void CTxMemPool::UpdateTransactionsFromBlock(const std::vector& vHashes
continue;
}
auto iter = mapNextTx.lower_bound(COutPoint(hash, 0));
- // First calculate the children, and update CTxMemPool::m_children to
+ // First calculate the children, and update CTxMemPoolEntry::m_children to
// include them, and update their CTxMemPoolEntry::m_parents to include this tx.
// we cache the in-mempool children to avoid duplicate updates
{
@@ -187,10 +187,7 @@ bool CTxMemPool::CalculateAncestorsAndCheckLimits(size_t entry_size,
size_t entry_count,
setEntries& setAncestors,
CTxMemPoolEntry::Parents& staged_ancestors,
- uint64_t limitAncestorCount,
- uint64_t limitAncestorSize,
- uint64_t limitDescendantCount,
- uint64_t limitDescendantSize,
+ const Limits& limits,
std::string &errString) const
{
size_t totalSizeWithAncestors = entry_size;
@@ -203,14 +200,14 @@ bool CTxMemPool::CalculateAncestorsAndCheckLimits(size_t entry_size,
staged_ancestors.erase(stage);
totalSizeWithAncestors += stageit->GetTxSize();
- if (stageit->GetSizeWithDescendants() + entry_size > limitDescendantSize) {
- errString = strprintf("exceeds descendant size limit for tx %s [limit: %u]", stageit->GetTx().GetHash().ToString(), limitDescendantSize);
+ if (stageit->GetSizeWithDescendants() + entry_size > static_cast(limits.descendant_size_vbytes)) {
+ errString = strprintf("exceeds descendant size limit for tx %s [limit: %u]", stageit->GetTx().GetHash().ToString(), limits.descendant_size_vbytes);
return false;
- } else if (stageit->GetCountWithDescendants() + entry_count > limitDescendantCount) {
- errString = strprintf("too many descendants for tx %s [limit: %u]", stageit->GetTx().GetHash().ToString(), limitDescendantCount);
+ } else if (stageit->GetCountWithDescendants() + entry_count > static_cast(limits.descendant_count)) {
+ errString = strprintf("too many descendants for tx %s [limit: %u]", stageit->GetTx().GetHash().ToString(), limits.descendant_count);
return false;
- } else if (totalSizeWithAncestors > limitAncestorSize) {
- errString = strprintf("exceeds ancestor size limit [limit: %u]", limitAncestorSize);
+ } else if (totalSizeWithAncestors > static_cast(limits.ancestor_size_vbytes)) {
+ errString = strprintf("exceeds ancestor size limit [limit: %u]", limits.ancestor_size_vbytes);
return false;
}
@@ -222,8 +219,8 @@ bool CTxMemPool::CalculateAncestorsAndCheckLimits(size_t entry_size,
if (setAncestors.count(parent_it) == 0) {
staged_ancestors.insert(parent);
}
- if (staged_ancestors.size() + setAncestors.size() + entry_count > limitAncestorCount) {
- errString = strprintf("too many unconfirmed ancestors [limit: %u]", limitAncestorCount);
+ if (staged_ancestors.size() + setAncestors.size() + entry_count > static_cast(limits.ancestor_count)) {
+ errString = strprintf("too many unconfirmed ancestors [limit: %u]", limits.ancestor_count);
return false;
}
}
@@ -233,10 +230,7 @@ bool CTxMemPool::CalculateAncestorsAndCheckLimits(size_t entry_size,
}
bool CTxMemPool::CheckPackageLimits(const Package& package,
- uint64_t limitAncestorCount,
- uint64_t limitAncestorSize,
- uint64_t limitDescendantCount,
- uint64_t limitDescendantSize,
+ const Limits& limits,
std::string &errString) const
{
CTxMemPoolEntry::Parents staged_ancestors;
@@ -247,8 +241,8 @@ bool CTxMemPool::CheckPackageLimits(const Package& package,
std::optional piter = GetIter(input.prevout.hash);
if (piter) {
staged_ancestors.insert(**piter);
- if (staged_ancestors.size() + package.size() > limitAncestorCount) {
- errString = strprintf("too many unconfirmed parents [limit: %u]", limitAncestorCount);
+ if (staged_ancestors.size() + package.size() > static_cast(limits.ancestor_count)) {
+ errString = strprintf("too many unconfirmed parents [limit: %u]", limits.ancestor_count);
return false;
}
}
@@ -260,8 +254,7 @@ bool CTxMemPool::CheckPackageLimits(const Package& package,
setEntries setAncestors;
const auto ret = CalculateAncestorsAndCheckLimits(total_size, package.size(),
setAncestors, staged_ancestors,
- limitAncestorCount, limitAncestorSize,
- limitDescendantCount, limitDescendantSize, errString);
+ limits, errString);
// It's possible to overestimate the ancestor/descendant totals.
if (!ret) errString.insert(0, "possibly ");
return ret;
@@ -269,10 +262,7 @@ bool CTxMemPool::CheckPackageLimits(const Package& package,
bool CTxMemPool::CalculateMemPoolAncestors(const CTxMemPoolEntry &entry,
setEntries &setAncestors,
- uint64_t limitAncestorCount,
- uint64_t limitAncestorSize,
- uint64_t limitDescendantCount,
- uint64_t limitDescendantSize,
+ const Limits& limits,
std::string &errString,
bool fSearchForParents /* = true */) const
{
@@ -287,8 +277,8 @@ bool CTxMemPool::CalculateMemPoolAncestors(const CTxMemPoolEntry &entry,
std::optional piter = GetIter(tx.vin[i].prevout.hash);
if (piter) {
staged_ancestors.insert(**piter);
- if (staged_ancestors.size() + 1 > limitAncestorCount) {
- errString = strprintf("too many unconfirmed parents [limit: %u]", limitAncestorCount);
+ if (staged_ancestors.size() + 1 > static_cast(limits.ancestor_count)) {
+ errString = strprintf("too many unconfirmed parents [limit: %u]", limits.ancestor_count);
return false;
}
}
@@ -302,8 +292,7 @@ bool CTxMemPool::CalculateMemPoolAncestors(const CTxMemPoolEntry &entry,
return CalculateAncestorsAndCheckLimits(entry.GetTxSize(), /*entry_count=*/1,
setAncestors, staged_ancestors,
- limitAncestorCount, limitAncestorSize,
- limitDescendantCount, limitDescendantSize, errString);
+ limits, errString);
}
void CTxMemPool::UpdateAncestorsOf(bool add, txiter it, setEntries &setAncestors)
@@ -347,7 +336,6 @@ void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove, b
{
// For each entry, walk back all ancestors and decrement size associated with this
// transaction
- const uint64_t nNoLimit = std::numeric_limits::max();
if (updateDescendants) {
// updateDescendants should be true whenever we're not recursively
// removing a tx and all its descendants, eg when a transaction is
@@ -390,7 +378,7 @@ void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove, b
// mempool parents we'd calculate by searching, and it's important that
// we use the cached notion of ancestor transactions as the set of
// things to update for removal.
- CalculateMemPoolAncestors(entry, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy, false);
+ CalculateMemPoolAncestors(entry, setAncestors, Limits::NoLimits(), dummy, false);
// Note that UpdateAncestorsOf severs the child links that point to
// removeIt in the entries for the parents of removeIt.
UpdateAncestorsOf(false, removeIt, setAncestors);
@@ -744,9 +732,8 @@ void CTxMemPool::check(const CCoinsViewCache& active_coins_tip, int64_t spendhei
assert(std::equal(setParentCheck.begin(), setParentCheck.end(), it->GetMemPoolParentsConst().begin(), comp));
// Verify ancestor state is correct.
setEntries setAncestors;
- uint64_t nNoLimit = std::numeric_limits::max();
std::string dummy;
- CalculateMemPoolAncestors(*it, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy);
+ CalculateMemPoolAncestors(*it, setAncestors, Limits::NoLimits(), dummy);
uint64_t nCountCheck = setAncestors.size() + 1;
uint64_t nSizeCheck = it->GetTxSize();
CAmount nFeesCheck = it->GetModifiedFee();
@@ -908,9 +895,8 @@ void CTxMemPool::PrioritiseTransaction(const uint256& hash, const CAmount& nFeeD
mapTx.modify(it, [&nFeeDelta](CTxMemPoolEntry& e) { e.UpdateModifiedFee(nFeeDelta); });
// Now update all ancestors' modified fees with descendants
setEntries setAncestors;
- uint64_t nNoLimit = std::numeric_limits::max();
std::string dummy;
- CalculateMemPoolAncestors(*it, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy, false);
+ CalculateMemPoolAncestors(*it, setAncestors, Limits::NoLimits(), dummy, false);
for (txiter ancestorIt : setAncestors) {
mapTx.modify(ancestorIt, [=](CTxMemPoolEntry& e){ e.UpdateDescendantState(0, nFeeDelta, 0);});
}
@@ -1049,9 +1035,8 @@ int CTxMemPool::Expire(std::chrono::seconds time)
void CTxMemPool::addUnchecked(const CTxMemPoolEntry &entry, bool validFeeEstimate)
{
setEntries setAncestors;
- uint64_t nNoLimit = std::numeric_limits::max();
std::string dummy;
- CalculateMemPoolAncestors(entry, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy);
+ CalculateMemPoolAncestors(entry, setAncestors, Limits::NoLimits(), dummy);
return addUnchecked(entry, setAncestors, validFeeEstimate);
}
diff --git a/src/txmempool.h b/src/txmempool.h
index cd15d069b1d2..4afaac050697 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -526,6 +526,8 @@ class CTxMemPool
typedef std::set setEntries;
+ using Limits = kernel::MemPoolLimits;
+
uint64_t CalculateDescendantMaximum(txiter entry) const EXCLUSIVE_LOCKS_REQUIRED(cs);
private:
typedef std::map cacheMap;
@@ -545,19 +547,22 @@ class CTxMemPool
/**
* Helper function to calculate all in-mempool ancestors of staged_ancestors and apply ancestor
* and descendant limits (including staged_ancestors thsemselves, entry_size and entry_count).
- * param@[in] entry_size Virtual size to include in the limits.
- * param@[in] entry_count How many entries to include in the limits.
- * param@[in] staged_ancestors Should contain entries in the mempool.
- * param@[out] setAncestors Will be populated with all mempool ancestors.
+ *
+ * @param[in] entry_size Virtual size to include in the limits.
+ * @param[in] entry_count How many entries to include in the limits.
+ * @param[out] setAncestors Will be populated with all mempool ancestors.
+ * @param[in] staged_ancestors Should contain entries in the mempool.
+ * @param[in] limits Maximum number and size of ancestors and descendants
+ * @param[out] errString Populated with error reason if any limits are hit
+ *
+ * @return true if no limits were hit and all in-mempool ancestors were calculated, false
+ * otherwise
*/
bool CalculateAncestorsAndCheckLimits(size_t entry_size,
size_t entry_count,
setEntries& setAncestors,
CTxMemPoolEntry::Parents &staged_ancestors,
- uint64_t limitAncestorCount,
- uint64_t limitAncestorSize,
- uint64_t limitDescendantCount,
- uint64_t limitDescendantSize,
+ const Limits& limits,
std::string &errString) const EXCLUSIVE_LOCKS_REQUIRED(cs);
public:
@@ -576,8 +581,6 @@ class CTxMemPool
const bool m_require_standard;
const bool m_full_rbf;
- using Limits = kernel::MemPoolLimits;
-
const Limits m_limits;
/** Create a new CTxMemPool.
@@ -668,38 +671,41 @@ class CTxMemPool
*/
void UpdateTransactionsFromBlock(const std::vector& vHashesToUpdate) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main) LOCKS_EXCLUDED(m_epoch);
- /** Try to calculate all in-mempool ancestors of entry.
- * (these are all calculated including the tx itself)
- * limitAncestorCount = max number of ancestors
- * limitAncestorSize = max size of ancestors
- * limitDescendantCount = max number of descendants any ancestor can have
- * limitDescendantSize = max size of descendants any ancestor can have
- * errString = populated with error reason if any limits are hit
- * fSearchForParents = whether to search a tx's vin for in-mempool parents, or
- * look up parents from mapLinks. Must be true for entries not in the mempool
+ /**
+ * Try to calculate all in-mempool ancestors of entry.
+ * (these are all calculated including the tx itself)
+ *
+ * @param[in] entry CTxMemPoolEntry of which all in-mempool ancestors are calculated
+ * @param[out] setAncestors Will be populated with all mempool ancestors.
+ * @param[in] limits Maximum number and size of ancestors and descendants
+ * @param[out] errString Populated with error reason if any limits are hit
+ * @param[in] fSearchForParents Whether to search a tx's vin for in-mempool parents, or look
+ * up parents from mapLinks. Must be true for entries not in
+ * the mempool
+ *
+ * @return true if no limits were hit and all in-mempool ancestors were calculated, false
+ * otherwise
*/
- bool CalculateMemPoolAncestors(const CTxMemPoolEntry& entry, setEntries& setAncestors, uint64_t limitAncestorCount, uint64_t limitAncestorSize, uint64_t limitDescendantCount, uint64_t limitDescendantSize, std::string& errString, bool fSearchForParents = true) const EXCLUSIVE_LOCKS_REQUIRED(cs);
+ bool CalculateMemPoolAncestors(const CTxMemPoolEntry& entry,
+ setEntries& setAncestors,
+ const Limits& limits,
+ std::string& errString,
+ bool fSearchForParents = true) const EXCLUSIVE_LOCKS_REQUIRED(cs);
/** Calculate all in-mempool ancestors of a set of transactions not already in the mempool and
* check ancestor and descendant limits. Heuristics are used to estimate the ancestor and
* descendant count of all entries if the package were to be added to the mempool. The limits
* are applied to the union of all package transactions. For example, if the package has 3
- * transactions and limitAncestorCount = 25, the union of all 3 sets of ancestors (including the
+ * transactions and limits.ancestor_count = 25, the union of all 3 sets of ancestors (including the
* transactions themselves) must be <= 22.
* @param[in] package Transaction package being evaluated for acceptance
* to mempool. The transactions need not be direct
* ancestors/descendants of each other.
- * @param[in] limitAncestorCount Max number of txns including ancestors.
- * @param[in] limitAncestorSize Max virtual size including ancestors.
- * @param[in] limitDescendantCount Max number of txns including descendants.
- * @param[in] limitDescendantSize Max virtual size including descendants.
+ * @param[in] limits Maximum number and size of ancestors and descendants
* @param[out] errString Populated with error reason if a limit is hit.
*/
bool CheckPackageLimits(const Package& package,
- uint64_t limitAncestorCount,
- uint64_t limitAncestorSize,
- uint64_t limitDescendantCount,
- uint64_t limitDescendantSize,
+ const Limits& limits,
std::string &errString) const EXCLUSIVE_LOCKS_REQUIRED(cs);
/** Populate setDescendants with all in-mempool descendants of hash.
@@ -825,7 +831,7 @@ class CTxMemPool
* mempool but may have child transactions in the mempool, eg during a
* chain reorg.
*
- * @pre CTxMemPool::m_children is correct for the given tx and all
+ * @pre CTxMemPoolEntry::m_children is correct for the given tx and all
* descendants.
* @pre cachedDescendants is an accurate cache where each entry has all
* descendants of the corresponding key, including those that should
diff --git a/src/util/system.cpp b/src/util/system.cpp
index d84c0dfb0e56..962c9f9d1f5b 100644
--- a/src/util/system.cpp
+++ b/src/util/system.cpp
@@ -5,19 +5,6 @@
#include
-#ifdef ENABLE_EXTERNAL_SIGNER
-#if defined(__GNUC__)
-// Boost 1.78 requires the following workaround.
-// See: https://github.com/boostorg/process/issues/235
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wnarrowing"
-#endif
-#include
-#if defined(__GNUC__)
-#pragma GCC diagnostic pop
-#endif
-#endif // ENABLE_EXTERNAL_SIGNER
-
#include
#include
#include
@@ -1332,44 +1319,6 @@ void runCommand(const std::string& strCommand)
}
#endif
-UniValue RunCommandParseJSON(const std::string& str_command, const std::string& str_std_in)
-{
-#ifdef ENABLE_EXTERNAL_SIGNER
- namespace bp = boost::process;
-
- UniValue result_json;
- bp::opstream stdin_stream;
- bp::ipstream stdout_stream;
- bp::ipstream stderr_stream;
-
- if (str_command.empty()) return UniValue::VNULL;
-
- bp::child c(
- str_command,
- bp::std_out > stdout_stream,
- bp::std_err > stderr_stream,
- bp::std_in < stdin_stream
- );
- if (!str_std_in.empty()) {
- stdin_stream << str_std_in << std::endl;
- }
- stdin_stream.pipe().close();
-
- std::string result;
- std::string error;
- std::getline(stdout_stream, result);
- std::getline(stderr_stream, error);
-
- c.wait();
- const int n_error = c.exit_code();
- if (n_error) throw std::runtime_error(strprintf("RunCommandParseJSON error: process(%s) returned %d: %s\n", str_command, n_error, error));
- if (!result_json.read(result)) throw std::runtime_error("Unable to parse JSON: " + result);
-
- return result_json;
-#else
- throw std::runtime_error("Compiled without external signing support (required for external signing).");
-#endif // ENABLE_EXTERNAL_SIGNER
-}
void SetupEnvironment()
{
diff --git a/src/util/system.h b/src/util/system.h
index c8e1de6700e2..29629e547efc 100644
--- a/src/util/system.h
+++ b/src/util/system.h
@@ -107,14 +107,6 @@ std::string ShellEscape(const std::string& arg);
#if HAVE_SYSTEM
void runCommand(const std::string& strCommand);
#endif
-/**
- * Execute a command which returns JSON, and parse the result.
- *
- * @param str_command The command to execute, including any arguments
- * @param str_std_in string to pass to stdin
- * @return parsed JSON
- */
-UniValue RunCommandParseJSON(const std::string& str_command, const std::string& str_std_in="");
/**
* Most paths passed as configuration arguments are treated as relative to
diff --git a/src/util/time.cpp b/src/util/time.cpp
index f6d37347f8de..0b208490792d 100644
--- a/src/util/time.cpp
+++ b/src/util/time.cpp
@@ -12,8 +12,6 @@
#include
#include
-#include
-
#include
#include
#include
@@ -142,20 +140,6 @@ std::string FormatISO8601Date(int64_t nTime) {
return strprintf("%04i-%02i-%02i", ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday);
}
-int64_t ParseISO8601DateTime(const std::string& str)
-{
- static const boost::posix_time::ptime epoch = boost::posix_time::from_time_t(0);
- static const std::locale loc(std::locale::classic(),
- new boost::posix_time::time_input_facet("%Y-%m-%dT%H:%M:%SZ"));
- std::istringstream iss(str);
- iss.imbue(loc);
- boost::posix_time::ptime ptime(boost::date_time::not_a_date_time);
- iss >> ptime;
- if (ptime.is_not_a_date_time() || epoch > ptime)
- return 0;
- return (ptime - epoch).total_seconds();
-}
-
struct timeval MillisToTimeval(int64_t nTimeout)
{
struct timeval timeout;
diff --git a/src/util/time.h b/src/util/time.h
index 4f9bde5d5632..10a581a44cab 100644
--- a/src/util/time.h
+++ b/src/util/time.h
@@ -57,6 +57,7 @@ constexpr int64_t count_microseconds(std::chrono::microseconds t) { return t.cou
using HoursDouble = std::chrono::duration;
using SecondsDouble = std::chrono::duration;
+using MillisecondsDouble = std::chrono::duration;
/**
* DEPRECATED
@@ -109,7 +110,6 @@ T GetTime()
*/
std::string FormatISO8601DateTime(int64_t nTime);
std::string FormatISO8601Date(int64_t nTime);
-int64_t ParseISO8601DateTime(const std::string& str);
/**
* Convert milliseconds to a struct timeval for e.g. select.
diff --git a/src/validation.cpp b/src/validation.cpp
index fb29ca3ae7cf..514a52831412 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -82,9 +82,6 @@ using node::SnapshotMetadata;
using node::UndoReadFromDisk;
using node::UnlinkPrunedFiles;
-#define MICRO 0.000001
-#define MILLI 0.001
-
/** Maximum kilobytes for transactions to store for processing during reorg */
static const unsigned int MAX_DISCONNECTED_TX_POOL_SIZE = 20000;
/** Time to wait between writing blocks/block index to disk. */
@@ -424,11 +421,13 @@ namespace {
class MemPoolAccept
{
public:
- explicit MemPoolAccept(CTxMemPool& mempool, Chainstate& active_chainstate) : m_pool(mempool), m_view(&m_dummy), m_viewmempool(&active_chainstate.CoinsTip(), m_pool), m_active_chainstate(active_chainstate),
- m_limit_ancestors(m_pool.m_limits.ancestor_count),
- m_limit_ancestor_size(m_pool.m_limits.ancestor_size_vbytes),
- m_limit_descendants(m_pool.m_limits.descendant_count),
- m_limit_descendant_size(m_pool.m_limits.descendant_size_vbytes) {
+ explicit MemPoolAccept(CTxMemPool& mempool, Chainstate& active_chainstate) :
+ m_pool(mempool),
+ m_view(&m_dummy),
+ m_viewmempool(&active_chainstate.CoinsTip(), m_pool),
+ m_active_chainstate(active_chainstate),
+ m_limits{m_pool.m_limits}
+ {
}
// We put the arguments we're handed into a struct, so we can pass them
@@ -660,13 +659,7 @@ class MemPoolAccept
Chainstate& m_active_chainstate;
- // The package limits in effect at the time of invocation.
- const size_t m_limit_ancestors;
- const size_t m_limit_ancestor_size;
- // These may be modified while evaluating a transaction (eg to account for
- // in-mempool conflicts; see below).
- size_t m_limit_descendants;
- size_t m_limit_descendant_size;
+ CTxMemPool::Limits m_limits;
/** Whether the transaction(s) would replace any mempool transactions. If so, RBF rules apply. */
bool m_rbf{false};
@@ -879,12 +872,12 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
assert(ws.m_iters_conflicting.size() == 1);
CTxMemPool::txiter conflict = *ws.m_iters_conflicting.begin();
- m_limit_descendants += 1;
- m_limit_descendant_size += conflict->GetSizeWithDescendants();
+ m_limits.descendant_count += 1;
+ m_limits.descendant_size_vbytes += conflict->GetSizeWithDescendants();
}
std::string errString;
- if (!m_pool.CalculateMemPoolAncestors(*entry, ws.m_ancestors, m_limit_ancestors, m_limit_ancestor_size, m_limit_descendants, m_limit_descendant_size, errString)) {
+ if (!m_pool.CalculateMemPoolAncestors(*entry, ws.m_ancestors, m_limits, errString)) {
ws.m_ancestors.clear();
// If CalculateMemPoolAncestors fails second time, we want the original error string.
std::string dummy_err_string;
@@ -899,8 +892,16 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
// to be secure by simply only having two immediately-spendable
// outputs - one for each counterparty. For more info on the uses for
// this, see https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-November/016518.html
+ CTxMemPool::Limits cpfp_carve_out_limits{
+ .ancestor_count = 2,
+ .ancestor_size_vbytes = m_limits.ancestor_size_vbytes,
+ .descendant_count = m_limits.descendant_count + 1,
+ .descendant_size_vbytes = m_limits.descendant_size_vbytes + EXTRA_DESCENDANT_TX_SIZE_LIMIT,
+ };
if (ws.m_vsize > EXTRA_DESCENDANT_TX_SIZE_LIMIT ||
- !m_pool.CalculateMemPoolAncestors(*entry, ws.m_ancestors, 2, m_limit_ancestor_size, m_limit_descendants + 1, m_limit_descendant_size + EXTRA_DESCENDANT_TX_SIZE_LIMIT, dummy_err_string)) {
+ !m_pool.CalculateMemPoolAncestors(*entry, ws.m_ancestors,
+ cpfp_carve_out_limits,
+ dummy_err_string)) {
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "too-long-mempool-chain", errString);
}
}
@@ -976,8 +977,7 @@ bool MemPoolAccept::PackageMempoolChecks(const std::vector& txn
{ return !m_pool.exists(GenTxid::Txid(tx->GetHash()));}));
std::string err_string;
- if (!m_pool.CheckPackageLimits(txns, m_limit_ancestors, m_limit_ancestor_size, m_limit_descendants,
- m_limit_descendant_size, err_string)) {
+ if (!m_pool.CheckPackageLimits(txns, m_limits, err_string)) {
// This is a package-wide error, separate from an individual transaction error.
return package_state.Invalid(PackageValidationResult::PCKG_POLICY, "package-mempool-limits", err_string);
}
@@ -1121,9 +1121,7 @@ bool MemPoolAccept::SubmitPackage(const ATMPArgs& args, std::vector&
// Re-calculate mempool ancestors to call addUnchecked(). They may have changed since the
// last calculation done in PreChecks, since package ancestors have already been submitted.
std::string unused_err_string;
- if(!m_pool.CalculateMemPoolAncestors(*ws.m_entry, ws.m_ancestors, m_limit_ancestors,
- m_limit_ancestor_size, m_limit_descendants,
- m_limit_descendant_size, unused_err_string)) {
+ if(!m_pool.CalculateMemPoolAncestors(*ws.m_entry, ws.m_ancestors, m_limits, unused_err_string)) {
results.emplace(ws.m_ptx->GetWitnessHash(), MempoolAcceptResult::Failure(ws.m_state));
// Since PreChecks() and PackageMempoolChecks() both enforce limits, this should never fail.
Assume(false);
@@ -1965,14 +1963,14 @@ static unsigned int GetBlockScriptFlags(const CBlockIndex& block_index, const Ch
}
-static int64_t nTimeCheck = 0;
-static int64_t nTimeForks = 0;
-static int64_t nTimeConnect = 0;
-static int64_t nTimeVerify = 0;
-static int64_t nTimeUndo = 0;
-static int64_t nTimeIndex = 0;
-static int64_t nTimeTotal = 0;
-static int64_t nBlocksTotal = 0;
+static SteadyClock::duration time_check{};
+static SteadyClock::duration time_forks{};
+static SteadyClock::duration time_connect{};
+static SteadyClock::duration time_verify{};
+static SteadyClock::duration time_undo{};
+static SteadyClock::duration time_index{};
+static SteadyClock::duration time_total{};
+static int64_t num_blocks_total = 0;
/** Apply the effects of this block (with given index) on the UTXO set represented by coins.
* Validity checks that depend on the UTXO set are also done; ConnectBlock()
@@ -1986,7 +1984,7 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
uint256 block_hash{block.GetHash()};
assert(*pindex->phashBlock == block_hash);
- int64_t nTimeStart = GetTimeMicros();
+ const auto time_start{SteadyClock::now()};
// Check it again in case a previous version let a bad block in
// NOTE: We don't currently (re-)invoke ContextualCheckBlock() or
@@ -2015,7 +2013,7 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
uint256 hashPrevBlock = pindex->pprev == nullptr ? uint256() : pindex->pprev->GetBlockHash();
assert(hashPrevBlock == view.GetBestBlock());
- nBlocksTotal++;
+ num_blocks_total++;
// Special case for the genesis block, skipping connection of its transactions
// (its coinbase is unspendable)
@@ -2056,8 +2054,12 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
}
}
- int64_t nTime1 = GetTimeMicros(); nTimeCheck += nTime1 - nTimeStart;
- LogPrint(BCLog::BENCH, " - Sanity checks: %.2fms [%.2fs (%.2fms/blk)]\n", MILLI * (nTime1 - nTimeStart), nTimeCheck * MICRO, nTimeCheck * MILLI / nBlocksTotal);
+ const auto time_1{SteadyClock::now()};
+ time_check += time_1 - time_start;
+ LogPrint(BCLog::BENCH, " - Sanity checks: %.2fms [%.2fs (%.2fms/blk)]\n",
+ Ticks(time_1 - time_start),
+ Ticks(time_check),
+ Ticks(time_check) / num_blocks_total);
// Do not allow blocks that contain transactions which 'overwrite' older transactions,
// unless those are already completely spent.
@@ -2155,8 +2157,12 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
// Get the script flags for this block
unsigned int flags{GetBlockScriptFlags(*pindex, m_chainman)};
- int64_t nTime2 = GetTimeMicros(); nTimeForks += nTime2 - nTime1;
- LogPrint(BCLog::BENCH, " - Fork checks: %.2fms [%.2fs (%.2fms/blk)]\n", MILLI * (nTime2 - nTime1), nTimeForks * MICRO, nTimeForks * MILLI / nBlocksTotal);
+ const auto time_2{SteadyClock::now()};
+ time_forks += time_2 - time_1;
+ LogPrint(BCLog::BENCH, " - Fork checks: %.2fms [%.2fs (%.2fms/blk)]\n",
+ Ticks(time_2 - time_1),
+ Ticks(time_forks),
+ Ticks(time_forks) / num_blocks_total);
CBlockUndo blockundo;
@@ -2240,8 +2246,13 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
}
UpdateCoins(tx, view, i == 0 ? undoDummy : blockundo.vtxundo.back(), pindex->nHeight);
}
- int64_t nTime3 = GetTimeMicros(); nTimeConnect += nTime3 - nTime2;
- LogPrint(BCLog::BENCH, " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs (%.2fms/blk)]\n", (unsigned)block.vtx.size(), MILLI * (nTime3 - nTime2), MILLI * (nTime3 - nTime2) / block.vtx.size(), nInputs <= 1 ? 0 : MILLI * (nTime3 - nTime2) / (nInputs-1), nTimeConnect * MICRO, nTimeConnect * MILLI / nBlocksTotal);
+ const auto time_3{SteadyClock::now()};
+ time_connect += time_3 - time_2;
+ LogPrint(BCLog::BENCH, " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs (%.2fms/blk)]\n", (unsigned)block.vtx.size(),
+ Ticks(time_3 - time_2), Ticks(time_3 - time_2) / block.vtx.size(),
+ nInputs <= 1 ? 0 : Ticks(time_3 - time_2) / (nInputs - 1),
+ Ticks(time_connect),
+ Ticks(time_connect) / num_blocks_total);
CAmount blockReward = nFees + GetBlockSubsidy(pindex->nHeight, m_params.GetConsensus());
if (block.vtx[0]->GetValueOut() > blockReward) {
@@ -2253,8 +2264,13 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
LogPrintf("ERROR: %s: CheckQueue failed\n", __func__);
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "block-validation-failed");
}
- int64_t nTime4 = GetTimeMicros(); nTimeVerify += nTime4 - nTime2;
- LogPrint(BCLog::BENCH, " - Verify %u txins: %.2fms (%.3fms/txin) [%.2fs (%.2fms/blk)]\n", nInputs - 1, MILLI * (nTime4 - nTime2), nInputs <= 1 ? 0 : MILLI * (nTime4 - nTime2) / (nInputs-1), nTimeVerify * MICRO, nTimeVerify * MILLI / nBlocksTotal);
+ const auto time_4{SteadyClock::now()};
+ time_verify += time_4 - time_2;
+ LogPrint(BCLog::BENCH, " - Verify %u txins: %.2fms (%.3fms/txin) [%.2fs (%.2fms/blk)]\n", nInputs - 1,
+ Ticks(time_4 - time_2),
+ nInputs <= 1 ? 0 : Ticks(time_4 - time_2) / (nInputs - 1),
+ Ticks(time_verify),
+ Ticks(time_verify) / num_blocks_total);
if (fJustCheck)
return true;
@@ -2263,8 +2279,12 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
return false;
}
- int64_t nTime5 = GetTimeMicros(); nTimeUndo += nTime5 - nTime4;
- LogPrint(BCLog::BENCH, " - Write undo data: %.2fms [%.2fs (%.2fms/blk)]\n", MILLI * (nTime5 - nTime4), nTimeUndo * MICRO, nTimeUndo * MILLI / nBlocksTotal);
+ const auto time_5{SteadyClock::now()};
+ time_undo += time_5 - time_4;
+ LogPrint(BCLog::BENCH, " - Write undo data: %.2fms [%.2fs (%.2fms/blk)]\n",
+ Ticks(time_5 - time_4),
+ Ticks(time_undo),
+ Ticks(time_undo) / num_blocks_total);
if (!pindex->IsValid(BLOCK_VALID_SCRIPTS)) {
pindex->RaiseValidity(BLOCK_VALID_SCRIPTS);
@@ -2274,8 +2294,12 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
// add this block to the view's block chain
view.SetBestBlock(pindex->GetBlockHash());
- int64_t nTime6 = GetTimeMicros(); nTimeIndex += nTime6 - nTime5;
- LogPrint(BCLog::BENCH, " - Index writing: %.2fms [%.2fs (%.2fms/blk)]\n", MILLI * (nTime6 - nTime5), nTimeIndex * MICRO, nTimeIndex * MILLI / nBlocksTotal);
+ const auto time_6{SteadyClock::now()};
+ time_index += time_6 - time_5;
+ LogPrint(BCLog::BENCH, " - Index writing: %.2fms [%.2fs (%.2fms/blk)]\n",
+ Ticks(time_6 - time_5),
+ Ticks(time_index),
+ Ticks(time_index) / num_blocks_total);
TRACE6(validation, block_connected,
block_hash.data(),
@@ -2283,7 +2307,7 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
block.vtx.size(),
nInputs,
nSigOpsCost,
- nTime5 - nTimeStart // in microseconds (µs)
+ time_5 - time_start // in microseconds (µs)
);
return true;
@@ -2590,7 +2614,7 @@ bool Chainstate::DisconnectTip(BlockValidationState& state, DisconnectedBlockTra
return error("DisconnectTip(): Failed to read block");
}
// Apply the block atomically to the chain state.
- int64_t nStart = GetTimeMicros();
+ const auto time_start{SteadyClock::now()};
{
CCoinsViewCache view(&CoinsTip());
assert(view.GetBestBlock() == pindexDelete->GetBlockHash());
@@ -2599,7 +2623,8 @@ bool Chainstate::DisconnectTip(BlockValidationState& state, DisconnectedBlockTra
bool flushed = view.Flush();
assert(flushed);
}
- LogPrint(BCLog::BENCH, "- Disconnect block: %.2fms\n", (GetTimeMicros() - nStart) * MILLI);
+ LogPrint(BCLog::BENCH, "- Disconnect block: %.2fms\n",
+ Ticks(SteadyClock::now() - time_start));
{
// Prune locks that began at or after the tip should be moved backward so they get a chance to reorg
@@ -2639,11 +2664,11 @@ bool Chainstate::DisconnectTip(BlockValidationState& state, DisconnectedBlockTra
return true;
}
-static int64_t nTimeReadFromDiskTotal = 0;
-static int64_t nTimeConnectTotal = 0;
-static int64_t nTimeFlush = 0;
-static int64_t nTimeChainState = 0;
-static int64_t nTimePostConnect = 0;
+static SteadyClock::duration time_read_from_disk_total{};
+static SteadyClock::duration time_connect_total{};
+static SteadyClock::duration time_flush{};
+static SteadyClock::duration time_chainstate{};
+static SteadyClock::duration time_post_connect{};
struct PerBlockConnectTrace {
CBlockIndex* pindex = nullptr;
@@ -2698,7 +2723,7 @@ bool Chainstate::ConnectTip(BlockValidationState& state, CBlockIndex* pindexNew,
assert(pindexNew->pprev == m_chain.Tip());
// Read block from disk.
- int64_t nTime1 = GetTimeMicros();
+ const auto time_1{SteadyClock::now()};
std::shared_ptr pthisBlock;
if (!pblock) {
std::shared_ptr pblockNew = std::make_shared();
@@ -2712,9 +2737,13 @@ bool Chainstate::ConnectTip(BlockValidationState& state, CBlockIndex* pindexNew,
}
const CBlock& blockConnecting = *pthisBlock;
// Apply the block atomically to the chain state.
- int64_t nTime2 = GetTimeMicros(); nTimeReadFromDiskTotal += nTime2 - nTime1;
- int64_t nTime3;
- LogPrint(BCLog::BENCH, " - Load block from disk: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime2 - nTime1) * MILLI, nTimeReadFromDiskTotal * MICRO, nTimeReadFromDiskTotal * MILLI / nBlocksTotal);
+ const auto time_2{SteadyClock::now()};
+ time_read_from_disk_total += time_2 - time_1;
+ SteadyClock::time_point time_3;
+ LogPrint(BCLog::BENCH, " - Load block from disk: %.2fms [%.2fs (%.2fms/blk)]\n",
+ Ticks(time_2 - time_1),
+ Ticks(time_read_from_disk_total),
+ Ticks(time_read_from_disk_total) / num_blocks_total);
{
CCoinsViewCache view(&CoinsTip());
bool rv = ConnectBlock(blockConnecting, state, pindexNew, view);
@@ -2724,20 +2753,32 @@ bool Chainstate::ConnectTip(BlockValidationState& state, CBlockIndex* pindexNew,
InvalidBlockFound(pindexNew, state);
return error("%s: ConnectBlock %s failed, %s", __func__, pindexNew->GetBlockHash().ToString(), state.ToString());
}
- nTime3 = GetTimeMicros(); nTimeConnectTotal += nTime3 - nTime2;
- assert(nBlocksTotal > 0);
- LogPrint(BCLog::BENCH, " - Connect total: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime3 - nTime2) * MILLI, nTimeConnectTotal * MICRO, nTimeConnectTotal * MILLI / nBlocksTotal);
+ time_3 = SteadyClock::now();
+ time_connect_total += time_3 - time_2;
+ assert(num_blocks_total > 0);
+ LogPrint(BCLog::BENCH, " - Connect total: %.2fms [%.2fs (%.2fms/blk)]\n",
+ Ticks(time_3 - time_2),
+ Ticks(time_connect_total),
+ Ticks(time_connect_total) / num_blocks_total);
bool flushed = view.Flush();
assert(flushed);
}
- int64_t nTime4 = GetTimeMicros(); nTimeFlush += nTime4 - nTime3;
- LogPrint(BCLog::BENCH, " - Flush: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime4 - nTime3) * MILLI, nTimeFlush * MICRO, nTimeFlush * MILLI / nBlocksTotal);
+ const auto time_4{SteadyClock::now()};
+ time_flush += time_4 - time_3;
+ LogPrint(BCLog::BENCH, " - Flush: %.2fms [%.2fs (%.2fms/blk)]\n",
+ Ticks(time_4 - time_3),
+ Ticks(time_flush),
+ Ticks(time_flush) / num_blocks_total);
// Write the chain state to disk, if necessary.
if (!FlushStateToDisk(state, FlushStateMode::IF_NEEDED)) {
return false;
}
- int64_t nTime5 = GetTimeMicros(); nTimeChainState += nTime5 - nTime4;
- LogPrint(BCLog::BENCH, " - Writing chainstate: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime5 - nTime4) * MILLI, nTimeChainState * MICRO, nTimeChainState * MILLI / nBlocksTotal);
+ const auto time_5{SteadyClock::now()};
+ time_chainstate += time_5 - time_4;
+ LogPrint(BCLog::BENCH, " - Writing chainstate: %.2fms [%.2fs (%.2fms/blk)]\n",
+ Ticks(time_5 - time_4),
+ Ticks(time_chainstate),
+ Ticks(time_chainstate) / num_blocks_total);
// Remove conflicting transactions from the mempool.;
if (m_mempool) {
m_mempool->removeForBlock(blockConnecting.vtx, pindexNew->nHeight);
@@ -2747,9 +2788,17 @@ bool Chainstate::ConnectTip(BlockValidationState& state, CBlockIndex* pindexNew,
m_chain.SetTip(*pindexNew);
UpdateTip(pindexNew);
- int64_t nTime6 = GetTimeMicros(); nTimePostConnect += nTime6 - nTime5; nTimeTotal += nTime6 - nTime1;
- LogPrint(BCLog::BENCH, " - Connect postprocess: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime6 - nTime5) * MILLI, nTimePostConnect * MICRO, nTimePostConnect * MILLI / nBlocksTotal);
- LogPrint(BCLog::BENCH, "- Connect block: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime6 - nTime1) * MILLI, nTimeTotal * MICRO, nTimeTotal * MILLI / nBlocksTotal);
+ const auto time_6{SteadyClock::now()};
+ time_post_connect += time_6 - time_5;
+ time_total += time_6 - time_1;
+ LogPrint(BCLog::BENCH, " - Connect postprocess: %.2fms [%.2fs (%.2fms/blk)]\n",
+ Ticks(time_6 - time_5),
+ Ticks(time_post_connect),
+ Ticks(time_post_connect) / num_blocks_total);
+ LogPrint(BCLog::BENCH, "- Connect block: %.2fms [%.2fs (%.2fms/blk)]\n",
+ Ticks(time_6 - time_1),
+ Ticks(time_total),
+ Ticks(time_total) / num_blocks_total);
connectTrace.BlockConnected(pindexNew, std::move(pthisBlock));
return true;
diff --git a/src/validation.h b/src/validation.h
index 9ba206855f0c..c882eac40885 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -65,9 +65,6 @@ static const int MAX_SCRIPTCHECK_THREADS = 15;
static const int DEFAULT_SCRIPTCHECK_THREADS = 0;
static const int64_t DEFAULT_MAX_TIP_AGE = 24 * 60 * 60;
static const bool DEFAULT_CHECKPOINTS_ENABLED = true;
-static const bool DEFAULT_TXINDEX = false;
-static constexpr bool DEFAULT_COINSTATSINDEX{false};
-static const char* const DEFAULT_BLOCKFILTERINDEX = "0";
/** Default for -stopatheight */
static const int DEFAULT_STOPATHEIGHT = 0;
/** Block files containing a block-height within MIN_BLOCKS_TO_KEEP of ActiveChain().Tip() will not be pruned. */
diff --git a/src/wallet/rpc/util.cpp b/src/wallet/rpc/util.cpp
index 3c1634324e2a..1aa2a87e99df 100644
--- a/src/wallet/rpc/util.cpp
+++ b/src/wallet/rpc/util.cpp
@@ -12,10 +12,26 @@
#include
+#include
+
namespace wallet {
static const std::string WALLET_ENDPOINT_BASE = "/wallet/";
const std::string HELP_REQUIRING_PASSPHRASE{"\nRequires wallet passphrase to be set with walletpassphrase call if wallet is encrypted.\n"};
+int64_t ParseISO8601DateTime(const std::string& str)
+{
+ static const boost::posix_time::ptime epoch = boost::posix_time::from_time_t(0);
+ static const std::locale loc(std::locale::classic(),
+ new boost::posix_time::time_input_facet("%Y-%m-%dT%H:%M:%SZ"));
+ std::istringstream iss(str);
+ iss.imbue(loc);
+ boost::posix_time::ptime ptime(boost::date_time::not_a_date_time);
+ iss >> ptime;
+ if (ptime.is_not_a_date_time() || epoch > ptime)
+ return 0;
+ return (ptime - epoch).total_seconds();
+}
+
bool GetAvoidReuseFlag(const CWallet& wallet, const UniValue& param) {
bool can_avoid_reuse = wallet.IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE);
bool avoid_reuse = param.isNull() ? can_avoid_reuse : param.get_bool();
diff --git a/src/wallet/rpc/util.h b/src/wallet/rpc/util.h
index 2ca28914e7f1..87d34f7c11f5 100644
--- a/src/wallet/rpc/util.h
+++ b/src/wallet/rpc/util.h
@@ -45,6 +45,8 @@ std::string LabelFromValue(const UniValue& value);
void PushParentDescriptors(const CWallet& wallet, const CScript& script_pubkey, UniValue& entry);
void HandleWalletError(const std::shared_ptr wallet, DatabaseStatus& status, bilingual_str& error);
+
+int64_t ParseISO8601DateTime(const std::string& str);
} // namespace wallet
#endif // BITCOIN_WALLET_RPC_UTIL_H
diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp
index 41654579c6ac..6da0741d5960 100644
--- a/src/wallet/scriptpubkeyman.cpp
+++ b/src/wallet/scriptpubkeyman.cpp
@@ -586,7 +586,7 @@ bool LegacyScriptPubKeyMan::CanProvide(const CScript& script, SignatureData& sig
// or solving information, even if not able to sign fully.
return true;
} else {
- // If, given the stuff in sigdata, we could make a valid sigature, then we can provide for this script
+ // If, given the stuff in sigdata, we could make a valid signature, then we can provide for this script
ProduceSignature(*this, DUMMY_SIGNATURE_CREATOR, script, sigdata);
if (!sigdata.signatures.empty()) {
// If we could make signatures, make sure we have a private key to actually make a signature
diff --git a/src/wallet/spend.cpp b/src/wallet/spend.cpp
index 523db8d7bc78..6833f9a09550 100644
--- a/src/wallet/spend.cpp
+++ b/src/wallet/spend.cpp
@@ -582,7 +582,13 @@ std::optional SelectCoins(const CWallet& wallet, CoinsResult& a
if (coin_control.HasSelected() && !coin_control.m_allow_other_inputs) {
SelectionResult result(nTargetValue, SelectionAlgorithm::MANUAL);
result.AddInput(preset_inputs);
- if (result.GetSelectedValue() < nTargetValue) return std::nullopt;
+
+ if (!coin_selection_params.m_subtract_fee_outputs && result.GetSelectedEffectiveValue() < nTargetValue) {
+ return std::nullopt;
+ } else if (result.GetSelectedValue() < nTargetValue) {
+ return std::nullopt;
+ }
+
result.ComputeAndSetWaste(coin_selection_params.min_viable_change, coin_selection_params.m_cost_of_change, coin_selection_params.m_change_fee);
return result;
}
diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp
index 30a7fb9eb6ec..23f024247d72 100644
--- a/src/wallet/test/coinselector_tests.cpp
+++ b/src/wallet/test/coinselector_tests.cpp
@@ -922,5 +922,52 @@ BOOST_AUTO_TEST_CASE(effective_value_test)
BOOST_CHECK_EQUAL(output5.GetEffectiveValue(), nValue); // The effective value should be equal to the absolute value if input_bytes is -1
}
+BOOST_AUTO_TEST_CASE(SelectCoins_effective_value_test)
+{
+ // Test that the effective value is used to check whether preset inputs provide sufficient funds when subtract_fee_outputs is not used.
+ // This test creates a coin whose value is higher than the target but whose effective value is lower than the target.
+ // The coin is selected using coin control, with m_allow_other_inputs = false. SelectCoins should fail due to insufficient funds.
+
+ std::unique_ptr wallet = std::make_unique(m_node.chain.get(), "", m_args, CreateMockWalletDatabase());
+ wallet->LoadWallet();
+ LOCK(wallet->cs_wallet);
+ wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
+ wallet->SetupDescriptorScriptPubKeyMans();
+
+ CoinsResult available_coins;
+ {
+ std::unique_ptr dummyWallet = std::make_unique(m_node.chain.get(), "dummy", m_args, CreateMockWalletDatabase());
+ dummyWallet->LoadWallet();
+ LOCK(dummyWallet->cs_wallet);
+ dummyWallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
+ dummyWallet->SetupDescriptorScriptPubKeyMans();
+
+ add_coin(available_coins, *dummyWallet, 100000); // 0.001 BTC
+ }
+
+ CAmount target{99900}; // 0.000999 BTC
+
+ FastRandomContext rand;
+ CoinSelectionParams cs_params{
+ rand,
+ /*change_output_size=*/34,
+ /*change_spend_size=*/148,
+ /*min_change_target=*/1000,
+ /*effective_feerate=*/CFeeRate(3000),
+ /*long_term_feerate=*/CFeeRate(1000),
+ /*discard_feerate=*/CFeeRate(1000),
+ /*tx_noinputs_size=*/0,
+ /*avoid_partial=*/false,
+ };
+ CCoinControl cc;
+ cc.m_allow_other_inputs = false;
+ COutput output = available_coins.All().at(0);
+ cc.SetInputWeight(output.outpoint, 148);
+ cc.SelectExternal(output.outpoint, output.txout);
+
+ const auto result = SelectCoins(*wallet, available_coins, target, cc, cs_params);
+ BOOST_CHECK(!result);
+}
+
BOOST_AUTO_TEST_SUITE_END()
} // namespace wallet
diff --git a/src/test/fuzz/parse_iso8601.cpp b/src/wallet/test/fuzz/parse_iso8601.cpp
similarity index 83%
rename from src/test/fuzz/parse_iso8601.cpp
rename to src/wallet/test/fuzz/parse_iso8601.cpp
index 0fef9a9a1d34..5be248c2fb0a 100644
--- a/src/test/fuzz/parse_iso8601.cpp
+++ b/src/wallet/test/fuzz/parse_iso8601.cpp
@@ -5,6 +5,7 @@
#include
#include
#include
+#include
#include
#include
@@ -20,7 +21,7 @@ FUZZ_TARGET(parse_iso8601)
const std::string iso8601_datetime = FormatISO8601DateTime(random_time);
(void)FormatISO8601Date(random_time);
- const int64_t parsed_time_1 = ParseISO8601DateTime(iso8601_datetime);
+ const int64_t parsed_time_1 = wallet::ParseISO8601DateTime(iso8601_datetime);
if (random_time >= 0) {
assert(parsed_time_1 >= 0);
if (iso8601_datetime.length() == 20) {
@@ -28,6 +29,6 @@ FUZZ_TARGET(parse_iso8601)
}
}
- const int64_t parsed_time_2 = ParseISO8601DateTime(random_string);
+ const int64_t parsed_time_2 = wallet::ParseISO8601DateTime(random_string);
assert(parsed_time_2 >= 0);
}
diff --git a/src/wallet/test/rpc_util_tests.cpp b/src/wallet/test/rpc_util_tests.cpp
new file mode 100644
index 000000000000..32f6f5ab465e
--- /dev/null
+++ b/src/wallet/test/rpc_util_tests.cpp
@@ -0,0 +1,24 @@
+// Copyright (c) 2022 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include
+
+#include
+
+namespace wallet {
+
+BOOST_AUTO_TEST_SUITE(wallet_util_tests)
+
+BOOST_AUTO_TEST_CASE(util_ParseISO8601DateTime)
+{
+ BOOST_CHECK_EQUAL(ParseISO8601DateTime("1970-01-01T00:00:00Z"), 0);
+ BOOST_CHECK_EQUAL(ParseISO8601DateTime("1960-01-01T00:00:00Z"), 0);
+ BOOST_CHECK_EQUAL(ParseISO8601DateTime("2000-01-01T00:00:01Z"), 946684801);
+ BOOST_CHECK_EQUAL(ParseISO8601DateTime("2011-09-30T23:36:17Z"), 1317425777);
+ BOOST_CHECK_EQUAL(ParseISO8601DateTime("2100-12-31T23:59:59Z"), 4133980799);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace wallet
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index ec5e8879cb22..3134182f09e3 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -124,7 +124,7 @@ bool RemoveWallet(WalletContext& context, const std::shared_ptr& wallet
interfaces::Chain& chain = wallet->chain();
std::string name = wallet->GetName();
- // Unregister with the validation interface which also drops shared ponters.
+ // Unregister with the validation interface which also drops shared pointers.
wallet->m_chain_notifications_handler.reset();
LOCK(context.wallets_mutex);
std::vector>::iterator i = std::find(context.wallets.begin(), context.wallets.end(), wallet);
@@ -3111,12 +3111,14 @@ bool CWallet::AttachChain(const std::shared_ptr& walletInstance, interf
// If a block is pruned after this check, we will load the wallet,
// but fail the rescan with a generic error.
- error = chain.hasAssumedValidChain() ?
- _(
- "Assumed-valid: last wallet synchronisation goes beyond "
- "available block data. You need to wait for the background "
- "validation chain to download more blocks.") :
- _("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)");
+ error = chain.havePruned() ?
+ _("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)") :
+ strprintf(_(
+ "Error loading wallet. Wallet requires blocks to be downloaded, "
+ "and software does not currently support loading wallets while "
+ "blocks are being downloaded out of order when using assumeutxo "
+ "snapshots. Wallet should be able to load successfully after "
+ "node sync reaches height %s"), block_height);
return false;
}
}
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 6a1b76505ce5..953d3e5bde7c 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -195,7 +195,7 @@ class ReserveDestination
util::Result GetReservedDestination(bool internal);
//! Return reserved address
void ReturnDestination();
- //! Keep the address. Do not return it's key to the keypool when this object goes out of scope
+ //! Keep the address. Do not return its key to the keypool when this object goes out of scope
void KeepDestination();
};
diff --git a/src/zmq/zmqabstractnotifier.h b/src/zmq/zmqabstractnotifier.h
index fa3944e32bea..97c2599366a1 100644
--- a/src/zmq/zmqabstractnotifier.h
+++ b/src/zmq/zmqabstractnotifier.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_ZMQ_ZMQABSTRACTNOTIFIER_H
#define BITCOIN_ZMQ_ZMQABSTRACTNOTIFIER_H
-
+#include