diff --git a/src/test/fuzz/miniscript.cpp b/src/test/fuzz/miniscript.cpp index edc9772a9ccd..57aae0ef3eb9 100644 --- a/src/test/fuzz/miniscript.cpp +++ b/src/test/fuzz/miniscript.cpp @@ -106,6 +106,12 @@ struct TestData { return &it->second; } } + + //! Whether signing material is available for this pubkey in this script context. + bool HasPrivKey(const MsCtx script_ctx, const Key& key) const { + const auto sig_ptr = GetSig(script_ctx, key); + return sig_ptr && sig_ptr->second; + } } TEST_DATA; /** @@ -126,13 +132,10 @@ struct ParserContext { std::optional ToString(const Key& key, bool& has_priv_key) const { - has_priv_key = false; - auto it = TEST_DATA.dummy_key_idx_map.find(key); - if (it == TEST_DATA.dummy_key_idx_map.end()) { - return HexStr(key); - } - has_priv_key = true; - uint8_t idx = it->second; + const auto it = TEST_DATA.dummy_key_idx_map.find(key); + assert(it != TEST_DATA.dummy_key_idx_map.end()); + has_priv_key = TEST_DATA.HasPrivKey(script_ctx, key); + const uint8_t idx = it->second; return HexStr(std::span{&idx, 1}); } @@ -1037,8 +1040,23 @@ void TestNode(const MsCtx script_ctx, const NodeRef& node, FuzzedDataProvider& p // Check that it roundtrips to text representation const ParserContext parser_ctx{script_ctx}; - std::optional str{node->ToString(parser_ctx)}; + bool has_priv_key{false}; + std::optional str{node->ToString(parser_ctx, has_priv_key)}; assert(str); + + // Check has_priv_key against expectation + bool expected_has_priv_key{false}; + std::vector nodes{node.get()}; + while (!nodes.empty() && !expected_has_priv_key) { + const Node* n{nodes.back()}; + nodes.pop_back(); + expected_has_priv_key = std::any_of(n->keys.begin(), n->keys.end(), [&](const auto& key) { + return TEST_DATA.HasPrivKey(script_ctx, key); + }); + for (const auto& sub : n->subs) nodes.push_back(sub.get()); + } + assert(has_priv_key == expected_has_priv_key); + auto parsed = miniscript::FromString(*str, parser_ctx); assert(parsed); assert(*parsed == *node); @@ -1162,8 +1180,7 @@ void TestNode(const MsCtx script_ctx, const NodeRef& node, FuzzedDataProvider& p // are identical, this implies that for such nodes, the non-malleable // satisfaction will also match the expected policy. const auto is_key_satisfiable = [script_ctx](const CPubKey& pubkey) -> bool { - auto sig_ptr{TEST_DATA.GetSig(script_ctx, pubkey)}; - return sig_ptr != nullptr && sig_ptr->second; + return TEST_DATA.HasPrivKey(script_ctx, pubkey); }; bool satisfiable = node->IsSatisfiable([&](const Node& node) -> bool { switch (node.fragment) {