Compare commits

...

22 Commits

Author SHA1 Message Date
Will Clark 53a64bc0e6
Merge 8f6d0cc827 into b510893d00 2025-10-08 10:00:07 +01:00
will 8f6d0cc827
NOMERGE: freebsd, save a cache 2025-10-08 09:59:58 +01:00
will 8ed7cc4bc4
NOMERGE: disable a few tests 2025-10-08 09:59:56 +01:00
will dd7001ca27
ci: add freebsd systemlibs job 2025-10-08 09:59:08 +01:00
Ava Chow b510893d00
Merge bitcoin/bitcoin#33494: depends: Update URL for `qrencode` package source tarball
93a70a42d3 depends: Update URL for `qrencode` package source tarball (Hennadii Stepanov)
6de8051263 depends: Use hash instead of file name for package download stamp (Hennadii Stepanov)
46135d90ea depends: Drop redundant check for downloaded file (Hennadii Stepanov)
771978952a depends: Fix `$(package)_fetched` target (Hennadii Stepanov)

Pull request description:

  The https://fukuchi.org/ homepage no longer links to the source tarball, and previously available files appear to have been removed. The homepage now instructs users to download source tarballs from the GitHub [releases](https://github.com/fukuchi/libqrencode/releases) page instead.

  The diff between the source trees is immaterial:
  ```diff
  --- old
  +++ new
  @@ -1,19 +1,16 @@
   27e7deccd2925c94e4190ee64794a051199f215f145f76fd664cdebedbbf8a35  acinclude.m4
  -e1e35b1309482f699a9700a2065a0bce09c2108dd1f78ba7bfbe0f7f0bdcd2e6  aclocal.m4
   a9308eec78790720dbcd5452ab8f241b5f1c6939ccf3389917b8e78cb2b58c9e  autogen.sh
   aa36725d577048f0370dc7415a1acb578fbdfb531c1b384a836d9360a81f6f5c  bitstream.c
   3feaacd7d096834fc5956215598564ec287ad443185c4433c3f8007cc53ceaa6  bitstream.h
   21bd5a34c90d3d6ee540ceb48c3d5aea5f21bd6b829ef3112db832af0bd423d8  ChangeLog
   f8a7a94c9622fab721df47e8121533ebfcb79885aca01ecec2fff00dfb84caef  cmake/FindIconv.cmake
   6345e7eecb92473f361a8eb98dd373aa09cae79a43408cf4b42b00b411c9c197  CMakeLists.txt
  -031d560570eab2eda57c2f9ee9952445002f8bf4a23965fcaf43bbc2c61590e2  config.h.in
  -d2f42cc5771b69f2d2ecd4b31509864ae2b18b25c823986390bb372ee07030fa  configure
   02867a8ea08206c84d5f4c05f41a15c639291091e3dfac27f3a9029d8f5d3028  configure.ac
   a9bdde5616ecdd1e980b44f360600ee8783b1f99b8cc83a2beb163a0a390e861  COPYING
   76c41754bccbf69a60fb7833776637c60b86f59104705c0a5cea9ee3a2968f3d  Doxyfile
   36d84f714cf28397b02d6c44860106a7cb858fc6d25239a2698a72fa5136e5c3  libqrencode.pc.in
   f0ce93a7e1b1f0fab87dd071ec3c8dd80a567d778dfc5930d9f375d676ecb9a0  Makefile.am
  -507c2385fb49c5724e8e3dfca97feb24cbdd4e651f3f0bfa62524e60088091a0  Makefile.in
  +dcb782b1b382328c0bce9194944bdcc65a6035d8e9f89e39436ed2e55ae8b969  makeREADME.sh
   6046d347c6c564fc13a24dc0a15a09a83023e00a4e0d0f23029a81f86ac4d024  mask.c
   9f853cee7d72191a8dbf018b7a86c0f0b6ca661e27a51fab677af911f2ff9e7e  mask.h
   a4e17b68d8db573e152132ebcbdc837b55415c12027f81232662db645faf79f0  mmask.c
  @@ -30,7 +27,7 @@
   6e9ff66002b4a839c6e78bcd6a55342d9eb8b289273fa838441b27ee9969e293  qrinput.h
   68831e02ee1ba602b1937328abec000e616c4472d9dc40067dd45ab7072df172  qrspec.c
   a2a9a5af4d62015e82b48b8316aea2b70031dcdc1ed2b829c0102ea5dc02aca2  qrspec.h
  -8730d006f1d45b90dc0ef9a20e4119420f15b37a09483c929baa4225e21f7900  README
  +a56773b55989ea5cae8a43f2d845ce0afa9576a26170937fbe36a69fee953cd4  README.md
   ace480f2e16001e276c73a5e965c282915ad81e2c28cce3ef574b5a8db7210e8  rsecc.c
   c731ebe26d58d5e5df3b2d694de0fb1c4ae80a36cf0559c49b04e989dee8b182  rsecc.h
   8ed1af4414b5628845519581c82bf51ba2b4dee1f8352c1fd01b50afcd0a0ed7  split.c
  @@ -46,7 +43,6 @@
   e26b20198a7393b3c060891876fa45edb81488aef9df6d6cf45893a605e5e5e4  tests/decoder.h
   adabfbddb0f25de2e2cae970195fcfdf11ad1fa66ce64e237d83f821346f64c4  tests/frame
   23c283a3d3b5f1bbb3108603ebf05d7a95951ba86a288e09140eab612a5eb258  tests/Makefile.am
  -c8b819bf7f00c979ab0b6f0d0fb10289d2006bc6acda1737d2f1c383a60e1e66  tests/Makefile.in
   ebd71b937d4d39f382f8c57f362a01f11fd617b66dbdf6f1a3c4897c8c42e235  tests/prof_qrencode.c
   d4adcb234d4c31473cd9ffedd1bfa9645ba336d426640ba5893dfe6e75db171d  tests/pthread_qrencode.c
   62298641504b0a2c1d199cd7f656cb376959200169042de76f7c5950d2d42395  tests/rscode.c
  @@ -63,6 +59,7 @@
   cf5792cbfb92ba46f7f5f14b98f00813b0e7e4f5e7c790c6a28793774474bf26  tests/test_monkey.c
   3a2c58346d57f6bb2a634d6febf3c65ac524259a2d789657f8d60c678bf8d658  tests/test_mqrspec.c
   b9d8c569ba36a2258cb1ad0d1f85ce4fb2935fad519e902bade59aa9772321aa  tests/test_qrencode.c
  +785fe14a6f8bc096b20ec271771fb09f22f29eb4f9d729f5b40d6b4cc824ce36  tests/test_qrenc.sh
   d0eee6eddf98ee4595c07f7da40c7de548651bf839b26995756e94db2599451f  tests/test_qrinput.c
   ace7885e435ef77cc127da0ac23c724498aaa8d80d53b908063f79c9f0b7acce  tests/test_qrspec.c
   fde9c2735ce94be51e1b0bbffe65415aa3afd2da5bd4c0e2c5e50e1a2f1ea3f7  tests/test_rs.c
  @@ -71,12 +68,4 @@
   6f35c0e1235b31d0068c4ab175d8110c736e60df0309d4be7b3e57dd62d316f6  tests/URI_testset.inc
   6be3983fc397cd5dade1dd219ad6cbe7977f416410b1509984006ecec51605b5  tests/view_qrcode.c
   92b5be1ca2239399232d51503715c848dae9bf3db71b1f03157bfa9779826910  TODO
  -c8af04e62bad4ab75dafd22119026e5e3943f385bdcbe7731a4938102453754c  use/compile
  -1d9048b0ac9d4d1dfce7aa4e3a0b59ccfd32db2f7693814aa6f4c778560f5669  use/config.guess
   b522487f9c47661d321367d133f3d41247dd16d435f2d4b9c643dee95bf65eee  use/config.rpath
  -5bf0da2576ebb21ab60a9d9291a85b40af0e956a9eafb709ca8b20dcb105f4ee  use/config.sub
  -732bcd6b9e23f241e015d71b0a3a862104053aba20718c1f56b292cee7e29371  use/depcomp
  -608b76d735bb2ec2bcb1271644c3d5e7a428fb8d2338e114e8a48ebf91ccfd23  use/install-sh
  -2304d53af1f63b76a11651efdd18578adf2bda1ffc2c257100cba374b55f284b  use/ltmain.sh
  -f038345dab184e538098d22a8edc423762da66a90ebe269f23bfef85287cd30c  use/missing
  -7c1ae35455771ae32050c2ed109e3d297160b6d1a2f70b0278cf6968e5e7e98c  use/test-driver
  ```

  ---

  **UPDATE 2025-09-30**

  A few commits have been added:

  1. The first commit fixes the `$(package)_fetched` target, which erroneously succeeds on the second run after a failure on the master branch:
  ```
  $ gmake -C depends clean-all
  $ gmake -C depends qrencode_fetched FALLBACK_DOWNLOAD_PATH="https://fallback.invalid"
  $ gmake -C depends qrencode_fetched FALLBACK_DOWNLOAD_PATH="https://fallback.invalid"
  $ echo $?
  0
  ```
  With the first commit applied:
  ```
  $ gmake -C depends clean-all
  $ gmake -C depends qrencode_fetched FALLBACK_DOWNLOAD_PATH="https://fallback.invalid"
  $ gmake -C depends qrencode_fetched FALLBACK_DOWNLOAD_PATH="https://fallback.invalid"
  $ echo $?
  2
  ```

  2. The second and third commits allow the depends build subsystem to detect when the source tarball content has been modified and needs to be re-downloaded, even if the file name remains the same.

ACKs for top commit:
  m3dwards:
    ACK 93a70a42d3
  achow101:
    ACK 93a70a42d3
  vasild:
    ACK 93a70a42d3
  janb84:
    ACK 93a70a42d3

Tree-SHA512: 38b7c029070426196c747fc45c9d00bae534eeeb2d9cd9f221580fce8380f4f8aecb6c48b2563e322edd8c9534f5dd42d8f4e110ada42bb83568cf2dcfb7dc22
2025-10-07 16:57:58 -07:00
Hennadii Stepanov ec5841888d
Merge bitcoin/bitcoin#32513: ci: remove 3rd party js from windows dll gha job
156927903d ci: Check windows manifests for all executables (Max Edwards)
e1a1b14c93 ci: use a more generic way of finding mt.exe (Max Edwards)
7ae0497eef ci: remove 3rd party js from windows dll gha job (Max Edwards)

Pull request description:

  The windows job uses the external dependency `ilammy/msvc-dev-cmd` which runs javascript. We use this to put various tools on the path such as `MSBuild.exe` and `mt.exe`. We can remove this dependency and use `vswhere.exe` directly to find these tools and create a "[Developer command prompt](https://github.com/microsoft/vswhere/wiki/Start-Developer-Command-Prompt#using-powershell)" as someone would on their dev machine.

  While in this area of the code, this PR also runs some additional manifest checks on the windows binaries.

  Fixes: #32508

ACKs for top commit:
  davidgumberg:
    crACK 156927903d
  hebasto:
    ACK 156927903d.

Tree-SHA512: df640dff27579a1c95daddc5a5ba8fd655bbd0a6f2aff74d0f63439c7185c0b18a90abfee3f1f032fe833cd19b822ef71812f44b24c4c044222e46d01c271864
2025-10-08 00:44:05 +01:00
Ava Chow d735e2e9b3
Merge bitcoin/bitcoin#32998: Bump SCRIPT_VERIFY flags to 64 bit
652424ad16 test: additional test coverage for script_verify_flags (Anthony Towns)
417437eb01 script/verify_flags: extend script_verify_flags to 64 bits (Anthony Towns)
3cbbcb66ef script/interpreter: make script_verify_flag_name an ordinary enum (Anthony Towns)
bddcadee82 script/verify_flags: make script_verify_flags type safe (Anthony Towns)
a5ead122fe script/interpreter: introduce script_verify_flags typename (Anthony Towns)
4577fb2b1e rpc: have getdeploymentinfo report script verify flags (Anthony Towns)
a3986935f0 validation: export GetBlockScriptFlags() (Anthony Towns)
5db8cd2d37 Move mapFlagNames and FormatScriptFlags logic to script/interpreter.h (Anthony Towns)

