#include <chainparams.h>
#include <key_io.h>
#include <pubkey.h>
#include <script/descriptor.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util/descriptor.h>
#include <util/chaintype.h>
#include <util/strencodings.h>
MockedDescriptorConverter MOCKED_DESC_CONVERTER;
static void TestDescriptor(const Descriptor& desc, FlatSigningProvider& sig_provider, std::string& dummy, std::optional<bool>& is_ranged, std::optional<bool>& is_solvable)
{
(void)desc.IsRange();
(void)desc.IsSingleType();
(void)desc.GetOutputType();
if (is_ranged.has_value()) {
assert(desc.IsRange() == *is_ranged);
} else {
is_ranged = desc.IsRange();
}
if (is_solvable.has_value()) {
assert(desc.IsSolvable() == *is_solvable);
} else {
is_solvable = desc.IsSolvable();
}
(void)desc.ToString();
(void)desc.ToPrivateString(sig_provider, dummy);
(void)desc.ToNormalizedString(sig_provider, dummy);
DescriptorCache cache;
std::vector<CScript> out_scripts;
(void)desc.Expand(0, sig_provider, out_scripts, sig_provider, &cache);
(void)desc.ExpandPrivate(0, sig_provider, sig_provider);
(void)desc.ExpandFromCache(0, cache, out_scripts, sig_provider);
if (!out_scripts.empty()) {
assert(InferDescriptor(out_scripts.back(), sig_provider));
const bool is_combo{!desc.IsSingleType()};
assert(is_combo || desc.ScriptSize() == out_scripts.back().size());
}
const auto max_sat_maxsig{desc.MaxSatisfactionWeight(true)};
const auto max_sat_nonmaxsig{desc.MaxSatisfactionWeight(true)};
const auto max_elems{desc.MaxSatisfactionElems()};
const bool is_nontop_or_nonsolvable{!*is_solvable || !desc.GetOutputType()};
const bool is_input_size_info_set{max_sat_maxsig && max_sat_nonmaxsig && max_elems};
assert(is_input_size_info_set || is_nontop_or_nonsolvable);
}
void initialize_descriptor_parse()
{
static ECC_Context ecc_context{};
SelectParams(ChainType::MAIN);
}
void initialize_mocked_descriptor_parse()
{
initialize_descriptor_parse();
MOCKED_DESC_CONVERTER.Init();
}
FUZZ_TARGET(mocked_descriptor_parse, .init = initialize_mocked_descriptor_parse)
{
if (HasDeepDerivPath(buffer)) return;
if (HasTooManySubFrag(buffer)) return;
if (HasTooManyWrappers(buffer)) return;
const std::string mocked_descriptor{buffer.begin(), buffer.end()};
if (const auto descriptor = MOCKED_DESC_CONVERTER.GetDescriptor(mocked_descriptor)) {
FlatSigningProvider signing_provider;
std::string error;
const auto desc = Parse(*descriptor, signing_provider, error);
std::optional<bool> is_ranged;
std::optional<bool> is_solvable;
for (const auto& d : desc) {
assert(d);
TestDescriptor(*d, signing_provider, error, is_ranged, is_solvable);
}
}
}
FUZZ_TARGET(descriptor_parse, .init = initialize_descriptor_parse)
{
if (HasDeepDerivPath(buffer)) return;
if (HasTooManySubFrag(buffer)) return;
if (HasTooManyWrappers(buffer)) return;
const std::string descriptor(buffer.begin(), buffer.end());
FlatSigningProvider signing_provider;
std::string error;
for (const bool require_checksum : {true, false}) {
const auto desc = Parse(descriptor, signing_provider, error, require_checksum);
std::optional<bool> is_ranged;
std::optional<bool> is_solvable;
for (const auto& d : desc) {
assert(d);
TestDescriptor(*d, signing_provider, error, is_ranged, is_solvable);
}
}
}