script/verify_flags: make script_verify_flags type safe

`using script_verify_flags = uint32_t` allows implicit conversion to
and from int, so replace it with a class to have the compiler ensure we
use the correct type. Provide from_int and as_int to allow for explicit
conversions when desired.

Introduces the type `script_verify_flag_name` for the individual flag
name enumeration.
This commit is contained in:
Anthony Towns
2025-07-26 18:51:24 +10:00
parent a5ead122fe
commit bddcadee82
12 changed files with 100 additions and 25 deletions

View File

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

View File

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

View File

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

View File

@@ -90,7 +90,7 @@ CScriptWitness ScriptWitnessFromJSON(const UniValue& univalue)
return scriptwitness;
}
const std::map<std::string, uint32_t> FLAG_NAMES = {
const std::map<std::string, script_verify_flag_name> FLAG_NAMES = {
{std::string("P2SH"), SCRIPT_VERIFY_P2SH},
{std::string("DERSIG"), SCRIPT_VERIFY_DERSIG},
{std::string("NULLDUMMY"), SCRIPT_VERIFY_NULLDUMMY},

View File

@@ -15,6 +15,14 @@
#include <utility>
#include <vector>
static DataStream& operator>>(DataStream& ds, script_verify_flags& f)
{
script_verify_flags::value_type n{0};
ds >> n;
f = script_verify_flags::from_int(n);
return ds;
}
FUZZ_TARGET(script_flags)
{
if (buffer.size() > 100'000) return;

View File

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