Pull request description:

  We currently use 21 of 32 possible bits for `SCRIPT_VERIFY_*` flags, with open PRs that may use 8 more (#29247, #31989, #32247, #32453). The mutinynet fork that has included many experimental soft fork features is [already reusing bits here](d4a86277ed/src/script/interpreter.h (L175-L195)). Therefore, bump this to 64 bits.

  In order to make it easier to update this logic in future, this PR also introduces a dedicated type for the script flags, and disables implicit conversion between that type and the underlying integer type. To make verifying that this change doesn't cause flags to disappear, this PR also resurrects the changes from #28806 so that the script flags that are consensus enforced on each block can be queried via getdeploymentinfo.

ACKs for top commit:
  instagibbs:
    reACK 652424ad16
  achow101:
    ACK 652424ad16
  darosior:
    ACK 652424ad16
  theStack:
    Code-review ACK 652424ad16 🎏

Tree-SHA512: 7b30152196cdfdef8b9700b571b7d7d4e94d28fbc5c26ea7532788037efc02e4b1d8de392b0b20507badfdc26f5c125f8356a479604a9149b8aae23a7cf5549f
2025-10-07 14:51:22 -07:00
Max Edwards 156927903d ci: Check windows manifests for all executables
The other executables have manifests and these should be checked in
addition to bitcoind. Skipping fuzz.exe, bench_bitcoin.exe and
test_bitcoin-qt.exe as they do not have manifests.
2025-10-02 15:13:29 +01:00
Max Edwards e1a1b14c93 ci: use a more generic way of finding mt.exe
This sets up a vs developer command prompt and should hopefully should
be more resilient to upstream changes

Co-authored-by: David Gumberg <davidzgumberg@gmail.com>
2025-10-02 15:13:26 +01:00
Hennadii Stepanov 93a70a42d3
depends: Update URL for `qrencode` package source tarball
The https://fukuchi.org/ homepage no longer links to the source tarball,
and previously available files appear to have been removed. The homepage
now instructs users to download source tarballs from the GitHub releases
page instead.

The diff between the source trees is immaterial.
2025-09-30 11:26:47 +01:00
Hennadii Stepanov 6de8051263
depends: Use hash instead of file name for package download stamp
The package version is still included for convenience.
2025-09-30 11:26:29 +01:00
Hennadii Stepanov 46135d90ea
depends: Drop redundant check for downloaded file
The `fetch_file` commands are invoked for the `$($(package)_fetched)`
target, so the existence of the download stamp has already been tested.
2025-09-30 11:22:50 +01:00
Hennadii Stepanov 771978952a
depends: Fix `$(package)_fetched` target
Ensure the download timestamp is created only after a successful
download.
2025-09-30 11:20:12 +01:00
Max Edwards 7ae0497eef ci: remove 3rd party js from windows dll gha job
We can use vswhere.exe directly to create a vs developer
prompt and so can remove this third party dependency.

Co-authored-by: David Gumberg <davidzgumberg@gmail.com>
2025-09-25 18:12:02 +01:00
Anthony Towns 652424ad16 test: additional test coverage for script_verify_flags 2025-09-11 11:24:09 +10:00
Anthony Towns 417437eb01 script/verify_flags: extend script_verify_flags to 64 bits 2025-08-14 10:17:32 +10:00
Anthony Towns 3cbbcb66ef script/interpreter: make script_verify_flag_name an ordinary enum
Instead of having `SCRIPT_VERIFY_FOO = (1U << n)` just have it
be `n` directly, and do the bit shifting when converting it to
`script_verify_flags`.
2025-08-14 10:17:32 +10:00
Anthony Towns bddcadee82 script/verify_flags: make script_verify_flags type safe
`using script_verify_flags = uint32_t` allows implicit conversion to
and from int, so replace it with a class to have the compiler ensure we
use the correct type. Provide from_int and as_int to allow for explicit
conversions when desired.

Introduces the type `script_verify_flag_name` for the individual flag
name enumeration.
2025-08-14 10:17:32 +10:00
Anthony Towns a5ead122fe script/interpreter: introduce script_verify_flags typename
Previously the SCRIPT_VERIFY_* flags were specified as either uint32_t,
unsigned int, or unsigned. This converts them to a common type alias in
preparation for changing the underlying type.
2025-08-14 10:17:32 +10:00
Anthony Towns 4577fb2b1e rpc: have getdeploymentinfo report script verify flags 2025-08-14 10:17:32 +10:00
Anthony Towns a3986935f0 validation: export GetBlockScriptFlags() 2025-08-14 10:17:32 +10:00
Anthony Towns 5db8cd2d37 Move mapFlagNames and FormatScriptFlags logic to script/interpreter.h
Moves FormatScriptFlags logic into GetScriptFlagNames which returns a
vector of strings. For completeness, also has GetScriptFlagNames report
on any bits that do not match a known script flag.
2025-08-14 10:17:30 +10:00
31 changed files with 767 additions and 525 deletions

View File

@ -186,379 +186,482 @@ jobs:
# https://github.com/actions/cache/blob/main/tips-and-workarounds.md#update-a-cache
key: ${{ github.job }}-${{ matrix.job-type }}-ccache-${{ github.run_id }}
windows-native-dll:
name: ${{ matrix.job-name }}
runs-on: windows-2022
# windows-native-dll:
# name: ${{ matrix.job-name }}
# runs-on: windows-2022
#
# if: ${{ vars.SKIP_BRANCH_PUSH != 'true' || github.event_name == 'pull_request' }}
#
# env:
# PYTHONUTF8: 1
# TEST_RUNNER_TIMEOUT_FACTOR: 40
#
# strategy:
# fail-fast: false
# matrix:
# job-type: [standard, fuzz]
# include:
# - job-type: standard
# generate-options: '-DBUILD_GUI=ON -DWITH_ZMQ=ON -DBUILD_BENCH=ON -DWERROR=ON'
# job-name: 'Windows native, VS 2022'
# - job-type: fuzz
# generate-options: '-DVCPKG_MANIFEST_NO_DEFAULT_FEATURES=ON -DVCPKG_MANIFEST_FEATURES="wallet" -DBUILD_GUI=OFF -DBUILD_FOR_FUZZING=ON -DWERROR=ON'
# job-name: 'Windows native, fuzz, VS 2022'
#
# steps:
# - *CHECKOUT
#
# - &SET_UP_VS
# name: Set up VS Developer Prompt
# shell: pwsh -Command "$PSVersionTable; $PSNativeCommandUseErrorActionPreference = $true; $ErrorActionPreference = 'Stop'; & '{0}'"
# run: |
# $vswherePath = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
# $installationPath = & $vswherePath -latest -property installationPath
# & "${env:COMSPEC}" /s /c "`"$installationPath\Common7\Tools\vsdevcmd.bat`" -arch=x64 -no_logo && set" | foreach-object {
# $name, $value = $_ -split '=', 2
# echo "$name=$value" >> $env:GITHUB_ENV
# }
#
# - name: Get tool information
# shell: pwsh
# run: |
# cmake -version | Tee-Object -FilePath "cmake_version"
# Write-Output "---"
# msbuild -version | Tee-Object -FilePath "msbuild_version"
# $env:VCToolsVersion | Tee-Object -FilePath "toolset_version"
# py -3 --version
# Write-Host "PowerShell version $($PSVersionTable.PSVersion.ToString())"
# bash --version
#
# - name: Using vcpkg with MSBuild
# run: |
# echo "set(VCPKG_BUILD_TYPE release)" >> "${VCPKG_INSTALLATION_ROOT}/triplets/x64-windows.cmake"
# # Workaround for libevent, which requires CMake 3.1 but is incompatible with CMake >= 4.0.
# sed -i '1s/^/set(ENV{CMAKE_POLICY_VERSION_MINIMUM} 3.5)\n/' "${VCPKG_INSTALLATION_ROOT}/scripts/ports.cmake"
#
# - name: vcpkg tools cache
# uses: actions/cache@v4
# with:
# path: C:/vcpkg/downloads/tools
# key: ${{ github.job }}-vcpkg-tools
#
# - name: Restore vcpkg binary cache
# uses: actions/cache/restore@v4
# id: vcpkg-binary-cache
# with:
# path: ~/AppData/Local/vcpkg/archives
# key: ${{ github.job }}-vcpkg-binary-${{ hashFiles('cmake_version', 'msbuild_version', 'toolset_version', 'vcpkg.json') }}
#
# - name: Generate build system
# run: |
# cmake -B build -Werror=dev --preset vs2022 -DCMAKE_TOOLCHAIN_FILE="${VCPKG_INSTALLATION_ROOT}/scripts/buildsystems/vcpkg.cmake" ${{ matrix.generate-options }}
#
# - name: Save vcpkg binary cache
# uses: actions/cache/save@v4
# if: github.event_name != 'pull_request' && steps.vcpkg-binary-cache.outputs.cache-hit != 'true' && matrix.job-type == 'standard'
# with:
# path: ~/AppData/Local/vcpkg/archives
# key: ${{ github.job }}-vcpkg-binary-${{ hashFiles('cmake_version', 'msbuild_version', 'toolset_version', 'vcpkg.json') }}
#
# - name: Build
# working-directory: build
# run: |
# cmake --build . -j $NUMBER_OF_PROCESSORS --config Release
#
# - name: Check executable manifests
# if: matrix.job-type == 'standard'
# working-directory: build
# shell: pwsh -Command "$PSVersionTable; $PSNativeCommandUseErrorActionPreference = $true; $ErrorActionPreference = 'Stop'; & '{0}'"
# run: |
# mt.exe -nologo -inputresource:bin\Release\bitcoind.exe -out:bitcoind.manifest
# Get-Content bitcoind.manifest
#
# Get-ChildItem -Filter "bin\Release\*.exe" | ForEach-Object {
# $exeName = $_.Name
#
# # Skip as they currently do not have manifests
# if ($exeName -eq "fuzz.exe" -or $exeName -eq "bench_bitcoin.exe" -or $exeName -eq "test_bitcoin-qt.exe") {
# Write-Host "Skipping $exeName (no manifest present)"
# return
# }
#
# Write-Host "Checking $exeName"
# & mt.exe -nologo -inputresource:$_.FullName -validate_manifest
# }
#
# - name: Run test suite
# if: matrix.job-type == 'standard'
# working-directory: build
# env:
# QT_PLUGIN_PATH: '${{ github.workspace }}\build\vcpkg_installed\x64-windows\Qt6\plugins'
# run: |
# ctest --output-on-failure --stop-on-failure -j $NUMBER_OF_PROCESSORS -C Release
#
# - name: Run functional tests
# if: matrix.job-type == 'standard'
# working-directory: build
# env:
# BITCOIN_BIN: '${{ github.workspace }}\build\bin\Release\bitcoin.exe'
# BITCOIND: '${{ github.workspace }}\build\bin\Release\bitcoind.exe'
# BITCOINCLI: '${{ github.workspace }}\build\bin\Release\bitcoin-cli.exe'
# BITCOINTX: '${{ github.workspace }}\build\bin\Release\bitcoin-tx.exe'
# BITCOINUTIL: '${{ github.workspace }}\build\bin\Release\bitcoin-util.exe'
# BITCOINWALLET: '${{ github.workspace }}\build\bin\Release\bitcoin-wallet.exe'
# TEST_RUNNER_EXTRA: ${{ github.event_name != 'pull_request' && '--extended' || '' }}
# run: py -3 test/functional/test_runner.py --jobs $NUMBER_OF_PROCESSORS --ci --quiet --tmpdirprefix="${RUNNER_TEMP}" --combinedlogslen=99999999 --timeout-factor=${TEST_RUNNER_TIMEOUT_FACTOR} ${TEST_RUNNER_EXTRA}
#
# - name: Clone corpora
# if: matrix.job-type == 'fuzz'
# run: |
# git clone --depth=1 https://github.com/bitcoin-core/qa-assets "${RUNNER_TEMP}/qa-assets"
# cd "${RUNNER_TEMP}/qa-assets"
# echo "Using qa-assets repo from commit ..."
# git log -1
#
# - name: Run fuzz tests
# if: matrix.job-type == 'fuzz'
# working-directory: build
# env:
# BITCOINFUZZ: '${{ github.workspace }}\build\bin\Release\fuzz.exe'
# run: |
# py -3 test/fuzz/test_runner.py --par $NUMBER_OF_PROCESSORS --loglevel DEBUG "${RUNNER_TEMP}/qa-assets/fuzz_corpora"
#
# windows-cross:
# name: 'Linux->Windows cross, no tests'
# needs: runners
# 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' }}
#
# env:
# FILE_ENV: './ci/test/00_setup_env_win64.sh'
# DANGER_CI_ON_HOST_FOLDERS: 1
#
# steps:
# - *CHECKOUT
#
# - name: Configure environment
# uses: ./.github/actions/configure-environment
#
# - name: Restore caches
# id: restore-cache
# uses: ./.github/actions/restore-caches
#
# - name: Configure Docker
# uses: ./.github/actions/configure-docker
# with:
# cache-provider: ${{ needs.runners.outputs.provider }}
#
# - name: CI script
# run: ./ci/test_run_all.sh
#
# - name: Save caches
# uses: ./.github/actions/save-caches
#
# - name: Upload built executables
# uses: actions/upload-artifact@v4
# with:
# name: x86_64-w64-mingw32-executables-${{ github.run_id }}
# path: |
# ${{ env.BASE_BUILD_DIR }}/bin/*.exe
# ${{ env.BASE_BUILD_DIR }}/src/secp256k1/bin/*.exe
# ${{ env.BASE_BUILD_DIR }}/src/univalue/*.exe
# ${{ env.BASE_BUILD_DIR }}/test/config.ini
#
# windows-native-test:
# name: 'Windows, test cross-built'
# runs-on: windows-2022
# needs: windows-cross
#
# env:
# PYTHONUTF8: 1
# TEST_RUNNER_TIMEOUT_FACTOR: 40
#
# steps:
# - *CHECKOUT
#
# - name: Download built executables
# uses: actions/download-artifact@v4
# with:
# name: x86_64-w64-mingw32-executables-${{ github.run_id }}
#
# - name: Run bitcoind.exe
# run: ./bin/bitcoind.exe -version
#
# - *SET_UP_VS
#
# - name: Check executable manifests
# shell: pwsh -Command "$PSVersionTable; $PSNativeCommandUseErrorActionPreference = $true; $ErrorActionPreference = 'Stop'; & '{0}'"
# run: |
# mt.exe -nologo -inputresource:bin\bitcoind.exe -out:bitcoind.manifest
# Get-Content bitcoind.manifest
#
# Get-ChildItem -Filter "bin\*.exe" | ForEach-Object {
# $exeName = $_.Name
#
# # Skip as they currently do not have manifests
# if ($exeName -eq "fuzz.exe" -or $exeName -eq "bench_bitcoin.exe") {
# Write-Host "Skipping $exeName (no manifest present)"
# return
# }
#
# Write-Host "Checking $exeName"
# & mt.exe -nologo -inputresource:$_.FullName -validate_manifest
# }
#
# - name: Run unit tests
# # Can't use ctest here like other jobs as we don't have a CMake build tree.
# run: |
# ./bin/test_bitcoin.exe -l test_suite # Intentionally run sequentially here, to catch test case failures caused by dirty global state from prior test cases.
# ./src/secp256k1/bin/exhaustive_tests.exe
# ./src/secp256k1/bin/noverify_tests.exe
# ./src/secp256k1/bin/tests.exe
# ./src/univalue/object.exe
# ./src/univalue/unitester.exe
#
# - name: Run benchmarks
# run: ./bin/bench_bitcoin.exe -sanity-check
#
# - name: Adjust paths in test/config.ini
# shell: pwsh
# run: |
# (Get-Content "test/config.ini") -replace '(?<=^SRCDIR=).*', '${{ github.workspace }}' -replace '(?<=^BUILDDIR=).*', '${{ github.workspace }}' -replace '(?<=^RPCAUTH=).*', '${{ github.workspace }}/share/rpcauth/rpcauth.py' | Set-Content "test/config.ini"
# Get-Content "test/config.ini"
#
# - name: Set previous release directory
# run: |
# echo "PREVIOUS_RELEASES_DIR=${{ runner.temp }}/previous_releases" >> "$GITHUB_ENV"
#
# - name: Get previous releases
# working-directory: test
# run: ./get_previous_releases.py --target-dir $PREVIOUS_RELEASES_DIR
#
# - name: Run functional tests
# env:
# # TODO: Fix the excluded test and re-enable it.
# # feature_unsupported_utxo_db.py fails on windows because of emojis in the test data directory
# EXCLUDE: '--exclude wallet_multiwallet.py,feature_unsupported_utxo_db.py'
# TEST_RUNNER_EXTRA: ${{ github.event_name != 'pull_request' && '--extended' || '' }}
# run: py -3 test/functional/test_runner.py --jobs $NUMBER_OF_PROCESSORS --ci --quiet --tmpdirprefix="$RUNNER_TEMP" --combinedlogslen=99999999 --timeout-factor=$TEST_RUNNER_TIMEOUT_FACTOR $EXCLUDE $TEST_RUNNER_EXTRA
if: ${{ vars.SKIP_BRANCH_PUSH != 'true' || github.event_name == 'pull_request' }}
env:
PYTHONUTF8: 1
TEST_RUNNER_TIMEOUT_FACTOR: 40
strategy:
fail-fast: false
matrix:
job-type: [standard, fuzz]
include:
- job-type: standard
generate-options: '-DBUILD_GUI=ON -DWITH_ZMQ=ON -DBUILD_BENCH=ON -DWERROR=ON'
job-name: 'Windows native, VS 2022'
- job-type: fuzz
generate-options: '-DVCPKG_MANIFEST_NO_DEFAULT_FEATURES=ON -DVCPKG_MANIFEST_FEATURES="wallet" -DBUILD_GUI=OFF -DBUILD_FOR_FUZZING=ON -DWERROR=ON'
job-name: 'Windows native, fuzz, VS 2022'
freebsd-syslibs:
name: 'FreeBSD: system libs, no GUI'
needs: runners
runs-on: ${{ needs.runners.outputs.use-cirrus-runners == 'true' && 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-md' || 'ubuntu-latest' }}
defaults:
run:
shell: freebsd {0}
steps:
- *CHECKOUT
- name: Configure Developer Command Prompt for Microsoft Visual C++
# Using microsoft/setup-msbuild is not enough.
uses: ilammy/msvc-dev-cmd@v1
with:
arch: x64
- name: Get tool information
shell: pwsh
- name: Setup Ccache directory
shell: bash
run: |
cmake -version | Tee-Object -FilePath "cmake_version"
Write-Output "---"
msbuild -version | Tee-Object -FilePath "msbuild_version"
$env:VCToolsVersion | Tee-Object -FilePath "toolset_version"
py -3 --version
Write-Host "PowerShell version $($PSVersionTable.PSVersion.ToString())"
bash --version
export CCACHE_DIR=${{ github.workspace }}/.ccache
echo "CCACHE_DIR=$CCACHE_DIR" >> "$GITHUB_ENV"
mkdir -p "$CCACHE_DIR"
- name: Using vcpkg with MSBuild
- name: Restore ccache
uses: cirruslabs/cache/restore@v4
with:
path: ${{ env.CCACHE_DIR }}
key: ccache-${{ github.job }}-${{ github.run_id }}
restore-keys: ccache-${{ github.job }}-
- name: Speed up VM install
shell: bash
run: |
echo "set(VCPKG_BUILD_TYPE release)" >> "${VCPKG_INSTALLATION_ROOT}/triplets/x64-windows.cmake"
# Workaround for libevent, which requires CMake 3.1 but is incompatible with CMake >= 4.0.
sed -i '1s/^/set(ENV{CMAKE_POLICY_VERSION_MINIMUM} 3.5)\n/' "${VCPKG_INSTALLATION_ROOT}/scripts/ports.cmake"
# Updating man-db can be slow
echo "set man-db/auto-update false" | sudo debconf-communicate; sudo dpkg-reconfigure man-db
- name: vcpkg tools cache
uses: actions/cache@v4
- name: Start FreeBSD VM
uses: vmactions/freebsd-vm@v1
with:
path: C:/vcpkg/downloads/tools
key: ${{ github.job }}-vcpkg-tools
- name: Restore vcpkg binary cache
uses: actions/cache/restore@v4
id: vcpkg-binary-cache
with:
path: ~/AppData/Local/vcpkg/archives
key: ${{ github.job }}-vcpkg-binary-${{ hashFiles('cmake_version', 'msbuild_version', 'toolset_version', 'vcpkg.json') }}
envs: 'CCACHE_DIR'
prepare: pkg install -y cmake-core ninja git pkgconf boost-libs libevent sqlite3 capnproto libzmq4 python3 net/py-pyzmq databases/py-sqlite3 ccache
run: git config --global --add safe.directory ${{ github.workspace }}
sync: 'nfs' # nfs is auto-synced and allows ccache save at the end of the run
- name: Generate buildsystem
env:
CMAKE_GENERATOR: 'Ninja'
run: |
cmake -B build -Werror=dev --preset vs2022 -DCMAKE_TOOLCHAIN_FILE="${VCPKG_INSTALLATION_ROOT}/scripts/buildsystems/vcpkg.cmake" ${{ matrix.generate-options }}
- name: Save vcpkg binary cache
uses: actions/cache/save@v4
if: github.event_name != 'pull_request' && steps.vcpkg-binary-cache.outputs.cache-hit != 'true' && matrix.job-type == 'standard'
with:
path: ~/AppData/Local/vcpkg/archives
key: ${{ github.job }}-vcpkg-binary-${{ hashFiles('cmake_version', 'msbuild_version', 'toolset_version', 'vcpkg.json') }}
cd ${{ github.workspace }}
cmake -B build -DWITH_ZMQ=ON -DBUILD_BENCH=ON -DWERROR=ON -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
- name: Build
working-directory: build
run: |
cmake --build . -j $NUMBER_OF_PROCESSORS --config Release
echo "CCACHE_DIR=$CCACHE_DIR"
ccache -s
ccache -z
cmake --build ${{ github.workspace }}/build -j$(nproc)
ccache -s
- name: Get bitcoind manifest
if: matrix.job-type == 'standard'
working-directory: build
- name: Check 'bitcoind' executable
run: |
mt.exe -nologo -inputresource:bin/Release/bitcoind.exe -out:bitcoind.manifest
cat bitcoind.manifest
echo
mt.exe -nologo -inputresource:bin/Release/bitcoind.exe -validate_manifest
set -e
cd ${{ github.workspace }}
ls -l build/bin/bitcoind
file build/bin/bitcoind
ldd build/bin/bitcoind
./build/bin/bitcoind -version
- name: Run test suite
if: matrix.job-type == 'standard'
working-directory: build
env:
QT_PLUGIN_PATH: '${{ github.workspace }}\build\vcpkg_installed\x64-windows\Qt6\plugins'
run: |
ctest --output-on-failure --stop-on-failure -j $NUMBER_OF_PROCESSORS -C Release
cmake -E env ctest --test-dir ${{ github.workspace }}/build -j $(nproc) --output-on-failure
- name: Run functional tests
if: matrix.job-type == 'standard'
working-directory: build
env:
BITCOIN_BIN: '${{ github.workspace }}\build\bin\Release\bitcoin.exe'
BITCOIND: '${{ github.workspace }}\build\bin\Release\bitcoind.exe'
BITCOINCLI: '${{ github.workspace }}\build\bin\Release\bitcoin-cli.exe'
BITCOINTX: '${{ github.workspace }}\build\bin\Release\bitcoin-tx.exe'
BITCOINUTIL: '${{ github.workspace }}\build\bin\Release\bitcoin-util.exe'
BITCOINWALLET: '${{ github.workspace }}\build\bin\Release\bitcoin-wallet.exe'
TEST_RUNNER_EXTRA: ${{ github.event_name != 'pull_request' && '--extended' || '' }}
run: py -3 test/functional/test_runner.py --jobs $NUMBER_OF_PROCESSORS --ci --quiet --tmpdirprefix="${RUNNER_TEMP}" --combinedlogslen=99999999 --timeout-factor=${TEST_RUNNER_TIMEOUT_FACTOR} ${TEST_RUNNER_EXTRA}
- name: Clone corpora
if: matrix.job-type == 'fuzz'
run: |
git clone --depth=1 https://github.com/bitcoin-core/qa-assets "${RUNNER_TEMP}/qa-assets"
cd "${RUNNER_TEMP}/qa-assets"
echo "Using qa-assets repo from commit ..."
git log -1
cd ${{ github.workspace }}
./build/test/functional/test_runner.py --ci --extended -j $(nproc) --combinedlogslen=99999999 --quiet --timeout-factor=8 --tmpdirprefix=/tmp --cachedir=/tmp/test_cache
- name: Run fuzz tests
if: matrix.job-type == 'fuzz'
working-directory: build
env:
BITCOINFUZZ: '${{ github.workspace }}\build\bin\Release\fuzz.exe'
run: |
py -3 test/fuzz/test_runner.py --par $NUMBER_OF_PROCESSORS --loglevel DEBUG "${RUNNER_TEMP}/qa-assets/fuzz_corpora"
windows-cross:
name: 'Linux->Windows cross, no tests'
needs: runners
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' }}
env:
FILE_ENV: './ci/test/00_setup_env_win64.sh'
DANGER_CI_ON_HOST_FOLDERS: 1
steps:
- *CHECKOUT
- name: Configure environment
uses: ./.github/actions/configure-environment
- name: Restore caches
id: restore-cache
uses: ./.github/actions/restore-caches
- name: Configure Docker
uses: ./.github/actions/configure-docker
- name: Save ccache
uses: cirruslabs/cache/save@v4
# if: ${{ (github.event_name == 'push') && (github.ref_name == github.event.repository.default_branch) }}
with:
cache-provider: ${{ needs.runners.outputs.provider }}
path: ${{ env.CCACHE_DIR }}
key: ccache-${{ github.job }}-${{ github.run_id }}
- name: CI script
run: ./ci/test_run_all.sh
- name: Save caches
uses: ./.github/actions/save-caches
- name: Upload built executables
uses: actions/upload-artifact@v4
with:
name: x86_64-w64-mingw32-executables-${{ github.run_id }}
path: |
${{ env.BASE_BUILD_DIR }}/bin/*.exe
${{ env.BASE_BUILD_DIR }}/src/secp256k1/bin/*.exe
${{ env.BASE_BUILD_DIR }}/src/univalue/*.exe
${{ env.BASE_BUILD_DIR }}/test/config.ini
windows-native-test:
name: 'Windows, test cross-built'
runs-on: windows-2022
needs: windows-cross
env:
PYTHONUTF8: 1
TEST_RUNNER_TIMEOUT_FACTOR: 40
steps:
- *CHECKOUT
- name: Download built executables
uses: actions/download-artifact@v4
with:
name: x86_64-w64-mingw32-executables-${{ github.run_id }}
- name: Run bitcoind.exe
run: ./bin/bitcoind.exe -version
- name: Find mt.exe tool
shell: pwsh
run: |
$sdk_dir = (Get-ItemProperty 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows Kits\Installed Roots' -Name KitsRoot10).KitsRoot10
$sdk_latest = (Get-ChildItem "$sdk_dir\bin" -Directory | Where-Object { $_.Name -match '^\d+\.\d+\.\d+\.\d+$' } | Sort-Object Name -Descending | Select-Object -First 1).Name
"MT_EXE=${sdk_dir}bin\${sdk_latest}\x64\mt.exe" >> $env:GITHUB_ENV
- name: Get bitcoind manifest
shell: pwsh
run: |
& $env:MT_EXE -nologo -inputresource:bin\bitcoind.exe -out:bitcoind.manifest
Get-Content bitcoind.manifest
& $env:MT_EXE -nologo -inputresource:bin\bitcoind.exe -validate_manifest
- name: Run unit tests
# Can't use ctest here like other jobs as we don't have a CMake build tree.
run: |
./bin/test_bitcoin.exe -l test_suite # Intentionally run sequentially here, to catch test case failures caused by dirty global state from prior test cases.
./src/secp256k1/bin/exhaustive_tests.exe
./src/secp256k1/bin/noverify_tests.exe
./src/secp256k1/bin/tests.exe
./src/univalue/object.exe
./src/univalue/unitester.exe
- name: Run benchmarks
run: ./bin/bench_bitcoin.exe -sanity-check
- name: Adjust paths in test/config.ini
shell: pwsh
run: |
(Get-Content "test/config.ini") -replace '(?<=^SRCDIR=).*', '${{ github.workspace }}' -replace '(?<=^BUILDDIR=).*', '${{ github.workspace }}' -replace '(?<=^RPCAUTH=).*', '${{ github.workspace }}/share/rpcauth/rpcauth.py' | Set-Content "test/config.ini"
Get-Content "test/config.ini"
- name: Set previous release directory
run: |
echo "PREVIOUS_RELEASES_DIR=${{ runner.temp }}/previous_releases" >> "$GITHUB_ENV"
- name: Get previous releases
working-directory: test
run: ./get_previous_releases.py --target-dir $PREVIOUS_RELEASES_DIR
- name: Run functional tests
env:
# TODO: Fix the excluded test and re-enable it.
# feature_unsupported_utxo_db.py fails on windows because of emojis in the test data directory
EXCLUDE: '--exclude wallet_multiwallet.py,feature_unsupported_utxo_db.py'
TEST_RUNNER_EXTRA: ${{ github.event_name != 'pull_request' && '--extended' || '' }}
run: py -3 test/functional/test_runner.py --jobs $NUMBER_OF_PROCESSORS --ci --quiet --tmpdirprefix="$RUNNER_TEMP" --combinedlogslen=99999999 --timeout-factor=$TEST_RUNNER_TIMEOUT_FACTOR $EXCLUDE $TEST_RUNNER_EXTRA
ci-matrix:
name: ${{ matrix.name }}
needs: runners
runs-on: ${{ needs.runners.outputs.provider == 'cirrus' && matrix.cirrus-runner || matrix.fallback-runner }}
if: ${{ vars.SKIP_BRANCH_PUSH != 'true' || github.event_name == 'pull_request' }}
timeout-minutes: ${{ matrix.timeout-minutes }}
env:
DANGER_CI_ON_HOST_FOLDERS: 1
FILE_ENV: ${{ matrix.file-env }}
strategy:
fail-fast: false
matrix:
include:
- name: '32 bit ARM, unit tests, no functional tests'
cirrus-runner: 'ubuntu-24.04-arm' # Cirrus' Arm runners are Apple (with virtual Linux aarch64), which doesn't support 32-bit mode
fallback-runner: 'ubuntu-24.04-arm'
timeout-minutes: 120
file-env: './ci/test/00_setup_env_arm.sh'
provider: 'gha'
- 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
fallback-runner: 'ubuntu-24.04'
timeout-minutes: 120
file-env: './ci/test/00_setup_env_native_asan.sh'
- name: 'macOS-cross, gui, no tests'
cirrus-runner: 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-sm'
fallback-runner: 'ubuntu-24.04'
timeout-minutes: 120
file-env: './ci/test/00_setup_env_mac_cross.sh'
- name: 'No wallet, libbitcoinkernel'
cirrus-runner: 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-sm'
fallback-runner: 'ubuntu-24.04'
timeout-minutes: 120
file-env: './ci/test/00_setup_env_native_nowallet_libbitcoinkernel.sh'
- name: 'no IPC, i686, DEBUG'
cirrus-runner: 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-md'
fallback-runner: 'ubuntu-24.04'
timeout-minutes: 120
file-env: './ci/test/00_setup_env_i686_no_ipc.sh'
- name: 'fuzzer,address,undefined,integer, no depends'
cirrus-runner: 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-lg'
fallback-runner: 'ubuntu-24.04'
timeout-minutes: 240
file-env: './ci/test/00_setup_env_native_fuzz.sh'
- name: 'previous releases, depends DEBUG'
cirrus-runner: 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-md'
fallback-runner: 'ubuntu-24.04'
timeout-minutes: 120
file-env: './ci/test/00_setup_env_native_previous_releases.sh'
- name: 'CentOS, depends, gui'
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_centos.sh'
- name: 'tidy'
cirrus-runner: 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-md'
fallback-runner: 'ubuntu-24.04'
timeout-minutes: 120
file-env: './ci/test/00_setup_env_native_tidy.sh'
- name: 'TSan, depends, no gui'
cirrus-runner: 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-md'
fallback-runner: 'ubuntu-24.04'
timeout-minutes: 120
file-env: './ci/test/00_setup_env_native_tsan.sh'
- name: 'MSan, depends'
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_msan.sh'
steps:
- *CHECKOUT
- name: Configure environment
uses: ./.github/actions/configure-environment
- name: Restore caches
id: restore-cache
uses: ./.github/actions/restore-caches
- name: Configure Docker
uses: ./.github/actions/configure-docker
with:
cache-provider: ${{ matrix.provider || needs.runners.outputs.provider }}
- name: Enable bpfcc script
if: ${{ env.CONTAINER_NAME == 'ci_native_asan' }}
# In the image build step, no external environment variables are available,
# so any settings will need to be written to the settings env file:
run: sed -i "s|\${INSTALL_BCC_TRACING_TOOLS}|true|g" ./ci/test/00_setup_env_native_asan.sh
- name: Set mmap_rnd_bits
if: ${{ env.CONTAINER_NAME == 'ci_native_tsan' || env.CONTAINER_NAME == 'ci_native_msan' }}
# Prevents crashes due to high ASLR entropy
run: sudo sysctl -w vm.mmap_rnd_bits=28
- name: CI script
run: ./ci/test_run_all.sh
- name: Save caches
uses: ./.github/actions/save-caches
lint:
name: 'lint'
needs: runners
runs-on: ${{ needs.runners.outputs.use-cirrus-runners == 'true' && 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-xs' || 'ubuntu-24.04' }}
if: ${{ vars.SKIP_BRANCH_PUSH != 'true' || github.event_name == 'pull_request' }}
timeout-minutes: 20
env:
CONTAINER_NAME: "bitcoin-linter"
steps:
- name: Checkout
uses: actions/checkout@v5
with:
ref: *CHECKOUT_REF_TMPL
fetch-depth: 0
- name: Configure Docker
uses: ./.github/actions/configure-docker
with:
cache-provider: ${{ needs.runners.outputs.provider }}
- name: CI script
run: |
set -o xtrace
docker buildx build -t "$CONTAINER_NAME" $DOCKER_BUILD_CACHE_ARG --file "./ci/lint_imagefile" .
CIRRUS_PR_FLAG=""
if [ "${{ github.event_name }}" = "pull_request" ]; then
CIRRUS_PR_FLAG="-e CIRRUS_PR=1"
fi
docker run --rm $CIRRUS_PR_FLAG -v "$(pwd)":/bitcoin "$CONTAINER_NAME"
# ci-matrix:
# name: ${{ matrix.name }}
# needs: runners
# runs-on: ${{ needs.runners.outputs.provider == 'cirrus' && matrix.cirrus-runner || matrix.fallback-runner }}
# if: ${{ vars.SKIP_BRANCH_PUSH != 'true' || github.event_name == 'pull_request' }}
# timeout-minutes: ${{ matrix.timeout-minutes }}
#
# env:
# DANGER_CI_ON_HOST_FOLDERS: 1
# FILE_ENV: ${{ matrix.file-env }}
#
# strategy:
# fail-fast: false
# matrix:
# include:
# - name: '32 bit ARM, unit tests, no functional tests'
# cirrus-runner: 'ubuntu-24.04-arm' # Cirrus' Arm runners are Apple (with virtual Linux aarch64), which doesn't support 32-bit mode
# fallback-runner: 'ubuntu-24.04-arm'
# timeout-minutes: 120
# file-env: './ci/test/00_setup_env_arm.sh'
# provider: 'gha'
#
# - 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
# fallback-runner: 'ubuntu-24.04'
# timeout-minutes: 120
# file-env: './ci/test/00_setup_env_native_asan.sh'
#
# - name: 'macOS-cross, gui, no tests'
# cirrus-runner: 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-sm'
# fallback-runner: 'ubuntu-24.04'
# timeout-minutes: 120
# file-env: './ci/test/00_setup_env_mac_cross.sh'
#
# - name: 'No wallet, libbitcoinkernel'
# cirrus-runner: 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-sm'
# fallback-runner: 'ubuntu-24.04'
# timeout-minutes: 120
# file-env: './ci/test/00_setup_env_native_nowallet_libbitcoinkernel.sh'
#
# - name: 'no IPC, i686, DEBUG'
# cirrus-runner: 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-md'
# fallback-runner: 'ubuntu-24.04'
# timeout-minutes: 120
# file-env: './ci/test/00_setup_env_i686_no_ipc.sh'
#
# - name: 'fuzzer,address,undefined,integer, no depends'
# cirrus-runner: 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-lg'
# fallback-runner: 'ubuntu-24.04'
# timeout-minutes: 240
# file-env: './ci/test/00_setup_env_native_fuzz.sh'
#
# - name: 'previous releases, depends DEBUG'
# cirrus-runner: 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-md'
# fallback-runner: 'ubuntu-24.04'
# timeout-minutes: 120
# file-env: './ci/test/00_setup_env_native_previous_releases.sh'
#
# - name: 'CentOS, depends, gui'
# 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_centos.sh'
#
# - name: 'tidy'
# cirrus-runner: 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-md'
# fallback-runner: 'ubuntu-24.04'
# timeout-minutes: 120
# file-env: './ci/test/00_setup_env_native_tidy.sh'
#
# - name: 'TSan, depends, no gui'
# cirrus-runner: 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-md'
# fallback-runner: 'ubuntu-24.04'
# timeout-minutes: 120
# file-env: './ci/test/00_setup_env_native_tsan.sh'
#
# - name: 'MSan, depends'
# 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_msan.sh'
#
# steps:
# - *CHECKOUT
#
# - name: Configure environment
# uses: ./.github/actions/configure-environment
#
# - name: Restore caches
# id: restore-cache
# uses: ./.github/actions/restore-caches
#
# - name: Configure Docker
# uses: ./.github/actions/configure-docker
# with:
# cache-provider: ${{ matrix.provider || needs.runners.outputs.provider }}
#
# - name: Enable bpfcc script
# if: ${{ env.CONTAINER_NAME == 'ci_native_asan' }}
# # In the image build step, no external environment variables are available,
# # so any settings will need to be written to the settings env file:
# run: sed -i "s|\${INSTALL_BCC_TRACING_TOOLS}|true|g" ./ci/test/00_setup_env_native_asan.sh
#
# - name: Set mmap_rnd_bits
# if: ${{ env.CONTAINER_NAME == 'ci_native_tsan' || env.CONTAINER_NAME == 'ci_native_msan' }}
# # Prevents crashes due to high ASLR entropy
# run: sudo sysctl -w vm.mmap_rnd_bits=28
#
# - name: CI script
# run: ./ci/test_run_all.sh
#
# - name: Save caches
# uses: ./.github/actions/save-caches
#
# lint:
# name: 'lint'
# needs: runners
# runs-on: ${{ needs.runners.outputs.use-cirrus-runners == 'true' && 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-xs' || 'ubuntu-24.04' }}
# if: ${{ vars.SKIP_BRANCH_PUSH != 'true' || github.event_name == 'pull_request' }}
# timeout-minutes: 20
# env:
# CONTAINER_NAME: "bitcoin-linter"
# steps:
# - name: Checkout
# uses: actions/checkout@v5
# with:
# ref: *CHECKOUT_REF_TMPL
# fetch-depth: 0
#
# - name: Configure Docker
# uses: ./.github/actions/configure-docker
# with:
# cache-provider: ${{ needs.runners.outputs.provider }}
#
# - name: CI script
# run: |
# set -o xtrace
# docker buildx build -t "$CONTAINER_NAME" $DOCKER_BUILD_CACHE_ARG --file "./ci/lint_imagefile" .
# CIRRUS_PR_FLAG=""
# if [ "${{ github.event_name }}" = "pull_request" ]; then
# CIRRUS_PR_FLAG="-e CIRRUS_PR=1"
# fi
# docker run --rm $CIRRUS_PR_FLAG -v "$(pwd)":/bitcoin "$CONTAINER_NAME"

View File

@ -36,9 +36,8 @@ define fetch_file_inner
endef
define fetch_file
( test -f $$($(1)_source_dir)/$(4) || \
( $(call fetch_file_inner,$(1),$(2),$(3),$(4),$(5)) || \
$(call fetch_file_inner,$(1),$(FALLBACK_DOWNLOAD_PATH),$(3),$(4),$(5))))
$(call fetch_file_inner,$(1),$(FALLBACK_DOWNLOAD_PATH),$(3),$(4),$(5)))
endef
# Shell script to create a source tarball in $(1)_source from local directory
@ -109,7 +108,7 @@ $(1)_prefixbin:=$($($(1)_type)_prefix)/bin/
$(1)_all_sources=$($(1)_file_name) $($(1)_extra_sources)
#stamps
$(1)_fetched=$(SOURCES_PATH)/download-stamps/.stamp_fetched-$(1)-$($(1)_file_name).hash
$(1)_fetched=$(SOURCES_PATH)/download-stamps/.stamp_fetched-$(1)-$($(1)_version)-$($(1)_sha256_hash).hash
$(1)_extracted=$$($(1)_extract_dir)/.stamp_extracted
$(1)_preprocessed=$$($(1)_extract_dir)/.stamp_preprocessed
$(1)_cleaned=$$($(1)_extract_dir)/.stamp_cleaned
@ -247,7 +246,6 @@ endif
$($(1)_fetched):
mkdir -p $$(@D) $(SOURCES_PATH)
rm -f $$@
touch $$@
cd $$(@D); $($(1)_fetch_cmds)
cd $($(1)_source_dir); $(foreach source,$($(1)_all_sources),$(build_SHA256SUM) $(source) >> $$(@);)
touch $$@

View File

@ -1,8 +1,9 @@
package=qrencode
$(package)_version=4.1.1
$(package)_download_path=https://fukuchi.org/works/qrencode/
$(package)_download_path=https://github.com/fukuchi/libqrencode/archive/refs/tags/
$(package)_download_file=v$($(package)_version).tar.gz
$(package)_file_name=$(package)-$($(package)_version).tar.gz
$(package)_sha256_hash=da448ed4f52aba6bcb0cd48cac0dd51b8692bccc4cd127431402fca6f8171e8e
$(package)_sha256_hash=5385bc1b8c2f20f3b91d258bf8ccc8cf62023935df2d2676b5b67049f31a049c
$(package)_patches=cmake_fixups.patch
define $(package)_set_vars

View File

@ -24,7 +24,7 @@ static void VerifyScriptBench(benchmark::Bench& bench)
{
ECC_Context ecc_context{};
const uint32_t flags{SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH};
const script_verify_flags flags{SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH};
const int witnessversion = 0;
// Key pair.

View File

@ -6,6 +6,7 @@
#ifndef BITCOIN_CONSENSUS_PARAMS_H
#define BITCOIN_CONSENSUS_PARAMS_H
#include <script/verify_flags.h>
#include <uint256.h>
#include <array>
@ -89,7 +90,7 @@ struct Params {
* - buried in the chain, and
* - fail if the default script verify flags are applied.
*/
std::map<uint256, uint32_t> script_flag_exceptions;
std::map<uint256, script_verify_flags> script_flag_exceptions;
/** Block height and hash at which BIP34 becomes active */
int BIP34Height;
uint256 BIP34Hash;

View File

@ -140,7 +140,7 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& in
return nSigOps;
}
int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& inputs, uint32_t flags)
int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& inputs, script_verify_flags flags)
{
int64_t nSigOps = GetLegacySigOpCount(tx) * WITNESS_SCALE_FACTOR;

View File

@ -6,6 +6,7 @@
#define BITCOIN_CONSENSUS_TX_VERIFY_H
#include <consensus/amount.h>
#include <script/verify_flags.h>
#include <cstdint>
#include <vector>
@ -52,7 +53,7 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& ma
* @param[in] flags Script verification flags
* @return Total signature operation cost of tx
*/
int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& inputs, uint32_t flags);
int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& inputs, script_verify_flags flags);
/**
* Check if transaction is final and can be included in a block with the

View File

@ -8,8 +8,10 @@
#include <consensus/params.h>
#include <array>
#include <cassert>
#include <optional>
#include <string>
#include <string_view>
struct VBDeploymentInfo {
/** Deployment name */

