mirror of https://github.com/bitcoin/bitcoin.git
Compare commits
123 Commits
9b32a5f96a
...
b9b1947b81
Author | SHA1 | Date |
---|---|---|
|
b9b1947b81 | |
|
b371761b52 | |
|
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 | |
|
d8fe258cd6 | |
|
dda5228e02 | |
|
ff05bebcc4 | |
|
200150beba | |
|
7e08445449 | |
|
7b5261f7ef | |
|
65e909dfdd | |
|
31b29f8eb6 | |
|
e62e0a12b3 | |
|
7ae0497eef | |
|
05d984b1a4 | |
|
b807dfcdc5 | |
|
d41b503ae1 | |
|
5ae8edbc30 | |
|
df67bb6fd8 | |
|
44a493e150 | |
|
ad4a49090d | |
|
dd61f08fd5 | |
|
350692e561 | |
|
94db966a3b | |
|
eca50854e1 | |
|
89144eb473 | |
|
eaa1a3cd0b | |
|
b77137a564 | |
|
a86e1a6e32 | |
|
6861dadfcb | |
|
3b3ab3a50a | |
|
2738b63e02 | |
|
fbde8d9a81 | |
|
34fefb6335 | |
|
56791b5829 | |
|
337a6e7386 | |
|
451ba9ada4 | |
|
77b2ebb811 | |
|
bf7996cbc3 | |
|
4c3c1f42cf | |
|
953544d028 | |
|
df101c97c2 | |
|
56c6daa64f | |
|
79752b9c0b | |
|
cad9a7fd73 | |
|
6a33970fef | |
|
2427939935 | |
|
d6aa266d43 | |
|
316a0c5132 | |
|
453b0fa286 | |
|
29e836fae6 | |
|
0972f55040 | |
|
ef20c2d11d | |
|
1ff9e92948 | |
|
75e6984ec8 | |
|
652424ad16 | |
|
00c253d494 | |
|
ff18b6bbaf | |
|
8e434a8499 | |
|
05353d9cf0 | |
|
fabc2615af | |
|
417437eb01 | |
|
3cbbcb66ef | |
|
bddcadee82 | |
|
a5ead122fe | |
|
4577fb2b1e | |
|
a3986935f0 | |
|
5db8cd2d37 | |
|
adefb51c54 | |
|
88b0647f02 | |
|
8a08eef645 | |
|
0802398e74 | |
|
6d9e5d130d | |
|
3265df63a4 | |
|
91cbf4dbd8 | |
|
50da7432ec | |
|
e6a917c8f8 | |
|
e883b37768 | |
|
b81f37031c |
|
@ -1,9 +1,12 @@
|
||||||
name: 'Configure Docker'
|
name: 'Configure Docker'
|
||||||
description: 'Set up Docker build driver and configure build cache args'
|
description: 'Set up Docker build driver and configure build cache args'
|
||||||
inputs:
|
inputs:
|
||||||
use-cirrus:
|
cache-provider:
|
||||||
description: 'Use cirrus cache'
|
description: 'gha or cirrus cache provider'
|
||||||
required: true
|
required: true
|
||||||
|
options:
|
||||||
|
- gh
|
||||||
|
- cirrus
|
||||||
runs:
|
runs:
|
||||||
using: 'composite'
|
using: 'composite'
|
||||||
steps:
|
steps:
|
||||||
|
@ -32,7 +35,7 @@ runs:
|
||||||
# which are set automatically when running on GitHub infra: https://docs.docker.com/build/cache/backends/gha/#synopsis
|
# which are set automatically when running on GitHub infra: https://docs.docker.com/build/cache/backends/gha/#synopsis
|
||||||
|
|
||||||
# Use cirrus cache host
|
# Use cirrus cache host
|
||||||
if [[ ${{ inputs.use-cirrus }} == 'true' ]]; then
|
if [[ ${{ inputs.cache-provider }} == 'cirrus' ]]; then
|
||||||
url_args="url=${CIRRUS_CACHE_HOST},url_v2=${CIRRUS_CACHE_HOST}"
|
url_args="url=${CIRRUS_CACHE_HOST},url_v2=${CIRRUS_CACHE_HOST}"
|
||||||
else
|
else
|
||||||
url_args=""
|
url_args=""
|
||||||
|
|
|
@ -33,15 +33,15 @@ jobs:
|
||||||
name: 'determine runners'
|
name: 'determine runners'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
outputs:
|
outputs:
|
||||||
use-cirrus-runners: ${{ steps.runners.outputs.use-cirrus-runners }}
|
provider: ${{ steps.runners.outputs.provider }}
|
||||||
steps:
|
steps:
|
||||||
- id: runners
|
- id: runners
|
||||||
run: |
|
run: |
|
||||||
if [[ "${REPO_USE_CIRRUS_RUNNERS}" == "${{ github.repository }}" ]]; then
|
if [[ "${REPO_USE_CIRRUS_RUNNERS}" == "${{ github.repository }}" ]]; then
|
||||||
echo "use-cirrus-runners=true" >> "$GITHUB_OUTPUT"
|
echo "provider=cirrus" >> "$GITHUB_OUTPUT"
|
||||||
echo "::notice title=Runner Selection::Using Cirrus Runners"
|
echo "::notice title=Runner Selection::Using Cirrus Runners"
|
||||||
else
|
else
|
||||||
echo "use-cirrus-runners=false" >> "$GITHUB_OUTPUT"
|
echo "provider=gha" >> "$GITHUB_OUTPUT"
|
||||||
echo "::notice title=Runner Selection::Using GitHub-hosted runners"
|
echo "::notice title=Runner Selection::Using GitHub-hosted runners"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -105,7 +105,7 @@ jobs:
|
||||||
name: ${{ matrix.job-name }}
|
name: ${{ matrix.job-name }}
|
||||||
# Use any image to support the xcode-select below, but hardcode version to avoid silent upgrades (and breaks).
|
# 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.
|
# 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
|
# 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:
|
# to their own fork, or to the main repository, will trigger two CI runs:
|
||||||
|
@ -123,10 +123,10 @@ jobs:
|
||||||
include:
|
include:
|
||||||
- job-type: standard
|
- job-type: standard
|
||||||
file-env: './ci/test/00_setup_env_mac_native.sh'
|
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
|
- job-type: fuzz
|
||||||
file-env: './ci/test/00_setup_env_mac_native_fuzz.sh'
|
file-env: './ci/test/00_setup_env_mac_native_fuzz.sh'
|
||||||
job-name: 'macOS 14 native, arm64, fuzz'
|
job-name: 'macOS native, fuzz'
|
||||||
|
|
||||||
env:
|
env:
|
||||||
DANGER_RUN_CI_ON_HOST: 1
|
DANGER_RUN_CI_ON_HOST: 1
|
||||||
|
@ -145,8 +145,8 @@ jobs:
|
||||||
# Use the earliest Xcode supported by the version of macOS denoted in
|
# Use the earliest Xcode supported by the version of macOS denoted in
|
||||||
# doc/release-notes-empty-template.md and providing at least the
|
# doc/release-notes-empty-template.md and providing at least the
|
||||||
# minimum clang version denoted in doc/dependencies.md.
|
# minimum clang version denoted in doc/dependencies.md.
|
||||||
# See: https://developer.apple.com/documentation/xcode-release-notes/xcode-15-release-notes
|
# See: https://developer.apple.com/documentation/xcode-release-notes/xcode-16-release-notes
|
||||||
sudo xcode-select --switch /Applications/Xcode_15.0.app
|
sudo xcode-select --switch /Applications/Xcode_16.0.app
|
||||||
clang --version
|
clang --version
|
||||||
|
|
||||||
- name: Install Homebrew packages
|
- name: Install Homebrew packages
|
||||||
|
@ -211,11 +211,16 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
- *CHECKOUT
|
- *CHECKOUT
|
||||||
|
|
||||||
- name: Configure Developer Command Prompt for Microsoft Visual C++
|
- &SET_UP_VS
|
||||||
# Using microsoft/setup-msbuild is not enough.
|
name: Set up VS Developer Prompt
|
||||||
uses: ilammy/msvc-dev-cmd@v1
|
shell: pwsh -Command "$PSVersionTable; $PSNativeCommandUseErrorActionPreference = $true; $ErrorActionPreference = 'Stop'; & '{0}'"
|
||||||
with:
|
run: |
|
||||||
arch: x64
|
$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
|
- name: Get tool information
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
|
@ -263,14 +268,26 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
cmake --build . -j $NUMBER_OF_PROCESSORS --config Release
|
cmake --build . -j $NUMBER_OF_PROCESSORS --config Release
|
||||||
|
|
||||||
- name: Get bitcoind manifest
|
- name: Check executable manifests
|
||||||
if: matrix.job-type == 'standard'
|
if: matrix.job-type == 'standard'
|
||||||
working-directory: build
|
working-directory: build
|
||||||
|
shell: pwsh -Command "$PSVersionTable; $PSNativeCommandUseErrorActionPreference = $true; $ErrorActionPreference = 'Stop'; & '{0}'"
|
||||||
run: |
|
run: |
|
||||||
mt.exe -nologo -inputresource:bin/Release/bitcoind.exe -out:bitcoind.manifest
|
mt.exe -nologo -inputresource:bin\Release\bitcoind.exe -out:bitcoind.manifest
|
||||||
cat bitcoind.manifest
|
Get-Content bitcoind.manifest
|
||||||
echo
|
|
||||||
mt.exe -nologo -inputresource:bin/Release/bitcoind.exe -validate_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
|
- name: Run test suite
|
||||||
if: matrix.job-type == 'standard'
|
if: matrix.job-type == 'standard'
|
||||||
|
@ -312,7 +329,7 @@ jobs:
|
||||||
windows-cross:
|
windows-cross:
|
||||||
name: 'Linux->Windows cross, no tests'
|
name: 'Linux->Windows cross, no tests'
|
||||||
needs: runners
|
needs: runners
|
||||||
runs-on: ${{ needs.runners.outputs.use-cirrus-runners == 'true' && 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-sm' || 'ubuntu-24.04' }}
|
runs-on: ${{ needs.runners.outputs.provider == 'cirrus' && 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-sm' || 'ubuntu-24.04' }}
|
||||||
if: ${{ vars.SKIP_BRANCH_PUSH != 'true' || github.event_name == 'pull_request' }}
|
if: ${{ vars.SKIP_BRANCH_PUSH != 'true' || github.event_name == 'pull_request' }}
|
||||||
|
|
||||||
env:
|
env:
|
||||||
|
@ -332,7 +349,7 @@ jobs:
|
||||||
- name: Configure Docker
|
- name: Configure Docker
|
||||||
uses: ./.github/actions/configure-docker
|
uses: ./.github/actions/configure-docker
|
||||||
with:
|
with:
|
||||||
use-cirrus: ${{ needs.runners.outputs.use-cirrus-runners }}
|
cache-provider: ${{ needs.runners.outputs.provider }}
|
||||||
|
|
||||||
- name: CI script
|
- name: CI script
|
||||||
run: ./ci/test_run_all.sh
|
run: ./ci/test_run_all.sh
|
||||||
|
@ -370,19 +387,26 @@ jobs:
|
||||||
- name: Run bitcoind.exe
|
- name: Run bitcoind.exe
|
||||||
run: ./bin/bitcoind.exe -version
|
run: ./bin/bitcoind.exe -version
|
||||||
|
|
||||||
- name: Find mt.exe tool
|
- *SET_UP_VS
|
||||||
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
|
|
||||||
|
|
||||||
- name: Get bitcoind manifest
|
- name: Check executable manifests
|
||||||
shell: pwsh
|
shell: pwsh -Command "$PSVersionTable; $PSNativeCommandUseErrorActionPreference = $true; $ErrorActionPreference = 'Stop'; & '{0}'"
|
||||||
run: |
|
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
|
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
|
- name: Run unit tests
|
||||||
# Can't use ctest here like other jobs as we don't have a CMake build tree.
|
# Can't use ctest here like other jobs as we don't have a CMake build tree.
|
||||||
|
@ -422,7 +446,7 @@ jobs:
|
||||||
ci-matrix:
|
ci-matrix:
|
||||||
name: ${{ matrix.name }}
|
name: ${{ matrix.name }}
|
||||||
needs: runners
|
needs: runners
|
||||||
runs-on: ${{ needs.runners.outputs.use-cirrus-runners == 'true' && matrix.cirrus-runner || matrix.fallback-runner }}
|
runs-on: ${{ needs.runners.outputs.provider == 'cirrus' && matrix.cirrus-runner || matrix.fallback-runner }}
|
||||||
if: ${{ vars.SKIP_BRANCH_PUSH != 'true' || github.event_name == 'pull_request' }}
|
if: ${{ vars.SKIP_BRANCH_PUSH != 'true' || github.event_name == 'pull_request' }}
|
||||||
timeout-minutes: ${{ matrix.timeout-minutes }}
|
timeout-minutes: ${{ matrix.timeout-minutes }}
|
||||||
|
|
||||||
|
@ -439,6 +463,7 @@ jobs:
|
||||||
fallback-runner: 'ubuntu-24.04-arm'
|
fallback-runner: 'ubuntu-24.04-arm'
|
||||||
timeout-minutes: 120
|
timeout-minutes: 120
|
||||||
file-env: './ci/test/00_setup_env_arm.sh'
|
file-env: './ci/test/00_setup_env_arm.sh'
|
||||||
|
provider: 'gha'
|
||||||
|
|
||||||
- name: 'ASan + LSan + UBSan + integer, no depends, USDT'
|
- name: 'ASan + LSan + UBSan + integer, no depends, USDT'
|
||||||
cirrus-runner: 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-md' # has to match container in ci/test/00_setup_env_native_asan.sh for tracing tools
|
cirrus-runner: 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-md' # has to match container in ci/test/00_setup_env_native_asan.sh for tracing tools
|
||||||
|
@ -482,6 +507,12 @@ jobs:
|
||||||
timeout-minutes: 120
|
timeout-minutes: 120
|
||||||
file-env: './ci/test/00_setup_env_native_centos.sh'
|
file-env: './ci/test/00_setup_env_native_centos.sh'
|
||||||
|
|
||||||
|
- name: 'Valgrind'
|
||||||
|
cirrus-runner: 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-lg'
|
||||||
|
fallback-runner: 'ubuntu-24.04'
|
||||||
|
timeout-minutes: 120
|
||||||
|
file-env: './ci/test/00_setup_env_native_valgrind.sh'
|
||||||
|
|
||||||
- name: 'tidy'
|
- name: 'tidy'
|
||||||
cirrus-runner: 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-md'
|
cirrus-runner: 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-md'
|
||||||
fallback-runner: 'ubuntu-24.04'
|
fallback-runner: 'ubuntu-24.04'
|
||||||
|
@ -513,7 +544,7 @@ jobs:
|
||||||
- name: Configure Docker
|
- name: Configure Docker
|
||||||
uses: ./.github/actions/configure-docker
|
uses: ./.github/actions/configure-docker
|
||||||
with:
|
with:
|
||||||
use-cirrus: ${{ needs.runners.outputs.use-cirrus-runners }}
|
cache-provider: ${{ matrix.provider || needs.runners.outputs.provider }}
|
||||||
|
|
||||||
- name: Enable bpfcc script
|
- name: Enable bpfcc script
|
||||||
if: ${{ env.CONTAINER_NAME == 'ci_native_asan' }}
|
if: ${{ env.CONTAINER_NAME == 'ci_native_asan' }}
|
||||||
|
@ -550,7 +581,7 @@ jobs:
|
||||||
- name: Configure Docker
|
- name: Configure Docker
|
||||||
uses: ./.github/actions/configure-docker
|
uses: ./.github/actions/configure-docker
|
||||||
with:
|
with:
|
||||||
use-cirrus: ${{ needs.runners.outputs.use-cirrus-runners }}
|
cache-provider: ${{ needs.runners.outputs.provider }}
|
||||||
|
|
||||||
- name: CI script
|
- name: CI script
|
||||||
run: |
|
run: |
|
||||||
|
|
|
@ -41,10 +41,10 @@ python3 --version
|
||||||
${CI_RETRY_EXE} pip3 install \
|
${CI_RETRY_EXE} pip3 install \
|
||||||
codespell==2.4.1 \
|
codespell==2.4.1 \
|
||||||
lief==0.16.6 \
|
lief==0.16.6 \
|
||||||
mypy==1.4.1 \
|
mypy==1.18.2 \
|
||||||
pyzmq==25.1.0 \
|
pyzmq==27.1.0 \
|
||||||
ruff==0.5.5 \
|
ruff==0.13.2 \
|
||||||
vulture==2.6
|
vulture==2.14
|
||||||
|
|
||||||
SHELLCHECK_VERSION=v0.11.0
|
SHELLCHECK_VERSION=v0.11.0
|
||||||
curl -sL "https://github.com/koalaman/shellcheck/releases/download/${SHELLCHECK_VERSION}/shellcheck-${SHELLCHECK_VERSION}.linux.x86_64.tar.xz" | \
|
curl -sL "https://github.com/koalaman/shellcheck/releases/download/${SHELLCHECK_VERSION}/shellcheck-${SHELLCHECK_VERSION}.linux.x86_64.tar.xz" | \
|
||||||
|
|
|
@ -7,12 +7,15 @@
|
||||||
export LC_ALL=C.UTF-8
|
export LC_ALL=C.UTF-8
|
||||||
|
|
||||||
export CI_IMAGE_NAME_TAG="mirror.gcr.io/ubuntu:24.04"
|
export CI_IMAGE_NAME_TAG="mirror.gcr.io/ubuntu:24.04"
|
||||||
|
export APT_LLVM_V="21"
|
||||||
LIBCXX_DIR="/cxx_build/"
|
LIBCXX_DIR="/cxx_build/"
|
||||||
export MSAN_FLAGS="-fsanitize=memory -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer -g -O1 -fno-optimize-sibling-calls"
|
export MSAN_FLAGS="-fsanitize=memory -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer -g -O1 -fno-optimize-sibling-calls"
|
||||||
LIBCXX_FLAGS="-nostdinc++ -nostdlib++ -isystem ${LIBCXX_DIR}include/c++/v1 -L${LIBCXX_DIR}lib -Wl,-rpath,${LIBCXX_DIR}lib -lc++ -lc++abi -lpthread -Wno-unused-command-line-argument"
|
# -lstdc++ to resolve link issues due to upstream packaging
|
||||||
|
LIBCXX_FLAGS="-nostdinc++ -nostdlib++ -isystem ${LIBCXX_DIR}include/c++/v1 -L${LIBCXX_DIR}lib -Wl,-rpath,${LIBCXX_DIR}lib -lc++ -lc++abi -lpthread -Wno-unused-command-line-argument -lstdc++"
|
||||||
export MSAN_AND_LIBCXX_FLAGS="${MSAN_FLAGS} ${LIBCXX_FLAGS}"
|
export MSAN_AND_LIBCXX_FLAGS="${MSAN_FLAGS} ${LIBCXX_FLAGS}"
|
||||||
|
|
||||||
export CONTAINER_NAME="ci_native_fuzz_msan"
|
export CONTAINER_NAME="ci_native_fuzz_msan"
|
||||||
|
export PACKAGES="clang-${APT_LLVM_V} llvm-${APT_LLVM_V} llvm-${APT_LLVM_V}-dev libclang-${APT_LLVM_V}-dev libclang-rt-${APT_LLVM_V}-dev"
|
||||||
export DEP_OPTS="DEBUG=1 NO_QT=1 CC=clang CXX=clang++ CFLAGS='${MSAN_FLAGS}' CXXFLAGS='${MSAN_AND_LIBCXX_FLAGS}'"
|
export DEP_OPTS="DEBUG=1 NO_QT=1 CC=clang CXX=clang++ CFLAGS='${MSAN_FLAGS}' CXXFLAGS='${MSAN_AND_LIBCXX_FLAGS}'"
|
||||||
export GOAL="all"
|
export GOAL="all"
|
||||||
# Setting CMAKE_{C,CXX}_FLAGS_DEBUG flags to an empty string ensures that the flags set in MSAN_FLAGS remain unaltered.
|
# Setting CMAKE_{C,CXX}_FLAGS_DEBUG flags to an empty string ensures that the flags set in MSAN_FLAGS remain unaltered.
|
||||||
|
|
|
@ -13,7 +13,7 @@ export PIP_PACKAGES="--break-system-packages pycapnp"
|
||||||
export USE_VALGRIND=1
|
export USE_VALGRIND=1
|
||||||
export NO_DEPENDS=1
|
export NO_DEPENDS=1
|
||||||
# bind tests excluded for now, see https://github.com/bitcoin/bitcoin/issues/17765#issuecomment-602068547
|
# bind tests excluded for now, see https://github.com/bitcoin/bitcoin/issues/17765#issuecomment-602068547
|
||||||
export TEST_RUNNER_EXTRA="--exclude rpc_bind,feature_bind_extra"
|
export TEST_RUNNER_EXTRA="--exclude rpc_bind,feature_bind_extra,wallet_miniscript"
|
||||||
export GOAL="install"
|
export GOAL="install"
|
||||||
# TODO enable GUI
|
# TODO enable GUI
|
||||||
export BITCOIN_CONFIG="\
|
export BITCOIN_CONFIG="\
|
||||||
|
|
|
@ -58,23 +58,6 @@ fi
|
||||||
if [[ -n "${USE_INSTRUMENTED_LIBCPP}" ]]; then
|
if [[ -n "${USE_INSTRUMENTED_LIBCPP}" ]]; then
|
||||||
${CI_RETRY_EXE} git clone --depth=1 https://github.com/llvm/llvm-project -b "llvmorg-21.1.1" /llvm-project
|
${CI_RETRY_EXE} git clone --depth=1 https://github.com/llvm/llvm-project -b "llvmorg-21.1.1" /llvm-project
|
||||||
|
|
||||||
if [ -n "${APT_LLVM_V}" ]; then
|
|
||||||
|
|
||||||
cmake -G Ninja -B /clang_build/ \
|
|
||||||
-DLLVM_ENABLE_PROJECTS="clang" \
|
|
||||||
-DCMAKE_BUILD_TYPE=Release \
|
|
||||||
-DLLVM_TARGETS_TO_BUILD=Native \
|
|
||||||
-DLLVM_ENABLE_RUNTIMES="compiler-rt;libcxx;libcxxabi;libunwind" \
|
|
||||||
-S /llvm-project/llvm
|
|
||||||
|
|
||||||
ninja -C /clang_build/ "$MAKEJOBS"
|
|
||||||
ninja -C /clang_build/ install-runtimes
|
|
||||||
|
|
||||||
update-alternatives --install /usr/bin/clang++ clang++ /clang_build/bin/clang++ 100
|
|
||||||
update-alternatives --install /usr/bin/clang clang /clang_build/bin/clang 100
|
|
||||||
update-alternatives --install /usr/bin/llvm-symbolizer llvm-symbolizer /clang_build/bin/llvm-symbolizer 100
|
|
||||||
fi
|
|
||||||
|
|
||||||
cmake -G Ninja -B /cxx_build/ \
|
cmake -G Ninja -B /cxx_build/ \
|
||||||
-DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi;libunwind" \
|
-DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi;libunwind" \
|
||||||
-DCMAKE_BUILD_TYPE=Release \
|
-DCMAKE_BUILD_TYPE=Release \
|
||||||
|
|
|
@ -130,7 +130,8 @@ if [[ "${RUN_TIDY}" == "true" ]]; then
|
||||||
BITCOIN_CONFIG_ALL="$BITCOIN_CONFIG_ALL -DCMAKE_EXPORT_COMPILE_COMMANDS=ON"
|
BITCOIN_CONFIG_ALL="$BITCOIN_CONFIG_ALL -DCMAKE_EXPORT_COMPILE_COMMANDS=ON"
|
||||||
fi
|
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}"
|
cd "${BASE_BUILD_DIR}"
|
||||||
# shellcheck disable=SC2046
|
# shellcheck disable=SC2046
|
||||||
cat $(cmake -P "${BASE_ROOT_DIR}/ci/test/GetCMakeLogFiles.cmake")
|
cat $(cmake -P "${BASE_ROOT_DIR}/ci/test/GetCMakeLogFiles.cmake")
|
||||||
|
|
|
@ -96,24 +96,24 @@ function(add_macos_deploy_target)
|
||||||
VERBATIM
|
VERBATIM
|
||||||
)
|
)
|
||||||
|
|
||||||
string(REPLACE " " "-" osx_volname ${CLIENT_NAME})
|
set(macos_zip "bitcoin-macos-app")
|
||||||
if(CMAKE_HOST_APPLE)
|
if(CMAKE_HOST_APPLE)
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
OUTPUT ${PROJECT_BINARY_DIR}/${osx_volname}.zip
|
OUTPUT ${PROJECT_BINARY_DIR}/${macos_zip}.zip
|
||||||
COMMAND Python3::Interpreter ${PROJECT_SOURCE_DIR}/contrib/macdeploy/macdeployqtplus ${macos_app} ${osx_volname} -translations-dir=${QT_TRANSLATIONS_DIR} -zip
|
COMMAND Python3::Interpreter ${PROJECT_SOURCE_DIR}/contrib/macdeploy/macdeployqtplus ${macos_app} -translations-dir=${QT_TRANSLATIONS_DIR} -zip=${macos_zip}
|
||||||
DEPENDS ${PROJECT_BINARY_DIR}/${macos_app}/Contents/MacOS/Bitcoin-Qt
|
DEPENDS ${PROJECT_BINARY_DIR}/${macos_app}/Contents/MacOS/Bitcoin-Qt
|
||||||
VERBATIM
|
VERBATIM
|
||||||
)
|
)
|
||||||
add_custom_target(deploydir
|
add_custom_target(deploydir
|
||||||
DEPENDS ${PROJECT_BINARY_DIR}/${osx_volname}.zip
|
DEPENDS ${PROJECT_BINARY_DIR}/${macos_zip}.zip
|
||||||
)
|
)
|
||||||
add_custom_target(deploy
|
add_custom_target(deploy
|
||||||
DEPENDS ${PROJECT_BINARY_DIR}/${osx_volname}.zip
|
DEPENDS ${PROJECT_BINARY_DIR}/${macos_zip}.zip
|
||||||
)
|
)
|
||||||
else()
|
else()
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
OUTPUT ${PROJECT_BINARY_DIR}/dist/${macos_app}/Contents/MacOS/Bitcoin-Qt
|
OUTPUT ${PROJECT_BINARY_DIR}/dist/${macos_app}/Contents/MacOS/Bitcoin-Qt
|
||||||
COMMAND ${CMAKE_COMMAND} -E env OBJDUMP=${CMAKE_OBJDUMP} $<TARGET_FILE:Python3::Interpreter> ${PROJECT_SOURCE_DIR}/contrib/macdeploy/macdeployqtplus ${macos_app} ${osx_volname} -translations-dir=${QT_TRANSLATIONS_DIR}
|
COMMAND ${CMAKE_COMMAND} -E env OBJDUMP=${CMAKE_OBJDUMP} $<TARGET_FILE:Python3::Interpreter> ${PROJECT_SOURCE_DIR}/contrib/macdeploy/macdeployqtplus ${macos_app} -translations-dir=${QT_TRANSLATIONS_DIR}
|
||||||
DEPENDS ${PROJECT_BINARY_DIR}/${macos_app}/Contents/MacOS/Bitcoin-Qt
|
DEPENDS ${PROJECT_BINARY_DIR}/${macos_app}/Contents/MacOS/Bitcoin-Qt
|
||||||
VERBATIM
|
VERBATIM
|
||||||
)
|
)
|
||||||
|
@ -128,13 +128,13 @@ function(add_macos_deploy_target)
|
||||||
)
|
)
|
||||||
else()
|
else()
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
OUTPUT ${PROJECT_BINARY_DIR}/dist/${osx_volname}.zip
|
OUTPUT ${PROJECT_BINARY_DIR}/dist/${macos_zip}.zip
|
||||||
WORKING_DIRECTORY dist
|
WORKING_DIRECTORY dist
|
||||||
COMMAND ${PROJECT_SOURCE_DIR}/cmake/script/macos_zip.sh ${ZIP_EXECUTABLE} ${osx_volname}.zip
|
COMMAND ${PROJECT_SOURCE_DIR}/cmake/script/macos_zip.sh ${ZIP_EXECUTABLE} ${macos_zip}.zip
|
||||||
VERBATIM
|
VERBATIM
|
||||||
)
|
)
|
||||||
add_custom_target(deploy
|
add_custom_target(deploy
|
||||||
DEPENDS ${PROJECT_BINARY_DIR}/dist/${osx_volname}.zip
|
DEPENDS ${PROJECT_BINARY_DIR}/dist/${macos_zip}.zip
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -369,7 +369,7 @@ mkdir -p "$DISTSRC"
|
||||||
;;
|
;;
|
||||||
*darwin*)
|
*darwin*)
|
||||||
cmake --build build --target deploy ${V:+--verbose}
|
cmake --build build --target deploy ${V:+--verbose}
|
||||||
mv build/dist/Bitcoin-Core.zip "${OUTDIR}/${DISTNAME}-${HOST}-unsigned.zip"
|
mv build/dist/bitcoin-macos-app.zip "${OUTDIR}/${DISTNAME}-${HOST}-unsigned.zip"
|
||||||
mkdir -p "unsigned-app-${HOST}"
|
mkdir -p "unsigned-app-${HOST}"
|
||||||
cp --target-directory="unsigned-app-${HOST}" \
|
cp --target-directory="unsigned-app-${HOST}" \
|
||||||
contrib/macdeploy/detached-sig-create.sh
|
contrib/macdeploy/detached-sig-create.sh
|
||||||
|
|
|
@ -112,7 +112,6 @@ ELF_ALLOWED_LIBRARIES = {
|
||||||
'libfontconfig.so.1', # font support
|
'libfontconfig.so.1', # font support
|
||||||
'libfreetype.so.6', # font parsing
|
'libfreetype.so.6', # font parsing
|
||||||
'libdl.so.2', # programming interface to dynamic linker
|
'libdl.so.2', # programming interface to dynamic linker
|
||||||
'libxcb-cursor.so.0',
|
|
||||||
'libxcb-icccm.so.4',
|
'libxcb-icccm.so.4',
|
||||||
'libxcb-image.so.0',
|
'libxcb-image.so.0',
|
||||||
'libxcb-shm.so.0',
|
'libxcb-shm.so.0',
|
||||||
|
@ -249,7 +248,7 @@ def check_MACHO_libraries(binary) -> bool:
|
||||||
return ok
|
return ok
|
||||||
|
|
||||||
def check_MACHO_min_os(binary) -> bool:
|
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 True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
|
@ -390,12 +390,11 @@ Note, that the "dist" folder will be deleted before deploying on each run.
|
||||||
Optionally, Qt translation files (.qm) can be added to the bundle.""")
|
Optionally, Qt translation files (.qm) can be added to the bundle.""")
|
||||||
|
|
||||||
ap.add_argument("app_bundle", nargs=1, metavar="app-bundle", help="application bundle to be deployed")
|
ap.add_argument("app_bundle", nargs=1, metavar="app-bundle", help="application bundle to be deployed")
|
||||||
ap.add_argument("appname", nargs=1, metavar="appname", help="name of the app being deployed")
|
|
||||||
ap.add_argument("-verbose", nargs="?", const=True, help="Output additional debugging information")
|
ap.add_argument("-verbose", nargs="?", const=True, help="Output additional debugging information")
|
||||||
ap.add_argument("-no-plugins", dest="plugins", action="store_false", default=True, help="skip plugin deployment")
|
ap.add_argument("-no-plugins", dest="plugins", action="store_false", default=True, help="skip plugin deployment")
|
||||||
ap.add_argument("-no-strip", dest="strip", action="store_false", default=True, help="don't run 'strip' on the binaries")
|
ap.add_argument("-no-strip", dest="strip", action="store_false", default=True, help="don't run 'strip' on the binaries")
|
||||||
ap.add_argument("-translations-dir", nargs=1, metavar="path", default=None, help="Path to Qt's translations. Base translations will automatically be added to the bundle's resources.")
|
ap.add_argument("-translations-dir", nargs=1, metavar="path", default=None, help="Path to Qt's translations. Base translations will automatically be added to the bundle's resources.")
|
||||||
ap.add_argument("-zip", nargs="?", const="", metavar="zip", help="create a .zip containing the app bundle")
|
ap.add_argument("-zip", nargs=1, metavar="zip", help="create a .zip containing the app bundle")
|
||||||
|
|
||||||
config = ap.parse_args()
|
config = ap.parse_args()
|
||||||
|
|
||||||
|
@ -404,7 +403,6 @@ verbose = config.verbose
|
||||||
# ------------------------------------------------
|
# ------------------------------------------------
|
||||||
|
|
||||||
app_bundle = config.app_bundle[0]
|
app_bundle = config.app_bundle[0]
|
||||||
appname = config.appname[0]
|
|
||||||
|
|
||||||
if not os.path.exists(app_bundle):
|
if not os.path.exists(app_bundle):
|
||||||
sys.stderr.write(f"Error: Could not find app bundle \"{app_bundle}\"\n")
|
sys.stderr.write(f"Error: Could not find app bundle \"{app_bundle}\"\n")
|
||||||
|
@ -416,10 +414,6 @@ if os.path.exists("dist"):
|
||||||
print("+ Removing existing dist folder +")
|
print("+ Removing existing dist folder +")
|
||||||
shutil.rmtree("dist")
|
shutil.rmtree("dist")
|
||||||
|
|
||||||
if os.path.exists(appname + ".zip"):
|
|
||||||
print("+ Removing existing .zip +")
|
|
||||||
os.unlink(appname + ".zip")
|
|
||||||
|
|
||||||
# ------------------------------------------------
|
# ------------------------------------------------
|
||||||
|
|
||||||
target = os.path.join("dist", "Bitcoin-Qt.app")
|
target = os.path.join("dist", "Bitcoin-Qt.app")
|
||||||
|
@ -466,18 +460,18 @@ if config.translations_dir:
|
||||||
sys.stderr.write(f"Error: Could not find translation dir \"{config.translations_dir[0]}\"\n")
|
sys.stderr.write(f"Error: Could not find translation dir \"{config.translations_dir[0]}\"\n")
|
||||||
sys.exit(1)
|
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:
|
if verbose:
|
||||||
print(file.as_posix(), "->", os.path.join(applicationBundle.resourcesPath, file.name))
|
print(file.as_posix(), "->", os.path.join(applicationBundle.resourcesPath, file.name))
|
||||||
shutil.copy2(file.as_posix(), os.path.join(applicationBundle.resourcesPath, file.name))
|
shutil.copy2(file.as_posix(), os.path.join(applicationBundle.resourcesPath, file.name))
|
||||||
|
|
||||||
# ------------------------------------------------
|
# ------------------------------------------------
|
||||||
|
|
||||||
|
@ -499,7 +493,13 @@ if platform.system() == "Darwin":
|
||||||
# ------------------------------------------------
|
# ------------------------------------------------
|
||||||
|
|
||||||
if config.zip is not None:
|
if config.zip is not None:
|
||||||
shutil.make_archive('{}'.format(appname), format='zip', root_dir='dist', base_dir='Bitcoin-Qt.app')
|
name = config.zip[0]
|
||||||
|
|
||||||
|
if os.path.exists(name + ".zip"):
|
||||||
|
print("+ Removing existing .zip +")
|
||||||
|
os.unlink(name + ".zip")
|
||||||
|
|
||||||
|
shutil.make_archive('{}'.format(name), format='zip', root_dir='dist', base_dir='Bitcoin-Qt.app')
|
||||||
|
|
||||||
# ------------------------------------------------
|
# ------------------------------------------------
|
||||||
|
|
||||||
|
|
|
@ -36,9 +36,8 @@ define fetch_file_inner
|
||||||
endef
|
endef
|
||||||
|
|
||||||
define fetch_file
|
define fetch_file
|
||||||
( test -f $$($(1)_source_dir)/$(4) || \
|
|
||||||
( $(call fetch_file_inner,$(1),$(2),$(3),$(4),$(5)) || \
|
( $(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
|
endef
|
||||||
|
|
||||||
# Shell script to create a source tarball in $(1)_source from local directory
|
# 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)
|
$(1)_all_sources=$($(1)_file_name) $($(1)_extra_sources)
|
||||||
|
|
||||||
#stamps
|
#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)_extracted=$$($(1)_extract_dir)/.stamp_extracted
|
||||||
$(1)_preprocessed=$$($(1)_extract_dir)/.stamp_preprocessed
|
$(1)_preprocessed=$$($(1)_extract_dir)/.stamp_preprocessed
|
||||||
$(1)_cleaned=$$($(1)_extract_dir)/.stamp_cleaned
|
$(1)_cleaned=$$($(1)_extract_dir)/.stamp_cleaned
|
||||||
|
@ -247,7 +246,6 @@ endif
|
||||||
$($(1)_fetched):
|
$($(1)_fetched):
|
||||||
mkdir -p $$(@D) $(SOURCES_PATH)
|
mkdir -p $$(@D) $(SOURCES_PATH)
|
||||||
rm -f $$@
|
rm -f $$@
|
||||||
touch $$@
|
|
||||||
cd $$(@D); $($(1)_fetch_cmds)
|
cd $$(@D); $($(1)_fetch_cmds)
|
||||||
cd $($(1)_source_dir); $(foreach source,$($(1)_all_sources),$(build_SHA256SUM) $(source) >> $$(@);)
|
cd $($(1)_source_dir); $(foreach source,$($(1)_all_sources),$(build_SHA256SUM) $(source) >> $$(@);)
|
||||||
touch $$@
|
touch $$@
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
OSX_MIN_VERSION=13.0
|
OSX_MIN_VERSION=14.0
|
||||||
OSX_SDK_VERSION=14.0
|
OSX_SDK_VERSION=14.0
|
||||||
XCODE_VERSION=15.0
|
XCODE_VERSION=15.0
|
||||||
XCODE_BUILD_ID=15A240d
|
XCODE_BUILD_ID=15A240d
|
||||||
|
|
|
@ -6,7 +6,7 @@ $(package)_sha256_hash=0e9c5446dc6f3beb8af6ebfcc9e27bcc6da6fe2860f7fc07b99144dfa
|
||||||
$(package)_dependencies=libxcb libxcb_util_render libxcb_util_image
|
$(package)_dependencies=libxcb libxcb_util_render libxcb_util_image
|
||||||
|
|
||||||
define $(package)_set_vars
|
define $(package)_set_vars
|
||||||
$(package)_config_opts = --disable-static
|
$(package)_config_opts = --disable-shared
|
||||||
$(package)_config_opts += --disable-dependency-tracking --enable-option-checking
|
$(package)_config_opts += --disable-dependency-tracking --enable-option-checking
|
||||||
endef
|
endef
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
package=qrencode
|
package=qrencode
|
||||||
$(package)_version=4.1.1
|
$(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)_file_name=$(package)-$($(package)_version).tar.gz
|
||||||
$(package)_sha256_hash=da448ed4f52aba6bcb0cd48cac0dd51b8692bccc4cd127431402fca6f8171e8e
|
$(package)_sha256_hash=5385bc1b8c2f20f3b91d258bf8ccc8cf62023935df2d2676b5b67049f31a049c
|
||||||
$(package)_patches=cmake_fixups.patch
|
$(package)_patches=cmake_fixups.patch
|
||||||
|
|
||||||
define $(package)_set_vars
|
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
|
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:
|
Additionally, to support Wayland protocol for modern desktop environments:
|
||||||
|
|
||||||
sudo apt install qt6-wayland
|
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
|
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:
|
Additionally, to support Wayland protocol for modern desktop environments:
|
||||||
|
|
||||||
sudo dnf install qt6-qtwayland
|
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
|
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:
|
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
|
apk add libqrencode-dev
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
| *libbitcoin_crypto* | Hardware-optimized functions for data encryption, hashing, message authentication, and key derivation. |
|
| *libbitcoin_crypto* | Hardware-optimized functions for data encryption, hashing, message authentication, and key derivation. |
|
||||||
| *libbitcoin_kernel* | Consensus engine and support library used for validation by *libbitcoin_node*. |
|
| *libbitcoin_kernel* | Consensus engine and support library used for validation by *libbitcoin_node*. |
|
||||||
| *libbitcoinqt* | GUI functionality used by *bitcoin-qt* and *bitcoin-gui* executables. |
|
| *libbitcoinqt* | GUI functionality used by *bitcoin-qt* and *bitcoin-gui* executables. |
|
||||||
| *libbitcoin_ipc* | IPC functionality used by *bitcoin-node*, *bitcoin-wallet*, *bitcoin-gui* executables to communicate when [`-DENABLE_IPC=ON`](multiprocess.md) is used. |
|
| *libbitcoin_ipc* | IPC functionality used by *bitcoin-node* and *bitcoin-gui* executables to communicate when [`-DENABLE_IPC=ON`](multiprocess.md) is used. |
|
||||||
| *libbitcoin_node* | P2P and RPC server functionality used by *bitcoind* and *bitcoin-qt* executables. |
|
| *libbitcoin_node* | P2P and RPC server functionality used by *bitcoind* and *bitcoin-qt* executables. |
|
||||||
| *libbitcoin_util* | Home for common functionality shared by different executables and libraries. Similar to *libbitcoin_common*, but lower-level (see [Dependencies](#dependencies)). |
|
| *libbitcoin_util* | Home for common functionality shared by different executables and libraries. Similar to *libbitcoin_common*, but lower-level (see [Dependencies](#dependencies)). |
|
||||||
| *libbitcoin_wallet* | Wallet functionality used by *bitcoind* and *bitcoin-wallet* executables. |
|
| *libbitcoin_wallet* | Wallet functionality used by *bitcoind* and *bitcoin-wallet* executables. |
|
||||||
|
|
|
@ -36,7 +36,7 @@ Compatibility
|
||||||
==============
|
==============
|
||||||
|
|
||||||
Bitcoin Core is supported and tested on operating systems using the
|
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
|
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
|
frequently tested on them. It is not recommended to use Bitcoin Core on
|
||||||
unsupported systems.
|
unsupported systems.
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<plist version="0.9">
|
<plist version="0.9">
|
||||||
<dict>
|
<dict>
|
||||||
<key>LSMinimumSystemVersion</key>
|
<key>LSMinimumSystemVersion</key>
|
||||||
<string>13</string>
|
<string>14</string>
|
||||||
|
|
||||||
<key>LSArchitecturePriority</key>
|
<key>LSArchitecturePriority</key>
|
||||||
<array>
|
<array>
|
||||||
|
|
|
@ -113,6 +113,19 @@ Section -post SEC0001
|
||||||
WriteRegStr HKCR "@CLIENT_TARNAME@" "" "URL:Bitcoin"
|
WriteRegStr HKCR "@CLIENT_TARNAME@" "" "URL:Bitcoin"
|
||||||
WriteRegStr HKCR "@CLIENT_TARNAME@\DefaultIcon" "" $INSTDIR\@BITCOIN_GUI_NAME@@EXEEXT@
|
WriteRegStr HKCR "@CLIENT_TARNAME@\DefaultIcon" "" $INSTDIR\@BITCOIN_GUI_NAME@@EXEEXT@
|
||||||
WriteRegStr HKCR "@CLIENT_TARNAME@\shell\open\command" "" '"$INSTDIR\@BITCOIN_GUI_NAME@@EXEEXT@" "%1"'
|
WriteRegStr HKCR "@CLIENT_TARNAME@\shell\open\command" "" '"$INSTDIR\@BITCOIN_GUI_NAME@@EXEEXT@" "%1"'
|
||||||
|
|
||||||
|
# Lingering since fb2b05b1259d3e69e6e675adfa30b429424c7625 which removed the suffix
|
||||||
|
DeleteRegValue HKCU "${REGKEY} (64-bit)\Components" Main
|
||||||
|
DeleteRegKey HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name) (64-bit)"
|
||||||
|
Delete /REBOOTOK "$SMPROGRAMS\$StartMenuGroup\Uninstall $(^Name) (64-bit).lnk"
|
||||||
|
Delete /REBOOTOK "$SMPROGRAMS\$StartMenuGroup\$(^Name) (64-bit).lnk"
|
||||||
|
DeleteRegValue HKCU "${REGKEY} (64-bit)" StartMenuGroup
|
||||||
|
DeleteRegValue HKCU "${REGKEY} (64-bit)" Path
|
||||||
|
DeleteRegKey /IfEmpty HKCU "${REGKEY} (64-bit)\Components"
|
||||||
|
DeleteRegKey /IfEmpty HKCU "${REGKEY} (64-bit)"
|
||||||
|
|
||||||
|
# Lingering since 77b2923f87131a407f7d4193c54db22375130403
|
||||||
|
Delete /REBOOTOK "$SMPROGRAMS\$StartMenuGroup\Bitcoin Core (testnet, 64-bit).lnk"
|
||||||
SectionEnd
|
SectionEnd
|
||||||
|
|
||||||
# Macro for selecting uninstaller sections
|
# Macro for selecting uninstaller sections
|
||||||
|
|
|
@ -292,7 +292,7 @@ if(BUILD_BITCOIN_BIN)
|
||||||
add_executable(bitcoin bitcoin.cpp)
|
add_executable(bitcoin bitcoin.cpp)
|
||||||
add_windows_resources(bitcoin bitcoin-res.rc)
|
add_windows_resources(bitcoin bitcoin-res.rc)
|
||||||
add_windows_application_manifest(bitcoin)
|
add_windows_application_manifest(bitcoin)
|
||||||
target_link_libraries(bitcoin core_interface bitcoin_util)
|
target_link_libraries(bitcoin core_interface bitcoin_common bitcoin_util)
|
||||||
install_binary_component(bitcoin HAS_MANPAGE)
|
install_binary_component(bitcoin HAS_MANPAGE)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ static void VerifyScriptBench(benchmark::Bench& bench)
|
||||||
{
|
{
|
||||||
ECC_Context ecc_context{};
|
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;
|
const int witnessversion = 0;
|
||||||
|
|
||||||
// Key pair.
|
// Key pair.
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <bitcoin-build-config.h> // IWYU pragma: keep
|
#include <bitcoin-build-config.h> // IWYU pragma: keep
|
||||||
|
|
||||||
#include <clientversion.h>
|
#include <clientversion.h>
|
||||||
|
#include <common/args.h>
|
||||||
#include <util/fs.h>
|
#include <util/fs.h>
|
||||||
#include <util/exec.h>
|
#include <util/exec.h>
|
||||||
#include <util/strencodings.h>
|
#include <util/strencodings.h>
|
||||||
|
@ -47,7 +48,7 @@ Run '%s help' to see additional commands (e.g. for testing and debugging).
|
||||||
)";
|
)";
|
||||||
|
|
||||||
struct CommandLine {
|
struct CommandLine {
|
||||||
bool use_multiprocess{false};
|
std::optional<bool> use_multiprocess;
|
||||||
bool show_version{false};
|
bool show_version{false};
|
||||||
bool show_help{false};
|
bool show_help{false};
|
||||||
std::string_view command;
|
std::string_view command;
|
||||||
|
@ -55,6 +56,7 @@ struct CommandLine {
|
||||||
};
|
};
|
||||||
|
|
||||||
CommandLine ParseCommandLine(int argc, char* argv[]);
|
CommandLine ParseCommandLine(int argc, char* argv[]);
|
||||||
|
bool UseMultiprocess(const CommandLine& cmd);
|
||||||
static void ExecCommand(const std::vector<const char*>& args, std::string_view argv0);
|
static void ExecCommand(const std::vector<const char*>& args, std::string_view argv0);
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
|
@ -78,9 +80,9 @@ int main(int argc, char* argv[])
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
} else if (cmd.command == "gui") {
|
} else if (cmd.command == "gui") {
|
||||||
args.emplace_back(cmd.use_multiprocess ? "bitcoin-gui" : "bitcoin-qt");
|
args.emplace_back(UseMultiprocess(cmd) ? "bitcoin-gui" : "bitcoin-qt");
|
||||||
} else if (cmd.command == "node") {
|
} else if (cmd.command == "node") {
|
||||||
args.emplace_back(cmd.use_multiprocess ? "bitcoin-node" : "bitcoind");
|
args.emplace_back(UseMultiprocess(cmd) ? "bitcoin-node" : "bitcoind");
|
||||||
} else if (cmd.command == "rpc") {
|
} else if (cmd.command == "rpc") {
|
||||||
args.emplace_back("bitcoin-cli");
|
args.emplace_back("bitcoin-cli");
|
||||||
// Since "bitcoin rpc" is a new interface that doesn't need to be
|
// Since "bitcoin rpc" is a new interface that doesn't need to be
|
||||||
|
@ -143,6 +145,30 @@ CommandLine ParseCommandLine(int argc, char* argv[])
|
||||||
return cmd;
|
return cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool UseMultiprocess(const CommandLine& cmd)
|
||||||
|
{
|
||||||
|
// If -m or -M options were explicitly specified, there is no need to
|
||||||
|
// further parse arguments to determine which to use.
|
||||||
|
if (cmd.use_multiprocess) return *cmd.use_multiprocess;
|
||||||
|
|
||||||
|
ArgsManager args;
|
||||||
|
args.SetDefaultFlags(ArgsManager::ALLOW_ANY);
|
||||||
|
std::string error_message;
|
||||||
|
auto argv{cmd.args};
|
||||||
|
argv.insert(argv.begin(), nullptr);
|
||||||
|
if (!args.ParseParameters(argv.size(), argv.data(), error_message)) {
|
||||||
|
tfm::format(std::cerr, "Warning: failed to parse subcommand command line options: %s\n", error_message);
|
||||||
|
}
|
||||||
|
if (!args.ReadConfigFiles(error_message, true)) {
|
||||||
|
tfm::format(std::cerr, "Warning: failed to parse subcommand config: %s\n", error_message);
|
||||||
|
}
|
||||||
|
args.SelectConfigNetwork(args.GetChainTypeString());
|
||||||
|
|
||||||
|
// If any -ipc* options are set these need to be processed by a
|
||||||
|
// multiprocess-capable binary.
|
||||||
|
return args.IsArgSet("-ipcbind") || args.IsArgSet("-ipcconnect") || args.IsArgSet("-ipcfd");
|
||||||
|
}
|
||||||
|
|
||||||
//! Execute the specified bitcoind, bitcoin-qt or other command line in `args`
|
//! Execute the specified bitcoind, bitcoin-qt or other command line in `args`
|
||||||
//! using src, bin and libexec directory paths relative to this executable, where
|
//! using src, bin and libexec directory paths relative to this executable, where
|
||||||
//! the path to this executable is specified in `wrapper_argv0`.
|
//! the path to this executable is specified in `wrapper_argv0`.
|
||||||
|
|
|
@ -132,11 +132,16 @@ static bool ParseArgs(NodeContext& node, int argc, char* argv[])
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ProcessInitCommands(ArgsManager& args)
|
static bool ProcessInitCommands(interfaces::Init& init, ArgsManager& args)
|
||||||
{
|
{
|
||||||
// Process help and version before taking care about datadir
|
// Process help and version before taking care about datadir
|
||||||
if (HelpRequested(args) || args.GetBoolArg("-version", false)) {
|
if (HelpRequested(args) || args.GetBoolArg("-version", false)) {
|
||||||
std::string strUsage = CLIENT_NAME " daemon version " + FormatFullVersion() + "\n";
|
std::string strUsage = CLIENT_NAME " daemon version " + FormatFullVersion();
|
||||||
|
if (const char* exe_name{init.exeName()}) {
|
||||||
|
strUsage += " ";
|
||||||
|
strUsage += exe_name;
|
||||||
|
}
|
||||||
|
strUsage += "\n";
|
||||||
|
|
||||||
if (args.GetBoolArg("-version", false)) {
|
if (args.GetBoolArg("-version", false)) {
|
||||||
strUsage += FormatParagraph(LicenseInfo());
|
strUsage += FormatParagraph(LicenseInfo());
|
||||||
|
@ -277,7 +282,7 @@ MAIN_FUNCTION
|
||||||
ArgsManager& args = *Assert(node.args);
|
ArgsManager& args = *Assert(node.args);
|
||||||
if (!ParseArgs(node, argc, argv)) return EXIT_FAILURE;
|
if (!ParseArgs(node, argc, argv)) return EXIT_FAILURE;
|
||||||
// Process early info return commands such as -help or -version
|
// Process early info return commands such as -help or -version
|
||||||
if (ProcessInitCommands(args)) return EXIT_SUCCESS;
|
if (ProcessInitCommands(*init, args)) return EXIT_SUCCESS;
|
||||||
|
|
||||||
// Start application
|
// Start application
|
||||||
if (!AppInit(node) || !Assert(node.shutdown_signal)->wait()) {
|
if (!AppInit(node) || !Assert(node.shutdown_signal)->wait()) {
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include <chain.h>
|
#include <chain.h>
|
||||||
#include <tinyformat.h>
|
#include <tinyformat.h>
|
||||||
|
#include <util/check.h>
|
||||||
#include <util/time.h>
|
#include <util/time.h>
|
||||||
|
|
||||||
std::string CBlockFileInfo::ToString() const
|
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.
|
/** Find the last common ancestor two blocks have.
|
||||||
* Both pa and pb must be non-nullptr. */
|
* Both pa and pb must be non-nullptr. */
|
||||||
const CBlockIndex* LastCommonAncestor(const CBlockIndex* pa, const CBlockIndex* pb) {
|
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) {
|
if (pa->nHeight > pb->nHeight) {
|
||||||
pa = pa->GetAncestor(pb->nHeight);
|
pa = pa->GetAncestor(pb->nHeight);
|
||||||
} else if (pb->nHeight > pa->nHeight) {
|
} else if (pb->nHeight > pa->nHeight) {
|
||||||
pb = pb->GetAncestor(pa->nHeight);
|
pb = pb->GetAncestor(pa->nHeight);
|
||||||
}
|
}
|
||||||
|
while (pa != pb) {
|
||||||
while (pa != pb && 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;
|
pa = pa->pprev;
|
||||||
pb = pb->pprev;
|
pb = pb->pprev;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Eventually all chain branches meet at the genesis block.
|
|
||||||
assert(pa == pb);
|
|
||||||
return pa;
|
return pa;
|
||||||
}
|
}
|
||||||
|
|
|
@ -266,7 +266,13 @@ std::optional<unsigned int> ArgsManager::GetArgFlags(const std::string& name) co
|
||||||
return search->second.m_flags;
|
return search->second.m_flags;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return std::nullopt;
|
return m_default_flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArgsManager::SetDefaultFlags(std::optional<unsigned int> flags)
|
||||||
|
{
|
||||||
|
LOCK(cs_args);
|
||||||
|
m_default_flags = flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
fs::path ArgsManager::GetPathArg(std::string arg, const fs::path& default_value) const
|
fs::path ArgsManager::GetPathArg(std::string arg, const fs::path& default_value) const
|
||||||
|
|
|
@ -137,6 +137,7 @@ protected:
|
||||||
std::string m_network GUARDED_BY(cs_args);
|
std::string m_network GUARDED_BY(cs_args);
|
||||||
std::set<std::string> m_network_only_args GUARDED_BY(cs_args);
|
std::set<std::string> m_network_only_args GUARDED_BY(cs_args);
|
||||||
std::map<OptionsCategory, std::map<std::string, Arg>> m_available_args GUARDED_BY(cs_args);
|
std::map<OptionsCategory, std::map<std::string, Arg>> m_available_args GUARDED_BY(cs_args);
|
||||||
|
std::optional<unsigned int> m_default_flags GUARDED_BY(cs_args){};
|
||||||
bool m_accept_any_command GUARDED_BY(cs_args){true};
|
bool m_accept_any_command GUARDED_BY(cs_args){true};
|
||||||
std::list<SectionInfo> m_config_sections GUARDED_BY(cs_args);
|
std::list<SectionInfo> m_config_sections GUARDED_BY(cs_args);
|
||||||
std::optional<fs::path> m_config_path GUARDED_BY(cs_args);
|
std::optional<fs::path> m_config_path GUARDED_BY(cs_args);
|
||||||
|
@ -375,10 +376,15 @@ protected:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return Flags for known arg.
|
* Return Flags for known arg.
|
||||||
* Return nullopt for unknown arg.
|
* Return default flags for unknown arg.
|
||||||
*/
|
*/
|
||||||
std::optional<unsigned int> GetArgFlags(const std::string& name) const;
|
std::optional<unsigned int> GetArgFlags(const std::string& name) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set default flags to return for an unknown arg.
|
||||||
|
*/
|
||||||
|
void SetDefaultFlags(std::optional<unsigned int>);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get settings file path, or return false if read-write settings were
|
* Get settings file path, or return false if read-write settings were
|
||||||
* disabled with -nosettings.
|
* disabled with -nosettings.
|
||||||
|
|
|
@ -113,10 +113,15 @@ int GetNumCores()
|
||||||
|
|
||||||
std::optional<size_t> GetTotalRAM()
|
std::optional<size_t> GetTotalRAM()
|
||||||
{
|
{
|
||||||
auto clamp{[](uint64_t v) { return size_t(std::min(v, uint64_t{std::numeric_limits<size_t>::max()})); }};
|
[[maybe_unused]] auto clamp{[](uint64_t v) { return size_t(std::min(v, uint64_t{std::numeric_limits<size_t>::max()})); }};
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
if (MEMORYSTATUSEX m{}; (m.dwLength = sizeof(m), GlobalMemoryStatusEx(&m))) return clamp(m.ullTotalPhys);
|
if (MEMORYSTATUSEX m{}; (m.dwLength = sizeof(m), GlobalMemoryStatusEx(&m))) return clamp(m.ullTotalPhys);
|
||||||
#elif defined(__linux__) || defined(__APPLE__)
|
#elif defined(__APPLE__) || \
|
||||||
|
defined(__FreeBSD__) || \
|
||||||
|
defined(__NetBSD__) || \
|
||||||
|
defined(__OpenBSD__) || \
|
||||||
|
defined(__illumos__) || \
|
||||||
|
defined(__linux__)
|
||||||
if (long p{sysconf(_SC_PHYS_PAGES)}, s{sysconf(_SC_PAGESIZE)}; p > 0 && s > 0) return clamp(1ULL * p * s);
|
if (long p{sysconf(_SC_PHYS_PAGES)}, s{sysconf(_SC_PAGESIZE)}; p > 0 && s > 0) return clamp(1ULL * p * s);
|
||||||
#endif
|
#endif
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#ifndef BITCOIN_CONSENSUS_PARAMS_H
|
#ifndef BITCOIN_CONSENSUS_PARAMS_H
|
||||||
#define BITCOIN_CONSENSUS_PARAMS_H
|
#define BITCOIN_CONSENSUS_PARAMS_H
|
||||||
|
|
||||||
|
#include <script/verify_flags.h>
|
||||||
#include <uint256.h>
|
#include <uint256.h>
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
@ -89,7 +90,7 @@ struct Params {
|
||||||
* - buried in the chain, and
|
* - buried in the chain, and
|
||||||
* - fail if the default script verify flags are applied.
|
* - 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 */
|
/** Block height and hash at which BIP34 becomes active */
|
||||||
int BIP34Height;
|
int BIP34Height;
|
||||||
uint256 BIP34Hash;
|
uint256 BIP34Hash;
|
||||||
|
|
|
@ -140,7 +140,7 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& in
|
||||||
return nSigOps;
|
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;
|
int64_t nSigOps = GetLegacySigOpCount(tx) * WITNESS_SCALE_FACTOR;
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#define BITCOIN_CONSENSUS_TX_VERIFY_H
|
#define BITCOIN_CONSENSUS_TX_VERIFY_H
|
||||||
|
|
||||||
#include <consensus/amount.h>
|
#include <consensus/amount.h>
|
||||||
|
#include <script/verify_flags.h>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -52,7 +53,7 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& ma
|
||||||
* @param[in] flags Script verification flags
|
* @param[in] flags Script verification flags
|
||||||
* @return Total signature operation cost of tx
|
* @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
|
* Check if transaction is final and can be included in a block with the
|
||||||
|
|
|
@ -8,8 +8,10 @@
|
||||||
#include <consensus/params.h>
|
#include <consensus/params.h>
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <cassert>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
struct VBDeploymentInfo {
|
struct VBDeploymentInfo {
|
||||||
/** Deployment name */
|
/** Deployment name */
|
||||||
|
|
|
@ -119,7 +119,7 @@ namespace sam {
|
||||||
|
|
||||||
Session::Session(const fs::path& private_key_file,
|
Session::Session(const fs::path& private_key_file,
|
||||||
const Proxy& control_host,
|
const Proxy& control_host,
|
||||||
CThreadInterrupt* interrupt)
|
std::shared_ptr<CThreadInterrupt> interrupt)
|
||||||
: m_private_key_file{private_key_file},
|
: m_private_key_file{private_key_file},
|
||||||
m_control_host{control_host},
|
m_control_host{control_host},
|
||||||
m_interrupt{interrupt},
|
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_control_host{control_host},
|
||||||
m_interrupt{interrupt},
|
m_interrupt{interrupt},
|
||||||
m_transient{true}
|
m_transient{true}
|
||||||
|
@ -162,7 +162,7 @@ bool Session::Accept(Connection& conn)
|
||||||
std::string errmsg;
|
std::string errmsg;
|
||||||
bool disconnect{false};
|
bool disconnect{false};
|
||||||
|
|
||||||
while (!*m_interrupt) {
|
while (!m_interrupt->interrupted()) {
|
||||||
Sock::Event occurred;
|
Sock::Event occurred;
|
||||||
if (!conn.sock->Wait(MAX_WAIT_FOR_IO, Sock::RECV, &occurred)) {
|
if (!conn.sock->Wait(MAX_WAIT_FOR_IO, Sock::RECV, &occurred)) {
|
||||||
errmsg = "wait on socket failed";
|
errmsg = "wait on socket failed";
|
||||||
|
@ -205,7 +205,7 @@ bool Session::Accept(Connection& conn)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*m_interrupt) {
|
if (m_interrupt->interrupted()) {
|
||||||
LogPrintLevel(BCLog::I2P, BCLog::Level::Debug, "Accept was interrupted\n");
|
LogPrintLevel(BCLog::I2P, BCLog::Level::Debug, "Accept was interrupted\n");
|
||||||
} else {
|
} else {
|
||||||
LogPrintLevel(BCLog::I2P, BCLog::Level::Debug, "Error accepting%s: %s\n", disconnect ? " (will close the session)" : "", errmsg);
|
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.
|
* private key will be generated and saved into the file.
|
||||||
* @param[in] control_host Location of the SAM proxy.
|
* @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
|
* @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
|
* possible and executing methods throw an exception.
|
||||||
* `CThreadInterrupt` object is saved, so it must not be destroyed earlier than this
|
|
||||||
* `Session` object.
|
|
||||||
*/
|
*/
|
||||||
Session(const fs::path& private_key_file,
|
Session(const fs::path& private_key_file,
|
||||||
const Proxy& control_host,
|
const Proxy& control_host,
|
||||||
CThreadInterrupt* interrupt);
|
std::shared_ptr<CThreadInterrupt> interrupt);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a transient session which will generate its own I2P private key
|
* 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.
|
* the session will be lazily created later when first used.
|
||||||
* @param[in] control_host Location of the SAM proxy.
|
* @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
|
* @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
|
* possible and executing methods throw an exception.
|
||||||
* `CThreadInterrupt` object is saved, so it must not be destroyed earlier than this
|
|
||||||
* `Session` object.
|
|
||||||
*/
|
*/
|
||||||
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
|
* 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.
|
* 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.
|
* 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("-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("-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("-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",
|
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)",
|
"are of this size or less, allowing multiple outputs (default: %u)",
|
||||||
MAX_OP_RETURN_RELAY),
|
MAX_OP_RETURN_RELAY),
|
||||||
ArgsManager::ALLOW_ANY, OptionsCategory::NODE_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."));
|
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.
|
// 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")) {
|
if (args.IsArgSet("-maxorphantx")) {
|
||||||
InitWarning(_("Option '-maxorphantx' is set but no longer has any effect (see release notes). Please remove it from your configuration."));
|
InitWarning(_("Option '-maxorphantx' is set but no longer has any effect (see release notes). Please remove it from your configuration."));
|
||||||
|
|
|
@ -39,6 +39,7 @@ public:
|
||||||
// bitcoin-node accepts the option, and bitcoin-gui accepts all bitcoin-node
|
// bitcoin-node accepts the option, and bitcoin-gui accepts all bitcoin-node
|
||||||
// options and will start the node with those options.
|
// options and will start the node with those options.
|
||||||
bool canListenIpc() override { return true; }
|
bool canListenIpc() override { return true; }
|
||||||
|
const char* exeName() override { return EXE_NAME; }
|
||||||
node::NodeContext m_node;
|
node::NodeContext m_node;
|
||||||
std::unique_ptr<interfaces::Ipc> m_ipc;
|
std::unique_ptr<interfaces::Ipc> m_ipc;
|
||||||
};
|
};
|
||||||
|
|
|
@ -38,6 +38,7 @@ public:
|
||||||
std::unique_ptr<interfaces::Echo> makeEcho() override { return interfaces::MakeEcho(); }
|
std::unique_ptr<interfaces::Echo> makeEcho() override { return interfaces::MakeEcho(); }
|
||||||
interfaces::Ipc* ipc() override { return m_ipc.get(); }
|
interfaces::Ipc* ipc() override { return m_ipc.get(); }
|
||||||
bool canListenIpc() override { return true; }
|
bool canListenIpc() override { return true; }
|
||||||
|
const char* exeName() override { return EXE_NAME; }
|
||||||
node::NodeContext& m_node;
|
node::NodeContext& m_node;
|
||||||
std::unique_ptr<interfaces::Ipc> m_ipc;
|
std::unique_ptr<interfaces::Ipc> m_ipc;
|
||||||
};
|
};
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
|
|
||||||
namespace init {
|
namespace init {
|
||||||
namespace {
|
namespace {
|
||||||
|
const char* EXE_NAME = "bitcoin-qt";
|
||||||
|
|
||||||
class BitcoinQtInit : public interfaces::Init
|
class BitcoinQtInit : public interfaces::Init
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -32,6 +34,7 @@ public:
|
||||||
return MakeWalletLoader(chain, *Assert(m_node.args));
|
return MakeWalletLoader(chain, *Assert(m_node.args));
|
||||||
}
|
}
|
||||||
std::unique_ptr<interfaces::Echo> makeEcho() override { return interfaces::MakeEcho(); }
|
std::unique_ptr<interfaces::Echo> makeEcho() override { return interfaces::MakeEcho(); }
|
||||||
|
const char* exeName() override { return EXE_NAME; }
|
||||||
node::NodeContext m_node;
|
node::NodeContext m_node;
|
||||||
};
|
};
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -18,6 +18,8 @@ using node::NodeContext;
|
||||||
|
|
||||||
namespace init {
|
namespace init {
|
||||||
namespace {
|
namespace {
|
||||||
|
const char* EXE_NAME = "bitcoind";
|
||||||
|
|
||||||
class BitcoindInit : public interfaces::Init
|
class BitcoindInit : public interfaces::Init
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -34,6 +36,7 @@ public:
|
||||||
return MakeWalletLoader(chain, *Assert(m_node.args));
|
return MakeWalletLoader(chain, *Assert(m_node.args));
|
||||||
}
|
}
|
||||||
std::unique_ptr<interfaces::Echo> makeEcho() override { return interfaces::MakeEcho(); }
|
std::unique_ptr<interfaces::Echo> makeEcho() override { return interfaces::MakeEcho(); }
|
||||||
|
const char* exeName() override { return EXE_NAME; }
|
||||||
NodeContext& m_node;
|
NodeContext& m_node;
|
||||||
};
|
};
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -38,6 +38,7 @@ public:
|
||||||
virtual std::unique_ptr<Echo> makeEcho() { return nullptr; }
|
virtual std::unique_ptr<Echo> makeEcho() { return nullptr; }
|
||||||
virtual Ipc* ipc() { return nullptr; }
|
virtual Ipc* ipc() { return nullptr; }
|
||||||
virtual bool canListenIpc() { return false; }
|
virtual bool canListenIpc() { return false; }
|
||||||
|
virtual const char* exeName() { return nullptr; }
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Return implementation of Init interface for the node process. If the argv
|
//! Return implementation of Init interface for the node process. If the argv
|
||||||
|
|
20
src/key.cpp
20
src/key.cpp
|
@ -155,7 +155,7 @@ int ec_seckey_export_der(const secp256k1_context *ctx, unsigned char *seckey, si
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CKey::Check(const unsigned char *vch) {
|
bool CKey::Check(const unsigned char *vch) {
|
||||||
return secp256k1_ec_seckey_verify(secp256k1_context_sign, vch);
|
return secp256k1_ec_seckey_verify(secp256k1_context_static, vch);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CKey::MakeNewKey(bool fCompressedIn) {
|
void CKey::MakeNewKey(bool fCompressedIn) {
|
||||||
|
@ -186,7 +186,7 @@ CPubKey CKey::GetPubKey() const {
|
||||||
CPubKey result;
|
CPubKey result;
|
||||||
int ret = secp256k1_ec_pubkey_create(secp256k1_context_sign, &pubkey, UCharCast(begin()));
|
int ret = secp256k1_ec_pubkey_create(secp256k1_context_sign, &pubkey, UCharCast(begin()));
|
||||||
assert(ret);
|
assert(ret);
|
||||||
secp256k1_ec_pubkey_serialize(secp256k1_context_sign, (unsigned char*)result.begin(), &clen, &pubkey, fCompressed ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED);
|
secp256k1_ec_pubkey_serialize(secp256k1_context_static, (unsigned char*)result.begin(), &clen, &pubkey, fCompressed ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED);
|
||||||
assert(result.size() == clen);
|
assert(result.size() == clen);
|
||||||
assert(result.IsValid());
|
assert(result.IsValid());
|
||||||
return result;
|
return result;
|
||||||
|
@ -196,7 +196,7 @@ CPubKey CKey::GetPubKey() const {
|
||||||
bool SigHasLowR(const secp256k1_ecdsa_signature* sig)
|
bool SigHasLowR(const secp256k1_ecdsa_signature* sig)
|
||||||
{
|
{
|
||||||
unsigned char compact_sig[64];
|
unsigned char compact_sig[64];
|
||||||
secp256k1_ecdsa_signature_serialize_compact(secp256k1_context_sign, compact_sig, sig);
|
secp256k1_ecdsa_signature_serialize_compact(secp256k1_context_static, compact_sig, sig);
|
||||||
|
|
||||||
// In DER serialization, all values are interpreted as big-endian, signed integers. The highest bit in the integer indicates
|
// In DER serialization, all values are interpreted as big-endian, signed integers. The highest bit in the integer indicates
|
||||||
// its signed-ness; 0 is positive, 1 is negative. When the value is interpreted as a negative integer, it must be converted
|
// its signed-ness; 0 is positive, 1 is negative. When the value is interpreted as a negative integer, it must be converted
|
||||||
|
@ -222,7 +222,7 @@ bool CKey::Sign(const uint256 &hash, std::vector<unsigned char>& vchSig, bool gr
|
||||||
ret = secp256k1_ecdsa_sign(secp256k1_context_sign, &sig, hash.begin(), UCharCast(begin()), secp256k1_nonce_function_rfc6979, extra_entropy);
|
ret = secp256k1_ecdsa_sign(secp256k1_context_sign, &sig, hash.begin(), UCharCast(begin()), secp256k1_nonce_function_rfc6979, extra_entropy);
|
||||||
}
|
}
|
||||||
assert(ret);
|
assert(ret);
|
||||||
secp256k1_ecdsa_signature_serialize_der(secp256k1_context_sign, vchSig.data(), &nSigLen, &sig);
|
secp256k1_ecdsa_signature_serialize_der(secp256k1_context_static, vchSig.data(), &nSigLen, &sig);
|
||||||
vchSig.resize(nSigLen);
|
vchSig.resize(nSigLen);
|
||||||
// Additional verification step to prevent using a potentially corrupted signature
|
// Additional verification step to prevent using a potentially corrupted signature
|
||||||
secp256k1_pubkey pk;
|
secp256k1_pubkey pk;
|
||||||
|
@ -254,7 +254,7 @@ bool CKey::SignCompact(const uint256 &hash, std::vector<unsigned char>& vchSig)
|
||||||
secp256k1_ecdsa_recoverable_signature rsig;
|
secp256k1_ecdsa_recoverable_signature rsig;
|
||||||
int ret = secp256k1_ecdsa_sign_recoverable(secp256k1_context_sign, &rsig, hash.begin(), UCharCast(begin()), secp256k1_nonce_function_rfc6979, nullptr);
|
int ret = secp256k1_ecdsa_sign_recoverable(secp256k1_context_sign, &rsig, hash.begin(), UCharCast(begin()), secp256k1_nonce_function_rfc6979, nullptr);
|
||||||
assert(ret);
|
assert(ret);
|
||||||
ret = secp256k1_ecdsa_recoverable_signature_serialize_compact(secp256k1_context_sign, &vchSig[1], &rec, &rsig);
|
ret = secp256k1_ecdsa_recoverable_signature_serialize_compact(secp256k1_context_static, &vchSig[1], &rec, &rsig);
|
||||||
assert(ret);
|
assert(ret);
|
||||||
assert(rec != -1);
|
assert(rec != -1);
|
||||||
vchSig[0] = 27 + rec + (fCompressed ? 4 : 0);
|
vchSig[0] = 27 + rec + (fCompressed ? 4 : 0);
|
||||||
|
@ -277,7 +277,7 @@ bool CKey::SignSchnorr(const uint256& hash, std::span<unsigned char> sig, const
|
||||||
|
|
||||||
bool CKey::Load(const CPrivKey &seckey, const CPubKey &vchPubKey, bool fSkipCheck=false) {
|
bool CKey::Load(const CPrivKey &seckey, const CPubKey &vchPubKey, bool fSkipCheck=false) {
|
||||||
MakeKeyData();
|
MakeKeyData();
|
||||||
if (!ec_seckey_import_der(secp256k1_context_sign, (unsigned char*)begin(), seckey.data(), seckey.size())) {
|
if (!ec_seckey_import_der(secp256k1_context_static, (unsigned char*)begin(), seckey.data(), seckey.size())) {
|
||||||
ClearKeyData();
|
ClearKeyData();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -303,7 +303,7 @@ bool CKey::Derive(CKey& keyChild, ChainCode &ccChild, unsigned int nChild, const
|
||||||
}
|
}
|
||||||
memcpy(ccChild.begin(), vout.data()+32, 32);
|
memcpy(ccChild.begin(), vout.data()+32, 32);
|
||||||
keyChild.Set(begin(), begin() + 32, true);
|
keyChild.Set(begin(), begin() + 32, true);
|
||||||
bool ret = secp256k1_ec_seckey_tweak_add(secp256k1_context_sign, (unsigned char*)keyChild.begin(), vout.data());
|
bool ret = secp256k1_ec_seckey_tweak_add(secp256k1_context_static, (unsigned char*)keyChild.begin(), vout.data());
|
||||||
if (!ret) keyChild.ClearKeyData();
|
if (!ret) keyChild.ClearKeyData();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -331,7 +331,7 @@ ECDHSecret CKey::ComputeBIP324ECDHSecret(const EllSwiftPubKey& their_ellswift, c
|
||||||
ECDHSecret output;
|
ECDHSecret output;
|
||||||
// BIP324 uses the initiator as party A, and the responder as party B. Remap the inputs
|
// BIP324 uses the initiator as party A, and the responder as party B. Remap the inputs
|
||||||
// accordingly:
|
// accordingly:
|
||||||
bool success = secp256k1_ellswift_xdh(secp256k1_context_sign,
|
bool success = secp256k1_ellswift_xdh(secp256k1_context_static,
|
||||||
UCharCast(output.data()),
|
UCharCast(output.data()),
|
||||||
UCharCast(initiating ? our_ellswift.data() : their_ellswift.data()),
|
UCharCast(initiating ? our_ellswift.data() : their_ellswift.data()),
|
||||||
UCharCast(initiating ? their_ellswift.data() : our_ellswift.data()),
|
UCharCast(initiating ? their_ellswift.data() : our_ellswift.data()),
|
||||||
|
@ -415,8 +415,8 @@ KeyPair::KeyPair(const CKey& key, const uint256* merkle_root)
|
||||||
if (success && merkle_root) {
|
if (success && merkle_root) {
|
||||||
secp256k1_xonly_pubkey pubkey;
|
secp256k1_xonly_pubkey pubkey;
|
||||||
unsigned char pubkey_bytes[32];
|
unsigned char pubkey_bytes[32];
|
||||||
assert(secp256k1_keypair_xonly_pub(secp256k1_context_sign, &pubkey, nullptr, keypair));
|
assert(secp256k1_keypair_xonly_pub(secp256k1_context_static, &pubkey, nullptr, keypair));
|
||||||
assert(secp256k1_xonly_pubkey_serialize(secp256k1_context_sign, pubkey_bytes, &pubkey));
|
assert(secp256k1_xonly_pubkey_serialize(secp256k1_context_static, pubkey_bytes, &pubkey));
|
||||||
uint256 tweak = XOnlyPubKey(pubkey_bytes).ComputeTapTweakHash(merkle_root->IsNull() ? nullptr : merkle_root);
|
uint256 tweak = XOnlyPubKey(pubkey_bytes).ComputeTapTweakHash(merkle_root->IsNull() ? nullptr : merkle_root);
|
||||||
success = secp256k1_keypair_xonly_tweak_add(secp256k1_context_static, keypair, tweak.data());
|
success = secp256k1_keypair_xonly_tweak_add(secp256k1_context_static, keypair, tweak.data());
|
||||||
}
|
}
|
||||||
|
|
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_NETGROUP = 0x6c0edd8036ef4036ULL; // SHA256("netgroup")[0:8]
|
||||||
static const uint64_t RANDOMIZER_ID_LOCALHOSTNONCE = 0xd93e69e2bbfa5735ULL; // SHA256("localhostnonce")[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
|
// Global state variables
|
||||||
//
|
//
|
||||||
|
@ -331,42 +331,22 @@ bool IsLocal(const CService& addr)
|
||||||
return mapLocalHost.count(addr) > 0;
|
return mapLocalHost.count(addr) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
CNode* CConnman::FindNode(const CNetAddr& ip)
|
bool CConnman::AlreadyConnectedToHost(const std::string& host) const
|
||||||
{
|
{
|
||||||
LOCK(m_nodes_mutex);
|
LOCK(m_nodes_mutex);
|
||||||
for (CNode* pnode : m_nodes) {
|
return std::ranges::any_of(m_nodes, [&host](CNode* node) { return node->m_addr_name == host; });
|
||||||
if (static_cast<CNetAddr>(pnode->addr) == ip) {
|
|
||||||
return pnode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CNode* CConnman::FindNode(const std::string& addrName)
|
bool CConnman::AlreadyConnectedToAddressPort(const CService& addr_port) const
|
||||||
{
|
{
|
||||||
LOCK(m_nodes_mutex);
|
LOCK(m_nodes_mutex);
|
||||||
for (CNode* pnode : m_nodes) {
|
return std::ranges::any_of(m_nodes, [&addr_port](CNode* node) { return node->addr == addr_port; });
|
||||||
if (pnode->m_addr_name == addrName) {
|
|
||||||
return pnode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CNode* CConnman::FindNode(const CService& addr)
|
bool CConnman::AlreadyConnectedToAddress(const CNetAddr& addr) const
|
||||||
{
|
{
|
||||||
LOCK(m_nodes_mutex);
|
LOCK(m_nodes_mutex);
|
||||||
for (CNode* pnode : m_nodes) {
|
return std::ranges::any_of(m_nodes, [&addr](CNode* node) { return node->addr == addr; });
|
||||||
if (static_cast<CService>(pnode->addr) == addr) {
|
|
||||||
return pnode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CConnman::AlreadyConnectedToAddress(const CAddress& addr)
|
|
||||||
{
|
|
||||||
return FindNode(static_cast<CNetAddr>(addr));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CConnman::CheckIncomingNonce(uint64_t nonce)
|
bool CConnman::CheckIncomingNonce(uint64_t nonce)
|
||||||
|
@ -393,7 +373,12 @@ static CService GetBindAddress(const Sock& sock)
|
||||||
return addr_bind;
|
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);
|
AssertLockNotHeld(m_unused_i2p_sessions_mutex);
|
||||||
assert(conn_type != ConnectionType::INBOUND);
|
assert(conn_type != ConnectionType::INBOUND);
|
||||||
|
@ -403,10 +388,8 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
// Look for an existing connection
|
// Look for an existing connection
|
||||||
CNode* pnode = FindNode(static_cast<CService>(addrConnect));
|
if (AlreadyConnectedToAddressPort(addrConnect)) {
|
||||||
if (pnode)
|
LogInfo("Failed to open new connection to %s, already connected", addrConnect.ToStringAddrPort());
|
||||||
{
|
|
||||||
LogPrintf("Failed to open new connection, already connected\n");
|
|
||||||
return nullptr;
|
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.
|
// 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.
|
// In that case, drop the connection that was just created.
|
||||||
LOCK(m_nodes_mutex);
|
if (AlreadyConnectedToAddressPort(addrConnect)) {
|
||||||
CNode* pnode = FindNode(static_cast<CService>(addrConnect));
|
|
||||||
if (pnode) {
|
|
||||||
LogPrintf("Not opening a connection to %s, already connected to %s\n", pszDest, addrConnect.ToStringAddrPort());
|
LogPrintf("Not opening a connection to %s, already connected to %s\n", pszDest, addrConnect.ToStringAddrPort());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -463,7 +444,13 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
|
||||||
|
|
||||||
for (auto& target_addr: connect_to) {
|
for (auto& target_addr: connect_to) {
|
||||||
if (target_addr.IsValid()) {
|
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;
|
bool proxyConnectionFailed = false;
|
||||||
|
|
||||||
if (target_addr.IsI2P() && use_proxy) {
|
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);
|
LOCK(m_unused_i2p_sessions_mutex);
|
||||||
if (m_unused_i2p_sessions.empty()) {
|
if (m_unused_i2p_sessions.empty()) {
|
||||||
i2p_transient_session =
|
i2p_transient_session =
|
||||||
std::make_unique<i2p::sam::Session>(proxy, &interruptNet);
|
std::make_unique<i2p::sam::Session>(proxy, m_interrupt_net);
|
||||||
} else {
|
} else {
|
||||||
i2p_transient_session.swap(m_unused_i2p_sessions.front());
|
i2p_transient_session.swap(m_unused_i2p_sessions.front());
|
||||||
m_unused_i2p_sessions.pop();
|
m_unused_i2p_sessions.pop();
|
||||||
|
@ -530,6 +517,13 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
|
||||||
if (!addr_bind.IsValid()) {
|
if (!addr_bind.IsValid()) {
|
||||||
addr_bind = GetBindAddress(*sock);
|
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,
|
CNode* pnode = new CNode(id,
|
||||||
std::move(sock),
|
std::move(sock),
|
||||||
target_addr,
|
target_addr,
|
||||||
|
@ -539,6 +533,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
|
||||||
pszDest ? pszDest : "",
|
pszDest ? pszDest : "",
|
||||||
conn_type,
|
conn_type,
|
||||||
/*inbound_onion=*/false,
|
/*inbound_onion=*/false,
|
||||||
|
network_id,
|
||||||
CNodeOptions{
|
CNodeOptions{
|
||||||
.permission_flags = permission_flags,
|
.permission_flags = permission_flags,
|
||||||
.i2p_sam_session = std::move(i2p_transient_session),
|
.i2p_sam_session = std::move(i2p_transient_session),
|
||||||
|
@ -1832,6 +1827,11 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
|
||||||
ServiceFlags local_services = GetLocalServices();
|
ServiceFlags local_services = GetLocalServices();
|
||||||
const bool use_v2transport(local_services & NODE_P2P_V2);
|
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,
|
CNode* pnode = new CNode(id,
|
||||||
std::move(sock),
|
std::move(sock),
|
||||||
CAddress{addr, NODE_NONE},
|
CAddress{addr, NODE_NONE},
|
||||||
|
@ -1841,6 +1841,7 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
|
||||||
/*addrNameIn=*/"",
|
/*addrNameIn=*/"",
|
||||||
ConnectionType::INBOUND,
|
ConnectionType::INBOUND,
|
||||||
inbound_onion,
|
inbound_onion,
|
||||||
|
network_id,
|
||||||
CNodeOptions{
|
CNodeOptions{
|
||||||
.permission_flags = permission_flags,
|
.permission_flags = permission_flags,
|
||||||
.prefer_evict = discouraged,
|
.prefer_evict = discouraged,
|
||||||
|
@ -2103,7 +2104,7 @@ void CConnman::SocketHandler()
|
||||||
// empty sets.
|
// empty sets.
|
||||||
events_per_sock = GenerateWaitSockets(snap.Nodes());
|
events_per_sock = GenerateWaitSockets(snap.Nodes());
|
||||||
if (events_per_sock.empty() || !events_per_sock.begin()->first->WaitMany(timeout, events_per_sock)) {
|
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.
|
// 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);
|
AssertLockNotHeld(m_total_bytes_sent_mutex);
|
||||||
|
|
||||||
for (CNode* pnode : nodes) {
|
for (CNode* pnode : nodes) {
|
||||||
if (interruptNet)
|
if (m_interrupt_net->interrupted()) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Receive
|
// Receive
|
||||||
|
@ -2216,7 +2218,7 @@ void CConnman::SocketHandlerConnected(const std::vector<CNode*>& nodes,
|
||||||
void CConnman::SocketHandlerListening(const Sock::EventsPerSock& events_per_sock)
|
void CConnman::SocketHandlerListening(const Sock::EventsPerSock& events_per_sock)
|
||||||
{
|
{
|
||||||
for (const ListenSocket& listen_socket : vhListenSocket) {
|
for (const ListenSocket& listen_socket : vhListenSocket) {
|
||||||
if (interruptNet) {
|
if (m_interrupt_net->interrupted()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto it = events_per_sock.find(listen_socket.sock);
|
const auto it = events_per_sock.find(listen_socket.sock);
|
||||||
|
@ -2230,8 +2232,7 @@ void CConnman::ThreadSocketHandler()
|
||||||
{
|
{
|
||||||
AssertLockNotHeld(m_total_bytes_sent_mutex);
|
AssertLockNotHeld(m_total_bytes_sent_mutex);
|
||||||
|
|
||||||
while (!interruptNet)
|
while (!m_interrupt_net->interrupted()) {
|
||||||
{
|
|
||||||
DisconnectNodes();
|
DisconnectNodes();
|
||||||
NotifyNumConnectionsChanged();
|
NotifyNumConnectionsChanged();
|
||||||
SocketHandler();
|
SocketHandler();
|
||||||
|
@ -2255,9 +2256,10 @@ void CConnman::ThreadDNSAddressSeed()
|
||||||
auto start = NodeClock::now();
|
auto start = NodeClock::now();
|
||||||
constexpr std::chrono::seconds SEEDNODE_TIMEOUT = 30s;
|
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());
|
LogPrintf("-seednode enabled. Trying the provided seeds for %d seconds before defaulting to the dnsseeds.\n", SEEDNODE_TIMEOUT.count());
|
||||||
while (!interruptNet) {
|
while (!m_interrupt_net->interrupted()) {
|
||||||
if (!interruptNet.sleep_for(std::chrono::milliseconds(500)))
|
if (!m_interrupt_net->sleep_for(500ms)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Abort if we have spent enough time without reaching our target.
|
// 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)
|
// 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
|
// early to see if we have enough peers and can stop
|
||||||
// this thread entirely freeing up its resources
|
// this thread entirely freeing up its resources
|
||||||
std::chrono::seconds w = std::min(DNSSEEDS_DELAY_FEW_PEERS, to_wait);
|
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;
|
to_wait -= w;
|
||||||
|
|
||||||
if (GetFullOutboundConnCount() >= SEED_OUTBOUND_CONNECTION_THRESHOLD) {
|
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
|
// hold off on querying seeds if P2P network deactivated
|
||||||
if (!fNetworkActive) {
|
if (!fNetworkActive) {
|
||||||
LogPrintf("Waiting for network to be reactivated before querying DNS seeds.\n");
|
LogPrintf("Waiting for network to be reactivated before querying DNS seeds.\n");
|
||||||
do {
|
do {
|
||||||
if (!interruptNet.sleep_for(std::chrono::seconds{1})) return;
|
if (!m_interrupt_net->sleep_for(1s)) return;
|
||||||
} while (!fNetworkActive);
|
} 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);
|
OpenNetworkConnection(addr, false, {}, strAddr.c_str(), ConnectionType::MANUAL, /*use_v2transport=*/use_v2transport);
|
||||||
for (int i = 0; i < 10 && i < nLoop; i++)
|
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;
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!interruptNet.sleep_for(std::chrono::milliseconds(500)))
|
if (!m_interrupt_net->sleep_for(500ms)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
PerformReconnections();
|
PerformReconnections();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2564,8 +2568,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect, std
|
||||||
LogPrintf("Fixed seeds are disabled\n");
|
LogPrintf("Fixed seeds are disabled\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!interruptNet)
|
while (!m_interrupt_net->interrupted()) {
|
||||||
{
|
|
||||||
if (add_addr_fetch) {
|
if (add_addr_fetch) {
|
||||||
add_addr_fetch = false;
|
add_addr_fetch = false;
|
||||||
const auto& seed{SpanPopBack(seed_nodes)};
|
const auto& seed{SpanPopBack(seed_nodes)};
|
||||||
|
@ -2580,14 +2583,16 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect, std
|
||||||
|
|
||||||
ProcessAddrFetch();
|
ProcessAddrFetch();
|
||||||
|
|
||||||
if (!interruptNet.sleep_for(std::chrono::milliseconds(500)))
|
if (!m_interrupt_net->sleep_for(500ms)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
PerformReconnections();
|
PerformReconnections();
|
||||||
|
|
||||||
CountingSemaphoreGrant<> grant(*semOutbound);
|
CountingSemaphoreGrant<> grant(*semOutbound);
|
||||||
if (interruptNet)
|
if (m_interrupt_net->interrupted()) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const std::unordered_set<Network> fixed_seed_networks{GetReachableEmptyNetworks()};
|
const std::unordered_set<Network> fixed_seed_networks{GetReachableEmptyNetworks()};
|
||||||
if (add_fixed_seeds && !fixed_seed_networks.empty()) {
|
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;
|
int nTries = 0;
|
||||||
const auto reachable_nets{g_reachable_nets.All()};
|
const auto reachable_nets{g_reachable_nets.All()};
|
||||||
|
|
||||||
while (!interruptNet)
|
while (!m_interrupt_net->interrupted()) {
|
||||||
{
|
|
||||||
if (anchor && !m_anchors.empty()) {
|
if (anchor && !m_anchors.empty()) {
|
||||||
const CAddress addr = m_anchors.back();
|
const CAddress addr = m_anchors.back();
|
||||||
m_anchors.pop_back();
|
m_anchors.pop_back();
|
||||||
|
@ -2864,7 +2868,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect, std
|
||||||
if (addrConnect.IsValid()) {
|
if (addrConnect.IsValid()) {
|
||||||
if (fFeeler) {
|
if (fFeeler) {
|
||||||
// Add small amount of random noise before connection to avoid synchronization.
|
// 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;
|
return;
|
||||||
}
|
}
|
||||||
LogDebug(BCLog::NET, "Making feeler connection to %s\n", addrConnect.ToStringAddrPort());
|
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)};
|
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.
|
// Use BIP324 transport when both us and them have NODE_V2_P2P set.
|
||||||
const bool use_v2transport(addrConnect.nServices & GetLocalServices() & NODE_P2P_V2);
|
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;
|
tried = true;
|
||||||
CAddress addr(CService(), NODE_NONE);
|
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);
|
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);
|
grant = CountingSemaphoreGrant<>(*semAddnode, /*fTry=*/true);
|
||||||
}
|
}
|
||||||
// See if any reconnections are desired.
|
// See if any reconnections are desired.
|
||||||
PerformReconnections();
|
PerformReconnections();
|
||||||
// Retry every 60 seconds if a connection was attempted, otherwise two seconds
|
// 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;
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if successful, this moves the passed grant to the constructed node
|
// 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);
|
AssertLockNotHeld(m_unused_i2p_sessions_mutex);
|
||||||
assert(conn_type != ConnectionType::INBOUND);
|
assert(conn_type != ConnectionType::INBOUND);
|
||||||
|
@ -2995,24 +3006,25 @@ void CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai
|
||||||
//
|
//
|
||||||
// Initiate outbound network connection
|
// Initiate outbound network connection
|
||||||
//
|
//
|
||||||
if (interruptNet) {
|
if (m_interrupt_net->interrupted()) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
if (!fNetworkActive) {
|
if (!fNetworkActive) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
if (!pszDest) {
|
if (!pszDest) {
|
||||||
bool banned_or_discouraged = m_banman && (m_banman->IsDiscouraged(addrConnect) || m_banman->IsBanned(addrConnect));
|
bool banned_or_discouraged = m_banman && (m_banman->IsDiscouraged(addrConnect) || m_banman->IsBanned(addrConnect));
|
||||||
if (IsLocal(addrConnect) || banned_or_discouraged || AlreadyConnectedToAddress(addrConnect)) {
|
if (IsLocal(addrConnect) || banned_or_discouraged || AlreadyConnectedToAddress(addrConnect)) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (FindNode(std::string(pszDest)))
|
} else if (AlreadyConnectedToHost(pszDest)) {
|
||||||
return;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
CNode* pnode = ConnectNode(addrConnect, pszDest, fCountFailure, conn_type, use_v2transport);
|
CNode* pnode = ConnectNode(addrConnect, pszDest, fCountFailure, conn_type, use_v2transport, proxy_override);
|
||||||
|
|
||||||
if (!pnode)
|
if (!pnode)
|
||||||
return;
|
return false;
|
||||||
pnode->grantOutbound = std::move(grant_outbound);
|
pnode->grantOutbound = std::move(grant_outbound);
|
||||||
|
|
||||||
m_msgproc->InitializeNode(*pnode, m_local_services);
|
m_msgproc->InitializeNode(*pnode, m_local_services);
|
||||||
|
@ -3030,6 +3042,8 @@ void CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai
|
||||||
pnode->ConnectionTypeAsString().c_str(),
|
pnode->ConnectionTypeAsString().c_str(),
|
||||||
pnode->ConnectedThroughNetwork(),
|
pnode->ConnectedThroughNetwork(),
|
||||||
GetNodeCount(ConnectionDirection::Out));
|
GetNodeCount(ConnectionDirection::Out));
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Mutex NetEventsInterface::g_msgproc_mutex;
|
Mutex NetEventsInterface::g_msgproc_mutex;
|
||||||
|
@ -3083,13 +3097,13 @@ void CConnman::ThreadI2PAcceptIncoming()
|
||||||
i2p::Connection conn;
|
i2p::Connection conn;
|
||||||
|
|
||||||
auto SleepOnFailure = [&]() {
|
auto SleepOnFailure = [&]() {
|
||||||
interruptNet.sleep_for(err_wait);
|
m_interrupt_net->sleep_for(err_wait);
|
||||||
if (err_wait < err_wait_cap) {
|
if (err_wait < err_wait_cap) {
|
||||||
err_wait += 1s;
|
err_wait += 1s;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
while (!interruptNet) {
|
while (!m_interrupt_net->interrupted()) {
|
||||||
|
|
||||||
if (!m_i2p_sam_session->Listen(conn)) {
|
if (!m_i2p_sam_session->Listen(conn)) {
|
||||||
if (advertising_listen_addr && conn.me.IsValid()) {
|
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,
|
CConnman::CConnman(uint64_t nSeed0In,
|
||||||
const NetGroupManager& netgroupman, const CChainParams& params, bool network_active)
|
uint64_t nSeed1In,
|
||||||
|
AddrMan& addrman_in,
|
||||||
|
const NetGroupManager& netgroupman,
|
||||||
|
const CChainParams& params,
|
||||||
|
bool network_active,
|
||||||
|
std::shared_ptr<CThreadInterrupt> interrupt_net)
|
||||||
: addrman(addrman_in)
|
: addrman(addrman_in)
|
||||||
, m_netgroupman{netgroupman}
|
, m_netgroupman{netgroupman}
|
||||||
, nSeed0(nSeed0In)
|
, nSeed0(nSeed0In)
|
||||||
, nSeed1(nSeed1In)
|
, nSeed1(nSeed1In)
|
||||||
|
, m_interrupt_net{interrupt_net}
|
||||||
, m_params(params)
|
, m_params(params)
|
||||||
{
|
{
|
||||||
SetTryNewOutboundPeer(false);
|
SetTryNewOutboundPeer(false);
|
||||||
|
@ -3312,7 +3332,7 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)
|
||||||
Proxy i2p_sam;
|
Proxy i2p_sam;
|
||||||
if (GetProxy(NET_I2P, i2p_sam) && connOptions.m_i2p_accept_incoming) {
|
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",
|
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)
|
// 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
|
// Start threads
|
||||||
//
|
//
|
||||||
assert(m_msgproc);
|
assert(m_msgproc);
|
||||||
interruptNet.reset();
|
m_interrupt_net->reset();
|
||||||
flagInterruptMsgProc = false;
|
flagInterruptMsgProc = false;
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -3425,7 +3445,7 @@ void CConnman::Interrupt()
|
||||||
}
|
}
|
||||||
condMsgProc.notify_all();
|
condMsgProc.notify_all();
|
||||||
|
|
||||||
interruptNet();
|
(*m_interrupt_net)();
|
||||||
g_socks5_interrupt();
|
g_socks5_interrupt();
|
||||||
|
|
||||||
if (semOutbound) {
|
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)
|
std::vector<CAddress> CConnman::GetAddresses(CNode& requestor, size_t max_addresses, size_t max_pct)
|
||||||
{
|
{
|
||||||
auto local_socket_bytes = requestor.addrBind.GetAddrBytes();
|
auto local_socket_bytes = requestor.addrBind.GetAddrBytes();
|
||||||
uint64_t cache_id = GetDeterministicRandomizer(RANDOMIZER_ID_ADDRCACHE)
|
uint64_t network_id = requestor.m_network_key;
|
||||||
.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();
|
|
||||||
const auto current_time = GetTime<std::chrono::microseconds>();
|
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;
|
CachedAddrResponse& cache_entry = r.first->second;
|
||||||
if (cache_entry.m_cache_entry_expiration < current_time) { // If emplace() added new one it has expiration 0.
|
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);
|
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)
|
bool CConnman::DisconnectNode(const std::string& strNode)
|
||||||
{
|
{
|
||||||
LOCK(m_nodes_mutex);
|
LOCK(m_nodes_mutex);
|
||||||
if (CNode* pnode = FindNode(strNode)) {
|
auto it = std::ranges::find_if(m_nodes, [&strNode](CNode* node) { return node->m_addr_name == strNode; });
|
||||||
LogDebug(BCLog::NET, "disconnect by address%s match, %s", (fLogIPs ? strprintf("=%s", strNode) : ""), pnode->DisconnectMsg(fLogIPs));
|
if (it != m_nodes.end()) {
|
||||||
pnode->fDisconnect = true;
|
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 true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -3804,6 +3820,7 @@ CNode::CNode(NodeId idIn,
|
||||||
const std::string& addrNameIn,
|
const std::string& addrNameIn,
|
||||||
ConnectionType conn_type_in,
|
ConnectionType conn_type_in,
|
||||||
bool inbound_onion,
|
bool inbound_onion,
|
||||||
|
uint64_t network_key,
|
||||||
CNodeOptions&& node_opts)
|
CNodeOptions&& node_opts)
|
||||||
: m_transport{MakeTransport(idIn, node_opts.use_v2transport, conn_type_in == ConnectionType::INBOUND)},
|
: m_transport{MakeTransport(idIn, node_opts.use_v2transport, conn_type_in == ConnectionType::INBOUND)},
|
||||||
m_permission_flags{node_opts.permission_flags},
|
m_permission_flags{node_opts.permission_flags},
|
||||||
|
@ -3816,6 +3833,7 @@ CNode::CNode(NodeId idIn,
|
||||||
m_inbound_onion{inbound_onion},
|
m_inbound_onion{inbound_onion},
|
||||||
m_prefer_evict{node_opts.prefer_evict},
|
m_prefer_evict{node_opts.prefer_evict},
|
||||||
nKeyedNetGroup{nKeyedNetGroupIn},
|
nKeyedNetGroup{nKeyedNetGroupIn},
|
||||||
|
m_network_key{network_key},
|
||||||
m_conn_type{conn_type_in},
|
m_conn_type{conn_type_in},
|
||||||
id{idIn},
|
id{idIn},
|
||||||
nLocalHostNonce{nLocalHostNonceIn},
|
nLocalHostNonce{nLocalHostNonceIn},
|
||||||
|
|
88
src/net.h
88
src/net.h
|
@ -738,6 +738,10 @@ public:
|
||||||
std::atomic_bool fPauseRecv{false};
|
std::atomic_bool fPauseRecv{false};
|
||||||
std::atomic_bool fPauseSend{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;
|
const ConnectionType m_conn_type;
|
||||||
|
|
||||||
/** Move all messages from the received queue to the processing queue. */
|
/** Move all messages from the received queue to the processing queue. */
|
||||||
|
@ -889,6 +893,7 @@ public:
|
||||||
const std::string& addrNameIn,
|
const std::string& addrNameIn,
|
||||||
ConnectionType conn_type_in,
|
ConnectionType conn_type_in,
|
||||||
bool inbound_onion,
|
bool inbound_onion,
|
||||||
|
uint64_t network_key,
|
||||||
CNodeOptions&& node_opts = {});
|
CNodeOptions&& node_opts = {});
|
||||||
CNode(const CNode&) = delete;
|
CNode(const CNode&) = delete;
|
||||||
CNode& operator=(const CNode&) = delete;
|
CNode& operator=(const CNode&) = delete;
|
||||||
|
@ -1119,8 +1124,13 @@ public:
|
||||||
whitelist_relay = connOptions.whitelist_relay;
|
whitelist_relay = connOptions.whitelist_relay;
|
||||||
}
|
}
|
||||||
|
|
||||||
CConnman(uint64_t seed0, uint64_t seed1, AddrMan& addrman, const NetGroupManager& netgroupman,
|
CConnman(uint64_t seed0,
|
||||||
const CChainParams& params, bool network_active = true);
|
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();
|
~CConnman();
|
||||||
|
|
||||||
|
@ -1138,7 +1148,28 @@ public:
|
||||||
bool GetNetworkActive() const { return fNetworkActive; };
|
bool GetNetworkActive() const { return fNetworkActive; };
|
||||||
bool GetUseAddrmanOutgoing() const { return m_use_addrman_outgoing; };
|
bool GetUseAddrmanOutgoing() const { return m_use_addrman_outgoing; };
|
||||||
void SetNetworkActive(bool active);
|
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);
|
bool CheckIncomingNonce(uint64_t nonce);
|
||||||
void ASMapHealthCheck();
|
void ASMapHealthCheck();
|
||||||
|
|
||||||
|
@ -1365,18 +1396,49 @@ private:
|
||||||
|
|
||||||
uint64_t CalculateKeyedNetGroup(const CNetAddr& ad) const;
|
uint64_t CalculateKeyedNetGroup(const CNetAddr& ad) const;
|
||||||
|
|
||||||
CNode* FindNode(const CNetAddr& ip);
|
/**
|
||||||
CNode* FindNode(const std::string& addrName);
|
* Determine whether we're already connected to a given "host:port".
|
||||||
CNode* FindNode(const CService& addr);
|
* 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
|
* Determine whether we're already connected to a given address:port.
|
||||||
* avoid initiating duplicate connections.
|
* 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();
|
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 AddWhitelistPermissionFlags(NetPermissionFlags& flags, std::optional<CNetAddr> addr, const std::vector<NetWhitelistPermissions>& ranges) const;
|
||||||
|
|
||||||
void DeleteNode(CNode* pnode);
|
void DeleteNode(CNode* pnode);
|
||||||
|
@ -1555,11 +1617,9 @@ private:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is signaled when network activity should cease.
|
* This is signaled when network activity should cease.
|
||||||
* A pointer to it is saved in `m_i2p_sam_session`, so make sure that
|
* A copy of this is saved in `m_i2p_sam_session`.
|
||||||
* the lifetime of `interruptNet` is not shorter than
|
|
||||||
* the lifetime of `m_i2p_sam_session`.
|
|
||||||
*/
|
*/
|
||||||
CThreadInterrupt interruptNet;
|
const std::shared_ptr<CThreadInterrupt> m_interrupt_net;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* I2P SAM session.
|
* I2P SAM session.
|
||||||
|
|
|
@ -167,7 +167,7 @@ static constexpr auto INBOUND_INVENTORY_BROADCAST_INTERVAL{5s};
|
||||||
static constexpr auto OUTBOUND_INVENTORY_BROADCAST_INTERVAL{2s};
|
static constexpr auto OUTBOUND_INVENTORY_BROADCAST_INTERVAL{2s};
|
||||||
/** Maximum rate of inventory items to send per second.
|
/** Maximum rate of inventory items to send per second.
|
||||||
* Limits the impact of low-fee transaction floods. */
|
* Limits the impact of low-fee transaction floods. */
|
||||||
static constexpr unsigned int INVENTORY_BROADCAST_PER_SECOND = 7;
|
static constexpr unsigned int INVENTORY_BROADCAST_PER_SECOND{14};
|
||||||
/** Target number of tx inventory items to send per transmission. */
|
/** Target number of tx inventory items to send per transmission. */
|
||||||
static constexpr unsigned int INVENTORY_BROADCAST_TARGET = INVENTORY_BROADCAST_PER_SECOND * count_seconds(INBOUND_INVENTORY_BROADCAST_INTERVAL);
|
static constexpr unsigned int INVENTORY_BROADCAST_TARGET = INVENTORY_BROADCAST_PER_SECOND * count_seconds(INBOUND_INVENTORY_BROADCAST_INTERVAL);
|
||||||
/** Maximum number of inventory items to send per transmission. */
|
/** Maximum number of inventory items to send per transmission. */
|
||||||
|
@ -312,7 +312,7 @@ struct Peer {
|
||||||
std::chrono::microseconds m_next_inv_send_time GUARDED_BY(m_tx_inventory_mutex){0};
|
std::chrono::microseconds m_next_inv_send_time GUARDED_BY(m_tx_inventory_mutex){0};
|
||||||
/** The mempool sequence num at which we sent the last `inv` message to this peer.
|
/** The mempool sequence num at which we sent the last `inv` message to this peer.
|
||||||
* Can relay txs with lower sequence numbers than this (see CTxMempool::info_for_relay). */
|
* Can relay txs with lower sequence numbers than this (see CTxMempool::info_for_relay). */
|
||||||
uint64_t m_last_inv_sequence GUARDED_BY(NetEventsInterface::g_msgproc_mutex){1};
|
uint64_t m_last_inv_sequence GUARDED_BY(m_tx_inventory_mutex){1};
|
||||||
|
|
||||||
/** Minimum fee rate with which to filter transaction announcements to this node. See BIP133. */
|
/** Minimum fee rate with which to filter transaction announcements to this node. See BIP133. */
|
||||||
std::atomic<CAmount> m_fee_filter_received{0};
|
std::atomic<CAmount> m_fee_filter_received{0};
|
||||||
|
@ -807,7 +807,7 @@ private:
|
||||||
|
|
||||||
uint32_t GetFetchFlags(const Peer& peer) const;
|
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. */
|
/** Number of nodes with fSyncStarted. */
|
||||||
int nSyncStarted GUARDED_BY(cs_main) = 0;
|
int nSyncStarted GUARDED_BY(cs_main) = 0;
|
||||||
|
@ -837,12 +837,14 @@ private:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For sending `inv`s to inbound peers, we use a single (exponentially
|
* 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
|
* peer, a spy node could make multiple inbound connections to us to
|
||||||
* accurately determine when we received the transaction (and potentially
|
* accurately determine when we received a transaction (and potentially
|
||||||
* determine the transaction's origin). */
|
* 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::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
|
// All of the following cache a recent block, and are protected by m_most_recent_block_mutex
|
||||||
|
@ -942,7 +944,7 @@ private:
|
||||||
|
|
||||||
/** Determine whether or not a peer can request a transaction, and return it (or nullptr if not found or not allowed). */
|
/** Determine whether or not a peer can request a transaction, and return it (or nullptr if not found or not allowed). */
|
||||||
CTransactionRef FindTxForGetData(const Peer::TxRelay& tx_relay, const GenTxid& gtxid)
|
CTransactionRef FindTxForGetData(const Peer::TxRelay& tx_relay, const GenTxid& gtxid)
|
||||||
EXCLUSIVE_LOCKS_REQUIRED(!m_most_recent_block_mutex, NetEventsInterface::g_msgproc_mutex);
|
EXCLUSIVE_LOCKS_REQUIRED(!m_most_recent_block_mutex, !tx_relay.m_tx_inventory_mutex);
|
||||||
|
|
||||||
void ProcessGetData(CNode& pfrom, Peer& peer, const std::atomic<bool>& interruptMsgProc)
|
void ProcessGetData(CNode& pfrom, Peer& peer, const std::atomic<bool>& interruptMsgProc)
|
||||||
EXCLUSIVE_LOCKS_REQUIRED(!m_most_recent_block_mutex, peer.m_getdata_requests_mutex, NetEventsInterface::g_msgproc_mutex)
|
EXCLUSIVE_LOCKS_REQUIRED(!m_most_recent_block_mutex, peer.m_getdata_requests_mutex, NetEventsInterface::g_msgproc_mutex)
|
||||||
|
@ -1143,15 +1145,15 @@ static bool CanServeWitnesses(const Peer& peer)
|
||||||
}
|
}
|
||||||
|
|
||||||
std::chrono::microseconds PeerManagerImpl::NextInvToInbounds(std::chrono::microseconds now,
|
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) {
|
auto [it, inserted] = m_next_inv_to_inbounds_per_network_key.try_emplace(network_key, 0us);
|
||||||
// If this function were called from multiple threads simultaneously
|
auto& timer{it->second};
|
||||||
// it would possible that both update the next send variable, and return a different result to their caller.
|
if (timer < now) {
|
||||||
// This is not possible in practice as only the net processing thread invokes this function.
|
timer = now + m_rng.rand_exp_duration(average_interval);
|
||||||
m_next_inv_to_inbounds = now + m_rng.rand_exp_duration(average_interval);
|
|
||||||
}
|
}
|
||||||
return m_next_inv_to_inbounds;
|
return timer;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PeerManagerImpl::IsBlockRequested(const uint256& hash)
|
bool PeerManagerImpl::IsBlockRequested(const uint256& hash)
|
||||||
|
@ -1728,9 +1730,13 @@ bool PeerManagerImpl::GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) c
|
||||||
if (auto tx_relay = peer->GetTxRelay(); tx_relay != nullptr) {
|
if (auto tx_relay = peer->GetTxRelay(); tx_relay != nullptr) {
|
||||||
stats.m_relay_txs = WITH_LOCK(tx_relay->m_bloom_filter_mutex, return tx_relay->m_relay_txs);
|
stats.m_relay_txs = WITH_LOCK(tx_relay->m_bloom_filter_mutex, return tx_relay->m_relay_txs);
|
||||||
stats.m_fee_filter_received = tx_relay->m_fee_filter_received.load();
|
stats.m_fee_filter_received = tx_relay->m_fee_filter_received.load();
|
||||||
|
LOCK(tx_relay->m_tx_inventory_mutex);
|
||||||
|
stats.m_last_inv_seq = tx_relay->m_last_inv_sequence;
|
||||||
|
stats.m_inv_to_send = tx_relay->m_tx_inventory_to_send.size();
|
||||||
} else {
|
} else {
|
||||||
stats.m_relay_txs = false;
|
stats.m_relay_txs = false;
|
||||||
stats.m_fee_filter_received = 0;
|
stats.m_fee_filter_received = 0;
|
||||||
|
stats.m_inv_to_send = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
stats.m_ping_wait = ping_wait;
|
stats.m_ping_wait = ping_wait;
|
||||||
|
@ -2362,8 +2368,8 @@ CTransactionRef PeerManagerImpl::FindTxForGetData(const Peer::TxRelay& tx_relay,
|
||||||
{
|
{
|
||||||
// If a tx was in the mempool prior to the last INV for this peer, permit the request.
|
// If a tx was in the mempool prior to the last INV for this peer, permit the request.
|
||||||
auto txinfo{std::visit(
|
auto txinfo{std::visit(
|
||||||
[&](const auto& id) EXCLUSIVE_LOCKS_REQUIRED(NetEventsInterface::g_msgproc_mutex) {
|
[&](const auto& id) {
|
||||||
return m_mempool.info_for_relay(id, tx_relay.m_last_inv_sequence);
|
return m_mempool.info_for_relay(id, WITH_LOCK(tx_relay.m_tx_inventory_mutex, return tx_relay.m_last_inv_sequence));
|
||||||
},
|
},
|
||||||
gtxid)};
|
gtxid)};
|
||||||
if (txinfo.tx) {
|
if (txinfo.tx) {
|
||||||
|
@ -5711,7 +5717,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
|
||||||
if (tx_relay->m_next_inv_send_time < current_time) {
|
if (tx_relay->m_next_inv_send_time < current_time) {
|
||||||
fSendTrickle = true;
|
fSendTrickle = true;
|
||||||
if (pto->IsInboundConn()) {
|
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 {
|
} else {
|
||||||
tx_relay->m_next_inv_send_time = current_time + m_rng.rand_exp_duration(OUTBOUND_INVENTORY_BROADCAST_INTERVAL);
|
tx_relay->m_next_inv_send_time = current_time + m_rng.rand_exp_duration(OUTBOUND_INVENTORY_BROADCAST_INTERVAL);
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,8 @@ struct CNodeStateStats {
|
||||||
std::chrono::microseconds m_ping_wait;
|
std::chrono::microseconds m_ping_wait;
|
||||||
std::vector<int> vHeightInFlight;
|
std::vector<int> vHeightInFlight;
|
||||||
bool m_relay_txs;
|
bool m_relay_txs;
|
||||||
|
int m_inv_to_send = 0;
|
||||||
|
uint64_t m_last_inv_seq{0};
|
||||||
CAmount m_fee_filter_received;
|
CAmount m_fee_filter_received;
|
||||||
uint64_t m_addr_processed = 0;
|
uint64_t m_addr_processed = 0;
|
||||||
uint64_t m_addr_rate_limited = 0;
|
uint64_t m_addr_rate_limited = 0;
|
||||||
|
|
|
@ -397,8 +397,8 @@ void BlockAssembler::addPackageTxs(int& nPackagesSelected, int& nDescendantsUpda
|
||||||
|
|
||||||
++nConsecutiveFailed;
|
++nConsecutiveFailed;
|
||||||
|
|
||||||
if (nConsecutiveFailed > MAX_CONSECUTIVE_FAILURES && nBlockWeight >
|
if (nConsecutiveFailed > MAX_CONSECUTIVE_FAILURES && nBlockWeight +
|
||||||
m_options.nBlockMaxWeight - BLOCK_FULL_ENOUGH_WEIGHT_DELTA) {
|
BLOCK_FULL_ENOUGH_WEIGHT_DELTA > m_options.nBlockMaxWeight) {
|
||||||
// Give up if we're close to full and haven't succeeded in a while
|
// Give up if we're close to full and haven't succeeded in a while
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,7 +98,7 @@ static constexpr unsigned int MAX_DUST_OUTPUTS_PER_TX{1};
|
||||||
* Note that this does not affect consensus validity; see GetBlockScriptFlags()
|
* Note that this does not affect consensus validity; see GetBlockScriptFlags()
|
||||||
* for that.
|
* 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_DERSIG |
|
||||||
SCRIPT_VERIFY_NULLDUMMY |
|
SCRIPT_VERIFY_NULLDUMMY |
|
||||||
SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY |
|
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
|
* the additional (non-mandatory) rules here, to improve forwards and
|
||||||
* backwards compatibility.
|
* 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_STRICTENC |
|
||||||
SCRIPT_VERIFY_MINIMALDATA |
|
SCRIPT_VERIFY_MINIMALDATA |
|
||||||
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS |
|
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};
|
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE};
|
||||||
|
|
||||||
/** For convenience, standard but not mandatory verify flags. */
|
/** 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. */
|
/** 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};
|
static constexpr unsigned int STANDARD_LOCKTIME_VERIFY_FLAGS{LOCKTIME_VERIFY_SEQUENCE};
|
||||||
|
|
|
@ -166,7 +166,7 @@ UniValue blockheaderToJSON(const CBlockIndex& tip, const CBlockIndex& blockindex
|
||||||
result.pushKV("mediantime", blockindex.GetMedianTimePast());
|
result.pushKV("mediantime", blockindex.GetMedianTimePast());
|
||||||
result.pushKV("nonce", blockindex.nNonce);
|
result.pushKV("nonce", blockindex.nNonce);
|
||||||
result.pushKV("bits", strprintf("%08x", blockindex.nBits));
|
result.pushKV("bits", strprintf("%08x", blockindex.nBits));
|
||||||
result.pushKV("target", GetTarget(tip, pow_limit).GetHex());
|
result.pushKV("target", GetTarget(blockindex, pow_limit).GetHex());
|
||||||
result.pushKV("difficulty", GetDifficulty(blockindex));
|
result.pushKV("difficulty", GetDifficulty(blockindex));
|
||||||
result.pushKV("chainwork", blockindex.nChainWork.GetHex());
|
result.pushKV("chainwork", blockindex.nChainWork.GetHex());
|
||||||
result.pushKV("nTx", blockindex.nTx);
|
result.pushKV("nTx", blockindex.nTx);
|
||||||
|
@ -1469,6 +1469,9 @@ RPCHelpMan getdeploymentinfo()
|
||||||
RPCResult::Type::OBJ, "", "", {
|
RPCResult::Type::OBJ, "", "", {
|
||||||
{RPCResult::Type::STR, "hash", "requested block hash (or tip)"},
|
{RPCResult::Type::STR, "hash", "requested block hash (or tip)"},
|
||||||
{RPCResult::Type::NUM, "height", "requested block height (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_DYN, "deployments", "", {
|
||||||
{RPCResult::Type::OBJ, "xxxx", "name of the deployment", RPCHelpForDeployment}
|
{RPCResult::Type::OBJ, "xxxx", "name of the deployment", RPCHelpForDeployment}
|
||||||
}},
|
}},
|
||||||
|
@ -1495,6 +1498,12 @@ RPCHelpMan getdeploymentinfo()
|
||||||
UniValue deploymentinfo(UniValue::VOBJ);
|
UniValue deploymentinfo(UniValue::VOBJ);
|
||||||
deploymentinfo.pushKV("hash", blockindex->GetBlockHash().ToString());
|
deploymentinfo.pushKV("hash", blockindex->GetBlockHash().ToString());
|
||||||
deploymentinfo.pushKV("height", blockindex->nHeight);
|
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));
|
deploymentinfo.pushKV("deployments", DeploymentInfo(blockindex, chainman));
|
||||||
return deploymentinfo;
|
return deploymentinfo;
|
||||||
},
|
},
|
||||||
|
|
|
@ -18,6 +18,7 @@ public:
|
||||||
std::string methodName; //!< method whose params want conversion
|
std::string methodName; //!< method whose params want conversion
|
||||||
int paramIdx; //!< 0-based idx of param to convert
|
int paramIdx; //!< 0-based idx of param to convert
|
||||||
std::string paramName; //!< parameter name
|
std::string paramName; //!< parameter name
|
||||||
|
bool also_string{false}; //!< The parameter is also a string
|
||||||
};
|
};
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
|
@ -188,10 +189,10 @@ static const CRPCConvertParam vRPCConvertParams[] =
|
||||||
{ "gettxout", 1, "n" },
|
{ "gettxout", 1, "n" },
|
||||||
{ "gettxout", 2, "include_mempool" },
|
{ "gettxout", 2, "include_mempool" },
|
||||||
{ "gettxoutproof", 0, "txids" },
|
{ "gettxoutproof", 0, "txids" },
|
||||||
{ "gettxoutsetinfo", 1, "hash_or_height" },
|
{ "gettxoutsetinfo", 1, "hash_or_height", /*also_string=*/true },
|
||||||
{ "gettxoutsetinfo", 2, "use_index"},
|
{ "gettxoutsetinfo", 2, "use_index"},
|
||||||
{ "dumptxoutset", 2, "options" },
|
{ "dumptxoutset", 2, "options" },
|
||||||
{ "dumptxoutset", 2, "rollback" },
|
{ "dumptxoutset", 2, "rollback", /*also_string=*/true },
|
||||||
{ "lockunspent", 0, "unlock" },
|
{ "lockunspent", 0, "unlock" },
|
||||||
{ "lockunspent", 1, "transactions" },
|
{ "lockunspent", 1, "transactions" },
|
||||||
{ "lockunspent", 2, "persistent" },
|
{ "lockunspent", 2, "persistent" },
|
||||||
|
@ -246,7 +247,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
|
||||||
{ "listdescriptors", 0, "private" },
|
{ "listdescriptors", 0, "private" },
|
||||||
{ "verifychain", 0, "checklevel" },
|
{ "verifychain", 0, "checklevel" },
|
||||||
{ "verifychain", 1, "nblocks" },
|
{ "verifychain", 1, "nblocks" },
|
||||||
{ "getblockstats", 0, "hash_or_height" },
|
{ "getblockstats", 0, "hash_or_height", /*also_string=*/true },
|
||||||
{ "getblockstats", 1, "stats" },
|
{ "getblockstats", 1, "stats" },
|
||||||
{ "pruneblockchain", 0, "height" },
|
{ "pruneblockchain", 0, "height" },
|
||||||
{ "keypoolrefill", 0, "newsize" },
|
{ "keypoolrefill", 0, "newsize" },
|
||||||
|
@ -318,18 +319,21 @@ static const CRPCConvertParam vRPCConvertParams[] =
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
/** Parse string to UniValue or throw runtime_error if string contains invalid JSON */
|
/** Parse string to UniValue or throw runtime_error if string contains invalid JSON */
|
||||||
static UniValue Parse(std::string_view raw)
|
static UniValue Parse(std::string_view raw, bool also_string)
|
||||||
{
|
{
|
||||||
UniValue parsed;
|
UniValue parsed;
|
||||||
if (!parsed.read(raw)) throw std::runtime_error(tfm::format("Error parsing JSON: %s", raw));
|
if (!parsed.read(raw)) {
|
||||||
|
if (!also_string) throw std::runtime_error(tfm::format("Error parsing JSON: %s", raw));
|
||||||
|
return raw;
|
||||||
|
}
|
||||||
return parsed;
|
return parsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
class CRPCConvertTable
|
class CRPCConvertTable
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
std::set<std::pair<std::string, int>> members;
|
std::map<std::pair<std::string, int>, bool> members;
|
||||||
std::set<std::pair<std::string, std::string>> membersByName;
|
std::map<std::pair<std::string, std::string>, bool> membersByName;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CRPCConvertTable();
|
CRPCConvertTable();
|
||||||
|
@ -337,21 +341,29 @@ public:
|
||||||
/** Return arg_value as UniValue, and first parse it if it is a non-string parameter */
|
/** Return arg_value as UniValue, and first parse it if it is a non-string parameter */
|
||||||
UniValue ArgToUniValue(std::string_view arg_value, const std::string& method, int param_idx)
|
UniValue ArgToUniValue(std::string_view arg_value, const std::string& method, int param_idx)
|
||||||
{
|
{
|
||||||
return members.count({method, param_idx}) > 0 ? Parse(arg_value) : arg_value;
|
const auto& it = members.find({method, param_idx});
|
||||||
|
if (it != members.end()) {
|
||||||
|
return Parse(arg_value, it->second);
|
||||||
|
}
|
||||||
|
return arg_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Return arg_value as UniValue, and first parse it if it is a non-string parameter */
|
/** Return arg_value as UniValue, and first parse it if it is a non-string parameter */
|
||||||
UniValue ArgToUniValue(std::string_view arg_value, const std::string& method, const std::string& param_name)
|
UniValue ArgToUniValue(std::string_view arg_value, const std::string& method, const std::string& param_name)
|
||||||
{
|
{
|
||||||
return membersByName.count({method, param_name}) > 0 ? Parse(arg_value) : arg_value;
|
const auto& it = membersByName.find({method, param_name});
|
||||||
|
if (it != membersByName.end()) {
|
||||||
|
return Parse(arg_value, it->second);
|
||||||
|
}
|
||||||
|
return arg_value;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
CRPCConvertTable::CRPCConvertTable()
|
CRPCConvertTable::CRPCConvertTable()
|
||||||
{
|
{
|
||||||
for (const auto& cp : vRPCConvertParams) {
|
for (const auto& cp : vRPCConvertParams) {
|
||||||
members.emplace(cp.methodName, cp.paramIdx);
|
members.emplace(std::make_pair(cp.methodName, cp.paramIdx), cp.also_string);
|
||||||
membersByName.emplace(cp.methodName, cp.paramName);
|
membersByName.emplace(std::make_pair(cp.methodName, cp.paramName), cp.also_string);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -955,7 +955,7 @@ static RPCHelpMan submitpackage()
|
||||||
RPCResult::Type::OBJ, "", "",
|
RPCResult::Type::OBJ, "", "",
|
||||||
{
|
{
|
||||||
{RPCResult::Type::STR, "package_msg", "The transaction package result message. \"success\" indicates all transactions were accepted into or are already in the mempool."},
|
{RPCResult::Type::STR, "package_msg", "The transaction package result message. \"success\" indicates all transactions were accepted into or are already in the mempool."},
|
||||||
{RPCResult::Type::OBJ_DYN, "tx-results", "transaction results keyed by wtxid",
|
{RPCResult::Type::OBJ_DYN, "tx-results", "The transaction results keyed by wtxid. An entry is returned for every submitted wtxid.",
|
||||||
{
|
{
|
||||||
{RPCResult::Type::OBJ, "wtxid", "transaction wtxid", {
|
{RPCResult::Type::OBJ, "wtxid", "transaction wtxid", {
|
||||||
{RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"},
|
{RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"},
|
||||||
|
@ -968,7 +968,7 @@ static RPCHelpMan submitpackage()
|
||||||
{{RPCResult::Type::STR_HEX, "", "transaction wtxid in hex"},
|
{{RPCResult::Type::STR_HEX, "", "transaction wtxid in hex"},
|
||||||
}},
|
}},
|
||||||
}},
|
}},
|
||||||
{RPCResult::Type::STR, "error", /*optional=*/true, "The transaction error string, if it was rejected by the mempool"},
|
{RPCResult::Type::STR, "error", /*optional=*/true, "Error string if rejected from mempool, or \"package-not-validated\" when the package aborts before any per-tx processing."},
|
||||||
}}
|
}}
|
||||||
}},
|
}},
|
||||||
{RPCResult::Type::ARR, "replaced-transactions", /*optional=*/true, "List of txids of replaced transactions",
|
{RPCResult::Type::ARR, "replaced-transactions", /*optional=*/true, "List of txids of replaced transactions",
|
||||||
|
@ -1082,10 +1082,15 @@ static RPCHelpMan submitpackage()
|
||||||
for (const auto& tx : txns) {
|
for (const auto& tx : txns) {
|
||||||
UniValue result_inner{UniValue::VOBJ};
|
UniValue result_inner{UniValue::VOBJ};
|
||||||
result_inner.pushKV("txid", tx->GetHash().GetHex());
|
result_inner.pushKV("txid", tx->GetHash().GetHex());
|
||||||
|
const auto wtxid_hex = tx->GetWitnessHash().GetHex();
|
||||||
auto it = package_result.m_tx_results.find(tx->GetWitnessHash());
|
auto it = package_result.m_tx_results.find(tx->GetWitnessHash());
|
||||||
if (it == package_result.m_tx_results.end()) {
|
if (it == package_result.m_tx_results.end()) {
|
||||||
// No results, report error and continue
|
// No per-tx result for this wtxid
|
||||||
result_inner.pushKV("error", "unevaluated");
|
// Current invariant: per-tx results are all-or-none (every member or empty on package abort).
|
||||||
|
// If any exist yet this one is missing, it's an unexpected partial map.
|
||||||
|
CHECK_NONFATAL(package_result.m_tx_results.empty());
|
||||||
|
result_inner.pushKV("error", "package-not-validated");
|
||||||
|
tx_result_map.pushKV(wtxid_hex, std::move(result_inner));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const auto& tx_result = it->second;
|
const auto& tx_result = it->second;
|
||||||
|
@ -1118,7 +1123,7 @@ static RPCHelpMan submitpackage()
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
tx_result_map.pushKV(tx->GetWitnessHash().GetHex(), std::move(result_inner));
|
tx_result_map.pushKV(wtxid_hex, std::move(result_inner));
|
||||||
}
|
}
|
||||||
rpc_result.pushKV("tx-results", std::move(tx_result_map));
|
rpc_result.pushKV("tx-results", std::move(tx_result_map));
|
||||||
UniValue replaced_list(UniValue::VARR);
|
UniValue replaced_list(UniValue::VARR);
|
||||||
|
|
|
@ -130,7 +130,7 @@ static RPCHelpMan getpeerinfo()
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
{RPCResult::Type::NUM, "id", "Peer index"},
|
{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, "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, "addrlocal", /*optional=*/true, "(ip:port) Local address as reported by the peer"},
|
||||||
{RPCResult::Type::STR, "network", "Network (" + Join(GetNetworkNames(/*append_unroutable=*/true), ", ") + ")"},
|
{RPCResult::Type::STR, "network", "Network (" + Join(GetNetworkNames(/*append_unroutable=*/true), ", ") + ")"},
|
||||||
|
@ -142,6 +142,8 @@ static RPCHelpMan getpeerinfo()
|
||||||
{RPCResult::Type::STR, "SERVICE_NAME", "the service name if it is recognised"}
|
{RPCResult::Type::STR, "SERVICE_NAME", "the service name if it is recognised"}
|
||||||
}},
|
}},
|
||||||
{RPCResult::Type::BOOL, "relaytxes", "Whether we relay transactions to this peer"},
|
{RPCResult::Type::BOOL, "relaytxes", "Whether we relay transactions to this peer"},
|
||||||
|
{RPCResult::Type::NUM, "last_inv_sequence", "Mempool sequence number of this peer's last INV"},
|
||||||
|
{RPCResult::Type::NUM, "inv_to_send", "How many txs we have queued to announce to this peer"},
|
||||||
{RPCResult::Type::NUM_TIME, "lastsend", "The " + UNIX_EPOCH_TIME + " of the last send"},
|
{RPCResult::Type::NUM_TIME, "lastsend", "The " + UNIX_EPOCH_TIME + " of the last send"},
|
||||||
{RPCResult::Type::NUM_TIME, "lastrecv", "The " + UNIX_EPOCH_TIME + " of the last receive"},
|
{RPCResult::Type::NUM_TIME, "lastrecv", "The " + UNIX_EPOCH_TIME + " of the last receive"},
|
||||||
{RPCResult::Type::NUM_TIME, "last_transaction", "The " + UNIX_EPOCH_TIME + " of the last valid transaction received from this peer"},
|
{RPCResult::Type::NUM_TIME, "last_transaction", "The " + UNIX_EPOCH_TIME + " of the last valid transaction received from this peer"},
|
||||||
|
@ -238,6 +240,8 @@ static RPCHelpMan getpeerinfo()
|
||||||
obj.pushKV("services", strprintf("%016x", services));
|
obj.pushKV("services", strprintf("%016x", services));
|
||||||
obj.pushKV("servicesnames", GetServicesNames(services));
|
obj.pushKV("servicesnames", GetServicesNames(services));
|
||||||
obj.pushKV("relaytxes", statestats.m_relay_txs);
|
obj.pushKV("relaytxes", statestats.m_relay_txs);
|
||||||
|
obj.pushKV("last_inv_sequence", statestats.m_last_inv_seq);
|
||||||
|
obj.pushKV("inv_to_send", statestats.m_inv_to_send);
|
||||||
obj.pushKV("lastsend", count_seconds(stats.m_last_send));
|
obj.pushKV("lastsend", count_seconds(stats.m_last_send));
|
||||||
obj.pushKV("lastrecv", count_seconds(stats.m_last_recv));
|
obj.pushKV("lastrecv", count_seconds(stats.m_last_recv));
|
||||||
obj.pushKV("last_transaction", count_seconds(stats.m_last_tx_time));
|
obj.pushKV("last_transaction", count_seconds(stats.m_last_tx_time));
|
||||||
|
@ -318,7 +322,7 @@ static RPCHelpMan addnode()
|
||||||
strprintf("Addnode connections are limited to %u at a time", MAX_ADDNODE_CONNECTIONS) +
|
strprintf("Addnode connections are limited to %u at a time", MAX_ADDNODE_CONNECTIONS) +
|
||||||
" and are counted separately from the -maxconnections limit.\n",
|
" 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"},
|
{"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)"},
|
{"v2transport", RPCArg::Type::BOOL, RPCArg::DefaultHint{"set by -v2transport"}, "Attempt to connect using BIP324 v2 transport protocol (ignored for 'remove' command)"},
|
||||||
},
|
},
|
||||||
|
@ -1000,26 +1004,28 @@ static RPCHelpMan addpeeraddress()
|
||||||
|
|
||||||
UniValue obj(UniValue::VOBJ);
|
UniValue obj(UniValue::VOBJ);
|
||||||
std::optional<CNetAddr> net_addr{LookupHost(addr_string, false)};
|
std::optional<CNetAddr> net_addr{LookupHost(addr_string, false)};
|
||||||
|
if (!net_addr.has_value()) {
|
||||||
|
throw JSONRPCError(RPC_CLIENT_INVALID_IP_OR_SUBNET, "Invalid IP address");
|
||||||
|
}
|
||||||
|
|
||||||
bool success{false};
|
bool success{false};
|
||||||
|
|
||||||
if (net_addr.has_value()) {
|
CService service{net_addr.value(), port};
|
||||||
CService service{net_addr.value(), port};
|
CAddress address{MaybeFlipIPv6toCJDNS(service), ServiceFlags{NODE_NETWORK | NODE_WITNESS}};
|
||||||
CAddress address{MaybeFlipIPv6toCJDNS(service), ServiceFlags{NODE_NETWORK | NODE_WITNESS}};
|
address.nTime = Now<NodeSeconds>();
|
||||||
address.nTime = Now<NodeSeconds>();
|
// The source address is set equal to the address. This is equivalent to the peer
|
||||||
// The source address is set equal to the address. This is equivalent to the peer
|
// announcing itself.
|
||||||
// announcing itself.
|
if (addrman.Add({address}, address)) {
|
||||||
if (addrman.Add({address}, address)) {
|
success = true;
|
||||||
success = true;
|
if (tried) {
|
||||||
if (tried) {
|
// Attempt to move the address to the tried addresses table.
|
||||||
// Attempt to move the address to the tried addresses table.
|
if (!addrman.Good(address)) {
|
||||||
if (!addrman.Good(address)) {
|
success = false;
|
||||||
success = false;
|
obj.pushKV("error", "failed-adding-to-tried");
|
||||||
obj.pushKV("error", "failed-adding-to-tried");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
obj.pushKV("error", "failed-adding-to-new");
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
obj.pushKV("error", "failed-adding-to-new");
|
||||||
}
|
}
|
||||||
|
|
||||||
obj.pushKV("success", success);
|
obj.pushKV("success", success);
|
||||||
|
|
|
@ -1608,7 +1608,7 @@ static RPCHelpMan finalizepsbt()
|
||||||
return RPCHelpMan{"finalizepsbt",
|
return RPCHelpMan{"finalizepsbt",
|
||||||
"Finalize the inputs of a PSBT. If the transaction is fully signed, it will produce a\n"
|
"Finalize the inputs of a PSBT. If the transaction is fully signed, it will produce a\n"
|
||||||
"network serialized transaction which can be broadcast with sendrawtransaction. Otherwise a PSBT will be\n"
|
"network serialized transaction which can be broadcast with sendrawtransaction. Otherwise a PSBT will be\n"
|
||||||
"created which has the final_scriptSig and final_scriptWitness fields filled for inputs that are complete.\n"
|
"created which has the final_scriptSig and final_scriptwitness fields filled for inputs that are complete.\n"
|
||||||
"Implements the Finalizer and Extractor roles.\n",
|
"Implements the Finalizer and Extractor roles.\n",
|
||||||
{
|
{
|
||||||
{"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "A base64 string of a PSBT"},
|
{"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "A base64 string of a PSBT"},
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <crypto/sha256.h>
|
#include <crypto/sha256.h>
|
||||||
#include <pubkey.h>
|
#include <pubkey.h>
|
||||||
#include <script/script.h>
|
#include <script/script.h>
|
||||||
|
#include <tinyformat.h>
|
||||||
#include <uint256.h>
|
#include <uint256.h>
|
||||||
|
|
||||||
typedef std::vector<unsigned char> valtype;
|
typedef std::vector<unsigned char> valtype;
|
||||||
|
@ -197,7 +198,7 @@ bool static IsDefinedHashtypeSignature(const valtype &vchSig) {
|
||||||
return true;
|
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
|
// Empty signature. Not strictly DER encoded, but allowed to provide a
|
||||||
// compact way to provide an invalid signature for use with CHECK(MULTI)SIG
|
// compact way to provide an invalid signature for use with CHECK(MULTI)SIG
|
||||||
if (vchSig.size() == 0) {
|
if (vchSig.size() == 0) {
|
||||||
|
@ -214,7 +215,7 @@ bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned i
|
||||||
return true;
|
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)) {
|
if ((flags & SCRIPT_VERIFY_STRICTENC) != 0 && !IsCompressedOrUncompressedPubKey(vchPubKey)) {
|
||||||
return set_error(serror, SCRIPT_ERR_PUBKEYTYPE);
|
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);
|
assert(sigversion == SigVersion::BASE || sigversion == SigVersion::WITNESS_V0);
|
||||||
|
|
||||||
|
@ -343,7 +344,7 @@ static bool EvalChecksigPreTapscript(const valtype& vchSig, const valtype& vchPu
|
||||||
return true;
|
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);
|
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
|
* A return value of false means the script fails entirely. When true is returned, the
|
||||||
* success variable indicates whether the signature check itself succeeded.
|
* 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) {
|
switch (sigversion) {
|
||||||
case SigVersion::BASE:
|
case SigVersion::BASE:
|
||||||
|
@ -403,7 +404,7 @@ static bool EvalChecksig(const valtype& sig, const valtype& pubkey, CScript::con
|
||||||
assert(false);
|
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 bnZero(0);
|
||||||
static const CScriptNum bnOne(1);
|
static const CScriptNum bnOne(1);
|
||||||
|
@ -1233,7 +1234,7 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
|
||||||
return set_success(serror);
|
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;
|
ScriptExecutionData execdata;
|
||||||
return EvalScript(stack, script, flags, checker, sigversion, execdata, serror);
|
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<CTransaction>;
|
||||||
template class GenericTransactionSignatureChecker<CMutableTransaction>;
|
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()};
|
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);
|
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)
|
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};
|
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.
|
// 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;
|
static const CScriptWitness emptyWitness;
|
||||||
if (witness == nullptr) {
|
if (witness == nullptr) {
|
||||||
|
@ -2131,7 +2132,7 @@ size_t static WitnessSigOps(int witversion, const std::vector<unsigned char>& wi
|
||||||
return 0;
|
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;
|
static const CScriptWitness witnessEmpty;
|
||||||
|
|
||||||
|
@ -2161,3 +2162,48 @@ size_t CountWitnessSigOps(const CScript& scriptSig, const CScript& scriptPubKey,
|
||||||
|
|
||||||
return 0;
|
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 <hash.h>
|
||||||
#include <primitives/transaction.h>
|
#include <primitives/transaction.h>
|
||||||
#include <script/script_error.h> // IWYU pragma: export
|
#include <script/script_error.h> // IWYU pragma: export
|
||||||
|
#include <script/verify_flags.h> // IWYU pragma: export
|
||||||
#include <span.h>
|
#include <span.h>
|
||||||
#include <uint256.h>
|
#include <uint256.h>
|
||||||
|
|
||||||
|
@ -42,35 +43,36 @@ enum
|
||||||
* All flags are intended to be soft forks: the set of acceptable scripts under
|
* 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).
|
* 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).
|
// 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.
|
// 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.
|
// 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).
|
// (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)
|
// 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
|
// Passing a non-strict-DER signature or one with S > order/2 to a checksig operation causes script failure
|
||||||
// (BIP62 rule 5).
|
// (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).
|
// 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).
|
// 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
|
// 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
|
// 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).
|
// 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).
|
// 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)
|
// 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.
|
// executed, e.g. within an unexecuted IF ENDIF block, are *not* rejected.
|
||||||
// NOPs that have associated forks to give them new meaning (CLTV, CSV)
|
// NOPs that have associated forks to give them new meaning (CLTV, CSV)
|
||||||
// are not subject to this rule.
|
// 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
|
// 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
|
// "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: 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
|
// 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.
|
// consensus rules. It is automatic there and does not need this flag.
|
||||||
SCRIPT_VERIFY_CLEANSTACK = (1U << 8),
|
SCRIPT_VERIFY_CLEANSTACK,
|
||||||
|
|
||||||
// Verify CHECKLOCKTIMEVERIFY
|
// Verify CHECKLOCKTIMEVERIFY
|
||||||
//
|
//
|
||||||
// See BIP65 for details.
|
// See BIP65 for details.
|
||||||
SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY = (1U << 9),
|
SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY,
|
||||||
|
|
||||||
// support CHECKSEQUENCEVERIFY opcode
|
// support CHECKSEQUENCEVERIFY opcode
|
||||||
//
|
//
|
||||||
// See BIP112 for details
|
// See BIP112 for details
|
||||||
SCRIPT_VERIFY_CHECKSEQUENCEVERIFY = (1U << 10),
|
SCRIPT_VERIFY_CHECKSEQUENCEVERIFY,
|
||||||
|
|
||||||
// Support segregated witness
|
// Support segregated witness
|
||||||
//
|
//
|
||||||
SCRIPT_VERIFY_WITNESS = (1U << 11),
|
SCRIPT_VERIFY_WITNESS,
|
||||||
|
|
||||||
// Making v1-v16 witness program non-standard
|
// 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
|
// 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
|
// 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.
|
// 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
|
// 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
|
// 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
|
// 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)
|
// Taproot/Tapscript validation (BIPs 341 & 342)
|
||||||
//
|
//
|
||||||
SCRIPT_VERIFY_TAPROOT = (1U << 17),
|
SCRIPT_VERIFY_TAPROOT,
|
||||||
|
|
||||||
// Making unknown Taproot leaf versions non-standard
|
// 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
|
// 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
|
// 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.
|
// Constants to point to the highest flag in use. Add new flags above this line.
|
||||||
//
|
//
|
||||||
SCRIPT_VERIFY_END_MARKER
|
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
|
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}). */
|
* 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);
|
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, 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, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, 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, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror = 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);
|
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
|
#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 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)
|
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
|
bloom_tests.cpp
|
||||||
bswap_tests.cpp
|
bswap_tests.cpp
|
||||||
caches_tests.cpp
|
caches_tests.cpp
|
||||||
|
chain_tests.cpp
|
||||||
chainstate_write_tests.cpp
|
chainstate_write_tests.cpp
|
||||||
checkqueue_tests.cpp
|
checkqueue_tests.cpp
|
||||||
cluster_linearize_tests.cpp
|
cluster_linearize_tests.cpp
|
||||||
|
@ -102,6 +103,7 @@ add_executable(test_bitcoin
|
||||||
span_tests.cpp
|
span_tests.cpp
|
||||||
streams_tests.cpp
|
streams_tests.cpp
|
||||||
sync_tests.cpp
|
sync_tests.cpp
|
||||||
|
system_ram_tests.cpp
|
||||||
system_tests.cpp
|
system_tests.cpp
|
||||||
testnet4_miner_tests.cpp
|
testnet4_miner_tests.cpp
|
||||||
timeoffsets_tests.cpp
|
timeoffsets_tests.cpp
|
||||||
|
@ -197,7 +199,10 @@ function(add_boost_test source_file)
|
||||||
COMMAND test_bitcoin --run_test=${test_suite_name} --catch_system_error=no --log_level=test_suite -- DEBUG_LOG_OUT
|
COMMAND test_bitcoin --run_test=${test_suite_name} --catch_system_error=no --log_level=test_suite -- DEBUG_LOG_OUT
|
||||||
)
|
)
|
||||||
set_property(TEST ${test_suite_name} PROPERTY
|
set_property(TEST ${test_suite_name} PROPERTY
|
||||||
SKIP_REGULAR_EXPRESSION "no test cases matching filter" "skipping script_assets_test"
|
SKIP_REGULAR_EXPRESSION
|
||||||
|
"no test cases matching filter"
|
||||||
|
"skipping script_assets_test"
|
||||||
|
"skipping total_ram"
|
||||||
)
|
)
|
||||||
endforeach()
|
endforeach()
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
|
@ -459,10 +459,16 @@ BOOST_AUTO_TEST_CASE(getaddr_unfiltered)
|
||||||
addrman->Attempt(addr3, /*fCountFailure=*/true, /*time=*/Now<NodeSeconds>() - 61s);
|
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
|
// 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);
|
BOOST_CHECK_EQUAL(addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt).size(), 1U);
|
||||||
// Unfiltered GetAddr should return all addrs
|
// 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)
|
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(),
|
CAddress(),
|
||||||
/*addrNameIn=*/"",
|
/*addrNameIn=*/"",
|
||||||
ConnectionType::OUTBOUND_FULL_RELAY,
|
ConnectionType::OUTBOUND_FULL_RELAY,
|
||||||
/*inbound_onion=*/false};
|
/*inbound_onion=*/false,
|
||||||
|
/*network_key=*/0};
|
||||||
|
|
||||||
connman.Handshake(
|
connman.Handshake(
|
||||||
/*node=*/dummyNode1,
|
/*node=*/dummyNode1,
|
||||||
|
@ -128,7 +129,8 @@ void AddRandomOutboundPeer(NodeId& id, std::vector<CNode*>& vNodes, PeerManager&
|
||||||
CAddress(),
|
CAddress(),
|
||||||
/*addrNameIn=*/"",
|
/*addrNameIn=*/"",
|
||||||
connType,
|
connType,
|
||||||
/*inbound_onion=*/false});
|
/*inbound_onion=*/false,
|
||||||
|
/*network_key=*/0});
|
||||||
CNode &node = *vNodes.back();
|
CNode &node = *vNodes.back();
|
||||||
node.SetCommonVersion(PROTOCOL_VERSION);
|
node.SetCommonVersion(PROTOCOL_VERSION);
|
||||||
|
|
||||||
|
@ -327,7 +329,8 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
|
||||||
CAddress(),
|
CAddress(),
|
||||||
/*addrNameIn=*/"",
|
/*addrNameIn=*/"",
|
||||||
ConnectionType::INBOUND,
|
ConnectionType::INBOUND,
|
||||||
/*inbound_onion=*/false};
|
/*inbound_onion=*/false,
|
||||||
|
/*network_key=*/1};
|
||||||
nodes[0]->SetCommonVersion(PROTOCOL_VERSION);
|
nodes[0]->SetCommonVersion(PROTOCOL_VERSION);
|
||||||
peerLogic->InitializeNode(*nodes[0], NODE_NETWORK);
|
peerLogic->InitializeNode(*nodes[0], NODE_NETWORK);
|
||||||
nodes[0]->fSuccessfullyConnected = true;
|
nodes[0]->fSuccessfullyConnected = true;
|
||||||
|
@ -347,7 +350,8 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
|
||||||
CAddress(),
|
CAddress(),
|
||||||
/*addrNameIn=*/"",
|
/*addrNameIn=*/"",
|
||||||
ConnectionType::INBOUND,
|
ConnectionType::INBOUND,
|
||||||
/*inbound_onion=*/false};
|
/*inbound_onion=*/false,
|
||||||
|
/*network_key=*/1};
|
||||||
nodes[1]->SetCommonVersion(PROTOCOL_VERSION);
|
nodes[1]->SetCommonVersion(PROTOCOL_VERSION);
|
||||||
peerLogic->InitializeNode(*nodes[1], NODE_NETWORK);
|
peerLogic->InitializeNode(*nodes[1], NODE_NETWORK);
|
||||||
nodes[1]->fSuccessfullyConnected = true;
|
nodes[1]->fSuccessfullyConnected = true;
|
||||||
|
@ -377,7 +381,8 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
|
||||||
CAddress(),
|
CAddress(),
|
||||||
/*addrNameIn=*/"",
|
/*addrNameIn=*/"",
|
||||||
ConnectionType::OUTBOUND_FULL_RELAY,
|
ConnectionType::OUTBOUND_FULL_RELAY,
|
||||||
/*inbound_onion=*/false};
|
/*inbound_onion=*/false,
|
||||||
|
/*network_key=*/2};
|
||||||
nodes[2]->SetCommonVersion(PROTOCOL_VERSION);
|
nodes[2]->SetCommonVersion(PROTOCOL_VERSION);
|
||||||
peerLogic->InitializeNode(*nodes[2], NODE_NETWORK);
|
peerLogic->InitializeNode(*nodes[2], NODE_NETWORK);
|
||||||
nodes[2]->fSuccessfullyConnected = true;
|
nodes[2]->fSuccessfullyConnected = true;
|
||||||
|
@ -419,7 +424,8 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
|
||||||
CAddress(),
|
CAddress(),
|
||||||
/*addrNameIn=*/"",
|
/*addrNameIn=*/"",
|
||||||
ConnectionType::INBOUND,
|
ConnectionType::INBOUND,
|
||||||
/*inbound_onion=*/false};
|
/*inbound_onion=*/false,
|
||||||
|
/*network_key=*/1};
|
||||||
dummyNode.SetCommonVersion(PROTOCOL_VERSION);
|
dummyNode.SetCommonVersion(PROTOCOL_VERSION);
|
||||||
peerLogic->InitializeNode(dummyNode, NODE_NETWORK);
|
peerLogic->InitializeNode(dummyNode, NODE_NETWORK);
|
||||||
dummyNode.fSuccessfullyConnected = true;
|
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.
|
// consensus/tx_verify.cpp:130: unsigned int GetP2SHSigOpCount(const CTransaction &, const CCoinsViewCache &): Assertion `!coin.IsSpent()' failed.
|
||||||
return;
|
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) {
|
if (!transaction.vin.empty() && (flags & SCRIPT_VERIFY_WITNESS) != 0 && (flags & SCRIPT_VERIFY_P2SH) == 0) {
|
||||||
// Avoid:
|
// Avoid:
|
||||||
// script/interpreter.cpp:1705: size_t CountWitnessSigOps(const CScript &, const CScript &, const CScriptWitness *, unsigned int): Assertion `(flags & SCRIPT_VERIFY_P2SH) != 0' failed.
|
// 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 <chainparams.h>
|
||||||
#include <common/args.h>
|
#include <common/args.h>
|
||||||
#include <net.h>
|
#include <net.h>
|
||||||
|
#include <net_processing.h>
|
||||||
#include <netaddress.h>
|
#include <netaddress.h>
|
||||||
#include <protocol.h>
|
#include <protocol.h>
|
||||||
#include <test/fuzz/FuzzedDataProvider.h>
|
#include <test/fuzz/FuzzedDataProvider.h>
|
||||||
#include <test/fuzz/fuzz.h>
|
#include <test/fuzz/fuzz.h>
|
||||||
#include <test/fuzz/util.h>
|
#include <test/fuzz/util.h>
|
||||||
#include <test/fuzz/util/net.h>
|
#include <test/fuzz/util/net.h>
|
||||||
|
#include <test/fuzz/util/threadinterrupt.h>
|
||||||
#include <test/util/setup_common.h>
|
#include <test/util/setup_common.h>
|
||||||
#include <util/translation.h>
|
#include <util/translation.h>
|
||||||
|
|
||||||
|
@ -51,19 +53,36 @@ FUZZ_TARGET(connman, .init = initialize_connman)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AddrManDeterministic& addr_man{*addr_man_ptr};
|
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>(),
|
ConnmanTestMsg connman{fuzzed_data_provider.ConsumeIntegral<uint64_t>(),
|
||||||
fuzzed_data_provider.ConsumeIntegral<uint64_t>(),
|
fuzzed_data_provider.ConsumeIntegral<uint64_t>(),
|
||||||
addr_man,
|
addr_man,
|
||||||
netgroupman,
|
netgroupman,
|
||||||
Params(),
|
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>()};
|
const uint64_t max_outbound_limit{fuzzed_data_provider.ConsumeIntegral<uint64_t>()};
|
||||||
CConnman::Options options;
|
CConnman::Options options;
|
||||||
|
options.m_msgproc = &net_events;
|
||||||
options.nMaxOutboundLimit = max_outbound_limit;
|
options.nMaxOutboundLimit = max_outbound_limit;
|
||||||
connman.Init(options);
|
connman.Init(options);
|
||||||
|
|
||||||
CNetAddr random_netaddr;
|
CNetAddr random_netaddr;
|
||||||
|
CAddress random_address;
|
||||||
CNode random_node = ConsumeNode(fuzzed_data_provider);
|
CNode random_node = ConsumeNode(fuzzed_data_provider);
|
||||||
CSubNet random_subnet;
|
CSubNet random_subnet;
|
||||||
std::string random_string;
|
std::string random_string;
|
||||||
|
@ -79,6 +98,9 @@ FUZZ_TARGET(connman, .init = initialize_connman)
|
||||||
[&] {
|
[&] {
|
||||||
random_netaddr = ConsumeNetAddr(fuzzed_data_provider);
|
random_netaddr = ConsumeNetAddr(fuzzed_data_provider);
|
||||||
},
|
},
|
||||||
|
[&] {
|
||||||
|
random_address = ConsumeAddress(fuzzed_data_provider);
|
||||||
|
},
|
||||||
[&] {
|
[&] {
|
||||||
random_subnet = ConsumeSubNet(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());
|
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());
|
(void)connman.GetAddedNodeInfo(fuzzed_data_provider.ConsumeBool());
|
||||||
|
@ -162,4 +230,6 @@ FUZZ_TARGET(connman, .init = initialize_connman)
|
||||||
(void)connman.ASMapHealthCheck();
|
(void)connman.ASMapHealthCheck();
|
||||||
|
|
||||||
connman.ClearTestNodes();
|
connman.ClearTestNodes();
|
||||||
|
g_dns_lookup = g_dns_lookup_orig;
|
||||||
|
CreateSock = CreateSockOrig;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
FUZZ_TARGET(eval_script)
|
FUZZ_TARGET(eval_script)
|
||||||
{
|
{
|
||||||
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
|
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 = [&] {
|
const std::vector<uint8_t> script_bytes = [&] {
|
||||||
if (fuzzed_data_provider.remaining_bytes() != 0) {
|
if (fuzzed_data_provider.remaining_bytes() != 0) {
|
||||||
return fuzzed_data_provider.ConsumeRemainingBytes<uint8_t>();
|
return fuzzed_data_provider.ConsumeRemainingBytes<uint8_t>();
|
||||||
|
|
|
@ -75,7 +75,7 @@ auto& FuzzTargets()
|
||||||
|
|
||||||
void FuzzFrameworkRegisterTarget(std::string_view name, TypeTestOneInput target, FuzzTargetOptions opts)
|
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);
|
Assert(ins);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <test/fuzz/fuzz.h>
|
#include <test/fuzz/fuzz.h>
|
||||||
#include <test/fuzz/util.h>
|
#include <test/fuzz/util.h>
|
||||||
#include <test/fuzz/util/net.h>
|
#include <test/fuzz/util/net.h>
|
||||||
|
#include <test/fuzz/util/threadinterrupt.h>
|
||||||
#include <test/util/setup_common.h>
|
#include <test/util/setup_common.h>
|
||||||
#include <util/fs_helpers.h>
|
#include <util/fs_helpers.h>
|
||||||
#include <util/threadinterrupt.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 fs::path private_key_path = gArgs.GetDataDirNet() / "fuzzed_i2p_private_key";
|
||||||
const CService addr{in6_addr(IN6ADDR_LOOPBACK_INIT), 7656};
|
const CService addr{in6_addr(IN6ADDR_LOOPBACK_INIT), 7656};
|
||||||
const Proxy sam_proxy{addr, /*tor_stream_isolation=*/false};
|
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;
|
i2p::Connection conn;
|
||||||
|
|
||||||
if (session.Listen(conn)) {
|
if (session.Listen(conn)) {
|
||||||
if (session.Accept(conn)) {
|
if (session.Accept(conn)) {
|
||||||
try {
|
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&) {
|
} catch (const std::runtime_error&) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,7 +54,7 @@ FUZZ_TARGET(i2p, .init = initialize_i2p)
|
||||||
|
|
||||||
if (session.Connect(CService{}, conn, proxy_error)) {
|
if (session.Connect(CService{}, conn, proxy_error)) {
|
||||||
try {
|
try {
|
||||||
conn.sock->SendComplete("verack\n", 10ms, interrupt);
|
conn.sock->SendComplete("verack\n", 10ms, *interrupt);
|
||||||
} catch (const std::runtime_error&) {
|
} catch (const std::runtime_error&) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,7 @@ FUZZ_TARGET(mini_miner, .init = initialize_miner)
|
||||||
std::deque<COutPoint> available_coins = g_available_coins;
|
std::deque<COutPoint> available_coins = g_available_coins;
|
||||||
LOCK2(::cs_main, pool.cs);
|
LOCK2(::cs_main, pool.cs);
|
||||||
// Cluster size cannot exceed 500
|
// Cluster size cannot exceed 500
|
||||||
LIMITED_WHILE(!available_coins.empty(), 500)
|
LIMITED_WHILE(!available_coins.empty(), 100)
|
||||||
{
|
{
|
||||||
CMutableTransaction mtx = CMutableTransaction();
|
CMutableTransaction mtx = CMutableTransaction();
|
||||||
const size_t num_inputs = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, available_coins.size());
|
const size_t num_inputs = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, available_coins.size());
|
||||||
|
|
|
@ -70,7 +70,7 @@ void HeadersSyncSetup::ResetAndInitialize()
|
||||||
|
|
||||||
for (auto conn_type : conn_types) {
|
for (auto conn_type : conn_types) {
|
||||||
CAddress addr{};
|
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();
|
CNode& p2p_node = *m_connections.back();
|
||||||
|
|
||||||
connman.Handshake(
|
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=*/{}));
|
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(),
|
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) {
|
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
|
// 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);
|
(void)FindAndDelete(script_mut, *other_script);
|
||||||
}
|
}
|
||||||
const std::vector<std::string> random_string_vector = ConsumeRandomLengthStringVector(fuzzed_data_provider);
|
const std::vector<std::string> random_string_vector = ConsumeRandomLengthStringVector(fuzzed_data_provider);
|
||||||
const uint32_t u32{fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
|
const auto flags_rand{fuzzed_data_provider.ConsumeIntegral<script_verify_flags::value_type>()};
|
||||||
const uint32_t flags{u32 | SCRIPT_VERIFY_P2SH};
|
const auto flags = script_verify_flags::from_int(flags_rand) | SCRIPT_VERIFY_P2SH;
|
||||||
{
|
{
|
||||||
CScriptWitness wit;
|
CScriptWitness wit;
|
||||||
for (const auto& s : random_string_vector) {
|
for (const auto& s : random_string_vector) {
|
||||||
|
|
|
@ -90,22 +90,22 @@ CScriptWitness ScriptWitnessFromJSON(const UniValue& univalue)
|
||||||
return scriptwitness;
|
return scriptwitness;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::map<std::string, unsigned int> FLAG_NAMES = {
|
const std::map<std::string, script_verify_flag_name> FLAG_NAMES = {
|
||||||
{std::string("P2SH"), (unsigned int)SCRIPT_VERIFY_P2SH},
|
{std::string("P2SH"), SCRIPT_VERIFY_P2SH},
|
||||||
{std::string("DERSIG"), (unsigned int)SCRIPT_VERIFY_DERSIG},
|
{std::string("DERSIG"), SCRIPT_VERIFY_DERSIG},
|
||||||
{std::string("NULLDUMMY"), (unsigned int)SCRIPT_VERIFY_NULLDUMMY},
|
{std::string("NULLDUMMY"), SCRIPT_VERIFY_NULLDUMMY},
|
||||||
{std::string("CHECKLOCKTIMEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY},
|
{std::string("CHECKLOCKTIMEVERIFY"), SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY},
|
||||||
{std::string("CHECKSEQUENCEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKSEQUENCEVERIFY},
|
{std::string("CHECKSEQUENCEVERIFY"), SCRIPT_VERIFY_CHECKSEQUENCEVERIFY},
|
||||||
{std::string("WITNESS"), (unsigned int)SCRIPT_VERIFY_WITNESS},
|
{std::string("WITNESS"), SCRIPT_VERIFY_WITNESS},
|
||||||
{std::string("TAPROOT"), (unsigned int)SCRIPT_VERIFY_TAPROOT},
|
{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) {
|
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 & 1) flag |= SCRIPT_VERIFY_P2SH;
|
||||||
if (i & 2) flag |= SCRIPT_VERIFY_DERSIG;
|
if (i & 2) flag |= SCRIPT_VERIFY_DERSIG;
|
||||||
if (i & 4) flag |= SCRIPT_VERIFY_NULLDUMMY;
|
if (i & 4) flag |= SCRIPT_VERIFY_NULLDUMMY;
|
||||||
|
@ -125,13 +125,13 @@ std::vector<unsigned int> AllFlags()
|
||||||
return ret;
|
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;
|
if (str.empty()) return 0;
|
||||||
|
|
||||||
unsigned int flags = 0;
|
script_verify_flags flags = 0;
|
||||||
std::vector<std::string> words = SplitString(str, ',');
|
std::vector<std::string> words = SplitString(str, ',');
|
||||||
|
|
||||||
for (const std::string& word : words) {
|
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");
|
if (prevouts.size() != tx.vin.size()) throw std::runtime_error("Incorrect number of prevouts");
|
||||||
size_t idx = test["index"].getInt<int64_t>();
|
size_t idx = test["index"].getInt<int64_t>();
|
||||||
if (idx >= tx.vin.size()) throw std::runtime_error("Invalid index");
|
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();
|
bool final = test.exists("final") && test["final"].get_bool();
|
||||||
|
|
||||||
if (test.exists("success")) {
|
if (test.exists("success")) {
|
||||||
|
|
|
@ -15,6 +15,15 @@
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#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)
|
FUZZ_TARGET(script_flags)
|
||||||
{
|
{
|
||||||
if (buffer.size() > 100'000) return;
|
if (buffer.size() > 100'000) return;
|
||||||
|
@ -22,12 +31,14 @@ FUZZ_TARGET(script_flags)
|
||||||
try {
|
try {
|
||||||
const CTransaction tx(deserialize, TX_WITH_WITNESS, ds);
|
const CTransaction tx(deserialize, TX_WITH_WITNESS, ds);
|
||||||
|
|
||||||
unsigned int verify_flags;
|
script_verify_flags verify_flags;
|
||||||
ds >> verify_flags;
|
ds >> verify_flags;
|
||||||
|
|
||||||
|
assert(verify_flags == script_verify_flags::from_int(verify_flags.as_int()));
|
||||||
|
|
||||||
if (!IsValidFlagCombination(verify_flags)) return;
|
if (!IsValidFlagCombination(verify_flags)) return;
|
||||||
|
|
||||||
unsigned int fuzzed_flags;
|
script_verify_flags fuzzed_flags;
|
||||||
ds >> fuzzed_flags;
|
ds >> fuzzed_flags;
|
||||||
|
|
||||||
std::vector<CTxOut> spent_outputs;
|
std::vector<CTxOut> spent_outputs;
|
||||||
|
|
|
@ -17,22 +17,22 @@ int ec_seckey_export_der(const secp256k1_context* ctx, unsigned char* seckey, si
|
||||||
FUZZ_TARGET(secp256k1_ec_seckey_import_export_der)
|
FUZZ_TARGET(secp256k1_ec_seckey_import_export_der)
|
||||||
{
|
{
|
||||||
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
|
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
|
||||||
secp256k1_context* secp256k1_context_sign = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
|
|
||||||
{
|
{
|
||||||
std::vector<uint8_t> out32(32);
|
std::vector<uint8_t> out32(32);
|
||||||
(void)ec_seckey_import_der(secp256k1_context_sign, out32.data(), ConsumeFixedLengthByteVector(fuzzed_data_provider, CKey::SIZE).data(), CKey::SIZE);
|
(void)ec_seckey_import_der(secp256k1_context_static, out32.data(), ConsumeFixedLengthByteVector(fuzzed_data_provider, CKey::SIZE).data(), CKey::SIZE);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
std::vector<uint8_t> seckey(CKey::SIZE);
|
std::vector<uint8_t> seckey(CKey::SIZE);
|
||||||
const std::vector<uint8_t> key32 = ConsumeFixedLengthByteVector(fuzzed_data_provider, 32);
|
const std::vector<uint8_t> key32 = ConsumeFixedLengthByteVector(fuzzed_data_provider, 32);
|
||||||
size_t seckeylen = CKey::SIZE;
|
size_t seckeylen = CKey::SIZE;
|
||||||
const bool compressed = fuzzed_data_provider.ConsumeBool();
|
const bool compressed = fuzzed_data_provider.ConsumeBool();
|
||||||
|
secp256k1_context* secp256k1_context_sign = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
|
||||||
const bool exported = ec_seckey_export_der(secp256k1_context_sign, seckey.data(), &seckeylen, key32.data(), compressed);
|
const bool exported = ec_seckey_export_der(secp256k1_context_sign, seckey.data(), &seckeylen, key32.data(), compressed);
|
||||||
|
secp256k1_context_destroy(secp256k1_context_sign);
|
||||||
if (exported) {
|
if (exported) {
|
||||||
std::vector<uint8_t> out32(32);
|
std::vector<uint8_t> out32(32);
|
||||||
const bool imported = ec_seckey_import_der(secp256k1_context_sign, out32.data(), seckey.data(), seckey.size()) == 1;
|
const bool imported = ec_seckey_import_der(secp256k1_context_static, out32.data(), seckey.data(), seckey.size()) == 1;
|
||||||
assert(imported && key32 == out32);
|
assert(imported && key32 == out32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
secp256k1_context_destroy(secp256k1_context_sign);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,7 @@ public:
|
||||||
FUZZ_TARGET(signature_checker)
|
FUZZ_TARGET(signature_checker)
|
||||||
{
|
{
|
||||||
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
|
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 SigVersion sig_version = fuzzed_data_provider.PickValueInArray({SigVersion::BASE, SigVersion::WITNESS_V0});
|
||||||
const auto script_1{ConsumeScript(fuzzed_data_provider)};
|
const auto script_1{ConsumeScript(fuzzed_data_provider)};
|
||||||
const auto script_2{ConsumeScript(fuzzed_data_provider)};
|
const auto script_2{ConsumeScript(fuzzed_data_provider)};
|
||||||
|
|
|
@ -223,7 +223,7 @@ FUZZ_TARGET(tx_pool_standard, .init = initialize_tx_pool)
|
||||||
return coin.out.nValue;
|
return coin.out.nValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 300)
|
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 100)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
// Total supply is the mempool fee + all outpoints
|
// Total supply is the mempool fee + all outpoints
|
||||||
|
@ -296,7 +296,6 @@ FUZZ_TARGET(tx_pool_standard, .init = initialize_tx_pool)
|
||||||
std::set<CTransactionRef> added;
|
std::set<CTransactionRef> added;
|
||||||
auto txr = std::make_shared<TransactionsDelta>(removed, added);
|
auto txr = std::make_shared<TransactionsDelta>(removed, added);
|
||||||
node.validation_signals->RegisterSharedValidationInterface(txr);
|
node.validation_signals->RegisterSharedValidationInterface(txr);
|
||||||
const bool bypass_limits = fuzzed_data_provider.ConsumeBool();
|
|
||||||
|
|
||||||
// Make sure ProcessNewPackage on one transaction works.
|
// Make sure ProcessNewPackage on one transaction works.
|
||||||
// The result is not guaranteed to be the same as what is returned by ATMP.
|
// 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);
|
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;
|
const bool accepted = res.m_result_type == MempoolAcceptResult::ResultType::VALID;
|
||||||
node.validation_signals->SyncWithValidationInterfaceQueue();
|
node.validation_signals->SyncWithValidationInterfaceQueue();
|
||||||
node.validation_signals->UnregisterSharedValidationInterface(txr);
|
node.validation_signals->UnregisterSharedValidationInterface(txr);
|
||||||
|
@ -394,6 +393,9 @@ FUZZ_TARGET(tx_pool, .init = initialize_tx_pool)
|
||||||
|
|
||||||
chainstate.SetMempool(&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)
|
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 300)
|
||||||
{
|
{
|
||||||
const auto mut_tx = ConsumeTransaction(fuzzed_data_provider, txids);
|
const auto mut_tx = ConsumeTransaction(fuzzed_data_provider, txids);
|
||||||
|
@ -412,13 +414,17 @@ FUZZ_TARGET(tx_pool, .init = initialize_tx_pool)
|
||||||
tx_pool.PrioritiseTransaction(txid, delta);
|
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 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 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;
|
const bool accepted = res.m_result_type == MempoolAcceptResult::ResultType::VALID;
|
||||||
if (accepted) {
|
if (accepted) {
|
||||||
txids.push_back(tx->GetHash());
|
txids.push_back(tx->GetHash());
|
||||||
CheckMempoolTRUCInvariants(tx_pool);
|
if (!ever_bypassed_limits) {
|
||||||
|
CheckMempoolTRUCInvariants(tx_pool);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Finish(fuzzed_data_provider, tx_pool, chainstate);
|
Finish(fuzzed_data_provider, tx_pool, chainstate);
|
||||||
|
|
|
@ -178,7 +178,7 @@ FUZZ_TARGET(txdownloadman, .init = initialize)
|
||||||
|
|
||||||
std::chrono::microseconds time{244466666};
|
std::chrono::microseconds time{244466666};
|
||||||
|
|
||||||
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10000)
|
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 500)
|
||||||
{
|
{
|
||||||
NodeId rand_peer = fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(0, NUM_PEERS - 1);
|
NodeId rand_peer = fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(0, NUM_PEERS - 1);
|
||||||
|
|
||||||
|
@ -303,7 +303,7 @@ FUZZ_TARGET(txdownloadman_impl, .init = initialize)
|
||||||
|
|
||||||
std::chrono::microseconds time{244466666};
|
std::chrono::microseconds time{244466666};
|
||||||
|
|
||||||
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10000)
|
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 500)
|
||||||
{
|
{
|
||||||
NodeId rand_peer = fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(0, NUM_PEERS - 1);
|
NodeId rand_peer = fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(0, NUM_PEERS - 1);
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ add_library(test_fuzz STATIC EXCLUDE_FROM_ALL
|
||||||
descriptor.cpp
|
descriptor.cpp
|
||||||
mempool.cpp
|
mempool.cpp
|
||||||
net.cpp
|
net.cpp
|
||||||
|
threadinterrupt.cpp
|
||||||
../fuzz.cpp
|
../fuzz.cpp
|
||||||
../util.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);
|
SetFuzzedErrNo(m_fuzzed_data_provider, accept_errnos);
|
||||||
return std::unique_ptr<FuzzedSock>();
|
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);
|
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
|
class FuzzedSock : public Sock
|
||||||
{
|
{
|
||||||
FuzzedDataProvider& m_fuzzed_data_provider;
|
FuzzedDataProvider& m_fuzzed_data_provider;
|
||||||
|
@ -203,6 +222,11 @@ public:
|
||||||
bool IsConnected(std::string& errmsg) const override;
|
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)
|
[[nodiscard]] inline FuzzedSock ConsumeSock(FuzzedDataProvider& fuzzed_data_provider)
|
||||||
{
|
{
|
||||||
return FuzzedSock{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>()};
|
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;
|
CAddress ConsumeAddress(FuzzedDataProvider& fuzzed_data_provider) noexcept;
|
||||||
|
|
||||||
template <bool ReturnUniquePtr = false>
|
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 std::string addr_name = fuzzed_data_provider.ConsumeRandomLengthString(64);
|
||||||
const ConnectionType conn_type = fuzzed_data_provider.PickValueInArray(ALL_CONNECTION_TYPES);
|
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 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);
|
NetPermissionFlags permission_flags = ConsumeWeakEnum(fuzzed_data_provider, ALL_NET_PERMISSION_FLAGS);
|
||||||
if constexpr (ReturnUniquePtr) {
|
if constexpr (ReturnUniquePtr) {
|
||||||
return std::make_unique<CNode>(node_id,
|
return std::make_unique<CNode>(node_id,
|
||||||
|
@ -250,6 +288,7 @@ auto ConsumeNode(FuzzedDataProvider& fuzzed_data_provider, const std::optional<N
|
||||||
addr_name,
|
addr_name,
|
||||||
conn_type,
|
conn_type,
|
||||||
inbound_onion,
|
inbound_onion,
|
||||||
|
network_id,
|
||||||
CNodeOptions{ .permission_flags = permission_flags });
|
CNodeOptions{ .permission_flags = permission_flags });
|
||||||
} else {
|
} else {
|
||||||
return CNode{node_id,
|
return CNode{node_id,
|
||||||
|
@ -261,6 +300,7 @@ auto ConsumeNode(FuzzedDataProvider& fuzzed_data_provider, const std::optional<N
|
||||||
addr_name,
|
addr_name,
|
||||||
conn_type,
|
conn_type,
|
||||||
inbound_onion,
|
inbound_onion,
|
||||||
|
network_id,
|
||||||
CNodeOptions{ .permission_flags = permission_flags }};
|
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'));
|
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 std::optional<CService> addr{Lookup("127.0.0.1", 9000, false)};
|
||||||
const Proxy sam_proxy(addr.value(), /*tor_stream_isolation=*/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");
|
ASSERT_DEBUG_LOG("Creating persistent SAM session");
|
||||||
|
@ -112,12 +112,12 @@ BOOST_AUTO_TEST_CASE(listen_ok_accept_fail)
|
||||||
// clang-format on
|
// clang-format on
|
||||||
};
|
};
|
||||||
|
|
||||||
CThreadInterrupt interrupt;
|
auto interrupt{std::make_shared<CThreadInterrupt>()};
|
||||||
const CService addr{in6_addr(IN6ADDR_LOOPBACK_INIT), /*port=*/7656};
|
const CService addr{in6_addr(IN6ADDR_LOOPBACK_INIT), /*port=*/7656};
|
||||||
const Proxy sam_proxy(addr, /*tor_stream_isolation=*/false);
|
const Proxy sam_proxy(addr, /*tor_stream_isolation=*/false);
|
||||||
i2p::sam::Session session(gArgs.GetDataDirNet() / "test_i2p_private_key",
|
i2p::sam::Session session(gArgs.GetDataDirNet() / "test_i2p_private_key",
|
||||||
sam_proxy,
|
sam_proxy,
|
||||||
&interrupt);
|
interrupt);
|
||||||
|
|
||||||
i2p::Connection conn;
|
i2p::Connection conn;
|
||||||
for (size_t i = 0; i < 5; ++i) {
|
for (size_t i = 0; i < 5; ++i) {
|
||||||
|
@ -155,10 +155,10 @@ BOOST_AUTO_TEST_CASE(damaged_private_key)
|
||||||
"391 bytes"}}) {
|
"391 bytes"}}) {
|
||||||
BOOST_REQUIRE(WriteBinaryFile(i2p_private_key_file, file_contents));
|
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 CService addr{in6_addr(IN6ADDR_LOOPBACK_INIT), /*port=*/7656};
|
||||||
const Proxy sam_proxy{addr, /*tor_stream_isolation=*/false};
|
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");
|
ASSERT_DEBUG_LOG("Creating persistent SAM session");
|
||||||
|
|
|
@ -376,9 +376,9 @@ BOOST_AUTO_TEST_CASE(key_schnorr_tweak_smoke_test)
|
||||||
secp256k1_keypair keypair;
|
secp256k1_keypair keypair;
|
||||||
BOOST_CHECK(secp256k1_keypair_create(secp256k1_context_sign, &keypair, UCharCast(key.begin())));
|
BOOST_CHECK(secp256k1_keypair_create(secp256k1_context_sign, &keypair, UCharCast(key.begin())));
|
||||||
secp256k1_xonly_pubkey xonly_pubkey;
|
secp256k1_xonly_pubkey xonly_pubkey;
|
||||||
BOOST_CHECK(secp256k1_keypair_xonly_pub(secp256k1_context_sign, &xonly_pubkey, nullptr, &keypair));
|
BOOST_CHECK(secp256k1_keypair_xonly_pub(secp256k1_context_static, &xonly_pubkey, nullptr, &keypair));
|
||||||
unsigned char xonly_bytes[32];
|
unsigned char xonly_bytes[32];
|
||||||
BOOST_CHECK(secp256k1_xonly_pubkey_serialize(secp256k1_context_sign, xonly_bytes, &xonly_pubkey));
|
BOOST_CHECK(secp256k1_xonly_pubkey_serialize(secp256k1_context_static, xonly_bytes, &xonly_pubkey));
|
||||||
uint256 tweak_old = XOnlyPubKey(xonly_bytes).ComputeTapTweakHash(&merkle_root);
|
uint256 tweak_old = XOnlyPubKey(xonly_bytes).ComputeTapTweakHash(&merkle_root);
|
||||||
|
|
||||||
// CPubKey
|
// CPubKey
|
||||||
|
|
|
@ -38,7 +38,7 @@ sign_multisig(const CScript& scriptPubKey, const std::vector<CKey>& keys, const
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(multisig_verify)
|
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;
|
ScriptError err;
|
||||||
CKey key[4];
|
CKey key[4];
|
||||||
|
|
|
@ -72,7 +72,8 @@ void AddPeer(NodeId& id, std::vector<CNode*>& nodes, PeerManager& peerman, Connm
|
||||||
CAddress{},
|
CAddress{},
|
||||||
/*addrNameIn=*/"",
|
/*addrNameIn=*/"",
|
||||||
conn_type,
|
conn_type,
|
||||||
/*inbound_onion=*/inbound_onion});
|
/*inbound_onion=*/inbound_onion,
|
||||||
|
/*network_key=*/0});
|
||||||
CNode& node = *nodes.back();
|
CNode& node = *nodes.back();
|
||||||
node.SetCommonVersion(PROTOCOL_VERSION);
|
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");
|
BOOST_TEST_MESSAGE("\nCheck that all connected peers are correctly detected as connected");
|
||||||
for (auto node : connman->TestNodes()) {
|
for (const auto& node : connman->TestNodes()) {
|
||||||
BOOST_CHECK(connman->AlreadyConnectedPublic(node->addr));
|
BOOST_CHECK(connman->AlreadyConnectedToAddressPublic(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}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean up
|
// Clean up
|
||||||
|
|
|
@ -67,7 +67,8 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test)
|
||||||
CAddress(),
|
CAddress(),
|
||||||
pszDest,
|
pszDest,
|
||||||
ConnectionType::OUTBOUND_FULL_RELAY,
|
ConnectionType::OUTBOUND_FULL_RELAY,
|
||||||
/*inbound_onion=*/false);
|
/*inbound_onion=*/false,
|
||||||
|
/*network_key=*/0);
|
||||||
BOOST_CHECK(pnode1->IsFullOutboundConn() == true);
|
BOOST_CHECK(pnode1->IsFullOutboundConn() == true);
|
||||||
BOOST_CHECK(pnode1->IsManualConn() == false);
|
BOOST_CHECK(pnode1->IsManualConn() == false);
|
||||||
BOOST_CHECK(pnode1->IsBlockOnlyConn() == false);
|
BOOST_CHECK(pnode1->IsBlockOnlyConn() == false);
|
||||||
|
@ -85,7 +86,8 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test)
|
||||||
CAddress(),
|
CAddress(),
|
||||||
pszDest,
|
pszDest,
|
||||||
ConnectionType::INBOUND,
|
ConnectionType::INBOUND,
|
||||||
/*inbound_onion=*/false);
|
/*inbound_onion=*/false,
|
||||||
|
/*network_key=*/1);
|
||||||
BOOST_CHECK(pnode2->IsFullOutboundConn() == false);
|
BOOST_CHECK(pnode2->IsFullOutboundConn() == false);
|
||||||
BOOST_CHECK(pnode2->IsManualConn() == false);
|
BOOST_CHECK(pnode2->IsManualConn() == false);
|
||||||
BOOST_CHECK(pnode2->IsBlockOnlyConn() == false);
|
BOOST_CHECK(pnode2->IsBlockOnlyConn() == false);
|
||||||
|
@ -103,7 +105,8 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test)
|
||||||
CAddress(),
|
CAddress(),
|
||||||
pszDest,
|
pszDest,
|
||||||
ConnectionType::OUTBOUND_FULL_RELAY,
|
ConnectionType::OUTBOUND_FULL_RELAY,
|
||||||
/*inbound_onion=*/false);
|
/*inbound_onion=*/false,
|
||||||
|
/*network_key=*/2);
|
||||||
BOOST_CHECK(pnode3->IsFullOutboundConn() == true);
|
BOOST_CHECK(pnode3->IsFullOutboundConn() == true);
|
||||||
BOOST_CHECK(pnode3->IsManualConn() == false);
|
BOOST_CHECK(pnode3->IsManualConn() == false);
|
||||||
BOOST_CHECK(pnode3->IsBlockOnlyConn() == false);
|
BOOST_CHECK(pnode3->IsBlockOnlyConn() == false);
|
||||||
|
@ -121,7 +124,8 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test)
|
||||||
CAddress(),
|
CAddress(),
|
||||||
pszDest,
|
pszDest,
|
||||||
ConnectionType::INBOUND,
|
ConnectionType::INBOUND,
|
||||||
/*inbound_onion=*/true);
|
/*inbound_onion=*/true,
|
||||||
|
/*network_key=*/3);
|
||||||
BOOST_CHECK(pnode4->IsFullOutboundConn() == false);
|
BOOST_CHECK(pnode4->IsFullOutboundConn() == false);
|
||||||
BOOST_CHECK(pnode4->IsManualConn() == false);
|
BOOST_CHECK(pnode4->IsManualConn() == false);
|
||||||
BOOST_CHECK(pnode4->IsBlockOnlyConn() == false);
|
BOOST_CHECK(pnode4->IsBlockOnlyConn() == false);
|
||||||
|
@ -613,7 +617,8 @@ BOOST_AUTO_TEST_CASE(ipv4_peer_with_ipv6_addrMe_test)
|
||||||
CAddress{},
|
CAddress{},
|
||||||
/*pszDest=*/std::string{},
|
/*pszDest=*/std::string{},
|
||||||
ConnectionType::OUTBOUND_FULL_RELAY,
|
ConnectionType::OUTBOUND_FULL_RELAY,
|
||||||
/*inbound_onion=*/false);
|
/*inbound_onion=*/false,
|
||||||
|
/*network_key=*/0);
|
||||||
pnode->fSuccessfullyConnected.store(true);
|
pnode->fSuccessfullyConnected.store(true);
|
||||||
|
|
||||||
// the peer claims to be reaching us via IPv6
|
// 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{},
|
/*addrBindIn=*/CService{},
|
||||||
/*addrNameIn=*/std::string{},
|
/*addrNameIn=*/std::string{},
|
||||||
/*conn_type_in=*/ConnectionType::OUTBOUND_FULL_RELAY,
|
/*conn_type_in=*/ConnectionType::OUTBOUND_FULL_RELAY,
|
||||||
/*inbound_onion=*/false};
|
/*inbound_onion=*/false,
|
||||||
|
/*network_key=*/0};
|
||||||
peer_out.fSuccessfullyConnected = true;
|
peer_out.fSuccessfullyConnected = true;
|
||||||
peer_out.SetAddrLocal(peer_us);
|
peer_out.SetAddrLocal(peer_us);
|
||||||
|
|
||||||
|
@ -688,7 +694,8 @@ BOOST_AUTO_TEST_CASE(get_local_addr_for_peer_port)
|
||||||
/*addrBindIn=*/CService{},
|
/*addrBindIn=*/CService{},
|
||||||
/*addrNameIn=*/std::string{},
|
/*addrNameIn=*/std::string{},
|
||||||
/*conn_type_in=*/ConnectionType::INBOUND,
|
/*conn_type_in=*/ConnectionType::INBOUND,
|
||||||
/*inbound_onion=*/false};
|
/*inbound_onion=*/false,
|
||||||
|
/*network_key=*/1};
|
||||||
peer_in.fSuccessfullyConnected = true;
|
peer_in.fSuccessfullyConnected = true;
|
||||||
peer_in.SetAddrLocal(peer_us);
|
peer_in.SetAddrLocal(peer_us);
|
||||||
|
|
||||||
|
@ -825,7 +832,8 @@ BOOST_AUTO_TEST_CASE(initial_advertise_from_version_message)
|
||||||
/*addrBindIn=*/CService{},
|
/*addrBindIn=*/CService{},
|
||||||
/*addrNameIn=*/std::string{},
|
/*addrNameIn=*/std::string{},
|
||||||
/*conn_type_in=*/ConnectionType::OUTBOUND_FULL_RELAY,
|
/*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 uint64_t services{NODE_NETWORK | NODE_WITNESS};
|
||||||
const int64_t time{0};
|
const int64_t time{0};
|
||||||
|
@ -900,7 +908,8 @@ BOOST_AUTO_TEST_CASE(advertise_local_address)
|
||||||
CAddress{},
|
CAddress{},
|
||||||
/*pszDest=*/std::string{},
|
/*pszDest=*/std::string{},
|
||||||
ConnectionType::OUTBOUND_FULL_RELAY,
|
ConnectionType::OUTBOUND_FULL_RELAY,
|
||||||
/*inbound_onion=*/false);
|
/*inbound_onion=*/false,
|
||||||
|
/*network_key=*/0);
|
||||||
};
|
};
|
||||||
g_reachable_nets.Add(NET_CJDNS);
|
g_reachable_nets.Add(NET_CJDNS);
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
|
|
||||||
#include <univalue.h>
|
#include <univalue.h>
|
||||||
|
|
||||||
unsigned int ParseScriptFlags(std::string strFlags);
|
script_verify_flags ParseScriptFlags(std::string strFlags);
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE(script_assets_tests)
|
BOOST_AUTO_TEST_SUITE(script_assets_tests)
|
||||||
|
|
||||||
|
@ -71,12 +71,12 @@ static CScriptWitness ScriptWitnessFromJSON(const UniValue& univalue)
|
||||||
return scriptwitness;
|
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) {
|
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 & 1) flag |= SCRIPT_VERIFY_P2SH;
|
||||||
if (i & 2) flag |= SCRIPT_VERIFY_DERSIG;
|
if (i & 2) flag |= SCRIPT_VERIFY_DERSIG;
|
||||||
if (i & 4) flag |= SCRIPT_VERIFY_NULLDUMMY;
|
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. */
|
/** 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)
|
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"]);
|
const std::vector<CTxOut> prevouts = TxOutsFromJSON(test["prevouts"]);
|
||||||
BOOST_CHECK(prevouts.size() == mtx.vin.size());
|
BOOST_CHECK(prevouts.size() == mtx.vin.size());
|
||||||
size_t idx = test["index"].getInt<int64_t>();
|
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();
|
bool fin = test.exists("final") && test["final"].get_bool();
|
||||||
|
|
||||||
if (test.exists("success")) {
|
if (test.exists("success")) {
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <core_io.h>
|
#include <core_io.h>
|
||||||
#include <key.h>
|
#include <key.h>
|
||||||
#include <rpc/util.h>
|
#include <rpc/util.h>
|
||||||
|
#include <script/interpreter.h>
|
||||||
#include <script/script.h>
|
#include <script/script.h>
|
||||||
#include <script/script_error.h>
|
#include <script/script_error.h>
|
||||||
#include <script/sigcache.h>
|
#include <script/sigcache.h>
|
||||||
|
@ -22,6 +23,7 @@
|
||||||
#include <test/util/transaction_utils.h>
|
#include <test/util/transaction_utils.h>
|
||||||
#include <util/fs.h>
|
#include <util/fs.h>
|
||||||
#include <util/strencodings.h>
|
#include <util/strencodings.h>
|
||||||
|
#include <util/string.h>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
@ -38,10 +40,9 @@
|
||||||
|
|
||||||
using namespace util::hex_literals;
|
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);
|
script_verify_flags ParseScriptFlags(std::string strFlags);
|
||||||
std::string FormatScriptFlags(unsigned int flags);
|
|
||||||
|
|
||||||
struct ScriptErrorDesc
|
struct ScriptErrorDesc
|
||||||
{
|
{
|
||||||
|
@ -95,6 +96,11 @@ static ScriptErrorDesc script_errors[]={
|
||||||
{SCRIPT_ERR_SIG_FINDANDDELETE, "SIG_FINDANDDELETE"},
|
{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)
|
static std::string FormatScriptError(ScriptError_t err)
|
||||||
{
|
{
|
||||||
for (const auto& se : script_errors)
|
for (const auto& se : script_errors)
|
||||||
|
@ -114,7 +120,7 @@ static ScriptError_t ParseScriptError(const std::string& name)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ScriptTest : BasicTestingSetup {
|
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);
|
bool expect = (scriptError == SCRIPT_ERR_OK);
|
||||||
if (flags & SCRIPT_VERIFY_CLEANSTACK) {
|
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);
|
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.
|
// 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) {
|
for (int i = 0; i < 256; ++i) {
|
||||||
uint32_t extra_flags(m_rng.randbits(16));
|
script_verify_flags extra_flags = script_verify_flags::from_int(m_rng.randbits(MAX_SCRIPT_VERIFY_FLAGS_BITS));
|
||||||
uint32_t combined_flags{expect ? (flags & ~extra_flags) : (flags | extra_flags)};
|
script_verify_flags combined_flags{expect ? (flags & ~extra_flags) : (flags | extra_flags)};
|
||||||
// Weed out some invalid flag combinations.
|
// 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_CLEANSTACK && ~combined_flags & (SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS)) continue;
|
||||||
if (combined_flags & SCRIPT_VERIFY_WITNESS && ~combined_flags & SCRIPT_VERIFY_P2SH) 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
|
}; // struct ScriptTest
|
||||||
|
@ -226,7 +232,7 @@ private:
|
||||||
bool havePush{false};
|
bool havePush{false};
|
||||||
std::vector<unsigned char> push;
|
std::vector<unsigned char> push;
|
||||||
std::string comment;
|
std::string comment;
|
||||||
uint32_t flags;
|
script_verify_flags flags;
|
||||||
int scriptError{SCRIPT_ERR_OK};
|
int scriptError{SCRIPT_ERR_OK};
|
||||||
CAmount nValue;
|
CAmount nValue;
|
||||||
|
|
||||||
|
@ -246,7 +252,7 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
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;
|
CScript scriptPubKey = script;
|
||||||
if (wm == WitnessMode::PKH) {
|
if (wm == WitnessMode::PKH) {
|
||||||
|
@ -963,7 +969,7 @@ BOOST_AUTO_TEST_CASE(script_json_test)
|
||||||
} else {
|
} else {
|
||||||
scriptPubKey = ParseScript(scriptPubKeyString);
|
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());
|
int scriptError = ParseScriptError(test[pos++].get_str());
|
||||||
|
|
||||||
DoTest(scriptPubKey, scriptSig, witness, scriptflags, strTest, scriptError, nValue);
|
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_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()
|
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
|
* Verifies script execution of the zeroth scriptPubKey of tx output and
|
||||||
* zeroth scriptSig and witness of tx input.
|
* 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;
|
ScriptError error;
|
||||||
CTransaction inputi(input);
|
CTransaction inputi(input);
|
||||||
|
@ -122,7 +122,7 @@ BOOST_AUTO_TEST_CASE(GetTxSigOpCost)
|
||||||
CKey key = GenerateRandomKey();
|
CKey key = GenerateRandomKey();
|
||||||
CPubKey pubkey = key.GetPubKey();
|
CPubKey pubkey = key.GetPubKey();
|
||||||
// Default flags
|
// 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)
|
// Multisig script (legacy counting)
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
// Copyright (c) 2025-present The Bitcoin Core developers
|
||||||
|
// Distributed under the MIT software license, see the accompanying
|
||||||
|
// file COPYING or https://opensource.org/license/mit/.
|
||||||
|
|
||||||
|
#include <common/system.h>
|
||||||
|
#include <test/util/setup_common.h>
|
||||||
|
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE(system_ram_tests)
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(total_ram)
|
||||||
|
{
|
||||||
|
const auto total{GetTotalRAM()};
|
||||||
|
if (!total) {
|
||||||
|
BOOST_WARN_MESSAGE(false, "skipping total_ram: total RAM unknown");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_CHECK_GE(*total, 1000_MiB);
|
||||||
|
|
||||||
|
if constexpr (SIZE_MAX == UINT64_MAX) {
|
||||||
|
// Upper bound check only on 64-bit: 32-bit systems can reasonably have max memory,
|
||||||
|
// but extremely large values on 64-bit likely indicate detection errors
|
||||||
|
BOOST_CHECK_LT(*total, 10'000'000_MiB); // >10 TiB memory is unlikely
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE_END()
|
|
@ -8,8 +8,6 @@
|
||||||
#include <common/run_command.h>
|
#include <common/run_command.h>
|
||||||
#include <univalue.h>
|
#include <univalue.h>
|
||||||
|
|
||||||
#include <common/system.h>
|
|
||||||
|
|
||||||
#ifdef ENABLE_EXTERNAL_SIGNER
|
#ifdef ENABLE_EXTERNAL_SIGNER
|
||||||
#include <util/subprocess.h>
|
#include <util/subprocess.h>
|
||||||
#endif // ENABLE_EXTERNAL_SIGNER
|
#endif // ENABLE_EXTERNAL_SIGNER
|
||||||
|
@ -18,17 +16,6 @@
|
||||||
|
|
||||||
BOOST_FIXTURE_TEST_SUITE(system_tests, BasicTestingSetup)
|
BOOST_FIXTURE_TEST_SUITE(system_tests, BasicTestingSetup)
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(total_ram)
|
|
||||||
{
|
|
||||||
BOOST_CHECK_GE(GetTotalRAM(), 1000_MiB);
|
|
||||||
|
|
||||||
if constexpr (SIZE_MAX == UINT64_MAX) {
|
|
||||||
// Upper bound check only on 64-bit: 32-bit systems can reasonably have max memory,
|
|
||||||
// but extremely large values on 64-bit likely indicate detection errors
|
|
||||||
BOOST_CHECK_LT(GetTotalRAM(), 10'000'000_MiB); // >10 TiB memory is unlikely
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef ENABLE_EXTERNAL_SIGNER
|
#ifdef ENABLE_EXTERNAL_SIGNER
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(run_command)
|
BOOST_AUTO_TEST_CASE(run_command)
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include <policy/policy.h>
|
#include <policy/policy.h>
|
||||||
#include <policy/settings.h>
|
#include <policy/settings.h>
|
||||||
#include <primitives/transaction_identifier.h>
|
#include <primitives/transaction_identifier.h>
|
||||||
|
#include <script/interpreter.h>
|
||||||
#include <script/script.h>
|
#include <script/script.h>
|
||||||
#include <script/script_error.h>
|
#include <script/script_error.h>
|
||||||
#include <script/sigcache.h>
|
#include <script/sigcache.h>
|
||||||
|
@ -49,41 +50,21 @@ typedef std::vector<unsigned char> valtype;
|
||||||
static CFeeRate g_dust{DUST_RELAY_TX_FEE};
|
static CFeeRate g_dust{DUST_RELAY_TX_FEE};
|
||||||
static bool g_bare_multi{DEFAULT_PERMIT_BAREMULTISIG};
|
static bool g_bare_multi{DEFAULT_PERMIT_BAREMULTISIG};
|
||||||
|
|
||||||
static std::map<std::string, unsigned int> mapFlagNames = {
|
static const std::map<std::string, script_verify_flag_name>& mapFlagNames = g_verify_flag_names;
|
||||||
{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},
|
|
||||||
};
|
|
||||||
|
|
||||||
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;
|
if (strFlags.empty() || strFlags == "NONE") return flags;
|
||||||
|
|
||||||
std::vector<std::string> words = SplitString(strFlags, ',');
|
std::vector<std::string> words = SplitString(strFlags, ',');
|
||||||
for (const std::string& word : words)
|
for (const std::string& word : words)
|
||||||
{
|
{
|
||||||
if (!mapFlagNames.count(word))
|
if (!mapFlagNames.count(word)) {
|
||||||
BOOST_ERROR("Bad test: unknown verification flag '" << word << "'");
|
BOOST_ERROR("Bad test: unknown verification flag '" << word << "'");
|
||||||
flags |= mapFlagNames[word];
|
continue;
|
||||||
|
}
|
||||||
|
flags |= mapFlagNames.at(word);
|
||||||
}
|
}
|
||||||
return flags;
|
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.
|
// Check that all flags in STANDARD_SCRIPT_VERIFY_FLAGS are present in mapFlagNames.
|
||||||
bool CheckMapFlagNames()
|
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) {
|
for (const auto& pair : mapFlagNames) {
|
||||||
standard_flags_missing &= ~(pair.second);
|
standard_flags_missing &= ~(pair.second);
|
||||||
}
|
}
|
||||||
return standard_flags_missing == 0;
|
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.
|
* 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,
|
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)
|
const PrecomputedTransactionData& txdata, const std::string& strTest, bool expect_valid)
|
||||||
{
|
{
|
||||||
bool tx_valid = true;
|
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
|
* CLEANSTACK must be used WITNESS and P2SH
|
||||||
*/
|
*/
|
||||||
|
|
||||||
unsigned int TrimFlags(unsigned int flags)
|
script_verify_flags TrimFlags(script_verify_flags flags)
|
||||||
{
|
{
|
||||||
// WITNESS requires P2SH
|
// 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)
|
// 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));
|
Assert(IsValidFlagCombination(flags));
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int FillFlags(unsigned int flags)
|
script_verify_flags FillFlags(script_verify_flags flags)
|
||||||
{
|
{
|
||||||
// CLEANSTACK implies WITNESS
|
// CLEANSTACK implies WITNESS
|
||||||
if (flags & SCRIPT_VERIFY_CLEANSTACK) flags |= SCRIPT_VERIFY_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
|
// 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}.
|
// 0001, 0010, 0100, and 1000, this should return the set {0111, 1011, 1101, 1110}.
|
||||||
// Assumes that mapFlagNames contains all script verify flags.
|
// 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) {
|
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) {
|
if (flags != flags_excluding_one) {
|
||||||
flags_combos.insert(flags_excluding_one);
|
flags_combos.insert(flags_excluding_one);
|
||||||
}
|
}
|
||||||
|
@ -247,7 +212,7 @@ BOOST_AUTO_TEST_CASE(tx_valid)
|
||||||
BOOST_CHECK(state.IsValid());
|
BOOST_CHECK(state.IsValid());
|
||||||
|
|
||||||
PrecomputedTransactionData txdata(tx);
|
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.
|
// 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)) {
|
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
|
// Backwards compatibility of script verification flags: Removing any flag(s) should not invalidate a valid transaction
|
||||||
for (const auto& [name, flag] : mapFlagNames) {
|
for (const auto& [name, flag] : mapFlagNames) {
|
||||||
// Removing individual flags
|
// 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)) {
|
if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, flags, txdata, strTest, /*expect_valid=*/true)) {
|
||||||
BOOST_ERROR("Tx unexpectedly failed with flag " << name << " unset: " << strTest);
|
BOOST_ERROR("Tx unexpectedly failed with flag " << name << " unset: " << strTest);
|
||||||
}
|
}
|
||||||
// Removing random combinations of flags
|
// 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)) {
|
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);
|
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.
|
// 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)) {
|
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
|
// Backwards compatibility of script verification flags: Adding any flag(s) should not validate an invalid transaction
|
||||||
for (const auto& [name, flag] : mapFlagNames) {
|
for (const auto& [name, flag] : mapFlagNames) {
|
||||||
unsigned int flags = FillFlags(verify_flags | flag);
|
script_verify_flags flags = FillFlags(verify_flags | flag);
|
||||||
// Adding individual flags
|
// Adding individual flags
|
||||||
if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, flags, txdata, strTest, /*expect_valid=*/false)) {
|
if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, flags, txdata, strTest, /*expect_valid=*/false)) {
|
||||||
BOOST_ERROR("Tx unexpectedly passed with flag " << name << " set: " << strTest);
|
BOOST_ERROR("Tx unexpectedly passed with flag " << name << " set: " << strTest);
|
||||||
}
|
}
|
||||||
// Adding random combinations of flags
|
// 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)) {
|
if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, flags, txdata, strTest, /*expect_valid=*/false)) {
|
||||||
BOOST_ERROR("Tx unexpectedly passed with random flags " << name << ": " << strTest);
|
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);
|
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;
|
ScriptError error;
|
||||||
CTransaction inputi(input);
|
CTransaction inputi(input);
|
||||||
|
|
|
@ -21,7 +21,7 @@ struct Dersig100Setup : public TestChain100Setup {
|
||||||
};
|
};
|
||||||
|
|
||||||
bool CheckInputScripts(const CTransaction& tx, TxValidationState& state,
|
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,
|
bool cacheFullScriptStore, PrecomputedTransactionData& txdata,
|
||||||
ValidationCache& validation_cache,
|
ValidationCache& validation_cache,
|
||||||
std::vector<CScriptCheck>* pvChecks) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
std::vector<CScriptCheck>* pvChecks) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
|
@ -120,7 +120,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, Dersig100Setup)
|
||||||
// should fail.
|
// should fail.
|
||||||
// Capture this interaction with the upgraded_nop argument: set it when evaluating
|
// Capture this interaction with the upgraded_nop argument: set it when evaluating
|
||||||
// any script flag that is implemented as an upgraded NOP code.
|
// 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;
|
PrecomputedTransactionData txdata;
|
||||||
|
|
||||||
|
@ -130,7 +130,7 @@ static void ValidateCheckInputsForAllFlags(const CTransaction &tx, uint32_t fail
|
||||||
TxValidationState state;
|
TxValidationState state;
|
||||||
|
|
||||||
// Randomly selects flag combinations
|
// 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
|
// Filter out incompatible flag choices
|
||||||
if ((test_flags & SCRIPT_VERIFY_CLEANSTACK)) {
|
if ((test_flags & SCRIPT_VERIFY_CLEANSTACK)) {
|
||||||
|
|
|
@ -8,7 +8,8 @@
|
||||||
#include <noui.h>
|
#include <noui.h>
|
||||||
#include <tinyformat.h>
|
#include <tinyformat.h>
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <cstdlib>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
DebugLogHelper::DebugLogHelper(std::string message, MatchFn match)
|
DebugLogHelper::DebugLogHelper(std::string message, MatchFn match)
|
||||||
: m_message{std::move(message)}, m_match(std::move(match))
|
: m_message{std::move(message)}, m_match(std::move(match))
|
||||||
|
@ -21,11 +22,12 @@ DebugLogHelper::DebugLogHelper(std::string message, MatchFn match)
|
||||||
noui_test_redirect();
|
noui_test_redirect();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebugLogHelper::check_found()
|
DebugLogHelper::~DebugLogHelper()
|
||||||
{
|
{
|
||||||
noui_reconnect();
|
noui_reconnect();
|
||||||
LogInstance().DeleteCallback(m_print_connection);
|
LogInstance().DeleteCallback(m_print_connection);
|
||||||
if (!m_found && m_match(nullptr)) {
|
if (!m_found && m_match(nullptr)) {
|
||||||
throw std::runtime_error(strprintf("'%s' not found in debug log\n", m_message));
|
tfm::format(std::cerr, "Fatal error: expected message not found in the debug log: '%s'\n", m_message);
|
||||||
|
std::abort();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,10 +13,7 @@
|
||||||
|
|
||||||
class DebugLogHelper
|
class DebugLogHelper
|
||||||
{
|
{
|
||||||
const std::string m_message;
|
public:
|
||||||
bool m_found{false};
|
|
||||||
std::list<std::function<void(const std::string&)>>::iterator m_print_connection;
|
|
||||||
|
|
||||||
//! Custom match checking function.
|
//! Custom match checking function.
|
||||||
//!
|
//!
|
||||||
//! Invoked with pointers to lines containing matching strings, and with
|
//! Invoked with pointers to lines containing matching strings, and with
|
||||||
|
@ -27,13 +24,19 @@ class DebugLogHelper
|
||||||
//! (2) raising an error in check_found if no match was found
|
//! (2) raising an error in check_found if no match was found
|
||||||
//! Can return false to do the opposite in either case.
|
//! Can return false to do the opposite in either case.
|
||||||
using MatchFn = std::function<bool(const std::string* line)>;
|
using MatchFn = std::function<bool(const std::string* line)>;
|
||||||
MatchFn m_match;
|
|
||||||
|
|
||||||
void check_found();
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit DebugLogHelper(std::string message, MatchFn match = [](const std::string*){ return true; });
|
explicit DebugLogHelper(std::string message, MatchFn match = [](const std::string*){ return true; });
|
||||||
~DebugLogHelper() noexcept(false) { check_found(); }
|
|
||||||
|
DebugLogHelper(const DebugLogHelper&) = delete;
|
||||||
|
DebugLogHelper& operator=(const DebugLogHelper&) = delete;
|
||||||
|
|
||||||
|
~DebugLogHelper();
|
||||||
|
|
||||||
|
private:
|
||||||
|
const std::string m_message;
|
||||||
|
bool m_found{false};
|
||||||
|
std::list<std::function<void(const std::string&)>>::iterator m_print_connection;
|
||||||
|
MatchFn m_match;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define ASSERT_DEBUG_LOG(message) DebugLogHelper UNIQUE_NAME(debugloghelper)(message)
|
#define ASSERT_DEBUG_LOG(message) DebugLogHelper UNIQUE_NAME(debugloghelper)(message)
|
||||||
|
|
|
@ -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* 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;
|
if (!node) return nullptr;
|
||||||
node->SetCommonVersion(PROTOCOL_VERSION);
|
node->SetCommonVersion(PROTOCOL_VERSION);
|
||||||
peerman.InitializeNode(*node, ServiceFlags(NODE_NETWORK | NODE_WITNESS));
|
peerman.InitializeNode(*node, ServiceFlags(NODE_NETWORK | NODE_WITNESS));
|
||||||
|
|
|
@ -71,6 +71,24 @@ struct ConnmanTestMsg : public CConnman {
|
||||||
m_nodes.clear();
|
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,
|
void Handshake(CNode& node,
|
||||||
bool successfully_connected,
|
bool successfully_connected,
|
||||||
ServiceFlags remote_services,
|
ServiceFlags remote_services,
|
||||||
|
@ -89,7 +107,7 @@ struct ConnmanTestMsg : public CConnman {
|
||||||
bool ReceiveMsgFrom(CNode& node, CSerializedNetMsg&& ser_msg) const;
|
bool ReceiveMsgFrom(CNode& node, CSerializedNetMsg&& ser_msg) const;
|
||||||
void FlushSendBuffer(CNode& node) 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)
|
CNode* ConnectNodePublic(PeerManager& peerman, const char* pszDest, ConnectionType conn_type)
|
||||||
EXCLUSIVE_LOCKS_REQUIRED(!m_unused_i2p_sessions_mutex);
|
EXCLUSIVE_LOCKS_REQUIRED(!m_unused_i2p_sessions_mutex);
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#include <script/interpreter.h>
|
#include <script/interpreter.h>
|
||||||
#include <test/util/script.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_CLEANSTACK && ~flags & (SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS)) return false;
|
||||||
if (flags & SCRIPT_VERIFY_WITNESS && ~flags & SCRIPT_VERIFY_P2SH) return false;
|
if (flags & SCRIPT_VERIFY_WITNESS && ~flags & SCRIPT_VERIFY_P2SH) return false;
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
#include <crypto/sha256.h>
|
#include <crypto/sha256.h>
|
||||||
#include <script/script.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 std::vector<uint8_t> WITNESS_STACK_ELEM_OP_TRUE{uint8_t{OP_TRUE}};
|
||||||
static const CScript P2WSH_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)}, {}};
|
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 */
|
/** 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
|
#endif // BITCOIN_TEST_UTIL_SCRIPT_H
|
||||||
|
|
|
@ -9,11 +9,16 @@
|
||||||
|
|
||||||
CThreadInterrupt::CThreadInterrupt() : flag(false) {}
|
CThreadInterrupt::CThreadInterrupt() : flag(false) {}
|
||||||
|
|
||||||
CThreadInterrupt::operator bool() const
|
bool CThreadInterrupt::interrupted() const
|
||||||
{
|
{
|
||||||
return flag.load(std::memory_order_acquire);
|
return flag.load(std::memory_order_acquire);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CThreadInterrupt::operator bool() const
|
||||||
|
{
|
||||||
|
return interrupted();
|
||||||
|
}
|
||||||
|
|
||||||
void CThreadInterrupt::reset()
|
void CThreadInterrupt::reset()
|
||||||
{
|
{
|
||||||
flag.store(false, std::memory_order_release);
|
flag.store(false, std::memory_order_release);
|
||||||
|
|
|
@ -27,11 +27,27 @@ class CThreadInterrupt
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using Clock = std::chrono::steady_clock;
|
using Clock = std::chrono::steady_clock;
|
||||||
|
|
||||||
CThreadInterrupt();
|
CThreadInterrupt();
|
||||||
explicit operator bool() const;
|
|
||||||
void operator()() EXCLUSIVE_LOCKS_REQUIRED(!mut);
|
virtual ~CThreadInterrupt() = default;
|
||||||
void reset();
|
|
||||||
bool sleep_for(Clock::duration rel_time) EXCLUSIVE_LOCKS_REQUIRED(!mut);
|
/// 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:
|
private:
|
||||||
std::condition_variable cond;
|
std::condition_variable cond;
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue