mirror of https://github.com/bitcoin/bitcoin.git
Compare commits
23 Commits
e694f8dc99
...
d36d605e63
Author | SHA1 | Date |
---|---|---|
|
d36d605e63 | |
|
b510893d00 | |
|
ec5841888d | |
|
d735e2e9b3 | |
|
de1dc6b47b | |
|
0fe7d552ab | |
|
3635d62f5a | |
|
2e09d66fbb | |
|
156927903d | |
|
e1a1b14c93 | |
|
93a70a42d3 | |
|
6de8051263 | |
|
46135d90ea | |
|
771978952a | |
|
7ae0497eef | |
|
652424ad16 | |
|
417437eb01 | |
|
3cbbcb66ef | |
|
bddcadee82 | |
|
a5ead122fe | |
|
4577fb2b1e | |
|
a3986935f0 | |
|
5db8cd2d37 |
|
@ -211,11 +211,16 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
- *CHECKOUT
|
- *CHECKOUT
|
||||||
|
|
||||||
- name: Configure Developer Command Prompt for Microsoft Visual C++
|
- &SET_UP_VS
|
||||||
# Using microsoft/setup-msbuild is not enough.
|
name: Set up VS Developer Prompt
|
||||||
uses: ilammy/msvc-dev-cmd@v1
|
shell: pwsh -Command "$PSVersionTable; $PSNativeCommandUseErrorActionPreference = $true; $ErrorActionPreference = 'Stop'; & '{0}'"
|
||||||
with:
|
run: |
|
||||||
arch: x64
|
$vswherePath = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
|
||||||
|
$installationPath = & $vswherePath -latest -property installationPath
|
||||||
|
& "${env:COMSPEC}" /s /c "`"$installationPath\Common7\Tools\vsdevcmd.bat`" -arch=x64 -no_logo && set" | foreach-object {
|
||||||
|
$name, $value = $_ -split '=', 2
|
||||||
|
echo "$name=$value" >> $env:GITHUB_ENV
|
||||||
|
}
|
||||||
|
|
||||||
- name: Get tool information
|
- name: Get tool information
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
|
@ -263,14 +268,26 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
cmake --build . -j $NUMBER_OF_PROCESSORS --config Release
|
cmake --build . -j $NUMBER_OF_PROCESSORS --config Release
|
||||||
|
|
||||||
- name: Get bitcoind manifest
|
- name: Check executable manifests
|
||||||
if: matrix.job-type == 'standard'
|
if: matrix.job-type == 'standard'
|
||||||
working-directory: build
|
working-directory: build
|
||||||
|
shell: pwsh -Command "$PSVersionTable; $PSNativeCommandUseErrorActionPreference = $true; $ErrorActionPreference = 'Stop'; & '{0}'"
|
||||||
run: |
|
run: |
|
||||||
mt.exe -nologo -inputresource:bin/Release/bitcoind.exe -out:bitcoind.manifest
|
mt.exe -nologo -inputresource:bin\Release\bitcoind.exe -out:bitcoind.manifest
|
||||||
cat bitcoind.manifest
|
Get-Content bitcoind.manifest
|
||||||
echo
|
|
||||||
mt.exe -nologo -inputresource:bin/Release/bitcoind.exe -validate_manifest
|
Get-ChildItem -Filter "bin\Release\*.exe" | ForEach-Object {
|
||||||
|
$exeName = $_.Name
|
||||||
|
|
||||||
|
# Skip as they currently do not have manifests
|
||||||
|
if ($exeName -eq "fuzz.exe" -or $exeName -eq "bench_bitcoin.exe" -or $exeName -eq "test_bitcoin-qt.exe") {
|
||||||
|
Write-Host "Skipping $exeName (no manifest present)"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "Checking $exeName"
|
||||||
|
& mt.exe -nologo -inputresource:$_.FullName -validate_manifest
|
||||||
|
}
|
||||||
|
|
||||||
- name: Run test suite
|
- name: Run test suite
|
||||||
if: matrix.job-type == 'standard'
|
if: matrix.job-type == 'standard'
|
||||||
|
@ -370,19 +387,26 @@ jobs:
|
||||||
- name: Run bitcoind.exe
|
- name: Run bitcoind.exe
|
||||||
run: ./bin/bitcoind.exe -version
|
run: ./bin/bitcoind.exe -version
|
||||||
|
|
||||||
- name: Find mt.exe tool
|
- *SET_UP_VS
|
||||||
shell: pwsh
|
|
||||||
run: |
|
|
||||||
$sdk_dir = (Get-ItemProperty 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows Kits\Installed Roots' -Name KitsRoot10).KitsRoot10
|
|
||||||
$sdk_latest = (Get-ChildItem "$sdk_dir\bin" -Directory | Where-Object { $_.Name -match '^\d+\.\d+\.\d+\.\d+$' } | Sort-Object Name -Descending | Select-Object -First 1).Name
|
|
||||||
"MT_EXE=${sdk_dir}bin\${sdk_latest}\x64\mt.exe" >> $env:GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Get bitcoind manifest
|
- name: Check executable manifests
|
||||||
shell: pwsh
|
shell: pwsh -Command "$PSVersionTable; $PSNativeCommandUseErrorActionPreference = $true; $ErrorActionPreference = 'Stop'; & '{0}'"
|
||||||
run: |
|
run: |
|
||||||
& $env:MT_EXE -nologo -inputresource:bin\bitcoind.exe -out:bitcoind.manifest
|
mt.exe -nologo -inputresource:bin\bitcoind.exe -out:bitcoind.manifest
|
||||||
Get-Content bitcoind.manifest
|
Get-Content bitcoind.manifest
|
||||||
& $env:MT_EXE -nologo -inputresource:bin\bitcoind.exe -validate_manifest
|
|
||||||
|
Get-ChildItem -Filter "bin\*.exe" | ForEach-Object {
|
||||||
|
$exeName = $_.Name
|
||||||
|
|
||||||
|
# Skip as they currently do not have manifests
|
||||||
|
if ($exeName -eq "fuzz.exe" -or $exeName -eq "bench_bitcoin.exe") {
|
||||||
|
Write-Host "Skipping $exeName (no manifest present)"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "Checking $exeName"
|
||||||
|
& mt.exe -nologo -inputresource:$_.FullName -validate_manifest
|
||||||
|
}
|
||||||
|
|
||||||
- name: Run unit tests
|
- name: Run unit tests
|
||||||
# Can't use ctest here like other jobs as we don't have a CMake build tree.
|
# Can't use ctest here like other jobs as we don't have a CMake build tree.
|
||||||
|
|
|
@ -301,6 +301,7 @@ mkdir -p "$DISTSRC"
|
||||||
;;
|
;;
|
||||||
*linux*)
|
*linux*)
|
||||||
cp "${DISTSRC}/README.md" "${DISTNAME}/"
|
cp "${DISTSRC}/README.md" "${DISTNAME}/"
|
||||||
|
cp "${DISTSRC}/doc/INSTALL_linux.md" "${DISTNAME}/INSTALL.md"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
|
|
@ -36,9 +36,8 @@ define fetch_file_inner
|
||||||
endef
|
endef
|
||||||
|
|
||||||
define fetch_file
|
define fetch_file
|
||||||
( test -f $$($(1)_source_dir)/$(4) || \
|
|
||||||
( $(call fetch_file_inner,$(1),$(2),$(3),$(4),$(5)) || \
|
( $(call fetch_file_inner,$(1),$(2),$(3),$(4),$(5)) || \
|
||||||
$(call fetch_file_inner,$(1),$(FALLBACK_DOWNLOAD_PATH),$(3),$(4),$(5))))
|
$(call fetch_file_inner,$(1),$(FALLBACK_DOWNLOAD_PATH),$(3),$(4),$(5)))
|
||||||
endef
|
endef
|
||||||
|
|
||||||
# Shell script to create a source tarball in $(1)_source from local directory
|
# Shell script to create a source tarball in $(1)_source from local directory
|
||||||
|
@ -109,7 +108,7 @@ $(1)_prefixbin:=$($($(1)_type)_prefix)/bin/
|
||||||
$(1)_all_sources=$($(1)_file_name) $($(1)_extra_sources)
|
$(1)_all_sources=$($(1)_file_name) $($(1)_extra_sources)
|
||||||
|
|
||||||
#stamps
|
#stamps
|
||||||
$(1)_fetched=$(SOURCES_PATH)/download-stamps/.stamp_fetched-$(1)-$($(1)_file_name).hash
|
$(1)_fetched=$(SOURCES_PATH)/download-stamps/.stamp_fetched-$(1)-$($(1)_version)-$($(1)_sha256_hash).hash
|
||||||
$(1)_extracted=$$($(1)_extract_dir)/.stamp_extracted
|
$(1)_extracted=$$($(1)_extract_dir)/.stamp_extracted
|
||||||
$(1)_preprocessed=$$($(1)_extract_dir)/.stamp_preprocessed
|
$(1)_preprocessed=$$($(1)_extract_dir)/.stamp_preprocessed
|
||||||
$(1)_cleaned=$$($(1)_extract_dir)/.stamp_cleaned
|
$(1)_cleaned=$$($(1)_extract_dir)/.stamp_cleaned
|
||||||
|
@ -247,7 +246,6 @@ endif
|
||||||
$($(1)_fetched):
|
$($(1)_fetched):
|
||||||
mkdir -p $$(@D) $(SOURCES_PATH)
|
mkdir -p $$(@D) $(SOURCES_PATH)
|
||||||
rm -f $$@
|
rm -f $$@
|
||||||
touch $$@
|
|
||||||
cd $$(@D); $($(1)_fetch_cmds)
|
cd $$(@D); $($(1)_fetch_cmds)
|
||||||
cd $($(1)_source_dir); $(foreach source,$($(1)_all_sources),$(build_SHA256SUM) $(source) >> $$(@);)
|
cd $($(1)_source_dir); $(foreach source,$($(1)_all_sources),$(build_SHA256SUM) $(source) >> $$(@);)
|
||||||
touch $$@
|
touch $$@
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
package=qrencode
|
package=qrencode
|
||||||
$(package)_version=4.1.1
|
$(package)_version=4.1.1
|
||||||
$(package)_download_path=https://fukuchi.org/works/qrencode/
|
$(package)_download_path=https://github.com/fukuchi/libqrencode/archive/refs/tags/
|
||||||
|
$(package)_download_file=v$($(package)_version).tar.gz
|
||||||
$(package)_file_name=$(package)-$($(package)_version).tar.gz
|
$(package)_file_name=$(package)-$($(package)_version).tar.gz
|
||||||
$(package)_sha256_hash=da448ed4f52aba6bcb0cd48cac0dd51b8692bccc4cd127431402fca6f8171e8e
|
$(package)_sha256_hash=5385bc1b8c2f20f3b91d258bf8ccc8cf62023935df2d2676b5b67049f31a049c
|
||||||
$(package)_patches=cmake_fixups.patch
|
$(package)_patches=cmake_fixups.patch
|
||||||
|
|
||||||
define $(package)_set_vars
|
define $(package)_set_vars
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
Bitcoin Core
|
||||||
|
=============
|
||||||
|
|
||||||
|
Below are notes on installing Bitcoin Core software on Linux systems.
|
||||||
|
|
||||||
|
General Runtime Requirements
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
Bitcoin Core requires glibc (GNU C Library) 2.31 or newer.
|
||||||
|
|
||||||
|
GUI Runtime Requirements
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
The GUI executable, `bitcoin-qt`, is based on the Qt 6 framework and uses the `xcb` QPA (Qt Platform Abstraction) platform plugin
|
||||||
|
to run on X11. Its runtime library [dependencies](https://doc.qt.io/archives/qt-6.7/linux-requirements.html) are as follows:
|
||||||
|
- `libfontconfig`
|
||||||
|
- `libfreetype`
|
||||||
|
- `libxcb`
|
||||||
|
- `libxcb-icccm`
|
||||||
|
- `libxcb-image`
|
||||||
|
- `libxcb-keysyms`
|
||||||
|
- `libxcb-randr`
|
||||||
|
- `libxcb-render`
|
||||||
|
- `libxcb-render-util`
|
||||||
|
- `libxcb-shape`
|
||||||
|
- `libxcb-shm`
|
||||||
|
- `libxcb-sync`
|
||||||
|
- `libxcb-xfixes`
|
||||||
|
- `libxcb-xkb`
|
||||||
|
- `libxkbcommon`
|
||||||
|
- `libxkbcommon-x11`
|
||||||
|
|
||||||
|
On Debian, Ubuntu, or their derivatives, you can run the following command to ensure all dependencies are installed:
|
||||||
|
```sh
|
||||||
|
sudo apt install \
|
||||||
|
libfontconfig1 \
|
||||||
|
libfreetype6 \
|
||||||
|
libxcb1 \
|
||||||
|
libxcb-icccm4 \
|
||||||
|
libxcb-image0 \
|
||||||
|
libxcb-keysyms1 \
|
||||||
|
libxcb-randr0 \
|
||||||
|
libxcb-render0 \
|
||||||
|
libxcb-render-util0 \
|
||||||
|
libxcb-shape0 \
|
||||||
|
libxcb-shm0 \
|
||||||
|
libxcb-sync1 \
|
||||||
|
libxcb-xfixes0 \
|
||||||
|
libxcb-xkb1 \
|
||||||
|
libxkbcommon0 \
|
||||||
|
libxkbcommon-x11-0
|
||||||
|
```
|
||||||
|
|
||||||
|
On Fedora, run:
|
||||||
|
```sh
|
||||||
|
sudo dnf install \
|
||||||
|
fontconfig \
|
||||||
|
freetype \
|
||||||
|
libxcb \
|
||||||
|
libxkbcommon \
|
||||||
|
libxkbcommon-x11 \
|
||||||
|
xcb-util-image \
|
||||||
|
xcb-util-keysyms \
|
||||||
|
xcb-util-renderutil \
|
||||||
|
xcb-util-wm
|
||||||
|
```
|
||||||
|
|
||||||
|
For other systems, please consult their documentation.
|
|
@ -24,7 +24,7 @@ static void VerifyScriptBench(benchmark::Bench& bench)
|
||||||
{
|
{
|
||||||
ECC_Context ecc_context{};
|
ECC_Context ecc_context{};
|
||||||
|
|
||||||
const uint32_t flags{SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH};
|
const script_verify_flags flags{SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH};
|
||||||
const int witnessversion = 0;
|
const int witnessversion = 0;
|
||||||
|
|
||||||
// Key pair.
|
// Key pair.
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include <chain.h>
|
#include <chain.h>
|
||||||
#include <tinyformat.h>
|
#include <tinyformat.h>
|
||||||
|
#include <util/check.h>
|
||||||
#include <util/time.h>
|
#include <util/time.h>
|
||||||
|
|
||||||
std::string CBlockFileInfo::ToString() const
|
std::string CBlockFileInfo::ToString() const
|
||||||
|
@ -158,18 +159,26 @@ int64_t GetBlockProofEquivalentTime(const CBlockIndex& to, const CBlockIndex& fr
|
||||||
/** Find the last common ancestor two blocks have.
|
/** Find the last common ancestor two blocks have.
|
||||||
* Both pa and pb must be non-nullptr. */
|
* Both pa and pb must be non-nullptr. */
|
||||||
const CBlockIndex* LastCommonAncestor(const CBlockIndex* pa, const CBlockIndex* pb) {
|
const CBlockIndex* LastCommonAncestor(const CBlockIndex* pa, const CBlockIndex* pb) {
|
||||||
|
// First rewind to the last common height (the forking point cannot be past one of the two).
|
||||||
if (pa->nHeight > pb->nHeight) {
|
if (pa->nHeight > pb->nHeight) {
|
||||||
pa = pa->GetAncestor(pb->nHeight);
|
pa = pa->GetAncestor(pb->nHeight);
|
||||||
} else if (pb->nHeight > pa->nHeight) {
|
} else if (pb->nHeight > pa->nHeight) {
|
||||||
pb = pb->GetAncestor(pa->nHeight);
|
pb = pb->GetAncestor(pa->nHeight);
|
||||||
}
|
}
|
||||||
|
while (pa != pb) {
|
||||||
while (pa != pb && pa && pb) {
|
// Jump back until pa and pb have a common "skip" ancestor.
|
||||||
|
while (pa->pskip != pb->pskip) {
|
||||||
|
// This logic relies on the property that equal-height blocks have equal-height skip
|
||||||
|
// pointers.
|
||||||
|
Assume(pa->nHeight == pb->nHeight);
|
||||||
|
Assume(pa->pskip->nHeight == pb->pskip->nHeight);
|
||||||
|
pa = pa->pskip;
|
||||||
|
pb = pb->pskip;
|
||||||
|
}
|
||||||
|
// At this point, pa and pb are different, but have equal pskip. The forking point lies in
|
||||||
|
// between pa/pb on the one end, and pa->pskip/pb->pskip on the other end.
|
||||||
pa = pa->pprev;
|
pa = pa->pprev;
|
||||||
pb = pb->pprev;
|
pb = pb->pprev;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Eventually all chain branches meet at the genesis block.
|
|
||||||
assert(pa == pb);
|
|
||||||
return pa;
|
return pa;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#ifndef BITCOIN_CONSENSUS_PARAMS_H
|
#ifndef BITCOIN_CONSENSUS_PARAMS_H
|
||||||
#define BITCOIN_CONSENSUS_PARAMS_H
|
#define BITCOIN_CONSENSUS_PARAMS_H
|
||||||
|
|
||||||
|
#include <script/verify_flags.h>
|
||||||
#include <uint256.h>
|
#include <uint256.h>
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
@ -89,7 +90,7 @@ struct Params {
|
||||||
* - buried in the chain, and
|
* - buried in the chain, and
|
||||||
* - fail if the default script verify flags are applied.
|
* - fail if the default script verify flags are applied.
|
||||||
*/
|
*/
|
||||||
std::map<uint256, uint32_t> script_flag_exceptions;
|
std::map<uint256, script_verify_flags> script_flag_exceptions;
|
||||||
/** Block height and hash at which BIP34 becomes active */
|
/** Block height and hash at which BIP34 becomes active */
|
||||||
int BIP34Height;
|
int BIP34Height;
|
||||||
uint256 BIP34Hash;
|
uint256 BIP34Hash;
|
||||||
|
|
|
@ -140,7 +140,7 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& in
|
||||||
return nSigOps;
|
return nSigOps;
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& inputs, uint32_t flags)
|
int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& inputs, script_verify_flags flags)
|
||||||
{
|
{
|
||||||
int64_t nSigOps = GetLegacySigOpCount(tx) * WITNESS_SCALE_FACTOR;
|
int64_t nSigOps = GetLegacySigOpCount(tx) * WITNESS_SCALE_FACTOR;
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#define BITCOIN_CONSENSUS_TX_VERIFY_H
|
#define BITCOIN_CONSENSUS_TX_VERIFY_H
|
||||||
|
|
||||||
#include <consensus/amount.h>
|
#include <consensus/amount.h>
|
||||||
|
#include <script/verify_flags.h>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -52,7 +53,7 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& ma
|
||||||
* @param[in] flags Script verification flags
|
* @param[in] flags Script verification flags
|
||||||
* @return Total signature operation cost of tx
|
* @return Total signature operation cost of tx
|
||||||
*/
|
*/
|
||||||
int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& inputs, uint32_t flags);
|
int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& inputs, script_verify_flags flags);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if transaction is final and can be included in a block with the
|
* Check if transaction is final and can be included in a block with the
|
||||||
|
|
|
@ -8,8 +8,10 @@
|
||||||
#include <consensus/params.h>
|
#include <consensus/params.h>
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <cassert>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
struct VBDeploymentInfo {
|
struct VBDeploymentInfo {
|
||||||
/** Deployment name */
|
/** Deployment name */
|
||||||
|
|
|
@ -98,7 +98,7 @@ static constexpr unsigned int MAX_DUST_OUTPUTS_PER_TX{1};
|
||||||
* Note that this does not affect consensus validity; see GetBlockScriptFlags()
|
* Note that this does not affect consensus validity; see GetBlockScriptFlags()
|
||||||
* for that.
|
* for that.
|
||||||
*/
|
*/
|
||||||
static constexpr unsigned int MANDATORY_SCRIPT_VERIFY_FLAGS{SCRIPT_VERIFY_P2SH |
|
static constexpr script_verify_flags MANDATORY_SCRIPT_VERIFY_FLAGS{SCRIPT_VERIFY_P2SH |
|
||||||
SCRIPT_VERIFY_DERSIG |
|
SCRIPT_VERIFY_DERSIG |
|
||||||
SCRIPT_VERIFY_NULLDUMMY |
|
SCRIPT_VERIFY_NULLDUMMY |
|
||||||
SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY |
|
SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY |
|
||||||
|
@ -112,7 +112,7 @@ static constexpr unsigned int MANDATORY_SCRIPT_VERIFY_FLAGS{SCRIPT_VERIFY_P2SH |
|
||||||
* the additional (non-mandatory) rules here, to improve forwards and
|
* the additional (non-mandatory) rules here, to improve forwards and
|
||||||
* backwards compatibility.
|
* backwards compatibility.
|
||||||
*/
|
*/
|
||||||
static constexpr unsigned int STANDARD_SCRIPT_VERIFY_FLAGS{MANDATORY_SCRIPT_VERIFY_FLAGS |
|
static constexpr script_verify_flags STANDARD_SCRIPT_VERIFY_FLAGS{MANDATORY_SCRIPT_VERIFY_FLAGS |
|
||||||
SCRIPT_VERIFY_STRICTENC |
|
SCRIPT_VERIFY_STRICTENC |
|
||||||
SCRIPT_VERIFY_MINIMALDATA |
|
SCRIPT_VERIFY_MINIMALDATA |
|
||||||
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS |
|
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS |
|
||||||
|
@ -128,7 +128,7 @@ static constexpr unsigned int STANDARD_SCRIPT_VERIFY_FLAGS{MANDATORY_SCRIPT_VERI
|
||||||
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE};
|
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE};
|
||||||
|
|
||||||
/** For convenience, standard but not mandatory verify flags. */
|
/** For convenience, standard but not mandatory verify flags. */
|
||||||
static constexpr unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS{STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS};
|
static constexpr script_verify_flags STANDARD_NOT_MANDATORY_VERIFY_FLAGS{STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS};
|
||||||
|
|
||||||
/** Used as the flags parameter to sequence and nLocktime checks in non-consensus code. */
|
/** Used as the flags parameter to sequence and nLocktime checks in non-consensus code. */
|
||||||
static constexpr unsigned int STANDARD_LOCKTIME_VERIFY_FLAGS{LOCKTIME_VERIFY_SEQUENCE};
|
static constexpr unsigned int STANDARD_LOCKTIME_VERIFY_FLAGS{LOCKTIME_VERIFY_SEQUENCE};
|
||||||
|
|
|
@ -1469,6 +1469,9 @@ RPCHelpMan getdeploymentinfo()
|
||||||
RPCResult::Type::OBJ, "", "", {
|
RPCResult::Type::OBJ, "", "", {
|
||||||
{RPCResult::Type::STR, "hash", "requested block hash (or tip)"},
|
{RPCResult::Type::STR, "hash", "requested block hash (or tip)"},
|
||||||
{RPCResult::Type::NUM, "height", "requested block height (or tip)"},
|
{RPCResult::Type::NUM, "height", "requested block height (or tip)"},
|
||||||
|
{RPCResult::Type::ARR, "script_flags", "script verify flags for the block", {
|
||||||
|
{RPCResult::Type::STR, "flag", "a script verify flag"},
|
||||||
|
}},
|
||||||
{RPCResult::Type::OBJ_DYN, "deployments", "", {
|
{RPCResult::Type::OBJ_DYN, "deployments", "", {
|
||||||
{RPCResult::Type::OBJ, "xxxx", "name of the deployment", RPCHelpForDeployment}
|
{RPCResult::Type::OBJ, "xxxx", "name of the deployment", RPCHelpForDeployment}
|
||||||
}},
|
}},
|
||||||
|
@ -1495,6 +1498,12 @@ RPCHelpMan getdeploymentinfo()
|
||||||
UniValue deploymentinfo(UniValue::VOBJ);
|
UniValue deploymentinfo(UniValue::VOBJ);
|
||||||
deploymentinfo.pushKV("hash", blockindex->GetBlockHash().ToString());
|
deploymentinfo.pushKV("hash", blockindex->GetBlockHash().ToString());
|
||||||
deploymentinfo.pushKV("height", blockindex->nHeight);
|
deploymentinfo.pushKV("height", blockindex->nHeight);
|
||||||
|
{
|
||||||
|
const auto flagnames = GetScriptFlagNames(GetBlockScriptFlags(*blockindex, chainman));
|
||||||
|
UniValue uv_flagnames(UniValue::VARR);
|
||||||
|
uv_flagnames.push_backV(flagnames.begin(), flagnames.end());
|
||||||
|
deploymentinfo.pushKV("script_flags", uv_flagnames);
|
||||||
|
}
|
||||||
deploymentinfo.pushKV("deployments", DeploymentInfo(blockindex, chainman));
|
deploymentinfo.pushKV("deployments", DeploymentInfo(blockindex, chainman));
|
||||||
return deploymentinfo;
|
return deploymentinfo;
|
||||||
},
|
},
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <crypto/sha256.h>
|
#include <crypto/sha256.h>
|
||||||
#include <pubkey.h>
|
#include <pubkey.h>
|
||||||
#include <script/script.h>
|
#include <script/script.h>
|
||||||
|
#include <tinyformat.h>
|
||||||
#include <uint256.h>
|
#include <uint256.h>
|
||||||
|
|
||||||
typedef std::vector<unsigned char> valtype;
|
typedef std::vector<unsigned char> valtype;
|
||||||
|
@ -197,7 +198,7 @@ bool static IsDefinedHashtypeSignature(const valtype &vchSig) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned int flags, ScriptError* serror) {
|
bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, script_verify_flags flags, ScriptError* serror) {
|
||||||
// Empty signature. Not strictly DER encoded, but allowed to provide a
|
// Empty signature. Not strictly DER encoded, but allowed to provide a
|
||||||
// compact way to provide an invalid signature for use with CHECK(MULTI)SIG
|
// compact way to provide an invalid signature for use with CHECK(MULTI)SIG
|
||||||
if (vchSig.size() == 0) {
|
if (vchSig.size() == 0) {
|
||||||
|
@ -214,7 +215,7 @@ bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned i
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool static CheckPubKeyEncoding(const valtype &vchPubKey, unsigned int flags, const SigVersion &sigversion, ScriptError* serror) {
|
bool static CheckPubKeyEncoding(const valtype &vchPubKey, script_verify_flags flags, const SigVersion &sigversion, ScriptError* serror) {
|
||||||
if ((flags & SCRIPT_VERIFY_STRICTENC) != 0 && !IsCompressedOrUncompressedPubKey(vchPubKey)) {
|
if ((flags & SCRIPT_VERIFY_STRICTENC) != 0 && !IsCompressedOrUncompressedPubKey(vchPubKey)) {
|
||||||
return set_error(serror, SCRIPT_ERR_PUBKEYTYPE);
|
return set_error(serror, SCRIPT_ERR_PUBKEYTYPE);
|
||||||
}
|
}
|
||||||
|
@ -317,7 +318,7 @@ public:
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool EvalChecksigPreTapscript(const valtype& vchSig, const valtype& vchPubKey, CScript::const_iterator pbegincodehash, CScript::const_iterator pend, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror, bool& fSuccess)
|
static bool EvalChecksigPreTapscript(const valtype& vchSig, const valtype& vchPubKey, CScript::const_iterator pbegincodehash, CScript::const_iterator pend, script_verify_flags flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror, bool& fSuccess)
|
||||||
{
|
{
|
||||||
assert(sigversion == SigVersion::BASE || sigversion == SigVersion::WITNESS_V0);
|
assert(sigversion == SigVersion::BASE || sigversion == SigVersion::WITNESS_V0);
|
||||||
|
|
||||||
|
@ -343,7 +344,7 @@ static bool EvalChecksigPreTapscript(const valtype& vchSig, const valtype& vchPu
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool EvalChecksigTapscript(const valtype& sig, const valtype& pubkey, ScriptExecutionData& execdata, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror, bool& success)
|
static bool EvalChecksigTapscript(const valtype& sig, const valtype& pubkey, ScriptExecutionData& execdata, script_verify_flags flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror, bool& success)
|
||||||
{
|
{
|
||||||
assert(sigversion == SigVersion::TAPSCRIPT);
|
assert(sigversion == SigVersion::TAPSCRIPT);
|
||||||
|
|
||||||
|
@ -388,7 +389,7 @@ static bool EvalChecksigTapscript(const valtype& sig, const valtype& pubkey, Scr
|
||||||
* A return value of false means the script fails entirely. When true is returned, the
|
* A return value of false means the script fails entirely. When true is returned, the
|
||||||
* success variable indicates whether the signature check itself succeeded.
|
* success variable indicates whether the signature check itself succeeded.
|
||||||
*/
|
*/
|
||||||
static bool EvalChecksig(const valtype& sig, const valtype& pubkey, CScript::const_iterator pbegincodehash, CScript::const_iterator pend, ScriptExecutionData& execdata, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror, bool& success)
|
static bool EvalChecksig(const valtype& sig, const valtype& pubkey, CScript::const_iterator pbegincodehash, CScript::const_iterator pend, ScriptExecutionData& execdata, script_verify_flags flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror, bool& success)
|
||||||
{
|
{
|
||||||
switch (sigversion) {
|
switch (sigversion) {
|
||||||
case SigVersion::BASE:
|
case SigVersion::BASE:
|
||||||
|
@ -403,7 +404,7 @@ static bool EvalChecksig(const valtype& sig, const valtype& pubkey, CScript::con
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* serror)
|
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, script_verify_flags flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* serror)
|
||||||
{
|
{
|
||||||
static const CScriptNum bnZero(0);
|
static const CScriptNum bnZero(0);
|
||||||
static const CScriptNum bnOne(1);
|
static const CScriptNum bnOne(1);
|
||||||
|
@ -1233,7 +1234,7 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
|
||||||
return set_success(serror);
|
return set_success(serror);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror)
|
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, script_verify_flags flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror)
|
||||||
{
|
{
|
||||||
ScriptExecutionData execdata;
|
ScriptExecutionData execdata;
|
||||||
return EvalScript(stack, script, flags, checker, sigversion, execdata, serror);
|
return EvalScript(stack, script, flags, checker, sigversion, execdata, serror);
|
||||||
|
@ -1824,7 +1825,7 @@ bool GenericTransactionSignatureChecker<T>::CheckSequence(const CScriptNum& nSeq
|
||||||
template class GenericTransactionSignatureChecker<CTransaction>;
|
template class GenericTransactionSignatureChecker<CTransaction>;
|
||||||
template class GenericTransactionSignatureChecker<CMutableTransaction>;
|
template class GenericTransactionSignatureChecker<CMutableTransaction>;
|
||||||
|
|
||||||
static bool ExecuteWitnessScript(const std::span<const valtype>& stack_span, const CScript& exec_script, unsigned int flags, SigVersion sigversion, const BaseSignatureChecker& checker, ScriptExecutionData& execdata, ScriptError* serror)
|
static bool ExecuteWitnessScript(const std::span<const valtype>& stack_span, const CScript& exec_script, script_verify_flags flags, SigVersion sigversion, const BaseSignatureChecker& checker, ScriptExecutionData& execdata, ScriptError* serror)
|
||||||
{
|
{
|
||||||
std::vector<valtype> stack{stack_span.begin(), stack_span.end()};
|
std::vector<valtype> stack{stack_span.begin(), stack_span.end()};
|
||||||
|
|
||||||
|
@ -1909,7 +1910,7 @@ static bool VerifyTaprootCommitment(const std::vector<unsigned char>& control, c
|
||||||
return q.CheckTapTweak(p, merkle_root, control[0] & 1);
|
return q.CheckTapTweak(p, merkle_root, control[0] & 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, const std::vector<unsigned char>& program, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror, bool is_p2sh)
|
static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, const std::vector<unsigned char>& program, script_verify_flags flags, const BaseSignatureChecker& checker, ScriptError* serror, bool is_p2sh)
|
||||||
{
|
{
|
||||||
CScript exec_script; //!< Actually executed script (last stack item in P2WSH; implied P2PKH script in P2WPKH; leaf script in P2TR)
|
CScript exec_script; //!< Actually executed script (last stack item in P2WSH; implied P2PKH script in P2WPKH; leaf script in P2TR)
|
||||||
std::span stack{witness.stack};
|
std::span stack{witness.stack};
|
||||||
|
@ -1994,7 +1995,7 @@ static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion,
|
||||||
// There is intentionally no return statement here, to be able to use "control reaches end of non-void function" warnings to detect gaps in the logic above.
|
// There is intentionally no return statement here, to be able to use "control reaches end of non-void function" warnings to detect gaps in the logic above.
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror)
|
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, script_verify_flags flags, const BaseSignatureChecker& checker, ScriptError* serror)
|
||||||
{
|
{
|
||||||
static const CScriptWitness emptyWitness;
|
static const CScriptWitness emptyWitness;
|
||||||
if (witness == nullptr) {
|
if (witness == nullptr) {
|
||||||
|
@ -2131,7 +2132,7 @@ size_t static WitnessSigOps(int witversion, const std::vector<unsigned char>& wi
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t CountWitnessSigOps(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, unsigned int flags)
|
size_t CountWitnessSigOps(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, script_verify_flags flags)
|
||||||
{
|
{
|
||||||
static const CScriptWitness witnessEmpty;
|
static const CScriptWitness witnessEmpty;
|
||||||
|
|
||||||
|
@ -2161,3 +2162,48 @@ size_t CountWitnessSigOps(const CScript& scriptSig, const CScript& scriptPubKey,
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define FLAG_NAME(flag) {std::string(#flag), SCRIPT_VERIFY_##flag}
|
||||||
|
const std::map<std::string, script_verify_flag_name> g_verify_flag_names{
|
||||||
|
FLAG_NAME(P2SH),
|
||||||
|
FLAG_NAME(STRICTENC),
|
||||||
|
FLAG_NAME(DERSIG),
|
||||||
|
FLAG_NAME(LOW_S),
|
||||||
|
FLAG_NAME(SIGPUSHONLY),
|
||||||
|
FLAG_NAME(MINIMALDATA),
|
||||||
|
FLAG_NAME(NULLDUMMY),
|
||||||
|
FLAG_NAME(DISCOURAGE_UPGRADABLE_NOPS),
|
||||||
|
FLAG_NAME(CLEANSTACK),
|
||||||
|
FLAG_NAME(MINIMALIF),
|
||||||
|
FLAG_NAME(NULLFAIL),
|
||||||
|
FLAG_NAME(CHECKLOCKTIMEVERIFY),
|
||||||
|
FLAG_NAME(CHECKSEQUENCEVERIFY),
|
||||||
|
FLAG_NAME(WITNESS),
|
||||||
|
FLAG_NAME(DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM),
|
||||||
|
FLAG_NAME(WITNESS_PUBKEYTYPE),
|
||||||
|
FLAG_NAME(CONST_SCRIPTCODE),
|
||||||
|
FLAG_NAME(TAPROOT),
|
||||||
|
FLAG_NAME(DISCOURAGE_UPGRADABLE_PUBKEYTYPE),
|
||||||
|
FLAG_NAME(DISCOURAGE_OP_SUCCESS),
|
||||||
|
FLAG_NAME(DISCOURAGE_UPGRADABLE_TAPROOT_VERSION),
|
||||||
|
};
|
||||||
|
#undef FLAG_NAME
|
||||||
|
|
||||||
|
std::vector<std::string> GetScriptFlagNames(script_verify_flags flags)
|
||||||
|
{
|
||||||
|
std::vector<std::string> res;
|
||||||
|
if (flags == SCRIPT_VERIFY_NONE) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
script_verify_flags leftover = flags;
|
||||||
|
for (const auto& [name, flag] : g_verify_flag_names) {
|
||||||
|
if ((flags & flag) != 0) {
|
||||||
|
res.push_back(name);
|
||||||
|
leftover &= ~flag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (leftover != 0) {
|
||||||
|
res.push_back(strprintf("0x%08x", leftover.as_int()));
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <hash.h>
|
#include <hash.h>
|
||||||
#include <primitives/transaction.h>
|
#include <primitives/transaction.h>
|
||||||
#include <script/script_error.h> // IWYU pragma: export
|
#include <script/script_error.h> // IWYU pragma: export
|
||||||
|
#include <script/verify_flags.h> // IWYU pragma: export
|
||||||
#include <span.h>
|
#include <span.h>
|
||||||
#include <uint256.h>
|
#include <uint256.h>
|
||||||
|
|
||||||
|
@ -42,35 +43,36 @@ enum
|
||||||
* All flags are intended to be soft forks: the set of acceptable scripts under
|
* All flags are intended to be soft forks: the set of acceptable scripts under
|
||||||
* flags (A | B) is a subset of the acceptable scripts under flag (A).
|
* flags (A | B) is a subset of the acceptable scripts under flag (A).
|
||||||
*/
|
*/
|
||||||
enum : uint32_t {
|
|
||||||
SCRIPT_VERIFY_NONE = 0,
|
|
||||||
|
|
||||||
|
static constexpr script_verify_flags SCRIPT_VERIFY_NONE{0};
|
||||||
|
|
||||||
|
enum class script_verify_flag_name : uint8_t {
|
||||||
// Evaluate P2SH subscripts (BIP16).
|
// Evaluate P2SH subscripts (BIP16).
|
||||||
SCRIPT_VERIFY_P2SH = (1U << 0),
|
SCRIPT_VERIFY_P2SH,
|
||||||
|
|
||||||
// Passing a non-strict-DER signature or one with undefined hashtype to a checksig operation causes script failure.
|
// Passing a non-strict-DER signature or one with undefined hashtype to a checksig operation causes script failure.
|
||||||
// Evaluating a pubkey that is not (0x04 + 64 bytes) or (0x02 or 0x03 + 32 bytes) by checksig causes script failure.
|
// Evaluating a pubkey that is not (0x04 + 64 bytes) or (0x02 or 0x03 + 32 bytes) by checksig causes script failure.
|
||||||
// (not used or intended as a consensus rule).
|
// (not used or intended as a consensus rule).
|
||||||
SCRIPT_VERIFY_STRICTENC = (1U << 1),
|
SCRIPT_VERIFY_STRICTENC,
|
||||||
|
|
||||||
// Passing a non-strict-DER signature to a checksig operation causes script failure (BIP62 rule 1)
|
// Passing a non-strict-DER signature to a checksig operation causes script failure (BIP62 rule 1)
|
||||||
SCRIPT_VERIFY_DERSIG = (1U << 2),
|
SCRIPT_VERIFY_DERSIG,
|
||||||
|
|
||||||
// Passing a non-strict-DER signature or one with S > order/2 to a checksig operation causes script failure
|
// Passing a non-strict-DER signature or one with S > order/2 to a checksig operation causes script failure
|
||||||
// (BIP62 rule 5).
|
// (BIP62 rule 5).
|
||||||
SCRIPT_VERIFY_LOW_S = (1U << 3),
|
SCRIPT_VERIFY_LOW_S,
|
||||||
|
|
||||||
// verify dummy stack item consumed by CHECKMULTISIG is of zero-length (BIP62 rule 7).
|
// verify dummy stack item consumed by CHECKMULTISIG is of zero-length (BIP62 rule 7).
|
||||||
SCRIPT_VERIFY_NULLDUMMY = (1U << 4),
|
SCRIPT_VERIFY_NULLDUMMY,
|
||||||
|
|
||||||
// Using a non-push operator in the scriptSig causes script failure (BIP62 rule 2).
|
// Using a non-push operator in the scriptSig causes script failure (BIP62 rule 2).
|
||||||
SCRIPT_VERIFY_SIGPUSHONLY = (1U << 5),
|
SCRIPT_VERIFY_SIGPUSHONLY,
|
||||||
|
|
||||||
// Require minimal encodings for all push operations (OP_0... OP_16, OP_1NEGATE where possible, direct
|
// Require minimal encodings for all push operations (OP_0... OP_16, OP_1NEGATE where possible, direct
|
||||||
// pushes up to 75 bytes, OP_PUSHDATA up to 255 bytes, OP_PUSHDATA2 for anything larger). Evaluating
|
// pushes up to 75 bytes, OP_PUSHDATA up to 255 bytes, OP_PUSHDATA2 for anything larger). Evaluating
|
||||||
// any other push causes the script to fail (BIP62 rule 3).
|
// any other push causes the script to fail (BIP62 rule 3).
|
||||||
// In addition, whenever a stack element is interpreted as a number, it must be of minimal length (BIP62 rule 4).
|
// In addition, whenever a stack element is interpreted as a number, it must be of minimal length (BIP62 rule 4).
|
||||||
SCRIPT_VERIFY_MINIMALDATA = (1U << 6),
|
SCRIPT_VERIFY_MINIMALDATA,
|
||||||
|
|
||||||
// Discourage use of NOPs reserved for upgrades (NOP1-10)
|
// Discourage use of NOPs reserved for upgrades (NOP1-10)
|
||||||
//
|
//
|
||||||
|
@ -82,7 +84,7 @@ enum : uint32_t {
|
||||||
// executed, e.g. within an unexecuted IF ENDIF block, are *not* rejected.
|
// executed, e.g. within an unexecuted IF ENDIF block, are *not* rejected.
|
||||||
// NOPs that have associated forks to give them new meaning (CLTV, CSV)
|
// NOPs that have associated forks to give them new meaning (CLTV, CSV)
|
||||||
// are not subject to this rule.
|
// are not subject to this rule.
|
||||||
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS = (1U << 7),
|
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS,
|
||||||
|
|
||||||
// Require that only a single stack element remains after evaluation. This changes the success criterion from
|
// Require that only a single stack element remains after evaluation. This changes the success criterion from
|
||||||
// "At least one stack element must remain, and when interpreted as a boolean, it must be true" to
|
// "At least one stack element must remain, and when interpreted as a boolean, it must be true" to
|
||||||
|
@ -91,64 +93,72 @@ enum : uint32_t {
|
||||||
// Note: CLEANSTACK should never be used without P2SH or WITNESS.
|
// Note: CLEANSTACK should never be used without P2SH or WITNESS.
|
||||||
// Note: WITNESS_V0 and TAPSCRIPT script execution have behavior similar to CLEANSTACK as part of their
|
// Note: WITNESS_V0 and TAPSCRIPT script execution have behavior similar to CLEANSTACK as part of their
|
||||||
// consensus rules. It is automatic there and does not need this flag.
|
// consensus rules. It is automatic there and does not need this flag.
|
||||||
SCRIPT_VERIFY_CLEANSTACK = (1U << 8),
|
SCRIPT_VERIFY_CLEANSTACK,
|
||||||
|
|
||||||
// Verify CHECKLOCKTIMEVERIFY
|
// Verify CHECKLOCKTIMEVERIFY
|
||||||
//
|
//
|
||||||
// See BIP65 for details.
|
// See BIP65 for details.
|
||||||
SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY = (1U << 9),
|
SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY,
|
||||||
|
|
||||||
// support CHECKSEQUENCEVERIFY opcode
|
// support CHECKSEQUENCEVERIFY opcode
|
||||||
//
|
//
|
||||||
// See BIP112 for details
|
// See BIP112 for details
|
||||||
SCRIPT_VERIFY_CHECKSEQUENCEVERIFY = (1U << 10),
|
SCRIPT_VERIFY_CHECKSEQUENCEVERIFY,
|
||||||
|
|
||||||
// Support segregated witness
|
// Support segregated witness
|
||||||
//
|
//
|
||||||
SCRIPT_VERIFY_WITNESS = (1U << 11),
|
SCRIPT_VERIFY_WITNESS,
|
||||||
|
|
||||||
// Making v1-v16 witness program non-standard
|
// Making v1-v16 witness program non-standard
|
||||||
//
|
//
|
||||||
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM = (1U << 12),
|
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM,
|
||||||
|
|
||||||
// Segwit script only: Require the argument of OP_IF/NOTIF to be exactly 0x01 or empty vector
|
// Segwit script only: Require the argument of OP_IF/NOTIF to be exactly 0x01 or empty vector
|
||||||
//
|
//
|
||||||
// Note: TAPSCRIPT script execution has behavior similar to MINIMALIF as part of its consensus
|
// Note: TAPSCRIPT script execution has behavior similar to MINIMALIF as part of its consensus
|
||||||
// rules. It is automatic there and does not depend on this flag.
|
// rules. It is automatic there and does not depend on this flag.
|
||||||
SCRIPT_VERIFY_MINIMALIF = (1U << 13),
|
SCRIPT_VERIFY_MINIMALIF,
|
||||||
|
|
||||||
// Signature(s) must be empty vector if a CHECK(MULTI)SIG operation failed
|
// Signature(s) must be empty vector if a CHECK(MULTI)SIG operation failed
|
||||||
//
|
//
|
||||||
SCRIPT_VERIFY_NULLFAIL = (1U << 14),
|
SCRIPT_VERIFY_NULLFAIL,
|
||||||
|
|
||||||
// Public keys in segregated witness scripts must be compressed
|
// Public keys in segregated witness scripts must be compressed
|
||||||
//
|
//
|
||||||
SCRIPT_VERIFY_WITNESS_PUBKEYTYPE = (1U << 15),
|
SCRIPT_VERIFY_WITNESS_PUBKEYTYPE,
|
||||||
|
|
||||||
// Making OP_CODESEPARATOR and FindAndDelete fail any non-segwit scripts
|
// Making OP_CODESEPARATOR and FindAndDelete fail any non-segwit scripts
|
||||||
//
|
//
|
||||||
SCRIPT_VERIFY_CONST_SCRIPTCODE = (1U << 16),
|
SCRIPT_VERIFY_CONST_SCRIPTCODE,
|
||||||
|
|
||||||
// Taproot/Tapscript validation (BIPs 341 & 342)
|
// Taproot/Tapscript validation (BIPs 341 & 342)
|
||||||
//
|
//
|
||||||
SCRIPT_VERIFY_TAPROOT = (1U << 17),
|
SCRIPT_VERIFY_TAPROOT,
|
||||||
|
|
||||||
// Making unknown Taproot leaf versions non-standard
|
// Making unknown Taproot leaf versions non-standard
|
||||||
//
|
//
|
||||||
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION = (1U << 18),
|
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION,
|
||||||
|
|
||||||
// Making unknown OP_SUCCESS non-standard
|
// Making unknown OP_SUCCESS non-standard
|
||||||
SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS = (1U << 19),
|
SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS,
|
||||||
|
|
||||||
// Making unknown public key versions (in BIP 342 scripts) non-standard
|
// Making unknown public key versions (in BIP 342 scripts) non-standard
|
||||||
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE = (1U << 20),
|
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE,
|
||||||
|
|
||||||
// Constants to point to the highest flag in use. Add new flags above this line.
|
// Constants to point to the highest flag in use. Add new flags above this line.
|
||||||
//
|
//
|
||||||
SCRIPT_VERIFY_END_MARKER
|
SCRIPT_VERIFY_END_MARKER
|
||||||
};
|
};
|
||||||
|
using enum script_verify_flag_name;
|
||||||
|
|
||||||
bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned int flags, ScriptError* serror);
|
static constexpr int MAX_SCRIPT_VERIFY_FLAGS_BITS = static_cast<int>(SCRIPT_VERIFY_END_MARKER);
|
||||||
|
|
||||||
|
// assert there is still a spare bit
|
||||||
|
static_assert(0 < MAX_SCRIPT_VERIFY_FLAGS_BITS && MAX_SCRIPT_VERIFY_FLAGS_BITS <= 63);
|
||||||
|
|
||||||
|
static constexpr script_verify_flags::value_type MAX_SCRIPT_VERIFY_FLAGS = ((script_verify_flags::value_type{1} << MAX_SCRIPT_VERIFY_FLAGS_BITS) - 1);
|
||||||
|
|
||||||
|
bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, script_verify_flags flags, ScriptError* serror);
|
||||||
|
|
||||||
struct PrecomputedTransactionData
|
struct PrecomputedTransactionData
|
||||||
{
|
{
|
||||||
|
@ -363,12 +373,16 @@ uint256 ComputeTapbranchHash(std::span<const unsigned char> a, std::span<const u
|
||||||
* Requires control block to have valid length (33 + k*32, with k in {0,1,..,128}). */
|
* Requires control block to have valid length (33 + k*32, with k in {0,1,..,128}). */
|
||||||
uint256 ComputeTaprootMerkleRoot(std::span<const unsigned char> control, const uint256& tapleaf_hash);
|
uint256 ComputeTaprootMerkleRoot(std::span<const unsigned char> control, const uint256& tapleaf_hash);
|
||||||
|
|
||||||
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* error = nullptr);
|
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, script_verify_flags flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* error = nullptr);
|
||||||
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* error = nullptr);
|
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, script_verify_flags flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* error = nullptr);
|
||||||
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror = nullptr);
|
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, script_verify_flags flags, const BaseSignatureChecker& checker, ScriptError* serror = nullptr);
|
||||||
|
|
||||||
size_t CountWitnessSigOps(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, unsigned int flags);
|
size_t CountWitnessSigOps(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, script_verify_flags flags);
|
||||||
|
|
||||||
int FindAndDelete(CScript& script, const CScript& b);
|
int FindAndDelete(CScript& script, const CScript& b);
|
||||||
|
|
||||||
|
extern const std::map<std::string, script_verify_flag_name> g_verify_flag_names;
|
||||||
|
|
||||||
|
std::vector<std::string> GetScriptFlagNames(script_verify_flags flags);
|
||||||
|
|
||||||
#endif // BITCOIN_SCRIPT_INTERPRETER_H
|
#endif // BITCOIN_SCRIPT_INTERPRETER_H
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||||
|
// Copyright (c) 2009-present The Bitcoin Core developers
|
||||||
|
// Distributed under the MIT software license, see the accompanying
|
||||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#ifndef BITCOIN_SCRIPT_VERIFY_FLAGS_H
|
||||||
|
#define BITCOIN_SCRIPT_VERIFY_FLAGS_H
|
||||||
|
|
||||||
|
#include <compare>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
enum class script_verify_flag_name : uint8_t;
|
||||||
|
|
||||||
|
class script_verify_flags
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using value_type = uint64_t;
|
||||||
|
|
||||||
|
consteval script_verify_flags() = default;
|
||||||
|
|
||||||
|
// also allow construction with hard-coded 0 (but not other integers)
|
||||||
|
consteval explicit(false) script_verify_flags(value_type f) : m_value{f} { if (f != 0) throw 0; }
|
||||||
|
|
||||||
|
// implicit construction from a hard-coded SCRIPT_VERIFY_* constant is also okay
|
||||||
|
constexpr explicit(false) script_verify_flags(script_verify_flag_name f) : m_value{value_type{1} << static_cast<uint8_t>(f)} { }
|
||||||
|
|
||||||
|
// rule of 5
|
||||||
|
constexpr script_verify_flags(const script_verify_flags&) = default;
|
||||||
|
constexpr script_verify_flags(script_verify_flags&&) = default;
|
||||||
|
constexpr script_verify_flags& operator=(const script_verify_flags&) = default;
|
||||||
|
constexpr script_verify_flags& operator=(script_verify_flags&&) = default;
|
||||||
|
constexpr ~script_verify_flags() = default;
|
||||||
|
|
||||||
|
// integer conversion needs to be very explicit
|
||||||
|
static constexpr script_verify_flags from_int(value_type f) { script_verify_flags r; r.m_value = f; return r; }
|
||||||
|
constexpr value_type as_int() const { return m_value; }
|
||||||
|
|
||||||
|
// bitwise operations
|
||||||
|
constexpr script_verify_flags operator~() const { return from_int(~m_value); }
|
||||||
|
friend constexpr script_verify_flags operator|(script_verify_flags a, script_verify_flags b) { return from_int(a.m_value | b.m_value); }
|
||||||
|
friend constexpr script_verify_flags operator&(script_verify_flags a, script_verify_flags b) { return from_int(a.m_value & b.m_value); }
|
||||||
|
|
||||||
|
// in-place bitwise operations
|
||||||
|
constexpr script_verify_flags& operator|=(script_verify_flags vf) { m_value |= vf.m_value; return *this; }
|
||||||
|
constexpr script_verify_flags& operator&=(script_verify_flags vf) { m_value &= vf.m_value; return *this; }
|
||||||
|
|
||||||
|
// tests
|
||||||
|
constexpr explicit operator bool() const { return m_value != 0; }
|
||||||
|
constexpr bool operator==(script_verify_flags other) const { return m_value == other.m_value; }
|
||||||
|
|
||||||
|
/** Compare two script_verify_flags. <, >, <=, and >= are auto-generated from this. */
|
||||||
|
friend constexpr std::strong_ordering operator<=>(const script_verify_flags& a, const script_verify_flags& b) noexcept
|
||||||
|
{
|
||||||
|
return a.m_value <=> b.m_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
value_type m_value{0}; // default value is SCRIPT_VERIFY_NONE
|
||||||
|
};
|
||||||
|
|
||||||
|
inline constexpr script_verify_flags operator~(script_verify_flag_name f)
|
||||||
|
{
|
||||||
|
return ~script_verify_flags{f};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline constexpr script_verify_flags operator|(script_verify_flag_name f1, script_verify_flag_name f2)
|
||||||
|
{
|
||||||
|
return script_verify_flags{f1} | f2;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // BITCOIN_SCRIPT_VERIFY_FLAGS_H
|
|
@ -26,7 +26,7 @@
|
||||||
|
|
||||||
static constexpr uint8_t SIGNET_HEADER[4] = {0xec, 0xc7, 0xda, 0xa2};
|
static constexpr uint8_t SIGNET_HEADER[4] = {0xec, 0xc7, 0xda, 0xa2};
|
||||||
|
|
||||||
static constexpr unsigned int BLOCK_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_NULLDUMMY;
|
static constexpr script_verify_flags BLOCK_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_NULLDUMMY;
|
||||||
|
|
||||||
static bool FetchAndClearCommitmentSection(const std::span<const uint8_t> header, CScript& witness_commitment, std::vector<uint8_t>& result)
|
static bool FetchAndClearCommitmentSection(const std::span<const uint8_t> header, CScript& witness_commitment, std::vector<uint8_t>& result)
|
||||||
{
|
{
|
||||||
|
|
|
@ -26,6 +26,7 @@ add_executable(test_bitcoin
|
||||||
bloom_tests.cpp
|
bloom_tests.cpp
|
||||||
bswap_tests.cpp
|
bswap_tests.cpp
|
||||||
caches_tests.cpp
|
caches_tests.cpp
|
||||||
|
chain_tests.cpp
|
||||||
chainstate_write_tests.cpp
|
chainstate_write_tests.cpp
|
||||||
checkqueue_tests.cpp
|
checkqueue_tests.cpp
|
||||||
cluster_linearize_tests.cpp
|
cluster_linearize_tests.cpp
|
||||||
|
|
|
@ -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()
|
|
@ -288,7 +288,7 @@ void TestCoinsView(FuzzedDataProvider& fuzzed_data_provider, CCoinsView& backend
|
||||||
// consensus/tx_verify.cpp:130: unsigned int GetP2SHSigOpCount(const CTransaction &, const CCoinsViewCache &): Assertion `!coin.IsSpent()' failed.
|
// consensus/tx_verify.cpp:130: unsigned int GetP2SHSigOpCount(const CTransaction &, const CCoinsViewCache &): Assertion `!coin.IsSpent()' failed.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto flags{fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
|
const auto flags = script_verify_flags::from_int(fuzzed_data_provider.ConsumeIntegral<script_verify_flags::value_type>());
|
||||||
if (!transaction.vin.empty() && (flags & SCRIPT_VERIFY_WITNESS) != 0 && (flags & SCRIPT_VERIFY_P2SH) == 0) {
|
if (!transaction.vin.empty() && (flags & SCRIPT_VERIFY_WITNESS) != 0 && (flags & SCRIPT_VERIFY_P2SH) == 0) {
|
||||||
// Avoid:
|
// Avoid:
|
||||||
// script/interpreter.cpp:1705: size_t CountWitnessSigOps(const CScript &, const CScript &, const CScriptWitness *, unsigned int): Assertion `(flags & SCRIPT_VERIFY_P2SH) != 0' failed.
|
// script/interpreter.cpp:1705: size_t CountWitnessSigOps(const CScript &, const CScript &, const CScriptWitness *, unsigned int): Assertion `(flags & SCRIPT_VERIFY_P2SH) != 0' failed.
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
FUZZ_TARGET(eval_script)
|
FUZZ_TARGET(eval_script)
|
||||||
{
|
{
|
||||||
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
|
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
|
||||||
const unsigned int flags = fuzzed_data_provider.ConsumeIntegral<unsigned int>();
|
const auto flags = script_verify_flags::from_int(fuzzed_data_provider.ConsumeIntegral<script_verify_flags::value_type>());
|
||||||
const std::vector<uint8_t> script_bytes = [&] {
|
const std::vector<uint8_t> script_bytes = [&] {
|
||||||
if (fuzzed_data_provider.remaining_bytes() != 0) {
|
if (fuzzed_data_provider.remaining_bytes() != 0) {
|
||||||
return fuzzed_data_provider.ConsumeRemainingBytes<uint8_t>();
|
return fuzzed_data_provider.ConsumeRemainingBytes<uint8_t>();
|
||||||
|
|
|
@ -118,8 +118,8 @@ FUZZ_TARGET(script, .init = initialize_script)
|
||||||
(void)FindAndDelete(script_mut, *other_script);
|
(void)FindAndDelete(script_mut, *other_script);
|
||||||
}
|
}
|
||||||
const std::vector<std::string> random_string_vector = ConsumeRandomLengthStringVector(fuzzed_data_provider);
|
const std::vector<std::string> random_string_vector = ConsumeRandomLengthStringVector(fuzzed_data_provider);
|
||||||
const uint32_t u32{fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
|
const auto flags_rand{fuzzed_data_provider.ConsumeIntegral<script_verify_flags::value_type>()};
|
||||||
const uint32_t flags{u32 | SCRIPT_VERIFY_P2SH};
|
const auto flags = script_verify_flags::from_int(flags_rand) | SCRIPT_VERIFY_P2SH;
|
||||||
{
|
{
|
||||||
CScriptWitness wit;
|
CScriptWitness wit;
|
||||||
for (const auto& s : random_string_vector) {
|
for (const auto& s : random_string_vector) {
|
||||||
|
|
|
@ -90,22 +90,22 @@ CScriptWitness ScriptWitnessFromJSON(const UniValue& univalue)
|
||||||
return scriptwitness;
|
return scriptwitness;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::map<std::string, unsigned int> FLAG_NAMES = {
|
const std::map<std::string, script_verify_flag_name> FLAG_NAMES = {
|
||||||
{std::string("P2SH"), (unsigned int)SCRIPT_VERIFY_P2SH},
|
{std::string("P2SH"), SCRIPT_VERIFY_P2SH},
|
||||||
{std::string("DERSIG"), (unsigned int)SCRIPT_VERIFY_DERSIG},
|
{std::string("DERSIG"), SCRIPT_VERIFY_DERSIG},
|
||||||
{std::string("NULLDUMMY"), (unsigned int)SCRIPT_VERIFY_NULLDUMMY},
|
{std::string("NULLDUMMY"), SCRIPT_VERIFY_NULLDUMMY},
|
||||||
{std::string("CHECKLOCKTIMEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY},
|
{std::string("CHECKLOCKTIMEVERIFY"), SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY},
|
||||||
{std::string("CHECKSEQUENCEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKSEQUENCEVERIFY},
|
{std::string("CHECKSEQUENCEVERIFY"), SCRIPT_VERIFY_CHECKSEQUENCEVERIFY},
|
||||||
{std::string("WITNESS"), (unsigned int)SCRIPT_VERIFY_WITNESS},
|
{std::string("WITNESS"), SCRIPT_VERIFY_WITNESS},
|
||||||
{std::string("TAPROOT"), (unsigned int)SCRIPT_VERIFY_TAPROOT},
|
{std::string("TAPROOT"), SCRIPT_VERIFY_TAPROOT},
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<unsigned int> AllFlags()
|
std::vector<script_verify_flags> AllFlags()
|
||||||
{
|
{
|
||||||
std::vector<unsigned int> ret;
|
std::vector<script_verify_flags> ret;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < 128; ++i) {
|
for (unsigned int i = 0; i < 128; ++i) {
|
||||||
unsigned int flag = 0;
|
script_verify_flags flag = 0;
|
||||||
if (i & 1) flag |= SCRIPT_VERIFY_P2SH;
|
if (i & 1) flag |= SCRIPT_VERIFY_P2SH;
|
||||||
if (i & 2) flag |= SCRIPT_VERIFY_DERSIG;
|
if (i & 2) flag |= SCRIPT_VERIFY_DERSIG;
|
||||||
if (i & 4) flag |= SCRIPT_VERIFY_NULLDUMMY;
|
if (i & 4) flag |= SCRIPT_VERIFY_NULLDUMMY;
|
||||||
|
@ -125,13 +125,13 @@ std::vector<unsigned int> AllFlags()
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<unsigned int> ALL_FLAGS = AllFlags();
|
const std::vector<script_verify_flags> ALL_FLAGS = AllFlags();
|
||||||
|
|
||||||
unsigned int ParseScriptFlags(const std::string& str)
|
script_verify_flags ParseScriptFlags(const std::string& str)
|
||||||
{
|
{
|
||||||
if (str.empty()) return 0;
|
if (str.empty()) return 0;
|
||||||
|
|
||||||
unsigned int flags = 0;
|
script_verify_flags flags = 0;
|
||||||
std::vector<std::string> words = SplitString(str, ',');
|
std::vector<std::string> words = SplitString(str, ',');
|
||||||
|
|
||||||
for (const std::string& word : words) {
|
for (const std::string& word : words) {
|
||||||
|
@ -153,7 +153,7 @@ void Test(const std::string& str)
|
||||||
if (prevouts.size() != tx.vin.size()) throw std::runtime_error("Incorrect number of prevouts");
|
if (prevouts.size() != tx.vin.size()) throw std::runtime_error("Incorrect number of prevouts");
|
||||||
size_t idx = test["index"].getInt<int64_t>();
|
size_t idx = test["index"].getInt<int64_t>();
|
||||||
if (idx >= tx.vin.size()) throw std::runtime_error("Invalid index");
|
if (idx >= tx.vin.size()) throw std::runtime_error("Invalid index");
|
||||||
unsigned int test_flags = ParseScriptFlags(test["flags"].get_str());
|
script_verify_flags test_flags = ParseScriptFlags(test["flags"].get_str());
|
||||||
bool final = test.exists("final") && test["final"].get_bool();
|
bool final = test.exists("final") && test["final"].get_bool();
|
||||||
|
|
||||||
if (test.exists("success")) {
|
if (test.exists("success")) {
|
||||||
|
|
|
@ -15,6 +15,15 @@
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
static DataStream& operator>>(DataStream& ds, script_verify_flags& f)
|
||||||
|
{
|
||||||
|
script_verify_flags::value_type n{0};
|
||||||
|
ds >> n;
|
||||||
|
f = script_verify_flags::from_int(n);
|
||||||
|
assert(n == f.as_int());
|
||||||
|
return ds;
|
||||||
|
}
|
||||||
|
|
||||||
FUZZ_TARGET(script_flags)
|
FUZZ_TARGET(script_flags)
|
||||||
{
|
{
|
||||||
if (buffer.size() > 100'000) return;
|
if (buffer.size() > 100'000) return;
|
||||||
|
@ -22,12 +31,14 @@ FUZZ_TARGET(script_flags)
|
||||||
try {
|
try {
|
||||||
const CTransaction tx(deserialize, TX_WITH_WITNESS, ds);
|
const CTransaction tx(deserialize, TX_WITH_WITNESS, ds);
|
||||||
|
|
||||||
unsigned int verify_flags;
|
script_verify_flags verify_flags;
|
||||||
ds >> verify_flags;
|
ds >> verify_flags;
|
||||||
|
|
||||||
|
assert(verify_flags == script_verify_flags::from_int(verify_flags.as_int()));
|
||||||
|
|
||||||
if (!IsValidFlagCombination(verify_flags)) return;
|
if (!IsValidFlagCombination(verify_flags)) return;
|
||||||
|
|
||||||
unsigned int fuzzed_flags;
|
script_verify_flags fuzzed_flags;
|
||||||
ds >> fuzzed_flags;
|
ds >> fuzzed_flags;
|
||||||
|
|
||||||
std::vector<CTxOut> spent_outputs;
|
std::vector<CTxOut> spent_outputs;
|
||||||
|
|
|
@ -51,7 +51,7 @@ public:
|
||||||
FUZZ_TARGET(signature_checker)
|
FUZZ_TARGET(signature_checker)
|
||||||
{
|
{
|
||||||
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
|
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
|
||||||
const unsigned int flags = fuzzed_data_provider.ConsumeIntegral<unsigned int>();
|
const auto flags = script_verify_flags::from_int(fuzzed_data_provider.ConsumeIntegral<script_verify_flags::value_type>());
|
||||||
const SigVersion sig_version = fuzzed_data_provider.PickValueInArray({SigVersion::BASE, SigVersion::WITNESS_V0});
|
const SigVersion sig_version = fuzzed_data_provider.PickValueInArray({SigVersion::BASE, SigVersion::WITNESS_V0});
|
||||||
const auto script_1{ConsumeScript(fuzzed_data_provider)};
|
const auto script_1{ConsumeScript(fuzzed_data_provider)};
|
||||||
const auto script_2{ConsumeScript(fuzzed_data_provider)};
|
const auto script_2{ConsumeScript(fuzzed_data_provider)};
|
||||||
|
|
|
@ -38,7 +38,7 @@ sign_multisig(const CScript& scriptPubKey, const std::vector<CKey>& keys, const
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(multisig_verify)
|
BOOST_AUTO_TEST_CASE(multisig_verify)
|
||||||
{
|
{
|
||||||
unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC;
|
script_verify_flags flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC;
|
||||||
|
|
||||||
ScriptError err;
|
ScriptError err;
|
||||||
CKey key[4];
|
CKey key[4];
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
|
|
||||||
#include <univalue.h>
|
#include <univalue.h>
|
||||||
|
|
||||||
unsigned int ParseScriptFlags(std::string strFlags);
|
script_verify_flags ParseScriptFlags(std::string strFlags);
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE(script_assets_tests)
|
BOOST_AUTO_TEST_SUITE(script_assets_tests)
|
||||||
|
|
||||||
|
@ -71,12 +71,12 @@ static CScriptWitness ScriptWitnessFromJSON(const UniValue& univalue)
|
||||||
return scriptwitness;
|
return scriptwitness;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<unsigned int> AllConsensusFlags()
|
static std::vector<script_verify_flags> AllConsensusFlags()
|
||||||
{
|
{
|
||||||
std::vector<unsigned int> ret;
|
std::vector<script_verify_flags> ret;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < 128; ++i) {
|
for (unsigned int i = 0; i < 128; ++i) {
|
||||||
unsigned int flag = 0;
|
script_verify_flags flag = 0;
|
||||||
if (i & 1) flag |= SCRIPT_VERIFY_P2SH;
|
if (i & 1) flag |= SCRIPT_VERIFY_P2SH;
|
||||||
if (i & 2) flag |= SCRIPT_VERIFY_DERSIG;
|
if (i & 2) flag |= SCRIPT_VERIFY_DERSIG;
|
||||||
if (i & 4) flag |= SCRIPT_VERIFY_NULLDUMMY;
|
if (i & 4) flag |= SCRIPT_VERIFY_NULLDUMMY;
|
||||||
|
@ -97,7 +97,7 @@ static std::vector<unsigned int> AllConsensusFlags()
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Precomputed list of all valid combinations of consensus-relevant script validation flags. */
|
/** Precomputed list of all valid combinations of consensus-relevant script validation flags. */
|
||||||
static const std::vector<unsigned int> ALL_CONSENSUS_FLAGS = AllConsensusFlags();
|
static const std::vector<script_verify_flags> ALL_CONSENSUS_FLAGS = AllConsensusFlags();
|
||||||
|
|
||||||
static void AssetTest(const UniValue& test, SignatureCache& signature_cache)
|
static void AssetTest(const UniValue& test, SignatureCache& signature_cache)
|
||||||
{
|
{
|
||||||
|
@ -107,7 +107,7 @@ static void AssetTest(const UniValue& test, SignatureCache& signature_cache)
|
||||||
const std::vector<CTxOut> prevouts = TxOutsFromJSON(test["prevouts"]);
|
const std::vector<CTxOut> prevouts = TxOutsFromJSON(test["prevouts"]);
|
||||||
BOOST_CHECK(prevouts.size() == mtx.vin.size());
|
BOOST_CHECK(prevouts.size() == mtx.vin.size());
|
||||||
size_t idx = test["index"].getInt<int64_t>();
|
size_t idx = test["index"].getInt<int64_t>();
|
||||||
uint32_t test_flags{ParseScriptFlags(test["flags"].get_str())};
|
script_verify_flags test_flags{ParseScriptFlags(test["flags"].get_str())};
|
||||||
bool fin = test.exists("final") && test["final"].get_bool();
|
bool fin = test.exists("final") && test["final"].get_bool();
|
||||||
|
|
||||||
if (test.exists("success")) {
|
if (test.exists("success")) {
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <core_io.h>
|
#include <core_io.h>
|
||||||
#include <key.h>
|
#include <key.h>
|
||||||
#include <rpc/util.h>
|
#include <rpc/util.h>
|
||||||
|
#include <script/interpreter.h>
|
||||||
#include <script/script.h>
|
#include <script/script.h>
|
||||||
#include <script/script_error.h>
|
#include <script/script_error.h>
|
||||||
#include <script/sigcache.h>
|
#include <script/sigcache.h>
|
||||||
|
@ -22,6 +23,7 @@
|
||||||
#include <test/util/transaction_utils.h>
|
#include <test/util/transaction_utils.h>
|
||||||
#include <util/fs.h>
|
#include <util/fs.h>
|
||||||
#include <util/strencodings.h>
|
#include <util/strencodings.h>
|
||||||
|
#include <util/string.h>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
@ -38,10 +40,9 @@
|
||||||
|
|
||||||
using namespace util::hex_literals;
|
using namespace util::hex_literals;
|
||||||
|
|
||||||
static const unsigned int gFlags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC;
|
static const script_verify_flags gFlags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC;
|
||||||
|
|
||||||
unsigned int ParseScriptFlags(std::string strFlags);
|
script_verify_flags ParseScriptFlags(std::string strFlags);
|
||||||
std::string FormatScriptFlags(unsigned int flags);
|
|
||||||
|
|
||||||
struct ScriptErrorDesc
|
struct ScriptErrorDesc
|
||||||
{
|
{
|
||||||
|
@ -95,6 +96,11 @@ static ScriptErrorDesc script_errors[]={
|
||||||
{SCRIPT_ERR_SIG_FINDANDDELETE, "SIG_FINDANDDELETE"},
|
{SCRIPT_ERR_SIG_FINDANDDELETE, "SIG_FINDANDDELETE"},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static std::string FormatScriptFlags(script_verify_flags flags)
|
||||||
|
{
|
||||||
|
return util::Join(GetScriptFlagNames(flags), ",");
|
||||||
|
}
|
||||||
|
|
||||||
static std::string FormatScriptError(ScriptError_t err)
|
static std::string FormatScriptError(ScriptError_t err)
|
||||||
{
|
{
|
||||||
for (const auto& se : script_errors)
|
for (const auto& se : script_errors)
|
||||||
|
@ -114,7 +120,7 @@ static ScriptError_t ParseScriptError(const std::string& name)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ScriptTest : BasicTestingSetup {
|
struct ScriptTest : BasicTestingSetup {
|
||||||
void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, const CScriptWitness& scriptWitness, uint32_t flags, const std::string& message, int scriptError, CAmount nValue = 0)
|
void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, const CScriptWitness& scriptWitness, script_verify_flags flags, const std::string& message, int scriptError, CAmount nValue = 0)
|
||||||
{
|
{
|
||||||
bool expect = (scriptError == SCRIPT_ERR_OK);
|
bool expect = (scriptError == SCRIPT_ERR_OK);
|
||||||
if (flags & SCRIPT_VERIFY_CLEANSTACK) {
|
if (flags & SCRIPT_VERIFY_CLEANSTACK) {
|
||||||
|
@ -128,13 +134,13 @@ void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, const CScript
|
||||||
BOOST_CHECK_MESSAGE(err == scriptError, FormatScriptError(err) + " where " + FormatScriptError((ScriptError_t)scriptError) + " expected: " + message);
|
BOOST_CHECK_MESSAGE(err == scriptError, FormatScriptError(err) + " where " + FormatScriptError((ScriptError_t)scriptError) + " expected: " + message);
|
||||||
|
|
||||||
// Verify that removing flags from a passing test or adding flags to a failing test does not change the result.
|
// Verify that removing flags from a passing test or adding flags to a failing test does not change the result.
|
||||||
for (int i = 0; i < 16; ++i) {
|
for (int i = 0; i < 256; ++i) {
|
||||||
uint32_t extra_flags(m_rng.randbits(16));
|
script_verify_flags extra_flags = script_verify_flags::from_int(m_rng.randbits(MAX_SCRIPT_VERIFY_FLAGS_BITS));
|
||||||
uint32_t combined_flags{expect ? (flags & ~extra_flags) : (flags | extra_flags)};
|
script_verify_flags combined_flags{expect ? (flags & ~extra_flags) : (flags | extra_flags)};
|
||||||
// Weed out some invalid flag combinations.
|
// Weed out some invalid flag combinations.
|
||||||
if (combined_flags & SCRIPT_VERIFY_CLEANSTACK && ~combined_flags & (SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS)) continue;
|
if (combined_flags & SCRIPT_VERIFY_CLEANSTACK && ~combined_flags & (SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS)) continue;
|
||||||
if (combined_flags & SCRIPT_VERIFY_WITNESS && ~combined_flags & SCRIPT_VERIFY_P2SH) continue;
|
if (combined_flags & SCRIPT_VERIFY_WITNESS && ~combined_flags & SCRIPT_VERIFY_P2SH) continue;
|
||||||
BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, &scriptWitness, combined_flags, MutableTransactionSignatureChecker(&tx, 0, txCredit.vout[0].nValue, MissingDataBehavior::ASSERT_FAIL), &err) == expect, message + strprintf(" (with flags %x)", combined_flags));
|
BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, &scriptWitness, combined_flags, MutableTransactionSignatureChecker(&tx, 0, txCredit.vout[0].nValue, MissingDataBehavior::ASSERT_FAIL), &err) == expect, message + strprintf(" (with flags %x)", combined_flags.as_int()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}; // struct ScriptTest
|
}; // struct ScriptTest
|
||||||
|
@ -226,7 +232,7 @@ private:
|
||||||
bool havePush{false};
|
bool havePush{false};
|
||||||
std::vector<unsigned char> push;
|
std::vector<unsigned char> push;
|
||||||
std::string comment;
|
std::string comment;
|
||||||
uint32_t flags;
|
script_verify_flags flags;
|
||||||
int scriptError{SCRIPT_ERR_OK};
|
int scriptError{SCRIPT_ERR_OK};
|
||||||
CAmount nValue;
|
CAmount nValue;
|
||||||
|
|
||||||
|
@ -246,7 +252,7 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TestBuilder(const CScript& script_, const std::string& comment_, uint32_t flags_, bool P2SH = false, WitnessMode wm = WitnessMode::NONE, int witnessversion = 0, CAmount nValue_ = 0) : script(script_), comment(comment_), flags(flags_), nValue(nValue_)
|
TestBuilder(const CScript& script_, const std::string& comment_, script_verify_flags flags_, bool P2SH = false, WitnessMode wm = WitnessMode::NONE, int witnessversion = 0, CAmount nValue_ = 0) : script(script_), comment(comment_), flags(flags_), nValue(nValue_)
|
||||||
{
|
{
|
||||||
CScript scriptPubKey = script;
|
CScript scriptPubKey = script;
|
||||||
if (wm == WitnessMode::PKH) {
|
if (wm == WitnessMode::PKH) {
|
||||||
|
@ -963,7 +969,7 @@ BOOST_AUTO_TEST_CASE(script_json_test)
|
||||||
} else {
|
} else {
|
||||||
scriptPubKey = ParseScript(scriptPubKeyString);
|
scriptPubKey = ParseScript(scriptPubKeyString);
|
||||||
}
|
}
|
||||||
unsigned int scriptflags = ParseScriptFlags(test[pos++].get_str());
|
script_verify_flags scriptflags = ParseScriptFlags(test[pos++].get_str());
|
||||||
int scriptError = ParseScriptError(test[pos++].get_str());
|
int scriptError = ParseScriptError(test[pos++].get_str());
|
||||||
|
|
||||||
DoTest(scriptPubKey, scriptSig, witness, scriptflags, strTest, scriptError, nValue);
|
DoTest(scriptPubKey, scriptSig, witness, scriptflags, strTest, scriptError, nValue);
|
||||||
|
@ -1706,4 +1712,15 @@ BOOST_AUTO_TEST_CASE(compute_tapleaf)
|
||||||
BOOST_CHECK_EQUAL(ComputeTapleafHash(0xc2, std::span(script)), tlc2);
|
BOOST_CHECK_EQUAL(ComputeTapleafHash(0xc2, std::span(script)), tlc2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(formatscriptflags)
|
||||||
|
{
|
||||||
|
// quick check that FormatScriptFlags reports any unknown/unexpected bits
|
||||||
|
BOOST_CHECK_EQUAL(FormatScriptFlags(SCRIPT_VERIFY_P2SH), "P2SH");
|
||||||
|
BOOST_CHECK_EQUAL(FormatScriptFlags(SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_TAPROOT), "P2SH,TAPROOT");
|
||||||
|
BOOST_CHECK_EQUAL(FormatScriptFlags(SCRIPT_VERIFY_P2SH | script_verify_flags::from_int(1u<<31)), "P2SH,0x80000000");
|
||||||
|
BOOST_CHECK_EQUAL(FormatScriptFlags(SCRIPT_VERIFY_TAPROOT | script_verify_flags::from_int(1u<<27)), "TAPROOT,0x08000000");
|
||||||
|
BOOST_CHECK_EQUAL(FormatScriptFlags(SCRIPT_VERIFY_TAPROOT | script_verify_flags::from_int((1u<<28) | (1ull<<58))), "TAPROOT,0x400000010000000");
|
||||||
|
BOOST_CHECK_EQUAL(FormatScriptFlags(script_verify_flags::from_int(1u<<26)), "0x04000000");
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
|
|
@ -69,7 +69,7 @@ BOOST_AUTO_TEST_CASE(GetSigOpCount)
|
||||||
* Verifies script execution of the zeroth scriptPubKey of tx output and
|
* Verifies script execution of the zeroth scriptPubKey of tx output and
|
||||||
* zeroth scriptSig and witness of tx input.
|
* zeroth scriptSig and witness of tx input.
|
||||||
*/
|
*/
|
||||||
static ScriptError VerifyWithFlag(const CTransaction& output, const CMutableTransaction& input, uint32_t flags)
|
static ScriptError VerifyWithFlag(const CTransaction& output, const CMutableTransaction& input, script_verify_flags flags)
|
||||||
{
|
{
|
||||||
ScriptError error;
|
ScriptError error;
|
||||||
CTransaction inputi(input);
|
CTransaction inputi(input);
|
||||||
|
@ -122,7 +122,7 @@ BOOST_AUTO_TEST_CASE(GetTxSigOpCost)
|
||||||
CKey key = GenerateRandomKey();
|
CKey key = GenerateRandomKey();
|
||||||
CPubKey pubkey = key.GetPubKey();
|
CPubKey pubkey = key.GetPubKey();
|
||||||
// Default flags
|
// Default flags
|
||||||
const uint32_t flags{SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH};
|
const script_verify_flags flags{SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH};
|
||||||
|
|
||||||
// Multisig script (legacy counting)
|
// Multisig script (legacy counting)
|
||||||
{
|
{
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include <policy/policy.h>
|
#include <policy/policy.h>
|
||||||
#include <policy/settings.h>
|
#include <policy/settings.h>
|
||||||
#include <primitives/transaction_identifier.h>
|
#include <primitives/transaction_identifier.h>
|
||||||
|
#include <script/interpreter.h>
|
||||||
#include <script/script.h>
|
#include <script/script.h>
|
||||||
#include <script/script_error.h>
|
#include <script/script_error.h>
|
||||||
#include <script/sigcache.h>
|
#include <script/sigcache.h>
|
||||||
|
@ -49,41 +50,21 @@ typedef std::vector<unsigned char> valtype;
|
||||||
static CFeeRate g_dust{DUST_RELAY_TX_FEE};
|
static CFeeRate g_dust{DUST_RELAY_TX_FEE};
|
||||||
static bool g_bare_multi{DEFAULT_PERMIT_BAREMULTISIG};
|
static bool g_bare_multi{DEFAULT_PERMIT_BAREMULTISIG};
|
||||||
|
|
||||||
static std::map<std::string, unsigned int> mapFlagNames = {
|
static const std::map<std::string, script_verify_flag_name>& mapFlagNames = g_verify_flag_names;
|
||||||
{std::string("P2SH"), (unsigned int)SCRIPT_VERIFY_P2SH},
|
|
||||||
{std::string("STRICTENC"), (unsigned int)SCRIPT_VERIFY_STRICTENC},
|
|
||||||
{std::string("DERSIG"), (unsigned int)SCRIPT_VERIFY_DERSIG},
|
|
||||||
{std::string("LOW_S"), (unsigned int)SCRIPT_VERIFY_LOW_S},
|
|
||||||
{std::string("SIGPUSHONLY"), (unsigned int)SCRIPT_VERIFY_SIGPUSHONLY},
|
|
||||||
{std::string("MINIMALDATA"), (unsigned int)SCRIPT_VERIFY_MINIMALDATA},
|
|
||||||
{std::string("NULLDUMMY"), (unsigned int)SCRIPT_VERIFY_NULLDUMMY},
|
|
||||||
{std::string("DISCOURAGE_UPGRADABLE_NOPS"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS},
|
|
||||||
{std::string("CLEANSTACK"), (unsigned int)SCRIPT_VERIFY_CLEANSTACK},
|
|
||||||
{std::string("MINIMALIF"), (unsigned int)SCRIPT_VERIFY_MINIMALIF},
|
|
||||||
{std::string("NULLFAIL"), (unsigned int)SCRIPT_VERIFY_NULLFAIL},
|
|
||||||
{std::string("CHECKLOCKTIMEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY},
|
|
||||||
{std::string("CHECKSEQUENCEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKSEQUENCEVERIFY},
|
|
||||||
{std::string("WITNESS"), (unsigned int)SCRIPT_VERIFY_WITNESS},
|
|
||||||
{std::string("DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM},
|
|
||||||
{std::string("WITNESS_PUBKEYTYPE"), (unsigned int)SCRIPT_VERIFY_WITNESS_PUBKEYTYPE},
|
|
||||||
{std::string("CONST_SCRIPTCODE"), (unsigned int)SCRIPT_VERIFY_CONST_SCRIPTCODE},
|
|
||||||
{std::string("TAPROOT"), (unsigned int)SCRIPT_VERIFY_TAPROOT},
|
|
||||||
{std::string("DISCOURAGE_UPGRADABLE_PUBKEYTYPE"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE},
|
|
||||||
{std::string("DISCOURAGE_OP_SUCCESS"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS},
|
|
||||||
{std::string("DISCOURAGE_UPGRADABLE_TAPROOT_VERSION"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION},
|
|
||||||
};
|
|
||||||
|
|
||||||
unsigned int ParseScriptFlags(std::string strFlags)
|
script_verify_flags ParseScriptFlags(std::string strFlags)
|
||||||
{
|
{
|
||||||
unsigned int flags = SCRIPT_VERIFY_NONE;
|
script_verify_flags flags = SCRIPT_VERIFY_NONE;
|
||||||
if (strFlags.empty() || strFlags == "NONE") return flags;
|
if (strFlags.empty() || strFlags == "NONE") return flags;
|
||||||
|
|
||||||
std::vector<std::string> words = SplitString(strFlags, ',');
|
std::vector<std::string> words = SplitString(strFlags, ',');
|
||||||
for (const std::string& word : words)
|
for (const std::string& word : words)
|
||||||
{
|
{
|
||||||
if (!mapFlagNames.count(word))
|
if (!mapFlagNames.count(word)) {
|
||||||
BOOST_ERROR("Bad test: unknown verification flag '" << word << "'");
|
BOOST_ERROR("Bad test: unknown verification flag '" << word << "'");
|
||||||
flags |= mapFlagNames[word];
|
continue;
|
||||||
|
}
|
||||||
|
flags |= mapFlagNames.at(word);
|
||||||
}
|
}
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
@ -91,34 +72,18 @@ unsigned int ParseScriptFlags(std::string strFlags)
|
||||||
// Check that all flags in STANDARD_SCRIPT_VERIFY_FLAGS are present in mapFlagNames.
|
// Check that all flags in STANDARD_SCRIPT_VERIFY_FLAGS are present in mapFlagNames.
|
||||||
bool CheckMapFlagNames()
|
bool CheckMapFlagNames()
|
||||||
{
|
{
|
||||||
unsigned int standard_flags_missing{STANDARD_SCRIPT_VERIFY_FLAGS};
|
script_verify_flags standard_flags_missing{STANDARD_SCRIPT_VERIFY_FLAGS};
|
||||||
for (const auto& pair : mapFlagNames) {
|
for (const auto& pair : mapFlagNames) {
|
||||||
standard_flags_missing &= ~(pair.second);
|
standard_flags_missing &= ~(pair.second);
|
||||||
}
|
}
|
||||||
return standard_flags_missing == 0;
|
return standard_flags_missing == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string FormatScriptFlags(unsigned int flags)
|
|
||||||
{
|
|
||||||
if (flags == SCRIPT_VERIFY_NONE) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
std::string ret;
|
|
||||||
std::map<std::string, unsigned int>::const_iterator it = mapFlagNames.begin();
|
|
||||||
while (it != mapFlagNames.end()) {
|
|
||||||
if (flags & it->second) {
|
|
||||||
ret += it->first + ",";
|
|
||||||
}
|
|
||||||
it++;
|
|
||||||
}
|
|
||||||
return ret.substr(0, ret.size() - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check that the input scripts of a transaction are valid/invalid as expected.
|
* Check that the input scripts of a transaction are valid/invalid as expected.
|
||||||
*/
|
*/
|
||||||
bool CheckTxScripts(const CTransaction& tx, const std::map<COutPoint, CScript>& map_prevout_scriptPubKeys,
|
bool CheckTxScripts(const CTransaction& tx, const std::map<COutPoint, CScript>& map_prevout_scriptPubKeys,
|
||||||
const std::map<COutPoint, int64_t>& map_prevout_values, unsigned int flags,
|
const std::map<COutPoint, int64_t>& map_prevout_values, script_verify_flags flags,
|
||||||
const PrecomputedTransactionData& txdata, const std::string& strTest, bool expect_valid)
|
const PrecomputedTransactionData& txdata, const std::string& strTest, bool expect_valid)
|
||||||
{
|
{
|
||||||
bool tx_valid = true;
|
bool tx_valid = true;
|
||||||
|
@ -152,18 +117,18 @@ bool CheckTxScripts(const CTransaction& tx, const std::map<COutPoint, CScript>&
|
||||||
* CLEANSTACK must be used WITNESS and P2SH
|
* CLEANSTACK must be used WITNESS and P2SH
|
||||||
*/
|
*/
|
||||||
|
|
||||||
unsigned int TrimFlags(unsigned int flags)
|
script_verify_flags TrimFlags(script_verify_flags flags)
|
||||||
{
|
{
|
||||||
// WITNESS requires P2SH
|
// WITNESS requires P2SH
|
||||||
if (!(flags & SCRIPT_VERIFY_P2SH)) flags &= ~(unsigned int)SCRIPT_VERIFY_WITNESS;
|
if (!(flags & SCRIPT_VERIFY_P2SH)) flags &= ~SCRIPT_VERIFY_WITNESS;
|
||||||
|
|
||||||
// CLEANSTACK requires WITNESS (and transitively CLEANSTACK requires P2SH)
|
// CLEANSTACK requires WITNESS (and transitively CLEANSTACK requires P2SH)
|
||||||
if (!(flags & SCRIPT_VERIFY_WITNESS)) flags &= ~(unsigned int)SCRIPT_VERIFY_CLEANSTACK;
|
if (!(flags & SCRIPT_VERIFY_WITNESS)) flags &= ~SCRIPT_VERIFY_CLEANSTACK;
|
||||||
Assert(IsValidFlagCombination(flags));
|
Assert(IsValidFlagCombination(flags));
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int FillFlags(unsigned int flags)
|
script_verify_flags FillFlags(script_verify_flags flags)
|
||||||
{
|
{
|
||||||
// CLEANSTACK implies WITNESS
|
// CLEANSTACK implies WITNESS
|
||||||
if (flags & SCRIPT_VERIFY_CLEANSTACK) flags |= SCRIPT_VERIFY_WITNESS;
|
if (flags & SCRIPT_VERIFY_CLEANSTACK) flags |= SCRIPT_VERIFY_WITNESS;
|
||||||
|
@ -178,11 +143,11 @@ unsigned int FillFlags(unsigned int flags)
|
||||||
// that are valid and without duplicates. For example: if flags=1111 and the 4 possible flags are
|
// that are valid and without duplicates. For example: if flags=1111 and the 4 possible flags are
|
||||||
// 0001, 0010, 0100, and 1000, this should return the set {0111, 1011, 1101, 1110}.
|
// 0001, 0010, 0100, and 1000, this should return the set {0111, 1011, 1101, 1110}.
|
||||||
// Assumes that mapFlagNames contains all script verify flags.
|
// Assumes that mapFlagNames contains all script verify flags.
|
||||||
std::set<unsigned int> ExcludeIndividualFlags(unsigned int flags)
|
std::set<script_verify_flags> ExcludeIndividualFlags(script_verify_flags flags)
|
||||||
{
|
{
|
||||||
std::set<unsigned int> flags_combos;
|
std::set<script_verify_flags> flags_combos;
|
||||||
for (const auto& pair : mapFlagNames) {
|
for (const auto& pair : mapFlagNames) {
|
||||||
const unsigned int flags_excluding_one = TrimFlags(flags & ~(pair.second));
|
script_verify_flags flags_excluding_one = TrimFlags(flags & ~(pair.second));
|
||||||
if (flags != flags_excluding_one) {
|
if (flags != flags_excluding_one) {
|
||||||
flags_combos.insert(flags_excluding_one);
|
flags_combos.insert(flags_excluding_one);
|
||||||
}
|
}
|
||||||
|
@ -247,7 +212,7 @@ BOOST_AUTO_TEST_CASE(tx_valid)
|
||||||
BOOST_CHECK(state.IsValid());
|
BOOST_CHECK(state.IsValid());
|
||||||
|
|
||||||
PrecomputedTransactionData txdata(tx);
|
PrecomputedTransactionData txdata(tx);
|
||||||
unsigned int verify_flags = ParseScriptFlags(test[2].get_str());
|
script_verify_flags verify_flags = ParseScriptFlags(test[2].get_str());
|
||||||
|
|
||||||
// Check that the test gives a valid combination of flags (otherwise VerifyScript will throw). Don't edit the flags.
|
// Check that the test gives a valid combination of flags (otherwise VerifyScript will throw). Don't edit the flags.
|
||||||
if (~verify_flags != FillFlags(~verify_flags)) {
|
if (~verify_flags != FillFlags(~verify_flags)) {
|
||||||
|
@ -260,14 +225,14 @@ BOOST_AUTO_TEST_CASE(tx_valid)
|
||||||
// Backwards compatibility of script verification flags: Removing any flag(s) should not invalidate a valid transaction
|
// Backwards compatibility of script verification flags: Removing any flag(s) should not invalidate a valid transaction
|
||||||
for (const auto& [name, flag] : mapFlagNames) {
|
for (const auto& [name, flag] : mapFlagNames) {
|
||||||
// Removing individual flags
|
// Removing individual flags
|
||||||
unsigned int flags = TrimFlags(~(verify_flags | flag));
|
script_verify_flags flags = TrimFlags(~(verify_flags | flag));
|
||||||
if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, flags, txdata, strTest, /*expect_valid=*/true)) {
|
if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, flags, txdata, strTest, /*expect_valid=*/true)) {
|
||||||
BOOST_ERROR("Tx unexpectedly failed with flag " << name << " unset: " << strTest);
|
BOOST_ERROR("Tx unexpectedly failed with flag " << name << " unset: " << strTest);
|
||||||
}
|
}
|
||||||
// Removing random combinations of flags
|
// Removing random combinations of flags
|
||||||
flags = TrimFlags(~(verify_flags | (unsigned int)m_rng.randbits(mapFlagNames.size())));
|
flags = TrimFlags(~(verify_flags | script_verify_flags::from_int(m_rng.randbits(MAX_SCRIPT_VERIFY_FLAGS_BITS))));
|
||||||
if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, flags, txdata, strTest, /*expect_valid=*/true)) {
|
if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, flags, txdata, strTest, /*expect_valid=*/true)) {
|
||||||
BOOST_ERROR("Tx unexpectedly failed with random flags " << ToString(flags) << ": " << strTest);
|
BOOST_ERROR("Tx unexpectedly failed with random flags " << ToString(flags.as_int()) << ": " << strTest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -337,7 +302,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
|
||||||
}
|
}
|
||||||
|
|
||||||
PrecomputedTransactionData txdata(tx);
|
PrecomputedTransactionData txdata(tx);
|
||||||
unsigned int verify_flags = ParseScriptFlags(test[2].get_str());
|
script_verify_flags verify_flags = ParseScriptFlags(test[2].get_str());
|
||||||
|
|
||||||
// Check that the test gives a valid combination of flags (otherwise VerifyScript will throw). Don't edit the flags.
|
// Check that the test gives a valid combination of flags (otherwise VerifyScript will throw). Don't edit the flags.
|
||||||
if (verify_flags != FillFlags(verify_flags)) {
|
if (verify_flags != FillFlags(verify_flags)) {
|
||||||
|
@ -350,13 +315,13 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
|
||||||
|
|
||||||
// Backwards compatibility of script verification flags: Adding any flag(s) should not validate an invalid transaction
|
// Backwards compatibility of script verification flags: Adding any flag(s) should not validate an invalid transaction
|
||||||
for (const auto& [name, flag] : mapFlagNames) {
|
for (const auto& [name, flag] : mapFlagNames) {
|
||||||
unsigned int flags = FillFlags(verify_flags | flag);
|
script_verify_flags flags = FillFlags(verify_flags | flag);
|
||||||
// Adding individual flags
|
// Adding individual flags
|
||||||
if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, flags, txdata, strTest, /*expect_valid=*/false)) {
|
if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, flags, txdata, strTest, /*expect_valid=*/false)) {
|
||||||
BOOST_ERROR("Tx unexpectedly passed with flag " << name << " set: " << strTest);
|
BOOST_ERROR("Tx unexpectedly passed with flag " << name << " set: " << strTest);
|
||||||
}
|
}
|
||||||
// Adding random combinations of flags
|
// Adding random combinations of flags
|
||||||
flags = FillFlags(verify_flags | (unsigned int)m_rng.randbits(mapFlagNames.size()));
|
flags = FillFlags(verify_flags | script_verify_flags::from_int(m_rng.randbits(MAX_SCRIPT_VERIFY_FLAGS_BITS)));
|
||||||
if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, flags, txdata, strTest, /*expect_valid=*/false)) {
|
if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, flags, txdata, strTest, /*expect_valid=*/false)) {
|
||||||
BOOST_ERROR("Tx unexpectedly passed with random flags " << name << ": " << strTest);
|
BOOST_ERROR("Tx unexpectedly passed with random flags " << name << ": " << strTest);
|
||||||
}
|
}
|
||||||
|
@ -488,7 +453,7 @@ static void CreateCreditAndSpend(const FillableSigningProvider& keystore, const
|
||||||
assert(input.vin[0].scriptWitness.stack == inputm.vin[0].scriptWitness.stack);
|
assert(input.vin[0].scriptWitness.stack == inputm.vin[0].scriptWitness.stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CheckWithFlag(const CTransactionRef& output, const CMutableTransaction& input, uint32_t flags, bool success)
|
static void CheckWithFlag(const CTransactionRef& output, const CMutableTransaction& input, script_verify_flags flags, bool success)
|
||||||
{
|
{
|
||||||
ScriptError error;
|
ScriptError error;
|
||||||
CTransaction inputi(input);
|
CTransaction inputi(input);
|
||||||
|
|
|
@ -21,7 +21,7 @@ struct Dersig100Setup : public TestChain100Setup {
|
||||||
};
|
};
|
||||||
|
|
||||||
bool CheckInputScripts(const CTransaction& tx, TxValidationState& state,
|
bool CheckInputScripts(const CTransaction& tx, TxValidationState& state,
|
||||||
const CCoinsViewCache& inputs, unsigned int flags, bool cacheSigStore,
|
const CCoinsViewCache& inputs, script_verify_flags flags, bool cacheSigStore,
|
||||||
bool cacheFullScriptStore, PrecomputedTransactionData& txdata,
|
bool cacheFullScriptStore, PrecomputedTransactionData& txdata,
|
||||||
ValidationCache& validation_cache,
|
ValidationCache& validation_cache,
|
||||||
std::vector<CScriptCheck>* pvChecks) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
std::vector<CScriptCheck>* pvChecks) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
|
@ -120,7 +120,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, Dersig100Setup)
|
||||||
// should fail.
|
// should fail.
|
||||||
// Capture this interaction with the upgraded_nop argument: set it when evaluating
|
// Capture this interaction with the upgraded_nop argument: set it when evaluating
|
||||||
// any script flag that is implemented as an upgraded NOP code.
|
// any script flag that is implemented as an upgraded NOP code.
|
||||||
static void ValidateCheckInputsForAllFlags(const CTransaction &tx, uint32_t failing_flags, bool add_to_cache, CCoinsViewCache& active_coins_tip, ValidationCache& validation_cache) EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
|
static void ValidateCheckInputsForAllFlags(const CTransaction &tx, script_verify_flags failing_flags, bool add_to_cache, CCoinsViewCache& active_coins_tip, ValidationCache& validation_cache) EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
|
||||||
{
|
{
|
||||||
PrecomputedTransactionData txdata;
|
PrecomputedTransactionData txdata;
|
||||||
|
|
||||||
|
@ -130,7 +130,7 @@ static void ValidateCheckInputsForAllFlags(const CTransaction &tx, uint32_t fail
|
||||||
TxValidationState state;
|
TxValidationState state;
|
||||||
|
|
||||||
// Randomly selects flag combinations
|
// Randomly selects flag combinations
|
||||||
uint32_t test_flags = (uint32_t) insecure_rand.randrange((SCRIPT_VERIFY_END_MARKER - 1) << 1);
|
script_verify_flags test_flags = script_verify_flags::from_int(insecure_rand.randrange(MAX_SCRIPT_VERIFY_FLAGS));
|
||||||
|
|
||||||
// Filter out incompatible flag choices
|
// Filter out incompatible flag choices
|
||||||
if ((test_flags & SCRIPT_VERIFY_CLEANSTACK)) {
|
if ((test_flags & SCRIPT_VERIFY_CLEANSTACK)) {
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#include <script/interpreter.h>
|
#include <script/interpreter.h>
|
||||||
#include <test/util/script.h>
|
#include <test/util/script.h>
|
||||||
|
|
||||||
bool IsValidFlagCombination(unsigned flags)
|
bool IsValidFlagCombination(script_verify_flags flags)
|
||||||
{
|
{
|
||||||
if (flags & SCRIPT_VERIFY_CLEANSTACK && ~flags & (SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS)) return false;
|
if (flags & SCRIPT_VERIFY_CLEANSTACK && ~flags & (SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS)) return false;
|
||||||
if (flags & SCRIPT_VERIFY_WITNESS && ~flags & SCRIPT_VERIFY_P2SH) return false;
|
if (flags & SCRIPT_VERIFY_WITNESS && ~flags & SCRIPT_VERIFY_P2SH) return false;
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
#include <crypto/sha256.h>
|
#include <crypto/sha256.h>
|
||||||
#include <script/script.h>
|
#include <script/script.h>
|
||||||
|
#include <script/verify_flags.h>
|
||||||
|
|
||||||
static const std::vector<uint8_t> WITNESS_STACK_ELEM_OP_TRUE{uint8_t{OP_TRUE}};
|
static const std::vector<uint8_t> WITNESS_STACK_ELEM_OP_TRUE{uint8_t{OP_TRUE}};
|
||||||
static const CScript P2WSH_OP_TRUE{
|
static const CScript P2WSH_OP_TRUE{
|
||||||
|
@ -31,6 +32,6 @@ static const std::vector<std::vector<uint8_t>> P2WSH_EMPTY_TRUE_STACK{{static_ca
|
||||||
static const std::vector<std::vector<uint8_t>> P2WSH_EMPTY_TWO_STACK{{static_cast<uint8_t>(OP_2)}, {}};
|
static const std::vector<std::vector<uint8_t>> P2WSH_EMPTY_TWO_STACK{{static_cast<uint8_t>(OP_2)}, {}};
|
||||||
|
|
||||||
/** Flags that are not forbidden by an assert in script validation */
|
/** Flags that are not forbidden by an assert in script validation */
|
||||||
bool IsValidFlagCombination(unsigned flags);
|
bool IsValidFlagCombination(script_verify_flags flags);
|
||||||
|
|
||||||
#endif // BITCOIN_TEST_UTIL_SCRIPT_H
|
#endif // BITCOIN_TEST_UTIL_SCRIPT_H
|
||||||
|
|
|
@ -139,7 +139,7 @@ const CBlockIndex* Chainstate::FindForkInGlobalIndex(const CBlockLocator& locato
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CheckInputScripts(const CTransaction& tx, TxValidationState& state,
|
bool CheckInputScripts(const CTransaction& tx, TxValidationState& state,
|
||||||
const CCoinsViewCache& inputs, unsigned int flags, bool cacheSigStore,
|
const CCoinsViewCache& inputs, script_verify_flags flags, bool cacheSigStore,
|
||||||
bool cacheFullScriptStore, PrecomputedTransactionData& txdata,
|
bool cacheFullScriptStore, PrecomputedTransactionData& txdata,
|
||||||
ValidationCache& validation_cache,
|
ValidationCache& validation_cache,
|
||||||
std::vector<CScriptCheck>* pvChecks = nullptr)
|
std::vector<CScriptCheck>* pvChecks = nullptr)
|
||||||
|
@ -262,9 +262,6 @@ bool CheckSequenceLocksAtTip(CBlockIndex* tip,
|
||||||
return EvaluateSequenceLocks(index, {lock_points.height, lock_points.time});
|
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)
|
static void LimitMempoolSize(CTxMemPool& pool, CCoinsViewCache& coins_cache)
|
||||||
EXCLUSIVE_LOCKS_REQUIRED(::cs_main, pool.cs)
|
EXCLUSIVE_LOCKS_REQUIRED(::cs_main, pool.cs)
|
||||||
{
|
{
|
||||||
|
@ -398,7 +395,7 @@ void Chainstate::MaybeUpdateMempoolForReorg(
|
||||||
* */
|
* */
|
||||||
static bool CheckInputsFromMempoolAndCache(const CTransaction& tx, TxValidationState& state,
|
static bool CheckInputsFromMempoolAndCache(const CTransaction& tx, TxValidationState& state,
|
||||||
const CCoinsViewCache& view, const CTxMemPool& pool,
|
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)
|
ValidationCache& validation_cache)
|
||||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main, pool.cs)
|
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;
|
const CTransaction& tx = *ws.m_ptx;
|
||||||
TxValidationState& state = ws.m_state;
|
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.
|
// Check input scripts and signatures.
|
||||||
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
|
// 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
|
// There is a similar check in CreateNewBlock() to prevent creating
|
||||||
// invalid blocks (using TestBlockValidity), however allowing such
|
// invalid blocks (using TestBlockValidity), however allowing such
|
||||||
// transactions into the mempool can be exploited as a DoS attack.
|
// 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,
|
if (!CheckInputsFromMempoolAndCache(tx, state, m_view, m_pool, currentBlockScriptVerifyFlags,
|
||||||
ws.m_precomputed_txdata, m_active_chainstate.CoinsTip(), GetValidationCache())) {
|
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());
|
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 CScript &scriptSig = ptxTo->vin[nIn].scriptSig;
|
||||||
const CScriptWitness *witness = &ptxTo->vin[nIn].scriptWitness;
|
const CScriptWitness *witness = &ptxTo->vin[nIn].scriptWitness;
|
||||||
ScriptError error{SCRIPT_ERR_UNKNOWN_ERROR};
|
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;
|
return std::nullopt;
|
||||||
} else {
|
} 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);
|
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
|
* Non-static (and redeclared) in src/test/txvalidationcache_tests.cpp
|
||||||
*/
|
*/
|
||||||
bool CheckInputScripts(const CTransaction& tx, TxValidationState& state,
|
bool CheckInputScripts(const CTransaction& tx, TxValidationState& state,
|
||||||
const CCoinsViewCache& inputs, unsigned int flags, bool cacheSigStore,
|
const CCoinsViewCache& inputs, script_verify_flags flags, bool cacheSigStore,
|
||||||
bool cacheFullScriptStore, PrecomputedTransactionData& txdata,
|
bool cacheFullScriptStore, PrecomputedTransactionData& txdata,
|
||||||
ValidationCache& validation_cache,
|
ValidationCache& validation_cache,
|
||||||
std::vector<CScriptCheck>* pvChecks)
|
std::vector<CScriptCheck>* pvChecks)
|
||||||
|
@ -2330,7 +2327,7 @@ DisconnectResult Chainstate::DisconnectBlock(const CBlock& block, const CBlockIn
|
||||||
return fClean ? DISCONNECT_OK : DISCONNECT_UNCLEAN;
|
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();
|
const Consensus::Params& consensusparams = chainman.GetConsensus();
|
||||||
|
|
||||||
|
@ -2342,7 +2339,7 @@ static unsigned int GetBlockScriptFlags(const CBlockIndex& block_index, const Ch
|
||||||
// mainnet.
|
// mainnet.
|
||||||
// For simplicity, always leave P2SH+WITNESS+TAPROOT on except for the two
|
// For simplicity, always leave P2SH+WITNESS+TAPROOT on except for the two
|
||||||
// violating blocks.
|
// 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))};
|
const auto it{consensusparams.script_flag_exceptions.find(*Assert(block_index.phashBlock))};
|
||||||
if (it != consensusparams.script_flag_exceptions.end()) {
|
if (it != consensusparams.script_flag_exceptions.end()) {
|
||||||
flags = it->second;
|
flags = it->second;
|
||||||
|
@ -2556,7 +2553,7 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the script flags for this block
|
// 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()};
|
const auto time_2{SteadyClock::now()};
|
||||||
m_chainman.time_forks += time_2 - time_1;
|
m_chainman.time_forks += time_2 - time_1;
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include <policy/policy.h>
|
#include <policy/policy.h>
|
||||||
#include <script/script_error.h>
|
#include <script/script_error.h>
|
||||||
#include <script/sigcache.h>
|
#include <script/sigcache.h>
|
||||||
|
#include <script/verify_flags.h>
|
||||||
#include <sync.h>
|
#include <sync.h>
|
||||||
#include <txdb.h>
|
#include <txdb.h>
|
||||||
#include <txmempool.h>
|
#include <txmempool.h>
|
||||||
|
@ -336,14 +337,14 @@ private:
|
||||||
CTxOut m_tx_out;
|
CTxOut m_tx_out;
|
||||||
const CTransaction *ptxTo;
|
const CTransaction *ptxTo;
|
||||||
unsigned int nIn;
|
unsigned int nIn;
|
||||||
unsigned int nFlags;
|
script_verify_flags m_flags;
|
||||||
bool cacheStore;
|
bool cacheStore;
|
||||||
PrecomputedTransactionData *txdata;
|
PrecomputedTransactionData *txdata;
|
||||||
SignatureCache* m_signature_cache;
|
SignatureCache* m_signature_cache;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CScriptCheck(const CTxOut& outIn, const CTransaction& txToIn, SignatureCache& signature_cache, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn, PrecomputedTransactionData* txdataIn) :
|
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), nFlags(nFlagsIn), cacheStore(cacheIn), txdata(txdataIn), m_signature_cache(&signature_cache) { }
|
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(const CScriptCheck&) = delete;
|
||||||
CScriptCheck& operator=(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) */
|
/** Identifies blocks which coinbase output was subsequently overwritten in the UTXO set (see BIP30) */
|
||||||
bool IsBIP30Unspendable(const uint256& block_hash, int block_height);
|
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
|
#endif // BITCOIN_VALIDATION_H
|
||||||
|
|
|
@ -213,6 +213,7 @@ class BlockchainTest(BitcoinTestFramework):
|
||||||
assert_equal(gdi_result, {
|
assert_equal(gdi_result, {
|
||||||
"hash": blockhash,
|
"hash": blockhash,
|
||||||
"height": height,
|
"height": height,
|
||||||
|
"script_flags": ["CHECKLOCKTIMEVERIFY","CHECKSEQUENCEVERIFY","DERSIG","NULLDUMMY","P2SH","TAPROOT","WITNESS"],
|
||||||
"deployments": {
|
"deployments": {
|
||||||
'bip34': {'type': 'buried', 'active': True, 'height': 2},
|
'bip34': {'type': 'buried', 'active': True, 'height': 2},
|
||||||
'bip66': {'type': 'buried', 'active': True, 'height': 3},
|
'bip66': {'type': 'buried', 'active': True, 'height': 3},
|
||||||
|
|
Loading…
Reference in New Issue