View File

@ -98,7 +98,7 @@ static constexpr unsigned int MAX_DUST_OUTPUTS_PER_TX{1};
* Note that this does not affect consensus validity; see GetBlockScriptFlags()
* for that.
*/
static constexpr unsigned int MANDATORY_SCRIPT_VERIFY_FLAGS{SCRIPT_VERIFY_P2SH |
static constexpr script_verify_flags MANDATORY_SCRIPT_VERIFY_FLAGS{SCRIPT_VERIFY_P2SH |
SCRIPT_VERIFY_DERSIG |
SCRIPT_VERIFY_NULLDUMMY |
SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY |
@ -112,7 +112,7 @@ static constexpr unsigned int MANDATORY_SCRIPT_VERIFY_FLAGS{SCRIPT_VERIFY_P2SH |
* the additional (non-mandatory) rules here, to improve forwards and
* backwards compatibility.
*/
static constexpr unsigned int STANDARD_SCRIPT_VERIFY_FLAGS{MANDATORY_SCRIPT_VERIFY_FLAGS |
static constexpr script_verify_flags STANDARD_SCRIPT_VERIFY_FLAGS{MANDATORY_SCRIPT_VERIFY_FLAGS |
SCRIPT_VERIFY_STRICTENC |
SCRIPT_VERIFY_MINIMALDATA |
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS |
@ -128,7 +128,7 @@ static constexpr unsigned int STANDARD_SCRIPT_VERIFY_FLAGS{MANDATORY_SCRIPT_VERI
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE};
/** For convenience, standard but not mandatory verify flags. */
static constexpr unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS{STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS};
static constexpr script_verify_flags STANDARD_NOT_MANDATORY_VERIFY_FLAGS{STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS};
/** Used as the flags parameter to sequence and nLocktime checks in non-consensus code. */
static constexpr unsigned int STANDARD_LOCKTIME_VERIFY_FLAGS{LOCKTIME_VERIFY_SEQUENCE};

View File

@ -1469,6 +1469,9 @@ RPCHelpMan getdeploymentinfo()
RPCResult::Type::OBJ, "", "", {
{RPCResult::Type::STR, "hash", "requested block hash (or tip)"},
{RPCResult::Type::NUM, "height", "requested block height (or tip)"},
{RPCResult::Type::ARR, "script_flags", "script verify flags for the block", {
{RPCResult::Type::STR, "flag", "a script verify flag"},
}},
{RPCResult::Type::OBJ_DYN, "deployments", "", {
{RPCResult::Type::OBJ, "xxxx", "name of the deployment", RPCHelpForDeployment}
}},
@ -1495,6 +1498,12 @@ RPCHelpMan getdeploymentinfo()
UniValue deploymentinfo(UniValue::VOBJ);
deploymentinfo.pushKV("hash", blockindex->GetBlockHash().ToString());
deploymentinfo.pushKV("height", blockindex->nHeight);
{
const auto flagnames = GetScriptFlagNames(GetBlockScriptFlags(*blockindex, chainman));
UniValue uv_flagnames(UniValue::VARR);
uv_flagnames.push_backV(flagnames.begin(), flagnames.end());
deploymentinfo.pushKV("script_flags", uv_flagnames);
}
deploymentinfo.pushKV("deployments", DeploymentInfo(blockindex, chainman));
return deploymentinfo;
},

View File

@ -10,6 +10,7 @@
#include <crypto/sha256.h>
#include <pubkey.h>
#include <script/script.h>
#include <tinyformat.h>
#include <uint256.h>
typedef std::vector<unsigned char> valtype;
@ -197,7 +198,7 @@ bool static IsDefinedHashtypeSignature(const valtype &vchSig) {
return true;
}
bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned int flags, ScriptError* serror) {
bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, script_verify_flags flags, ScriptError* serror) {
// Empty signature. Not strictly DER encoded, but allowed to provide a
// compact way to provide an invalid signature for use with CHECK(MULTI)SIG
if (vchSig.size() == 0) {
@ -214,7 +215,7 @@ bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned i
return true;
}
bool static CheckPubKeyEncoding(const valtype &vchPubKey, unsigned int flags, const SigVersion &sigversion, ScriptError* serror) {
bool static CheckPubKeyEncoding(const valtype &vchPubKey, script_verify_flags flags, const SigVersion &sigversion, ScriptError* serror) {
if ((flags & SCRIPT_VERIFY_STRICTENC) != 0 && !IsCompressedOrUncompressedPubKey(vchPubKey)) {
return set_error(serror, SCRIPT_ERR_PUBKEYTYPE);
}
@ -317,7 +318,7 @@ public:
};
}
static bool EvalChecksigPreTapscript(const valtype& vchSig, const valtype& vchPubKey, CScript::const_iterator pbegincodehash, CScript::const_iterator pend, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror, bool& fSuccess)
static bool EvalChecksigPreTapscript(const valtype& vchSig, const valtype& vchPubKey, CScript::const_iterator pbegincodehash, CScript::const_iterator pend, script_verify_flags flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror, bool& fSuccess)
{
assert(sigversion == SigVersion::BASE || sigversion == SigVersion::WITNESS_V0);
@ -343,7 +344,7 @@ static bool EvalChecksigPreTapscript(const valtype& vchSig, const valtype& vchPu
return true;
}
static bool EvalChecksigTapscript(const valtype& sig, const valtype& pubkey, ScriptExecutionData& execdata, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror, bool& success)
static bool EvalChecksigTapscript(const valtype& sig, const valtype& pubkey, ScriptExecutionData& execdata, script_verify_flags flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror, bool& success)
{
assert(sigversion == SigVersion::TAPSCRIPT);
@ -388,7 +389,7 @@ static bool EvalChecksigTapscript(const valtype& sig, const valtype& pubkey, Scr
* A return value of false means the script fails entirely. When true is returned, the
* success variable indicates whether the signature check itself succeeded.
*/
static bool EvalChecksig(const valtype& sig, const valtype& pubkey, CScript::const_iterator pbegincodehash, CScript::const_iterator pend, ScriptExecutionData& execdata, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror, bool& success)
static bool EvalChecksig(const valtype& sig, const valtype& pubkey, CScript::const_iterator pbegincodehash, CScript::const_iterator pend, ScriptExecutionData& execdata, script_verify_flags flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror, bool& success)
{
switch (sigversion) {
case SigVersion::BASE:
@ -403,7 +404,7 @@ static bool EvalChecksig(const valtype& sig, const valtype& pubkey, CScript::con
assert(false);
}
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* serror)
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, script_verify_flags flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* serror)
{
static const CScriptNum bnZero(0);
static const CScriptNum bnOne(1);
@ -1233,7 +1234,7 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
return set_success(serror);
}
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror)
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, script_verify_flags flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror)
{
ScriptExecutionData execdata;
return EvalScript(stack, script, flags, checker, sigversion, execdata, serror);
@ -1824,7 +1825,7 @@ bool GenericTransactionSignatureChecker<T>::CheckSequence(const CScriptNum& nSeq
template class GenericTransactionSignatureChecker<CTransaction>;
template class GenericTransactionSignatureChecker<CMutableTransaction>;
static bool ExecuteWitnessScript(const std::span<const valtype>& stack_span, const CScript& exec_script, unsigned int flags, SigVersion sigversion, const BaseSignatureChecker& checker, ScriptExecutionData& execdata, ScriptError* serror)
static bool ExecuteWitnessScript(const std::span<const valtype>& stack_span, const CScript& exec_script, script_verify_flags flags, SigVersion sigversion, const BaseSignatureChecker& checker, ScriptExecutionData& execdata, ScriptError* serror)
{
std::vector<valtype> stack{stack_span.begin(), stack_span.end()};
@ -1909,7 +1910,7 @@ static bool VerifyTaprootCommitment(const std::vector<unsigned char>& control, c
return q.CheckTapTweak(p, merkle_root, control[0] & 1);
}
static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, const std::vector<unsigned char>& program, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror, bool is_p2sh)
static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, const std::vector<unsigned char>& program, script_verify_flags flags, const BaseSignatureChecker& checker, ScriptError* serror, bool is_p2sh)
{
CScript exec_script; //!< Actually executed script (last stack item in P2WSH; implied P2PKH script in P2WPKH; leaf script in P2TR)
std::span stack{witness.stack};
@ -1994,7 +1995,7 @@ static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion,
// There is intentionally no return statement here, to be able to use "control reaches end of non-void function" warnings to detect gaps in the logic above.
}
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror)
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, script_verify_flags flags, const BaseSignatureChecker& checker, ScriptError* serror)
{
static const CScriptWitness emptyWitness;
if (witness == nullptr) {
@ -2131,7 +2132,7 @@ size_t static WitnessSigOps(int witversion, const std::vector<unsigned char>& wi
return 0;
}
size_t CountWitnessSigOps(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, unsigned int flags)
size_t CountWitnessSigOps(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, script_verify_flags flags)
{
static const CScriptWitness witnessEmpty;
@ -2161,3 +2162,48 @@ size_t CountWitnessSigOps(const CScript& scriptSig, const CScript& scriptPubKey,
return 0;
}
#define FLAG_NAME(flag) {std::string(#flag), SCRIPT_VERIFY_##flag}
const std::map<std::string, script_verify_flag_name> g_verify_flag_names{
FLAG_NAME(P2SH),
FLAG_NAME(STRICTENC),
FLAG_NAME(DERSIG),
FLAG_NAME(LOW_S),
FLAG_NAME(SIGPUSHONLY),
FLAG_NAME(MINIMALDATA),
FLAG_NAME(NULLDUMMY),
FLAG_NAME(DISCOURAGE_UPGRADABLE_NOPS),
FLAG_NAME(CLEANSTACK),
FLAG_NAME(MINIMALIF),
FLAG_NAME(NULLFAIL),
FLAG_NAME(CHECKLOCKTIMEVERIFY),
FLAG_NAME(CHECKSEQUENCEVERIFY),
FLAG_NAME(WITNESS),
FLAG_NAME(DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM),
FLAG_NAME(WITNESS_PUBKEYTYPE),
FLAG_NAME(CONST_SCRIPTCODE),
FLAG_NAME(TAPROOT),
FLAG_NAME(DISCOURAGE_UPGRADABLE_PUBKEYTYPE),
FLAG_NAME(DISCOURAGE_OP_SUCCESS),
FLAG_NAME(DISCOURAGE_UPGRADABLE_TAPROOT_VERSION),
};
#undef FLAG_NAME
std::vector<std::string> GetScriptFlagNames(script_verify_flags flags)
{
std::vector<std::string> res;
if (flags == SCRIPT_VERIFY_NONE) {
return res;
}
script_verify_flags leftover = flags;
for (const auto& [name, flag] : g_verify_flag_names) {
if ((flags & flag) != 0) {
res.push_back(name);
leftover &= ~flag;
}
}
if (leftover != 0) {
res.push_back(strprintf("0x%08x", leftover.as_int()));
}
return res;
}

View File

@ -10,6 +10,7 @@
#include <hash.h>
#include <primitives/transaction.h>
#include <script/script_error.h> // IWYU pragma: export
#include <script/verify_flags.h> // IWYU pragma: export
#include <span.h>
#include <uint256.h>
@ -42,35 +43,36 @@ enum
* All flags are intended to be soft forks: the set of acceptable scripts under
* flags (A | B) is a subset of the acceptable scripts under flag (A).
*/
enum : uint32_t {
SCRIPT_VERIFY_NONE = 0,
static constexpr script_verify_flags SCRIPT_VERIFY_NONE{0};
enum class script_verify_flag_name : uint8_t {
// Evaluate P2SH subscripts (BIP16).
SCRIPT_VERIFY_P2SH = (1U << 0),
SCRIPT_VERIFY_P2SH,
// Passing a non-strict-DER signature or one with undefined hashtype to a checksig operation causes script failure.
// Evaluating a pubkey that is not (0x04 + 64 bytes) or (0x02 or 0x03 + 32 bytes) by checksig causes script failure.
// (not used or intended as a consensus rule).
SCRIPT_VERIFY_STRICTENC = (1U << 1),
SCRIPT_VERIFY_STRICTENC,
// Passing a non-strict-DER signature to a checksig operation causes script failure (BIP62 rule 1)
SCRIPT_VERIFY_DERSIG = (1U << 2),
SCRIPT_VERIFY_DERSIG,
// Passing a non-strict-DER signature or one with S > order/2 to a checksig operation causes script failure
// (BIP62 rule 5).
SCRIPT_VERIFY_LOW_S = (1U << 3),
SCRIPT_VERIFY_LOW_S,
// verify dummy stack item consumed by CHECKMULTISIG is of zero-length (BIP62 rule 7).
SCRIPT_VERIFY_NULLDUMMY = (1U << 4),
SCRIPT_VERIFY_NULLDUMMY,
// Using a non-push operator in the scriptSig causes script failure (BIP62 rule 2).
SCRIPT_VERIFY_SIGPUSHONLY = (1U << 5),
SCRIPT_VERIFY_SIGPUSHONLY,
// Require minimal encodings for all push operations (OP_0... OP_16, OP_1NEGATE where possible, direct
// pushes up to 75 bytes, OP_PUSHDATA up to 255 bytes, OP_PUSHDATA2 for anything larger). Evaluating
// any other push causes the script to fail (BIP62 rule 3).
// In addition, whenever a stack element is interpreted as a number, it must be of minimal length (BIP62 rule 4).
SCRIPT_VERIFY_MINIMALDATA = (1U << 6),
SCRIPT_VERIFY_MINIMALDATA,
// Discourage use of NOPs reserved for upgrades (NOP1-10)
//
@ -82,7 +84,7 @@ enum : uint32_t {
// executed, e.g. within an unexecuted IF ENDIF block, are *not* rejected.
// NOPs that have associated forks to give them new meaning (CLTV, CSV)
// are not subject to this rule.
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS = (1U << 7),
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS,
// Require that only a single stack element remains after evaluation. This changes the success criterion from
// "At least one stack element must remain, and when interpreted as a boolean, it must be true" to
@ -91,64 +93,72 @@ enum : uint32_t {
// Note: CLEANSTACK should never be used without P2SH or WITNESS.
// Note: WITNESS_V0 and TAPSCRIPT script execution have behavior similar to CLEANSTACK as part of their
// consensus rules. It is automatic there and does not need this flag.
SCRIPT_VERIFY_CLEANSTACK = (1U << 8),
SCRIPT_VERIFY_CLEANSTACK,
// Verify CHECKLOCKTIMEVERIFY
//
// See BIP65 for details.
SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY = (1U << 9),
SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY,
// support CHECKSEQUENCEVERIFY opcode
//
// See BIP112 for details
SCRIPT_VERIFY_CHECKSEQUENCEVERIFY = (1U << 10),
SCRIPT_VERIFY_CHECKSEQUENCEVERIFY,
// Support segregated witness
//
SCRIPT_VERIFY_WITNESS = (1U << 11),
SCRIPT_VERIFY_WITNESS,
// Making v1-v16 witness program non-standard
//
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM = (1U << 12),
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM,
// Segwit script only: Require the argument of OP_IF/NOTIF to be exactly 0x01 or empty vector
//
// Note: TAPSCRIPT script execution has behavior similar to MINIMALIF as part of its consensus
// rules. It is automatic there and does not depend on this flag.
SCRIPT_VERIFY_MINIMALIF = (1U << 13),
SCRIPT_VERIFY_MINIMALIF,
// Signature(s) must be empty vector if a CHECK(MULTI)SIG operation failed
//
SCRIPT_VERIFY_NULLFAIL = (1U << 14),
SCRIPT_VERIFY_NULLFAIL,
// Public keys in segregated witness scripts must be compressed
//
SCRIPT_VERIFY_WITNESS_PUBKEYTYPE = (1U << 15),
SCRIPT_VERIFY_WITNESS_PUBKEYTYPE,
// Making OP_CODESEPARATOR and FindAndDelete fail any non-segwit scripts
//
SCRIPT_VERIFY_CONST_SCRIPTCODE = (1U << 16),
SCRIPT_VERIFY_CONST_SCRIPTCODE,
// Taproot/Tapscript validation (BIPs 341 & 342)
//
SCRIPT_VERIFY_TAPROOT = (1U << 17),
SCRIPT_VERIFY_TAPROOT,
// Making unknown Taproot leaf versions non-standard
//
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION = (1U << 18),
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION,
// Making unknown OP_SUCCESS non-standard
SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS = (1U << 19),
SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS,
// Making unknown public key versions (in BIP 342 scripts) non-standard
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE = (1U << 20),
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE,
// Constants to point to the highest flag in use. Add new flags above this line.
//
SCRIPT_VERIFY_END_MARKER
};
using enum script_verify_flag_name;
bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned int flags, ScriptError* serror);
static constexpr int MAX_SCRIPT_VERIFY_FLAGS_BITS = static_cast<int>(SCRIPT_VERIFY_END_MARKER);
// assert there is still a spare bit
static_assert(0 < MAX_SCRIPT_VERIFY_FLAGS_BITS && MAX_SCRIPT_VERIFY_FLAGS_BITS <= 63);
static constexpr script_verify_flags::value_type MAX_SCRIPT_VERIFY_FLAGS = ((script_verify_flags::value_type{1} << MAX_SCRIPT_VERIFY_FLAGS_BITS) - 1);
bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, script_verify_flags flags, ScriptError* serror);
struct PrecomputedTransactionData
{
@ -363,12 +373,16 @@ uint256 ComputeTapbranchHash(std::span<const unsigned char> a, std::span<const u
* Requires control block to have valid length (33 + k*32, with k in {0,1,..,128}). */
uint256 ComputeTaprootMerkleRoot(std::span<const unsigned char> control, const uint256& tapleaf_hash);
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* error = nullptr);
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* error = nullptr);
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror = nullptr);
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, script_verify_flags flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* error = nullptr);
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, script_verify_flags flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* error = nullptr);
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, script_verify_flags flags, const BaseSignatureChecker& checker, ScriptError* serror = nullptr);
size_t CountWitnessSigOps(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, unsigned int flags);
size_t CountWitnessSigOps(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, script_verify_flags flags);
int FindAndDelete(CScript& script, const CScript& b);
extern const std::map<std::string, script_verify_flag_name> g_verify_flag_names;
std::vector<std::string> GetScriptFlagNames(script_verify_flags flags);
#endif // BITCOIN_SCRIPT_INTERPRETER_H

71
src/script/verify_flags.h Normal file
View File

@ -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

View File

@ -26,7 +26,7 @@
static constexpr uint8_t SIGNET_HEADER[4] = {0xec, 0xc7, 0xda, 0xa2};
static constexpr unsigned int BLOCK_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_NULLDUMMY;
static constexpr script_verify_flags BLOCK_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_NULLDUMMY;
static bool FetchAndClearCommitmentSection(const std::span<const uint8_t> header, CScript& witness_commitment, std::vector<uint8_t>& result)
{

View File

@ -288,7 +288,7 @@ void TestCoinsView(FuzzedDataProvider& fuzzed_data_provider, CCoinsView& backend
// consensus/tx_verify.cpp:130: unsigned int GetP2SHSigOpCount(const CTransaction &, const CCoinsViewCache &): Assertion `!coin.IsSpent()' failed.
return;
}
const auto flags{fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
const auto flags = script_verify_flags::from_int(fuzzed_data_provider.ConsumeIntegral<script_verify_flags::value_type>());
if (!transaction.vin.empty() && (flags & SCRIPT_VERIFY_WITNESS) != 0 && (flags & SCRIPT_VERIFY_P2SH) == 0) {
// Avoid:
// script/interpreter.cpp:1705: size_t CountWitnessSigOps(const CScript &, const CScript &, const CScriptWitness *, unsigned int): Assertion `(flags & SCRIPT_VERIFY_P2SH) != 0' failed.

View File

@ -12,7 +12,7 @@
FUZZ_TARGET(eval_script)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
const unsigned int flags = fuzzed_data_provider.ConsumeIntegral<unsigned int>();
const auto flags = script_verify_flags::from_int(fuzzed_data_provider.ConsumeIntegral<script_verify_flags::value_type>());
const std::vector<uint8_t> script_bytes = [&] {
if (fuzzed_data_provider.remaining_bytes() != 0) {
return fuzzed_data_provider.ConsumeRemainingBytes<uint8_t>();

View File

@ -118,8 +118,8 @@ FUZZ_TARGET(script, .init = initialize_script)
(void)FindAndDelete(script_mut, *other_script);
}
const std::vector<std::string> random_string_vector = ConsumeRandomLengthStringVector(fuzzed_data_provider);
const uint32_t u32{fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
const uint32_t flags{u32 | SCRIPT_VERIFY_P2SH};
const auto flags_rand{fuzzed_data_provider.ConsumeIntegral<script_verify_flags::value_type>()};
const auto flags = script_verify_flags::from_int(flags_rand) | SCRIPT_VERIFY_P2SH;
{
CScriptWitness wit;
for (const auto& s : random_string_vector) {

View File

@ -90,22 +90,22 @@ CScriptWitness ScriptWitnessFromJSON(const UniValue& univalue)
return scriptwitness;
}
const std::map<std::string, unsigned int> FLAG_NAMES = {
{std::string("P2SH"), (unsigned int)SCRIPT_VERIFY_P2SH},
{std::string("DERSIG"), (unsigned int)SCRIPT_VERIFY_DERSIG},
{std::string("NULLDUMMY"), (unsigned int)SCRIPT_VERIFY_NULLDUMMY},
{std::string("CHECKLOCKTIMEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY},
{std::string("CHECKSEQUENCEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKSEQUENCEVERIFY},
{std::string("WITNESS"), (unsigned int)SCRIPT_VERIFY_WITNESS},
{std::string("TAPROOT"), (unsigned int)SCRIPT_VERIFY_TAPROOT},
const std::map<std::string, script_verify_flag_name> FLAG_NAMES = {
{std::string("P2SH"), SCRIPT_VERIFY_P2SH},
{std::string("DERSIG"), SCRIPT_VERIFY_DERSIG},
{std::string("NULLDUMMY"), SCRIPT_VERIFY_NULLDUMMY},
{std::string("CHECKLOCKTIMEVERIFY"), SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY},
{std::string("CHECKSEQUENCEVERIFY"), SCRIPT_VERIFY_CHECKSEQUENCEVERIFY},
{std::string("WITNESS"), SCRIPT_VERIFY_WITNESS},
{std::string("TAPROOT"), SCRIPT_VERIFY_TAPROOT},
};
std::vector<unsigned int> AllFlags()
std::vector<script_verify_flags> AllFlags()
{
std::vector<unsigned int> ret;
std::vector<script_verify_flags> ret;
for (unsigned int i = 0; i < 128; ++i) {
unsigned int flag = 0;
script_verify_flags flag = 0;
if (i & 1) flag |= SCRIPT_VERIFY_P2SH;
if (i & 2) flag |= SCRIPT_VERIFY_DERSIG;
if (i & 4) flag |= SCRIPT_VERIFY_NULLDUMMY;
@ -125,13 +125,13 @@ std::vector<unsigned int> AllFlags()
return ret;
}
const std::vector<unsigned int> ALL_FLAGS = AllFlags();
const std::vector<script_verify_flags> ALL_FLAGS = AllFlags();
unsigned int ParseScriptFlags(const std::string& str)
script_verify_flags ParseScriptFlags(const std::string& str)
{
if (str.empty()) return 0;
unsigned int flags = 0;
script_verify_flags flags = 0;
std::vector<std::string> words = SplitString(str, ',');
for (const std::string& word : words) {
@ -153,7 +153,7 @@ void Test(const std::string& str)
if (prevouts.size() != tx.vin.size()) throw std::runtime_error("Incorrect number of prevouts");
size_t idx = test["index"].getInt<int64_t>();
if (idx >= tx.vin.size()) throw std::runtime_error("Invalid index");
unsigned int test_flags = ParseScriptFlags(test["flags"].get_str());
script_verify_flags test_flags = ParseScriptFlags(test["flags"].get_str());
bool final = test.exists("final") && test["final"].get_bool();
if (test.exists("success")) {

View File

@ -15,6 +15,15 @@
#include <utility>
#include <vector>
static DataStream& operator>>(DataStream& ds, script_verify_flags& f)
{
script_verify_flags::value_type n{0};
ds >> n;
f = script_verify_flags::from_int(n);
assert(n == f.as_int());
return ds;
}
FUZZ_TARGET(script_flags)
{
if (buffer.size() > 100'000) return;
@ -22,12 +31,14 @@ FUZZ_TARGET(script_flags)
try {
const CTransaction tx(deserialize, TX_WITH_WITNESS, ds);
unsigned int verify_flags;
script_verify_flags verify_flags;
ds >> verify_flags;
assert(verify_flags == script_verify_flags::from_int(verify_flags.as_int()));
if (!IsValidFlagCombination(verify_flags)) return;
unsigned int fuzzed_flags;
script_verify_flags fuzzed_flags;
ds >> fuzzed_flags;
std::vector<CTxOut> spent_outputs;

View File

@ -51,7 +51,7 @@ public:
FUZZ_TARGET(signature_checker)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
const unsigned int flags = fuzzed_data_provider.ConsumeIntegral<unsigned int>();
const auto flags = script_verify_flags::from_int(fuzzed_data_provider.ConsumeIntegral<script_verify_flags::value_type>());
const SigVersion sig_version = fuzzed_data_provider.PickValueInArray({SigVersion::BASE, SigVersion::WITNESS_V0});
const auto script_1{ConsumeScript(fuzzed_data_provider)};
const auto script_2{ConsumeScript(fuzzed_data_provider)};

View File

@ -38,7 +38,7 @@ sign_multisig(const CScript& scriptPubKey, const std::vector<CKey>& keys, const
BOOST_AUTO_TEST_CASE(multisig_verify)
{
unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC;
script_verify_flags flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC;
ScriptError err;
CKey key[4];

View File

@ -25,7 +25,7 @@
#include <univalue.h>
unsigned int ParseScriptFlags(std::string strFlags);
script_verify_flags ParseScriptFlags(std::string strFlags);
BOOST_AUTO_TEST_SUITE(script_assets_tests)
@ -71,12 +71,12 @@ static CScriptWitness ScriptWitnessFromJSON(const UniValue& univalue)
return scriptwitness;
}
static std::vector<unsigned int> AllConsensusFlags()
static std::vector<script_verify_flags> AllConsensusFlags()
{
std::vector<unsigned int> ret;
std::vector<script_verify_flags> ret;
for (unsigned int i = 0; i < 128; ++i) {
unsigned int flag = 0;
script_verify_flags flag = 0;
if (i & 1) flag |= SCRIPT_VERIFY_P2SH;
if (i & 2) flag |= SCRIPT_VERIFY_DERSIG;
if (i & 4) flag |= SCRIPT_VERIFY_NULLDUMMY;
@ -97,7 +97,7 @@ static std::vector<unsigned int> AllConsensusFlags()
}
/** Precomputed list of all valid combinations of consensus-relevant script validation flags. */
static const std::vector<unsigned int> ALL_CONSENSUS_FLAGS = AllConsensusFlags();
static const std::vector<script_verify_flags> ALL_CONSENSUS_FLAGS = AllConsensusFlags();
static void AssetTest(const UniValue& test, SignatureCache& signature_cache)
{
@ -107,7 +107,7 @@ static void AssetTest(const UniValue& test, SignatureCache& signature_cache)
const std::vector<CTxOut> prevouts = TxOutsFromJSON(test["prevouts"]);
BOOST_CHECK(prevouts.size() == mtx.vin.size());
size_t idx = test["index"].getInt<int64_t>();
uint32_t test_flags{ParseScriptFlags(test["flags"].get_str())};
script_verify_flags test_flags{ParseScriptFlags(test["flags"].get_str())};
bool fin = test.exists("final") && test["final"].get_bool();
if (test.exists("success")) {

View File

@ -9,6 +9,7 @@
#include <core_io.h>
#include <key.h>
#include <rpc/util.h>
#include <script/interpreter.h>
#include <script/script.h>
#include <script/script_error.h>
#include <script/sigcache.h>
@ -22,6 +23,7 @@
#include <test/util/transaction_utils.h>
#include <util/fs.h>
#include <util/strencodings.h>
#include <util/string.h>
#include <cstdint>
#include <fstream>
@ -38,10 +40,9 @@
using namespace util::hex_literals;
static const unsigned int gFlags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC;
static const script_verify_flags gFlags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC;
unsigned int ParseScriptFlags(std::string strFlags);
std::string FormatScriptFlags(unsigned int flags);
script_verify_flags ParseScriptFlags(std::string strFlags);
struct ScriptErrorDesc
{
@ -95,6 +96,11 @@ static ScriptErrorDesc script_errors[]={
{SCRIPT_ERR_SIG_FINDANDDELETE, "SIG_FINDANDDELETE"},
};
static std::string FormatScriptFlags(script_verify_flags flags)
{
return util::Join(GetScriptFlagNames(flags), ",");
}
static std::string FormatScriptError(ScriptError_t err)
{
for (const auto& se : script_errors)
@ -114,7 +120,7 @@ static ScriptError_t ParseScriptError(const std::string& name)
}
struct ScriptTest : BasicTestingSetup {
void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, const CScriptWitness& scriptWitness, uint32_t flags, const std::string& message, int scriptError, CAmount nValue = 0)
void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, const CScriptWitness& scriptWitness, script_verify_flags flags, const std::string& message, int scriptError, CAmount nValue = 0)
{
bool expect = (scriptError == SCRIPT_ERR_OK);
if (flags & SCRIPT_VERIFY_CLEANSTACK) {
@ -128,13 +134,13 @@ void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, const CScript
BOOST_CHECK_MESSAGE(err == scriptError, FormatScriptError(err) + " where " + FormatScriptError((ScriptError_t)scriptError) + " expected: " + message);
// Verify that removing flags from a passing test or adding flags to a failing test does not change the result.
for (int i = 0; i < 16; ++i) {
uint32_t extra_flags(m_rng.randbits(16));
uint32_t combined_flags{expect ? (flags & ~extra_flags) : (flags | extra_flags)};
for (int i = 0; i < 256; ++i) {
script_verify_flags extra_flags = script_verify_flags::from_int(m_rng.randbits(MAX_SCRIPT_VERIFY_FLAGS_BITS));
script_verify_flags combined_flags{expect ? (flags & ~extra_flags) : (flags | extra_flags)};
// Weed out some invalid flag combinations.
if (combined_flags & SCRIPT_VERIFY_CLEANSTACK && ~combined_flags & (SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS)) continue;
if (combined_flags & SCRIPT_VERIFY_WITNESS && ~combined_flags & SCRIPT_VERIFY_P2SH) continue;
BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, &scriptWitness, combined_flags, MutableTransactionSignatureChecker(&tx, 0, txCredit.vout[0].nValue, MissingDataBehavior::ASSERT_FAIL), &err) == expect, message + strprintf(" (with flags %x)", combined_flags));
BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, &scriptWitness, combined_flags, MutableTransactionSignatureChecker(&tx, 0, txCredit.vout[0].nValue, MissingDataBehavior::ASSERT_FAIL), &err) == expect, message + strprintf(" (with flags %x)", combined_flags.as_int()));
}
}
}; // struct ScriptTest
@ -226,7 +232,7 @@ private:
bool havePush{false};
std::vector<unsigned char> push;
std::string comment;
uint32_t flags;
script_verify_flags flags;
int scriptError{SCRIPT_ERR_OK};
CAmount nValue;
@ -246,7 +252,7 @@ private:
}
public:
TestBuilder(const CScript& script_, const std::string& comment_, uint32_t flags_, bool P2SH = false, WitnessMode wm = WitnessMode::NONE, int witnessversion = 0, CAmount nValue_ = 0) : script(script_), comment(comment_), flags(flags_), nValue(nValue_)
TestBuilder(const CScript& script_, const std::string& comment_, script_verify_flags flags_, bool P2SH = false, WitnessMode wm = WitnessMode::NONE, int witnessversion = 0, CAmount nValue_ = 0) : script(script_), comment(comment_), flags(flags_), nValue(nValue_)
{
CScript scriptPubKey = script;
if (wm == WitnessMode::PKH) {
@ -963,7 +969,7 @@ BOOST_AUTO_TEST_CASE(script_json_test)
} else {
scriptPubKey = ParseScript(scriptPubKeyString);
}
unsigned int scriptflags = ParseScriptFlags(test[pos++].get_str());
script_verify_flags scriptflags = ParseScriptFlags(test[pos++].get_str());
int scriptError = ParseScriptError(test[pos++].get_str());
DoTest(scriptPubKey, scriptSig, witness, scriptflags, strTest, scriptError, nValue);
@ -1706,4 +1712,15 @@ BOOST_AUTO_TEST_CASE(compute_tapleaf)
BOOST_CHECK_EQUAL(ComputeTapleafHash(0xc2, std::span(script)), tlc2);
}
BOOST_AUTO_TEST_CASE(formatscriptflags)
{
// quick check that FormatScriptFlags reports any unknown/unexpected bits
BOOST_CHECK_EQUAL(FormatScriptFlags(SCRIPT_VERIFY_P2SH), "P2SH");
BOOST_CHECK_EQUAL(FormatScriptFlags(SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_TAPROOT), "P2SH,TAPROOT");
BOOST_CHECK_EQUAL(FormatScriptFlags(SCRIPT_VERIFY_P2SH | script_verify_flags::from_int(1u<<31)), "P2SH,0x80000000");
BOOST_CHECK_EQUAL(FormatScriptFlags(SCRIPT_VERIFY_TAPROOT | script_verify_flags::from_int(1u<<27)), "TAPROOT,0x08000000");
BOOST_CHECK_EQUAL(FormatScriptFlags(SCRIPT_VERIFY_TAPROOT | script_verify_flags::from_int((1u<<28) | (1ull<<58))), "TAPROOT,0x400000010000000");
BOOST_CHECK_EQUAL(FormatScriptFlags(script_verify_flags::from_int(1u<<26)), "0x04000000");
}
BOOST_AUTO_TEST_SUITE_END()

View File

@ -69,7 +69,7 @@ BOOST_AUTO_TEST_CASE(GetSigOpCount)
* Verifies script execution of the zeroth scriptPubKey of tx output and
* zeroth scriptSig and witness of tx input.
*/
static ScriptError VerifyWithFlag(const CTransaction& output, const CMutableTransaction& input, uint32_t flags)
static ScriptError VerifyWithFlag(const CTransaction& output, const CMutableTransaction& input, script_verify_flags flags)
{
ScriptError error;
CTransaction inputi(input);
@ -122,7 +122,7 @@ BOOST_AUTO_TEST_CASE(GetTxSigOpCost)
CKey key = GenerateRandomKey();
CPubKey pubkey = key.GetPubKey();
// Default flags
const uint32_t flags{SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH};
const script_verify_flags flags{SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH};
// Multisig script (legacy counting)
{

View File

@ -17,6 +17,7 @@
#include <policy/policy.h>
#include <policy/settings.h>
#include <primitives/transaction_identifier.h>
#include <script/interpreter.h>
#include <script/script.h>
#include <script/script_error.h>
#include <script/sigcache.h>
@ -49,41 +50,21 @@ typedef std::vector<unsigned char> valtype;
static CFeeRate g_dust{DUST_RELAY_TX_FEE};
static bool g_bare_multi{DEFAULT_PERMIT_BAREMULTISIG};
static std::map<std::string, unsigned int> mapFlagNames = {
{std::string("P2SH"), (unsigned int)SCRIPT_VERIFY_P2SH},
{std::string("STRICTENC"), (unsigned int)SCRIPT_VERIFY_STRICTENC},
{std::string("DERSIG"), (unsigned int)SCRIPT_VERIFY_DERSIG},
{std::string("LOW_S"), (unsigned int)SCRIPT_VERIFY_LOW_S},
{std::string("SIGPUSHONLY"), (unsigned int)SCRIPT_VERIFY_SIGPUSHONLY},
{std::string("MINIMALDATA"), (unsigned int)SCRIPT_VERIFY_MINIMALDATA},
{std::string("NULLDUMMY"), (unsigned int)SCRIPT_VERIFY_NULLDUMMY},
{std::string("DISCOURAGE_UPGRADABLE_NOPS"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS},
{std::string("CLEANSTACK"), (unsigned int)SCRIPT_VERIFY_CLEANSTACK},
{std::string("MINIMALIF"), (unsigned int)SCRIPT_VERIFY_MINIMALIF},
{std::string("NULLFAIL"), (unsigned int)SCRIPT_VERIFY_NULLFAIL},
{std::string("CHECKLOCKTIMEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY},
{std::string("CHECKSEQUENCEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKSEQUENCEVERIFY},
{std::string("WITNESS"), (unsigned int)SCRIPT_VERIFY_WITNESS},
{std::string("DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM},
{std::string("WITNESS_PUBKEYTYPE"), (unsigned int)SCRIPT_VERIFY_WITNESS_PUBKEYTYPE},
{std::string("CONST_SCRIPTCODE"), (unsigned int)SCRIPT_VERIFY_CONST_SCRIPTCODE},
{std::string("TAPROOT"), (unsigned int)SCRIPT_VERIFY_TAPROOT},
{std::string("DISCOURAGE_UPGRADABLE_PUBKEYTYPE"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE},
{std::string("DISCOURAGE_OP_SUCCESS"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS},
{std::string("DISCOURAGE_UPGRADABLE_TAPROOT_VERSION"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION},
};
static const std::map<std::string, script_verify_flag_name>& mapFlagNames = g_verify_flag_names;
unsigned int ParseScriptFlags(std::string strFlags)
script_verify_flags ParseScriptFlags(std::string strFlags)
{
unsigned int flags = SCRIPT_VERIFY_NONE;
script_verify_flags flags = SCRIPT_VERIFY_NONE;
if (strFlags.empty() || strFlags == "NONE") return flags;
std::vector<std::string> words = SplitString(strFlags, ',');
for (const std::string& word : words)
{
if (!mapFlagNames.count(word))
if (!mapFlagNames.count(word)) {
BOOST_ERROR("Bad test: unknown verification flag '" << word << "'");
flags |= mapFlagNames[word];
continue;
}
flags |= mapFlagNames.at(word);
}
return flags;
}
@ -91,34 +72,18 @@ unsigned int ParseScriptFlags(std::string strFlags)
// Check that all flags in STANDARD_SCRIPT_VERIFY_FLAGS are present in mapFlagNames.
bool CheckMapFlagNames()
{
unsigned int standard_flags_missing{STANDARD_SCRIPT_VERIFY_FLAGS};
script_verify_flags standard_flags_missing{STANDARD_SCRIPT_VERIFY_FLAGS};
for (const auto& pair : mapFlagNames) {
standard_flags_missing &= ~(pair.second);
}
return standard_flags_missing == 0;
}
std::string FormatScriptFlags(unsigned int flags)
{
if (flags == SCRIPT_VERIFY_NONE) {
return "";
}
std::string ret;
std::map<std::string, unsigned int>::const_iterator it = mapFlagNames.begin();
while (it != mapFlagNames.end()) {
if (flags & it->second) {
ret += it->first + ",";
}
it++;
}
return ret.substr(0, ret.size() - 1);
}
/*
* Check that the input scripts of a transaction are valid/invalid as expected.
*/
bool CheckTxScripts(const CTransaction& tx, const std::map<COutPoint, CScript>& map_prevout_scriptPubKeys,
const std::map<COutPoint, int64_t>& map_prevout_values, unsigned int flags,
const std::map<COutPoint, int64_t>& map_prevout_values, script_verify_flags flags,
const PrecomputedTransactionData& txdata, const std::string& strTest, bool expect_valid)
{
bool tx_valid = true;
@ -152,18 +117,18 @@ bool CheckTxScripts(const CTransaction& tx, const std::map<COutPoint, CScript>&
* CLEANSTACK must be used WITNESS and P2SH
*/
unsigned int TrimFlags(unsigned int flags)
script_verify_flags TrimFlags(script_verify_flags flags)
{
// WITNESS requires P2SH
if (!(flags & SCRIPT_VERIFY_P2SH)) flags &= ~(unsigned int)SCRIPT_VERIFY_WITNESS;
if (!(flags & SCRIPT_VERIFY_P2SH)) flags &= ~SCRIPT_VERIFY_WITNESS;
// CLEANSTACK requires WITNESS (and transitively CLEANSTACK requires P2SH)
if (!(flags & SCRIPT_VERIFY_WITNESS)) flags &= ~(unsigned int)SCRIPT_VERIFY_CLEANSTACK;
if (!(flags & SCRIPT_VERIFY_WITNESS)) flags &= ~SCRIPT_VERIFY_CLEANSTACK;
Assert(IsValidFlagCombination(flags));
return flags;
}
unsigned int FillFlags(unsigned int flags)
script_verify_flags FillFlags(script_verify_flags flags)
{
// CLEANSTACK implies WITNESS
if (flags & SCRIPT_VERIFY_CLEANSTACK) flags |= SCRIPT_VERIFY_WITNESS;
@ -178,11 +143,11 @@ unsigned int FillFlags(unsigned int flags)
// that are valid and without duplicates. For example: if flags=1111 and the 4 possible flags are
// 0001, 0010, 0100, and 1000, this should return the set {0111, 1011, 1101, 1110}.
// Assumes that mapFlagNames contains all script verify flags.
std::set<unsigned int> ExcludeIndividualFlags(unsigned int flags)
std::set<script_verify_flags> ExcludeIndividualFlags(script_verify_flags flags)
{
std::set<unsigned int> flags_combos;
std::set<script_verify_flags> flags_combos;
for (const auto& pair : mapFlagNames) {
const unsigned int flags_excluding_one = TrimFlags(flags & ~(pair.second));
script_verify_flags flags_excluding_one = TrimFlags(flags & ~(pair.second));
if (flags != flags_excluding_one) {
flags_combos.insert(flags_excluding_one);
}
@ -247,7 +212,7 @@ BOOST_AUTO_TEST_CASE(tx_valid)
BOOST_CHECK(state.IsValid());
PrecomputedTransactionData txdata(tx);
unsigned int verify_flags = ParseScriptFlags(test[2].get_str());
script_verify_flags verify_flags = ParseScriptFlags(test[2].get_str());
// Check that the test gives a valid combination of flags (otherwise VerifyScript will throw). Don't edit the flags.
if (~verify_flags != FillFlags(~verify_flags)) {
@ -260,14 +225,14 @@ BOOST_AUTO_TEST_CASE(tx_valid)
// Backwards compatibility of script verification flags: Removing any flag(s) should not invalidate a valid transaction
for (const auto& [name, flag] : mapFlagNames) {
// Removing individual flags
unsigned int flags = TrimFlags(~(verify_flags | flag));
script_verify_flags flags = TrimFlags(~(verify_flags | flag));
if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, flags, txdata, strTest, /*expect_valid=*/true)) {
BOOST_ERROR("Tx unexpectedly failed with flag " << name << " unset: " << strTest);
}
// Removing random combinations of flags
flags = TrimFlags(~(verify_flags | (unsigned int)m_rng.randbits(mapFlagNames.size())));
flags = TrimFlags(~(verify_flags | script_verify_flags::from_int(m_rng.randbits(MAX_SCRIPT_VERIFY_FLAGS_BITS))));
if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, flags, txdata, strTest, /*expect_valid=*/true)) {
BOOST_ERROR("Tx unexpectedly failed with random flags " << ToString(flags) << ": " << strTest);
BOOST_ERROR("Tx unexpectedly failed with random flags " << ToString(flags.as_int()) << ": " << strTest);
}
}
@ -337,7 +302,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
}
PrecomputedTransactionData txdata(tx);
unsigned int verify_flags = ParseScriptFlags(test[2].get_str());
script_verify_flags verify_flags = ParseScriptFlags(test[2].get_str());
// Check that the test gives a valid combination of flags (otherwise VerifyScript will throw). Don't edit the flags.
if (verify_flags != FillFlags(verify_flags)) {
@ -350,13 +315,13 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
// Backwards compatibility of script verification flags: Adding any flag(s) should not validate an invalid transaction
for (const auto& [name, flag] : mapFlagNames) {
unsigned int flags = FillFlags(verify_flags | flag);
script_verify_flags flags = FillFlags(verify_flags | flag);
// Adding individual flags
if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, flags, txdata, strTest, /*expect_valid=*/false)) {
BOOST_ERROR("Tx unexpectedly passed with flag " << name << " set: " << strTest);
}
// Adding random combinations of flags
flags = FillFlags(verify_flags | (unsigned int)m_rng.randbits(mapFlagNames.size()));
flags = FillFlags(verify_flags | script_verify_flags::from_int(m_rng.randbits(MAX_SCRIPT_VERIFY_FLAGS_BITS)));
if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, flags, txdata, strTest, /*expect_valid=*/false)) {
BOOST_ERROR("Tx unexpectedly passed with random flags " << name << ": " << strTest);
}
@ -488,7 +453,7 @@ static void CreateCreditAndSpend(const FillableSigningProvider& keystore, const
assert(input.vin[0].scriptWitness.stack == inputm.vin[0].scriptWitness.stack);
}
static void CheckWithFlag(const CTransactionRef& output, const CMutableTransaction& input, uint32_t flags, bool success)
static void CheckWithFlag(const CTransactionRef& output, const CMutableTransaction& input, script_verify_flags flags, bool success)
{
ScriptError error;
CTransaction inputi(input);

View File

@ -21,7 +21,7 @@ struct Dersig100Setup : public TestChain100Setup {
};
bool CheckInputScripts(const CTransaction& tx, TxValidationState& state,
const CCoinsViewCache& inputs, unsigned int flags, bool cacheSigStore,
const CCoinsViewCache& inputs, script_verify_flags flags, bool cacheSigStore,
bool cacheFullScriptStore, PrecomputedTransactionData& txdata,
ValidationCache& validation_cache,
std::vector<CScriptCheck>* pvChecks) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
@ -120,7 +120,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, Dersig100Setup)
// should fail.
// Capture this interaction with the upgraded_nop argument: set it when evaluating
// any script flag that is implemented as an upgraded NOP code.
static void ValidateCheckInputsForAllFlags(const CTransaction &tx, uint32_t failing_flags, bool add_to_cache, CCoinsViewCache& active_coins_tip, ValidationCache& validation_cache) EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
static void ValidateCheckInputsForAllFlags(const CTransaction &tx, script_verify_flags failing_flags, bool add_to_cache, CCoinsViewCache& active_coins_tip, ValidationCache& validation_cache) EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
{
PrecomputedTransactionData txdata;
@ -130,7 +130,7 @@ static void ValidateCheckInputsForAllFlags(const CTransaction &tx, uint32_t fail
TxValidationState state;
// Randomly selects flag combinations
uint32_t test_flags = (uint32_t) insecure_rand.randrange((SCRIPT_VERIFY_END_MARKER - 1) << 1);
script_verify_flags test_flags = script_verify_flags::from_int(insecure_rand.randrange(MAX_SCRIPT_VERIFY_FLAGS));
// Filter out incompatible flag choices
if ((test_flags & SCRIPT_VERIFY_CLEANSTACK)) {

View File

@ -5,7 +5,7 @@
#include <script/interpreter.h>
#include <test/util/script.h>
bool IsValidFlagCombination(unsigned flags)
bool IsValidFlagCombination(script_verify_flags flags)
{
if (flags & SCRIPT_VERIFY_CLEANSTACK && ~flags & (SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS)) return false;
if (flags & SCRIPT_VERIFY_WITNESS && ~flags & SCRIPT_VERIFY_P2SH) return false;

View File

@ -7,6 +7,7 @@
#include <crypto/sha256.h>
#include <script/script.h>
#include <script/verify_flags.h>
static const std::vector<uint8_t> WITNESS_STACK_ELEM_OP_TRUE{uint8_t{OP_TRUE}};
static const CScript P2WSH_OP_TRUE{
@ -31,6 +32,6 @@ static const std::vector<std::vector<uint8_t>> P2WSH_EMPTY_TRUE_STACK{{static_ca
static const std::vector<std::vector<uint8_t>> P2WSH_EMPTY_TWO_STACK{{static_cast<uint8_t>(OP_2)}, {}};
/** Flags that are not forbidden by an assert in script validation */
bool IsValidFlagCombination(unsigned flags);
bool IsValidFlagCombination(script_verify_flags flags);
#endif // BITCOIN_TEST_UTIL_SCRIPT_H

View File

@ -139,7 +139,7 @@ const CBlockIndex* Chainstate::FindForkInGlobalIndex(const CBlockLocator& locato
}
bool CheckInputScripts(const CTransaction& tx, TxValidationState& state,
const CCoinsViewCache& inputs, unsigned int flags, bool cacheSigStore,
const CCoinsViewCache& inputs, script_verify_flags flags, bool cacheSigStore,
bool cacheFullScriptStore, PrecomputedTransactionData& txdata,
ValidationCache& validation_cache,
std::vector<CScriptCheck>* pvChecks = nullptr)
@ -262,9 +262,6 @@ bool CheckSequenceLocksAtTip(CBlockIndex* tip,
return EvaluateSequenceLocks(index, {lock_points.height, lock_points.time});
}
// Returns the script flags which should be checked for a given block
static unsigned int GetBlockScriptFlags(const CBlockIndex& block_index, const ChainstateManager& chainman);
static void LimitMempoolSize(CTxMemPool& pool, CCoinsViewCache& coins_cache)
EXCLUSIVE_LOCKS_REQUIRED(::cs_main, pool.cs)
{
@ -398,7 +395,7 @@ void Chainstate::MaybeUpdateMempoolForReorg(
* */
static bool CheckInputsFromMempoolAndCache(const CTransaction& tx, TxValidationState& state,
const CCoinsViewCache& view, const CTxMemPool& pool,
unsigned int flags, PrecomputedTransactionData& txdata, CCoinsViewCache& coins_tip,
script_verify_flags flags, PrecomputedTransactionData& txdata, CCoinsViewCache& coins_tip,
ValidationCache& validation_cache)
EXCLUSIVE_LOCKS_REQUIRED(cs_main, pool.cs)
{
@ -1251,7 +1248,7 @@ bool MemPoolAccept::PolicyScriptChecks(const ATMPArgs& args, Workspace& ws)
const CTransaction& tx = *ws.m_ptx;
TxValidationState& state = ws.m_state;
constexpr unsigned int scriptVerifyFlags = STANDARD_SCRIPT_VERIFY_FLAGS;
constexpr script_verify_flags scriptVerifyFlags = STANDARD_SCRIPT_VERIFY_FLAGS;
// Check input scripts and signatures.
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
@ -1290,7 +1287,7 @@ bool MemPoolAccept::ConsensusScriptChecks(const ATMPArgs& args, Workspace& ws)
// There is a similar check in CreateNewBlock() to prevent creating
// invalid blocks (using TestBlockValidity), however allowing such
// transactions into the mempool can be exploited as a DoS attack.
unsigned int currentBlockScriptVerifyFlags{GetBlockScriptFlags(*m_active_chainstate.m_chain.Tip(), m_active_chainstate.m_chainman)};
script_verify_flags currentBlockScriptVerifyFlags{GetBlockScriptFlags(*m_active_chainstate.m_chain.Tip(), m_active_chainstate.m_chainman)};
if (!CheckInputsFromMempoolAndCache(tx, state, m_view, m_pool, currentBlockScriptVerifyFlags,
ws.m_precomputed_txdata, m_active_chainstate.CoinsTip(), GetValidationCache())) {
LogPrintf("BUG! PLEASE REPORT THIS! CheckInputScripts failed against latest-block but not STANDARD flags %s, %s\n", hash.ToString(), state.ToString());
@ -2098,7 +2095,7 @@ std::optional<std::pair<ScriptError, std::string>> CScriptCheck::operator()() {
const CScript &scriptSig = ptxTo->vin[nIn].scriptSig;
const CScriptWitness *witness = &ptxTo->vin[nIn].scriptWitness;
ScriptError error{SCRIPT_ERR_UNKNOWN_ERROR};
if (VerifyScript(scriptSig, m_tx_out.scriptPubKey, witness, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, m_tx_out.nValue, cacheStore, *m_signature_cache, *txdata), &error)) {
if (VerifyScript(scriptSig, m_tx_out.scriptPubKey, witness, m_flags, CachingTransactionSignatureChecker(ptxTo, nIn, m_tx_out.nValue, cacheStore, *m_signature_cache, *txdata), &error)) {
return std::nullopt;
} else {
auto debug_str = strprintf("input %i of %s (wtxid %s), spending %s:%i", nIn, ptxTo->GetHash().ToString(), ptxTo->GetWitnessHash().ToString(), ptxTo->vin[nIn].prevout.hash.ToString(), ptxTo->vin[nIn].prevout.n);
@ -2142,7 +2139,7 @@ ValidationCache::ValidationCache(const size_t script_execution_cache_bytes, cons
* Non-static (and redeclared) in src/test/txvalidationcache_tests.cpp
*/
bool CheckInputScripts(const CTransaction& tx, TxValidationState& state,
const CCoinsViewCache& inputs, unsigned int flags, bool cacheSigStore,
const CCoinsViewCache& inputs, script_verify_flags flags, bool cacheSigStore,
bool cacheFullScriptStore, PrecomputedTransactionData& txdata,
ValidationCache& validation_cache,
std::vector<CScriptCheck>* pvChecks)
@ -2330,7 +2327,7 @@ DisconnectResult Chainstate::DisconnectBlock(const CBlock& block, const CBlockIn
return fClean ? DISCONNECT_OK : DISCONNECT_UNCLEAN;
}
static unsigned int GetBlockScriptFlags(const CBlockIndex& block_index, const ChainstateManager& chainman)
script_verify_flags GetBlockScriptFlags(const CBlockIndex& block_index, const ChainstateManager& chainman)
{
const Consensus::Params& consensusparams = chainman.GetConsensus();
@ -2342,7 +2339,7 @@ static unsigned int GetBlockScriptFlags(const CBlockIndex& block_index, const Ch
// mainnet.
// For simplicity, always leave P2SH+WITNESS+TAPROOT on except for the two
// violating blocks.
uint32_t flags{SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_TAPROOT};
script_verify_flags flags{SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_TAPROOT};
const auto it{consensusparams.script_flag_exceptions.find(*Assert(block_index.phashBlock))};
if (it != consensusparams.script_flag_exceptions.end()) {
flags = it->second;
@ -2556,7 +2553,7 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
}
// Get the script flags for this block
unsigned int flags{GetBlockScriptFlags(*pindex, m_chainman)};
script_verify_flags flags{GetBlockScriptFlags(*pindex, m_chainman)};
const auto time_2{SteadyClock::now()};
m_chainman.time_forks += time_2 - time_1;

View File

@ -23,6 +23,7 @@
#include <policy/policy.h>
#include <script/script_error.h>
#include <script/sigcache.h>
#include <script/verify_flags.h>
#include <sync.h>
#include <txdb.h>
#include <txmempool.h>
@ -336,14 +337,14 @@ private:
CTxOut m_tx_out;
const CTransaction *ptxTo;
unsigned int nIn;
unsigned int nFlags;
script_verify_flags m_flags;
bool cacheStore;
PrecomputedTransactionData *txdata;
SignatureCache* m_signature_cache;
public:
CScriptCheck(const CTxOut& outIn, const CTransaction& txToIn, SignatureCache& signature_cache, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn, PrecomputedTransactionData* txdataIn) :
m_tx_out(outIn), ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), txdata(txdataIn), m_signature_cache(&signature_cache) { }
CScriptCheck(const CTxOut& outIn, const CTransaction& txToIn, SignatureCache& signature_cache, unsigned int nInIn, script_verify_flags flags, bool cacheIn, PrecomputedTransactionData* txdataIn) :
m_tx_out(outIn), ptxTo(&txToIn), nIn(nInIn), m_flags(flags), cacheStore(cacheIn), txdata(txdataIn), m_signature_cache(&signature_cache) { }
CScriptCheck(const CScriptCheck&) = delete;
CScriptCheck& operator=(const CScriptCheck&) = delete;
@ -1365,4 +1366,7 @@ bool IsBIP30Repeat(const CBlockIndex& block_index);
/** Identifies blocks which coinbase output was subsequently overwritten in the UTXO set (see BIP30) */
bool IsBIP30Unspendable(const uint256& block_hash, int block_height);
// Returns the script flags which should be checked for a given block
script_verify_flags GetBlockScriptFlags(const CBlockIndex& block_index, const ChainstateManager& chainman);
#endif // BITCOIN_VALIDATION_H

View File

@ -213,6 +213,7 @@ class BlockchainTest(BitcoinTestFramework):
assert_equal(gdi_result, {
"hash": blockhash,
"height": height,
"script_flags": ["CHECKLOCKTIMEVERIFY","CHECKSEQUENCEVERIFY","DERSIG","NULLDUMMY","P2SH","TAPROOT","WITNESS"],
"deployments": {
'bip34': {'type': 'buried', 'active': True, 'height': 2},
'bip66': {'type': 'buried', 'active': True, 'height': 3},