Compare commits

...

26 Commits

Author SHA1 Message Date
pablomartin4btc fc39f66e50
Merge 8aa49a4b82 into b510893d00 2025-10-08 02:00:47 +02: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
Ava Chow de1dc6b47b
Merge bitcoin/bitcoin#33515: Improve LastCommonAncestor performance + add tests
3635d62f5a chain: make use of pskip in LastCommonAncestor (optimization) (Pieter Wuille)
2e09d66fbb tests: add unit tests for CBlockIndex::GetAncestor and LastCommonAncestor (Pieter Wuille)

Pull request description:

  In theory, the `LastCommonAncestor` function in chain.cpp can take $\mathcal{O}(n)$ time, walking over the entire chain, if the forking point is very early, which could take ~milliseconds. I expect this to be very rare in normal occurrences, but it seems nontrivial to reason about worst cases as it's accessible from several places in net_processing.

  This PR modifies the algorithm to make use of the `CBlockIndex::pskip` skip pointers to find the forking point in sublinear time (a simulation shows that for heights up to $34 \cdot 4^k - 2$ and $k \geq 8$, no more than $k^2 + 10k + 13$ steps are ever needed), in a way that should be nearly free - at worst the same number of memory accesses should be made, with a tiny increase in computation.

  As it appears we didn't really have tests for this function, unit tests are added for that function as well as `CBlockIndex::GetAncestor()`.

  This is inspired by https://github.com/bitcoin/bitcoin/pull/32180#discussion_r2394877881

ACKs for top commit:
  optout21:
    ACK 3635d62f5a
  achow101:
    ACK 3635d62f5a
  vasild:
    ACK 3635d62f5a
  mzumsande:
    Code Review ACK 3635d62f5a
  furszy:
    ACK 3635d62f5a
  stratospher:
    ACK 3635d62f5a.

Tree-SHA512: f9b7dea1e34c1cc1ec1da3fb9e90c4acbf4aaf0f04768844f538201efa6b11eeeefc97b720509e78c21878977192e2c4031fd8974151667e2e756247002b8164
2025-10-07 13:54:25 -07:00
pablomartin4btc 8aa49a4b82 cli, refactor, test: Use parsed command args from ArgsManager
Refactor bitcoin-cli to use command arguments provided by ArgsManager
instead of manually slicing argv.

- Introduce GetCommandArgs() helper.
- Remove local argv/argc skipping logic.
- Simplify CommandLineRPC argument collection.

This improves consistency in bitcoin-cli, avoiding duplicating parsing
logic.

Added a new functional test passing an option after a non-option
argument (GNU-style).

No behavior change intended.
2025-10-04 19:37:00 -03:00
pablomartin4btc 13bb9caa54 argsman, test: Allow options after non-option arguments
Previously, ArgsManager stopped interpreting options once a
non-option argument was encountered (non-GNU parsing).

For example:

    bitcoind -a -b param -c

would ignore `-c` because it followed the non-option argument
`param`. In cases where some 'param' command receives parameters,
'-c' is interpreted as one of them producing unexpected behavior
(e.g. empty arrays for listtransactions command).

This commit changes the behavior so that options following
non-option argument are recognized and processed (GNU parsing).
This is needed for workflows for tools like CLI where command
arguments may be followed by wallet- or RPC-specific options, e.g.:

    bitcoin-cli listtransactions -rpcwallet=mywallet

    bitcoin-cli getaddressinfo <address> -rpcwallet=mywallet

    bitcoin-wallet create -wallet=newname
