Repository: bitcoin/bitcoin
File: src/script/descriptor.cpp (C++)

Code before:
            ret = m_pubkeys[key]->ToString(PubkeyProvider::StringType::COMPAT);
            break;
        }
        return ret;
    }
};

class MiniscriptDescriptor final : public DescriptorImpl
{
private:
    miniscript::NodeRef<uint32_t> m_node;

protected:
    std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, std::span<const CScript> scripts,
                                     FlatSigningProvider& provider) const override
    {
        const auto script_ctx{m_node->GetMsCtx()};
        for (const auto& key : keys) {
            if (miniscript::IsTapscript(script_ctx)) {
                provider.pubkeys.emplace(Hash160(XOnlyPubKey{key}), key);
            } else {
                provider.pubkeys.emplace(key.GetID(), key);
            }
        }
        return Vector(m_node->ToScript(ScriptMaker(keys, script_ctx)));
    }

public:
    MiniscriptDescriptor(std::vector<std::unique_ptr<PubkeyProvider>> providers, miniscript::NodeRef<uint32_t> node)
        : DescriptorImpl(std::move(providers), "?"), m_node(std::move(node))
    {
        // Traverse miniscript tree for unsafe use of older()
        miniscript::ForEachNode(*m_node, [&](const miniscript::Node<uint32_t>& node) {
            if (node.fragment == miniscript::Fragment::OLDER) {
                const uint32_t raw = node.k;
                const uint32_t value_part = raw & ~CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG;
                if (value_part > CTxIn::SEQUENCE_LOCKTIME_MASK) {
                    const bool is_time_based = (raw & CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG) != 0;
                    if (is_time_based) {
                        m_warnings.push_back(strprintf("time-based relative locktime: older(%u) > (65535 * 512) seconds is unsafe", raw));
                    } else {
                        m_warnings.push_back(strprintf("height-based relative locktime: older(%u) > 65535 blocks is unsafe", raw));
                    }
                }
            }
        });
    }

    bool ToStringHelper(const SigningProvider* arg, std::string& out, const StringType type,
                        const DescriptorCache* cache = nullptr) const override
    {

Review comment (suggestion):
In https://github.com/bitcoin/bitcoin/commit/deed439bff638abfc298a3b9c4f3d9f75fa18244 "descriptor: ToPrivateString() pass if at least 1 priv key exists"

Looks like the same argument applies here too?

https://github.com/bitcoin/bitcoin/pull/32471#discussion_r2258451488

> If has_priv_key is never supposed to be null, then it should be a reference.

Code after:
    }

    std::vector<unsigned char> ToPKHBytes(uint32_t key) const {
        auto id = GetHash160(key);
        return {id.begin(), id.end()};
    }
};

/**
 * The context for converting a Miniscript descriptor to its textual form.
 */
class StringMaker {
    //! To convert private keys for private descriptors.
    const SigningProvider* m_arg;
    //! Keys contained in the Miniscript (a reference to DescriptorImpl::m_pubkey_args).
    const std::vector<std::unique_ptr<PubkeyProvider>>& m_pubkeys;
    //! StringType to serialize keys
    const DescriptorImpl::StringType m_type;
    const DescriptorCache* m_cache;

public:
    StringMaker(const SigningProvider* arg LIFETIMEBOUND,
                const std::vector<std::unique_ptr<PubkeyProvider>>& pubkeys LIFETIMEBOUND,
                DescriptorImpl::StringType type,
                const DescriptorCache* cache LIFETIMEBOUND)
        : m_arg(arg), m_pubkeys(pubkeys), m_type(type), m_cache(cache) {}

    std::optional<std::string> ToString(uint32_t key, bool& has_priv_key) const
    {
        std::string ret;
        has_priv_key = false;
        switch (m_type) {
        case DescriptorImpl::StringType::PUBLIC:
            ret = m_pubkeys[key]->ToString();
            break;
        case DescriptorImpl::StringType::PRIVATE:
            has_priv_key = m_pubkeys[key]->ToPrivateString(*m_arg, ret);
            break;
        case DescriptorImpl::StringType::NORMALIZED:
            if (!m_pubkeys[key]->ToNormalizedString(*m_arg, ret, m_cache)) return {};
            break;
        case DescriptorImpl::StringType::COMPAT:
            ret = m_pubkeys[key]->ToString(PubkeyProvider::StringType::COMPAT);
            break;
        }
        return ret;
    }
};

class MiniscriptDescriptor final : public DescriptorImpl
{