mirror of https://github.com/bitcoin/bitcoin.git
Compare commits
69 Commits
76a784c3b0
...
e4c04f7759
Author | SHA1 | Date |
---|---|---|
|
e4c04f7759 | |
|
b510893d00 | |
|
ec5841888d | |
|
d735e2e9b3 | |
|
de1dc6b47b | |
|
919e6d01e9 | |
|
452ea59281 | |
|
a33bd767a3 | |
|
2578da69f4 | |
|
25dbe4bc86 | |
|
cfb0d74698 | |
|
86eaa4d6cd | |
|
007900ee9b | |
|
8e47ed6906 | |
|
3635d62f5a | |
|
2e09d66fbb | |
|
156927903d | |
|
e1a1b14c93 | |
|
1ed00a0d39 | |
|
c76de2eea1 | |
|
75353a0163 | |
|
87e7f37918 | |
|
2a4450ccbb | |
|
4268abae1a | |
|
acc7f2a433 | |
|
1aaaaa078b | |
|
fadad7a494 | |
|
50194029e7 | |
|
f41f97240c | |
|
cc4a2cc6bd | |
|
7502d4e940 | |
|
14ae71f323 | |
|
99bc552980 | |
|
576dd97cb9 | |
|
8f73d95221 | |
|
0f7d4ee4e8 | |
|
93a70a42d3 | |
|
6de8051263 | |
|
46135d90ea | |
|
771978952a | |
|
25212dfdb4 | |
|
06df14ba75 | |
|
26e71c237d | |
|
bbe8e9063c | |
|
d4f47f9771 | |
|
fc861332b3 | |
|
3a4d1a25cf | |
|
dda5228e02 | |
|
7b5261f7ef | |
|
7ae0497eef | |
|
94db966a3b | |
|
eca50854e1 | |
|
451ba9ada4 | |
|
652424ad16 | |
|
fabc2615af | |
|
417437eb01 | |
|
3cbbcb66ef | |
|
bddcadee82 | |
|
a5ead122fe | |
|
4577fb2b1e | |
|
a3986935f0 | |
|
5db8cd2d37 | |
|
0802398e74 | |
|
6d9e5d130d | |
|
3265df63a4 | |
|
91cbf4dbd8 | |
|
50da7432ec | |
|
e6a917c8f8 | |
|
e883b37768 |
|
@ -105,7 +105,7 @@ jobs:
|
|||
name: ${{ matrix.job-name }}
|
||||
# Use any image to support the xcode-select below, but hardcode version to avoid silent upgrades (and breaks).
|
||||
# See: https://github.com/actions/runner-images#available-images.
|
||||
runs-on: macos-14
|
||||
runs-on: macos-15
|
||||
|
||||
# When a contributor maintains a fork of the repo, any pull request they make
|
||||
# to their own fork, or to the main repository, will trigger two CI runs:
|
||||
|
@ -123,10 +123,10 @@ jobs:
|
|||
include:
|
||||
- job-type: standard
|
||||
file-env: './ci/test/00_setup_env_mac_native.sh'
|
||||
job-name: 'macOS 14 native, arm64, no depends, sqlite only, gui'
|
||||
job-name: 'macOS native, no depends, sqlite only, gui'
|
||||
- job-type: fuzz
|
||||
file-env: './ci/test/00_setup_env_mac_native_fuzz.sh'
|
||||
job-name: 'macOS 14 native, arm64, fuzz'
|
||||
job-name: 'macOS native, fuzz'
|
||||
|
||||
env:
|
||||
DANGER_RUN_CI_ON_HOST: 1
|
||||
|
@ -145,8 +145,8 @@ jobs:
|
|||
# Use the earliest Xcode supported by the version of macOS denoted in
|
||||
# doc/release-notes-empty-template.md and providing at least the
|
||||
# minimum clang version denoted in doc/dependencies.md.
|
||||
# See: https://developer.apple.com/documentation/xcode-release-notes/xcode-15-release-notes
|
||||
sudo xcode-select --switch /Applications/Xcode_15.0.app
|
||||
# See: https://developer.apple.com/documentation/xcode-release-notes/xcode-16-release-notes
|
||||
sudo xcode-select --switch /Applications/Xcode_16.0.app
|
||||
clang --version
|
||||
|
||||
- name: Install Homebrew packages
|
||||
|
@ -211,11 +211,16 @@ jobs:
|
|||
steps:
|
||||
- *CHECKOUT
|
||||
|
||||
- name: Configure Developer Command Prompt for Microsoft Visual C++
|
||||
# Using microsoft/setup-msbuild is not enough.
|
||||
uses: ilammy/msvc-dev-cmd@v1
|
||||
with:
|
||||
arch: x64
|
||||
- &SET_UP_VS
|
||||
name: Set up VS Developer Prompt
|
||||
shell: pwsh -Command "$PSVersionTable; $PSNativeCommandUseErrorActionPreference = $true; $ErrorActionPreference = 'Stop'; & '{0}'"
|
||||
run: |
|
||||
$vswherePath = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
|
||||
$installationPath = & $vswherePath -latest -property installationPath
|
||||
& "${env:COMSPEC}" /s /c "`"$installationPath\Common7\Tools\vsdevcmd.bat`" -arch=x64 -no_logo && set" | foreach-object {
|
||||
$name, $value = $_ -split '=', 2
|
||||
echo "$name=$value" >> $env:GITHUB_ENV
|
||||
}
|
||||
|
||||
- name: Get tool information
|
||||
shell: pwsh
|
||||
|
@ -263,14 +268,26 @@ jobs:
|
|||
run: |
|
||||
cmake --build . -j $NUMBER_OF_PROCESSORS --config Release
|
||||
|
||||
- name: Get bitcoind manifest
|
||||
- name: Check executable manifests
|
||||
if: matrix.job-type == 'standard'
|
||||
working-directory: build
|
||||
shell: pwsh -Command "$PSVersionTable; $PSNativeCommandUseErrorActionPreference = $true; $ErrorActionPreference = 'Stop'; & '{0}'"
|
||||
run: |
|
||||
mt.exe -nologo -inputresource:bin/Release/bitcoind.exe -out:bitcoind.manifest
|
||||
cat bitcoind.manifest
|
||||
echo
|
||||
mt.exe -nologo -inputresource:bin/Release/bitcoind.exe -validate_manifest
|
||||
mt.exe -nologo -inputresource:bin\Release\bitcoind.exe -out:bitcoind.manifest
|
||||
Get-Content bitcoind.manifest
|
||||
|
||||
Get-ChildItem -Filter "bin\Release\*.exe" | ForEach-Object {
|
||||
$exeName = $_.Name
|
||||
|
||||
# Skip as they currently do not have manifests
|
||||
if ($exeName -eq "fuzz.exe" -or $exeName -eq "bench_bitcoin.exe" -or $exeName -eq "test_bitcoin-qt.exe") {
|
||||
Write-Host "Skipping $exeName (no manifest present)"
|
||||
return
|
||||
}
|
||||
|
||||
Write-Host "Checking $exeName"
|
||||
& mt.exe -nologo -inputresource:$_.FullName -validate_manifest
|
||||
}
|
||||
|
||||
- name: Run test suite
|
||||
if: matrix.job-type == 'standard'
|
||||
|
@ -370,19 +387,26 @@ jobs:
|
|||
- name: Run bitcoind.exe
|
||||
run: ./bin/bitcoind.exe -version
|
||||
|
||||
- name: Find mt.exe tool
|
||||
shell: pwsh
|
||||
run: |
|
||||
$sdk_dir = (Get-ItemProperty 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows Kits\Installed Roots' -Name KitsRoot10).KitsRoot10
|
||||
$sdk_latest = (Get-ChildItem "$sdk_dir\bin" -Directory | Where-Object { $_.Name -match '^\d+\.\d+\.\d+\.\d+$' } | Sort-Object Name -Descending | Select-Object -First 1).Name
|
||||
"MT_EXE=${sdk_dir}bin\${sdk_latest}\x64\mt.exe" >> $env:GITHUB_ENV
|
||||
- *SET_UP_VS
|
||||
|
||||
- name: Get bitcoind manifest
|
||||
shell: pwsh
|
||||
- name: Check executable manifests
|
||||
shell: pwsh -Command "$PSVersionTable; $PSNativeCommandUseErrorActionPreference = $true; $ErrorActionPreference = 'Stop'; & '{0}'"
|
||||
run: |
|
||||
& $env:MT_EXE -nologo -inputresource:bin\bitcoind.exe -out:bitcoind.manifest
|
||||
mt.exe -nologo -inputresource:bin\bitcoind.exe -out:bitcoind.manifest
|
||||
Get-Content bitcoind.manifest
|
||||
& $env:MT_EXE -nologo -inputresource:bin\bitcoind.exe -validate_manifest
|
||||
|
||||
Get-ChildItem -Filter "bin\*.exe" | ForEach-Object {
|
||||
$exeName = $_.Name
|
||||
|
||||
# Skip as they currently do not have manifests
|
||||
if ($exeName -eq "fuzz.exe" -or $exeName -eq "bench_bitcoin.exe") {
|
||||
Write-Host "Skipping $exeName (no manifest present)"
|
||||
return
|
||||
}
|
||||
|
||||
Write-Host "Checking $exeName"
|
||||
& mt.exe -nologo -inputresource:$_.FullName -validate_manifest
|
||||
}
|
||||
|
||||
- name: Run unit tests
|
||||
# Can't use ctest here like other jobs as we don't have a CMake build tree.
|
||||
|
|
|
@ -41,10 +41,10 @@ python3 --version
|
|||
${CI_RETRY_EXE} pip3 install \
|
||||
codespell==2.4.1 \
|
||||
lief==0.16.6 \
|
||||
mypy==1.4.1 \
|
||||
pyzmq==25.1.0 \
|
||||
ruff==0.5.5 \
|
||||
vulture==2.6
|
||||
mypy==1.18.2 \
|
||||
pyzmq==27.1.0 \
|
||||
ruff==0.13.2 \
|
||||
vulture==2.14
|
||||
|
||||
SHELLCHECK_VERSION=v0.11.0
|
||||
curl -sL "https://github.com/koalaman/shellcheck/releases/download/${SHELLCHECK_VERSION}/shellcheck-${SHELLCHECK_VERSION}.linux.x86_64.tar.xz" | \
|
||||
|
|
|
@ -8,7 +8,7 @@ export LC_ALL=C.UTF-8
|
|||
|
||||
export CONTAINER_NAME="ci_mac_native_fuzz" # macos does not use a container, but the env var is needed for logging
|
||||
export CMAKE_GENERATOR="Ninja"
|
||||
export BITCOIN_CONFIG="-DBUILD_FOR_FUZZING=ON -DCMAKE_EXE_LINKER_FLAGS='-Wl,-stack_size -Wl,0x80000'"
|
||||
export BITCOIN_CONFIG="-DBUILD_FOR_FUZZING=ON -DCMAKE_EXE_LINKER_FLAGS='-Wl,-stack_size -Wl,0x80000' -DAPPEND_CPPFLAGS='-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG'"
|
||||
export CI_OS_NAME="macos"
|
||||
export NO_DEPENDS=1
|
||||
export OSX_SDK=""
|
||||
|
|
|
@ -130,7 +130,8 @@ if [[ "${RUN_TIDY}" == "true" ]]; then
|
|||
BITCOIN_CONFIG_ALL="$BITCOIN_CONFIG_ALL -DCMAKE_EXPORT_COMPILE_COMMANDS=ON"
|
||||
fi
|
||||
|
||||
bash -c "cmake -S $BASE_ROOT_DIR -B ${BASE_BUILD_DIR} $BITCOIN_CONFIG_ALL $BITCOIN_CONFIG" || (
|
||||
eval "CMAKE_ARGS=($BITCOIN_CONFIG_ALL $BITCOIN_CONFIG)"
|
||||
cmake -S "$BASE_ROOT_DIR" -B "$BASE_BUILD_DIR" "${CMAKE_ARGS[@]}" || (
|
||||
cd "${BASE_BUILD_DIR}"
|
||||
# shellcheck disable=SC2046
|
||||
cat $(cmake -P "${BASE_ROOT_DIR}/ci/test/GetCMakeLogFiles.cmake")
|
||||
|
|
|
@ -112,7 +112,6 @@ ELF_ALLOWED_LIBRARIES = {
|
|||
'libfontconfig.so.1', # font support
|
||||
'libfreetype.so.6', # font parsing
|
||||
'libdl.so.2', # programming interface to dynamic linker
|
||||
'libxcb-cursor.so.0',
|
||||
'libxcb-icccm.so.4',
|
||||
'libxcb-image.so.0',
|
||||
'libxcb-shm.so.0',
|
||||
|
@ -249,7 +248,7 @@ def check_MACHO_libraries(binary) -> bool:
|
|||
return ok
|
||||
|
||||
def check_MACHO_min_os(binary) -> bool:
|
||||
if binary.build_version.minos == [13,0,0]:
|
||||
if binary.build_version.minos == [14,0,0]:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
|
|
@ -460,15 +460,15 @@ if config.translations_dir:
|
|||
sys.stderr.write(f"Error: Could not find translation dir \"{config.translations_dir[0]}\"\n")
|
||||
sys.exit(1)
|
||||
|
||||
print("+ Adding Qt translations +")
|
||||
print("+ Adding Qt translations +")
|
||||
|
||||
translations = Path(config.translations_dir[0])
|
||||
translations = Path(config.translations_dir[0])
|
||||
|
||||
regex = re.compile('qt_[a-z]*(.qm|_[A-Z]*.qm)')
|
||||
regex = re.compile('qt_[a-z]*(.qm|_[A-Z]*.qm)')
|
||||
|
||||
lang_files = [x for x in translations.iterdir() if regex.match(x.name)]
|
||||
lang_files = [x for x in translations.iterdir() if regex.match(x.name)]
|
||||
|
||||
for file in lang_files:
|
||||
for file in lang_files:
|
||||
if verbose:
|
||||
print(file.as_posix(), "->", os.path.join(applicationBundle.resourcesPath, file.name))
|
||||
shutil.copy2(file.as_posix(), os.path.join(applicationBundle.resourcesPath, file.name))
|
||||
|
|
|
@ -36,9 +36,8 @@ define fetch_file_inner
|
|||
endef
|
||||
|
||||
define fetch_file
|
||||
( test -f $$($(1)_source_dir)/$(4) || \
|
||||
( $(call fetch_file_inner,$(1),$(2),$(3),$(4),$(5)) || \
|
||||
$(call fetch_file_inner,$(1),$(FALLBACK_DOWNLOAD_PATH),$(3),$(4),$(5))))
|
||||
$(call fetch_file_inner,$(1),$(FALLBACK_DOWNLOAD_PATH),$(3),$(4),$(5)))
|
||||
endef
|
||||
|
||||
# Shell script to create a source tarball in $(1)_source from local directory
|
||||
|
@ -109,7 +108,7 @@ $(1)_prefixbin:=$($($(1)_type)_prefix)/bin/
|
|||
$(1)_all_sources=$($(1)_file_name) $($(1)_extra_sources)
|
||||
|
||||
#stamps
|
||||
$(1)_fetched=$(SOURCES_PATH)/download-stamps/.stamp_fetched-$(1)-$($(1)_file_name).hash
|
||||
$(1)_fetched=$(SOURCES_PATH)/download-stamps/.stamp_fetched-$(1)-$($(1)_version)-$($(1)_sha256_hash).hash
|
||||
$(1)_extracted=$$($(1)_extract_dir)/.stamp_extracted
|
||||
$(1)_preprocessed=$$($(1)_extract_dir)/.stamp_preprocessed
|
||||
$(1)_cleaned=$$($(1)_extract_dir)/.stamp_cleaned
|
||||
|
@ -247,7 +246,6 @@ endif
|
|||
$($(1)_fetched):
|
||||
mkdir -p $$(@D) $(SOURCES_PATH)
|
||||
rm -f $$@
|
||||
touch $$@
|
||||
cd $$(@D); $($(1)_fetch_cmds)
|
||||
cd $($(1)_source_dir); $(foreach source,$($(1)_all_sources),$(build_SHA256SUM) $(source) >> $$(@);)
|
||||
touch $$@
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
OSX_MIN_VERSION=13.0
|
||||
OSX_MIN_VERSION=14.0
|
||||
OSX_SDK_VERSION=14.0
|
||||
XCODE_VERSION=15.0
|
||||
XCODE_BUILD_ID=15A240d
|
||||
|
|
|
@ -6,7 +6,7 @@ $(package)_sha256_hash=0e9c5446dc6f3beb8af6ebfcc9e27bcc6da6fe2860f7fc07b99144dfa
|
|||
$(package)_dependencies=libxcb libxcb_util_render libxcb_util_image
|
||||
|
||||
define $(package)_set_vars
|
||||
$(package)_config_opts = --disable-static
|
||||
$(package)_config_opts = --disable-shared
|
||||
$(package)_config_opts += --disable-dependency-tracking --enable-option-checking
|
||||
endef
|
||||
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
package=qrencode
|
||||
$(package)_version=4.1.1
|
||||
$(package)_download_path=https://fukuchi.org/works/qrencode/
|
||||
$(package)_download_path=https://github.com/fukuchi/libqrencode/archive/refs/tags/
|
||||
$(package)_download_file=v$($(package)_version).tar.gz
|
||||
$(package)_file_name=$(package)-$($(package)_version).tar.gz
|
||||
$(package)_sha256_hash=da448ed4f52aba6bcb0cd48cac0dd51b8692bccc4cd127431402fca6f8171e8e
|
||||
$(package)_sha256_hash=5385bc1b8c2f20f3b91d258bf8ccc8cf62023935df2d2676b5b67049f31a049c
|
||||
$(package)_patches=cmake_fixups.patch
|
||||
|
||||
define $(package)_set_vars
|
||||
|
|
|
@ -81,8 +81,6 @@ the necessary parts of Qt, the libqrencode and pass `-DBUILD_GUI=ON`. Skip if yo
|
|||
|
||||
sudo apt-get install qt6-base-dev qt6-tools-dev qt6-l10n-tools qt6-tools-dev-tools libgl-dev
|
||||
|
||||
For Qt 6.5 and later, the `libxcb-cursor0` package must be installed at runtime.
|
||||
|
||||
Additionally, to support Wayland protocol for modern desktop environments:
|
||||
|
||||
sudo apt install qt6-wayland
|
||||
|
@ -133,8 +131,6 @@ the necessary parts of Qt, the libqrencode and pass `-DBUILD_GUI=ON`. Skip if yo
|
|||
|
||||
sudo dnf install qt6-qtbase-devel qt6-qttools-devel
|
||||
|
||||
For Qt 6.5 and later, the `xcb-util-cursor` package must be installed at runtime.
|
||||
|
||||
Additionally, to support Wayland protocol for modern desktop environments:
|
||||
|
||||
sudo dnf install qt6-qtwayland
|
||||
|
@ -182,8 +178,6 @@ the necessary parts of Qt, the libqrencode and pass `-DBUILD_GUI=ON`. Skip if yo
|
|||
|
||||
apk add qt6-qtbase-dev qt6-qttools-dev
|
||||
|
||||
For Qt 6.5 and later, the `xcb-util-cursor` package must be installed at runtime.
|
||||
|
||||
The GUI will be able to encode addresses in QR codes unless this feature is explicitly disabled. To install libqrencode, run:
|
||||
|
||||
apk add libqrencode-dev
|
||||
|
|
|
@ -36,7 +36,7 @@ Compatibility
|
|||
==============
|
||||
|
||||
Bitcoin Core is supported and tested on operating systems using the
|
||||
Linux Kernel 3.17+, macOS 13+, and Windows 10+. Bitcoin
|
||||
Linux Kernel 3.17+, macOS 14+, and Windows 10+. 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.
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<plist version="0.9">
|
||||
<dict>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>13</string>
|
||||
<string>14</string>
|
||||
|
||||
<key>LSArchitecturePriority</key>
|
||||
<array>
|
||||
|
|
|
@ -24,7 +24,7 @@ static void VerifyScriptBench(benchmark::Bench& bench)
|
|||
{
|
||||
ECC_Context ecc_context{};
|
||||
|
||||
const uint32_t flags{SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH};
|
||||
const script_verify_flags flags{SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH};
|
||||
const int witnessversion = 0;
|
||||
|
||||
// Key pair.
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include <chain.h>
|
||||
#include <tinyformat.h>
|
||||
#include <util/check.h>
|
||||
#include <util/time.h>
|
||||
|
||||
std::string CBlockFileInfo::ToString() const
|
||||
|
@ -158,18 +159,26 @@ int64_t GetBlockProofEquivalentTime(const CBlockIndex& to, const CBlockIndex& fr
|
|||
/** Find the last common ancestor two blocks have.
|
||||
* Both pa and pb must be non-nullptr. */
|
||||
const CBlockIndex* LastCommonAncestor(const CBlockIndex* pa, const CBlockIndex* pb) {
|
||||
// First rewind to the last common height (the forking point cannot be past one of the two).
|
||||
if (pa->nHeight > pb->nHeight) {
|
||||
pa = pa->GetAncestor(pb->nHeight);
|
||||
} else if (pb->nHeight > pa->nHeight) {
|
||||
pb = pb->GetAncestor(pa->nHeight);
|
||||
}
|
||||
|
||||
while (pa != pb && pa && pb) {
|
||||
while (pa != pb) {
|
||||
// Jump back until pa and pb have a common "skip" ancestor.
|
||||
while (pa->pskip != pb->pskip) {
|
||||
// This logic relies on the property that equal-height blocks have equal-height skip
|
||||
// pointers.
|
||||
Assume(pa->nHeight == pb->nHeight);
|
||||
Assume(pa->pskip->nHeight == pb->pskip->nHeight);
|
||||
pa = pa->pskip;
|
||||
pb = pb->pskip;
|
||||
}
|
||||
// At this point, pa and pb are different, but have equal pskip. The forking point lies in
|
||||
// between pa/pb on the one end, and pa->pskip/pb->pskip on the other end.
|
||||
pa = pa->pprev;
|
||||
pb = pb->pprev;
|
||||
}
|
||||
|
||||
// Eventually all chain branches meet at the genesis block.
|
||||
assert(pa == pb);
|
||||
return pa;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#ifndef BITCOIN_CONSENSUS_PARAMS_H
|
||||
#define BITCOIN_CONSENSUS_PARAMS_H
|
||||
|
||||
#include <script/verify_flags.h>
|
||||
#include <uint256.h>
|
||||
|
||||
#include <array>
|
||||
|
@ -89,7 +90,7 @@ struct Params {
|
|||
* - buried in the chain, and
|
||||
* - fail if the default script verify flags are applied.
|
||||
*/
|
||||
std::map<uint256, uint32_t> script_flag_exceptions;
|
||||
std::map<uint256, script_verify_flags> script_flag_exceptions;
|
||||
/** Block height and hash at which BIP34 becomes active */
|
||||
int BIP34Height;
|
||||
uint256 BIP34Hash;
|
||||
|
|
|
@ -140,7 +140,7 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& in
|
|||
return nSigOps;
|
||||
}
|
||||
|
||||
int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& inputs, uint32_t flags)
|
||||
int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& inputs, script_verify_flags flags)
|
||||
{
|
||||
int64_t nSigOps = GetLegacySigOpCount(tx) * WITNESS_SCALE_FACTOR;
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#define BITCOIN_CONSENSUS_TX_VERIFY_H
|
||||
|
||||
#include <consensus/amount.h>
|
||||
#include <script/verify_flags.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
@ -52,7 +53,7 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& ma
|
|||
* @param[in] flags Script verification flags
|
||||
* @return Total signature operation cost of tx
|
||||
*/
|
||||
int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& inputs, uint32_t flags);
|
||||
int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& inputs, script_verify_flags flags);
|
||||
|
||||
/**
|
||||
* Check if transaction is final and can be included in a block with the
|
||||
|
|
|
@ -8,8 +8,10 @@
|
|||
#include <consensus/params.h>
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
struct VBDeploymentInfo {
|
||||
/** Deployment name */
|
||||
|
|
|
@ -119,7 +119,7 @@ namespace sam {
|
|||
|
||||
Session::Session(const fs::path& private_key_file,
|
||||
const Proxy& control_host,
|
||||
CThreadInterrupt* interrupt)
|
||||
std::shared_ptr<CThreadInterrupt> interrupt)
|
||||
: m_private_key_file{private_key_file},
|
||||
m_control_host{control_host},
|
||||
m_interrupt{interrupt},
|
||||
|
@ -127,7 +127,7 @@ Session::Session(const fs::path& private_key_file,
|
|||
{
|
||||
}
|
||||
|
||||
Session::Session(const Proxy& control_host, CThreadInterrupt* interrupt)
|
||||
Session::Session(const Proxy& control_host, std::shared_ptr<CThreadInterrupt> interrupt)
|
||||
: m_control_host{control_host},
|
||||
m_interrupt{interrupt},
|
||||
m_transient{true}
|
||||
|
@ -162,7 +162,7 @@ bool Session::Accept(Connection& conn)
|
|||
std::string errmsg;
|
||||
bool disconnect{false};
|
||||
|
||||
while (!*m_interrupt) {
|
||||
while (!m_interrupt->interrupted()) {
|
||||
Sock::Event occurred;
|
||||
if (!conn.sock->Wait(MAX_WAIT_FOR_IO, Sock::RECV, &occurred)) {
|
||||
errmsg = "wait on socket failed";
|
||||
|
@ -205,7 +205,7 @@ bool Session::Accept(Connection& conn)
|
|||
return true;
|
||||
}
|
||||
|
||||
if (*m_interrupt) {
|
||||
if (m_interrupt->interrupted()) {
|
||||
LogPrintLevel(BCLog::I2P, BCLog::Level::Debug, "Accept was interrupted\n");
|
||||
} else {
|
||||
LogPrintLevel(BCLog::I2P, BCLog::Level::Debug, "Error accepting%s: %s\n", disconnect ? " (will close the session)" : "", errmsg);
|
||||
|
|
14
src/i2p.h
14
src/i2p.h
|
@ -63,13 +63,11 @@ public:
|
|||
* private key will be generated and saved into the file.
|
||||
* @param[in] control_host Location of the SAM proxy.
|
||||
* @param[in,out] interrupt If this is signaled then all operations are canceled as soon as
|
||||
* possible and executing methods throw an exception. Notice: only a pointer to the
|
||||
* `CThreadInterrupt` object is saved, so it must not be destroyed earlier than this
|
||||
* `Session` object.
|
||||
* possible and executing methods throw an exception.
|
||||
*/
|
||||
Session(const fs::path& private_key_file,
|
||||
const Proxy& control_host,
|
||||
CThreadInterrupt* interrupt);
|
||||
std::shared_ptr<CThreadInterrupt> interrupt);
|
||||
|
||||
/**
|
||||
* Construct a transient session which will generate its own I2P private key
|
||||
|
@ -78,11 +76,9 @@ public:
|
|||
* the session will be lazily created later when first used.
|
||||
* @param[in] control_host Location of the SAM proxy.
|
||||
* @param[in,out] interrupt If this is signaled then all operations are canceled as soon as
|
||||
* possible and executing methods throw an exception. Notice: only a pointer to the
|
||||
* `CThreadInterrupt` object is saved, so it must not be destroyed earlier than this
|
||||
* `Session` object.
|
||||
* possible and executing methods throw an exception.
|
||||
*/
|
||||
Session(const Proxy& control_host, CThreadInterrupt* interrupt);
|
||||
Session(const Proxy& control_host, std::shared_ptr<CThreadInterrupt> interrupt);
|
||||
|
||||
/**
|
||||
* Destroy the session, closing the internally used sockets. The sockets that have been
|
||||
|
@ -235,7 +231,7 @@ private:
|
|||
/**
|
||||
* Cease network activity when this is signaled.
|
||||
*/
|
||||
CThreadInterrupt* const m_interrupt;
|
||||
const std::shared_ptr<CThreadInterrupt> m_interrupt;
|
||||
|
||||
/**
|
||||
* Mutex protecting the members that can be concurrently accessed.
|
||||
|
|
|
@ -658,9 +658,9 @@ void SetupServerArgs(ArgsManager& argsman, bool can_listen_ipc)
|
|||
argsman.AddArg("-dustrelayfee=<amt>", strprintf("Fee rate (in %s/kvB) used to define dust, the value of an output such that it will cost more than its value in fees at this fee rate to spend it. (default: %s)", CURRENCY_UNIT, FormatMoney(DUST_RELAY_TX_FEE)), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::NODE_RELAY);
|
||||
argsman.AddArg("-acceptstalefeeestimates", strprintf("Read fee estimates even if they are stale (%sdefault: %u) fee estimates are considered stale if they are %s hours old", "regtest only; ", DEFAULT_ACCEPT_STALE_FEE_ESTIMATES, Ticks<std::chrono::hours>(MAX_FILE_AGE)), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
|
||||
argsman.AddArg("-bytespersigop", strprintf("Equivalent bytes per sigop in transactions for relay and mining (default: %u)", DEFAULT_BYTES_PER_SIGOP), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
|
||||
argsman.AddArg("-datacarrier", strprintf("(DEPRECATED) Relay and mine data carrier transactions (default: %u)", DEFAULT_ACCEPT_DATACARRIER), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
|
||||
argsman.AddArg("-datacarrier", strprintf("Relay and mine data carrier transactions (default: %u)", DEFAULT_ACCEPT_DATACARRIER), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
|
||||
argsman.AddArg("-datacarriersize",
|
||||
strprintf("(DEPRECATED) Relay and mine transactions whose data-carrying raw scriptPubKeys in aggregate "
|
||||
strprintf("Relay and mine transactions whose data-carrying raw scriptPubKeys in aggregate "
|
||||
"are of this size or less, allowing multiple outputs (default: %u)",
|
||||
MAX_OP_RETURN_RELAY),
|
||||
ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
|
||||
|
@ -903,10 +903,6 @@ bool AppInitParameterInteraction(const ArgsManager& args)
|
|||
InitWarning(_("Option '-checkpoints' is set but checkpoints were removed. This option has no effect."));
|
||||
}
|
||||
|
||||
if (args.IsArgSet("-datacarriersize") || args.IsArgSet("-datacarrier")) {
|
||||
InitWarning(_("Options '-datacarrier' or '-datacarriersize' are set but are marked as deprecated and are expected to be removed in a future version."));
|
||||
}
|
||||
|
||||
// We no longer limit the orphanage based on number of transactions but keep the option to warn users who still have it in their config.
|
||||
if (args.IsArgSet("-maxorphantx")) {
|
||||
InitWarning(_("Option '-maxorphantx' is set but no longer has any effect (see release notes). Please remove it from your configuration."));
|
||||
|
|
190
src/net.cpp
190
src/net.cpp
|
@ -108,7 +108,7 @@ const std::string NET_MESSAGE_TYPE_OTHER = "*other*";
|
|||
|
||||
static const uint64_t RANDOMIZER_ID_NETGROUP = 0x6c0edd8036ef4036ULL; // SHA256("netgroup")[0:8]
|
||||
static const uint64_t RANDOMIZER_ID_LOCALHOSTNONCE = 0xd93e69e2bbfa5735ULL; // SHA256("localhostnonce")[0:8]
|
||||
static const uint64_t RANDOMIZER_ID_ADDRCACHE = 0x1cf2e4ddd306dda9ULL; // SHA256("addrcache")[0:8]
|
||||
static const uint64_t RANDOMIZER_ID_NETWORKKEY = 0x0e8a2b136c592a7dULL; // SHA256("networkkey")[0:8]
|
||||
//
|
||||
// Global state variables
|
||||
//
|
||||
|
@ -331,42 +331,22 @@ bool IsLocal(const CService& addr)
|
|||
return mapLocalHost.count(addr) > 0;
|
||||
}
|
||||
|
||||
CNode* CConnman::FindNode(const CNetAddr& ip)
|
||||
bool CConnman::AlreadyConnectedToHost(const std::string& host) const
|
||||
{
|
||||
LOCK(m_nodes_mutex);
|
||||
for (CNode* pnode : m_nodes) {
|
||||
if (static_cast<CNetAddr>(pnode->addr) == ip) {
|
||||
return pnode;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
return std::ranges::any_of(m_nodes, [&host](CNode* node) { return node->m_addr_name == host; });
|
||||
}
|
||||
|
||||
CNode* CConnman::FindNode(const std::string& addrName)
|
||||
bool CConnman::AlreadyConnectedToAddressPort(const CService& addr_port) const
|
||||
{
|
||||
LOCK(m_nodes_mutex);
|
||||
for (CNode* pnode : m_nodes) {
|
||||
if (pnode->m_addr_name == addrName) {
|
||||
return pnode;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
return std::ranges::any_of(m_nodes, [&addr_port](CNode* node) { return node->addr == addr_port; });
|
||||
}
|
||||
|
||||
CNode* CConnman::FindNode(const CService& addr)
|
||||
bool CConnman::AlreadyConnectedToAddress(const CNetAddr& addr) const
|
||||
{
|
||||
LOCK(m_nodes_mutex);
|
||||
for (CNode* pnode : m_nodes) {
|
||||
if (static_cast<CService>(pnode->addr) == addr) {
|
||||
return pnode;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool CConnman::AlreadyConnectedToAddress(const CAddress& addr)
|
||||
{
|
||||
return FindNode(static_cast<CNetAddr>(addr));
|
||||
return std::ranges::any_of(m_nodes, [&addr](CNode* node) { return node->addr == addr; });
|
||||
}
|
||||
|
||||
bool CConnman::CheckIncomingNonce(uint64_t nonce)
|
||||
|
@ -393,7 +373,12 @@ static CService GetBindAddress(const Sock& sock)
|
|||
return addr_bind;
|
||||
}
|
||||
|
||||
CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure, ConnectionType conn_type, bool use_v2transport)
|
||||
CNode* CConnman::ConnectNode(CAddress addrConnect,
|
||||
const char* pszDest,
|
||||
bool fCountFailure,
|
||||
ConnectionType conn_type,
|
||||
bool use_v2transport,
|
||||
const std::optional<Proxy>& proxy_override)
|
||||
{
|
||||
AssertLockNotHeld(m_unused_i2p_sessions_mutex);
|
||||
assert(conn_type != ConnectionType::INBOUND);
|
||||
|
@ -403,10 +388,8 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
|
|||
return nullptr;
|
||||
|
||||
// Look for an existing connection
|
||||
CNode* pnode = FindNode(static_cast<CService>(addrConnect));
|
||||
if (pnode)
|
||||
{
|
||||
LogPrintf("Failed to open new connection, already connected\n");
|
||||
if (AlreadyConnectedToAddressPort(addrConnect)) {
|
||||
LogInfo("Failed to open new connection to %s, already connected", addrConnect.ToStringAddrPort());
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
@ -436,9 +419,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
|
|||
}
|
||||
// It is possible that we already have a connection to the IP/port pszDest resolved to.
|
||||
// In that case, drop the connection that was just created.
|
||||
LOCK(m_nodes_mutex);
|
||||
CNode* pnode = FindNode(static_cast<CService>(addrConnect));
|
||||
if (pnode) {
|
||||
if (AlreadyConnectedToAddressPort(addrConnect)) {
|
||||
LogPrintf("Not opening a connection to %s, already connected to %s\n", pszDest, addrConnect.ToStringAddrPort());
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -463,7 +444,13 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
|
|||
|
||||
for (auto& target_addr: connect_to) {
|
||||
if (target_addr.IsValid()) {
|
||||
const bool use_proxy{GetProxy(target_addr.GetNetwork(), proxy)};
|
||||
bool use_proxy;
|
||||
if (proxy_override.has_value()) {
|
||||
use_proxy = true;
|
||||
proxy = proxy_override.value();
|
||||
} else {
|
||||
use_proxy = GetProxy(target_addr.GetNetwork(), proxy);
|
||||
}
|
||||
bool proxyConnectionFailed = false;
|
||||
|
||||
if (target_addr.IsI2P() && use_proxy) {
|
||||
|
@ -477,7 +464,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
|
|||
LOCK(m_unused_i2p_sessions_mutex);
|
||||
if (m_unused_i2p_sessions.empty()) {
|
||||
i2p_transient_session =
|
||||
std::make_unique<i2p::sam::Session>(proxy, &interruptNet);
|
||||
std::make_unique<i2p::sam::Session>(proxy, m_interrupt_net);
|
||||
} else {
|
||||
i2p_transient_session.swap(m_unused_i2p_sessions.front());
|
||||
m_unused_i2p_sessions.pop();
|
||||
|
@ -530,6 +517,13 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
|
|||
if (!addr_bind.IsValid()) {
|
||||
addr_bind = GetBindAddress(*sock);
|
||||
}
|
||||
uint64_t network_id = GetDeterministicRandomizer(RANDOMIZER_ID_NETWORKKEY)
|
||||
.Write(target_addr.GetNetClass())
|
||||
.Write(addr_bind.GetAddrBytes())
|
||||
// For outbound connections, the port of the bound address is randomly
|
||||
// assigned by the OS and would therefore not be useful for seeding.
|
||||
.Write(0)
|
||||
.Finalize();
|
||||
CNode* pnode = new CNode(id,
|
||||
std::move(sock),
|
||||
target_addr,
|
||||
|
@ -539,6 +533,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
|
|||
pszDest ? pszDest : "",
|
||||
conn_type,
|
||||
/*inbound_onion=*/false,
|
||||
network_id,
|
||||
CNodeOptions{
|
||||
.permission_flags = permission_flags,
|
||||
.i2p_sam_session = std::move(i2p_transient_session),
|
||||
|
@ -1832,6 +1827,11 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
|
|||
ServiceFlags local_services = GetLocalServices();
|
||||
const bool use_v2transport(local_services & NODE_P2P_V2);
|
||||
|
||||
uint64_t network_id = GetDeterministicRandomizer(RANDOMIZER_ID_NETWORKKEY)
|
||||
.Write(inbound_onion ? NET_ONION : addr.GetNetClass())
|
||||
.Write(addr_bind.GetAddrBytes())
|
||||
.Write(addr_bind.GetPort()) // inbound connections use bind port
|
||||
.Finalize();
|
||||
CNode* pnode = new CNode(id,
|
||||
std::move(sock),
|
||||
CAddress{addr, NODE_NONE},
|
||||
|
@ -1841,6 +1841,7 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
|
|||
/*addrNameIn=*/"",
|
||||
ConnectionType::INBOUND,
|
||||
inbound_onion,
|
||||
network_id,
|
||||
CNodeOptions{
|
||||
.permission_flags = permission_flags,
|
||||
.prefer_evict = discouraged,
|
||||
|
@ -2103,7 +2104,7 @@ void CConnman::SocketHandler()
|
|||
// empty sets.
|
||||
events_per_sock = GenerateWaitSockets(snap.Nodes());
|
||||
if (events_per_sock.empty() || !events_per_sock.begin()->first->WaitMany(timeout, events_per_sock)) {
|
||||
interruptNet.sleep_for(timeout);
|
||||
m_interrupt_net->sleep_for(timeout);
|
||||
}
|
||||
|
||||
// Service (send/receive) each of the already connected nodes.
|
||||
|
@ -2120,8 +2121,9 @@ void CConnman::SocketHandlerConnected(const std::vector<CNode*>& nodes,
|
|||
AssertLockNotHeld(m_total_bytes_sent_mutex);
|
||||
|
||||
for (CNode* pnode : nodes) {
|
||||
if (interruptNet)
|
||||
if (m_interrupt_net->interrupted()) {
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Receive
|
||||
|
@ -2216,7 +2218,7 @@ void CConnman::SocketHandlerConnected(const std::vector<CNode*>& nodes,
|
|||
void CConnman::SocketHandlerListening(const Sock::EventsPerSock& events_per_sock)
|
||||
{
|
||||
for (const ListenSocket& listen_socket : vhListenSocket) {
|
||||
if (interruptNet) {
|
||||
if (m_interrupt_net->interrupted()) {
|
||||
return;
|
||||
}
|
||||
const auto it = events_per_sock.find(listen_socket.sock);
|
||||
|
@ -2230,8 +2232,7 @@ void CConnman::ThreadSocketHandler()
|
|||
{
|
||||
AssertLockNotHeld(m_total_bytes_sent_mutex);
|
||||
|
||||
while (!interruptNet)
|
||||
{
|
||||
while (!m_interrupt_net->interrupted()) {
|
||||
DisconnectNodes();
|
||||
NotifyNumConnectionsChanged();
|
||||
SocketHandler();
|
||||
|
@ -2255,9 +2256,10 @@ void CConnman::ThreadDNSAddressSeed()
|
|||
auto start = NodeClock::now();
|
||||
constexpr std::chrono::seconds SEEDNODE_TIMEOUT = 30s;
|
||||
LogPrintf("-seednode enabled. Trying the provided seeds for %d seconds before defaulting to the dnsseeds.\n", SEEDNODE_TIMEOUT.count());
|
||||
while (!interruptNet) {
|
||||
if (!interruptNet.sleep_for(std::chrono::milliseconds(500)))
|
||||
while (!m_interrupt_net->interrupted()) {
|
||||
if (!m_interrupt_net->sleep_for(500ms)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Abort if we have spent enough time without reaching our target.
|
||||
// Giving seed nodes 30 seconds so this does not become a race against fixedseeds (which triggers after 1 min)
|
||||
|
@ -2318,7 +2320,7 @@ void CConnman::ThreadDNSAddressSeed()
|
|||
// early to see if we have enough peers and can stop
|
||||
// this thread entirely freeing up its resources
|
||||
std::chrono::seconds w = std::min(DNSSEEDS_DELAY_FEW_PEERS, to_wait);
|
||||
if (!interruptNet.sleep_for(w)) return;
|
||||
if (!m_interrupt_net->sleep_for(w)) return;
|
||||
to_wait -= w;
|
||||
|
||||
if (GetFullOutboundConnCount() >= SEED_OUTBOUND_CONNECTION_THRESHOLD) {
|
||||
|
@ -2334,13 +2336,13 @@ void CConnman::ThreadDNSAddressSeed()
|
|||
}
|
||||
}
|
||||
|
||||
if (interruptNet) return;
|
||||
if (m_interrupt_net->interrupted()) return;
|
||||
|
||||
// hold off on querying seeds if P2P network deactivated
|
||||
if (!fNetworkActive) {
|
||||
LogPrintf("Waiting for network to be reactivated before querying DNS seeds.\n");
|
||||
do {
|
||||
if (!interruptNet.sleep_for(std::chrono::seconds{1})) return;
|
||||
if (!m_interrupt_net->sleep_for(1s)) return;
|
||||
} while (!fNetworkActive);
|
||||
}
|
||||
|
||||
|
@ -2535,12 +2537,14 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect, std
|
|||
OpenNetworkConnection(addr, false, {}, strAddr.c_str(), ConnectionType::MANUAL, /*use_v2transport=*/use_v2transport);
|
||||
for (int i = 0; i < 10 && i < nLoop; i++)
|
||||
{
|
||||
if (!interruptNet.sleep_for(std::chrono::milliseconds(500)))
|
||||
if (!m_interrupt_net->sleep_for(500ms)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!interruptNet.sleep_for(std::chrono::milliseconds(500)))
|
||||
}
|
||||
if (!m_interrupt_net->sleep_for(500ms)) {
|
||||
return;
|
||||
}
|
||||
PerformReconnections();
|
||||
}
|
||||
}
|
||||
|
@ -2564,8 +2568,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect, std
|
|||
LogPrintf("Fixed seeds are disabled\n");
|
||||
}
|
||||
|
||||
while (!interruptNet)
|
||||
{
|
||||
while (!m_interrupt_net->interrupted()) {
|
||||
if (add_addr_fetch) {
|
||||
add_addr_fetch = false;
|
||||
const auto& seed{SpanPopBack(seed_nodes)};
|
||||
|
@ -2580,14 +2583,16 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect, std
|
|||
|
||||
ProcessAddrFetch();
|
||||
|
||||
if (!interruptNet.sleep_for(std::chrono::milliseconds(500)))
|
||||
if (!m_interrupt_net->sleep_for(500ms)) {
|
||||
return;
|
||||
}
|
||||
|
||||
PerformReconnections();
|
||||
|
||||
CountingSemaphoreGrant<> grant(*semOutbound);
|
||||
if (interruptNet)
|
||||
if (m_interrupt_net->interrupted()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const std::unordered_set<Network> fixed_seed_networks{GetReachableEmptyNetworks()};
|
||||
if (add_fixed_seeds && !fixed_seed_networks.empty()) {
|
||||
|
@ -2761,8 +2766,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect, std
|
|||
int nTries = 0;
|
||||
const auto reachable_nets{g_reachable_nets.All()};
|
||||
|
||||
while (!interruptNet)
|
||||
{
|
||||
while (!m_interrupt_net->interrupted()) {
|
||||
if (anchor && !m_anchors.empty()) {
|
||||
const CAddress addr = m_anchors.back();
|
||||
m_anchors.pop_back();
|
||||
|
@ -2864,7 +2868,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect, std
|
|||
if (addrConnect.IsValid()) {
|
||||
if (fFeeler) {
|
||||
// Add small amount of random noise before connection to avoid synchronization.
|
||||
if (!interruptNet.sleep_for(rng.rand_uniform_duration<CThreadInterrupt::Clock>(FEELER_SLEEP_WINDOW))) {
|
||||
if (!m_interrupt_net->sleep_for(rng.rand_uniform_duration<CThreadInterrupt::Clock>(FEELER_SLEEP_WINDOW))) {
|
||||
return;
|
||||
}
|
||||
LogDebug(BCLog::NET, "Making feeler connection to %s\n", addrConnect.ToStringAddrPort());
|
||||
|
@ -2879,7 +2883,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect, std
|
|||
const bool count_failures{((int)outbound_ipv46_peer_netgroups.size() + outbound_privacy_network_peers) >= std::min(m_max_automatic_connections - 1, 2)};
|
||||
// Use BIP324 transport when both us and them have NODE_V2_P2P set.
|
||||
const bool use_v2transport(addrConnect.nServices & GetLocalServices() & NODE_P2P_V2);
|
||||
OpenNetworkConnection(addrConnect, count_failures, std::move(grant), /*strDest=*/nullptr, conn_type, use_v2transport);
|
||||
OpenNetworkConnection(addrConnect, count_failures, std::move(grant), /*pszDest=*/nullptr, conn_type, use_v2transport);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2975,19 +2979,26 @@ void CConnman::ThreadOpenAddedConnections()
|
|||
tried = true;
|
||||
CAddress addr(CService(), NODE_NONE);
|
||||
OpenNetworkConnection(addr, false, std::move(grant), info.m_params.m_added_node.c_str(), ConnectionType::MANUAL, info.m_params.m_use_v2transport);
|
||||
if (!interruptNet.sleep_for(std::chrono::milliseconds(500))) return;
|
||||
if (!m_interrupt_net->sleep_for(500ms)) return;
|
||||
grant = CountingSemaphoreGrant<>(*semAddnode, /*fTry=*/true);
|
||||
}
|
||||
// See if any reconnections are desired.
|
||||
PerformReconnections();
|
||||
// Retry every 60 seconds if a connection was attempted, otherwise two seconds
|
||||
if (!interruptNet.sleep_for(std::chrono::seconds(tried ? 60 : 2)))
|
||||
if (!m_interrupt_net->sleep_for(tried ? 60s : 2s)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if successful, this moves the passed grant to the constructed node
|
||||
void CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CountingSemaphoreGrant<>&& grant_outbound, const char *pszDest, ConnectionType conn_type, bool use_v2transport)
|
||||
bool CConnman::OpenNetworkConnection(const CAddress& addrConnect,
|
||||
bool fCountFailure,
|
||||
CountingSemaphoreGrant<>&& grant_outbound,
|
||||
const char* pszDest,
|
||||
ConnectionType conn_type,
|
||||
bool use_v2transport,
|
||||
const std::optional<Proxy>& proxy_override)
|
||||
{
|
||||
AssertLockNotHeld(m_unused_i2p_sessions_mutex);
|
||||
assert(conn_type != ConnectionType::INBOUND);
|
||||
|
@ -2995,24 +3006,25 @@ void CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai
|
|||
//
|
||||
// Initiate outbound network connection
|
||||
//
|
||||
if (interruptNet) {
|
||||
return;
|
||||
if (m_interrupt_net->interrupted()) {
|
||||
return false;
|
||||
}
|
||||
if (!fNetworkActive) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
if (!pszDest) {
|
||||
bool banned_or_discouraged = m_banman && (m_banman->IsDiscouraged(addrConnect) || m_banman->IsBanned(addrConnect));
|
||||
if (IsLocal(addrConnect) || banned_or_discouraged || AlreadyConnectedToAddress(addrConnect)) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
} else if (AlreadyConnectedToHost(pszDest)) {
|
||||
return false;
|
||||
}
|
||||
} else if (FindNode(std::string(pszDest)))
|
||||
return;
|
||||
|
||||
CNode* pnode = ConnectNode(addrConnect, pszDest, fCountFailure, conn_type, use_v2transport);
|
||||
CNode* pnode = ConnectNode(addrConnect, pszDest, fCountFailure, conn_type, use_v2transport, proxy_override);
|
||||
|
||||
if (!pnode)
|
||||
return;
|
||||
return false;
|
||||
pnode->grantOutbound = std::move(grant_outbound);
|
||||
|
||||
m_msgproc->InitializeNode(*pnode, m_local_services);
|
||||
|
@ -3030,6 +3042,8 @@ void CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai
|
|||
pnode->ConnectionTypeAsString().c_str(),
|
||||
pnode->ConnectedThroughNetwork(),
|
||||
GetNodeCount(ConnectionDirection::Out));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Mutex NetEventsInterface::g_msgproc_mutex;
|
||||
|
@ -3083,13 +3097,13 @@ void CConnman::ThreadI2PAcceptIncoming()
|
|||
i2p::Connection conn;
|
||||
|
||||
auto SleepOnFailure = [&]() {
|
||||
interruptNet.sleep_for(err_wait);
|
||||
m_interrupt_net->sleep_for(err_wait);
|
||||
if (err_wait < err_wait_cap) {
|
||||
err_wait += 1s;
|
||||
}
|
||||
};
|
||||
|
||||
while (!interruptNet) {
|
||||
while (!m_interrupt_net->interrupted()) {
|
||||
|
||||
if (!m_i2p_sam_session->Listen(conn)) {
|
||||
if (advertising_listen_addr && conn.me.IsValid()) {
|
||||
|
@ -3211,12 +3225,18 @@ void CConnman::SetNetworkActive(bool active)
|
|||
}
|
||||
}
|
||||
|
||||
CConnman::CConnman(uint64_t nSeed0In, uint64_t nSeed1In, AddrMan& addrman_in,
|
||||
const NetGroupManager& netgroupman, const CChainParams& params, bool network_active)
|
||||
CConnman::CConnman(uint64_t nSeed0In,
|
||||
uint64_t nSeed1In,
|
||||
AddrMan& addrman_in,
|
||||
const NetGroupManager& netgroupman,
|
||||
const CChainParams& params,
|
||||
bool network_active,
|
||||
std::shared_ptr<CThreadInterrupt> interrupt_net)
|
||||
: addrman(addrman_in)
|
||||
, m_netgroupman{netgroupman}
|
||||
, nSeed0(nSeed0In)
|
||||
, nSeed1(nSeed1In)
|
||||
, m_interrupt_net{interrupt_net}
|
||||
, m_params(params)
|
||||
{
|
||||
SetTryNewOutboundPeer(false);
|
||||
|
@ -3312,7 +3332,7 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)
|
|||
Proxy i2p_sam;
|
||||
if (GetProxy(NET_I2P, i2p_sam) && connOptions.m_i2p_accept_incoming) {
|
||||
m_i2p_sam_session = std::make_unique<i2p::sam::Session>(gArgs.GetDataDirNet() / "i2p_private_key",
|
||||
i2p_sam, &interruptNet);
|
||||
i2p_sam, m_interrupt_net);
|
||||
}
|
||||
|
||||
// Randomize the order in which we may query seednode to potentially prevent connecting to the same one every restart (and signal that we have restarted)
|
||||
|
@ -3349,7 +3369,7 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)
|
|||
// Start threads
|
||||
//
|
||||
assert(m_msgproc);
|
||||
interruptNet.reset();
|
||||
m_interrupt_net->reset();
|
||||
flagInterruptMsgProc = false;
|
||||
|
||||
{
|
||||
|
@ -3425,7 +3445,7 @@ void CConnman::Interrupt()
|
|||
}
|
||||
condMsgProc.notify_all();
|
||||
|
||||
interruptNet();
|
||||
(*m_interrupt_net)();
|
||||
g_socks5_interrupt();
|
||||
|
||||
if (semOutbound) {
|
||||
|
@ -3519,15 +3539,9 @@ std::vector<CAddress> CConnman::GetAddressesUnsafe(size_t max_addresses, size_t
|
|||
std::vector<CAddress> CConnman::GetAddresses(CNode& requestor, size_t max_addresses, size_t max_pct)
|
||||
{
|
||||
auto local_socket_bytes = requestor.addrBind.GetAddrBytes();
|
||||
uint64_t cache_id = GetDeterministicRandomizer(RANDOMIZER_ID_ADDRCACHE)
|
||||
.Write(requestor.ConnectedThroughNetwork())
|
||||
.Write(local_socket_bytes)
|
||||
// For outbound connections, the port of the bound address is randomly
|
||||
// assigned by the OS and would therefore not be useful for seeding.
|
||||
.Write(requestor.IsInboundConn() ? requestor.addrBind.GetPort() : 0)
|
||||
.Finalize();
|
||||
uint64_t network_id = requestor.m_network_key;
|
||||
const auto current_time = GetTime<std::chrono::microseconds>();
|
||||
auto r = m_addr_response_caches.emplace(cache_id, CachedAddrResponse{});
|
||||
auto r = m_addr_response_caches.emplace(network_id, CachedAddrResponse{});
|
||||
CachedAddrResponse& cache_entry = r.first->second;
|
||||
if (cache_entry.m_cache_entry_expiration < current_time) { // If emplace() added new one it has expiration 0.
|
||||
cache_entry.m_addrs_response_cache = GetAddressesUnsafe(max_addresses, max_pct, /*network=*/std::nullopt);
|
||||
|
@ -3641,9 +3655,11 @@ void CConnman::GetNodeStats(std::vector<CNodeStats>& vstats) const
|
|||
bool CConnman::DisconnectNode(const std::string& strNode)
|
||||
{
|
||||
LOCK(m_nodes_mutex);
|
||||
if (CNode* pnode = FindNode(strNode)) {
|
||||
LogDebug(BCLog::NET, "disconnect by address%s match, %s", (fLogIPs ? strprintf("=%s", strNode) : ""), pnode->DisconnectMsg(fLogIPs));
|
||||
pnode->fDisconnect = true;
|
||||
auto it = std::ranges::find_if(m_nodes, [&strNode](CNode* node) { return node->m_addr_name == strNode; });
|
||||
if (it != m_nodes.end()) {
|
||||
CNode* node{*it};
|
||||
LogDebug(BCLog::NET, "disconnect by address%s match, %s", (fLogIPs ? strprintf("=%s", strNode) : ""), node->DisconnectMsg(fLogIPs));
|
||||
node->fDisconnect = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -3804,6 +3820,7 @@ CNode::CNode(NodeId idIn,
|
|||
const std::string& addrNameIn,
|
||||
ConnectionType conn_type_in,
|
||||
bool inbound_onion,
|
||||
uint64_t network_key,
|
||||
CNodeOptions&& node_opts)
|
||||
: m_transport{MakeTransport(idIn, node_opts.use_v2transport, conn_type_in == ConnectionType::INBOUND)},
|
||||
m_permission_flags{node_opts.permission_flags},
|
||||
|
@ -3816,6 +3833,7 @@ CNode::CNode(NodeId idIn,
|
|||
m_inbound_onion{inbound_onion},
|
||||
m_prefer_evict{node_opts.prefer_evict},
|
||||
nKeyedNetGroup{nKeyedNetGroupIn},
|
||||
m_network_key{network_key},
|
||||
m_conn_type{conn_type_in},
|
||||
id{idIn},
|
||||
nLocalHostNonce{nLocalHostNonceIn},
|
||||
|
|
88
src/net.h
88
src/net.h
|
@ -738,6 +738,10 @@ public:
|
|||
std::atomic_bool fPauseRecv{false};
|
||||
std::atomic_bool fPauseSend{false};
|
||||
|
||||
/** Network key used to prevent fingerprinting our node across networks.
|
||||
* Influenced by the network and the bind address (+ bind port for inbounds) */
|
||||
const uint64_t m_network_key;
|
||||
|
||||
const ConnectionType m_conn_type;
|
||||
|
||||
/** Move all messages from the received queue to the processing queue. */
|
||||
|
@ -889,6 +893,7 @@ public:
|
|||
const std::string& addrNameIn,
|
||||
ConnectionType conn_type_in,
|
||||
bool inbound_onion,
|
||||
uint64_t network_key,
|
||||
CNodeOptions&& node_opts = {});
|
||||
CNode(const CNode&) = delete;
|
||||
CNode& operator=(const CNode&) = delete;
|
||||
|
@ -1119,8 +1124,13 @@ public:
|
|||
whitelist_relay = connOptions.whitelist_relay;
|
||||
}
|
||||
|
||||
CConnman(uint64_t seed0, uint64_t seed1, AddrMan& addrman, const NetGroupManager& netgroupman,
|
||||
const CChainParams& params, bool network_active = true);
|
||||
CConnman(uint64_t seed0,
|
||||
uint64_t seed1,
|
||||
AddrMan& addrman,
|
||||
const NetGroupManager& netgroupman,
|
||||
const CChainParams& params,
|
||||
bool network_active = true,
|
||||
std::shared_ptr<CThreadInterrupt> interrupt_net = std::make_shared<CThreadInterrupt>());
|
||||
|
||||
~CConnman();
|
||||
|
||||
|
@ -1138,7 +1148,28 @@ public:
|
|||
bool GetNetworkActive() const { return fNetworkActive; };
|
||||
bool GetUseAddrmanOutgoing() const { return m_use_addrman_outgoing; };
|
||||
void SetNetworkActive(bool active);
|
||||
void OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CountingSemaphoreGrant<>&& grant_outbound, const char* strDest, ConnectionType conn_type, bool use_v2transport) EXCLUSIVE_LOCKS_REQUIRED(!m_unused_i2p_sessions_mutex);
|
||||
|
||||
/**
|
||||
* Open a new P2P connection and initialize it with the PeerManager at `m_msgproc`.
|
||||
* @param[in] addrConnect Address to connect to, if `pszDest` is `nullptr`.
|
||||
* @param[in] fCountFailure Increment the number of connection attempts to this address in Addrman.
|
||||
* @param[in] grant_outbound Take ownership of this grant, to be released later when the connection is closed.
|
||||
* @param[in] pszDest Address to resolve and connect to.
|
||||
* @param[in] conn_type Type of the connection to open, must not be `ConnectionType::INBOUND`.
|
||||
* @param[in] use_v2transport Use P2P encryption, (aka V2 transport, BIP324).
|
||||
* @param[in] proxy_override Optional proxy to use and override normal proxy selection.
|
||||
* @retval true The connection was opened successfully.
|
||||
* @retval false The connection attempt failed.
|
||||
*/
|
||||
bool OpenNetworkConnection(const CAddress& addrConnect,
|
||||
bool fCountFailure,
|
||||
CountingSemaphoreGrant<>&& grant_outbound,
|
||||
const char* pszDest,
|
||||
ConnectionType conn_type,
|
||||
bool use_v2transport,
|
||||
const std::optional<Proxy>& proxy_override = std::nullopt)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(!m_unused_i2p_sessions_mutex);
|
||||
|
||||
bool CheckIncomingNonce(uint64_t nonce);
|
||||
void ASMapHealthCheck();
|
||||
|
||||
|
@ -1365,18 +1396,49 @@ private:
|
|||
|
||||
uint64_t CalculateKeyedNetGroup(const CNetAddr& ad) const;
|
||||
|
||||
CNode* FindNode(const CNetAddr& ip);
|
||||
CNode* FindNode(const std::string& addrName);
|
||||
CNode* FindNode(const CService& addr);
|
||||
/**
|
||||
* Determine whether we're already connected to a given "host:port".
|
||||
* Note that for inbound connections, the peer is likely using a random outbound
|
||||
* port on their side, so this will likely not match any inbound connections.
|
||||
* @param[in] host String of the form "host[:port]", e.g. "localhost" or "localhost:8333" or "1.2.3.4:8333".
|
||||
* @return true if connected to `host`.
|
||||
*/
|
||||
bool AlreadyConnectedToHost(const std::string& host) const;
|
||||
|
||||
/**
|
||||
* Determine whether we're already connected to a given address, in order to
|
||||
* avoid initiating duplicate connections.
|
||||
* Determine whether we're already connected to a given address:port.
|
||||
* Note that for inbound connections, the peer is likely using a random outbound
|
||||
* port on their side, so this will likely not match any inbound connections.
|
||||
* @param[in] addr_port Address and port to check.
|
||||
* @return true if connected to addr_port.
|
||||
*/
|
||||
bool AlreadyConnectedToAddress(const CAddress& addr);
|
||||
bool AlreadyConnectedToAddressPort(const CService& addr_port) const;
|
||||
|
||||
/**
|
||||
* Determine whether we're already connected to a given address.
|
||||
*/
|
||||
bool AlreadyConnectedToAddress(const CNetAddr& addr) const;
|
||||
|
||||
bool AttemptToEvictConnection();
|
||||
CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure, ConnectionType conn_type, bool use_v2transport) EXCLUSIVE_LOCKS_REQUIRED(!m_unused_i2p_sessions_mutex);
|
||||
|
||||
/**
|
||||
* Open a new P2P connection.
|
||||
* @param[in] addrConnect Address to connect to, if `pszDest` is `nullptr`.
|
||||
* @param[in] pszDest Address to resolve and connect to.
|
||||
* @param[in] fCountFailure Increment the number of connection attempts to this address in Addrman.
|
||||
* @param[in] conn_type Type of the connection to open, must not be `ConnectionType::INBOUND`.
|
||||
* @param[in] use_v2transport Use P2P encryption, (aka V2 transport, BIP324).
|
||||
* @param[in] proxy_override Optional proxy to use and override normal proxy selection.
|
||||
* @return Newly created CNode object or nullptr if the connection failed.
|
||||
*/
|
||||
CNode* ConnectNode(CAddress addrConnect,
|
||||
const char* pszDest,
|
||||
bool fCountFailure,
|
||||
ConnectionType conn_type,
|
||||
bool use_v2transport,
|
||||
const std::optional<Proxy>& proxy_override)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(!m_unused_i2p_sessions_mutex);
|
||||
|
||||
void AddWhitelistPermissionFlags(NetPermissionFlags& flags, std::optional<CNetAddr> addr, const std::vector<NetWhitelistPermissions>& ranges) const;
|
||||
|
||||
void DeleteNode(CNode* pnode);
|
||||
|
@ -1555,11 +1617,9 @@ private:
|
|||
|
||||
/**
|
||||
* This is signaled when network activity should cease.
|
||||
* A pointer to it is saved in `m_i2p_sam_session`, so make sure that
|
||||
* the lifetime of `interruptNet` is not shorter than
|
||||
* the lifetime of `m_i2p_sam_session`.
|
||||
* A copy of this is saved in `m_i2p_sam_session`.
|
||||
*/
|
||||
CThreadInterrupt interruptNet;
|
||||
const std::shared_ptr<CThreadInterrupt> m_interrupt_net;
|
||||
|
||||
/**
|
||||
* I2P SAM session.
|
||||
|
|
|
@ -807,7 +807,7 @@ private:
|
|||
|
||||
uint32_t GetFetchFlags(const Peer& peer) const;
|
||||
|
||||
std::atomic<std::chrono::microseconds> m_next_inv_to_inbounds{0us};
|
||||
std::map<uint64_t, std::chrono::microseconds> m_next_inv_to_inbounds_per_network_key GUARDED_BY(g_msgproc_mutex);
|
||||
|
||||
/** Number of nodes with fSyncStarted. */
|
||||
int nSyncStarted GUARDED_BY(cs_main) = 0;
|
||||
|
@ -837,12 +837,14 @@ private:
|
|||
|
||||
/**
|
||||
* For sending `inv`s to inbound peers, we use a single (exponentially
|
||||
* distributed) timer for all peers. If we used a separate timer for each
|
||||
* distributed) timer for all peers with the same network key. If we used a separate timer for each
|
||||
* peer, a spy node could make multiple inbound connections to us to
|
||||
* accurately determine when we received the transaction (and potentially
|
||||
* determine the transaction's origin). */
|
||||
* accurately determine when we received a transaction (and potentially
|
||||
* determine the transaction's origin). Each network key has its own timer
|
||||
* to make fingerprinting harder. */
|
||||
std::chrono::microseconds NextInvToInbounds(std::chrono::microseconds now,
|
||||
std::chrono::seconds average_interval) EXCLUSIVE_LOCKS_REQUIRED(g_msgproc_mutex);
|
||||
std::chrono::seconds average_interval,
|
||||
uint64_t network_key) EXCLUSIVE_LOCKS_REQUIRED(g_msgproc_mutex);
|
||||
|
||||
|
||||
// All of the following cache a recent block, and are protected by m_most_recent_block_mutex
|
||||
|
@ -1143,15 +1145,15 @@ static bool CanServeWitnesses(const Peer& peer)
|
|||
}
|
||||
|
||||
std::chrono::microseconds PeerManagerImpl::NextInvToInbounds(std::chrono::microseconds now,
|
||||
std::chrono::seconds average_interval)
|
||||
std::chrono::seconds average_interval,
|
||||
uint64_t network_key)
|
||||
{
|
||||
if (m_next_inv_to_inbounds.load() < now) {
|
||||
// If this function were called from multiple threads simultaneously
|
||||
// it would possible that both update the next send variable, and return a different result to their caller.
|
||||
// This is not possible in practice as only the net processing thread invokes this function.
|
||||
m_next_inv_to_inbounds = now + m_rng.rand_exp_duration(average_interval);
|
||||
auto [it, inserted] = m_next_inv_to_inbounds_per_network_key.try_emplace(network_key, 0us);
|
||||
auto& timer{it->second};
|
||||
if (timer < now) {
|
||||
timer = now + m_rng.rand_exp_duration(average_interval);
|
||||
}
|
||||
return m_next_inv_to_inbounds;
|
||||
return timer;
|
||||
}
|
||||
|
||||
bool PeerManagerImpl::IsBlockRequested(const uint256& hash)
|
||||
|
@ -5715,7 +5717,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
|
|||
if (tx_relay->m_next_inv_send_time < current_time) {
|
||||
fSendTrickle = true;
|
||||
if (pto->IsInboundConn()) {
|
||||
tx_relay->m_next_inv_send_time = NextInvToInbounds(current_time, INBOUND_INVENTORY_BROADCAST_INTERVAL);
|
||||
tx_relay->m_next_inv_send_time = NextInvToInbounds(current_time, INBOUND_INVENTORY_BROADCAST_INTERVAL, pto->m_network_key);
|
||||
} else {
|
||||
tx_relay->m_next_inv_send_time = current_time + m_rng.rand_exp_duration(OUTBOUND_INVENTORY_BROADCAST_INTERVAL);
|
||||
}
|
||||
|
|
|
@ -98,7 +98,7 @@ static constexpr unsigned int MAX_DUST_OUTPUTS_PER_TX{1};
|
|||
* Note that this does not affect consensus validity; see GetBlockScriptFlags()
|
||||
* for that.
|
||||
*/
|
||||
static constexpr unsigned int MANDATORY_SCRIPT_VERIFY_FLAGS{SCRIPT_VERIFY_P2SH |
|
||||
static constexpr script_verify_flags MANDATORY_SCRIPT_VERIFY_FLAGS{SCRIPT_VERIFY_P2SH |
|
||||
SCRIPT_VERIFY_DERSIG |
|
||||
SCRIPT_VERIFY_NULLDUMMY |
|
||||
SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY |
|
||||
|
@ -112,7 +112,7 @@ static constexpr unsigned int MANDATORY_SCRIPT_VERIFY_FLAGS{SCRIPT_VERIFY_P2SH |
|
|||
* the additional (non-mandatory) rules here, to improve forwards and
|
||||
* backwards compatibility.
|
||||
*/
|
||||
static constexpr unsigned int STANDARD_SCRIPT_VERIFY_FLAGS{MANDATORY_SCRIPT_VERIFY_FLAGS |
|
||||
static constexpr script_verify_flags STANDARD_SCRIPT_VERIFY_FLAGS{MANDATORY_SCRIPT_VERIFY_FLAGS |
|
||||
SCRIPT_VERIFY_STRICTENC |
|
||||
SCRIPT_VERIFY_MINIMALDATA |
|
||||
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS |
|
||||
|
@ -128,7 +128,7 @@ static constexpr unsigned int STANDARD_SCRIPT_VERIFY_FLAGS{MANDATORY_SCRIPT_VERI
|
|||
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE};
|
||||
|
||||
/** For convenience, standard but not mandatory verify flags. */
|
||||
static constexpr unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS{STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS};
|
||||
static constexpr script_verify_flags STANDARD_NOT_MANDATORY_VERIFY_FLAGS{STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS};
|
||||
|
||||
/** Used as the flags parameter to sequence and nLocktime checks in non-consensus code. */
|
||||
static constexpr unsigned int STANDARD_LOCKTIME_VERIFY_FLAGS{LOCKTIME_VERIFY_SEQUENCE};
|
||||
|
|
|
@ -1469,6 +1469,9 @@ RPCHelpMan getdeploymentinfo()
|
|||
RPCResult::Type::OBJ, "", "", {
|
||||
{RPCResult::Type::STR, "hash", "requested block hash (or tip)"},
|
||||
{RPCResult::Type::NUM, "height", "requested block height (or tip)"},
|
||||
{RPCResult::Type::ARR, "script_flags", "script verify flags for the block", {
|
||||
{RPCResult::Type::STR, "flag", "a script verify flag"},
|
||||
}},
|
||||
{RPCResult::Type::OBJ_DYN, "deployments", "", {
|
||||
{RPCResult::Type::OBJ, "xxxx", "name of the deployment", RPCHelpForDeployment}
|
||||
}},
|
||||
|
@ -1495,6 +1498,12 @@ RPCHelpMan getdeploymentinfo()
|
|||
UniValue deploymentinfo(UniValue::VOBJ);
|
||||
deploymentinfo.pushKV("hash", blockindex->GetBlockHash().ToString());
|
||||
deploymentinfo.pushKV("height", blockindex->nHeight);
|
||||
{
|
||||
const auto flagnames = GetScriptFlagNames(GetBlockScriptFlags(*blockindex, chainman));
|
||||
UniValue uv_flagnames(UniValue::VARR);
|
||||
uv_flagnames.push_backV(flagnames.begin(), flagnames.end());
|
||||
deploymentinfo.pushKV("script_flags", uv_flagnames);
|
||||
}
|
||||
deploymentinfo.pushKV("deployments", DeploymentInfo(blockindex, chainman));
|
||||
return deploymentinfo;
|
||||
},
|
||||
|
|
|
@ -130,7 +130,7 @@ static RPCHelpMan getpeerinfo()
|
|||
{
|
||||
{
|
||||
{RPCResult::Type::NUM, "id", "Peer index"},
|
||||
{RPCResult::Type::STR, "addr", "(host:port) The IP address and port of the peer"},
|
||||
{RPCResult::Type::STR, "addr", "(host:port) The IP address/hostname optionally followed by :port of the peer"},
|
||||
{RPCResult::Type::STR, "addrbind", /*optional=*/true, "(ip:port) Bind address of the connection to the peer"},
|
||||
{RPCResult::Type::STR, "addrlocal", /*optional=*/true, "(ip:port) Local address as reported by the peer"},
|
||||
{RPCResult::Type::STR, "network", "Network (" + Join(GetNetworkNames(/*append_unroutable=*/true), ", ") + ")"},
|
||||
|
@ -322,7 +322,7 @@ static RPCHelpMan addnode()
|
|||
strprintf("Addnode connections are limited to %u at a time", MAX_ADDNODE_CONNECTIONS) +
|
||||
" and are counted separately from the -maxconnections limit.\n",
|
||||
{
|
||||
{"node", RPCArg::Type::STR, RPCArg::Optional::NO, "The address of the peer to connect to"},
|
||||
{"node", RPCArg::Type::STR, RPCArg::Optional::NO, "The IP address/hostname optionally followed by :port of the peer to connect to"},
|
||||
{"command", RPCArg::Type::STR, RPCArg::Optional::NO, "'add' to add a node to the list, 'remove' to remove a node from the list, 'onetry' to try a connection to the node once"},
|
||||
{"v2transport", RPCArg::Type::BOOL, RPCArg::DefaultHint{"set by -v2transport"}, "Attempt to connect using BIP324 v2 transport protocol (ignored for 'remove' command)"},
|
||||
},
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <crypto/sha256.h>
|
||||
#include <pubkey.h>
|
||||
#include <script/script.h>
|
||||
#include <tinyformat.h>
|
||||
#include <uint256.h>
|
||||
|
||||
typedef std::vector<unsigned char> valtype;
|
||||
|
@ -197,7 +198,7 @@ bool static IsDefinedHashtypeSignature(const valtype &vchSig) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned int flags, ScriptError* serror) {
|
||||
bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, script_verify_flags flags, ScriptError* serror) {
|
||||
// Empty signature. Not strictly DER encoded, but allowed to provide a
|
||||
// compact way to provide an invalid signature for use with CHECK(MULTI)SIG
|
||||
if (vchSig.size() == 0) {
|
||||
|
@ -214,7 +215,7 @@ bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned i
|
|||
return true;
|
||||
}
|
||||
|
||||
bool static CheckPubKeyEncoding(const valtype &vchPubKey, unsigned int flags, const SigVersion &sigversion, ScriptError* serror) {
|
||||
bool static CheckPubKeyEncoding(const valtype &vchPubKey, script_verify_flags flags, const SigVersion &sigversion, ScriptError* serror) {
|
||||
if ((flags & SCRIPT_VERIFY_STRICTENC) != 0 && !IsCompressedOrUncompressedPubKey(vchPubKey)) {
|
||||
return set_error(serror, SCRIPT_ERR_PUBKEYTYPE);
|
||||
}
|
||||
|
@ -317,7 +318,7 @@ public:
|
|||
};
|
||||
}
|
||||
|
||||
static bool EvalChecksigPreTapscript(const valtype& vchSig, const valtype& vchPubKey, CScript::const_iterator pbegincodehash, CScript::const_iterator pend, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror, bool& fSuccess)
|
||||
static bool EvalChecksigPreTapscript(const valtype& vchSig, const valtype& vchPubKey, CScript::const_iterator pbegincodehash, CScript::const_iterator pend, script_verify_flags flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror, bool& fSuccess)
|
||||
{
|
||||
assert(sigversion == SigVersion::BASE || sigversion == SigVersion::WITNESS_V0);
|
||||
|
||||
|
@ -343,7 +344,7 @@ static bool EvalChecksigPreTapscript(const valtype& vchSig, const valtype& vchPu
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool EvalChecksigTapscript(const valtype& sig, const valtype& pubkey, ScriptExecutionData& execdata, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror, bool& success)
|
||||
static bool EvalChecksigTapscript(const valtype& sig, const valtype& pubkey, ScriptExecutionData& execdata, script_verify_flags flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror, bool& success)
|
||||
{
|
||||
assert(sigversion == SigVersion::TAPSCRIPT);
|
||||
|
||||
|
@ -388,7 +389,7 @@ static bool EvalChecksigTapscript(const valtype& sig, const valtype& pubkey, Scr
|
|||
* A return value of false means the script fails entirely. When true is returned, the
|
||||
* success variable indicates whether the signature check itself succeeded.
|
||||
*/
|
||||
static bool EvalChecksig(const valtype& sig, const valtype& pubkey, CScript::const_iterator pbegincodehash, CScript::const_iterator pend, ScriptExecutionData& execdata, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror, bool& success)
|
||||
static bool EvalChecksig(const valtype& sig, const valtype& pubkey, CScript::const_iterator pbegincodehash, CScript::const_iterator pend, ScriptExecutionData& execdata, script_verify_flags flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror, bool& success)
|
||||
{
|
||||
switch (sigversion) {
|
||||
case SigVersion::BASE:
|
||||
|
@ -403,7 +404,7 @@ static bool EvalChecksig(const valtype& sig, const valtype& pubkey, CScript::con
|
|||
assert(false);
|
||||
}
|
||||
|
||||
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* serror)
|
||||
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, script_verify_flags flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* serror)
|
||||
{
|
||||
static const CScriptNum bnZero(0);
|
||||
static const CScriptNum bnOne(1);
|
||||
|
@ -1233,7 +1234,7 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
|
|||
return set_success(serror);
|
||||
}
|
||||
|
||||
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror)
|
||||
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, script_verify_flags flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror)
|
||||
{
|
||||
ScriptExecutionData execdata;
|
||||
return EvalScript(stack, script, flags, checker, sigversion, execdata, serror);
|
||||
|
@ -1824,7 +1825,7 @@ bool GenericTransactionSignatureChecker<T>::CheckSequence(const CScriptNum& nSeq
|
|||
template class GenericTransactionSignatureChecker<CTransaction>;
|
||||
template class GenericTransactionSignatureChecker<CMutableTransaction>;
|
||||
|
||||
static bool ExecuteWitnessScript(const std::span<const valtype>& stack_span, const CScript& exec_script, unsigned int flags, SigVersion sigversion, const BaseSignatureChecker& checker, ScriptExecutionData& execdata, ScriptError* serror)
|
||||
static bool ExecuteWitnessScript(const std::span<const valtype>& stack_span, const CScript& exec_script, script_verify_flags flags, SigVersion sigversion, const BaseSignatureChecker& checker, ScriptExecutionData& execdata, ScriptError* serror)
|
||||
{
|
||||
std::vector<valtype> stack{stack_span.begin(), stack_span.end()};
|
||||
|
||||
|
@ -1909,7 +1910,7 @@ static bool VerifyTaprootCommitment(const std::vector<unsigned char>& control, c
|
|||
return q.CheckTapTweak(p, merkle_root, control[0] & 1);
|
||||
}
|
||||
|
||||
static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, const std::vector<unsigned char>& program, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror, bool is_p2sh)
|
||||
static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, const std::vector<unsigned char>& program, script_verify_flags flags, const BaseSignatureChecker& checker, ScriptError* serror, bool is_p2sh)
|
||||
{
|
||||
CScript exec_script; //!< Actually executed script (last stack item in P2WSH; implied P2PKH script in P2WPKH; leaf script in P2TR)
|
||||
std::span stack{witness.stack};
|
||||
|
@ -1994,7 +1995,7 @@ static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion,
|
|||
// There is intentionally no return statement here, to be able to use "control reaches end of non-void function" warnings to detect gaps in the logic above.
|
||||
}
|
||||
|
||||
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror)
|
||||
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, script_verify_flags flags, const BaseSignatureChecker& checker, ScriptError* serror)
|
||||
{
|
||||
static const CScriptWitness emptyWitness;
|
||||
if (witness == nullptr) {
|
||||
|
@ -2131,7 +2132,7 @@ size_t static WitnessSigOps(int witversion, const std::vector<unsigned char>& wi
|
|||
return 0;
|
||||
}
|
||||
|
||||
size_t CountWitnessSigOps(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, unsigned int flags)
|
||||
size_t CountWitnessSigOps(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, script_verify_flags flags)
|
||||
{
|
||||
static const CScriptWitness witnessEmpty;
|
||||
|
||||
|
@ -2161,3 +2162,48 @@ size_t CountWitnessSigOps(const CScript& scriptSig, const CScript& scriptPubKey,
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define FLAG_NAME(flag) {std::string(#flag), SCRIPT_VERIFY_##flag}
|
||||
const std::map<std::string, script_verify_flag_name> g_verify_flag_names{
|
||||
FLAG_NAME(P2SH),
|
||||
FLAG_NAME(STRICTENC),
|
||||
FLAG_NAME(DERSIG),
|
||||
FLAG_NAME(LOW_S),
|
||||
FLAG_NAME(SIGPUSHONLY),
|
||||
FLAG_NAME(MINIMALDATA),
|
||||
FLAG_NAME(NULLDUMMY),
|
||||
FLAG_NAME(DISCOURAGE_UPGRADABLE_NOPS),
|
||||
FLAG_NAME(CLEANSTACK),
|
||||
FLAG_NAME(MINIMALIF),
|
||||
FLAG_NAME(NULLFAIL),
|
||||
FLAG_NAME(CHECKLOCKTIMEVERIFY),
|
||||
FLAG_NAME(CHECKSEQUENCEVERIFY),
|
||||
FLAG_NAME(WITNESS),
|
||||
FLAG_NAME(DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM),
|
||||
FLAG_NAME(WITNESS_PUBKEYTYPE),
|
||||
FLAG_NAME(CONST_SCRIPTCODE),
|
||||
FLAG_NAME(TAPROOT),
|
||||
FLAG_NAME(DISCOURAGE_UPGRADABLE_PUBKEYTYPE),
|
||||
FLAG_NAME(DISCOURAGE_OP_SUCCESS),
|
||||
FLAG_NAME(DISCOURAGE_UPGRADABLE_TAPROOT_VERSION),
|
||||
};
|
||||
#undef FLAG_NAME
|
||||
|
||||
std::vector<std::string> GetScriptFlagNames(script_verify_flags flags)
|
||||
{
|
||||
std::vector<std::string> res;
|
||||
if (flags == SCRIPT_VERIFY_NONE) {
|
||||
return res;
|
||||
}
|
||||
script_verify_flags leftover = flags;
|
||||
for (const auto& [name, flag] : g_verify_flag_names) {
|
||||
if ((flags & flag) != 0) {
|
||||
res.push_back(name);
|
||||
leftover &= ~flag;
|
||||
}
|
||||
}
|
||||
if (leftover != 0) {
|
||||
res.push_back(strprintf("0x%08x", leftover.as_int()));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <hash.h>
|
||||
#include <primitives/transaction.h>
|
||||
#include <script/script_error.h> // IWYU pragma: export
|
||||
#include <script/verify_flags.h> // IWYU pragma: export
|
||||
#include <span.h>
|
||||
#include <uint256.h>
|
||||
|
||||
|
@ -42,35 +43,36 @@ enum
|
|||
* All flags are intended to be soft forks: the set of acceptable scripts under
|
||||
* flags (A | B) is a subset of the acceptable scripts under flag (A).
|
||||
*/
|
||||
enum : uint32_t {
|
||||
SCRIPT_VERIFY_NONE = 0,
|
||||
|
||||
static constexpr script_verify_flags SCRIPT_VERIFY_NONE{0};
|
||||
|
||||
enum class script_verify_flag_name : uint8_t {
|
||||
// Evaluate P2SH subscripts (BIP16).
|
||||
SCRIPT_VERIFY_P2SH = (1U << 0),
|
||||
SCRIPT_VERIFY_P2SH,
|
||||
|
||||
// Passing a non-strict-DER signature or one with undefined hashtype to a checksig operation causes script failure.
|
||||
// Evaluating a pubkey that is not (0x04 + 64 bytes) or (0x02 or 0x03 + 32 bytes) by checksig causes script failure.
|
||||
// (not used or intended as a consensus rule).
|
||||
SCRIPT_VERIFY_STRICTENC = (1U << 1),
|
||||
SCRIPT_VERIFY_STRICTENC,
|
||||
|
||||
// Passing a non-strict-DER signature to a checksig operation causes script failure (BIP62 rule 1)
|
||||
SCRIPT_VERIFY_DERSIG = (1U << 2),
|
||||
SCRIPT_VERIFY_DERSIG,
|
||||
|
||||
// Passing a non-strict-DER signature or one with S > order/2 to a checksig operation causes script failure
|
||||
// (BIP62 rule 5).
|
||||
SCRIPT_VERIFY_LOW_S = (1U << 3),
|
||||
SCRIPT_VERIFY_LOW_S,
|
||||
|
||||
// verify dummy stack item consumed by CHECKMULTISIG is of zero-length (BIP62 rule 7).
|
||||
SCRIPT_VERIFY_NULLDUMMY = (1U << 4),
|
||||
SCRIPT_VERIFY_NULLDUMMY,
|
||||
|
||||
// Using a non-push operator in the scriptSig causes script failure (BIP62 rule 2).
|
||||
SCRIPT_VERIFY_SIGPUSHONLY = (1U << 5),
|
||||
SCRIPT_VERIFY_SIGPUSHONLY,
|
||||
|
||||
// Require minimal encodings for all push operations (OP_0... OP_16, OP_1NEGATE where possible, direct
|
||||
// pushes up to 75 bytes, OP_PUSHDATA up to 255 bytes, OP_PUSHDATA2 for anything larger). Evaluating
|
||||
// any other push causes the script to fail (BIP62 rule 3).
|
||||
// In addition, whenever a stack element is interpreted as a number, it must be of minimal length (BIP62 rule 4).
|
||||
SCRIPT_VERIFY_MINIMALDATA = (1U << 6),
|
||||
SCRIPT_VERIFY_MINIMALDATA,
|
||||
|
||||
// Discourage use of NOPs reserved for upgrades (NOP1-10)
|
||||
//
|
||||
|
@ -82,7 +84,7 @@ enum : uint32_t {
|
|||
// executed, e.g. within an unexecuted IF ENDIF block, are *not* rejected.
|
||||
// NOPs that have associated forks to give them new meaning (CLTV, CSV)
|
||||
// are not subject to this rule.
|
||||
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS = (1U << 7),
|
||||
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS,
|
||||
|
||||
// Require that only a single stack element remains after evaluation. This changes the success criterion from
|
||||
// "At least one stack element must remain, and when interpreted as a boolean, it must be true" to
|
||||
|
@ -91,64 +93,72 @@ enum : uint32_t {
|
|||
// Note: CLEANSTACK should never be used without P2SH or WITNESS.
|
||||
// Note: WITNESS_V0 and TAPSCRIPT script execution have behavior similar to CLEANSTACK as part of their
|
||||
// consensus rules. It is automatic there and does not need this flag.
|
||||
SCRIPT_VERIFY_CLEANSTACK = (1U << 8),
|
||||
SCRIPT_VERIFY_CLEANSTACK,
|
||||
|
||||
// Verify CHECKLOCKTIMEVERIFY
|
||||
//
|
||||
// See BIP65 for details.
|
||||
SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY = (1U << 9),
|
||||
SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY,
|
||||
|
||||
// support CHECKSEQUENCEVERIFY opcode
|
||||
//
|
||||
// See BIP112 for details
|
||||
SCRIPT_VERIFY_CHECKSEQUENCEVERIFY = (1U << 10),
|
||||
SCRIPT_VERIFY_CHECKSEQUENCEVERIFY,
|
||||
|
||||
// Support segregated witness
|
||||
//
|
||||
SCRIPT_VERIFY_WITNESS = (1U << 11),
|
||||
SCRIPT_VERIFY_WITNESS,
|
||||
|
||||
// Making v1-v16 witness program non-standard
|
||||
//
|
||||
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM = (1U << 12),
|
||||
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM,
|
||||
|
||||
// Segwit script only: Require the argument of OP_IF/NOTIF to be exactly 0x01 or empty vector
|
||||
//
|
||||
// Note: TAPSCRIPT script execution has behavior similar to MINIMALIF as part of its consensus
|
||||
// rules. It is automatic there and does not depend on this flag.
|
||||
SCRIPT_VERIFY_MINIMALIF = (1U << 13),
|
||||
SCRIPT_VERIFY_MINIMALIF,
|
||||
|
||||
// Signature(s) must be empty vector if a CHECK(MULTI)SIG operation failed
|
||||
//
|
||||
SCRIPT_VERIFY_NULLFAIL = (1U << 14),
|
||||
SCRIPT_VERIFY_NULLFAIL,
|
||||
|
||||
// Public keys in segregated witness scripts must be compressed
|
||||
//
|
||||
SCRIPT_VERIFY_WITNESS_PUBKEYTYPE = (1U << 15),
|
||||
SCRIPT_VERIFY_WITNESS_PUBKEYTYPE,
|
||||
|
||||
// Making OP_CODESEPARATOR and FindAndDelete fail any non-segwit scripts
|
||||
//
|
||||
SCRIPT_VERIFY_CONST_SCRIPTCODE = (1U << 16),
|
||||
SCRIPT_VERIFY_CONST_SCRIPTCODE,
|
||||
|
||||
// Taproot/Tapscript validation (BIPs 341 & 342)
|
||||
//
|
||||
SCRIPT_VERIFY_TAPROOT = (1U << 17),
|
||||
SCRIPT_VERIFY_TAPROOT,
|
||||
|
||||
// Making unknown Taproot leaf versions non-standard
|
||||
//
|
||||
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION = (1U << 18),
|
||||
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION,
|
||||
|
||||
// Making unknown OP_SUCCESS non-standard
|
||||
SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS = (1U << 19),
|
||||
SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS,
|
||||
|
||||
// Making unknown public key versions (in BIP 342 scripts) non-standard
|
||||
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE = (1U << 20),
|
||||
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE,
|
||||
|
||||
// Constants to point to the highest flag in use. Add new flags above this line.
|
||||
//
|
||||
SCRIPT_VERIFY_END_MARKER
|
||||
};
|
||||
using enum script_verify_flag_name;
|
||||
|
||||
bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned int flags, ScriptError* serror);
|
||||
static constexpr int MAX_SCRIPT_VERIFY_FLAGS_BITS = static_cast<int>(SCRIPT_VERIFY_END_MARKER);
|
||||
|
||||
// assert there is still a spare bit
|
||||
static_assert(0 < MAX_SCRIPT_VERIFY_FLAGS_BITS && MAX_SCRIPT_VERIFY_FLAGS_BITS <= 63);
|
||||
|
||||
static constexpr script_verify_flags::value_type MAX_SCRIPT_VERIFY_FLAGS = ((script_verify_flags::value_type{1} << MAX_SCRIPT_VERIFY_FLAGS_BITS) - 1);
|
||||
|
||||
bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, script_verify_flags flags, ScriptError* serror);
|
||||
|
||||
struct PrecomputedTransactionData
|
||||
{
|
||||
|
@ -363,12 +373,16 @@ uint256 ComputeTapbranchHash(std::span<const unsigned char> a, std::span<const u
|
|||
* Requires control block to have valid length (33 + k*32, with k in {0,1,..,128}). */
|
||||
uint256 ComputeTaprootMerkleRoot(std::span<const unsigned char> control, const uint256& tapleaf_hash);
|
||||
|
||||
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* error = nullptr);
|
||||
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* error = nullptr);
|
||||
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror = nullptr);
|
||||
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, script_verify_flags flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* error = nullptr);
|
||||
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, script_verify_flags flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* error = nullptr);
|
||||
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, script_verify_flags flags, const BaseSignatureChecker& checker, ScriptError* serror = nullptr);
|
||||
|
||||
size_t CountWitnessSigOps(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, unsigned int flags);
|
||||
size_t CountWitnessSigOps(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, script_verify_flags flags);
|
||||
|
||||
int FindAndDelete(CScript& script, const CScript& b);
|
||||
|
||||
extern const std::map<std::string, script_verify_flag_name> g_verify_flag_names;
|
||||
|
||||
std::vector<std::string> GetScriptFlagNames(script_verify_flags flags);
|
||||
|
||||
#endif // BITCOIN_SCRIPT_INTERPRETER_H
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-present The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_SCRIPT_VERIFY_FLAGS_H
|
||||
#define BITCOIN_SCRIPT_VERIFY_FLAGS_H
|
||||
|
||||
#include <compare>
|
||||
#include <cstdint>
|
||||
|
||||
enum class script_verify_flag_name : uint8_t;
|
||||
|
||||
class script_verify_flags
|
||||
{
|
||||
public:
|
||||
using value_type = uint64_t;
|
||||
|
||||
consteval script_verify_flags() = default;
|
||||
|
||||
// also allow construction with hard-coded 0 (but not other integers)
|
||||
consteval explicit(false) script_verify_flags(value_type f) : m_value{f} { if (f != 0) throw 0; }
|
||||
|
||||
// implicit construction from a hard-coded SCRIPT_VERIFY_* constant is also okay
|
||||
constexpr explicit(false) script_verify_flags(script_verify_flag_name f) : m_value{value_type{1} << static_cast<uint8_t>(f)} { }
|
||||
|
||||
// rule of 5
|
||||
constexpr script_verify_flags(const script_verify_flags&) = default;
|
||||
constexpr script_verify_flags(script_verify_flags&&) = default;
|
||||
constexpr script_verify_flags& operator=(const script_verify_flags&) = default;
|
||||
constexpr script_verify_flags& operator=(script_verify_flags&&) = default;
|
||||
constexpr ~script_verify_flags() = default;
|
||||
|
||||
// integer conversion needs to be very explicit
|
||||
static constexpr script_verify_flags from_int(value_type f) { script_verify_flags r; r.m_value = f; return r; }
|
||||
constexpr value_type as_int() const { return m_value; }
|
||||
|
||||
// bitwise operations
|
||||
constexpr script_verify_flags operator~() const { return from_int(~m_value); }
|
||||
friend constexpr script_verify_flags operator|(script_verify_flags a, script_verify_flags b) { return from_int(a.m_value | b.m_value); }
|
||||
friend constexpr script_verify_flags operator&(script_verify_flags a, script_verify_flags b) { return from_int(a.m_value & b.m_value); }
|
||||
|
||||
// in-place bitwise operations
|
||||
constexpr script_verify_flags& operator|=(script_verify_flags vf) { m_value |= vf.m_value; return *this; }
|
||||
constexpr script_verify_flags& operator&=(script_verify_flags vf) { m_value &= vf.m_value; return *this; }
|
||||
|
||||
// tests
|
||||
constexpr explicit operator bool() const { return m_value != 0; }
|
||||
constexpr bool operator==(script_verify_flags other) const { return m_value == other.m_value; }
|
||||
|
||||
/** Compare two script_verify_flags. <, >, <=, and >= are auto-generated from this. */
|
||||
friend constexpr std::strong_ordering operator<=>(const script_verify_flags& a, const script_verify_flags& b) noexcept
|
||||
{
|
||||
return a.m_value <=> b.m_value;
|
||||
}
|
||||
|
||||
private:
|
||||
value_type m_value{0}; // default value is SCRIPT_VERIFY_NONE
|
||||
};
|
||||
|
||||
inline constexpr script_verify_flags operator~(script_verify_flag_name f)
|
||||
{
|
||||
return ~script_verify_flags{f};
|
||||
}
|
||||
|
||||
inline constexpr script_verify_flags operator|(script_verify_flag_name f1, script_verify_flag_name f2)
|
||||
{
|
||||
return script_verify_flags{f1} | f2;
|
||||
}
|
||||
|
||||
#endif // BITCOIN_SCRIPT_VERIFY_FLAGS_H
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
static constexpr uint8_t SIGNET_HEADER[4] = {0xec, 0xc7, 0xda, 0xa2};
|
||||
|
||||
static constexpr unsigned int BLOCK_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_NULLDUMMY;
|
||||
static constexpr script_verify_flags BLOCK_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_NULLDUMMY;
|
||||
|
||||
static bool FetchAndClearCommitmentSection(const std::span<const uint8_t> header, CScript& witness_commitment, std::vector<uint8_t>& result)
|
||||
{
|
||||
|
|
|
@ -26,6 +26,7 @@ add_executable(test_bitcoin
|
|||
bloom_tests.cpp
|
||||
bswap_tests.cpp
|
||||
caches_tests.cpp
|
||||
chain_tests.cpp
|
||||
chainstate_write_tests.cpp
|
||||
checkqueue_tests.cpp
|
||||
cluster_linearize_tests.cpp
|
||||
|
|
|
@ -459,10 +459,16 @@ BOOST_AUTO_TEST_CASE(getaddr_unfiltered)
|
|||
addrman->Attempt(addr3, /*fCountFailure=*/true, /*time=*/Now<NodeSeconds>() - 61s);
|
||||
}
|
||||
|
||||
// Set time more than 10 minutes in the future (flying DeLorean), so this
|
||||
// addr should be isTerrible = true
|
||||
CAddress addr4 = CAddress(ResolveService("250.252.2.4", 9997), NODE_NONE);
|
||||
addr4.nTime = Now<NodeSeconds>() + 11min;
|
||||
BOOST_CHECK(addrman->Add({addr4}, source));
|
||||
|
||||
// GetAddr filtered by quality (i.e. not IsTerrible) should only return addr1
|
||||
BOOST_CHECK_EQUAL(addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt).size(), 1U);
|
||||
// Unfiltered GetAddr should return all addrs
|
||||
BOOST_CHECK_EQUAL(addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt, /*filtered=*/false).size(), 3U);
|
||||
BOOST_CHECK_EQUAL(addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt, /*filtered=*/false).size(), 4U);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket_legacy)
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
// Copyright (c) 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 <boost/test/unit_test.hpp>
|
||||
|
||||
#include <chain.h>
|
||||
#include <test/util/setup_common.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
BOOST_FIXTURE_TEST_SUITE(chain_tests, BasicTestingSetup)
|
||||
|
||||
namespace {
|
||||
|
||||
const CBlockIndex* NaiveGetAncestor(const CBlockIndex* a, int height)
|
||||
{
|
||||
while (a->nHeight > height) {
|
||||
a = a->pprev;
|
||||
}
|
||||
BOOST_REQUIRE_EQUAL(a->nHeight, height);
|
||||
return a;
|
||||
}
|
||||
|
||||
const CBlockIndex* NaiveLastCommonAncestor(const CBlockIndex* a, const CBlockIndex* b)
|
||||
{
|
||||
while (a->nHeight > b->nHeight) {
|
||||
a = a->pprev;
|
||||
}
|
||||
while (b->nHeight > a->nHeight) {
|
||||
b = b->pprev;
|
||||
}
|
||||
while (a != b) {
|
||||
BOOST_REQUIRE_EQUAL(a->nHeight, b->nHeight);
|
||||
a = a->pprev;
|
||||
b = b->pprev;
|
||||
}
|
||||
BOOST_REQUIRE_EQUAL(a, b);
|
||||
return a;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
BOOST_AUTO_TEST_CASE(chain_test)
|
||||
{
|
||||
FastRandomContext ctx;
|
||||
std::vector<std::unique_ptr<CBlockIndex>> block_index;
|
||||
// Run 10 iterations of the whole test.
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
block_index.clear();
|
||||
// Create genesis block.
|
||||
auto genesis = std::make_unique<CBlockIndex>();
|
||||
genesis->nHeight = 0;
|
||||
block_index.push_back(std::move(genesis));
|
||||
// Create 10000 more blocks.
|
||||
for (int b = 0; b < 10000; ++b) {
|
||||
auto new_index = std::make_unique<CBlockIndex>();
|
||||
// 95% of blocks build on top of the last block; the others fork off randomly.
|
||||
if (ctx.randrange(20) != 0) {
|
||||
new_index->pprev = block_index.back().get();
|
||||
} else {
|
||||
new_index->pprev = block_index[ctx.randrange(block_index.size())].get();
|
||||
}
|
||||
new_index->nHeight = new_index->pprev->nHeight + 1;
|
||||
new_index->BuildSkip();
|
||||
block_index.push_back(std::move(new_index));
|
||||
}
|
||||
// Run 10000 random GetAncestor queries.
|
||||
for (int q = 0; q < 10000; ++q) {
|
||||
const CBlockIndex* block = block_index[ctx.randrange(block_index.size())].get();
|
||||
unsigned height = ctx.randrange<unsigned>(block->nHeight + 1);
|
||||
const CBlockIndex* result = block->GetAncestor(height);
|
||||
BOOST_CHECK(result == NaiveGetAncestor(block, height));
|
||||
}
|
||||
// Run 10000 random LastCommonAncestor queries.
|
||||
for (int q = 0; q < 10000; ++q) {
|
||||
const CBlockIndex* block1 = block_index[ctx.randrange(block_index.size())].get();
|
||||
const CBlockIndex* block2 = block_index[ctx.randrange(block_index.size())].get();
|
||||
const CBlockIndex* result = LastCommonAncestor(block1, block2);
|
||||
BOOST_CHECK(result == NaiveLastCommonAncestor(block1, block2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
|
@ -62,7 +62,8 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
|
|||
CAddress(),
|
||||
/*addrNameIn=*/"",
|
||||
ConnectionType::OUTBOUND_FULL_RELAY,
|
||||
/*inbound_onion=*/false};
|
||||
/*inbound_onion=*/false,
|
||||
/*network_key=*/0};
|
||||
|
||||
connman.Handshake(
|
||||
/*node=*/dummyNode1,
|
||||
|
@ -128,7 +129,8 @@ void AddRandomOutboundPeer(NodeId& id, std::vector<CNode*>& vNodes, PeerManager&
|
|||
CAddress(),
|
||||
/*addrNameIn=*/"",
|
||||
connType,
|
||||
/*inbound_onion=*/false});
|
||||
/*inbound_onion=*/false,
|
||||
/*network_key=*/0});
|
||||
CNode &node = *vNodes.back();
|
||||
node.SetCommonVersion(PROTOCOL_VERSION);
|
||||
|
||||
|
@ -327,7 +329,8 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
|
|||
CAddress(),
|
||||
/*addrNameIn=*/"",
|
||||
ConnectionType::INBOUND,
|
||||
/*inbound_onion=*/false};
|
||||
/*inbound_onion=*/false,
|
||||
/*network_key=*/1};
|
||||
nodes[0]->SetCommonVersion(PROTOCOL_VERSION);
|
||||
peerLogic->InitializeNode(*nodes[0], NODE_NETWORK);
|
||||
nodes[0]->fSuccessfullyConnected = true;
|
||||
|
@ -347,7 +350,8 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
|
|||
CAddress(),
|
||||
/*addrNameIn=*/"",
|
||||
ConnectionType::INBOUND,
|
||||
/*inbound_onion=*/false};
|
||||
/*inbound_onion=*/false,
|
||||
/*network_key=*/1};
|
||||
nodes[1]->SetCommonVersion(PROTOCOL_VERSION);
|
||||
peerLogic->InitializeNode(*nodes[1], NODE_NETWORK);
|
||||
nodes[1]->fSuccessfullyConnected = true;
|
||||
|
@ -377,7 +381,8 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
|
|||
CAddress(),
|
||||
/*addrNameIn=*/"",
|
||||
ConnectionType::OUTBOUND_FULL_RELAY,
|
||||
/*inbound_onion=*/false};
|
||||
/*inbound_onion=*/false,
|
||||
/*network_key=*/2};
|
||||
nodes[2]->SetCommonVersion(PROTOCOL_VERSION);
|
||||
peerLogic->InitializeNode(*nodes[2], NODE_NETWORK);
|
||||
nodes[2]->fSuccessfullyConnected = true;
|
||||
|
@ -419,7 +424,8 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
|
|||
CAddress(),
|
||||
/*addrNameIn=*/"",
|
||||
ConnectionType::INBOUND,
|
||||
/*inbound_onion=*/false};
|
||||
/*inbound_onion=*/false,
|
||||
/*network_key=*/1};
|
||||
dummyNode.SetCommonVersion(PROTOCOL_VERSION);
|
||||
peerLogic->InitializeNode(dummyNode, NODE_NETWORK);
|
||||
dummyNode.fSuccessfullyConnected = true;
|
||||
|
|
|
@ -288,7 +288,7 @@ void TestCoinsView(FuzzedDataProvider& fuzzed_data_provider, CCoinsView& backend
|
|||
// consensus/tx_verify.cpp:130: unsigned int GetP2SHSigOpCount(const CTransaction &, const CCoinsViewCache &): Assertion `!coin.IsSpent()' failed.
|
||||
return;
|
||||
}
|
||||
const auto flags{fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
|
||||
const auto flags = script_verify_flags::from_int(fuzzed_data_provider.ConsumeIntegral<script_verify_flags::value_type>());
|
||||
if (!transaction.vin.empty() && (flags & SCRIPT_VERIFY_WITNESS) != 0 && (flags & SCRIPT_VERIFY_P2SH) == 0) {
|
||||
// Avoid:
|
||||
// script/interpreter.cpp:1705: size_t CountWitnessSigOps(const CScript &, const CScript &, const CScriptWitness *, unsigned int): Assertion `(flags & SCRIPT_VERIFY_P2SH) != 0' failed.
|
||||
|
|
|
@ -6,12 +6,14 @@
|
|||
#include <chainparams.h>
|
||||
#include <common/args.h>
|
||||
#include <net.h>
|
||||
#include <net_processing.h>
|
||||
#include <netaddress.h>
|
||||
#include <protocol.h>
|
||||
#include <test/fuzz/FuzzedDataProvider.h>
|
||||
#include <test/fuzz/fuzz.h>
|
||||
#include <test/fuzz/util.h>
|
||||
#include <test/fuzz/util/net.h>
|
||||
#include <test/fuzz/util/threadinterrupt.h>
|
||||
#include <test/util/setup_common.h>
|
||||
#include <util/translation.h>
|
||||
|
||||
|
@ -51,19 +53,36 @@ FUZZ_TARGET(connman, .init = initialize_connman)
|
|||
}
|
||||
}
|
||||
AddrManDeterministic& addr_man{*addr_man_ptr};
|
||||
auto net_events{ConsumeNetEvents(fuzzed_data_provider)};
|
||||
|
||||
// Mock CreateSock() to create FuzzedSock.
|
||||
auto CreateSockOrig = CreateSock;
|
||||
CreateSock = [&fuzzed_data_provider](int, int, int) {
|
||||
return std::make_unique<FuzzedSock>(fuzzed_data_provider);
|
||||
};
|
||||
|
||||
// Mock g_dns_lookup() to return a fuzzed address.
|
||||
auto g_dns_lookup_orig = g_dns_lookup;
|
||||
g_dns_lookup = [&fuzzed_data_provider](const std::string&, bool) {
|
||||
return std::vector<CNetAddr>{ConsumeNetAddr(fuzzed_data_provider)};
|
||||
};
|
||||
|
||||
ConnmanTestMsg connman{fuzzed_data_provider.ConsumeIntegral<uint64_t>(),
|
||||
fuzzed_data_provider.ConsumeIntegral<uint64_t>(),
|
||||
addr_man,
|
||||
netgroupman,
|
||||
Params(),
|
||||
fuzzed_data_provider.ConsumeBool()};
|
||||
fuzzed_data_provider.ConsumeBool(),
|
||||
ConsumeThreadInterrupt(fuzzed_data_provider)};
|
||||
|
||||
const uint64_t max_outbound_limit{fuzzed_data_provider.ConsumeIntegral<uint64_t>()};
|
||||
CConnman::Options options;
|
||||
options.m_msgproc = &net_events;
|
||||
options.nMaxOutboundLimit = max_outbound_limit;
|
||||
connman.Init(options);
|
||||
|
||||
CNetAddr random_netaddr;
|
||||
CAddress random_address;
|
||||
CNode random_node = ConsumeNode(fuzzed_data_provider);
|
||||
CSubNet random_subnet;
|
||||
std::string random_string;
|
||||
|
@ -79,6 +98,9 @@ FUZZ_TARGET(connman, .init = initialize_connman)
|
|||
[&] {
|
||||
random_netaddr = ConsumeNetAddr(fuzzed_data_provider);
|
||||
},
|
||||
[&] {
|
||||
random_address = ConsumeAddress(fuzzed_data_provider);
|
||||
},
|
||||
[&] {
|
||||
random_subnet = ConsumeSubNet(fuzzed_data_provider);
|
||||
},
|
||||
|
@ -143,6 +165,52 @@ FUZZ_TARGET(connman, .init = initialize_connman)
|
|||
},
|
||||
[&] {
|
||||
connman.SetTryNewOutboundPeer(fuzzed_data_provider.ConsumeBool());
|
||||
},
|
||||
[&] {
|
||||
ConnectionType conn_type{
|
||||
fuzzed_data_provider.PickValueInArray(ALL_CONNECTION_TYPES)};
|
||||
if (conn_type == ConnectionType::INBOUND) { // INBOUND is not allowed
|
||||
conn_type = ConnectionType::OUTBOUND_FULL_RELAY;
|
||||
}
|
||||
|
||||
connman.OpenNetworkConnection(
|
||||
/*addrConnect=*/random_address,
|
||||
/*fCountFailure=*/fuzzed_data_provider.ConsumeBool(),
|
||||
/*grant_outbound=*/{},
|
||||
/*pszDest=*/fuzzed_data_provider.ConsumeBool() ? nullptr : random_string.c_str(),
|
||||
/*conn_type=*/conn_type,
|
||||
/*use_v2transport=*/fuzzed_data_provider.ConsumeBool());
|
||||
},
|
||||
[&] {
|
||||
connman.SetNetworkActive(fuzzed_data_provider.ConsumeBool());
|
||||
const auto peer = ConsumeAddress(fuzzed_data_provider);
|
||||
connman.CreateNodeFromAcceptedSocketPublic(
|
||||
/*sock=*/CreateSock(AF_INET, SOCK_STREAM, IPPROTO_TCP),
|
||||
/*permissions=*/ConsumeWeakEnum(fuzzed_data_provider, ALL_NET_PERMISSION_FLAGS),
|
||||
/*addr_bind=*/ConsumeAddress(fuzzed_data_provider),
|
||||
/*addr_peer=*/peer);
|
||||
},
|
||||
[&] {
|
||||
CConnman::Options options;
|
||||
|
||||
options.vBinds = ConsumeServiceVector(fuzzed_data_provider);
|
||||
|
||||
options.vWhiteBinds = std::vector<NetWhitebindPermissions>{
|
||||
fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 5)};
|
||||
for (auto& wb : options.vWhiteBinds) {
|
||||
wb.m_flags = ConsumeWeakEnum(fuzzed_data_provider, ALL_NET_PERMISSION_FLAGS);
|
||||
wb.m_service = ConsumeService(fuzzed_data_provider);
|
||||
}
|
||||
|
||||
options.onion_binds = ConsumeServiceVector(fuzzed_data_provider);
|
||||
|
||||
options.bind_on_any = options.vBinds.empty() && options.vWhiteBinds.empty() &&
|
||||
options.onion_binds.empty();
|
||||
|
||||
connman.InitBindsPublic(options);
|
||||
},
|
||||
[&] {
|
||||
connman.SocketHandlerPublic();
|
||||
});
|
||||
}
|
||||
(void)connman.GetAddedNodeInfo(fuzzed_data_provider.ConsumeBool());
|
||||
|
@ -162,4 +230,6 @@ FUZZ_TARGET(connman, .init = initialize_connman)
|
|||
(void)connman.ASMapHealthCheck();
|
||||
|
||||
connman.ClearTestNodes();
|
||||
g_dns_lookup = g_dns_lookup_orig;
|
||||
CreateSock = CreateSockOrig;
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
FUZZ_TARGET(eval_script)
|
||||
{
|
||||
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
|
||||
const unsigned int flags = fuzzed_data_provider.ConsumeIntegral<unsigned int>();
|
||||
const auto flags = script_verify_flags::from_int(fuzzed_data_provider.ConsumeIntegral<script_verify_flags::value_type>());
|
||||
const std::vector<uint8_t> script_bytes = [&] {
|
||||
if (fuzzed_data_provider.remaining_bytes() != 0) {
|
||||
return fuzzed_data_provider.ConsumeRemainingBytes<uint8_t>();
|
||||
|
|
|
@ -75,7 +75,7 @@ auto& FuzzTargets()
|
|||
|
||||
void FuzzFrameworkRegisterTarget(std::string_view name, TypeTestOneInput target, FuzzTargetOptions opts)
|
||||
{
|
||||
const auto [it, ins]{FuzzTargets().try_emplace(name, FuzzTarget /* temporary can be dropped after Apple-Clang-16 ? */ {std::move(target), std::move(opts)})};
|
||||
const auto [it, ins]{FuzzTargets().try_emplace(name, std::move(target), std::move(opts))};
|
||||
Assert(ins);
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <test/fuzz/fuzz.h>
|
||||
#include <test/fuzz/util.h>
|
||||
#include <test/fuzz/util/net.h>
|
||||
#include <test/fuzz/util/threadinterrupt.h>
|
||||
#include <test/util/setup_common.h>
|
||||
#include <util/fs_helpers.h>
|
||||
#include <util/threadinterrupt.h>
|
||||
|
@ -35,15 +36,15 @@ FUZZ_TARGET(i2p, .init = initialize_i2p)
|
|||
const fs::path private_key_path = gArgs.GetDataDirNet() / "fuzzed_i2p_private_key";
|
||||
const CService addr{in6_addr(IN6ADDR_LOOPBACK_INIT), 7656};
|
||||
const Proxy sam_proxy{addr, /*tor_stream_isolation=*/false};
|
||||
CThreadInterrupt interrupt;
|
||||
auto interrupt{ConsumeThreadInterrupt(fuzzed_data_provider)};
|
||||
|
||||
i2p::sam::Session session{private_key_path, sam_proxy, &interrupt};
|
||||
i2p::sam::Session session{private_key_path, sam_proxy, interrupt};
|
||||
i2p::Connection conn;
|
||||
|
||||
if (session.Listen(conn)) {
|
||||
if (session.Accept(conn)) {
|
||||
try {
|
||||
(void)conn.sock->RecvUntilTerminator('\n', 10ms, interrupt, i2p::sam::MAX_MSG_SIZE);
|
||||
(void)conn.sock->RecvUntilTerminator('\n', 10ms, *interrupt, i2p::sam::MAX_MSG_SIZE);
|
||||
} catch (const std::runtime_error&) {
|
||||
}
|
||||
}
|
||||
|
@ -53,7 +54,7 @@ FUZZ_TARGET(i2p, .init = initialize_i2p)
|
|||
|
||||
if (session.Connect(CService{}, conn, proxy_error)) {
|
||||
try {
|
||||
conn.sock->SendComplete("verack\n", 10ms, interrupt);
|
||||
conn.sock->SendComplete("verack\n", 10ms, *interrupt);
|
||||
} catch (const std::runtime_error&) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,7 +70,7 @@ void HeadersSyncSetup::ResetAndInitialize()
|
|||
|
||||
for (auto conn_type : conn_types) {
|
||||
CAddress addr{};
|
||||
m_connections.push_back(new CNode(id++, nullptr, addr, 0, 0, addr, "", conn_type, false));
|
||||
m_connections.push_back(new CNode(id++, nullptr, addr, 0, 0, addr, "", conn_type, false, 0));
|
||||
CNode& p2p_node = *m_connections.back();
|
||||
|
||||
connman.Handshake(
|
||||
|
|
|
@ -325,7 +325,7 @@ FUZZ_TARGET(ephemeral_package_eval, .init = initialize_tx_pool)
|
|||
return ProcessNewPackage(chainstate, tx_pool, txs, /*test_accept=*/single_submit, /*client_maxfeerate=*/{}));
|
||||
|
||||
const auto res = WITH_LOCK(::cs_main, return AcceptToMemoryPool(chainstate, txs.back(), GetTime(),
|
||||
/*bypass_limits=*/fuzzed_data_provider.ConsumeBool(), /*test_accept=*/!single_submit));
|
||||
/*bypass_limits=*/false, /*test_accept=*/!single_submit));
|
||||
|
||||
if (!single_submit && result_package.m_state.GetResult() != PackageValidationResult::PCKG_POLICY) {
|
||||
// We don't know anything about the validity since transactions were randomly generated, so
|
||||
|
|
|
@ -118,8 +118,8 @@ FUZZ_TARGET(script, .init = initialize_script)
|
|||
(void)FindAndDelete(script_mut, *other_script);
|
||||
}
|
||||
const std::vector<std::string> random_string_vector = ConsumeRandomLengthStringVector(fuzzed_data_provider);
|
||||
const uint32_t u32{fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
|
||||
const uint32_t flags{u32 | SCRIPT_VERIFY_P2SH};
|
||||
const auto flags_rand{fuzzed_data_provider.ConsumeIntegral<script_verify_flags::value_type>()};
|
||||
const auto flags = script_verify_flags::from_int(flags_rand) | SCRIPT_VERIFY_P2SH;
|
||||
{
|
||||
CScriptWitness wit;
|
||||
for (const auto& s : random_string_vector) {
|
||||
|
|
|
@ -90,22 +90,22 @@ CScriptWitness ScriptWitnessFromJSON(const UniValue& univalue)
|
|||
return scriptwitness;
|
||||
}
|
||||
|
||||
const std::map<std::string, unsigned int> FLAG_NAMES = {
|
||||
{std::string("P2SH"), (unsigned int)SCRIPT_VERIFY_P2SH},
|
||||
{std::string("DERSIG"), (unsigned int)SCRIPT_VERIFY_DERSIG},
|
||||
{std::string("NULLDUMMY"), (unsigned int)SCRIPT_VERIFY_NULLDUMMY},
|
||||
{std::string("CHECKLOCKTIMEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY},
|
||||
{std::string("CHECKSEQUENCEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKSEQUENCEVERIFY},
|
||||
{std::string("WITNESS"), (unsigned int)SCRIPT_VERIFY_WITNESS},
|
||||
{std::string("TAPROOT"), (unsigned int)SCRIPT_VERIFY_TAPROOT},
|
||||
const std::map<std::string, script_verify_flag_name> FLAG_NAMES = {
|
||||
{std::string("P2SH"), SCRIPT_VERIFY_P2SH},
|
||||
{std::string("DERSIG"), SCRIPT_VERIFY_DERSIG},
|
||||
{std::string("NULLDUMMY"), SCRIPT_VERIFY_NULLDUMMY},
|
||||
{std::string("CHECKLOCKTIMEVERIFY"), SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY},
|
||||
{std::string("CHECKSEQUENCEVERIFY"), SCRIPT_VERIFY_CHECKSEQUENCEVERIFY},
|
||||
{std::string("WITNESS"), SCRIPT_VERIFY_WITNESS},
|
||||
{std::string("TAPROOT"), SCRIPT_VERIFY_TAPROOT},
|
||||
};
|
||||
|
||||
std::vector<unsigned int> AllFlags()
|
||||
std::vector<script_verify_flags> AllFlags()
|
||||
{
|
||||
std::vector<unsigned int> ret;
|
||||
std::vector<script_verify_flags> ret;
|
||||
|
||||
for (unsigned int i = 0; i < 128; ++i) {
|
||||
unsigned int flag = 0;
|
||||
script_verify_flags flag = 0;
|
||||
if (i & 1) flag |= SCRIPT_VERIFY_P2SH;
|
||||
if (i & 2) flag |= SCRIPT_VERIFY_DERSIG;
|
||||
if (i & 4) flag |= SCRIPT_VERIFY_NULLDUMMY;
|
||||
|
@ -125,13 +125,13 @@ std::vector<unsigned int> AllFlags()
|
|||
return ret;
|
||||
}
|
||||
|
||||
const std::vector<unsigned int> ALL_FLAGS = AllFlags();
|
||||
const std::vector<script_verify_flags> ALL_FLAGS = AllFlags();
|
||||
|
||||
unsigned int ParseScriptFlags(const std::string& str)
|
||||
script_verify_flags ParseScriptFlags(const std::string& str)
|
||||
{
|
||||
if (str.empty()) return 0;
|
||||
|
||||
unsigned int flags = 0;
|
||||
script_verify_flags flags = 0;
|
||||
std::vector<std::string> words = SplitString(str, ',');
|
||||
|
||||
for (const std::string& word : words) {
|
||||
|
@ -153,7 +153,7 @@ void Test(const std::string& str)
|
|||
if (prevouts.size() != tx.vin.size()) throw std::runtime_error("Incorrect number of prevouts");
|
||||
size_t idx = test["index"].getInt<int64_t>();
|
||||
if (idx >= tx.vin.size()) throw std::runtime_error("Invalid index");
|
||||
unsigned int test_flags = ParseScriptFlags(test["flags"].get_str());
|
||||
script_verify_flags test_flags = ParseScriptFlags(test["flags"].get_str());
|
||||
bool final = test.exists("final") && test["final"].get_bool();
|
||||
|
||||
if (test.exists("success")) {
|
||||
|
|
|
@ -15,6 +15,15 @@
|
|||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
static DataStream& operator>>(DataStream& ds, script_verify_flags& f)
|
||||
{
|
||||
script_verify_flags::value_type n{0};
|
||||
ds >> n;
|
||||
f = script_verify_flags::from_int(n);
|
||||
assert(n == f.as_int());
|
||||
return ds;
|
||||
}
|
||||
|
||||
FUZZ_TARGET(script_flags)
|
||||
{
|
||||
if (buffer.size() > 100'000) return;
|
||||
|
@ -22,12 +31,14 @@ FUZZ_TARGET(script_flags)
|
|||
try {
|
||||
const CTransaction tx(deserialize, TX_WITH_WITNESS, ds);
|
||||
|
||||
unsigned int verify_flags;
|
||||
script_verify_flags verify_flags;
|
||||
ds >> verify_flags;
|
||||
|
||||
assert(verify_flags == script_verify_flags::from_int(verify_flags.as_int()));
|
||||
|
||||
if (!IsValidFlagCombination(verify_flags)) return;
|
||||
|
||||
unsigned int fuzzed_flags;
|
||||
script_verify_flags fuzzed_flags;
|
||||
ds >> fuzzed_flags;
|
||||
|
||||
std::vector<CTxOut> spent_outputs;
|
||||
|
|
|
@ -51,7 +51,7 @@ public:
|
|||
FUZZ_TARGET(signature_checker)
|
||||
{
|
||||
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
|
||||
const unsigned int flags = fuzzed_data_provider.ConsumeIntegral<unsigned int>();
|
||||
const auto flags = script_verify_flags::from_int(fuzzed_data_provider.ConsumeIntegral<script_verify_flags::value_type>());
|
||||
const SigVersion sig_version = fuzzed_data_provider.PickValueInArray({SigVersion::BASE, SigVersion::WITNESS_V0});
|
||||
const auto script_1{ConsumeScript(fuzzed_data_provider)};
|
||||
const auto script_2{ConsumeScript(fuzzed_data_provider)};
|
||||
|
|
|
@ -296,7 +296,6 @@ FUZZ_TARGET(tx_pool_standard, .init = initialize_tx_pool)
|
|||
std::set<CTransactionRef> added;
|
||||
auto txr = std::make_shared<TransactionsDelta>(removed, added);
|
||||
node.validation_signals->RegisterSharedValidationInterface(txr);
|
||||
const bool bypass_limits = fuzzed_data_provider.ConsumeBool();
|
||||
|
||||
// Make sure ProcessNewPackage on one transaction works.
|
||||
// The result is not guaranteed to be the same as what is returned by ATMP.
|
||||
|
@ -311,7 +310,7 @@ FUZZ_TARGET(tx_pool_standard, .init = initialize_tx_pool)
|
|||
it->second.m_result_type == MempoolAcceptResult::ResultType::INVALID);
|
||||
}
|
||||
|
||||
const auto res = WITH_LOCK(::cs_main, return AcceptToMemoryPool(chainstate, tx, GetTime(), bypass_limits, /*test_accept=*/false));
|
||||
const auto res = WITH_LOCK(::cs_main, return AcceptToMemoryPool(chainstate, tx, GetTime(), /*bypass_limits=*/false, /*test_accept=*/false));
|
||||
const bool accepted = res.m_result_type == MempoolAcceptResult::ResultType::VALID;
|
||||
node.validation_signals->SyncWithValidationInterfaceQueue();
|
||||
node.validation_signals->UnregisterSharedValidationInterface(txr);
|
||||
|
@ -394,6 +393,9 @@ FUZZ_TARGET(tx_pool, .init = initialize_tx_pool)
|
|||
|
||||
chainstate.SetMempool(&tx_pool);
|
||||
|
||||
// If we ever bypass limits, do not do TRUC invariants checks
|
||||
bool ever_bypassed_limits{false};
|
||||
|
||||
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 300)
|
||||
{
|
||||
const auto mut_tx = ConsumeTransaction(fuzzed_data_provider, txids);
|
||||
|
@ -412,15 +414,19 @@ FUZZ_TARGET(tx_pool, .init = initialize_tx_pool)
|
|||
tx_pool.PrioritiseTransaction(txid, delta);
|
||||
}
|
||||
|
||||
const bool bypass_limits{fuzzed_data_provider.ConsumeBool()};
|
||||
ever_bypassed_limits |= bypass_limits;
|
||||
|
||||
const auto tx = MakeTransactionRef(mut_tx);
|
||||
const bool bypass_limits = fuzzed_data_provider.ConsumeBool();
|
||||
const auto res = WITH_LOCK(::cs_main, return AcceptToMemoryPool(chainstate, tx, GetTime(), bypass_limits, /*test_accept=*/false));
|
||||
const bool accepted = res.m_result_type == MempoolAcceptResult::ResultType::VALID;
|
||||
if (accepted) {
|
||||
txids.push_back(tx->GetHash());
|
||||
if (!ever_bypassed_limits) {
|
||||
CheckMempoolTRUCInvariants(tx_pool);
|
||||
}
|
||||
}
|
||||
}
|
||||
Finish(fuzzed_data_provider, tx_pool, chainstate);
|
||||
}
|
||||
} // namespace
|
||||
|
|
|
@ -7,6 +7,7 @@ add_library(test_fuzz STATIC EXCLUDE_FROM_ALL
|
|||
descriptor.cpp
|
||||
mempool.cpp
|
||||
net.cpp
|
||||
threadinterrupt.cpp
|
||||
../fuzz.cpp
|
||||
../util.cpp
|
||||
)
|
||||
|
|
|
@ -312,6 +312,33 @@ std::unique_ptr<Sock> FuzzedSock::Accept(sockaddr* addr, socklen_t* addr_len) co
|
|||
SetFuzzedErrNo(m_fuzzed_data_provider, accept_errnos);
|
||||
return std::unique_ptr<FuzzedSock>();
|
||||
}
|
||||
if (addr != nullptr) {
|
||||
// Set a fuzzed address in the output argument addr.
|
||||
memset(addr, 0x00, *addr_len);
|
||||
if (m_fuzzed_data_provider.ConsumeBool()) {
|
||||
// IPv4
|
||||
const socklen_t write_len = static_cast<socklen_t>(sizeof(sockaddr_in));
|
||||
if (*addr_len >= write_len) {
|
||||
*addr_len = write_len;
|
||||
auto addr4 = reinterpret_cast<sockaddr_in*>(addr);
|
||||
addr4->sin_family = AF_INET;
|
||||
const auto sin_addr_bytes = m_fuzzed_data_provider.ConsumeBytes<uint8_t>(sizeof(addr4->sin_addr));
|
||||
memcpy(&addr4->sin_addr, sin_addr_bytes.data(), sin_addr_bytes.size());
|
||||
addr4->sin_port = m_fuzzed_data_provider.ConsumeIntegralInRange<uint16_t>(1, 65535);
|
||||
}
|
||||
} else {
|
||||
// IPv6
|
||||
const socklen_t write_len = static_cast<socklen_t>(sizeof(sockaddr_in6));
|
||||
if (*addr_len >= write_len) {
|
||||
*addr_len = write_len;
|
||||
auto addr6 = reinterpret_cast<sockaddr_in6*>(addr);
|
||||
addr6->sin6_family = AF_INET6;
|
||||
const auto sin_addr_bytes = m_fuzzed_data_provider.ConsumeBytes<uint8_t>(sizeof(addr6->sin6_addr));
|
||||
memcpy(&addr6->sin6_addr, sin_addr_bytes.data(), sin_addr_bytes.size());
|
||||
addr6->sin6_port = m_fuzzed_data_provider.ConsumeIntegralInRange<uint16_t>(1, 65535);
|
||||
}
|
||||
}
|
||||
}
|
||||
return std::make_unique<FuzzedSock>(m_fuzzed_data_provider);
|
||||
}
|
||||
|
||||
|
|
|
@ -139,6 +139,25 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class FuzzedNetEvents : public NetEventsInterface
|
||||
{
|
||||
public:
|
||||
FuzzedNetEvents(FuzzedDataProvider& fdp) : m_fdp(fdp) {}
|
||||
|
||||
virtual void InitializeNode(const CNode&, ServiceFlags) override {}
|
||||
|
||||
virtual void FinalizeNode(const CNode&) override {}
|
||||
|
||||
virtual bool HasAllDesirableServiceFlags(ServiceFlags) const override { return m_fdp.ConsumeBool(); }
|
||||
|
||||
virtual bool ProcessMessages(CNode*, std::atomic<bool>&) override { return m_fdp.ConsumeBool(); }
|
||||
|
||||
virtual bool SendMessages(CNode*) override { return m_fdp.ConsumeBool(); }
|
||||
|
||||
private:
|
||||
FuzzedDataProvider& m_fdp;
|
||||
};
|
||||
|
||||
class FuzzedSock : public Sock
|
||||
{
|
||||
FuzzedDataProvider& m_fuzzed_data_provider;
|
||||
|
@ -203,6 +222,11 @@ public:
|
|||
bool IsConnected(std::string& errmsg) const override;
|
||||
};
|
||||
|
||||
[[nodiscard]] inline FuzzedNetEvents ConsumeNetEvents(FuzzedDataProvider& fdp) noexcept
|
||||
{
|
||||
return FuzzedNetEvents{fdp};
|
||||
}
|
||||
|
||||
[[nodiscard]] inline FuzzedSock ConsumeSock(FuzzedDataProvider& fuzzed_data_provider)
|
||||
{
|
||||
return FuzzedSock{fuzzed_data_provider};
|
||||
|
@ -225,6 +249,18 @@ inline CService ConsumeService(FuzzedDataProvider& fuzzed_data_provider) noexcep
|
|||
return {ConsumeNetAddr(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<uint16_t>()};
|
||||
}
|
||||
|
||||
inline std::vector<CService> ConsumeServiceVector(FuzzedDataProvider& fuzzed_data_provider,
|
||||
size_t max_vector_size = 5) noexcept
|
||||
{
|
||||
std::vector<CService> ret;
|
||||
const size_t size = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, max_vector_size);
|
||||
ret.reserve(size);
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
ret.emplace_back(ConsumeService(fuzzed_data_provider));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
CAddress ConsumeAddress(FuzzedDataProvider& fuzzed_data_provider) noexcept;
|
||||
|
||||
template <bool ReturnUniquePtr = false>
|
||||
|
@ -239,6 +275,8 @@ auto ConsumeNode(FuzzedDataProvider& fuzzed_data_provider, const std::optional<N
|
|||
const std::string addr_name = fuzzed_data_provider.ConsumeRandomLengthString(64);
|
||||
const ConnectionType conn_type = fuzzed_data_provider.PickValueInArray(ALL_CONNECTION_TYPES);
|
||||
const bool inbound_onion{conn_type == ConnectionType::INBOUND ? fuzzed_data_provider.ConsumeBool() : false};
|
||||
const uint64_t network_id = fuzzed_data_provider.ConsumeIntegral<uint64_t>();
|
||||
|
||||
NetPermissionFlags permission_flags = ConsumeWeakEnum(fuzzed_data_provider, ALL_NET_PERMISSION_FLAGS);
|
||||
if constexpr (ReturnUniquePtr) {
|
||||
return std::make_unique<CNode>(node_id,
|
||||
|
@ -250,6 +288,7 @@ auto ConsumeNode(FuzzedDataProvider& fuzzed_data_provider, const std::optional<N
|
|||
addr_name,
|
||||
conn_type,
|
||||
inbound_onion,
|
||||
network_id,
|
||||
CNodeOptions{ .permission_flags = permission_flags });
|
||||
} else {
|
||||
return CNode{node_id,
|
||||
|
@ -261,6 +300,7 @@ auto ConsumeNode(FuzzedDataProvider& fuzzed_data_provider, const std::optional<N
|
|||
addr_name,
|
||||
conn_type,
|
||||
inbound_onion,
|
||||
network_id,
|
||||
CNodeOptions{ .permission_flags = permission_flags }};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
// Copyright (c) 2024-present The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <test/fuzz/util.h>
|
||||
#include <test/fuzz/util/threadinterrupt.h>
|
||||
|
||||
FuzzedThreadInterrupt::FuzzedThreadInterrupt(FuzzedDataProvider& fuzzed_data_provider)
|
||||
: m_fuzzed_data_provider{fuzzed_data_provider}
|
||||
{
|
||||
}
|
||||
|
||||
bool FuzzedThreadInterrupt::interrupted() const
|
||||
{
|
||||
return m_fuzzed_data_provider.ConsumeBool();
|
||||
}
|
||||
|
||||
bool FuzzedThreadInterrupt::sleep_for(Clock::duration)
|
||||
{
|
||||
SetMockTime(ConsumeTime(m_fuzzed_data_provider)); // Time could go backwards.
|
||||
return m_fuzzed_data_provider.ConsumeBool();
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
// Copyright (c) 2024-present The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_TEST_FUZZ_UTIL_THREADINTERRUPT_H
|
||||
#define BITCOIN_TEST_FUZZ_UTIL_THREADINTERRUPT_H
|
||||
|
||||
#include <test/fuzz/FuzzedDataProvider.h>
|
||||
#include <util/threadinterrupt.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
/**
|
||||
* Mocked CThreadInterrupt that returns "randomly" whether it is interrupted and never sleeps.
|
||||
*/
|
||||
class FuzzedThreadInterrupt : public CThreadInterrupt
|
||||
{
|
||||
public:
|
||||
explicit FuzzedThreadInterrupt(FuzzedDataProvider& fuzzed_data_provider);
|
||||
|
||||
virtual bool interrupted() const override;
|
||||
virtual bool sleep_for(Clock::duration) override;
|
||||
|
||||
private:
|
||||
FuzzedDataProvider& m_fuzzed_data_provider;
|
||||
};
|
||||
|
||||
[[nodiscard]] inline std::shared_ptr<CThreadInterrupt> ConsumeThreadInterrupt(FuzzedDataProvider& fuzzed_data_provider)
|
||||
{
|
||||
return std::make_shared<FuzzedThreadInterrupt>(fuzzed_data_provider);
|
||||
}
|
||||
|
||||
#endif // BITCOIN_TEST_FUZZ_UTIL_THREADINTERRUPT_H
|
|
@ -50,10 +50,10 @@ BOOST_AUTO_TEST_CASE(unlimited_recv)
|
|||
return std::make_unique<StaticContentsSock>(std::string(i2p::sam::MAX_MSG_SIZE + 1, 'a'));
|
||||
};
|
||||
|
||||
CThreadInterrupt interrupt;
|
||||
auto interrupt{std::make_shared<CThreadInterrupt>()};
|
||||
const std::optional<CService> addr{Lookup("127.0.0.1", 9000, false)};
|
||||
const Proxy sam_proxy(addr.value(), /*tor_stream_isolation=*/false);
|
||||
i2p::sam::Session session(gArgs.GetDataDirNet() / "test_i2p_private_key", sam_proxy, &interrupt);
|
||||
i2p::sam::Session session(gArgs.GetDataDirNet() / "test_i2p_private_key", sam_proxy, interrupt);
|
||||
|
||||
{
|
||||
ASSERT_DEBUG_LOG("Creating persistent SAM session");
|
||||
|
@ -112,12 +112,12 @@ BOOST_AUTO_TEST_CASE(listen_ok_accept_fail)
|
|||
// clang-format on
|
||||
};
|
||||
|
||||
CThreadInterrupt interrupt;
|
||||
auto interrupt{std::make_shared<CThreadInterrupt>()};
|
||||
const CService addr{in6_addr(IN6ADDR_LOOPBACK_INIT), /*port=*/7656};
|
||||
const Proxy sam_proxy(addr, /*tor_stream_isolation=*/false);
|
||||
i2p::sam::Session session(gArgs.GetDataDirNet() / "test_i2p_private_key",
|
||||
sam_proxy,
|
||||
&interrupt);
|
||||
interrupt);
|
||||
|
||||
i2p::Connection conn;
|
||||
for (size_t i = 0; i < 5; ++i) {
|
||||
|
@ -155,10 +155,10 @@ BOOST_AUTO_TEST_CASE(damaged_private_key)
|
|||
"391 bytes"}}) {
|
||||
BOOST_REQUIRE(WriteBinaryFile(i2p_private_key_file, file_contents));
|
||||
|
||||
CThreadInterrupt interrupt;
|
||||
auto interrupt{std::make_shared<CThreadInterrupt>()};
|
||||
const CService addr{in6_addr(IN6ADDR_LOOPBACK_INIT), /*port=*/7656};
|
||||
const Proxy sam_proxy{addr, /*tor_stream_isolation=*/false};
|
||||
i2p::sam::Session session(i2p_private_key_file, sam_proxy, &interrupt);
|
||||
i2p::sam::Session session(i2p_private_key_file, sam_proxy, interrupt);
|
||||
|
||||
{
|
||||
ASSERT_DEBUG_LOG("Creating persistent SAM session");
|
||||
|
|
|
@ -38,7 +38,7 @@ sign_multisig(const CScript& scriptPubKey, const std::vector<CKey>& keys, const
|
|||
|
||||
BOOST_AUTO_TEST_CASE(multisig_verify)
|
||||
{
|
||||
unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC;
|
||||
script_verify_flags flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC;
|
||||
|
||||
ScriptError err;
|
||||
CKey key[4];
|
||||
|
|
|
@ -72,7 +72,8 @@ void AddPeer(NodeId& id, std::vector<CNode*>& nodes, PeerManager& peerman, Connm
|
|||
CAddress{},
|
||||
/*addrNameIn=*/"",
|
||||
conn_type,
|
||||
/*inbound_onion=*/inbound_onion});
|
||||
/*inbound_onion=*/inbound_onion,
|
||||
/*network_key=*/0});
|
||||
CNode& node = *nodes.back();
|
||||
node.SetCommonVersion(PROTOCOL_VERSION);
|
||||
|
||||
|
@ -151,15 +152,8 @@ BOOST_FIXTURE_TEST_CASE(test_addnode_getaddednodeinfo_and_connection_detection,
|
|||
}
|
||||
|
||||
BOOST_TEST_MESSAGE("\nCheck that all connected peers are correctly detected as connected");
|
||||
for (auto node : connman->TestNodes()) {
|
||||
BOOST_CHECK(connman->AlreadyConnectedPublic(node->addr));
|
||||
}
|
||||
|
||||
BOOST_TEST_MESSAGE("\nCheck that peers with the same addresses as connected peers but different ports are detected as connected.");
|
||||
for (auto node : connman->TestNodes()) {
|
||||
uint16_t changed_port = node->addr.GetPort() + 1;
|
||||
CService address_with_changed_port{node->addr, changed_port};
|
||||
BOOST_CHECK(connman->AlreadyConnectedPublic(CAddress{address_with_changed_port, NODE_NONE}));
|
||||
for (const auto& node : connman->TestNodes()) {
|
||||
BOOST_CHECK(connman->AlreadyConnectedToAddressPublic(node->addr));
|
||||
}
|
||||
|
||||
// Clean up
|
||||
|
|
|
@ -67,7 +67,8 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test)
|
|||
CAddress(),
|
||||
pszDest,
|
||||
ConnectionType::OUTBOUND_FULL_RELAY,
|
||||
/*inbound_onion=*/false);
|
||||
/*inbound_onion=*/false,
|
||||
/*network_key=*/0);
|
||||
BOOST_CHECK(pnode1->IsFullOutboundConn() == true);
|
||||
BOOST_CHECK(pnode1->IsManualConn() == false);
|
||||
BOOST_CHECK(pnode1->IsBlockOnlyConn() == false);
|
||||
|
@ -85,7 +86,8 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test)
|
|||
CAddress(),
|
||||
pszDest,
|
||||
ConnectionType::INBOUND,
|
||||
/*inbound_onion=*/false);
|
||||
/*inbound_onion=*/false,
|
||||
/*network_key=*/1);
|
||||
BOOST_CHECK(pnode2->IsFullOutboundConn() == false);
|
||||
BOOST_CHECK(pnode2->IsManualConn() == false);
|
||||
BOOST_CHECK(pnode2->IsBlockOnlyConn() == false);
|
||||
|
@ -103,7 +105,8 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test)
|
|||
CAddress(),
|
||||
pszDest,
|
||||
ConnectionType::OUTBOUND_FULL_RELAY,
|
||||
/*inbound_onion=*/false);
|
||||
/*inbound_onion=*/false,
|
||||
/*network_key=*/2);
|
||||
BOOST_CHECK(pnode3->IsFullOutboundConn() == true);
|
||||
BOOST_CHECK(pnode3->IsManualConn() == false);
|
||||
BOOST_CHECK(pnode3->IsBlockOnlyConn() == false);
|
||||
|
@ -121,7 +124,8 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test)
|
|||
CAddress(),
|
||||
pszDest,
|
||||
ConnectionType::INBOUND,
|
||||
/*inbound_onion=*/true);
|
||||
/*inbound_onion=*/true,
|
||||
/*network_key=*/3);
|
||||
BOOST_CHECK(pnode4->IsFullOutboundConn() == false);
|
||||
BOOST_CHECK(pnode4->IsManualConn() == false);
|
||||
BOOST_CHECK(pnode4->IsBlockOnlyConn() == false);
|
||||
|
@ -613,7 +617,8 @@ BOOST_AUTO_TEST_CASE(ipv4_peer_with_ipv6_addrMe_test)
|
|||
CAddress{},
|
||||
/*pszDest=*/std::string{},
|
||||
ConnectionType::OUTBOUND_FULL_RELAY,
|
||||
/*inbound_onion=*/false);
|
||||
/*inbound_onion=*/false,
|
||||
/*network_key=*/0);
|
||||
pnode->fSuccessfullyConnected.store(true);
|
||||
|
||||
// the peer claims to be reaching us via IPv6
|
||||
|
@ -667,7 +672,8 @@ BOOST_AUTO_TEST_CASE(get_local_addr_for_peer_port)
|
|||
/*addrBindIn=*/CService{},
|
||||
/*addrNameIn=*/std::string{},
|
||||
/*conn_type_in=*/ConnectionType::OUTBOUND_FULL_RELAY,
|
||||
/*inbound_onion=*/false};
|
||||
/*inbound_onion=*/false,
|
||||
/*network_key=*/0};
|
||||
peer_out.fSuccessfullyConnected = true;
|
||||
peer_out.SetAddrLocal(peer_us);
|
||||
|
||||
|
@ -688,7 +694,8 @@ BOOST_AUTO_TEST_CASE(get_local_addr_for_peer_port)
|
|||
/*addrBindIn=*/CService{},
|
||||
/*addrNameIn=*/std::string{},
|
||||
/*conn_type_in=*/ConnectionType::INBOUND,
|
||||
/*inbound_onion=*/false};
|
||||
/*inbound_onion=*/false,
|
||||
/*network_key=*/1};
|
||||
peer_in.fSuccessfullyConnected = true;
|
||||
peer_in.SetAddrLocal(peer_us);
|
||||
|
||||
|
@ -825,7 +832,8 @@ BOOST_AUTO_TEST_CASE(initial_advertise_from_version_message)
|
|||
/*addrBindIn=*/CService{},
|
||||
/*addrNameIn=*/std::string{},
|
||||
/*conn_type_in=*/ConnectionType::OUTBOUND_FULL_RELAY,
|
||||
/*inbound_onion=*/false};
|
||||
/*inbound_onion=*/false,
|
||||
/*network_key=*/2};
|
||||
|
||||
const uint64_t services{NODE_NETWORK | NODE_WITNESS};
|
||||
const int64_t time{0};
|
||||
|
@ -900,7 +908,8 @@ BOOST_AUTO_TEST_CASE(advertise_local_address)
|
|||
CAddress{},
|
||||
/*pszDest=*/std::string{},
|
||||
ConnectionType::OUTBOUND_FULL_RELAY,
|
||||
/*inbound_onion=*/false);
|
||||
/*inbound_onion=*/false,
|
||||
/*network_key=*/0);
|
||||
};
|
||||
g_reachable_nets.Add(NET_CJDNS);
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
|
||||
#include <univalue.h>
|
||||
|
||||
unsigned int ParseScriptFlags(std::string strFlags);
|
||||
script_verify_flags ParseScriptFlags(std::string strFlags);
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(script_assets_tests)
|
||||
|
||||
|
@ -71,12 +71,12 @@ static CScriptWitness ScriptWitnessFromJSON(const UniValue& univalue)
|
|||
return scriptwitness;
|
||||
}
|
||||
|
||||
static std::vector<unsigned int> AllConsensusFlags()
|
||||
static std::vector<script_verify_flags> AllConsensusFlags()
|
||||
{
|
||||
std::vector<unsigned int> ret;
|
||||
std::vector<script_verify_flags> ret;
|
||||
|
||||
for (unsigned int i = 0; i < 128; ++i) {
|
||||
unsigned int flag = 0;
|
||||
script_verify_flags flag = 0;
|
||||
if (i & 1) flag |= SCRIPT_VERIFY_P2SH;
|
||||
if (i & 2) flag |= SCRIPT_VERIFY_DERSIG;
|
||||
if (i & 4) flag |= SCRIPT_VERIFY_NULLDUMMY;
|
||||
|
@ -97,7 +97,7 @@ static std::vector<unsigned int> AllConsensusFlags()
|
|||
}
|
||||
|
||||
/** Precomputed list of all valid combinations of consensus-relevant script validation flags. */
|
||||
static const std::vector<unsigned int> ALL_CONSENSUS_FLAGS = AllConsensusFlags();
|
||||
static const std::vector<script_verify_flags> ALL_CONSENSUS_FLAGS = AllConsensusFlags();
|
||||
|
||||
static void AssetTest(const UniValue& test, SignatureCache& signature_cache)
|
||||
{
|
||||
|
@ -107,7 +107,7 @@ static void AssetTest(const UniValue& test, SignatureCache& signature_cache)
|
|||
const std::vector<CTxOut> prevouts = TxOutsFromJSON(test["prevouts"]);
|
||||
BOOST_CHECK(prevouts.size() == mtx.vin.size());
|
||||
size_t idx = test["index"].getInt<int64_t>();
|
||||
uint32_t test_flags{ParseScriptFlags(test["flags"].get_str())};
|
||||
script_verify_flags test_flags{ParseScriptFlags(test["flags"].get_str())};
|
||||
bool fin = test.exists("final") && test["final"].get_bool();
|
||||
|
||||
if (test.exists("success")) {
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <core_io.h>
|
||||
#include <key.h>
|
||||
#include <rpc/util.h>
|
||||
#include <script/interpreter.h>
|
||||
#include <script/script.h>
|
||||
#include <script/script_error.h>
|
||||
#include <script/sigcache.h>
|
||||
|
@ -22,6 +23,7 @@
|
|||
#include <test/util/transaction_utils.h>
|
||||
#include <util/fs.h>
|
||||
#include <util/strencodings.h>
|
||||
#include <util/string.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
|
@ -38,10 +40,9 @@
|
|||
|
||||
using namespace util::hex_literals;
|
||||
|
||||
static const unsigned int gFlags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC;
|
||||
static const script_verify_flags gFlags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC;
|
||||
|
||||
unsigned int ParseScriptFlags(std::string strFlags);
|
||||
std::string FormatScriptFlags(unsigned int flags);
|
||||
script_verify_flags ParseScriptFlags(std::string strFlags);
|
||||
|
||||
struct ScriptErrorDesc
|
||||
{
|
||||
|
@ -95,6 +96,11 @@ static ScriptErrorDesc script_errors[]={
|
|||
{SCRIPT_ERR_SIG_FINDANDDELETE, "SIG_FINDANDDELETE"},
|
||||
};
|
||||
|
||||
static std::string FormatScriptFlags(script_verify_flags flags)
|
||||
{
|
||||
return util::Join(GetScriptFlagNames(flags), ",");
|
||||
}
|
||||
|
||||
static std::string FormatScriptError(ScriptError_t err)
|
||||
{
|
||||
for (const auto& se : script_errors)
|
||||
|
@ -114,7 +120,7 @@ static ScriptError_t ParseScriptError(const std::string& name)
|
|||
}
|
||||
|
||||
struct ScriptTest : BasicTestingSetup {
|
||||
void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, const CScriptWitness& scriptWitness, uint32_t flags, const std::string& message, int scriptError, CAmount nValue = 0)
|
||||
void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, const CScriptWitness& scriptWitness, script_verify_flags flags, const std::string& message, int scriptError, CAmount nValue = 0)
|
||||
{
|
||||
bool expect = (scriptError == SCRIPT_ERR_OK);
|
||||
if (flags & SCRIPT_VERIFY_CLEANSTACK) {
|
||||
|
@ -128,13 +134,13 @@ void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, const CScript
|
|||
BOOST_CHECK_MESSAGE(err == scriptError, FormatScriptError(err) + " where " + FormatScriptError((ScriptError_t)scriptError) + " expected: " + message);
|
||||
|
||||
// Verify that removing flags from a passing test or adding flags to a failing test does not change the result.
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
uint32_t extra_flags(m_rng.randbits(16));
|
||||
uint32_t combined_flags{expect ? (flags & ~extra_flags) : (flags | extra_flags)};
|
||||
for (int i = 0; i < 256; ++i) {
|
||||
script_verify_flags extra_flags = script_verify_flags::from_int(m_rng.randbits(MAX_SCRIPT_VERIFY_FLAGS_BITS));
|
||||
script_verify_flags combined_flags{expect ? (flags & ~extra_flags) : (flags | extra_flags)};
|
||||
// Weed out some invalid flag combinations.
|
||||
if (combined_flags & SCRIPT_VERIFY_CLEANSTACK && ~combined_flags & (SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS)) continue;
|
||||
if (combined_flags & SCRIPT_VERIFY_WITNESS && ~combined_flags & SCRIPT_VERIFY_P2SH) continue;
|
||||
BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, &scriptWitness, combined_flags, MutableTransactionSignatureChecker(&tx, 0, txCredit.vout[0].nValue, MissingDataBehavior::ASSERT_FAIL), &err) == expect, message + strprintf(" (with flags %x)", combined_flags));
|
||||
BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, &scriptWitness, combined_flags, MutableTransactionSignatureChecker(&tx, 0, txCredit.vout[0].nValue, MissingDataBehavior::ASSERT_FAIL), &err) == expect, message + strprintf(" (with flags %x)", combined_flags.as_int()));
|
||||
}
|
||||
}
|
||||
}; // struct ScriptTest
|
||||
|
@ -226,7 +232,7 @@ private:
|
|||
bool havePush{false};
|
||||
std::vector<unsigned char> push;
|
||||
std::string comment;
|
||||
uint32_t flags;
|
||||
script_verify_flags flags;
|
||||
int scriptError{SCRIPT_ERR_OK};
|
||||
CAmount nValue;
|
||||
|
||||
|
@ -246,7 +252,7 @@ private:
|
|||
}
|
||||
|
||||
public:
|
||||
TestBuilder(const CScript& script_, const std::string& comment_, uint32_t flags_, bool P2SH = false, WitnessMode wm = WitnessMode::NONE, int witnessversion = 0, CAmount nValue_ = 0) : script(script_), comment(comment_), flags(flags_), nValue(nValue_)
|
||||
TestBuilder(const CScript& script_, const std::string& comment_, script_verify_flags flags_, bool P2SH = false, WitnessMode wm = WitnessMode::NONE, int witnessversion = 0, CAmount nValue_ = 0) : script(script_), comment(comment_), flags(flags_), nValue(nValue_)
|
||||
{
|
||||
CScript scriptPubKey = script;
|
||||
if (wm == WitnessMode::PKH) {
|
||||
|
@ -963,7 +969,7 @@ BOOST_AUTO_TEST_CASE(script_json_test)
|
|||
} else {
|
||||
scriptPubKey = ParseScript(scriptPubKeyString);
|
||||
}
|
||||
unsigned int scriptflags = ParseScriptFlags(test[pos++].get_str());
|
||||
script_verify_flags scriptflags = ParseScriptFlags(test[pos++].get_str());
|
||||
int scriptError = ParseScriptError(test[pos++].get_str());
|
||||
|
||||
DoTest(scriptPubKey, scriptSig, witness, scriptflags, strTest, scriptError, nValue);
|
||||
|
@ -1706,4 +1712,15 @@ BOOST_AUTO_TEST_CASE(compute_tapleaf)
|
|||
BOOST_CHECK_EQUAL(ComputeTapleafHash(0xc2, std::span(script)), tlc2);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(formatscriptflags)
|
||||
{
|
||||
// quick check that FormatScriptFlags reports any unknown/unexpected bits
|
||||
BOOST_CHECK_EQUAL(FormatScriptFlags(SCRIPT_VERIFY_P2SH), "P2SH");
|
||||
BOOST_CHECK_EQUAL(FormatScriptFlags(SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_TAPROOT), "P2SH,TAPROOT");
|
||||
BOOST_CHECK_EQUAL(FormatScriptFlags(SCRIPT_VERIFY_P2SH | script_verify_flags::from_int(1u<<31)), "P2SH,0x80000000");
|
||||
BOOST_CHECK_EQUAL(FormatScriptFlags(SCRIPT_VERIFY_TAPROOT | script_verify_flags::from_int(1u<<27)), "TAPROOT,0x08000000");
|
||||
BOOST_CHECK_EQUAL(FormatScriptFlags(SCRIPT_VERIFY_TAPROOT | script_verify_flags::from_int((1u<<28) | (1ull<<58))), "TAPROOT,0x400000010000000");
|
||||
BOOST_CHECK_EQUAL(FormatScriptFlags(script_verify_flags::from_int(1u<<26)), "0x04000000");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
|
|
@ -69,7 +69,7 @@ BOOST_AUTO_TEST_CASE(GetSigOpCount)
|
|||
* Verifies script execution of the zeroth scriptPubKey of tx output and
|
||||
* zeroth scriptSig and witness of tx input.
|
||||
*/
|
||||
static ScriptError VerifyWithFlag(const CTransaction& output, const CMutableTransaction& input, uint32_t flags)
|
||||
static ScriptError VerifyWithFlag(const CTransaction& output, const CMutableTransaction& input, script_verify_flags flags)
|
||||
{
|
||||
ScriptError error;
|
||||
CTransaction inputi(input);
|
||||
|
@ -122,7 +122,7 @@ BOOST_AUTO_TEST_CASE(GetTxSigOpCost)
|
|||
CKey key = GenerateRandomKey();
|
||||
CPubKey pubkey = key.GetPubKey();
|
||||
// Default flags
|
||||
const uint32_t flags{SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH};
|
||||
const script_verify_flags flags{SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH};
|
||||
|
||||
// Multisig script (legacy counting)
|
||||
{
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <policy/policy.h>
|
||||
#include <policy/settings.h>
|
||||
#include <primitives/transaction_identifier.h>
|
||||
#include <script/interpreter.h>
|
||||
#include <script/script.h>
|
||||
#include <script/script_error.h>
|
||||
#include <script/sigcache.h>
|
||||
|
@ -49,41 +50,21 @@ typedef std::vector<unsigned char> valtype;
|
|||
static CFeeRate g_dust{DUST_RELAY_TX_FEE};
|
||||
static bool g_bare_multi{DEFAULT_PERMIT_BAREMULTISIG};
|
||||
|
||||
static std::map<std::string, unsigned int> mapFlagNames = {
|
||||
{std::string("P2SH"), (unsigned int)SCRIPT_VERIFY_P2SH},
|
||||
{std::string("STRICTENC"), (unsigned int)SCRIPT_VERIFY_STRICTENC},
|
||||
{std::string("DERSIG"), (unsigned int)SCRIPT_VERIFY_DERSIG},
|
||||
{std::string("LOW_S"), (unsigned int)SCRIPT_VERIFY_LOW_S},
|
||||
{std::string("SIGPUSHONLY"), (unsigned int)SCRIPT_VERIFY_SIGPUSHONLY},
|
||||
{std::string("MINIMALDATA"), (unsigned int)SCRIPT_VERIFY_MINIMALDATA},
|
||||
{std::string("NULLDUMMY"), (unsigned int)SCRIPT_VERIFY_NULLDUMMY},
|
||||
{std::string("DISCOURAGE_UPGRADABLE_NOPS"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS},
|
||||
{std::string("CLEANSTACK"), (unsigned int)SCRIPT_VERIFY_CLEANSTACK},
|
||||
{std::string("MINIMALIF"), (unsigned int)SCRIPT_VERIFY_MINIMALIF},
|
||||
{std::string("NULLFAIL"), (unsigned int)SCRIPT_VERIFY_NULLFAIL},
|
||||
{std::string("CHECKLOCKTIMEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY},
|
||||
{std::string("CHECKSEQUENCEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKSEQUENCEVERIFY},
|
||||
{std::string("WITNESS"), (unsigned int)SCRIPT_VERIFY_WITNESS},
|
||||
{std::string("DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM},
|
||||
{std::string("WITNESS_PUBKEYTYPE"), (unsigned int)SCRIPT_VERIFY_WITNESS_PUBKEYTYPE},
|
||||
{std::string("CONST_SCRIPTCODE"), (unsigned int)SCRIPT_VERIFY_CONST_SCRIPTCODE},
|
||||
{std::string("TAPROOT"), (unsigned int)SCRIPT_VERIFY_TAPROOT},
|
||||
{std::string("DISCOURAGE_UPGRADABLE_PUBKEYTYPE"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE},
|
||||
{std::string("DISCOURAGE_OP_SUCCESS"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS},
|
||||
{std::string("DISCOURAGE_UPGRADABLE_TAPROOT_VERSION"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION},
|
||||
};
|
||||
static const std::map<std::string, script_verify_flag_name>& mapFlagNames = g_verify_flag_names;
|
||||
|
||||
unsigned int ParseScriptFlags(std::string strFlags)
|
||||
script_verify_flags ParseScriptFlags(std::string strFlags)
|
||||
{
|
||||
unsigned int flags = SCRIPT_VERIFY_NONE;
|
||||
script_verify_flags flags = SCRIPT_VERIFY_NONE;
|
||||
if (strFlags.empty() || strFlags == "NONE") return flags;
|
||||
|
||||
std::vector<std::string> words = SplitString(strFlags, ',');
|
||||
for (const std::string& word : words)
|
||||
{
|
||||
if (!mapFlagNames.count(word))
|
||||
if (!mapFlagNames.count(word)) {
|
||||
BOOST_ERROR("Bad test: unknown verification flag '" << word << "'");
|
||||
flags |= mapFlagNames[word];
|
||||
continue;
|
||||
}
|
||||
flags |= mapFlagNames.at(word);
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
@ -91,34 +72,18 @@ unsigned int ParseScriptFlags(std::string strFlags)
|
|||
// Check that all flags in STANDARD_SCRIPT_VERIFY_FLAGS are present in mapFlagNames.
|
||||
bool CheckMapFlagNames()
|
||||
{
|
||||
unsigned int standard_flags_missing{STANDARD_SCRIPT_VERIFY_FLAGS};
|
||||
script_verify_flags standard_flags_missing{STANDARD_SCRIPT_VERIFY_FLAGS};
|
||||
for (const auto& pair : mapFlagNames) {
|
||||
standard_flags_missing &= ~(pair.second);
|
||||
}
|
||||
return standard_flags_missing == 0;
|
||||
}
|
||||
|
||||
std::string FormatScriptFlags(unsigned int flags)
|
||||
{
|
||||
if (flags == SCRIPT_VERIFY_NONE) {
|
||||
return "";
|
||||
}
|
||||
std::string ret;
|
||||
std::map<std::string, unsigned int>::const_iterator it = mapFlagNames.begin();
|
||||
while (it != mapFlagNames.end()) {
|
||||
if (flags & it->second) {
|
||||
ret += it->first + ",";
|
||||
}
|
||||
it++;
|
||||
}
|
||||
return ret.substr(0, ret.size() - 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that the input scripts of a transaction are valid/invalid as expected.
|
||||
*/
|
||||
bool CheckTxScripts(const CTransaction& tx, const std::map<COutPoint, CScript>& map_prevout_scriptPubKeys,
|
||||
const std::map<COutPoint, int64_t>& map_prevout_values, unsigned int flags,
|
||||
const std::map<COutPoint, int64_t>& map_prevout_values, script_verify_flags flags,
|
||||
const PrecomputedTransactionData& txdata, const std::string& strTest, bool expect_valid)
|
||||
{
|
||||
bool tx_valid = true;
|
||||
|
@ -152,18 +117,18 @@ bool CheckTxScripts(const CTransaction& tx, const std::map<COutPoint, CScript>&
|
|||
* CLEANSTACK must be used WITNESS and P2SH
|
||||
*/
|
||||
|
||||
unsigned int TrimFlags(unsigned int flags)
|
||||
script_verify_flags TrimFlags(script_verify_flags flags)
|
||||
{
|
||||
// WITNESS requires P2SH
|
||||
if (!(flags & SCRIPT_VERIFY_P2SH)) flags &= ~(unsigned int)SCRIPT_VERIFY_WITNESS;
|
||||
if (!(flags & SCRIPT_VERIFY_P2SH)) flags &= ~SCRIPT_VERIFY_WITNESS;
|
||||
|
||||
// CLEANSTACK requires WITNESS (and transitively CLEANSTACK requires P2SH)
|
||||
if (!(flags & SCRIPT_VERIFY_WITNESS)) flags &= ~(unsigned int)SCRIPT_VERIFY_CLEANSTACK;
|
||||
if (!(flags & SCRIPT_VERIFY_WITNESS)) flags &= ~SCRIPT_VERIFY_CLEANSTACK;
|
||||
Assert(IsValidFlagCombination(flags));
|
||||
return flags;
|
||||
}
|
||||
|
||||
unsigned int FillFlags(unsigned int flags)
|
||||
script_verify_flags FillFlags(script_verify_flags flags)
|
||||
{
|
||||
// CLEANSTACK implies WITNESS
|
||||
if (flags & SCRIPT_VERIFY_CLEANSTACK) flags |= SCRIPT_VERIFY_WITNESS;
|
||||
|
@ -178,11 +143,11 @@ unsigned int FillFlags(unsigned int flags)
|
|||
// that are valid and without duplicates. For example: if flags=1111 and the 4 possible flags are
|
||||
// 0001, 0010, 0100, and 1000, this should return the set {0111, 1011, 1101, 1110}.
|
||||
// Assumes that mapFlagNames contains all script verify flags.
|
||||
std::set<unsigned int> ExcludeIndividualFlags(unsigned int flags)
|
||||
std::set<script_verify_flags> ExcludeIndividualFlags(script_verify_flags flags)
|
||||
{
|
||||
std::set<unsigned int> flags_combos;
|
||||
std::set<script_verify_flags> flags_combos;
|
||||
for (const auto& pair : mapFlagNames) {
|
||||
const unsigned int flags_excluding_one = TrimFlags(flags & ~(pair.second));
|
||||
script_verify_flags flags_excluding_one = TrimFlags(flags & ~(pair.second));
|
||||
if (flags != flags_excluding_one) {
|
||||
flags_combos.insert(flags_excluding_one);
|
||||
}
|
||||
|
@ -247,7 +212,7 @@ BOOST_AUTO_TEST_CASE(tx_valid)
|
|||
BOOST_CHECK(state.IsValid());
|
||||
|
||||
PrecomputedTransactionData txdata(tx);
|
||||
unsigned int verify_flags = ParseScriptFlags(test[2].get_str());
|
||||
script_verify_flags verify_flags = ParseScriptFlags(test[2].get_str());
|
||||
|
||||
// Check that the test gives a valid combination of flags (otherwise VerifyScript will throw). Don't edit the flags.
|
||||
if (~verify_flags != FillFlags(~verify_flags)) {
|
||||
|
@ -260,14 +225,14 @@ BOOST_AUTO_TEST_CASE(tx_valid)
|
|||
// Backwards compatibility of script verification flags: Removing any flag(s) should not invalidate a valid transaction
|
||||
for (const auto& [name, flag] : mapFlagNames) {
|
||||
// Removing individual flags
|
||||
unsigned int flags = TrimFlags(~(verify_flags | flag));
|
||||
script_verify_flags flags = TrimFlags(~(verify_flags | flag));
|
||||
if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, flags, txdata, strTest, /*expect_valid=*/true)) {
|
||||
BOOST_ERROR("Tx unexpectedly failed with flag " << name << " unset: " << strTest);
|
||||
}
|
||||
// Removing random combinations of flags
|
||||
flags = TrimFlags(~(verify_flags | (unsigned int)m_rng.randbits(mapFlagNames.size())));
|
||||
flags = TrimFlags(~(verify_flags | script_verify_flags::from_int(m_rng.randbits(MAX_SCRIPT_VERIFY_FLAGS_BITS))));
|
||||
if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, flags, txdata, strTest, /*expect_valid=*/true)) {
|
||||
BOOST_ERROR("Tx unexpectedly failed with random flags " << ToString(flags) << ": " << strTest);
|
||||
BOOST_ERROR("Tx unexpectedly failed with random flags " << ToString(flags.as_int()) << ": " << strTest);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -337,7 +302,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
|
|||
}
|
||||
|
||||
PrecomputedTransactionData txdata(tx);
|
||||
unsigned int verify_flags = ParseScriptFlags(test[2].get_str());
|
||||
script_verify_flags verify_flags = ParseScriptFlags(test[2].get_str());
|
||||
|
||||
// Check that the test gives a valid combination of flags (otherwise VerifyScript will throw). Don't edit the flags.
|
||||
if (verify_flags != FillFlags(verify_flags)) {
|
||||
|
@ -350,13 +315,13 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
|
|||
|
||||
// Backwards compatibility of script verification flags: Adding any flag(s) should not validate an invalid transaction
|
||||
for (const auto& [name, flag] : mapFlagNames) {
|
||||
unsigned int flags = FillFlags(verify_flags | flag);
|
||||
script_verify_flags flags = FillFlags(verify_flags | flag);
|
||||
// Adding individual flags
|
||||
if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, flags, txdata, strTest, /*expect_valid=*/false)) {
|
||||
BOOST_ERROR("Tx unexpectedly passed with flag " << name << " set: " << strTest);
|
||||
}
|
||||
// Adding random combinations of flags
|
||||
flags = FillFlags(verify_flags | (unsigned int)m_rng.randbits(mapFlagNames.size()));
|
||||
flags = FillFlags(verify_flags | script_verify_flags::from_int(m_rng.randbits(MAX_SCRIPT_VERIFY_FLAGS_BITS)));
|
||||
if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, flags, txdata, strTest, /*expect_valid=*/false)) {
|
||||
BOOST_ERROR("Tx unexpectedly passed with random flags " << name << ": " << strTest);
|
||||
}
|
||||
|
@ -488,7 +453,7 @@ static void CreateCreditAndSpend(const FillableSigningProvider& keystore, const
|
|||
assert(input.vin[0].scriptWitness.stack == inputm.vin[0].scriptWitness.stack);
|
||||
}
|
||||
|
||||
static void CheckWithFlag(const CTransactionRef& output, const CMutableTransaction& input, uint32_t flags, bool success)
|
||||
static void CheckWithFlag(const CTransactionRef& output, const CMutableTransaction& input, script_verify_flags flags, bool success)
|
||||
{
|
||||
ScriptError error;
|
||||
CTransaction inputi(input);
|
||||
|
|
|
@ -21,7 +21,7 @@ struct Dersig100Setup : public TestChain100Setup {
|
|||
};
|
||||
|
||||
bool CheckInputScripts(const CTransaction& tx, TxValidationState& state,
|
||||
const CCoinsViewCache& inputs, unsigned int flags, bool cacheSigStore,
|
||||
const CCoinsViewCache& inputs, script_verify_flags flags, bool cacheSigStore,
|
||||
bool cacheFullScriptStore, PrecomputedTransactionData& txdata,
|
||||
ValidationCache& validation_cache,
|
||||
std::vector<CScriptCheck>* pvChecks) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||
|
@ -120,7 +120,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, Dersig100Setup)
|
|||
// should fail.
|
||||
// Capture this interaction with the upgraded_nop argument: set it when evaluating
|
||||
// any script flag that is implemented as an upgraded NOP code.
|
||||
static void ValidateCheckInputsForAllFlags(const CTransaction &tx, uint32_t failing_flags, bool add_to_cache, CCoinsViewCache& active_coins_tip, ValidationCache& validation_cache) EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
|
||||
static void ValidateCheckInputsForAllFlags(const CTransaction &tx, script_verify_flags failing_flags, bool add_to_cache, CCoinsViewCache& active_coins_tip, ValidationCache& validation_cache) EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
|
||||
{
|
||||
PrecomputedTransactionData txdata;
|
||||
|
||||
|
@ -130,7 +130,7 @@ static void ValidateCheckInputsForAllFlags(const CTransaction &tx, uint32_t fail
|
|||
TxValidationState state;
|
||||
|
||||
// Randomly selects flag combinations
|
||||
uint32_t test_flags = (uint32_t) insecure_rand.randrange((SCRIPT_VERIFY_END_MARKER - 1) << 1);
|
||||
script_verify_flags test_flags = script_verify_flags::from_int(insecure_rand.randrange(MAX_SCRIPT_VERIFY_FLAGS));
|
||||
|
||||
// Filter out incompatible flag choices
|
||||
if ((test_flags & SCRIPT_VERIFY_CLEANSTACK)) {
|
||||
|
|
|
@ -116,7 +116,7 @@ bool ConnmanTestMsg::ReceiveMsgFrom(CNode& node, CSerializedNetMsg&& ser_msg) co
|
|||
|
||||
CNode* ConnmanTestMsg::ConnectNodePublic(PeerManager& peerman, const char* pszDest, ConnectionType conn_type)
|
||||
{
|
||||
CNode* node = ConnectNode(CAddress{}, pszDest, /*fCountFailure=*/false, conn_type, /*use_v2transport=*/true);
|
||||
CNode* node = ConnectNode(CAddress{}, pszDest, /*fCountFailure=*/false, conn_type, /*use_v2transport=*/true, /*proxy_override=*/std::nullopt);
|
||||
if (!node) return nullptr;
|
||||
node->SetCommonVersion(PROTOCOL_VERSION);
|
||||
peerman.InitializeNode(*node, ServiceFlags(NODE_NETWORK | NODE_WITNESS));
|
||||
|
|
|
@ -71,6 +71,24 @@ struct ConnmanTestMsg : public CConnman {
|
|||
m_nodes.clear();
|
||||
}
|
||||
|
||||
void CreateNodeFromAcceptedSocketPublic(std::unique_ptr<Sock> sock,
|
||||
NetPermissionFlags permissions,
|
||||
const CAddress& addr_bind,
|
||||
const CAddress& addr_peer)
|
||||
{
|
||||
CreateNodeFromAcceptedSocket(std::move(sock), permissions, addr_bind, addr_peer);
|
||||
}
|
||||
|
||||
bool InitBindsPublic(const CConnman::Options& options)
|
||||
{
|
||||
return InitBinds(options);
|
||||
}
|
||||
|
||||
void SocketHandlerPublic()
|
||||
{
|
||||
SocketHandler();
|
||||
}
|
||||
|
||||
void Handshake(CNode& node,
|
||||
bool successfully_connected,
|
||||
ServiceFlags remote_services,
|
||||
|
@ -89,7 +107,7 @@ struct ConnmanTestMsg : public CConnman {
|
|||
bool ReceiveMsgFrom(CNode& node, CSerializedNetMsg&& ser_msg) const;
|
||||
void FlushSendBuffer(CNode& node) const;
|
||||
|
||||
bool AlreadyConnectedPublic(const CAddress& addr) { return AlreadyConnectedToAddress(addr); };
|
||||
bool AlreadyConnectedToAddressPublic(const CNetAddr& addr) { return AlreadyConnectedToAddress(addr); };
|
||||
|
||||
CNode* ConnectNodePublic(PeerManager& peerman, const char* pszDest, ConnectionType conn_type)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(!m_unused_i2p_sessions_mutex);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include <script/interpreter.h>
|
||||
#include <test/util/script.h>
|
||||
|
||||
bool IsValidFlagCombination(unsigned flags)
|
||||
bool IsValidFlagCombination(script_verify_flags flags)
|
||||
{
|
||||
if (flags & SCRIPT_VERIFY_CLEANSTACK && ~flags & (SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS)) return false;
|
||||
if (flags & SCRIPT_VERIFY_WITNESS && ~flags & SCRIPT_VERIFY_P2SH) return false;
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include <crypto/sha256.h>
|
||||
#include <script/script.h>
|
||||
#include <script/verify_flags.h>
|
||||
|
||||
static const std::vector<uint8_t> WITNESS_STACK_ELEM_OP_TRUE{uint8_t{OP_TRUE}};
|
||||
static const CScript P2WSH_OP_TRUE{
|
||||
|
@ -31,6 +32,6 @@ static const std::vector<std::vector<uint8_t>> P2WSH_EMPTY_TRUE_STACK{{static_ca
|
|||
static const std::vector<std::vector<uint8_t>> P2WSH_EMPTY_TWO_STACK{{static_cast<uint8_t>(OP_2)}, {}};
|
||||
|
||||
/** Flags that are not forbidden by an assert in script validation */
|
||||
bool IsValidFlagCombination(unsigned flags);
|
||||
bool IsValidFlagCombination(script_verify_flags flags);
|
||||
|
||||
#endif // BITCOIN_TEST_UTIL_SCRIPT_H
|
||||
|
|
|
@ -9,11 +9,16 @@
|
|||
|
||||
CThreadInterrupt::CThreadInterrupt() : flag(false) {}
|
||||
|
||||
CThreadInterrupt::operator bool() const
|
||||
bool CThreadInterrupt::interrupted() const
|
||||
{
|
||||
return flag.load(std::memory_order_acquire);
|
||||
}
|
||||
|
||||
CThreadInterrupt::operator bool() const
|
||||
{
|
||||
return interrupted();
|
||||
}
|
||||
|
||||
void CThreadInterrupt::reset()
|
||||
{
|
||||
flag.store(false, std::memory_order_release);
|
||||
|
|
|
@ -27,11 +27,27 @@ class CThreadInterrupt
|
|||
{
|
||||
public:
|
||||
using Clock = std::chrono::steady_clock;
|
||||
|
||||
CThreadInterrupt();
|
||||
explicit operator bool() const;
|
||||
void operator()() EXCLUSIVE_LOCKS_REQUIRED(!mut);
|
||||
void reset();
|
||||
bool sleep_for(Clock::duration rel_time) EXCLUSIVE_LOCKS_REQUIRED(!mut);
|
||||
|
||||
virtual ~CThreadInterrupt() = default;
|
||||
|
||||
/// Return true if `operator()()` has been called.
|
||||
virtual bool interrupted() const;
|
||||
|
||||
/// An alias for `interrupted()`.
|
||||
virtual explicit operator bool() const;
|
||||
|
||||
/// Interrupt any sleeps. After this `interrupted()` will return `true`.
|
||||
virtual void operator()() EXCLUSIVE_LOCKS_REQUIRED(!mut);
|
||||
|
||||
/// Reset to an non-interrupted state.
|
||||
virtual void reset();
|
||||
|
||||
/// Sleep for the given duration.
|
||||
/// @retval true The time passed.
|
||||
/// @retval false The sleep was interrupted.
|
||||
virtual bool sleep_for(Clock::duration rel_time) EXCLUSIVE_LOCKS_REQUIRED(!mut);
|
||||
|
||||
private:
|
||||
std::condition_variable cond;
|
||||
|
|
|
@ -139,7 +139,7 @@ const CBlockIndex* Chainstate::FindForkInGlobalIndex(const CBlockLocator& locato
|
|||
}
|
||||
|
||||
bool CheckInputScripts(const CTransaction& tx, TxValidationState& state,
|
||||
const CCoinsViewCache& inputs, unsigned int flags, bool cacheSigStore,
|
||||
const CCoinsViewCache& inputs, script_verify_flags flags, bool cacheSigStore,
|
||||
bool cacheFullScriptStore, PrecomputedTransactionData& txdata,
|
||||
ValidationCache& validation_cache,
|
||||
std::vector<CScriptCheck>* pvChecks = nullptr)
|
||||
|
@ -262,9 +262,6 @@ bool CheckSequenceLocksAtTip(CBlockIndex* tip,
|
|||
return EvaluateSequenceLocks(index, {lock_points.height, lock_points.time});
|
||||
}
|
||||
|
||||
// Returns the script flags which should be checked for a given block
|
||||
static unsigned int GetBlockScriptFlags(const CBlockIndex& block_index, const ChainstateManager& chainman);
|
||||
|
||||
static void LimitMempoolSize(CTxMemPool& pool, CCoinsViewCache& coins_cache)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(::cs_main, pool.cs)
|
||||
{
|
||||
|
@ -398,7 +395,7 @@ void Chainstate::MaybeUpdateMempoolForReorg(
|
|||
* */
|
||||
static bool CheckInputsFromMempoolAndCache(const CTransaction& tx, TxValidationState& state,
|
||||
const CCoinsViewCache& view, const CTxMemPool& pool,
|
||||
unsigned int flags, PrecomputedTransactionData& txdata, CCoinsViewCache& coins_tip,
|
||||
script_verify_flags flags, PrecomputedTransactionData& txdata, CCoinsViewCache& coins_tip,
|
||||
ValidationCache& validation_cache)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main, pool.cs)
|
||||
{
|
||||
|
@ -1044,6 +1041,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
|||
// Even though just checking direct mempool parents for inheritance would be sufficient, we
|
||||
// check using the full ancestor set here because it's more convenient to use what we have
|
||||
// already calculated.
|
||||
if (!args.m_bypass_limits) {
|
||||
if (const auto err{SingleTRUCChecks(ws.m_ptx, ws.m_ancestors, ws.m_conflicts, ws.m_vsize)}) {
|
||||
// Single transaction contexts only.
|
||||
if (args.m_allow_sibling_eviction && err->second != nullptr) {
|
||||
|
@ -1066,6 +1064,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
|||
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "TRUC-violation", err->first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A transaction that spends outputs that would be replaced by it is invalid. Now
|
||||
// that we have the set of all ancestors we can detect this
|
||||
|
@ -1249,7 +1248,7 @@ bool MemPoolAccept::PolicyScriptChecks(const ATMPArgs& args, Workspace& ws)
|
|||
const CTransaction& tx = *ws.m_ptx;
|
||||
TxValidationState& state = ws.m_state;
|
||||
|
||||
constexpr unsigned int scriptVerifyFlags = STANDARD_SCRIPT_VERIFY_FLAGS;
|
||||
constexpr script_verify_flags scriptVerifyFlags = STANDARD_SCRIPT_VERIFY_FLAGS;
|
||||
|
||||
// Check input scripts and signatures.
|
||||
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
|
||||
|
@ -1288,7 +1287,7 @@ bool MemPoolAccept::ConsensusScriptChecks(const ATMPArgs& args, Workspace& ws)
|
|||
// There is a similar check in CreateNewBlock() to prevent creating
|
||||
// invalid blocks (using TestBlockValidity), however allowing such
|
||||
// transactions into the mempool can be exploited as a DoS attack.
|
||||
unsigned int currentBlockScriptVerifyFlags{GetBlockScriptFlags(*m_active_chainstate.m_chain.Tip(), m_active_chainstate.m_chainman)};
|
||||
script_verify_flags currentBlockScriptVerifyFlags{GetBlockScriptFlags(*m_active_chainstate.m_chain.Tip(), m_active_chainstate.m_chainman)};
|
||||
if (!CheckInputsFromMempoolAndCache(tx, state, m_view, m_pool, currentBlockScriptVerifyFlags,
|
||||
ws.m_precomputed_txdata, m_active_chainstate.CoinsTip(), GetValidationCache())) {
|
||||
LogPrintf("BUG! PLEASE REPORT THIS! CheckInputScripts failed against latest-block but not STANDARD flags %s, %s\n", hash.ToString(), state.ToString());
|
||||
|
@ -2096,7 +2095,7 @@ std::optional<std::pair<ScriptError, std::string>> CScriptCheck::operator()() {
|
|||
const CScript &scriptSig = ptxTo->vin[nIn].scriptSig;
|
||||
const CScriptWitness *witness = &ptxTo->vin[nIn].scriptWitness;
|
||||
ScriptError error{SCRIPT_ERR_UNKNOWN_ERROR};
|
||||
if (VerifyScript(scriptSig, m_tx_out.scriptPubKey, witness, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, m_tx_out.nValue, cacheStore, *m_signature_cache, *txdata), &error)) {
|
||||
if (VerifyScript(scriptSig, m_tx_out.scriptPubKey, witness, m_flags, CachingTransactionSignatureChecker(ptxTo, nIn, m_tx_out.nValue, cacheStore, *m_signature_cache, *txdata), &error)) {
|
||||
return std::nullopt;
|
||||
} else {
|
||||
auto debug_str = strprintf("input %i of %s (wtxid %s), spending %s:%i", nIn, ptxTo->GetHash().ToString(), ptxTo->GetWitnessHash().ToString(), ptxTo->vin[nIn].prevout.hash.ToString(), ptxTo->vin[nIn].prevout.n);
|
||||
|
@ -2140,7 +2139,7 @@ ValidationCache::ValidationCache(const size_t script_execution_cache_bytes, cons
|
|||
* Non-static (and redeclared) in src/test/txvalidationcache_tests.cpp
|
||||
*/
|
||||
bool CheckInputScripts(const CTransaction& tx, TxValidationState& state,
|
||||
const CCoinsViewCache& inputs, unsigned int flags, bool cacheSigStore,
|
||||
const CCoinsViewCache& inputs, script_verify_flags flags, bool cacheSigStore,
|
||||
bool cacheFullScriptStore, PrecomputedTransactionData& txdata,
|
||||
ValidationCache& validation_cache,
|
||||
std::vector<CScriptCheck>* pvChecks)
|
||||
|
@ -2328,7 +2327,7 @@ DisconnectResult Chainstate::DisconnectBlock(const CBlock& block, const CBlockIn
|
|||
return fClean ? DISCONNECT_OK : DISCONNECT_UNCLEAN;
|
||||
}
|
||||
|
||||
static unsigned int GetBlockScriptFlags(const CBlockIndex& block_index, const ChainstateManager& chainman)
|
||||
script_verify_flags GetBlockScriptFlags(const CBlockIndex& block_index, const ChainstateManager& chainman)
|
||||
{
|
||||
const Consensus::Params& consensusparams = chainman.GetConsensus();
|
||||
|
||||
|
@ -2340,7 +2339,7 @@ static unsigned int GetBlockScriptFlags(const CBlockIndex& block_index, const Ch
|
|||
// mainnet.
|
||||
// For simplicity, always leave P2SH+WITNESS+TAPROOT on except for the two
|
||||
// violating blocks.
|
||||
uint32_t flags{SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_TAPROOT};
|
||||
script_verify_flags flags{SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_TAPROOT};
|
||||
const auto it{consensusparams.script_flag_exceptions.find(*Assert(block_index.phashBlock))};
|
||||
if (it != consensusparams.script_flag_exceptions.end()) {
|
||||
flags = it->second;
|
||||
|
@ -2554,7 +2553,7 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
|
|||
}
|
||||
|
||||
// Get the script flags for this block
|
||||
unsigned int flags{GetBlockScriptFlags(*pindex, m_chainman)};
|
||||
script_verify_flags flags{GetBlockScriptFlags(*pindex, m_chainman)};
|
||||
|
||||
const auto time_2{SteadyClock::now()};
|
||||
m_chainman.time_forks += time_2 - time_1;
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <policy/policy.h>
|
||||
#include <script/script_error.h>
|
||||
#include <script/sigcache.h>
|
||||
#include <script/verify_flags.h>
|
||||
#include <sync.h>
|
||||
#include <txdb.h>
|
||||
#include <txmempool.h>
|
||||
|
@ -336,14 +337,14 @@ private:
|
|||
CTxOut m_tx_out;
|
||||
const CTransaction *ptxTo;
|
||||
unsigned int nIn;
|
||||
unsigned int nFlags;
|
||||
script_verify_flags m_flags;
|
||||
bool cacheStore;
|
||||
PrecomputedTransactionData *txdata;
|
||||
SignatureCache* m_signature_cache;
|
||||
|
||||
public:
|
||||
CScriptCheck(const CTxOut& outIn, const CTransaction& txToIn, SignatureCache& signature_cache, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn, PrecomputedTransactionData* txdataIn) :
|
||||
m_tx_out(outIn), ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), txdata(txdataIn), m_signature_cache(&signature_cache) { }
|
||||
CScriptCheck(const CTxOut& outIn, const CTransaction& txToIn, SignatureCache& signature_cache, unsigned int nInIn, script_verify_flags flags, bool cacheIn, PrecomputedTransactionData* txdataIn) :
|
||||
m_tx_out(outIn), ptxTo(&txToIn), nIn(nInIn), m_flags(flags), cacheStore(cacheIn), txdata(txdataIn), m_signature_cache(&signature_cache) { }
|
||||
|
||||
CScriptCheck(const CScriptCheck&) = delete;
|
||||
CScriptCheck& operator=(const CScriptCheck&) = delete;
|
||||
|
@ -1365,4 +1366,7 @@ bool IsBIP30Repeat(const CBlockIndex& block_index);
|
|||
/** Identifies blocks which coinbase output was subsequently overwritten in the UTXO set (see BIP30) */
|
||||
bool IsBIP30Unspendable(const uint256& block_hash, int block_height);
|
||||
|
||||
// Returns the script flags which should be checked for a given block
|
||||
script_verify_flags GetBlockScriptFlags(const CBlockIndex& block_index, const ChainstateManager& chainman);
|
||||
|
||||
#endif // BITCOIN_VALIDATION_H
|
||||
|
|
|
@ -51,6 +51,8 @@ bool VerifyWallets(WalletContext& context)
|
|||
}
|
||||
|
||||
LogInfo("Using wallet directory %s", fs::PathToString(GetWalletDir()));
|
||||
// Print general DB information
|
||||
LogDBInfo();
|
||||
|
||||
chain.initMessage(_("Verifying wallet(s)…"));
|
||||
|
||||
|
|
|
@ -116,9 +116,6 @@ SQLiteDatabase::SQLiteDatabase(const fs::path& dir_path, const fs::path& file_pa
|
|||
{
|
||||
{
|
||||
LOCK(g_sqlite_mutex);
|
||||
LogInfo("Using SQLite Version %s", SQLiteDatabaseVersion());
|
||||
LogInfo("Using wallet %s", fs::PathToString(m_dir_path));
|
||||
|
||||
if (++g_sqlite_count == 1) {
|
||||
// Setup logging
|
||||
int ret = sqlite3_config(SQLITE_CONFIG_LOG, ErrorLogCallback, nullptr);
|
||||
|
|
|
@ -63,6 +63,12 @@ const std::string WATCHS{"watchs"};
|
|||
const std::unordered_set<std::string> LEGACY_TYPES{CRYPTED_KEY, CSCRIPT, DEFAULTKEY, HDCHAIN, KEYMETA, KEY, OLD_KEY, POOL, WATCHMETA, WATCHS};
|
||||
} // namespace DBKeys
|
||||
|
||||
void LogDBInfo()
|
||||
{
|
||||
// Add useful DB information here. This will be printed during startup.
|
||||
LogInfo("Using SQLite Version %s", SQLiteDatabaseVersion());
|
||||
}
|
||||
|
||||
//
|
||||
// WalletBatch
|
||||
//
|
||||
|
|
|
@ -27,6 +27,9 @@ class CWallet;
|
|||
class CWalletTx;
|
||||
struct WalletContext;
|
||||
|
||||
// Logs information about the database, including available engines, features, and other capabilities
|
||||
void LogDBInfo();
|
||||
|
||||
/**
|
||||
* Overview of wallet database classes:
|
||||
*
|
||||
|
|
|
@ -39,37 +39,41 @@ class BindExtraTest(BitcoinTestFramework):
|
|||
loopback_ipv4 = addr_to_hex("127.0.0.1")
|
||||
|
||||
# Start custom ports by reusing unused p2p ports
|
||||
port = p2p_port(self.num_nodes)
|
||||
def extra_port():
|
||||
port = p2p_port(extra_port.index)
|
||||
extra_port.index += 1
|
||||
return port
|
||||
extra_port.index = self.num_nodes
|
||||
|
||||
# Array of tuples [command line arguments, expected bind addresses].
|
||||
self.expected = []
|
||||
|
||||
# Node0, no normal -bind=... with -bind=...=onion, thus only the tor target.
|
||||
port = extra_port()
|
||||
self.expected.append(
|
||||
[
|
||||
[f"-bind=127.0.0.1:{port}=onion"],
|
||||
[(loopback_ipv4, port)]
|
||||
[(loopback_ipv4, port)],
|
||||
],
|
||||
)
|
||||
port += 1
|
||||
|
||||
# Node1, both -bind=... and -bind=...=onion.
|
||||
port = [extra_port(), extra_port()]
|
||||
self.expected.append(
|
||||
[
|
||||
[f"-bind=127.0.0.1:{port}", f"-bind=127.0.0.1:{port + 1}=onion"],
|
||||
[(loopback_ipv4, port), (loopback_ipv4, port + 1)]
|
||||
[f"-bind=127.0.0.1:{port[0]}", f"-bind=127.0.0.1:{port[1]}=onion"],
|
||||
[(loopback_ipv4, port[0]), (loopback_ipv4, port[1])],
|
||||
],
|
||||
)
|
||||
port += 2
|
||||
|
||||
# Node2, no -bind=...=onion, thus no extra port for Tor target.
|
||||
port = extra_port()
|
||||
self.expected.append(
|
||||
[
|
||||
[f"-bind=127.0.0.1:{port}"],
|
||||
[(loopback_ipv4, port)]
|
||||
[(loopback_ipv4, port)],
|
||||
],
|
||||
)
|
||||
port += 1
|
||||
|
||||
self.extra_args = list(map(lambda e: e[0], self.expected))
|
||||
self.setup_nodes()
|
||||
|
|
|
@ -100,17 +100,5 @@ class DataCarrierTest(BitcoinTestFramework):
|
|||
self.test_null_data_transaction(node=self.nodes[2], data=one_byte, success=True)
|
||||
self.test_null_data_transaction(node=self.nodes[3], data=one_byte, success=False)
|
||||
|
||||
# Clean shutdown boilerplate due to deprecation
|
||||
self.expected_stderr = [
|
||||
"", # node 0 has no deprecated options
|
||||
"Warning: Options '-datacarrier' or '-datacarriersize' are set but are marked as deprecated and are expected to be removed in a future version.",
|
||||
"Warning: Options '-datacarrier' or '-datacarriersize' are set but are marked as deprecated and are expected to be removed in a future version.",
|
||||
"Warning: Options '-datacarrier' or '-datacarriersize' are set but are marked as deprecated and are expected to be removed in a future version.",
|
||||
]
|
||||
|
||||
for i in range(self.num_nodes):
|
||||
self.stop_node(i, expected_stderr=self.expected_stderr[i])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
DataCarrierTest(__file__).main()
|
||||
|
|
|
@ -165,23 +165,36 @@ class MempoolTRUC(BitcoinTestFramework):
|
|||
def test_truc_reorg(self):
|
||||
node = self.nodes[0]
|
||||
self.log.info("Test that, during a reorg, TRUC rules are not enforced")
|
||||
tx_v2_block = self.wallet.send_self_transfer(from_node=node, version=2)
|
||||
tx_v3_block = self.wallet.send_self_transfer(from_node=node, version=3)
|
||||
tx_v3_block2 = self.wallet.send_self_transfer(from_node=node, version=3)
|
||||
self.check_mempool([tx_v3_block["txid"], tx_v2_block["txid"], tx_v3_block2["txid"]])
|
||||
self.check_mempool([])
|
||||
|
||||
# Testing 2<-3 versions allowed
|
||||
tx_v2_block = self.wallet.create_self_transfer(version=2)
|
||||
|
||||
# Testing 3<-2 versions allowed
|
||||
tx_v3_block = self.wallet.create_self_transfer(version=3)
|
||||
|
||||
# Testing overly-large child size
|
||||
tx_v3_block2 = self.wallet.create_self_transfer(version=3)
|
||||
|
||||
# Also create a linear chain of 3 TRUC transactions that will be directly mined, followed by one v2 in-mempool after block is made
|
||||
tx_chain_1 = self.wallet.create_self_transfer(version=3)
|
||||
tx_chain_2 = self.wallet.create_self_transfer(utxo_to_spend=tx_chain_1["new_utxo"], version=3)
|
||||
tx_chain_3 = self.wallet.create_self_transfer(utxo_to_spend=tx_chain_2["new_utxo"], version=3)
|
||||
|
||||
tx_to_mine = [tx_v3_block["hex"], tx_v2_block["hex"], tx_v3_block2["hex"], tx_chain_1["hex"], tx_chain_2["hex"], tx_chain_3["hex"]]
|
||||
block = self.generateblock(node, output="raw(42)", transactions=tx_to_mine)
|
||||
|
||||
block = self.generate(node, 1)
|
||||
self.check_mempool([])
|
||||
tx_v2_from_v3 = self.wallet.send_self_transfer(from_node=node, utxo_to_spend=tx_v3_block["new_utxo"], version=2)
|
||||
tx_v3_from_v2 = self.wallet.send_self_transfer(from_node=node, utxo_to_spend=tx_v2_block["new_utxo"], version=3)
|
||||
tx_v3_child_large = self.wallet.send_self_transfer(from_node=node, utxo_to_spend=tx_v3_block2["new_utxo"], target_vsize=1250, version=3)
|
||||
assert_greater_than(node.getmempoolentry(tx_v3_child_large["txid"])["vsize"], TRUC_CHILD_MAX_VSIZE)
|
||||
self.check_mempool([tx_v2_from_v3["txid"], tx_v3_from_v2["txid"], tx_v3_child_large["txid"]])
|
||||
node.invalidateblock(block[0])
|
||||
self.check_mempool([tx_v3_block["txid"], tx_v2_block["txid"], tx_v3_block2["txid"], tx_v2_from_v3["txid"], tx_v3_from_v2["txid"], tx_v3_child_large["txid"]])
|
||||
# This is needed because generate() will create the exact same block again.
|
||||
node.reconsiderblock(block[0])
|
||||
tx_chain_4 = self.wallet.send_self_transfer(from_node=node, utxo_to_spend=tx_chain_3["new_utxo"], version=2)
|
||||
self.check_mempool([tx_v2_from_v3["txid"], tx_v3_from_v2["txid"], tx_v3_child_large["txid"], tx_chain_4["txid"]])
|
||||
|
||||
# Reorg should have all block transactions re-accepted, ignoring TRUC enforcement
|
||||
node.invalidateblock(block["hash"])
|
||||
self.check_mempool([tx_v3_block["txid"], tx_v2_block["txid"], tx_v3_block2["txid"], tx_v2_from_v3["txid"], tx_v3_from_v2["txid"], tx_v3_child_large["txid"], tx_chain_1["txid"], tx_chain_2["txid"], tx_chain_3["txid"], tx_chain_4["txid"]])
|
||||
|
||||
@cleanup(extra_args=["-limitdescendantsize=10"])
|
||||
def test_nondefault_package_limits(self):
|
||||
|
|
|
@ -15,7 +15,7 @@ from test_framework.wallet import MiniWallet
|
|||
import time
|
||||
|
||||
class P2PNode(P2PDataStore):
|
||||
def on_inv(self, msg):
|
||||
def on_inv(self, message):
|
||||
pass
|
||||
|
||||
|
||||
|
@ -26,6 +26,7 @@ class P2PLeakTxTest(BitcoinTestFramework):
|
|||
def run_test(self):
|
||||
self.gen_node = self.nodes[0] # The block and tx generating node
|
||||
self.miniwallet = MiniWallet(self.gen_node)
|
||||
self.mocktime = int(time.time())
|
||||
|
||||
self.test_tx_in_block()
|
||||
self.test_notfound_on_replaced_tx()
|
||||
|
@ -33,20 +34,20 @@ class P2PLeakTxTest(BitcoinTestFramework):
|
|||
|
||||
def test_tx_in_block(self):
|
||||
self.log.info("Check that a transaction in the last block is uploaded (beneficial for compact block relay)")
|
||||
self.gen_node.setmocktime(self.mocktime)
|
||||
inbound_peer = self.gen_node.add_p2p_connection(P2PNode())
|
||||
|
||||
self.log.debug("Generate transaction and block")
|
||||
inbound_peer.last_message.pop("inv", None)
|
||||
|
||||
self.gen_node.setmocktime(int(time.time())) # pause time based activities
|
||||
wtxid = self.miniwallet.send_self_transfer(from_node=self.gen_node)["wtxid"]
|
||||
rawmp = self.gen_node.getrawmempool(False, True)
|
||||
pi = self.gen_node.getpeerinfo()[0]
|
||||
assert_equal(rawmp["mempool_sequence"], 2) # our tx cause mempool activity
|
||||
assert_equal(pi["last_inv_sequence"], 1) # that is after the last inv
|
||||
assert_equal(pi["inv_to_send"], 1) # and our tx has been queued
|
||||
self.gen_node.setmocktime(0)
|
||||
|
||||
self.mocktime += 120
|
||||
self.gen_node.setmocktime(self.mocktime)
|
||||
inbound_peer.wait_until(lambda: "inv" in inbound_peer.last_message and inbound_peer.last_message.get("inv").inv[0].hash == int(wtxid, 16))
|
||||
|
||||
rawmp = self.gen_node.getrawmempool(False, True)
|
||||
|
@ -65,15 +66,20 @@ class P2PLeakTxTest(BitcoinTestFramework):
|
|||
|
||||
def test_notfound_on_replaced_tx(self):
|
||||
self.gen_node.disconnect_p2ps()
|
||||
self.gen_node.setmocktime(self.mocktime)
|
||||
inbound_peer = self.gen_node.add_p2p_connection(P2PTxInvStore())
|
||||
|
||||
self.log.info("Transaction tx_a is broadcast")
|
||||
tx_a = self.miniwallet.send_self_transfer(from_node=self.gen_node)
|
||||
self.mocktime += 120
|
||||
self.gen_node.setmocktime(self.mocktime)
|
||||
inbound_peer.wait_for_broadcast(txns=[tx_a["wtxid"]])
|
||||
|
||||
tx_b = tx_a["tx"]
|
||||
tx_b.vout[0].nValue -= 9000
|
||||
self.gen_node.sendrawtransaction(tx_b.serialize().hex())
|
||||
self.mocktime += 120
|
||||
self.gen_node.setmocktime(self.mocktime)
|
||||
inbound_peer.wait_until(lambda: "tx" in inbound_peer.last_message and inbound_peer.last_message.get("tx").tx.wtxid_hex == tx_b.wtxid_hex)
|
||||
|
||||
self.log.info("Re-request of tx_a after replacement is answered with notfound")
|
||||
|
@ -96,28 +102,31 @@ class P2PLeakTxTest(BitcoinTestFramework):
|
|||
self.gen_node.disconnect_p2ps()
|
||||
inbound_peer = self.gen_node.add_p2p_connection(P2PNode()) # An "attacking" inbound peer
|
||||
|
||||
MAX_REPEATS = 100
|
||||
self.log.info("Running test up to {} times.".format(MAX_REPEATS))
|
||||
for i in range(MAX_REPEATS):
|
||||
self.log.info('Run repeat {}'.format(i + 1))
|
||||
txid = self.miniwallet.send_self_transfer(from_node=self.gen_node)["wtxid"]
|
||||
# Set a mock time so that time does not pass, and gen_node never announces the transaction
|
||||
self.gen_node.setmocktime(self.mocktime)
|
||||
wtxid = int(self.miniwallet.send_self_transfer(from_node=self.gen_node)["wtxid"], 16)
|
||||
|
||||
want_tx = msg_getdata()
|
||||
want_tx.inv.append(CInv(t=MSG_TX, h=int(txid, 16)))
|
||||
want_tx.inv.append(CInv(t=MSG_WTX, h=wtxid))
|
||||
with p2p_lock:
|
||||
inbound_peer.last_message.pop('notfound', None)
|
||||
inbound_peer.send_and_ping(want_tx)
|
||||
|
||||
if inbound_peer.last_message.get('notfound'):
|
||||
self.log.debug('tx {} was not yet announced to us.'.format(txid))
|
||||
self.log.debug("node has responded with a notfound message. End test.")
|
||||
assert_equal(inbound_peer.last_message['notfound'].vec[0].hash, int(txid, 16))
|
||||
inbound_peer.wait_until(lambda: "notfound" in inbound_peer.last_message)
|
||||
with p2p_lock:
|
||||
assert_equal(inbound_peer.last_message.get("notfound").vec[0].hash, wtxid)
|
||||
inbound_peer.last_message.pop('notfound')
|
||||
break
|
||||
else:
|
||||
self.log.debug('tx {} was already announced to us. Try test again.'.format(txid))
|
||||
assert int(txid, 16) in [inv.hash for inv in inbound_peer.last_message['inv'].inv]
|
||||
|
||||
# Move mocktime forward and wait for the announcement.
|
||||
inbound_peer.last_message.pop('inv', None)
|
||||
self.mocktime += 120
|
||||
self.gen_node.setmocktime(self.mocktime)
|
||||
inbound_peer.wait_for_inv([CInv(t=MSG_WTX, h=wtxid)], timeout=120)
|
||||
|
||||
# Send the getdata again, this time the node should send us a TX message.
|
||||
inbound_peer.last_message.pop('tx', None)
|
||||
inbound_peer.send_and_ping(want_tx)
|
||||
self.wait_until(lambda: "tx" in inbound_peer.last_message)
|
||||
assert_equal(wtxid, int(inbound_peer.last_message["tx"].tx.wtxid_hex, 16))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -213,6 +213,7 @@ class BlockchainTest(BitcoinTestFramework):
|
|||
assert_equal(gdi_result, {
|
||||
"hash": blockhash,
|
||||
"height": height,
|
||||
"script_flags": ["CHECKLOCKTIMEVERIFY","CHECKSEQUENCEVERIFY","DERSIG","NULLDUMMY","P2SH","TAPROOT","WITNESS"],
|
||||
"deployments": {
|
||||
'bip34': {'type': 'buried', 'active': True, 'height': 2},
|
||||
'bip66': {'type': 'buried', 'active': True, 'height': 3},
|
||||
|
|
|
@ -474,6 +474,7 @@ def write_config(config_path, *, n, chain, extra_config="", disable_autoconnect=
|
|||
# min_required_fds = MIN_CORE_FDS + MAX_ADDNODE_CONNECTIONS + nBind = 151 + 8 + 3 = 162;
|
||||
# nMaxConnections = available_fds - min_required_fds = 256 - 161 = 94;
|
||||
f.write("maxconnections=94\n")
|
||||
f.write("par=" + str(min(2, os.cpu_count())) + "\n")
|
||||
f.write(extra_config)
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue