Bitcoin full node and query server

Jun 22, 2026

View in context in the libbitcoin Slack #general mirror.

evoskuil02:57
Schnorr Capture
// This script type is fabricated in witness::extract_taproot.
constexpr bool script::is_pay_taproot_key_path_pattern(
    const operations& ops) NOEXCEPT
{
    return ops.size() == 1
        && ops[0].code() == opcode::checksig;
}

constexpr bool script::is_pay_tapscript_single_pattern(
    const operations& ops) NOEXCEPT
{
    return ops.size() == 2
        && ops[0].data().size() == ec_xonly_size
        && ops[1].code() == opcode::checksig;
}

constexpr bool script::is_pay_tapscript_timelock_pattern(
    const operations& ops) NOEXCEPT
{
    return ops.size() == 5u
        && ops[0].is_nonnegative()
        && ops[1].is_timelock()
        && ops[2].code() == opcode::drop
        && ops[3].data().size() == ec_xonly_size
        && ops[4].code() == opcode::checksig;
}

constexpr bool script::is_pay_tapscript_inscription_pattern(
    const operations& ops) NOEXCEPT
{
    return ops.size() > 4u
        && ops[0].data().size() == ec_xonly_size
        && ops[1].code() == opcode::checksig
        && ops[2].code() == opcode::push_size_0
        && ops[3].code() == opcode::if_
        && ops.back().code() == opcode::endif;
}

constexpr bool script::is_pay_tapscript_threshold_pattern(
    const operations& ops) NOEXCEPT
{
    const auto size = ops.size();
    if (is_zero(size))
        return false;

    // opcode::within requires an additional number in the script.
    const auto within = (ops.back().code() == opcode::within);
    if ((is_even(size) == within) ||
        (size < (4u + to_int<uint8_t>(within))))
        return false;

    auto op = ops.begin();
    if ((op++)->data().size() != ec_xonly_size)
        return false;

    if ((op++)->code() != opcode::checksig)
        return false;

    while (op != std::prev(ops.end(), 2 + to_int(within)))
    {
        if (((op++)->data().size() != ec_xonly_size) ||
            ((op++)->code() != opcode::checksigadd))
            return false;
    }

    if (!(op++)->is_unsigned32() || (within &&
        !(op++)->is_unsigned32()))
        return false;

    return op->is_threshold();
}

constexpr bool script::is_pay_tapscript_multisig_pattern(
    const operations& ops) NOEXCEPT
{
    if (ops.size() < 2u || !is_even(ops.size()))
        return false;

    auto op = ops.begin();
    while (op != std::prev(ops.end(), 2))
    {
        if (((op++)->data().size() != ec_xonly_size) ||
            ((op++)->code() != opcode::checksigverify))
            return false;
    }

    if (((op++)->data().size() != ec_xonly_size) ||
        ((op++)->code() != opcode::checksig))
        return false;

    return true;
}