2025-10-04 19:37:00 -03:00
pablomartin4btc 283198874a util, refactor, test: Reintroduce ParsePrechecks and ParseDouble helpers
Previously removed in commit fa9d72a794 (PR #23156)
due to lack of use.

Reintroducing these helpers to support the next commit, which verifies
negative numbers passed as command line arguments.
2025-10-04 19:36:46 -03:00
pablomartin4btc 15039d6c64 argsman, refactor: Factor out ProcessOptionKey from ParseParameters
- Centralizes normalization of option keys in `ProcessOptionKey`.
  This will help in next commit to reuse this function avoiding code
  duplication.
- Improves readability and makes behavior easier to reason about.

Functional and unit tests confirm no behavior change.
2025-10-02 15:10:45 -03:00
Pieter Wuille 3635d62f5a chain: make use of pskip in LastCommonAncestor (optimization)
By using the pskip pointer, which regularly allows jumping back much faster
than pprev, the forking point between two CBlockIndex entries can be found
much faster.

A simulation shows that no more than 136 steps are needed to jump anywhere
within the first 2^20 block heights, and on average 65 jumps for uniform
forking points around that height.
2025-10-02 10:34:12 -04:00
Pieter Wuille 2e09d66fbb tests: add unit tests for CBlockIndex::GetAncestor and LastCommonAncestor 2025-10-02 10:34:09 -04: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
43 changed files with 605 additions and 238 deletions

View File

@ -211,11 +211,16 @@ jobs:
steps:
- *CHECKOUT
- name: Configure Developer Command Prompt for Microsoft Visual C++
# Using microsoft/setup-msbuild is not enough.
uses: ilammy/msvc-dev-cmd@v1
with:
arch: x64
- &SET_UP_VS
name: Set up VS Developer Prompt
shell: pwsh -Command "$PSVersionTable; $PSNativeCommandUseErrorActionPreference = $true; $ErrorActionPreference = 'Stop'; & '{0}'"
run: |
$vswherePath = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
$installationPath = & $vswherePath -latest -property installationPath
& "${env:COMSPEC}" /s /c "`"$installationPath\Common7\Tools\vsdevcmd.bat`" -arch=x64 -no_logo && set" | foreach-object {
$name, $value = $_ -split '=', 2
echo "$name=$value" >> $env:GITHUB_ENV
}
- name: Get tool information
shell: pwsh
@ -263,14 +268,26 @@ jobs:
run: |
cmake --build . -j $NUMBER_OF_PROCESSORS --config Release
- name: Get bitcoind manifest
- name: Check executable manifests
if: matrix.job-type == 'standard'
working-directory: build
shell: pwsh -Command "$PSVersionTable; $PSNativeCommandUseErrorActionPreference = $true; $ErrorActionPreference = 'Stop'; & '{0}'"
run: |
mt.exe -nologo -inputresource:bin/Release/bitcoind.exe -out:bitcoind.manifest
cat bitcoind.manifest
echo
mt.exe -nologo -inputresource:bin/Release/bitcoind.exe -validate_manifest
mt.exe -nologo -inputresource:bin\Release\bitcoind.exe -out:bitcoind.manifest
Get-Content bitcoind.manifest
Get-ChildItem -Filter "bin\Release\*.exe" | ForEach-Object {
$exeName = $_.Name
# Skip as they currently do not have manifests
if ($exeName -eq "fuzz.exe" -or $exeName -eq "bench_bitcoin.exe" -or $exeName -eq "test_bitcoin-qt.exe") {
Write-Host "Skipping $exeName (no manifest present)"
return
}
Write-Host "Checking $exeName"
& mt.exe -nologo -inputresource:$_.FullName -validate_manifest
}
- name: Run test suite
if: matrix.job-type == 'standard'
@ -370,19 +387,26 @@ jobs:
- name: Run bitcoind.exe
run: ./bin/bitcoind.exe -version
- name: Find mt.exe tool
shell: pwsh
run: |
$sdk_dir = (Get-ItemProperty 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows Kits\Installed Roots' -Name KitsRoot10).KitsRoot10
$sdk_latest = (Get-ChildItem "$sdk_dir\bin" -Directory | Where-Object { $_.Name -match '^\d+\.\d+\.\d+\.\d+$' } | Sort-Object Name -Descending | Select-Object -First 1).Name
"MT_EXE=${sdk_dir}bin\${sdk_latest}\x64\mt.exe" >> $env:GITHUB_ENV
- *SET_UP_VS
- name: Get bitcoind manifest
shell: pwsh
- name: Check executable manifests
shell: pwsh -Command "$PSVersionTable; $PSNativeCommandUseErrorActionPreference = $true; $ErrorActionPreference = 'Stop'; & '{0}'"
run: |
& $env:MT_EXE -nologo -inputresource:bin\bitcoind.exe -out:bitcoind.manifest
mt.exe -nologo -inputresource:bin\bitcoind.exe -out:bitcoind.manifest
Get-Content bitcoind.manifest
& $env:MT_EXE -nologo -inputresource:bin\bitcoind.exe -validate_manifest
Get-ChildItem -Filter "bin\*.exe" | ForEach-Object {
$exeName = $_.Name
# Skip as they currently do not have manifests
if ($exeName -eq "fuzz.exe" -or $exeName -eq "bench_bitcoin.exe") {
Write-Host "Skipping $exeName (no manifest present)"
return
}
Write-Host "Checking $exeName"
& mt.exe -nologo -inputresource:$_.FullName -validate_manifest
}
- name: Run unit tests
# Can't use ctest here like other jobs as we don't have a CMake build tree.

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

@ -1207,16 +1207,21 @@ static void SetGenerateToAddressArgs(const std::string& address, std::vector<std
args.emplace(args.begin() + 1, address);
}
static int CommandLineRPC(int argc, char *argv[])
std::vector<std::string> GetCommandArgs() {
std::optional<const ArgsManager::Command> command = gArgs.GetCommand();
// Return command args if command is present, otherwise return an empty vector
if (command.has_value()) {
return command->args;
}
return {};
}
static int CommandLineRPC()
{
std::string strPrint;
int nRet = 0;
try {
// Skip switches
while (argc > 1 && IsSwitchChar(argv[1][0])) {
argc--;
argv++;
}
std::string rpcPass;
if (gArgs.GetBoolArg("-stdinrpcpass", false)) {
NO_STDIN_ECHO();
@ -1232,7 +1237,7 @@ static int CommandLineRPC(int argc, char *argv[])
}
gArgs.ForceSetArg("-rpcpassword", rpcPass);
}
std::vector<std::string> args = std::vector<std::string>(&argv[1], &argv[argc]);
std::vector<std::string> args = GetCommandArgs();
if (gArgs.GetBoolArg("-stdinwalletpassphrase", false)) {
NO_STDIN_ECHO();
std::string walletPass;
@ -1354,7 +1359,7 @@ MAIN_FUNCTION
int ret = EXIT_FAILURE;
try {
ret = CommandLineRPC(argc, argv);
ret = CommandLineRPC();
}
catch (const std::exception& e) {
PrintExceptionContinue(&e, "CommandLineRPC()");

View File

@ -5,6 +5,7 @@
#include <chain.h>
#include <tinyformat.h>
#include <util/check.h>
#include <util/time.h>
std::string CBlockFileInfo::ToString() const
@ -158,18 +159,26 @@ int64_t GetBlockProofEquivalentTime(const CBlockIndex& to, const CBlockIndex& fr
/** Find the last common ancestor two blocks have.
* Both pa and pb must be non-nullptr. */
const CBlockIndex* LastCommonAncestor(const CBlockIndex* pa, const CBlockIndex* pb) {
// First rewind to the last common height (the forking point cannot be past one of the two).
if (pa->nHeight > pb->nHeight) {
pa = pa->GetAncestor(pb->nHeight);
} else if (pb->nHeight > pa->nHeight) {
pb = pb->GetAncestor(pa->nHeight);
}
while (pa != pb && pa && pb) {
while (pa != pb) {
// Jump back until pa and pb have a common "skip" ancestor.
while (pa->pskip != pb->pskip) {
// This logic relies on the property that equal-height blocks have equal-height skip
// pointers.
Assume(pa->nHeight == pb->nHeight);
Assume(pa->pskip->nHeight == pb->pskip->nHeight);
pa = pa->pskip;
pb = pb->pskip;
}
// At this point, pa and pb are different, but have equal pskip. The forking point lies in
// between pa/pb on the one end, and pa->pskip/pb->pskip on the other end.
pa = pa->pprev;
pb = pb->pprev;
}
// Eventually all chain branches meet at the genesis block.
assert(pa == pb);
return pa;
}

View File

@ -176,6 +176,42 @@ void ArgsManager::SelectConfigNetwork(const std::string& network)
m_network = network;
}
bool IsArgNumber(const char* arg) {
double dummy{};
return ParseDouble(arg, &dummy);
}
bool ArgsManager::ProcessOptionKey(std::string& key, std::optional<std::string>& val, std::string& error) {
std::string original_input = key; // Capture the original key
if (val) original_input += "=" + *val; // Append =value if it exists
// Transform --foo to -foo
if (key.length() > 1 && key[1] == '-')
key.erase(0, 1);
// Transform -foo to foo
key.erase(0, 1);
KeyInfo keyinfo = InterpretKey(key);
std::optional<unsigned int> flags = GetArgFlags('-' + keyinfo.name);
// Unknown command line options and command line options with dot characters
// (which are returned from InterpretKey with nonempty section strings)are not valid.
if (!flags || !keyinfo.section.empty()) {
error = strprintf("Invalid parameter %s", original_input);
return false;
}
std::optional<common::SettingsValue> value = InterpretValue(keyinfo, val ? &*val : nullptr, *flags, error);
if (!value) return false;
// Store the option
LOCK(cs_args);
m_settings.command_line_options[keyinfo.name].push_back(*value);
return true;
}
bool ArgsManager::ParseParameters(int argc, const char* const argv[], std::string& error)
{
LOCK(cs_args);
@ -217,32 +253,28 @@ bool ArgsManager::ParseParameters(int argc, const char* const argv[], std::strin
m_command.push_back(key);
while (++i < argc) {
// The remaining args are command args
m_command.emplace_back(argv[i]);
if (argv[i][0] == '-' && !IsArgNumber(argv[i])) {
// except it starts with dash "-" (and it's not a number) then will check if it's a valid option
key = argv[i];
val.reset();
is_index = key.find('=');
if (is_index != std::string::npos) {
val = key.substr(is_index + 1);
key.erase(is_index);
}
if (!ProcessOptionKey(key, val, error)) {
return false;
}
} else {
m_command.emplace_back(argv[i]);
}
}
break;
}
// Transform --foo to -foo
if (key.length() > 1 && key[1] == '-')
key.erase(0, 1);
// Transform -foo to foo
key.erase(0, 1);
KeyInfo keyinfo = InterpretKey(key);
std::optional<unsigned int> flags = GetArgFlags('-' + keyinfo.name);
// Unknown command line options and command line options with dot
// characters (which are returned from InterpretKey with nonempty
// section strings) are not valid.
if (!flags || !keyinfo.section.empty()) {
error = strprintf("Invalid parameter %s", argv[i]);
if (!ProcessOptionKey(key, val, error)) {
return false;
}
std::optional<common::SettingsValue> value = InterpretValue(keyinfo, val ? &*val : nullptr, *flags, error);
if (!value) return false;
m_settings.command_line_options[keyinfo.name].push_back(*value);
}
// we do not allow -includeconf from command line, only -noincludeconf

View File

@ -446,6 +446,8 @@ private:
const std::string& prefix,
const std::string& section,
const std::map<std::string, std::vector<common::SettingsValue>>& args) const;
bool ProcessOptionKey(std::string& key, std::optional<std::string>& val, std::string& error);
};
extern ArgsManager gArgs;

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

@ -26,6 +26,7 @@ add_executable(test_bitcoin
bloom_tests.cpp
bswap_tests.cpp
caches_tests.cpp
chain_tests.cpp
chainstate_write_tests.cpp
checkqueue_tests.cpp
cluster_linearize_tests.cpp

View File

@ -1,4 +1,4 @@
// Copyright (c) 2011-2022 The Bitcoin Core developers
// Copyright (c) 2011-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.
@ -227,13 +227,13 @@ BOOST_AUTO_TEST_CASE(util_ParseParameters)
BOOST_CHECK(testArgs.ParseParameters(7, argv_test, error));
// expectation: -ignored is ignored (program name argument),
// -a, -b and -ccc end up in map, -d ignored because it is after
// a non-option argument (non-GNU option parsing)
BOOST_CHECK(testArgs.m_settings.command_line_options.size() == 3 && testArgs.m_settings.ro_config.empty());
// -a, -b and -ccc end up in map, also -d since the parser detects
// [options] after a non-option argument (GNU-style option parsing)
BOOST_CHECK(testArgs.m_settings.command_line_options.size() == 4 && testArgs.m_settings.ro_config.empty());
BOOST_CHECK(testArgs.IsArgSet("-a") && testArgs.IsArgSet("-b") && testArgs.IsArgSet("-ccc")
&& !testArgs.IsArgSet("f") && !testArgs.IsArgSet("-d"));
&& !testArgs.IsArgSet("f") && testArgs.IsArgSet("-d"));
BOOST_CHECK(testArgs.m_settings.command_line_options.count("a") && testArgs.m_settings.command_line_options.count("b") && testArgs.m_settings.command_line_options.count("ccc")
&& !testArgs.m_settings.command_line_options.count("f") && !testArgs.m_settings.command_line_options.count("d"));
&& !testArgs.m_settings.command_line_options.count("f") && testArgs.m_settings.command_line_options.count("d"));
BOOST_CHECK(testArgs.m_settings.command_line_options["a"].size() == 1);
BOOST_CHECK(testArgs.m_settings.command_line_options["a"].front().get_str() == "");

85
src/test/chain_tests.cpp Normal file
View File

@ -0,0 +1,85 @@
// Copyright (c) The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <boost/test/unit_test.hpp>
#include <chain.h>
#include <test/util/setup_common.h>
#include <memory>
BOOST_FIXTURE_TEST_SUITE(chain_tests, BasicTestingSetup)
namespace {
const CBlockIndex* NaiveGetAncestor(const CBlockIndex* a, int height)
{
while (a->nHeight > height) {
a = a->pprev;
}
BOOST_REQUIRE_EQUAL(a->nHeight, height);
return a;
}
const CBlockIndex* NaiveLastCommonAncestor(const CBlockIndex* a, const CBlockIndex* b)
{
while (a->nHeight > b->nHeight) {
a = a->pprev;
}
while (b->nHeight > a->nHeight) {
b = b->pprev;
}
while (a != b) {
BOOST_REQUIRE_EQUAL(a->nHeight, b->nHeight);
a = a->pprev;
b = b->pprev;
}
BOOST_REQUIRE_EQUAL(a, b);
return a;
}
} // namespace
BOOST_AUTO_TEST_CASE(chain_test)
{
FastRandomContext ctx;
std::vector<std::unique_ptr<CBlockIndex>> block_index;
// Run 10 iterations of the whole test.
for (int i = 0; i < 10; ++i) {
block_index.clear();
// Create genesis block.
auto genesis = std::make_unique<CBlockIndex>();
genesis->nHeight = 0;
block_index.push_back(std::move(genesis));
// Create 10000 more blocks.
for (int b = 0; b < 10000; ++b) {
auto new_index = std::make_unique<CBlockIndex>();
// 95% of blocks build on top of the last block; the others fork off randomly.
if (ctx.randrange(20) != 0) {
new_index->pprev = block_index.back().get();
} else {
new_index->pprev = block_index[ctx.randrange(block_index.size())].get();
}
new_index->nHeight = new_index->pprev->nHeight + 1;
new_index->BuildSkip();
block_index.push_back(std::move(new_index));
}
// Run 10000 random GetAncestor queries.
for (int q = 0; q < 10000; ++q) {
const CBlockIndex* block = block_index[ctx.randrange(block_index.size())].get();
unsigned height = ctx.randrange<unsigned>(block->nHeight + 1);
const CBlockIndex* result = block->GetAncestor(height);
BOOST_CHECK(result == NaiveGetAncestor(block, height));
}
// Run 10000 random LastCommonAncestor queries.
for (int q = 0; q < 10000; ++q) {
const CBlockIndex* block1 = block_index[ctx.randrange(block_index.size())].get();
const CBlockIndex* block2 = block_index[ctx.randrange(block_index.size())].get();
const CBlockIndex* result = LastCommonAncestor(block1, block2);
BOOST_CHECK(result == NaiveLastCommonAncestor(block1, block2));
}
}
}
BOOST_AUTO_TEST_SUITE_END()

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

@ -1,4 +1,4 @@
// Copyright (c) 2009-2021 The Bitcoin Core developers
// 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.
@ -55,6 +55,9 @@ FUZZ_TARGET(parse_numbers)
(void)ParseMoney(random_string);
double d;
(void)ParseDouble(random_string, &d);
(void)LocaleIndependentAtoi<int>(random_string);
int64_t i64;

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

@ -835,6 +835,32 @@ BOOST_AUTO_TEST_CASE(test_LocaleIndependentAtoi)
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint8_t>("256"), 255U);
}
BOOST_AUTO_TEST_CASE(test_ParseDouble)
{
double n;
// Valid values
BOOST_CHECK(ParseDouble("1234", nullptr));
BOOST_CHECK(ParseDouble("0", &n) && n == 0.0);
BOOST_CHECK(ParseDouble("1234", &n) && n == 1234.0);
BOOST_CHECK(ParseDouble("01234", &n) && n == 1234.0); // no octal
BOOST_CHECK(ParseDouble("2147483647", &n) && n == 2147483647.0);
BOOST_CHECK(ParseDouble("-2147483648", &n) && n == -2147483648.0);
BOOST_CHECK(ParseDouble("-1234", &n) && n == -1234.0);
BOOST_CHECK(ParseDouble("1e6", &n) && n == 1e6);
BOOST_CHECK(ParseDouble("-1e6", &n) && n == -1e6);
// Invalid values
BOOST_CHECK(!ParseDouble("", &n));
BOOST_CHECK(!ParseDouble(" 1", &n)); // no padding inside
BOOST_CHECK(!ParseDouble("1 ", &n));
BOOST_CHECK(!ParseDouble("1a", &n));
BOOST_CHECK(!ParseDouble("aap", &n));
BOOST_CHECK(!ParseDouble("0x1", &n)); // no hex
BOOST_CHECK(!ParseDouble(STRING_WITH_EMBEDDED_NULL_CHAR, &n));
// Overflow and underflow
BOOST_CHECK(!ParseDouble("-1e10000", nullptr));
BOOST_CHECK(!ParseDouble("1e10000", nullptr));
}
BOOST_AUTO_TEST_CASE(test_FormatParagraph)
{
BOOST_CHECK_EQUAL(FormatParagraph("", 79, 0), "");

View File

@ -17,6 +17,8 @@
#include <string>
#include <vector>
using util::ContainsNoNUL;
static const std::string CHARS_ALPHA_NUM = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
static const std::string SAFE_CHARS[] =
@ -199,6 +201,31 @@ std::optional<std::vector<unsigned char>> DecodeBase32(std::string_view str)
return ret;
}
[[nodiscard]] static bool ParsePrechecks(const std::string& str)
{
if (str.empty()) // No empty string allowed
return false;
if (str.size() >= 1 && (IsSpace(str[0]) || IsSpace(str[str.size()-1]))) // No padding allowed
return false;
if (!ContainsNoNUL(str)) // No embedded NUL characters allowed
return false;
return true;
}
bool ParseDouble(const std::string& str, double *out)
{
if (!ParsePrechecks(str))
return false;
if (str.size() >= 2 && str[0] == '0' && str[1] == 'x') // No hexadecimal floats allowed
return false;
std::istringstream text(str);
text.imbue(std::locale::classic());
double result;
text >> result;
if(out) *out = result;
return text.eof() && !text.fail();
}
std::string FormatParagraph(std::string_view in, size_t width, size_t indent)
{
assert(width >= indent);

View File

@ -186,6 +186,13 @@ std::optional<T> ToIntegral(std::string_view str)
return result;
}
/**
* Convert string to double with strict parse error feedback.
* @returns true if the entire string could be parsed as valid double,
* false if not the entire string could be parsed or when overflow or underflow occurred.
*/
[[nodiscard]] bool ParseDouble(const std::string& str, double *out);
/**
* Format a paragraph of text to a fixed width, adding spaces for
* indentation to any added line.

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

@ -1,5 +1,5 @@
#!/usr/bin/env python3
# Copyright (c) 2017-2022 The Bitcoin Core developers
# Copyright (c) 2017-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.
"""Test bitcoin-cli"""
@ -352,6 +352,7 @@ class TestBitcoinCli(BitcoinTestFramework):
self.nodes[0].loadwallet(wallets[2])
n3 = 4
n4 = 10
n5 = 5
blocks = self.nodes[0].getblockcount()
self.log.info('Test -generate -rpcwallet=<filename> raise RPC error')
@ -386,9 +387,15 @@ class TestBitcoinCli(BitcoinTestFramework):
assert_raises_rpc_error(-19, WALLET_NOT_SPECIFIED, self.nodes[0].cli('-generate', 'foo').echo)
assert_raises_rpc_error(-19, WALLET_NOT_SPECIFIED, self.nodes[0].cli('-generate', 0).echo)
assert_raises_rpc_error(-19, WALLET_NOT_SPECIFIED, self.nodes[0].cli('-generate', 1, 2, 3).echo)
self.log.info('Test -generate passing -rpcwallet after the nblocks arg')
generate = self.nodes[0].cli('-generate', n5, rpcwallet2).send_cli()
assert_equal(set(generate.keys()), {'address', 'blocks'})
assert_equal(len(generate["blocks"]), n5)
assert_equal(self.nodes[0].getblockcount(), blocks + 1 + n3 + n4 + n5)
else:
self.log.info("*** Wallet not compiled; cli getwalletinfo and -getinfo wallet tests skipped")
self.generate(self.nodes[0], 25) # maintain block parity with the wallet_compiled conditional branch
self.generate(self.nodes[0], 30) # maintain block parity with the wallet_compiled conditional branch
self.test_netinfo()
@ -402,7 +409,7 @@ class TestBitcoinCli(BitcoinTestFramework):
self.nodes[0].wait_for_cookie_credentials() # ensure cookie file is available to avoid race condition
blocks = self.nodes[0].cli('-rpcwait').send_cli('getblockcount')
self.nodes[0].wait_for_rpc_connection()
assert_equal(blocks, BLOCKS + 25)
assert_equal(blocks, BLOCKS + 30)
self.log.info("Test -rpcwait option waits at most -rpcwaittimeout seconds for startup")
self.stop_node(0) # stop the node so we time out

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},